【同步】BOOT 和 CLOUD 的功能
parent
2503432067
commit
24402eaeef
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 32 KiB |
|
@ -69,17 +69,17 @@ public class LocalDateTimeUtils {
|
||||||
* 创建指定时间
|
* 创建指定时间
|
||||||
*
|
*
|
||||||
* @param year 年
|
* @param year 年
|
||||||
* @param mouth 月
|
* @param month 月
|
||||||
* @param day 日
|
* @param day 日
|
||||||
* @return 指定时间
|
* @return 指定时间
|
||||||
*/
|
*/
|
||||||
public static LocalDateTime buildTime(int year, int mouth, int day) {
|
public static LocalDateTime buildTime(int year, int month, int day) {
|
||||||
return LocalDateTime.of(year, mouth, day, 0, 0, 0);
|
return LocalDateTime.of(year, month, day, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
|
public static LocalDateTime[] buildBetweenTime(int year1, int month1, int day1,
|
||||||
int year2, int mouth2, int day2) {
|
int year2, int month2, int day2) {
|
||||||
return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
|
return new LocalDateTime[]{buildTime(year1, month1, day1), buildTime(year2, month2, day2)};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl;
|
package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
|
||||||
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
|
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
|
||||||
import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
@ -18,7 +18,7 @@ public class DefaultIdempotentKeyResolver implements IdempotentKeyResolver {
|
||||||
@Override
|
@Override
|
||||||
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
||||||
String methodName = joinPoint.getSignature().toString();
|
String methodName = joinPoint.getSignature().toString();
|
||||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||||
return SecureUtil.md5(methodName + argsStr);
|
return SecureUtil.md5(methodName + argsStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl;
|
package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
|
||||||
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
|
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
|
||||||
import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
|
||||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
|
@ -19,7 +19,7 @@ public class UserIdempotentKeyResolver implements IdempotentKeyResolver {
|
||||||
@Override
|
@Override
|
||||||
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
||||||
String methodName = joinPoint.getSignature().toString();
|
String methodName = joinPoint.getSignature().toString();
|
||||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||||
Long userId = WebFrameworkUtils.getLoginUserId();
|
Long userId = WebFrameworkUtils.getLoginUserId();
|
||||||
Integer userType = WebFrameworkUtils.getLoginUserType();
|
Integer userType = WebFrameworkUtils.getLoginUserType();
|
||||||
return SecureUtil.md5(methodName + argsStr + userId + userType);
|
return SecureUtil.md5(methodName + argsStr + userId + userType);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
|
||||||
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter;
|
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter;
|
||||||
import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver;
|
import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver;
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
@ -19,7 +19,7 @@ public class ClientIpRateLimiterKeyResolver implements RateLimiterKeyResolver {
|
||||||
@Override
|
@Override
|
||||||
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
||||||
String methodName = joinPoint.getSignature().toString();
|
String methodName = joinPoint.getSignature().toString();
|
||||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||||
String clientIp = ServletUtils.getClientIP();
|
String clientIp = ServletUtils.getClientIP();
|
||||||
return SecureUtil.md5(methodName + argsStr + clientIp);
|
return SecureUtil.md5(methodName + argsStr + clientIp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
|
||||||
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter;
|
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter;
|
||||||
import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver;
|
import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver;
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
@ -18,7 +18,7 @@ public class DefaultRateLimiterKeyResolver implements RateLimiterKeyResolver {
|
||||||
@Override
|
@Override
|
||||||
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
||||||
String methodName = joinPoint.getSignature().toString();
|
String methodName = joinPoint.getSignature().toString();
|
||||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||||
return SecureUtil.md5(methodName + argsStr);
|
return SecureUtil.md5(methodName + argsStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
import cn.hutool.system.SystemUtil;
|
import cn.hutool.system.SystemUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
|
||||||
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter;
|
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter;
|
||||||
import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver;
|
import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver;
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
@ -19,7 +19,7 @@ public class ServerNodeRateLimiterKeyResolver implements RateLimiterKeyResolver
|
||||||
@Override
|
@Override
|
||||||
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
||||||
String methodName = joinPoint.getSignature().toString();
|
String methodName = joinPoint.getSignature().toString();
|
||||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||||
String serverNode = String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID());
|
String serverNode = String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID());
|
||||||
return SecureUtil.md5(methodName + argsStr + serverNode);
|
return SecureUtil.md5(methodName + argsStr + serverNode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
|
||||||
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter;
|
import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter;
|
||||||
import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver;
|
import cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.RateLimiterKeyResolver;
|
||||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||||
|
@ -19,7 +19,7 @@ public class UserRateLimiterKeyResolver implements RateLimiterKeyResolver {
|
||||||
@Override
|
@Override
|
||||||
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
||||||
String methodName = joinPoint.getSignature().toString();
|
String methodName = joinPoint.getSignature().toString();
|
||||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||||
Long userId = WebFrameworkUtils.getLoginUserId();
|
Long userId = WebFrameworkUtils.getLoginUserId();
|
||||||
Integer userType = WebFrameworkUtils.getLoginUserType();
|
Integer userType = WebFrameworkUtils.getLoginUserType();
|
||||||
return SecureUtil.md5(methodName + argsStr + userId + userType);
|
return SecureUtil.md5(methodName + argsStr + userId + userType);
|
||||||
|
|
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.ratelimiter.core.redis;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.redisson.api.*;
|
import org.redisson.api.*;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -40,11 +41,13 @@ public class RateLimiterRedisDAO {
|
||||||
String redisKey = formatKey(key);
|
String redisKey = formatKey(key);
|
||||||
RRateLimiter rateLimiter = redissonClient.getRateLimiter(redisKey);
|
RRateLimiter rateLimiter = redissonClient.getRateLimiter(redisKey);
|
||||||
long rateInterval = timeUnit.toSeconds(time);
|
long rateInterval = timeUnit.toSeconds(time);
|
||||||
|
Duration duration = Duration.ofSeconds(rateInterval);
|
||||||
// 1. 如果不存在,设置 rate 速率
|
// 1. 如果不存在,设置 rate 速率
|
||||||
RateLimiterConfig config = rateLimiter.getConfig();
|
RateLimiterConfig config = rateLimiter.getConfig();
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
rateLimiter.trySetRate(RateType.OVERALL, count, rateInterval, RateIntervalUnit.SECONDS);
|
rateLimiter.trySetRate(RateType.OVERALL, count, duration);
|
||||||
rateLimiter.expire(rateInterval, TimeUnit.SECONDS); // 原因参见 https://t.zsxq.com/lcR0W
|
// 原因参见 https://t.zsxq.com/lcR0W
|
||||||
|
rateLimiter.expire(duration);
|
||||||
return rateLimiter;
|
return rateLimiter;
|
||||||
}
|
}
|
||||||
// 2. 如果存在,并且配置相同,则直接返回
|
// 2. 如果存在,并且配置相同,则直接返回
|
||||||
|
@ -54,8 +57,9 @@ public class RateLimiterRedisDAO {
|
||||||
return rateLimiter;
|
return rateLimiter;
|
||||||
}
|
}
|
||||||
// 3. 如果存在,并且配置不同,则进行新建
|
// 3. 如果存在,并且配置不同,则进行新建
|
||||||
rateLimiter.setRate(RateType.OVERALL, count, rateInterval, RateIntervalUnit.SECONDS);
|
rateLimiter.setRate(RateType.OVERALL, count, duration);
|
||||||
rateLimiter.expire(rateInterval, TimeUnit.SECONDS); // 原因参见 https://t.zsxq.com/lcR0W
|
// 原因参见 https://t.zsxq.com/lcR0W
|
||||||
|
rateLimiter.expire(duration);
|
||||||
return rateLimiter;
|
return rateLimiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,6 @@ import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
|
|
||||||
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
|
|
||||||
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageOptions;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
|
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
|
||||||
|
@ -24,6 +21,9 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
|
||||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||||
import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper;
|
import cn.iocoder.yudao.module.ai.dal.mysql.image.AiImageMapper;
|
||||||
import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum;
|
import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
|
||||||
|
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
|
||||||
|
import cn.iocoder.yudao.module.ai.framework.ai.core.model.siliconflow.SiliconFlowImageOptions;
|
||||||
import cn.iocoder.yudao.module.ai.service.model.AiModelService;
|
import cn.iocoder.yudao.module.ai.service.model.AiModelService;
|
||||||
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||||
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
|
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
|
||||||
|
@ -89,7 +89,7 @@ public class AiImageServiceImpl implements AiImageService {
|
||||||
if (CollUtil.isEmpty(ids)) {
|
if (CollUtil.isEmpty(ids)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
return imageMapper.selectBatchIds(ids);
|
return imageMapper.selectByIds(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -16,8 +16,11 @@ import org.springframework.ai.image.ImageResponse;
|
||||||
*/
|
*/
|
||||||
public class TongYiImagesModelTest {
|
public class TongYiImagesModelTest {
|
||||||
|
|
||||||
private final DashScopeImageModel imageModel = new DashScopeImageModel(
|
private final DashScopeImageModel imageModel = DashScopeImageModel.builder()
|
||||||
new DashScopeImageApi("sk-7d903764249848cfa912733146da12d1"));
|
.dashScopeApi(DashScopeImageApi.builder()
|
||||||
|
.apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled
|
@Disabled
|
||||||
|
|
|
@ -35,7 +35,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> {
|
||||||
// 50 ~ 条件分支
|
// 50 ~ 条件分支
|
||||||
CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式
|
CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式
|
||||||
CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"),
|
CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"),
|
||||||
PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"),
|
PARALLEL_BRANCH_NODE(52, "并行分支", "inclusiveGateway"), // 并行分支使用包容网关实现,条件表达式结果设置为 true
|
||||||
INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"),
|
INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"),
|
||||||
ROUTER_BRANCH_NODE(54, "路由分支", "exclusiveGateway")
|
ROUTER_BRANCH_NODE(54, "路由分支", "exclusiveGateway")
|
||||||
;
|
;
|
||||||
|
|
|
@ -541,14 +541,23 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
|
||||||
* @see <a href="https://github.com/binarywang/weixin-java-pay-demo/blob/master/src/main/java/com/github/binarywang/demo/wx/pay/controller/WxPayV3Controller.java#L202-L221">官方示例</a>
|
* @see <a href="https://github.com/binarywang/weixin-java-pay-demo/blob/master/src/main/java/com/github/binarywang/demo/wx/pay/controller/WxPayV3Controller.java#L202-L221">官方示例</a>
|
||||||
*/
|
*/
|
||||||
private SignatureHeader getRequestHeader(Map<String, String> headers) {
|
private SignatureHeader getRequestHeader(Map<String, String> headers) {
|
||||||
|
// 参见 https://gitee.com/zhijiantianya/yudao-cloud/issues/ICSFL6
|
||||||
return SignatureHeader.builder()
|
return SignatureHeader.builder()
|
||||||
.signature(headers.get("wechatpay-signature"))
|
.signature(getHeaderValue(headers, "Wechatpay-Signature", "wechatpay-signature"))
|
||||||
.nonce(headers.get("wechatpay-nonce"))
|
.nonce(getHeaderValue(headers, "Wechatpay-Nonce", "wechatpay-nonce"))
|
||||||
.serial(headers.get("wechatpay-serial"))
|
.serial(getHeaderValue(headers, "Wechatpay-Serial", "wechatpay-serial"))
|
||||||
.timeStamp(headers.get("wechatpay-timestamp"))
|
.timeStamp(getHeaderValue(headers, "Wechatpay-Timestamp", "wechatpay-timestamp"))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getHeaderValue(Map<String, String> headers, String capitalizedKey, String lowercaseKey) {
|
||||||
|
String value = headers.get(capitalizedKey);
|
||||||
|
if (value != null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return headers.get(lowercaseKey);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO @芋艿:可能是 wxjava 的 bug:https://github.com/binarywang/WxJava/issues/1557
|
// TODO @芋艿:可能是 wxjava 的 bug:https://github.com/binarywang/WxJava/issues/1557
|
||||||
private void fixV3HttpClientConnectionPoolShutDown() {
|
private void fixV3HttpClientConnectionPoolShutDown() {
|
||||||
client.getConfig().setApiV3HttpClient(null);
|
client.getConfig().setApiV3HttpClient(null);
|
||||||
|
|
|
@ -111,6 +111,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
@SuppressWarnings("EnhancedSwitchMigration")
|
||||||
Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
|
Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
|
||||||
switch (templateStatus) {
|
switch (templateStatus) {
|
||||||
case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
|
case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
|
||||||
|
@ -134,20 +135,25 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
.map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue())))
|
.map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue())))
|
||||||
.collect(Collectors.joining("&"));
|
.collect(Collectors.joining("&"));
|
||||||
|
|
||||||
// 2.1 请求 Header
|
// 2. 请求 Body
|
||||||
|
String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空
|
||||||
|
String hashedRequestPayload = DigestUtil.sha256Hex(requestBody);
|
||||||
|
|
||||||
|
// 3.1 请求 Header
|
||||||
TreeMap<String, String> headers = new TreeMap<>();
|
TreeMap<String, String> headers = new TreeMap<>();
|
||||||
headers.put("host", HOST);
|
headers.put("host", HOST);
|
||||||
headers.put("x-acs-version", VERSION);
|
headers.put("x-acs-version", VERSION);
|
||||||
headers.put("x-acs-action", apiName);
|
headers.put("x-acs-action", apiName);
|
||||||
headers.put("x-acs-date", FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("GMT")).format(new Date()));
|
headers.put("x-acs-date", FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("GMT")).format(new Date()));
|
||||||
headers.put("x-acs-signature-nonce", IdUtil.randomUUID());
|
headers.put("x-acs-signature-nonce", IdUtil.randomUUID());
|
||||||
|
headers.put("x-acs-content-sha256", hashedRequestPayload);
|
||||||
|
|
||||||
// 2.2 构建签名 Header
|
// 3.2 构建签名 Header
|
||||||
StringBuilder canonicalHeaders = new StringBuilder(); // 构造请求头,多个规范化消息头,按照消息头名称(小写)的字符代码顺序以升序排列后拼接在一起
|
StringBuilder canonicalHeaders = new StringBuilder(); // 构造请求头,多个规范化消息头,按照消息头名称(小写)的字符代码顺序以升序排列后拼接在一起
|
||||||
StringBuilder signedHeadersBuilder = new StringBuilder(); // 已签名消息头列表,多个请求头名称(小写)按首字母升序排列并以英文分号(;)分隔
|
StringBuilder signedHeadersBuilder = new StringBuilder(); // 已签名消息头列表,多个请求头名称(小写)按首字母升序排列并以英文分号(;)分隔
|
||||||
headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-")
|
headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-")
|
||||||
|| entry.getKey().equalsIgnoreCase("host")
|
|| "host".equalsIgnoreCase(entry.getKey())
|
||||||
|| entry.getKey().equalsIgnoreCase("content-type"))
|
|| "content-type".equalsIgnoreCase(entry.getKey()))
|
||||||
.sorted(Map.Entry.comparingByKey()).forEach(entry -> {
|
.sorted(Map.Entry.comparingByKey()).forEach(entry -> {
|
||||||
String lowerKey = entry.getKey().toLowerCase();
|
String lowerKey = entry.getKey().toLowerCase();
|
||||||
canonicalHeaders.append(lowerKey).append(":").append(String.valueOf(entry.getValue()).trim()).append("\n");
|
canonicalHeaders.append(lowerKey).append(":").append(String.valueOf(entry.getValue()).trim()).append("\n");
|
||||||
|
@ -155,13 +161,13 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
});
|
});
|
||||||
String signedHeaders = signedHeadersBuilder.substring(0, signedHeadersBuilder.length() - 1);
|
String signedHeaders = signedHeadersBuilder.substring(0, signedHeadersBuilder.length() - 1);
|
||||||
|
|
||||||
// 3. 请求 Body
|
|
||||||
String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空。
|
|
||||||
String hashedRequestBody = DigestUtil.sha256Hex(requestBody);
|
|
||||||
|
|
||||||
// 4. 构建 Authorization 签名
|
// 4. 构建 Authorization 签名
|
||||||
String canonicalRequest = "POST" + "\n" + "/" + "\n" + queryString + "\n"
|
String canonicalRequest = "POST" + "\n" +
|
||||||
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestBody;
|
"/" + "\n" +
|
||||||
|
queryString + "\n" +
|
||||||
|
canonicalHeaders + "\n" +
|
||||||
|
signedHeaders + "\n" +
|
||||||
|
hashedRequestPayload;
|
||||||
String hashedCanonicalRequest = DigestUtil.sha256Hex(canonicalRequest);
|
String hashedCanonicalRequest = DigestUtil.sha256Hex(canonicalRequest);
|
||||||
String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest;
|
String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest;
|
||||||
String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名
|
String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名
|
||||||
|
@ -188,4 +194,4 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
.replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~"
|
.replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue