【同步】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 mouth 月
|
||||
* @param month 月
|
||||
* @param day 日
|
||||
* @return 指定时间
|
||||
*/
|
||||
public static LocalDateTime buildTime(int year, int mouth, int day) {
|
||||
return LocalDateTime.of(year, mouth, day, 0, 0, 0);
|
||||
public static LocalDateTime buildTime(int year, int month, int day) {
|
||||
return LocalDateTime.of(year, month, day, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
|
||||
int year2, int mouth2, int day2) {
|
||||
return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
|
||||
public static LocalDateTime[] buildBetweenTime(int year1, int month1, int day1,
|
||||
int year2, int month2, int 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;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.keyresolver.IdempotentKeyResolver;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
|
@ -18,7 +18,7 @@ public class DefaultIdempotentKeyResolver implements IdempotentKeyResolver {
|
|||
@Override
|
||||
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
||||
String methodName = joinPoint.getSignature().toString();
|
||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
||||
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||
return SecureUtil.md5(methodName + argsStr);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.keyresolver.IdempotentKeyResolver;
|
||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||
|
@ -19,7 +19,7 @@ public class UserIdempotentKeyResolver implements IdempotentKeyResolver {
|
|||
@Override
|
||||
public String resolver(JoinPoint joinPoint, Idempotent idempotent) {
|
||||
String methodName = joinPoint.getSignature().toString();
|
||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
||||
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||
Long userId = WebFrameworkUtils.getLoginUserId();
|
||||
Integer userType = WebFrameworkUtils.getLoginUserType();
|
||||
return SecureUtil.md5(methodName + argsStr + userId + userType);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
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.keyresolver.RateLimiterKeyResolver;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
|
@ -19,7 +19,7 @@ public class ClientIpRateLimiterKeyResolver implements RateLimiterKeyResolver {
|
|||
@Override
|
||||
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
||||
String methodName = joinPoint.getSignature().toString();
|
||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
||||
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||
String clientIp = ServletUtils.getClientIP();
|
||||
return SecureUtil.md5(methodName + argsStr + clientIp);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.keyresolver.RateLimiterKeyResolver;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
|
@ -18,7 +18,7 @@ public class DefaultRateLimiterKeyResolver implements RateLimiterKeyResolver {
|
|||
@Override
|
||||
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
||||
String methodName = joinPoint.getSignature().toString();
|
||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
||||
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||
return SecureUtil.md5(methodName + argsStr);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
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.keyresolver.RateLimiterKeyResolver;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
|
@ -19,7 +19,7 @@ public class ServerNodeRateLimiterKeyResolver implements RateLimiterKeyResolver
|
|||
@Override
|
||||
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
||||
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());
|
||||
return SecureUtil.md5(methodName + argsStr + serverNode);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cn.iocoder.yudao.framework.ratelimiter.core.keyresolver.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
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.keyresolver.RateLimiterKeyResolver;
|
||||
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
|
||||
|
@ -19,7 +19,7 @@ public class UserRateLimiterKeyResolver implements RateLimiterKeyResolver {
|
|||
@Override
|
||||
public String resolver(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
||||
String methodName = joinPoint.getSignature().toString();
|
||||
String argsStr = StrUtil.join(",", joinPoint.getArgs());
|
||||
String argsStr = StrUtils.joinMethodArgs(joinPoint);
|
||||
Long userId = WebFrameworkUtils.getLoginUserId();
|
||||
Integer userType = WebFrameworkUtils.getLoginUserType();
|
||||
return SecureUtil.md5(methodName + argsStr + userId + userType);
|
||||
|
|
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.ratelimiter.core.redis;
|
|||
import lombok.AllArgsConstructor;
|
||||
import org.redisson.api.*;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -40,11 +41,13 @@ public class RateLimiterRedisDAO {
|
|||
String redisKey = formatKey(key);
|
||||
RRateLimiter rateLimiter = redissonClient.getRateLimiter(redisKey);
|
||||
long rateInterval = timeUnit.toSeconds(time);
|
||||
Duration duration = Duration.ofSeconds(rateInterval);
|
||||
// 1. 如果不存在,设置 rate 速率
|
||||
RateLimiterConfig config = rateLimiter.getConfig();
|
||||
if (config == null) {
|
||||
rateLimiter.trySetRate(RateType.OVERALL, count, rateInterval, RateIntervalUnit.SECONDS);
|
||||
rateLimiter.expire(rateInterval, TimeUnit.SECONDS); // 原因参见 https://t.zsxq.com/lcR0W
|
||||
rateLimiter.trySetRate(RateType.OVERALL, count, duration);
|
||||
// 原因参见 https://t.zsxq.com/lcR0W
|
||||
rateLimiter.expire(duration);
|
||||
return rateLimiter;
|
||||
}
|
||||
// 2. 如果存在,并且配置相同,则直接返回
|
||||
|
@ -54,8 +57,9 @@ public class RateLimiterRedisDAO {
|
|||
return rateLimiter;
|
||||
}
|
||||
// 3. 如果存在,并且配置不同,则进行新建
|
||||
rateLimiter.setRate(RateType.OVERALL, count, rateInterval, RateIntervalUnit.SECONDS);
|
||||
rateLimiter.expire(rateInterval, TimeUnit.SECONDS); // 原因参见 https://t.zsxq.com/lcR0W
|
||||
rateLimiter.setRate(RateType.OVERALL, count, duration);
|
||||
// 原因参见 https://t.zsxq.com/lcR0W
|
||||
rateLimiter.expire(duration);
|
||||
return rateLimiter;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,6 @@ import cn.hutool.core.util.ObjUtil;
|
|||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
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.util.object.BeanUtils;
|
||||
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.mysql.image.AiImageMapper;
|
||||
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.infra.api.file.FileApi;
|
||||
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageOptions;
|
||||
|
@ -89,7 +89,7 @@ public class AiImageServiceImpl implements AiImageService {
|
|||
if (CollUtil.isEmpty(ids)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return imageMapper.selectBatchIds(ids);
|
||||
return imageMapper.selectByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,8 +16,11 @@ import org.springframework.ai.image.ImageResponse;
|
|||
*/
|
||||
public class TongYiImagesModelTest {
|
||||
|
||||
private final DashScopeImageModel imageModel = new DashScopeImageModel(
|
||||
new DashScopeImageApi("sk-7d903764249848cfa912733146da12d1"));
|
||||
private final DashScopeImageModel imageModel = DashScopeImageModel.builder()
|
||||
.dashScopeApi(DashScopeImageApi.builder()
|
||||
.apiKey("sk-47aa124781be4bfb95244cc62f63f7d0")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
|
|
|
@ -35,7 +35,7 @@ public enum BpmSimpleModelNodeTypeEnum implements ArrayValuable<Integer> {
|
|||
// 50 ~ 条件分支
|
||||
CONDITION_NODE(50, "条件", "sequenceFlow"), // 用于构建流转条件的表达式
|
||||
CONDITION_BRANCH_NODE(51, "条件分支", "exclusiveGateway"),
|
||||
PARALLEL_BRANCH_NODE(52, "并行分支", "parallelGateway"),
|
||||
PARALLEL_BRANCH_NODE(52, "并行分支", "inclusiveGateway"), // 并行分支使用包容网关实现,条件表达式结果设置为 true
|
||||
INCLUSIVE_BRANCH_NODE(53, "包容分支", "inclusiveGateway"),
|
||||
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>
|
||||
*/
|
||||
private SignatureHeader getRequestHeader(Map<String, String> headers) {
|
||||
// 参见 https://gitee.com/zhijiantianya/yudao-cloud/issues/ICSFL6
|
||||
return SignatureHeader.builder()
|
||||
.signature(headers.get("wechatpay-signature"))
|
||||
.nonce(headers.get("wechatpay-nonce"))
|
||||
.serial(headers.get("wechatpay-serial"))
|
||||
.timeStamp(headers.get("wechatpay-timestamp"))
|
||||
.signature(getHeaderValue(headers, "Wechatpay-Signature", "wechatpay-signature"))
|
||||
.nonce(getHeaderValue(headers, "Wechatpay-Nonce", "wechatpay-nonce"))
|
||||
.serial(getHeaderValue(headers, "Wechatpay-Serial", "wechatpay-serial"))
|
||||
.timeStamp(getHeaderValue(headers, "Wechatpay-Timestamp", "wechatpay-timestamp"))
|
||||
.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
|
||||
private void fixV3HttpClientConnectionPoolShutDown() {
|
||||
client.getConfig().setApiV3HttpClient(null);
|
||||
|
|
|
@ -111,6 +111,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
|||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@SuppressWarnings("EnhancedSwitchMigration")
|
||||
Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
|
||||
switch (templateStatus) {
|
||||
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())))
|
||||
.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<>();
|
||||
headers.put("host", HOST);
|
||||
headers.put("x-acs-version", VERSION);
|
||||
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-signature-nonce", IdUtil.randomUUID());
|
||||
headers.put("x-acs-content-sha256", hashedRequestPayload);
|
||||
|
||||
// 2.2 构建签名 Header
|
||||
// 3.2 构建签名 Header
|
||||
StringBuilder canonicalHeaders = new StringBuilder(); // 构造请求头,多个规范化消息头,按照消息头名称(小写)的字符代码顺序以升序排列后拼接在一起
|
||||
StringBuilder signedHeadersBuilder = new StringBuilder(); // 已签名消息头列表,多个请求头名称(小写)按首字母升序排列并以英文分号(;)分隔
|
||||
headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-")
|
||||
|| entry.getKey().equalsIgnoreCase("host")
|
||||
|| entry.getKey().equalsIgnoreCase("content-type"))
|
||||
|| "host".equalsIgnoreCase(entry.getKey())
|
||||
|| "content-type".equalsIgnoreCase(entry.getKey()))
|
||||
.sorted(Map.Entry.comparingByKey()).forEach(entry -> {
|
||||
String lowerKey = entry.getKey().toLowerCase();
|
||||
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);
|
||||
|
||||
// 3. 请求 Body
|
||||
String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空。
|
||||
String hashedRequestBody = DigestUtil.sha256Hex(requestBody);
|
||||
|
||||
// 4. 构建 Authorization 签名
|
||||
String canonicalRequest = "POST" + "\n" + "/" + "\n" + queryString + "\n"
|
||||
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestBody;
|
||||
String canonicalRequest = "POST" + "\n" +
|
||||
"/" + "\n" +
|
||||
queryString + "\n" +
|
||||
canonicalHeaders + "\n" +
|
||||
signedHeaders + "\n" +
|
||||
hashedRequestPayload;
|
||||
String hashedCanonicalRequest = DigestUtil.sha256Hex(canonicalRequest);
|
||||
String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest;
|
||||
String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名
|
||||
|
@ -188,4 +194,4 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
|||
.replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue