Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/yudao-cloud
commit
32c353c53d
|
|
@ -64,12 +64,10 @@ public class HttpUtils {
|
|||
return URLDecoder.decode(encoded, StandardCharsets.UTF_8.name());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static String replaceUrlQuery(String url, String key, String value) {
|
||||
UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());
|
||||
// 先移除
|
||||
// 先移除;再添加
|
||||
builder.getQuery().remove(key);
|
||||
// 后添加
|
||||
builder.addQuery(key, value);
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +1,52 @@
|
|||
package cn.iocoder.yudao.framework.common.util.http;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* {@link HttpUtils} 的单元测试
|
||||
*/
|
||||
public class HttpUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testReplaceUrlQuery() {
|
||||
// 定义测试用例:{原始URL, Key, Value, 期望结果}
|
||||
String[][] testCases = {
|
||||
// 场景1: 替换已存在的参数 (注意参数顺序可能会变,因为 UrlQuery 内部是 List)
|
||||
{"https://example.com/path?a=1&b=2", "a", "3", "https://example.com/path?b=2&a=3"},
|
||||
// 场景2: 添加不存在的参数
|
||||
{"https://example.com/path?a=1", "b", "2", "https://example.com/path?a=1&b=2"},
|
||||
// 场景3: URL 本身没有查询参数
|
||||
{"https://example.com/path", "a", "1", "https://example.com/path?a=1"},
|
||||
// 场景4: 值为空 (根据原逻辑,空值通常会被移除或不添加,这里假设是移除)
|
||||
// 注意:你需要根据 HttpUtils 实际对 null/empty 的处理来调整 expected
|
||||
{"https://example.com/path?a=1", "a", "", "https://example.com/path?a="},
|
||||
};
|
||||
|
||||
System.out.println("开始运行 HttpUtils.replaceUrlQuery 测试...");
|
||||
|
||||
for (int i = 0; i < testCases.length; i++) {
|
||||
String[] currentCase = testCases[i]; // 必须先取出当前这一行的数组
|
||||
|
||||
String url = currentCase[0];
|
||||
String key = currentCase[1];
|
||||
String value = currentCase[2];
|
||||
String expected = currentCase[3];
|
||||
|
||||
// 调用你优化后的方法
|
||||
String actual = HttpUtils.replaceUrlQuery(url, key, value);
|
||||
|
||||
// 核心验证:断言实际结果必须等于期望结果
|
||||
// 如果不相等,测试会直接报错,并打印出是哪一行错了
|
||||
try {
|
||||
assertEquals(expected, actual, "测试用例 " + (i + 1) + " 失败: " + url);
|
||||
System.out.println("✅ 用例 " + (i + 1) + " 通过: " + actual);
|
||||
} catch (AssertionError e) {
|
||||
System.err.println("❌ 用例 " + (i + 1) + " 失败!");
|
||||
System.err.println(" 输入: " + url + " | " + key + "=" + value);
|
||||
System.err.println(" 期望: " + expected);
|
||||
System.err.println(" 实际: " + actual);
|
||||
throw e; // 抛出错误,让测试标记为失败
|
||||
}
|
||||
}
|
||||
public void testReplaceUrlQuery_replace() {
|
||||
// 准备参数
|
||||
String url = "https://www.iocoder.cn/path?a=1&b=2";
|
||||
// 调用
|
||||
String result = HttpUtils.replaceUrlQuery(url, "a", "3");
|
||||
// 断言:被替换的 key 会移到末尾,原顺序的其它参数保留
|
||||
assertEquals("https://www.iocoder.cn/path?b=2&a=3", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceUrlQuery_add() {
|
||||
// 准备参数
|
||||
String url = "https://www.iocoder.cn/path?a=1";
|
||||
// 调用
|
||||
String result = HttpUtils.replaceUrlQuery(url, "b", "2");
|
||||
// 断言
|
||||
assertEquals("https://www.iocoder.cn/path?a=1&b=2", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceUrlQuery_noQuery() {
|
||||
// 准备参数:原 URL 没有 query
|
||||
String url = "https://www.iocoder.cn/path";
|
||||
// 调用
|
||||
String result = HttpUtils.replaceUrlQuery(url, "a", "1");
|
||||
// 断言
|
||||
assertEquals("https://www.iocoder.cn/path?a=1", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceUrlQuery_emptyValue() {
|
||||
// 准备参数:value 为空字符串
|
||||
String url = "https://www.iocoder.cn/path?a=1";
|
||||
// 调用
|
||||
String result = HttpUtils.replaceUrlQuery(url, "a", "");
|
||||
// 断言:保留 key,value 为空
|
||||
assertEquals("https://www.iocoder.cn/path?a=", result);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService {
|
|||
public Long createAlertConfig(IotAlertConfigSaveReqVO createReqVO) {
|
||||
// 校验关联数据是否存在
|
||||
sceneRuleService.validateSceneRuleList(createReqVO.getSceneRuleIds());
|
||||
adminUserApi.validateUserList(createReqVO.getReceiveUserIds());
|
||||
adminUserApi.validateUserList(createReqVO.getReceiveUserIds()).checkError();
|
||||
|
||||
// 插入
|
||||
IotAlertConfigDO alertConfig = BeanUtils.toBean(createReqVO, IotAlertConfigDO.class);
|
||||
|
|
@ -55,7 +55,7 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService {
|
|||
validateAlertConfigExists(updateReqVO.getId());
|
||||
// 校验关联数据是否存在
|
||||
sceneRuleService.validateSceneRuleList(updateReqVO.getSceneRuleIds());
|
||||
adminUserApi.validateUserList(updateReqVO.getReceiveUserIds());
|
||||
adminUserApi.validateUserList(updateReqVO.getReceiveUserIds()).checkError();
|
||||
|
||||
// 更新
|
||||
IotAlertConfigDO updateObj = BeanUtils.toBean(updateReqVO, IotAlertConfigDO.class);
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction {
|
|||
break;
|
||||
case NOTIFY:
|
||||
notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO().setUserId(userId)
|
||||
.setTemplateCode(typeEnum.getTemplateCode()).setTemplateParams(templateParams));
|
||||
.setTemplateCode(typeEnum.getTemplateCode()).setTemplateParams(templateParams)).checkError();
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
// TODO huihui:单测需要补充
|
||||
/**
|
||||
* 砍价活动的 {@link TradePriceCalculator} 实现类
|
||||
*
|
||||
|
|
@ -29,12 +28,12 @@ public class TradeBargainActivityPriceCalculator implements TradePriceCalculator
|
|||
|
||||
@Override
|
||||
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
|
||||
// 1. 判断订单类型和是否具有拼团记录编号
|
||||
// 1. 判断订单类型和是否具有砍价记录编号
|
||||
if (ObjectUtil.notEqual(result.getType(), TradeOrderTypeEnum.BARGAIN.getType())) {
|
||||
return;
|
||||
}
|
||||
Assert.isTrue(param.getItems().size() == 1, "砍价时,只允许选择一个商品");
|
||||
Assert.isTrue(param.getItems().get(0).getCount() == 1, "砍价时,只允许选择一个商品");
|
||||
Assert.isTrue(param.getItems().get(0).getCount() == 1, "砍价时,商品数量只允许为 1");
|
||||
// 2. 校验是否可以参与砍价
|
||||
TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0);
|
||||
BargainValidateJoinRespDTO bargainActivity = bargainRecordApi.validateJoinBargain(
|
||||
|
|
@ -44,7 +43,7 @@ public class TradeBargainActivityPriceCalculator implements TradePriceCalculator
|
|||
Integer discountPrice = orderItem.getPayPrice() - bargainActivity.getBargainPrice() * orderItem.getCount();
|
||||
// TODO 芋艿:极端情况,优惠金额为负数,需要处理
|
||||
TradePriceCalculatorHelper.addPromotion(result, orderItem,
|
||||
param.getSeckillActivityId(), bargainActivity.getName(), PromotionTypeEnum.BARGAIN_ACTIVITY.getType(),
|
||||
bargainActivity.getActivityId(), bargainActivity.getName(), PromotionTypeEnum.BARGAIN_ACTIVITY.getType(),
|
||||
StrUtil.format("砍价活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)),
|
||||
discountPrice);
|
||||
// 3.2 更新 SKU 优惠金额
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator {
|
|||
}
|
||||
double totalChargeValue = getTotalChargeValue(orderItems, chargeMode);
|
||||
double totalPrice = TradePriceCalculatorHelper.calculateTotalPayPrice(orderItems);
|
||||
return totalChargeValue <= templateFree.getFreeCount() && totalPrice >= templateFree.getFreePrice();
|
||||
return totalChargeValue >= templateFree.getFreeCount() && totalPrice >= templateFree.getFreePrice();
|
||||
}
|
||||
|
||||
private double getTotalChargeValue(List<OrderItem> orderItems, Integer chargeMode) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package cn.iocoder.yudao.module.trade.service.price.calculator;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
|
|
@ -61,7 +62,7 @@ public class TradePriceCalculatorHelper {
|
|||
// spu 信息
|
||||
orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId())
|
||||
.setDeliveryTypes(spu.getDeliveryTypes()).setDeliveryTemplateId(spu.getDeliveryTemplateId())
|
||||
.setGivePoint(spu.getGiveIntegral()).setUsePoint(0);
|
||||
.setGivePoint(ObjectUtil.defaultIfNull(spu.getGiveIntegral(), 0)).setUsePoint(0);
|
||||
if (StrUtil.isBlank(orderItem.getPicUrl())) {
|
||||
orderItem.setPicUrl(spu.getPicUrl());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ public class MesQcIndicatorResultServiceImpl implements MesQcIndicatorResultServ
|
|||
if (Objects.equals(resultType, MesQcResultValueTypeEnum.DICT.getType())) {
|
||||
String dictType = indicator.getResultSpecification();
|
||||
if (StrUtil.isNotBlank(dictType)) {
|
||||
dictDataApi.validateDictDataList(dictType, Collections.singleton(item.getValue()));
|
||||
dictDataApi.validateDictDataList(dictType, Collections.singleton(item.getValue())).checkError();
|
||||
}
|
||||
}
|
||||
if (Objects.equals(resultType, MesQcResultValueTypeEnum.FILE.getType())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
package cn.iocoder.yudao.module.system.job.token;
|
||||
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
|
||||
import com.xxl.job.core.context.XxlJobHelper;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 物理删除过期 N 天的令牌的 Job
|
||||
*
|
||||
* @author preschooler
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class TokenCleanJob {
|
||||
|
||||
@Resource
|
||||
private OAuth2TokenService oauth2TokenService;
|
||||
|
||||
/**
|
||||
* 清理过期(14)天的令牌
|
||||
*/
|
||||
private static final Integer JOB_CLEAN_RETAIN_DAY = 14;
|
||||
|
||||
/**
|
||||
* 每次删除间隔的条数,如果值太高可能会造成数据库的压力过大
|
||||
*/
|
||||
private static final Integer DELETE_LIMIT = 100;
|
||||
|
||||
@XxlJob("tokenCleanJob")
|
||||
@TenantIgnore
|
||||
public void execute() {
|
||||
Integer refreshCount = oauth2TokenService.cleanRefreshToken(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
|
||||
log.info("[execute][定时执行清理刷新令牌数量 ({}) 个]", refreshCount);
|
||||
Integer accessCount = oauth2TokenService.cleanAccessToken(JOB_CLEAN_RETAIN_DAY, DELETE_LIMIT);
|
||||
log.info("[execute][定时执行清理访问令牌数量 ({}) 个]", accessCount);
|
||||
XxlJobHelper.handleSuccess(
|
||||
String.format("定时执行清理刷新令牌数量 %s 个,访问令牌数量 %s 个", refreshCount, accessCount));
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue