配置、记录请求、支付

This commit is contained in:
Jerry Yan 2024-12-17 18:54:07 +08:00
parent d70bfbc605
commit 5249cc2cc8
12 changed files with 311 additions and 31 deletions

View File

@ -0,0 +1,11 @@
package com.ycwl.basic.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
public @interface RequestToFile {
}

View File

@ -0,0 +1,63 @@
package com.ycwl.basic.aspectj;
import com.ycwl.basic.annotation.RequestToFile;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.Enumeration;
import java.util.stream.Collectors;
@Aspect
@Component
@Slf4j
public class HttpSaver {
@Pointcut("@annotation(com.ycwl.basic.annotation.RequestToFile)")
public void requestToFilePointCut() {
}
@After("requestToFilePointCut()")
public void requestToFile() throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return;
}
HttpServletRequest request = attributes.getRequest();
StringBuilder rawReq = new StringBuilder();
rawReq.append(request.getMethod()).append(" ").append(request.getRequestURL());
String queryString = request.getQueryString();
if (queryString != null) {
rawReq.append("?").append(queryString);
}
rawReq.append("\r\n");
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
rawReq.append(headerName).append(": ").append(request.getHeader(headerName)).append("\r\n");
}
rawReq.append("\r\n");
// 获取body
rawReq.append(request.getReader().lines().collect(Collectors.joining("\r\n")));
rawReq.append("\r\n");
// 写入文件
File file = new File("./request/"+System.currentTimeMillis()+".http");
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
try (java.io.FileWriter writer = new java.io.FileWriter(file, true)) {
writer.write(rawReq.toString());
}
}
}

View File

@ -2,6 +2,8 @@ package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.annotation.IgnoreToken; import com.ycwl.basic.annotation.IgnoreToken;
import com.ycwl.basic.annotation.RequestToFile;
import com.ycwl.basic.aspectj.HttpSaver;
import com.ycwl.basic.enums.BizCodeEnum; import com.ycwl.basic.enums.BizCodeEnum;
import com.ycwl.basic.model.wx.WXPayOrderReqVO; import com.ycwl.basic.model.wx.WXPayOrderReqVO;
import com.ycwl.basic.model.wx.WxPayRespVO; import com.ycwl.basic.model.wx.WxPayRespVO;
@ -42,6 +44,7 @@ public class AppWxPayController {
@ApiOperation(value = "微信支付回调", notes = "微信支付回调") @ApiOperation(value = "微信支付回调", notes = "微信支付回调")
@PostMapping("/payNotify") @PostMapping("/payNotify")
@IgnoreToken @IgnoreToken
@RequestToFile
public ApiResponse<?> payNotify(HttpServletRequest request) { public ApiResponse<?> payNotify(HttpServletRequest request) {
wxPayService.payNotify(request); wxPayService.payNotify(request);
return ApiResponse.success(BizCodeEnum.REQUEST_OK); return ApiResponse.success(BizCodeEnum.REQUEST_OK);
@ -58,6 +61,7 @@ public class AppWxPayController {
@ApiOperation(value = "微信支付退款回调", notes = "微信支付退款回调") @ApiOperation(value = "微信支付退款回调", notes = "微信支付退款回调")
@PostMapping("/refundNotify") @PostMapping("/refundNotify")
@IgnoreToken @IgnoreToken
@RequestToFile
public ApiResponse<?> refundNotify(@RequestBody String refundResult) throws GeneralSecurityException, IOException { public ApiResponse<?> refundNotify(@RequestBody String refundResult) throws GeneralSecurityException, IOException {
return ApiResponse.buildResult(wxPayService.refundNotify(refundResult) ? return ApiResponse.buildResult(wxPayService.refundNotify(refundResult) ?
BizCodeEnum.SUCCESS : BizCodeEnum.SUCCESS :

View File

@ -26,4 +26,6 @@ public class WXPayOrderReqVO {
@ApiModelProperty(value = "商品订单号",required = true) @ApiModelProperty(value = "商品订单号",required = true)
private Long orderSn; private Long orderSn;
private String description;
} }

View File

@ -1,5 +1,6 @@
package com.ycwl.basic.service.impl.mobile; package com.ycwl.basic.service.impl.mobile;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.mapper.*; import com.ycwl.basic.mapper.*;
import com.ycwl.basic.model.jwt.JwtInfo; import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.goods.*; import com.ycwl.basic.model.mobile.goods.*;
@ -43,14 +44,13 @@ public class GoodsServiceImpl implements GoodsService {
private FaceMapper faceMapper; private FaceMapper faceMapper;
public ApiResponse<List<GoodsPageVO>> goodsList(GoodsReqQuery query) { public ApiResponse<List<GoodsPageVO>> goodsList(GoodsReqQuery query) {
JwtInfo worker = JwtTokenUtil.getWorker();
//查询原素材 //查询原素材
List<GoodsPageVO> goodsList = new ArrayList<>(); List<GoodsPageVO> goodsList = new ArrayList<>();
VideoReqQuery videoReqQuery = new VideoReqQuery(); VideoReqQuery videoReqQuery = new VideoReqQuery();
videoReqQuery.setScenicId(query.getScenicId()); videoReqQuery.setScenicId(query.getScenicId());
videoReqQuery.setIsBuy(query.getIsBuy()); videoReqQuery.setIsBuy(query.getIsBuy());
videoReqQuery.setMemberId(worker.getUserId()); videoReqQuery.setMemberId(Long.valueOf(BaseContextHandler.getUserId()));
//查询成片vlog //查询成片vlog
List<VideoRespVO> videoList = videoMapper.list(videoReqQuery); List<VideoRespVO> videoList = videoMapper.list(videoReqQuery);
videoList.forEach(videoRespVO -> { videoList.forEach(videoRespVO -> {

View File

@ -90,13 +90,14 @@ public class WxPayServiceImpl implements WxPayService {
// request.setXxx(val)设置所需参数具体参数可见Request定义 // request.setXxx(val)设置所需参数具体参数可见Request定义
PrepayRequest request = new PrepayRequest(); PrepayRequest request = new PrepayRequest();
Amount amount = new Amount(); Amount amount = new Amount();
amount.setTotal(req.getTotalPrice()); amount.setTotal(1);
request.setAmount(amount); request.setAmount(amount);
request.setAppid(wechatConfig.getAppId()); request.setAppid(wechatConfig.getMiniProgramAppId());
request.setMchid(wechatConfig.getMchId()); request.setMchid(wechatConfig.getMchId());
request.setDescription(req.getGoodsName()); request.setDescription(req.getGoodsName());
request.setNotifyUrl(wechatConfig.getPayNotifyUrl()); request.setNotifyUrl(wechatConfig.getPayNotifyUrl());
request.setOutTradeNo(req.getOrderSn().toString()); request.setOutTradeNo(req.getOrderSn().toString());
request.setDescription(req.getDescription());
Payer payer = new Payer(); Payer payer = new Payer();
payer.setOpenid(req.getOpenId()); payer.setOpenid(req.getOpenId());
@ -109,7 +110,7 @@ public class WxPayServiceImpl implements WxPayService {
vo.setTimeStamp(timeStamp); vo.setTimeStamp(timeStamp);
String substring = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); String substring = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
vo.setNonceStr(substring); vo.setNonceStr(substring);
String signatureStr = Stream.of(wechatConfig.getAppId(), String.valueOf(timeStamp), substring, "prepay_id=" + response.getPrepayId()) String signatureStr = Stream.of(wechatConfig.getMiniProgramAppId(), String.valueOf(timeStamp), substring, "prepay_id=" + response.getPrepayId())
.collect(Collectors.joining("\n", "", "\n")); .collect(Collectors.joining("\n", "", "\n"));
String sign = WXPayUtil.getSign(signatureStr, wechatConfig.getKeyPath()); String sign = WXPayUtil.getSign(signatureStr, wechatConfig.getKeyPath());
vo.setPaySign(sign); vo.setPaySign(sign);
@ -137,6 +138,7 @@ public class WxPayServiceImpl implements WxPayService {
stringBuffer.append(s); stringBuffer.append(s);
} }
String s1 = stringBuffer.toString(); String s1 = stringBuffer.toString();
log.warn("微信支付回调:{}", s1);
String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP); String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
String nonce = request.getHeader(WECHAT_PAY_NONCE); String nonce = request.getHeader(WECHAT_PAY_NONCE);
String signType = request.getHeader(WeiXinConstant.WECHATPAY_SIGNATURE_TYPE); String signType = request.getHeader(WeiXinConstant.WECHATPAY_SIGNATURE_TYPE);
@ -145,7 +147,7 @@ public class WxPayServiceImpl implements WxPayService {
NotificationConfig config = new RSAAutoCertificateConfig.Builder() NotificationConfig config = new RSAAutoCertificateConfig.Builder()
.merchantId(wechatConfig.getMchId()) .merchantId(wechatConfig.getMchId())
.privateKeyFromPath(wechatConfig.getKeyPath()) .privateKey(wechatConfig.getKeyPath())
.merchantSerialNumber(wechatConfig.getMchSerialNo()) .merchantSerialNumber(wechatConfig.getMchSerialNo())
.apiV3Key(wechatConfig.getApiV3()) .apiV3Key(wechatConfig.getApiV3())
.build(); .build();
@ -401,7 +403,7 @@ public class WxPayServiceImpl implements WxPayService {
// 对参数进行加密 // 对参数进行加密
byte[] bytes = parameter.getBytes(String.valueOf(StandardCharsets.UTF_8)); byte[] bytes = parameter.getBytes(String.valueOf(StandardCharsets.UTF_8));
Signature sign = Signature.getInstance("SHA256withRSA"); Signature sign = Signature.getInstance("SHA256withRSA");
PrivateKey privateKey = PemUtil.loadPrivateKeyFromPath(wechatConfig.getKeyPath()); // privateKeyPath是商户证书密钥的位置apiclient_key.pem PrivateKey privateKey = PemUtil.loadPrivateKeyFromString(wechatConfig.getKeyPath()); // privateKeyPath是商户证书密钥的位置apiclient_key.pem
sign.initSign(privateKey); // 商户密钥文件路径 sign.initSign(privateKey); // 商户密钥文件路径
sign.update(bytes); sign.update(bytes);
String signature = Base64.getEncoder().encodeToString(sign.sign()); String signature = Base64.getEncoder().encodeToString(sign.sign());
@ -425,7 +427,7 @@ public class WxPayServiceImpl implements WxPayService {
static void init(WechatConfig wechatConfig) { static void init(WechatConfig wechatConfig) {
instance = new RSAAutoCertificateConfig.Builder() instance = new RSAAutoCertificateConfig.Builder()
.merchantId(wechatConfig.getMchId()) .merchantId(wechatConfig.getMchId())
.privateKeyFromPath(wechatConfig.getKeyPath()) .privateKey(wechatConfig.getKeyPath())
.merchantSerialNumber(wechatConfig.getMchSerialNo()) .merchantSerialNumber(wechatConfig.getMchSerialNo())
.apiV3Key(wechatConfig.getApiV3()) .apiV3Key(wechatConfig.getApiV3())
.build(); .build();

View File

@ -130,17 +130,17 @@ public class OrderServiceImpl implements OrderService {
orderItems.add(orderItemEntity); orderItems.add(orderItemEntity);
//修改商品状态 //修改商品状态
if (Objects.equals(goodsType, GoodsTypeEnum.VIDEO.code)) { // if (Objects.equals(goodsType, GoodsTypeEnum.VIDEO.code)) {
VideoEntity videoEntity = new VideoEntity(); // VideoEntity videoEntity = new VideoEntity();
videoEntity.setId(goodsId); // videoEntity.setId(goodsId);
videoEntity.setIsBuy(1); // videoEntity.setIsBuy(1);
videoMapper.update(videoEntity); // videoMapper.update(videoEntity);
}else if (Objects.equals(goodsType, GoodsTypeEnum.SOURCE.code)) { // }else if (Objects.equals(goodsType, GoodsTypeEnum.SOURCE.code)) {
SourceEntity sourceEntity = new SourceEntity(); // SourceEntity sourceEntity = new SourceEntity();
sourceEntity.setId(goodsId); // sourceEntity.setId(goodsId);
sourceEntity.setIsBuy(1); // sourceEntity.setIsBuy(1);
sourceMapper.update(sourceEntity); // sourceMapper.update(sourceEntity);
} // }
}); });
int addOrderItems = orderMapper.addOrderItems(orderItems); int addOrderItems = orderMapper.addOrderItems(orderItems);
if (addOrderItems == NumberConstant.ZERO) { if (addOrderItems == NumberConstant.ZERO) {
@ -157,12 +157,10 @@ public class OrderServiceImpl implements OrderService {
statisticsMapper.addStatisticsRecord(statisticsRecordAddReq); statisticsMapper.addStatisticsRecord(statisticsRecordAddReq);
//TODO 封装微信支付请求 WxPayRespVO wxPayRespVO = initiatePayment(order, goodsDetailVO);
// WxPayRespVO wxPayRespVO = initiatePayment(order, goodsDetailVO); return ApiResponse.success(wxPayRespVO);
// return ApiResponse.success(wxPayRespVO);
return ApiResponse.success(null);
} }
} }
@ -187,7 +185,8 @@ public class OrderServiceImpl implements OrderService {
wxPayOrderReqVO.setOpenId(order.getOpenid()) wxPayOrderReqVO.setOpenId(order.getOpenid())
.setOrderSn(order.getId()) .setOrderSn(order.getId())
.setTotalPrice(BigDecimalUtil.convertToCents(order.getPrice())) .setTotalPrice(BigDecimalUtil.convertToCents(order.getPrice()))
.setGoodsName(goodsName); .setGoodsName(goodsName)
.setDescription("VLOG视频支付");
return wxPayService.createOrder(wxPayOrderReqVO); return wxPayService.createOrder(wxPayOrderReqVO);
} }

View File

@ -18,7 +18,7 @@ public interface WxPayService {
/** /**
* 微信支付回调 * 微信支付回调
*/ */
void payNotify(HttpServletRequest request); void payNotify(HttpServletRequest xml);
/** /**
* 微信支付结果查询 * 微信支付结果查询

View File

@ -1,6 +1,7 @@
package com.ycwl.basic.utils; package com.ycwl.basic.utils;
import cn.hutool.core.util.XmlUtil;
import com.wechat.pay.java.core.util.PemUtil; import com.wechat.pay.java.core.util.PemUtil;
import org.springframework.util.Base64Utils; import org.springframework.util.Base64Utils;
@ -8,6 +9,7 @@ import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.*; import java.security.*;
import java.util.Map;
import java.util.Random; import java.util.Random;
/** /**
@ -26,7 +28,7 @@ public class WXPayUtil {
public static String getSign(String signatureStr,String privateKey) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IOException, URISyntaxException { public static String getSign(String signatureStr,String privateKey) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, IOException, URISyntaxException {
//replace 根据实际情况不一定都需要 //replace 根据实际情况不一定都需要
String replace = privateKey.replace("\\n", "\n"); String replace = privateKey.replace("\\n", "\n");
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKeyFromPath(replace); PrivateKey merchantPrivateKey = PemUtil.loadPrivateKeyFromString(replace);
Signature sign = Signature.getInstance("SHA256withRSA"); Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(merchantPrivateKey); sign.initSign(merchantPrivateKey);
sign.update(signatureStr.getBytes(StandardCharsets.UTF_8)); sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));
@ -46,4 +48,7 @@ public class WXPayUtil {
return new String(nonceChars); return new String(nonceChars);
} }
public static Map<String, Object> xmlToMap(String xmlData) {
return XmlUtil.xmlToMap(xmlData);
}
} }

View File

@ -84,7 +84,34 @@ wx:
# 退款回调接口地址 # 退款回调接口地址
refundNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/refundNotify refundNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/refundNotify
# 商户API私钥路径 # 商户API私钥路径
keyPath: module-app/src/main/resources/cert/apiclient_key.pem keyPath: "-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
YfkdFNxtYLdVAwuylMoV3fKI
-----END PRIVATE KEY-----"
# 商户APIV3密钥 # 商户APIV3密钥
apiV3: ZHENTUAIzhentuaiZHENTUAIzhentuai apiV3: ZHENTUAIzhentuaiZHENTUAIzhentuai

View File

@ -55,11 +55,9 @@ mybatis-plus:
# 开启驼峰命名法 # 开启驼峰命名法
map-underscore-to-camel-case: true map-underscore-to-camel-case: true
use-generated-keys: true use-generated-keys: true
# 这个配置会将执行的sql打印出来在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 指定使用的日志配置文件 # 指定使用的日志配置文件
logging: logging:
config: classpath:logback-spring.xml config: classpath:logback-spring-prod.xml
# 微信小程序相关配置 # 微信小程序相关配置
wx: wx:
# 公众号的appId # 公众号的appId
@ -84,7 +82,34 @@ wx:
# 退款回调接口地址 # 退款回调接口地址
refundNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/refundNotify refundNotifyUrl: https://zhentuai.com/api/mobile/wx/pay/v1/refundNotify
# 商户API私钥路径 # 商户API私钥路径
keyPath: module-app/src/main/resources/cert/apiclient_key.pem keyPath: "-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHwDoab8iRX4vn
Ta3a+gh5Z3wcyTM3VkWhkAPJGNJhaNgzOBI9b4v1x+uSZ4To2uXhQE5hvcxWSfNZ
F7H6yp+6estADeZLpdXLBDBvPDOjEGhG7YUHJjWnFh5eY2Rtnx4/7x+xCsRS+Mtq
Mx6KMrb4UZYNIq14peTQgfICkDBdqnUIkFjDmChUy0LlsSFW8AyJIqrBec5VZWf/
QqsIBf9vsTVxrqlX+5owYZuPYoFOIQJFUW8dfU20qk//BxiDjPFZBLNa02aIEbNF
SXZE2TlKD7zD0Qv/w95Hf1V+a/cxP2B6LNtqwioIdHbU6Axu7uHkr0RSPXPsvOWY
eUIpGP4bAgMBAAECggEBALm34w3TYtKu2D/tfDh9gkWGTuHgu6q2nrTxVmOxnWEN
/v3YIzVVsfaJs2ACuZNaeqNsi7PaqNKNnSD3o/X+UHYsVy8t/THWdSl1sqapfYUd
6yYPDkEwaG/6Y6/0j1pQt+pPpNKRpSlTwqTx9HIfZvkHuhBqbokfDNhECUQS1bUu
8pmyALIkuXu38B/xCs/EH+Lp1N69IA0mwalT/2zi9ZJhGNg5OWBzNbkMKf2Tck+9
SnS6s+pAT6YxB9qYhg645H3dRKXdeSYbjI+uiIe/7cJvTxfQDLD/oDap2TJQH3iM
SVbSfNFbR1tH6PiYx9eXeElEg2QXEPztbf8NcUlGOGkCgYEA8PewLVzUdHD20KkX
tZP+JCvSTy2f0kPHTc3+BU+MOlG8uZzsK06efo+X5BGkMRj8P+MPp9rJQr5IJqJl
GpeA1XpF54v2DIcNcjrQHIJ9XWoWirZjMWRVn4D5laQTI+FEV8pyFfJJOLIgBe9b
c6hBHNnAB4Y6JZ/s+US4ymK4wQ0CgYEA1DZMcuyiUgjnprUsOIokpg8RxGLIvB5+
2FyCffa/CikMRU8bRtHdpJLguArrR9rEILU6fICPARdlCg8r0XMrvniiAaS3YlDj
tSxbfrrS6xySvVFdNusv/j3i5/76IedsSArJLeQpIZMZ3n6q/dmq4kbWh+bT/5z+
MVpjWixpYccCgYBtaEh5kDh2VgP6YYv+SZ+OVMc8Y/64vUV0sh6v0ppcsFf7/p/M
WfnkhNX2G3xtPmbpqvKkx9WxlCu2Pu2g0UERrF6o7wdcUMVuI/3xs92v2Ec72+vV
tTSbIzgvFTwLgnBBXA3IoSVVtKqNh0wCi1Zk/wkNYYhtJNu3odg1K/Wu0QKBgBOv
IbI7TucrGkm1Xm+0KKgal7xOqW4BqiRpmFUU0S2hFxlKuC3+g3+jfCK2KJLWsQCT
ruQjjKA+Skn/lEHuW+1kBSr/217MQALrJWWA8NWMJfRXmrzgXehIV0bLuOnyLHIW
Rgjys/oAShMATt4TFa29gmLCv4FjT5TGXJbdrby7AoGBAOqER71Vi90UV84sYLWx
DSW/3q5/QrndmeeaQALslA6sidnTZWqlhMsNPl8dfBKl6xnrCdcaeY5xk/xmVOqP
0KedJgT+IjLwY1yJ9QOBd02ejAY3qNlKt2NiSWv2GBY1cZxqhkHNaI/UWI9CAyH5
YfkdFNxtYLdVAwuylMoV3fKI
-----END PRIVATE KEY-----"
# 商户APIV3密钥 # 商户APIV3密钥
apiV3: ZHENTUAIzhentuaiZHENTUAIzhentuai apiV3: ZHENTUAIzhentuaiZHENTUAIzhentuai

View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- appender是configuration的子节点是负责写日志的组件。 -->
<!-- ConsoleAppender把日志输出到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 默认情况下,每个日志事件都会立即刷新到基础输出流。 这种默认方法更安全因为如果应用程序在没有正确关闭appender的情况下退出则日志事件不会丢失。
但是为了显着增加日志记录吞吐量您可能希望将immediateFlush属性设置为false -->
<!--<immediateFlush>true</immediateFlush>-->
<encoder>
<!-- %37():如果字符没有37个字符长度,则左侧用空格补齐 -->
<!-- %-37():如果字符没有37个字符长度,则右侧用空格补齐 -->
<!-- %15.15():如果记录的线程字符长度小于15(第一个)则用空格在左侧补齐,如果字符长度大于15(第二个),则从开头开始截断多余的字符 -->
<!-- %-40.40():如果记录的logger字符长度小于40(第一个)则用空格在右侧补齐,如果字符长度大于40(第二个),则从开头开始截断多余的字符 -->
<!-- %msg日志打印详情 -->
<!-- %n:换行符 -->
<!-- %highlight():转换说明符以粗体红色显示其级别为ERROR的事件红色为WARNBLUE为INFO以及其他级别的默认颜色。 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) --- [%15.15(%thread)] %cyan(%-40.40(%logger{40})) : %msg%n</pattern>
<!-- 控制台也要使用UTF-8不要使用GBK否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- info 日志-->
<!-- RollingFileAppender滚动记录文件先将日志记录到指定文件当符合某个条件时将日志记录到其他文件 -->
<!-- 以下的大概意思是1.先按日期存日志日期变了将前一天的日志文件名重命名为XXX%日期%索引新的日志仍然是project_info.log -->
<!-- 2.如果日期没有发生变化但是当前日志的文件大小超过10MB时对当前日志进行分割 重命名-->
<appender name="info_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件路径和名称-->
<File>logs/project_info.log</File>
<!--是否追加到文件末尾,默认为true-->
<append>true</append>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch><!-- 如果命中ERROR就禁止这条日志 -->
<onMismatch>ACCEPT</onMismatch><!-- 如果没有命中就使用这条规则 -->
</filter>
<!--有两个与RollingFileAppender交互的重要子组件。 第一个RollingFileAppender子组件即RollingPolicy:负责执行翻转所需的操作。
RollingFileAppender的第二个子组件即TriggeringPolicy:将确定是否以及何时发生翻转。 因此RollingPolicy负责什么和TriggeringPolicy负责什么时候.
作为任何用途RollingFileAppender必须同时设置RollingPolicy和TriggeringPolicy,但是如果其RollingPolicy也实现了TriggeringPolicy接口则只需要显式指定前者。-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件的名字会根据fileNamePattern的值每隔一段时间改变一次 -->
<!-- 文件名logs/project_info.2017-12-05.0.log -->
<!-- 注意SizeAndTimeBasedRollingPolicy中 i和d令牌都是强制性的必须存在要不会报错 -->
<fileNamePattern>logs/project_info.%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天, ps:maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的,例如上面选用了yyyy-MM-dd,则单位为天
如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd-->
<maxHistory>30</maxHistory>
<!-- 每个日志文件到10mb的时候开始切分最多保留30天但最大到20GB哪怕没到30天也要删除多余的日志 -->
<totalSizeCap>20GB</totalSizeCap>
<!-- maxFileSize:这是活动文件的大小默认值是10MB测试时可改成5KB看效果 -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<!--编码器-->
<encoder>
<!-- pattern节点用来设置日志的输入格式 ps:日志文件中没有设置颜色,否则颜色部分会有ESC[0:39em等乱码-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n</pattern>
<!-- 记录日志的编码:此处设置字符集 - -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- error 日志-->
<!-- RollingFileAppender滚动记录文件先将日志记录到指定文件当符合某个条件时将日志记录到其他文件 -->
<!-- 以下的大概意思是1.先按日期存日志日期变了将前一天的日志文件名重命名为XXX%日期%索引新的日志仍然是project_error.log -->
<!-- 2.如果日期没有发生变化但是当前日志的文件大小超过10MB时对当前日志进行分割 重命名-->
<appender name="error_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件路径和名称-->
<File>logs/project_error.log</File>
<!--是否追加到文件末尾,默认为true-->
<append>true</append>
<!-- ThresholdFilter过滤低于指定阈值的事件。 对于等于或高于阈值的事件ThresholdFilter将在调用其decision方法时响应NEUTRAL。 但是,将拒绝级别低于阈值的事件 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level><!-- 低于ERROR级别的日志debug,info将被拒绝等于或者高于ERROR的级别将相应NEUTRAL -->
</filter>
<!--有两个与RollingFileAppender交互的重要子组件。 第一个RollingFileAppender子组件即RollingPolicy:负责执行翻转所需的操作。
RollingFileAppender的第二个子组件即TriggeringPolicy:将确定是否以及何时发生翻转。 因此RollingPolicy负责什么和TriggeringPolicy负责什么时候.
作为任何用途RollingFileAppender必须同时设置RollingPolicy和TriggeringPolicy,但是如果其RollingPolicy也实现了TriggeringPolicy接口则只需要显式指定前者。-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值每隔一段时间改变一次 -->
<!-- 文件名logs/project_error.2017-12-05.0.log -->
<!-- 注意SizeAndTimeBasedRollingPolicy中 i和d令牌都是强制性的必须存在要不会报错 -->
<fileNamePattern>logs/project_error.%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天, ps:maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的,例如上面选用了yyyy-MM-dd,则单位为天
如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd-->
<maxHistory>30</maxHistory>
<!-- 每个日志文件到10mb的时候开始切分最多保留30天但最大到20GB哪怕没到30天也要删除多余的日志 -->
<totalSizeCap>20GB</totalSizeCap>
<!-- maxFileSize:这是活动文件的大小默认值是10MB测试时可改成5KB看效果 -->
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<!--编码器-->
<encoder>
<!-- pattern节点用来设置日志的输入格式 ps:日志文件中没有设置颜色,否则颜色部分会有ESC[0:39em等乱码-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n</pattern>
<!-- 记录日志的编码:此处设置字符集 - -->
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="sql_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>logs/project_sql.log</File>
<append>true</append>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/project_sql.%d.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--给定记录器的每个启用的日志记录请求都将转发到该记录器中的所有appender以及层次结构中较高的appender不用在意level值
换句话说appender是从记录器层次结构中附加地继承的。
例如如果将控制台appender添加到根记录器则所有启用的日志记录请求将至少在控制台上打印。
如果另外将文件追加器添加到记录器例如L则对L和L'子项启用的记录请求将打印在文件和控制台上。
通过将记录器的additivity标志设置为false可以覆盖此默认行为以便不再添加appender累积-->
<!-- configuration中最多允许一个root别的logger如果没有设置级别则从父级别root继承 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
<!-- 级别依次为【从高到低】FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
<logger name="com.ycwl.basic" level="INFO">
<appender-ref ref="info_log" />
<appender-ref ref="error_log" />
</logger>
<!-- 利用logback输入mybatis的sql日志
注意:如果不加 additivity="false" 则此logger会将输出转发到自身以及祖先的logger中就会出现日志文件中sql重复打印-->
<logger name="com.ycwl.basic.mapper" level="DEBUG" additivity="false">
<appender-ref ref="sql_log" />
</logger>
</configuration>