Skip to content

Commit e46163c

Browse files
committed
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # yudao-dependencies/pom.xml
2 parents cd2c6d2 + 0bbc682 commit e46163c

File tree

16 files changed

+256
-123
lines changed

16 files changed

+256
-123
lines changed

sql/mysql/ruoyi-vue-pro.sql

+84-24
Large diffs are not rendered by default.

sql/postgresql/ruoyi-vue-pro.sql

+97
Large diffs are not rendered by default.

yudao-dependencies/pom.xml

+4-16
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,9 @@
6868
<netty.version>4.1.113.Final</netty.version>
6969
<mqtt.version>1.2.5</mqtt.version>
7070
<!-- 三方云服务相关 -->
71-
<okio.version>3.5.0</okio.version>
72-
<okhttp3.version>4.11.0</okhttp3.version>
7371
<commons-io.version>2.17.0</commons-io.version>
7472
<commons-compress.version>1.27.1</commons-compress.version>
75-
<minio.version>8.5.7</minio.version>
73+
<aws-java-sdk-s3.version>1.12.777</aws-java-sdk-s3.version>
7674
<justauth.version>1.0.8</justauth.version>
7775
<jimureport.version>1.7.8</jimureport.version>
7876
<weixin-java.version>4.6.0</weixin-java.version>
@@ -571,19 +569,9 @@
571569

572570
<!-- 三方云服务相关 -->
573571
<dependency>
574-
<groupId>com.squareup.okio</groupId>
575-
<artifactId>okio</artifactId>
576-
<version>${okio.version}</version>
577-
</dependency>
578-
<dependency>
579-
<groupId>com.squareup.okhttp3</groupId>
580-
<artifactId>okhttp</artifactId>
581-
<version>${okhttp3.version}</version>
582-
</dependency>
583-
<dependency>
584-
<groupId>io.minio</groupId>
585-
<artifactId>minio</artifactId>
586-
<version>${minio.version}</version>
572+
<groupId>com.amazonaws</groupId>
573+
<artifactId>aws-java-sdk-s3</artifactId>
574+
<version>${aws-java-sdk-s3.version}</version>
587575
</dependency>
588576

589577
<dependency>

yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/job/TenantJobAspect.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public String around(ProceedingJoinPoint joinPoint, TenantJob tenantJob) {
4646
TenantUtils.execute(tenantId, () -> {
4747
try {
4848
Object result = joinPoint.proceed();
49-
results.put(tenantId, StrUtil.toStringOrNull(result));
49+
results.put(tenantId, StrUtil.toStringOrEmpty(result));
5050
} catch (Throwable e) {
5151
log.error("[execute][租户({}) 执行 Job 发生异常", tenantId, e);
5252
results.put(tenantId, ExceptionUtil.getRootCauseMessage(e));

yudao-module-infra/yudao-module-infra-biz/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@
116116
<artifactId>jsch</artifactId> <!-- 文件客户端:解决 sftp 连接 -->
117117
</dependency>
118118
<dependency>
119-
<groupId>io.minio</groupId>
120-
<artifactId>minio</artifactId> <!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 -->
119+
<groupId>com.amazonaws</groupId>
120+
<artifactId>aws-java-sdk-s3</artifactId><!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 -->
121121
</dependency>
122122

123123
<dependency>

yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java

+44-69
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@
44
import cn.hutool.core.util.StrUtil;
55
import cn.hutool.http.HttpUtil;
66
import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient;
7-
import io.minio.*;
8-
import io.minio.http.Method;
7+
import com.amazonaws.HttpMethod;
8+
import com.amazonaws.auth.AWSStaticCredentialsProvider;
9+
import com.amazonaws.auth.BasicAWSCredentials;
10+
import com.amazonaws.client.builder.AwsClientBuilder;
11+
import com.amazonaws.services.s3.AmazonS3Client;
12+
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
13+
import com.amazonaws.services.s3.model.ObjectMetadata;
14+
import com.amazonaws.services.s3.model.S3Object;
915

1016
import java.io.ByteArrayInputStream;
17+
import java.util.Date;
1118
import java.util.concurrent.TimeUnit;
1219

1320
/**
@@ -19,7 +26,7 @@
1926
*/
2027
public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
2128

22-
private MinioClient client;
29+
private AmazonS3Client client;
2330

2431
public S3FileClient(Long id, S3FileClientConfig config) {
2532
super(id, config);
@@ -32,25 +39,30 @@ protected void doInit() {
3239
config.setDomain(buildDomain());
3340
}
3441
// 初始化客户端
35-
client = MinioClient.builder()
36-
.endpoint(buildEndpointURL()) // Endpoint URL
37-
.region(buildRegion()) // Region
38-
.credentials(config.getAccessKey(), config.getAccessSecret()) // 认证密钥
42+
client = (AmazonS3Client)AmazonS3ClientBuilder.standard()
43+
.withCredentials(buildCredentials())
44+
.withEndpointConfiguration(buildEndpointConfiguration())
3945
.build();
40-
enableVirtualStyleEndpoint();
4146
}
4247

4348
/**
44-
* 基于 endpoint 构建调用云服务的 URL 地址
49+
* 基于 config 秘钥,构建 S3 客户端的认证信息
4550
*
46-
* @return URI 地址
51+
* @return S3 客户端的认证信息
4752
*/
48-
private String buildEndpointURL() {
49-
// 如果已经是 http 或者 https,则不进行拼接.主要适配 MinIO
50-
if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) {
51-
return config.getEndpoint();
52-
}
53-
return StrUtil.format("https://{}", config.getEndpoint());
53+
private AWSStaticCredentialsProvider buildCredentials() {
54+
return new AWSStaticCredentialsProvider(
55+
new BasicAWSCredentials(config.getAccessKey(), config.getAccessSecret()));
56+
}
57+
58+
/**
59+
* 构建 S3 客户端的 Endpoint 配置,包括 region、endpoint
60+
*
61+
* @return S3 客户端的 EndpointConfiguration 配置
62+
*/
63+
private AwsClientBuilder.EndpointConfiguration buildEndpointConfiguration() {
64+
return new AwsClientBuilder.EndpointConfiguration(config.getEndpoint(),
65+
null); // 无需设置 region
5466
}
5567

5668
/**
@@ -67,76 +79,39 @@ private String buildDomain() {
6779
return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint());
6880
}
6981

70-
/**
71-
* 基于 bucket 构建 region 地区
72-
*
73-
* @return region 地区
74-
*/
75-
private String buildRegion() {
76-
// 阿里云必须有 region,否则会报错
77-
if (config.getEndpoint().contains(S3FileClientConfig.ENDPOINT_ALIYUN)) {
78-
return StrUtil.subBefore(config.getEndpoint(), '.', false)
79-
.replaceAll("-internal", "")// 去除内网 Endpoint 的后缀
80-
.replaceAll("https://", "");
81-
}
82-
// 腾讯云必须有 region,否则会报错
83-
if (config.getEndpoint().contains(S3FileClientConfig.ENDPOINT_TENCENT)) {
84-
return StrUtil.subAfter(config.getEndpoint(), "cos.", false)
85-
.replaceAll("." + S3FileClientConfig.ENDPOINT_TENCENT, ""); // 去除 Endpoint
86-
}
87-
return null;
88-
}
89-
90-
/**
91-
* 开启 VirtualStyle 模式
92-
*/
93-
private void enableVirtualStyleEndpoint() {
94-
if (StrUtil.containsAny(config.getEndpoint(),
95-
S3FileClientConfig.ENDPOINT_TENCENT, // 腾讯云 https://cloud.tencent.com/document/product/436/41284
96-
S3FileClientConfig.ENDPOINT_VOLCES)) { // 火山云 https://www.volcengine.com/docs/6349/1288493
97-
client.enableVirtualStyleEndpoint();
98-
}
99-
}
100-
10182
@Override
10283
public String upload(byte[] content, String path, String type) throws Exception {
84+
// 元数据,主要用于设置文件类型
85+
ObjectMetadata objectMetadata = new ObjectMetadata();
86+
objectMetadata.setContentType(type);
87+
objectMetadata.setContentLength(content.length); // 如果不设置,会有 “ No content length specified for stream data” 警告日志
10388
// 执行上传
104-
client.putObject(PutObjectArgs.builder()
105-
.bucket(config.getBucket()) // bucket 必须传递
106-
.contentType(type)
107-
.object(path) // 相对路径作为 key
108-
.stream(new ByteArrayInputStream(content), content.length, -1) // 文件内容
109-
.build());
89+
client.putObject(config.getBucket(),
90+
path, // 相对路径
91+
new ByteArrayInputStream(content), // 文件内容
92+
objectMetadata);
93+
11094
// 拼接返回路径
11195
return config.getDomain() + "/" + path;
11296
}
11397

11498
@Override
11599
public void delete(String path) throws Exception {
116-
client.removeObject(RemoveObjectArgs.builder()
117-
.bucket(config.getBucket()) // bucket 必须传递
118-
.object(path) // 相对路径作为 key
119-
.build());
100+
client.deleteObject(config.getBucket(), path);
120101
}
121102

122103
@Override
123104
public byte[] getContent(String path) throws Exception {
124-
GetObjectResponse response = client.getObject(GetObjectArgs.builder()
125-
.bucket(config.getBucket()) // bucket 必须传递
126-
.object(path) // 相对路径作为 key
127-
.build());
128-
return IoUtil.readBytes(response);
105+
S3Object tempS3Object = client.getObject(config.getBucket(), path);
106+
return IoUtil.readBytes(tempS3Object.getObjectContent());
129107
}
130108

131109
@Override
132110
public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception {
133-
String uploadUrl = client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
134-
.method(Method.PUT)
135-
.bucket(config.getBucket())
136-
.object(path)
137-
.expiry(10, TimeUnit.MINUTES) // 过期时间(秒数)取值范围:1 秒 ~ 7 天
138-
.build()
139-
);
111+
// 设定过期时间为 10 分钟。取值范围:1 秒 ~ 7 天
112+
Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(10));
113+
// 生成上传 URL
114+
String uploadUrl = String.valueOf(client.generatePresignedUrl(config.getBucket(), path, expiration , HttpMethod.PUT));
140115
return new FilePresignedUrlRespDTO(uploadUrl, config.getDomain() + "/" + path);
141116
}
142117

yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ public class S3FileClientConfig implements FileClientConfig {
2828
* 2. 阿里云:https://help.aliyun.com/document_detail/31837.html
2929
* 3. 腾讯云:https://cloud.tencent.com/document/product/436/6224
3030
* 4. 七牛云:https://developer.qiniu.com/kodo/4088/s3-access-domainname
31-
* 5. 华为云:https://developer.huaweicloud.com/endpoint?OBS
31+
* 5. 华为云:https://console.huaweicloud.com/apiexplorer/#/endpoint/OBS
32+
* 6. 火山云:https://www.volcengine.com/docs/6349/107356
3233
*/
3334
@NotNull(message = "endpoint 不能为空")
3435
private String endpoint;
@@ -39,6 +40,7 @@ public class S3FileClientConfig implements FileClientConfig {
3940
* 3. 腾讯云:https://cloud.tencent.com/document/product/436/11142
4041
* 4. 七牛云:https://developer.qiniu.com/kodo/8556/set-the-custom-source-domain-name
4142
* 5. 华为云:https://support.huaweicloud.com/usermanual-obs/obs_03_0032.html
43+
* 6. 火山云:https://www.volcengine.com/docs/6349/128983
4244
*/
4345
@URL(message = "domain 必须是 URL 格式")
4446
private String domain;
@@ -55,6 +57,7 @@ public class S3FileClientConfig implements FileClientConfig {
5557
* 3. 腾讯云:https://console.cloud.tencent.com/cam/capi
5658
* 4. 七牛云:https://portal.qiniu.com/user/key
5759
* 5. 华为云:https://support.huaweicloud.com/qs-obs/obs_qs_0005.html
60+
* 6. 火山云:https://console.volcengine.com/iam/keymanage/
5861
*/
5962
@NotNull(message = "accessKey 不能为空")
6063
private String accessKey;

yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ public static class Product {
6363
@Min(value = 0, message = "优惠金额需要大于等于 0")
6464
private Integer discountPrice;
6565

66-
@AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99")
66+
@AssertTrue(message = "折扣百分比需要大于等于 0.01%,小于等于 99.99%")
6767
@JsonIgnore
6868
public boolean isDiscountPercentValid() {
6969
return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType())
70-
|| (discountPercent != null && discountPercent >= 1 && discountPercent<= 99);
70+
|| (discountPercent != null && discountPercent >= 1 && discountPercent <= 9999);
7171
}
7272

7373
@AssertTrue(message = "优惠金额不能为空")

yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java

+5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
@EqualsAndHashCode(callSuper = true)
3131
public class CouponTemplateDO extends BaseDO {
3232

33+
/**
34+
* 不限制领取数量
35+
*/
36+
public static final Integer TIME_LIMIT_COUNT_MAX = -1;
37+
3338
// ========== 基本信息 BEGIN ==========
3439
/**
3540
* 模板编号,自增唯一

yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public KeyValue<CombinationActivityDO, CombinationProductDO> validateCombination
131131
throw exception(COMBINATION_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
132132
}
133133
// 4.3 校验库存是否充足
134-
if (count > sku.getStock()) {
134+
if (count >= sku.getStock()) {
135135
throw exception(COMBINATION_ACTIVITY_UPDATE_STOCK_FAIL);
136136
}
137137

yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ private void validateCouponTemplateCanTake(CouponTemplateDO couponTemplate, Set<
269269
throw exception(COUPON_TEMPLATE_NOT_EXISTS);
270270
}
271271
// 校验剩余数量
272-
if (couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) {
272+
if (ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制
273+
&& couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) {
273274
throw exception(COUPON_TEMPLATE_NOT_ENOUGH);
274275
}
275276
// 校验"固定日期"的有效期类型是否过期

yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package cn.iocoder.yudao.module.promotion.service.coupon;
22

3+
import cn.hutool.core.util.ObjUtil;
34
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
45
import cn.iocoder.yudao.framework.common.pojo.PageResult;
56
import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi;
@@ -59,7 +60,7 @@ public void updateCouponTemplate(CouponTemplateUpdateReqVO updateReqVO) {
5960
CouponTemplateDO couponTemplate = validateCouponTemplateExists(updateReqVO.getId());
6061
// 校验发放数量不能过小(仅在 CouponTakeTypeEnum.USER 用户领取时)
6162
if (CouponTakeTypeEnum.isUser(couponTemplate.getTakeType())
62-
&& updateReqVO.getTotalCount() > 0 // 大于 0 的原因,是因为 -1 不限制
63+
&& ObjUtil.notEqual(couponTemplate.getTakeLimitCount(), CouponTemplateDO.TIME_LIMIT_COUNT_MAX) // 非不限制
6364
&& updateReqVO.getTotalCount() < couponTemplate.getTakeCount()) {
6465
throw exception(COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL, couponTemplate.getTakeCount());
6566
}

yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/point/PointActivityServiceImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ public PointValidateJoinRespDTO validateJoinPointActivity(Long activityId, Long
300300
throw exception(POINT_ACTIVITY_JOIN_ACTIVITY_SINGLE_LIMIT_COUNT_EXCEED);
301301
}
302302
// 2.2 校验库存是否充足
303-
if (count > product.getStock()) {
303+
if (count >= product.getStock()) {
304304
throw exception(POINT_ACTIVITY_UPDATE_STOCK_FAIL);
305305
}
306306
return BeanUtils.toBean(product, PointValidateJoinRespDTO.class);

yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/seckill/SeckillActivityServiceImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ public SeckillValidateJoinRespDTO validateJoinSeckill(Long activityId, Long skuI
317317
throw exception(SECKILL_JOIN_ACTIVITY_PRODUCT_NOT_EXISTS);
318318
}
319319
// 2.2 校验库存是否充足
320-
if (count > product.getStock()) {
320+
if (count >= product.getStock()) {
321321
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
322322
}
323323
return SeckillActivityConvert.INSTANCE.convert02(activity, product);

yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import cn.hutool.core.date.LocalDateTimeUtil;
55
import cn.hutool.core.lang.Assert;
66
import cn.hutool.core.map.MapUtil;
7+
import cn.hutool.core.net.NetUtil;
78
import cn.hutool.core.util.ObjUtil;
89
import cn.hutool.core.util.ObjectUtil;
910
import cn.hutool.core.util.RandomUtil;
@@ -888,16 +889,17 @@ public void cancelPaidOrder(Long userId, Long orderId, Integer cancelType) {
888889
if (!order.getPayStatus()) {
889890
throw exception(ORDER_CANCEL_PAID_FAIL, "已支付");
890891
}
891-
// 1.3 校验订单是否已退款
892-
if (ObjUtil.equal(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
892+
// 1.3 校验订单是否未退款
893+
if (ObjUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
893894
throw exception(ORDER_CANCEL_PAID_FAIL, "未退款");
894895
}
895896

896897
// 2.1 取消订单
897898
cancelOrder0(order, TradeOrderCancelTypeEnum.COMBINATION_CLOSE);
898899
// 2.2 创建退款单
899900
payRefundApi.createRefund(new PayRefundCreateReqDTO()
900-
.setAppKey(tradeOrderProperties.getPayAppKey()).setUserIp(getClientIP()) // 支付应用
901+
.setAppKey(tradeOrderProperties.getPayAppKey()) // 支付应用
902+
.setUserIp(NetUtil.getLocalhostStr()) // 使用本机 IP,因为是服务器发起退款的
901903
.setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
902904
.setMerchantRefundId(String.valueOf(order.getId()))
903905
.setReason(TradeOrderCancelTypeEnum.COMBINATION_CLOSE.getName()).setPrice(order.getPayPrice())); // 价格信息

yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Ex
8888
throw new IllegalArgumentException(String.format("未知的 API 版本(%s)", config.getApiVersion()));
8989
}
9090
} catch (WxPayException e) {
91+
log.error("[doUnifiedOrder][退款({}) 发起微信支付异常", reqDTO, e);
9192
String errorCode = getErrorCode(e);
9293
String errorMessage = getErrorMessage(e);
9394
return PayOrderRespDTO.closedOf(errorCode, errorMessage,

0 commit comments

Comments
 (0)