Commit 3e3bcc963da25b5dd1eb5cec09321a0adb48773c

Authored by YunaiV
2 parents e2edd7a4 5b6723fc

Merge branch 'develop' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17

yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java
@@ -21,7 +21,8 @@ import org.springframework.context.annotation.Bean; @@ -21,7 +21,8 @@ import org.springframework.context.annotation.Bean;
21 @AutoConfiguration 21 @AutoConfiguration
22 @ConditionalOnClass(name = { 22 @ConditionalOnClass(name = {
23 "org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer", 23 "org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer",
24 - "io.opentracing.Tracer" 24 + "io.opentracing.Tracer",
  25 + "jakarta.servlet.Filter"
25 }) 26 })
26 @EnableConfigurationProperties(TracerProperties.class) 27 @EnableConfigurationProperties(TracerProperties.class)
27 @ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true) 28 @ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true)
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.SortingField; @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.pojo.SortingField;
9 import cn.iocoder.yudao.framework.mybatis.core.enums.DbTypeEnum; 9 import cn.iocoder.yudao.framework.mybatis.core.enums.DbTypeEnum;
10 import com.baomidou.mybatisplus.annotation.DbType; 10 import com.baomidou.mybatisplus.annotation.DbType;
11 import com.baomidou.mybatisplus.core.conditions.Wrapper; 11 import com.baomidou.mybatisplus.core.conditions.Wrapper;
  12 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
12 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 13 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
13 import com.baomidou.mybatisplus.core.metadata.OrderItem; 14 import com.baomidou.mybatisplus.core.metadata.OrderItem;
14 import com.baomidou.mybatisplus.core.toolkit.StringPool; 15 import com.baomidou.mybatisplus.core.toolkit.StringPool;
@@ -47,16 +48,36 @@ public class MyBatisUtils { @@ -47,16 +48,36 @@ public class MyBatisUtils {
47 return page; 48 return page;
48 } 49 }
49 50
  51 + @SuppressWarnings("PatternVariableCanBeUsed")
50 public static <T> void addOrder(Wrapper<T> wrapper, Collection<SortingField> sortingFields) { 52 public static <T> void addOrder(Wrapper<T> wrapper, Collection<SortingField> sortingFields) {
51 if (CollUtil.isEmpty(sortingFields)) { 53 if (CollUtil.isEmpty(sortingFields)) {
52 return; 54 return;
53 } 55 }
54 - QueryWrapper<T> query = (QueryWrapper<T>) wrapper;  
55 - for (SortingField sortingField : sortingFields) {  
56 - query.orderBy(true,  
57 - SortingField.ORDER_ASC.equals(sortingField.getOrder()),  
58 - StrUtil.toUnderlineCase(sortingField.getField())); 56 + if (wrapper instanceof QueryWrapper<T>) {
  57 + QueryWrapper<T> query = (QueryWrapper<T>) wrapper;
  58 + for (SortingField sortingField : sortingFields) {
  59 + query.orderBy(true,
  60 + SortingField.ORDER_ASC.equals(sortingField.getOrder()),
  61 + StrUtil.toUnderlineCase(sortingField.getField()));
  62 + }
  63 + } else if (wrapper instanceof LambdaQueryWrapper<T>) {
  64 + // LambdaQueryWrapper 不直接支持字符串字段排序,使用 last 方法拼接 ORDER BY
  65 + LambdaQueryWrapper<T> lambdaQuery = (LambdaQueryWrapper<T>) wrapper;
  66 + StringBuilder orderBy = new StringBuilder();
  67 + for (SortingField sortingField : sortingFields) {
  68 + if (StrUtil.isNotEmpty(orderBy)) {
  69 + orderBy.append(", ");
  70 + }
  71 + orderBy.append(StrUtil.toUnderlineCase(sortingField.getField()))
  72 + .append(" ")
  73 + .append(SortingField.ORDER_ASC.equals(sortingField.getOrder()) ? "ASC" : "DESC");
  74 + }
  75 + lambdaQuery.last("ORDER BY " + orderBy);
  76 + // 另外个思路:https://blog.csdn.net/m0_59084856/article/details/138450913
  77 + } else {
  78 + throw new IllegalArgumentException("Unsupported wrapper type: " + wrapper.getClass().getName());
59 } 79 }
  80 +
60 } 81 }
61 82
62 /** 83 /**
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/encrypt/core/filter/ApiEncryptFilter.java
@@ -128,6 +128,7 @@ public class ApiEncryptFilter extends ApiRequestFilter { @@ -128,6 +128,7 @@ public class ApiEncryptFilter extends ApiRequestFilter {
128 * 128 *
129 * @param request 请求 129 * @param request 请求
130 */ 130 */
  131 + @SuppressWarnings("PatternVariableCanBeUsed")
131 private ApiEncrypt getApiEncrypt(HttpServletRequest request) { 132 private ApiEncrypt getApiEncrypt(HttpServletRequest request) {
132 try { 133 try {
133 HandlerExecutionChain mappingHandler = requestMappingHandlerMapping.getHandler(request); 134 HandlerExecutionChain mappingHandler = requestMappingHandlerMapping.getHandler(request);
@@ -135,7 +136,8 @@ public class ApiEncryptFilter extends ApiRequestFilter { @@ -135,7 +136,8 @@ public class ApiEncryptFilter extends ApiRequestFilter {
135 return null; 136 return null;
136 } 137 }
137 Object handler = mappingHandler.getHandler(); 138 Object handler = mappingHandler.getHandler();
138 - if (handler instanceof HandlerMethod handlerMethod) { 139 + if (handler instanceof HandlerMethod) {
  140 + HandlerMethod handlerMethod = (HandlerMethod) handler;
139 ApiEncrypt annotation = handlerMethod.getMethodAnnotation(ApiEncrypt.class); 141 ApiEncrypt annotation = handlerMethod.getMethodAnnotation(ApiEncrypt.class);
140 if (annotation == null) { 142 if (annotation == null) {
141 annotation = handlerMethod.getBeanType().getAnnotation(ApiEncrypt.class); 143 annotation = handlerMethod.getBeanType().getAnnotation(ApiEncrypt.class);
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
@@ -36,6 +36,7 @@ import org.springframework.web.bind.MissingServletRequestParameterException; @@ -36,6 +36,7 @@ import org.springframework.web.bind.MissingServletRequestParameterException;
36 import org.springframework.web.bind.annotation.ExceptionHandler; 36 import org.springframework.web.bind.annotation.ExceptionHandler;
37 import org.springframework.web.bind.annotation.RestControllerAdvice; 37 import org.springframework.web.bind.annotation.RestControllerAdvice;
38 import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; 38 import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
  39 +import org.springframework.web.multipart.MaxUploadSizeExceededException;
39 import org.springframework.web.servlet.NoHandlerFoundException; 40 import org.springframework.web.servlet.NoHandlerFoundException;
40 import org.springframework.web.servlet.resource.NoResourceFoundException; 41 import org.springframework.web.servlet.resource.NoResourceFoundException;
41 42
@@ -93,6 +94,9 @@ public class GlobalExceptionHandler { @@ -93,6 +94,9 @@ public class GlobalExceptionHandler {
93 if (ex instanceof ValidationException) { 94 if (ex instanceof ValidationException) {
94 return validationException((ValidationException) ex); 95 return validationException((ValidationException) ex);
95 } 96 }
  97 + if (ex instanceof MaxUploadSizeExceededException) {
  98 + return maxUploadSizeExceededExceptionHandler((MaxUploadSizeExceededException) ex);
  99 + }
96 if (ex instanceof NoHandlerFoundException) { 100 if (ex instanceof NoHandlerFoundException) {
97 return noHandlerFoundExceptionHandler((NoHandlerFoundException) ex); 101 return noHandlerFoundExceptionHandler((NoHandlerFoundException) ex);
98 } 102 }
@@ -111,9 +115,6 @@ public class GlobalExceptionHandler { @@ -111,9 +115,6 @@ public class GlobalExceptionHandler {
111 if (ex instanceof AccessDeniedException) { 115 if (ex instanceof AccessDeniedException) {
112 return accessDeniedExceptionHandler(request, (AccessDeniedException) ex); 116 return accessDeniedExceptionHandler(request, (AccessDeniedException) ex);
113 } 117 }
114 - if (ex instanceof UncheckedExecutionException && ex.getCause() != ex) {  
115 - return allExceptionHandler(request, ex.getCause());  
116 - }  
117 return defaultExceptionHandler(request, ex); 118 return defaultExceptionHandler(request, ex);
118 } 119 }
119 120
@@ -214,6 +215,14 @@ public class GlobalExceptionHandler { @@ -214,6 +215,14 @@ public class GlobalExceptionHandler {
214 } 215 }
215 216
216 /** 217 /**
  218 + * 处理上传文件过大异常
  219 + */
  220 + @ExceptionHandler(MaxUploadSizeExceededException.class)
  221 + public CommonResult<?> maxUploadSizeExceededExceptionHandler(MaxUploadSizeExceededException ex) {
  222 + return CommonResult.error(BAD_REQUEST.getCode(), "上传文件过大,请调整后重试");
  223 + }
  224 +
  225 + /**
217 * 处理 SpringMVC 请求地址不存在 226 * 处理 SpringMVC 请求地址不存在
218 * 227 *
219 * 注意,它需要设置如下两个配置项: 228 * 注意,它需要设置如下两个配置项:
@@ -309,6 +318,12 @@ public class GlobalExceptionHandler { @@ -309,6 +318,12 @@ public class GlobalExceptionHandler {
309 */ 318 */
310 @ExceptionHandler(value = Exception.class) 319 @ExceptionHandler(value = Exception.class)
311 public CommonResult<?> defaultExceptionHandler(HttpServletRequest req, Throwable ex) { 320 public CommonResult<?> defaultExceptionHandler(HttpServletRequest req, Throwable ex) {
  321 + // 特殊:如果是 ServiceException 的异常,则直接返回
  322 + // 例如说:https://gitee.com/zhijiantianya/yudao-cloud/issues/ICSSRM、https://gitee.com/zhijiantianya/yudao-cloud/issues/ICT6FM
  323 + if (ex.getCause() != null && ex.getCause() instanceof ServiceException) {
  324 + return serviceExceptionHandler((ServiceException) ex.getCause());
  325 + }
  326 +
312 // 情况一:处理表不存在的异常 327 // 情况一:处理表不存在的异常
313 CommonResult<?> tableNotExistsResult = handleTableNotExists(ex); 328 CommonResult<?> tableNotExistsResult = handleTableNotExists(ex);
314 if (tableNotExistsResult != null) { 329 if (tableNotExistsResult != null) {
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java
@@ -30,7 +30,7 @@ public interface CouponConvert { @@ -30,7 +30,7 @@ public interface CouponConvert {
30 CouponRespDTO convert(CouponDO bean); 30 CouponRespDTO convert(CouponDO bean);
31 31
32 default CouponDO convert(CouponTemplateDO template, Long userId) { 32 default CouponDO convert(CouponTemplateDO template, Long userId) {
33 - CouponDO couponDO = new CouponDO() 33 + CouponDO coupon = new CouponDO()
34 .setTemplateId(template.getId()) 34 .setTemplateId(template.getId())
35 .setName(template.getName()) 35 .setName(template.getName())
36 .setTakeType(template.getTakeType()) 36 .setTakeType(template.getTakeType())
@@ -44,13 +44,13 @@ public interface CouponConvert { @@ -44,13 +44,13 @@ public interface CouponConvert {
44 .setStatus(CouponStatusEnum.UNUSED.getStatus()) 44 .setStatus(CouponStatusEnum.UNUSED.getStatus())
45 .setUserId(userId); 45 .setUserId(userId);
46 if (CouponTemplateValidityTypeEnum.DATE.getType().equals(template.getValidityType())) { 46 if (CouponTemplateValidityTypeEnum.DATE.getType().equals(template.getValidityType())) {
47 - couponDO.setValidStartTime(template.getValidStartTime());  
48 - couponDO.setValidEndTime(template.getValidEndTime()); 47 + coupon.setValidStartTime(template.getValidStartTime());
  48 + coupon.setValidEndTime(template.getValidEndTime());
49 } else if (CouponTemplateValidityTypeEnum.TERM.getType().equals(template.getValidityType())) { 49 } else if (CouponTemplateValidityTypeEnum.TERM.getType().equals(template.getValidityType())) {
50 - couponDO.setValidStartTime(LocalDateTime.now().plusDays(template.getFixedStartTerm()));  
51 - couponDO.setValidEndTime(LocalDateTime.now().plusDays(template.getFixedEndTerm())); 50 + coupon.setValidStartTime(LocalDateTime.now().plusDays(template.getFixedStartTerm()));
  51 + coupon.setValidEndTime(coupon.getValidStartTime().plusDays(template.getFixedEndTerm()));
52 } 52 }
53 - return couponDO; 53 + return coupon;
54 } 54 }
55 55
56 CouponPageReqVO convert(AppCouponPageReqVO pageReqVO, Collection<Long> userIds); 56 CouponPageReqVO convert(AppCouponPageReqVO pageReqVO, Collection<Long> userIds);
yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeStatusSyncToWxaOrderHandler.java
@@ -42,6 +42,40 @@ public class TradeStatusSyncToWxaOrderHandler implements TradeOrderHandler { @@ -42,6 +42,40 @@ public class TradeStatusSyncToWxaOrderHandler implements TradeOrderHandler {
42 if (ObjUtil.notEqual(order.getPayChannelCode(), PayChannelEnum.WX_LITE.getCode())) { 42 if (ObjUtil.notEqual(order.getPayChannelCode(), PayChannelEnum.WX_LITE.getCode())) {
43 return; 43 return;
44 } 44 }
  45 +
  46 + // 上传订单物流信息到微信小程序
  47 + uploadWxaOrderShippingInfo(order);
  48 + }
  49 +
  50 + @Override
  51 + public void afterReceiveOrder(TradeOrderDO order) {
  52 + // 注意:只有微信小程序支付的订单,才需要同步
  53 + if (ObjUtil.notEqual(order.getPayChannelCode(), PayChannelEnum.WX_LITE.getCode())) {
  54 + return;
  55 + }
  56 + PayOrderRespDTO payOrder = payOrderApi.getOrder(order.getPayOrderId());
  57 + SocialWxaOrderNotifyConfirmReceiveReqDTO reqDTO = new SocialWxaOrderNotifyConfirmReceiveReqDTO()
  58 + .setTransactionId(payOrder.getChannelOrderNo())
  59 + .setReceivedTime(order.getReceiveTime());
  60 + try {
  61 + socialClientApi.notifyWxaOrderConfirmReceive(UserTypeEnum.MEMBER.getValue(), reqDTO);
  62 + } catch (Exception ex) {
  63 + log.error("[afterReceiveOrder][订单({}) 通知订单收货到微信小程序失败]", order, ex);
  64 + }
  65 +
  66 + // 如果是门店自提订单,上传订单物流信息到微信小程序
  67 + // 原因是,门店自提订单没有 “afterDeliveryOrder” 阶段。可见 https://t.zsxq.com/KWD3u 反馈
  68 + if (DeliveryTypeEnum.PICK_UP.getType().equals(order.getDeliveryType())) {
  69 + uploadWxaOrderShippingInfo(order);
  70 + }
  71 + }
  72 +
  73 + /**
  74 + * 上传订单物流信息到微信小程序
  75 + *
  76 + * @param order 订单
  77 + */
  78 + private void uploadWxaOrderShippingInfo(TradeOrderDO order) {
45 PayOrderRespDTO payOrder = payOrderApi.getOrder(order.getPayOrderId()); 79 PayOrderRespDTO payOrder = payOrderApi.getOrder(order.getPayOrderId());
46 SocialWxaOrderUploadShippingInfoReqDTO reqDTO = new SocialWxaOrderUploadShippingInfoReqDTO() 80 SocialWxaOrderUploadShippingInfoReqDTO reqDTO = new SocialWxaOrderUploadShippingInfoReqDTO()
47 .setTransactionId(payOrder.getChannelOrderNo()) 81 .setTransactionId(payOrder.getChannelOrderNo())
@@ -64,23 +98,6 @@ public class TradeStatusSyncToWxaOrderHandler implements TradeOrderHandler { @@ -64,23 +98,6 @@ public class TradeStatusSyncToWxaOrderHandler implements TradeOrderHandler {
64 } 98 }
65 } 99 }
66 100
67 - @Override  
68 - public void afterReceiveOrder(TradeOrderDO order) {  
69 - // 注意:只有微信小程序支付的订单,才需要同步  
70 - if (ObjUtil.notEqual(order.getPayChannelCode(), PayChannelEnum.WX_LITE.getCode())) {  
71 - return;  
72 - }  
73 - PayOrderRespDTO payOrder = payOrderApi.getOrder(order.getPayOrderId());  
74 - SocialWxaOrderNotifyConfirmReceiveReqDTO reqDTO = new SocialWxaOrderNotifyConfirmReceiveReqDTO()  
75 - .setTransactionId(payOrder.getChannelOrderNo())  
76 - .setReceivedTime(order.getReceiveTime());  
77 - try {  
78 - socialClientApi.notifyWxaOrderConfirmReceive(UserTypeEnum.MEMBER.getValue(), reqDTO);  
79 - } catch (Exception ex) {  
80 - log.error("[afterReceiveOrder][订单({}) 通知订单收货到微信小程序失败]", order, ex);  
81 - }  
82 - }  
83 -  
84 // TODO @芋艿:【设置路径】 https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E5%85%AD%E3%80%81%E6%B6%88%E6%81%AF%E8%B7%B3%E8%BD%AC%E8%B7%AF%E5%BE%84%E8%AE%BE%E7%BD%AE%E6%8E%A5%E5%8F%A3 101 // TODO @芋艿:【设置路径】 https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E5%85%AD%E3%80%81%E6%B6%88%E6%81%AF%E8%B7%B3%E8%BD%AC%E8%B7%AF%E5%BE%84%E8%AE%BE%E7%BD%AE%E6%8E%A5%E5%8F%A3
85 102
86 } 103 }