Commit 7168e60fddc4210691a4f93651b2f0c9c081b1f3

Authored by YunaiV
1 parent 5e71d1fc

【功能新增】IoT:实现 IotRuleSceneDataBridgeAction 的 http 部分的逻辑

Showing 12 changed files with 229 additions and 21 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java
@@ -7,13 +7,15 @@ import cn.hutool.core.util.ReflectUtil; @@ -7,13 +7,15 @@ import cn.hutool.core.util.ReflectUtil;
7 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
8 import cn.hutool.http.HttpRequest; 8 import cn.hutool.http.HttpRequest;
9 import cn.hutool.http.HttpResponse; 9 import cn.hutool.http.HttpResponse;
  10 +import jakarta.servlet.http.HttpServletRequest;
10 import org.springframework.util.StringUtils; 11 import org.springframework.util.StringUtils;
11 import org.springframework.web.util.UriComponents; 12 import org.springframework.web.util.UriComponents;
12 import org.springframework.web.util.UriComponentsBuilder; 13 import org.springframework.web.util.UriComponentsBuilder;
13 14
14 -import jakarta.servlet.http.HttpServletRequest;  
15 import java.net.URI; 15 import java.net.URI;
  16 +import java.net.URLEncoder;
16 import java.nio.charset.Charset; 17 import java.nio.charset.Charset;
  18 +import java.nio.charset.StandardCharsets;
17 import java.util.Map; 19 import java.util.Map;
18 20
19 /** 21 /**
@@ -23,6 +25,16 @@ import java.util.Map; @@ -23,6 +25,16 @@ import java.util.Map;
23 */ 25 */
24 public class HttpUtils { 26 public class HttpUtils {
25 27
  28 + /**
  29 + * 编码 URL 参数
  30 + *
  31 + * @param value 参数
  32 + * @return 编码后的参数
  33 + */
  34 + public static String encodeUtf8(String value) {
  35 + return URLEncoder.encode(value, StandardCharsets.UTF_8);
  36 + }
  37 +
26 @SuppressWarnings("unchecked") 38 @SuppressWarnings("unchecked")
27 public static String replaceUrlQuery(String url, String key, String value) { 39 public static String replaceUrlQuery(String url, String key, String value) {
28 UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset()); 40 UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
@@ -98,4 +98,8 @@ public class ServletUtils { @@ -98,4 +98,8 @@ public class ServletUtils {
98 return JakartaServletUtil.getParamMap(request); 98 return JakartaServletUtil.getParamMap(request);
99 } 99 }
100 100
  101 + public static Map<String, String> getHeaderMap(HttpServletRequest request) {
  102 + return JakartaServletUtil.getHeaderMap(request);
  103 + }
  104 +
101 } 105 }
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
1 package cn.iocoder.yudao.framework.excel.core.util; 1 package cn.iocoder.yudao.framework.excel.core.util;
2 2
  3 +import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
3 import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; 4 import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
4 import com.alibaba.excel.EasyExcel; 5 import com.alibaba.excel.EasyExcel;
5 import com.alibaba.excel.converters.longconverter.LongStringConverter; 6 import com.alibaba.excel.converters.longconverter.LongStringConverter;
@@ -8,8 +9,6 @@ import jakarta.servlet.http.HttpServletResponse; @@ -8,8 +9,6 @@ import jakarta.servlet.http.HttpServletResponse;
8 import org.springframework.web.multipart.MultipartFile; 9 import org.springframework.web.multipart.MultipartFile;
9 10
10 import java.io.IOException; 11 import java.io.IOException;
11 -import java.net.URLEncoder;  
12 -import java.nio.charset.StandardCharsets;  
13 import java.util.List; 12 import java.util.List;
14 13
15 /** 14 /**
@@ -40,7 +39,7 @@ public class ExcelUtils { @@ -40,7 +39,7 @@ public class ExcelUtils {
40 .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 39 .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
41 .sheet(sheetName).doWrite(data); 40 .sheet(sheetName).doWrite(data);
42 // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 41 // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了
43 - response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name())); 42 + response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
44 response.setContentType("application/vnd.ms-excel;charset=UTF-8"); 43 response.setContentType("application/vnd.ms-excel;charset=UTF-8");
45 } 44 }
46 45
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java
@@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.infra.framework.file.core.utils; @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.infra.framework.file.core.utils;
2 2
3 import cn.hutool.core.io.IoUtil; 3 import cn.hutool.core.io.IoUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
5 import com.alibaba.ttl.TransmittableThreadLocal; 6 import com.alibaba.ttl.TransmittableThreadLocal;
6 import jakarta.servlet.http.HttpServletResponse; 7 import jakarta.servlet.http.HttpServletResponse;
7 import lombok.SneakyThrows; 8 import lombok.SneakyThrows;
8 import org.apache.tika.Tika; 9 import org.apache.tika.Tika;
9 10
10 import java.io.IOException; 11 import java.io.IOException;
11 -import java.net.URLEncoder;  
12 12
13 /** 13 /**
14 * 文件类型 Utils 14 * 文件类型 Utils
@@ -60,7 +60,7 @@ public class FileTypeUtils { @@ -60,7 +60,7 @@ public class FileTypeUtils {
60 */ 60 */
61 public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException { 61 public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
62 // 设置 header 和 contentType 62 // 设置 header 和 contentType
63 - response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); 63 + response.setHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
64 String contentType = getMineType(content, filename); 64 String contentType = getMineType(content, filename);
65 response.setContentType(contentType); 65 response.setContentType(contentType);
66 // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题 66 // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.dal.mysql.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +@Mapper
  8 +public interface IotDataBridgeMapper extends BaseMapperX<IotDataBridgeDO> {
  9 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.rule;
  2 +
  3 +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
  4 +
  5 +/**
  6 + * IoT 数据桥梁的 Service 接口
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public interface IotDataBridgeService {
  11 +
  12 + /**
  13 + * 获得指定数据桥梁
  14 + *
  15 + * @param id 数据桥梁编号
  16 + * @return 数据桥梁
  17 + */
  18 + IotDataBridgeDO getIotDataBridge(Long id);
  19 +
  20 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.rule;
  2 +
  3 +import cn.hutool.core.map.MapUtil;
  4 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  5 +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
  6 +import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataBridgeMapper;
  7 +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum;
  8 +import jakarta.annotation.Resource;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.stereotype.Service;
  11 +import org.springframework.validation.annotation.Validated;
  12 +
  13 +import java.util.Objects;
  14 +
  15 +/**
  16 + * IoT 数据桥梁的 Service 实现类
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +@Service
  21 +@Validated
  22 +@Slf4j
  23 +public class IotDataBridgeServiceImpl implements IotDataBridgeService {
  24 +
  25 + @Resource
  26 + private IotDataBridgeMapper dataBridgeMapper;
  27 +
  28 + // TODO @芋艿:临时测试
  29 + @Override
  30 + public IotDataBridgeDO getIotDataBridge(Long id) {
  31 + if (Objects.equals(id, 1L)) {
  32 + IotDataBridgeDO.HttpConfig config = new IotDataBridgeDO.HttpConfig()
  33 + .setUrl("http://127.0.0.1:48080/test")
  34 +// .setMethod("POST")
  35 + .setMethod("GET")
  36 + .setQuery(MapUtil.of("aaa", "bbb"))
  37 + .setHeaders(MapUtil.of("ccc", "ddd"))
  38 + .setBody(JsonUtils.toJsonString(MapUtil.of("eee", "fff")));
  39 + return IotDataBridgeDO.builder().id(1L).name("芋道").description("芋道源码").status(0).direction(1)
  40 + .type(IotDataBridgTypeEnum.HTTP.getType()).config(config).build();
  41 + }
  42 + return dataBridgeMapper.selectById(id);
  43 + }
  44 +
  45 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java
@@ -139,6 +139,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -139,6 +139,7 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
139 ruleScene01.getTriggers().add(trigger01); 139 ruleScene01.getTriggers().add(trigger01);
140 // 动作 140 // 动作
141 ruleScene01.setActions(CollUtil.newArrayList()); 141 ruleScene01.setActions(CollUtil.newArrayList());
  142 + // 设备控制
142 IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig(); 143 IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig();
143 action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType()); 144 action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType());
144 IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl(); 145 IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl();
@@ -151,7 +152,12 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService { @@ -151,7 +152,12 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
151 .put("color", "red") 152 .put("color", "red")
152 .build()); 153 .build());
153 action01.setDeviceControl(actionDeviceControl01); 154 action01.setDeviceControl(actionDeviceControl01);
154 - ruleScene01.getActions().add(action01); 155 +// ruleScene01.getActions().add(action01); // TODO 芋艿:先不测试了
  156 + // 数据桥接(http)
  157 + IotRuleSceneDO.ActionConfig action02 = new IotRuleSceneDO.ActionConfig();
  158 + action02.setType(IotRuleSceneActionTypeEnum.DATA_BRIDGE.getType());
  159 + action02.setDataBridgeId(1L);
  160 + ruleScene01.getActions().add(action02);
155 return ListUtil.toList(ruleScene01); 161 return ListUtil.toList(ruleScene01);
156 } 162 }
157 163
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java
1 package cn.iocoder.yudao.module.iot.service.rule.action; 1 package cn.iocoder.yudao.module.iot.service.rule.action;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  6 +import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
  7 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  8 +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
3 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO; 9 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
  10 +import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum;
4 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; 11 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
5 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; 12 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
  13 +import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService;
  14 +import com.fasterxml.jackson.databind.ObjectMapper;
  15 +import jakarta.annotation.Resource;
  16 +import lombok.extern.slf4j.Slf4j;
  17 +import org.springframework.http.*;
6 import org.springframework.stereotype.Component; 18 import org.springframework.stereotype.Component;
  19 +import org.springframework.web.client.RestTemplate;
  20 +import org.springframework.web.util.UriComponentsBuilder;
  21 +
  22 +import java.util.HashMap;
  23 +import java.util.Map;
  24 +
  25 +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
7 26
8 /** 27 /**
9 * IoT 数据桥梁的 {@link IotRuleSceneAction} 实现类 28 * IoT 数据桥梁的 {@link IotRuleSceneAction} 实现类
@@ -11,11 +30,38 @@ import org.springframework.stereotype.Component; @@ -11,11 +30,38 @@ import org.springframework.stereotype.Component;
11 * @author 芋道源码 30 * @author 芋道源码
12 */ 31 */
13 @Component 32 @Component
  33 +@Slf4j
14 public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { 34 public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction {
15 35
  36 + @Resource
  37 + private RestTemplate restTemplate;
  38 +
  39 + @Resource
  40 + private IotDataBridgeService dataBridgeService;
  41 +
  42 + private final ObjectMapper objectMapper = new ObjectMapper();
  43 +
16 @Override 44 @Override
17 public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) { 45 public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) {
18 - // TODO @芋艿:http 46 + // 1. 获得数据桥梁
  47 + Assert.notNull(config.getDataBridgeId(), "数据桥梁编号不能为空");
  48 + IotDataBridgeDO dataBridge = dataBridgeService.getIotDataBridge(config.getDataBridgeId());
  49 + if (dataBridge == null || dataBridge.getConfig() == null) {
  50 + log.error("[execute][message({}) config({}) 对应的数据桥梁不存在]", message, config);
  51 + return;
  52 + }
  53 + if (CommonStatusEnum.isDisable(dataBridge.getStatus())) {
  54 + log.info("[execute][message({}) config({}) 对应的数据桥梁({}) 状态为禁用]", message, config, dataBridge);
  55 + return;
  56 + }
  57 +
  58 + // 2.1 执行 HTTP 请求
  59 + // TODO @芋艿:groovy 或者 javascript 实现数据的转换;可以考虑基于 hutool 的 ScriptUtil 做
  60 + if (IotDataBridgTypeEnum.HTTP.getType().equals(dataBridge.getType())) {
  61 + executeHttp(message, (IotDataBridgeDO.HttpConfig) dataBridge.getConfig());
  62 + return;
  63 + }
  64 +
19 // TODO @芋艿:mq-redis 65 // TODO @芋艿:mq-redis
20 // TODO @芋艿:mq-数据库 66 // TODO @芋艿:mq-数据库
21 // TODO @芋艿:kafka 67 // TODO @芋艿:kafka
@@ -23,6 +69,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { @@ -23,6 +69,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction {
23 // TODO @芋艿:rabbitmq 69 // TODO @芋艿:rabbitmq
24 // TODO @芋艿:mqtt 70 // TODO @芋艿:mqtt
25 // TODO @芋艿:tcp 71 // TODO @芋艿:tcp
  72 + // TODO @芋艿:websocket
26 } 73 }
27 74
28 @Override 75 @Override
@@ -30,4 +77,54 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction { @@ -30,4 +77,54 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction {
30 return IotRuleSceneActionTypeEnum.DATA_BRIDGE; 77 return IotRuleSceneActionTypeEnum.DATA_BRIDGE;
31 } 78 }
32 79
  80 + @SuppressWarnings({"unchecked", "deprecation"})
  81 + private void executeHttp(IotDeviceMessage message, IotDataBridgeDO.HttpConfig config) {
  82 + String url = null;
  83 + HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase());
  84 + HttpEntity<String> requestEntity = null;
  85 + ResponseEntity<String> responseEntity = null;
  86 + try {
  87 + // 1.1 构建 Header
  88 + HttpHeaders headers = new HttpHeaders();
  89 + if (CollUtil.isNotEmpty(config.getHeaders())) {
  90 + config.getHeaders().putAll(config.getHeaders());
  91 + }
  92 + headers.add(HEADER_TENANT_ID, message.getTenantId().toString());
  93 + // 1.2 构建 URL
  94 + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(config.getUrl());
  95 + if (CollUtil.isNotEmpty(config.getQuery())) {
  96 + config.getQuery().forEach(uriBuilder::queryParam);
  97 + }
  98 + // 1.3 构建请求体
  99 + if (method == HttpMethod.GET) {
  100 + uriBuilder.queryParam("message", HttpUtils.encodeUtf8(JsonUtils.toJsonString(message)));
  101 + url = uriBuilder.build().toUriString();
  102 + requestEntity = new HttpEntity<>(headers);
  103 + } else {
  104 + url = uriBuilder.build().toUriString();
  105 + Map<String, Object> requestBody = JsonUtils.parseObject(config.getBody(), Map.class);
  106 + if (requestBody == null) {
  107 + requestBody = new HashMap<>();
  108 + }
  109 + requestBody.put("message", message);
  110 + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
  111 + requestEntity = new HttpEntity<>(JsonUtils.toJsonString(requestBody), headers);
  112 + }
  113 +
  114 + // 2.1 发送请求
  115 + responseEntity = restTemplate.exchange(url, method, requestEntity, String.class);
  116 + // 2.2 记录日志
  117 + if (responseEntity.getStatusCode().is2xxSuccessful()) {
  118 + log.info("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求成功({})]",
  119 + message, config, url, method, requestEntity, responseEntity);
  120 + } else {
  121 + log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求失败({})]",
  122 + message, config, url, method, requestEntity, responseEntity);
  123 + }
  124 + } catch (Exception e) {
  125 + log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求异常({})]",
  126 + message, config, url, method, requestEntity, responseEntity, e);
  127 + }
  128 + }
  129 +
33 } 130 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java
@@ -184,7 +184,7 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -184,7 +184,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
184 @SneakyThrows 184 @SneakyThrows
185 private static String percentCode(String str) { 185 private static String percentCode(String str) {
186 Assert.notNull(str, "str 不能为空"); 186 Assert.notNull(str, "str 不能为空");
187 - return URLEncoder.encode(str, StandardCharsets.UTF_8.name()) 187 + return HttpUtils.encodeUtf8(str)
188 .replace("+", "%20") // 加号 "+" 被替换为 "%20" 188 .replace("+", "%20") // 加号 "+" 被替换为 "%20"
189 .replace("*", "%2A") // 星号 "*" 被替换为 "%2A" 189 .replace("*", "%2A") // 星号 "*" 被替换为 "%2A"
190 .replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~" 190 .replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~"
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/HuaweiSmsClient.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
3 import cn.hutool.core.collection.ListUtil; 3 import cn.hutool.core.collection.ListUtil;
4 import cn.hutool.core.date.format.FastDateFormat; 4 import cn.hutool.core.date.format.FastDateFormat;
5 import cn.hutool.core.lang.Assert; 5 import cn.hutool.core.lang.Assert;
6 -import cn.hutool.core.util.CharsetUtil;  
7 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
8 import cn.hutool.crypto.SecureUtil; 7 import cn.hutool.crypto.SecureUtil;
9 import cn.hutool.http.HttpUtil; 8 import cn.hutool.http.HttpUtil;
@@ -19,8 +18,6 @@ import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditS @@ -19,8 +18,6 @@ import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditS
19 import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; 18 import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
20 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
21 20
22 -import java.io.UnsupportedEncodingException;  
23 -import java.net.URLEncoder;  
24 import java.nio.charset.StandardCharsets; 21 import java.nio.charset.StandardCharsets;
25 import java.time.Instant; 22 import java.time.Instant;
26 import java.time.LocalDateTime; 23 import java.time.LocalDateTime;
@@ -156,10 +153,9 @@ public class HuaweiSmsClient extends AbstractSmsClient { @@ -156,10 +153,9 @@ public class HuaweiSmsClient extends AbstractSmsClient {
156 .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(null); 153 .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(null);
157 } 154 }
158 155
159 - @SuppressWarnings("CharsetObjectCanBeUsed")  
160 - private static void appendToBody(StringBuilder body, String key, String value) throws UnsupportedEncodingException { 156 + private static void appendToBody(StringBuilder body, String key, String value) {
161 if (StrUtil.isNotEmpty(value)) { 157 if (StrUtil.isNotEmpty(value)) {
162 - body.append(key).append(URLEncoder.encode(value, CharsetUtil.CHARSET_UTF_8.name())); 158 + body.append(key).append(HttpUtils.encodeUtf8(value));
163 } 159 }
164 } 160 }
165 161
yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java
1 package cn.iocoder.yudao.server.controller; 1 package cn.iocoder.yudao.server.controller;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
  5 +import jakarta.annotation.security.PermitAll;
  6 +import jakarta.servlet.http.HttpServletRequest;
  7 +import lombok.extern.slf4j.Slf4j;
4 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.RequestMapping;
5 import org.springframework.web.bind.annotation.RestController; 9 import org.springframework.web.bind.annotation.RestController;
6 10
@@ -13,6 +17,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC @@ -13,6 +17,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC
13 * @author 芋道源码 17 * @author 芋道源码
14 */ 18 */
15 @RestController 19 @RestController
  20 +@Slf4j
16 public class DefaultController { 21 public class DefaultController {
17 22
18 @RequestMapping("/admin-api/bpm/**") 23 @RequestMapping("/admin-api/bpm/**")
@@ -27,9 +32,9 @@ public class DefaultController { @@ -27,9 +32,9 @@ public class DefaultController {
27 "[微信公众号 yudao-module-mp - 已禁用][参考 https://doc.iocoder.cn/mp/build/ 开启]"); 32 "[微信公众号 yudao-module-mp - 已禁用][参考 https://doc.iocoder.cn/mp/build/ 开启]");
28 } 33 }
29 34
30 - @RequestMapping(value = {"/admin-api/product/**", // 商品中心 35 + @RequestMapping(value = { "/admin-api/product/**", // 商品中心
31 "/admin-api/trade/**", // 交易中心 36 "/admin-api/trade/**", // 交易中心
32 - "/admin-api/promotion/**"}) // 营销中心 37 + "/admin-api/promotion/**" }) // 营销中心
33 public CommonResult<Boolean> mall404() { 38 public CommonResult<Boolean> mall404() {
34 return CommonResult.error(NOT_IMPLEMENTED.getCode(), 39 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
35 "[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]"); 40 "[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
@@ -47,28 +52,43 @@ public class DefaultController { @@ -47,28 +52,43 @@ public class DefaultController {
47 "[CRM 模块 yudao-module-crm - 已禁用][参考 https://doc.iocoder.cn/crm/build/ 开启]"); 52 "[CRM 模块 yudao-module-crm - 已禁用][参考 https://doc.iocoder.cn/crm/build/ 开启]");
48 } 53 }
49 54
50 - @RequestMapping(value = {"/admin-api/report/**"}) 55 + @RequestMapping(value = { "/admin-api/report/**"})
51 public CommonResult<Boolean> report404() { 56 public CommonResult<Boolean> report404() {
52 return CommonResult.error(NOT_IMPLEMENTED.getCode(), 57 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
53 "[报表模块 yudao-module-report - 已禁用][参考 https://doc.iocoder.cn/report/ 开启]"); 58 "[报表模块 yudao-module-report - 已禁用][参考 https://doc.iocoder.cn/report/ 开启]");
54 } 59 }
55 60
56 - @RequestMapping(value = {"/admin-api/pay/**"}) 61 + @RequestMapping(value = { "/admin-api/pay/**"})
57 public CommonResult<Boolean> pay404() { 62 public CommonResult<Boolean> pay404() {
58 return CommonResult.error(NOT_IMPLEMENTED.getCode(), 63 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
59 "[支付模块 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]"); 64 "[支付模块 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]");
60 } 65 }
61 66
62 - @RequestMapping(value = {"/admin-api/ai/**"}) 67 + @RequestMapping(value = { "/admin-api/ai/**"})
63 public CommonResult<Boolean> ai404() { 68 public CommonResult<Boolean> ai404() {
64 return CommonResult.error(NOT_IMPLEMENTED.getCode(), 69 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
65 "[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]"); 70 "[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]");
66 } 71 }
67 72
68 - @RequestMapping(value = {"/admin-api/iot/**"}) 73 + @RequestMapping(value = { "/admin-api/iot/**"})
69 public CommonResult<Boolean> iot404() { 74 public CommonResult<Boolean> iot404() {
70 return CommonResult.error(NOT_IMPLEMENTED.getCode(), 75 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
71 "[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]"); 76 "[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]");
72 } 77 }
73 78
  79 + /**
  80 + * 测试接口:打印 query、header、body
  81 + */
  82 + @RequestMapping(value = { "/test" })
  83 + @PermitAll
  84 + public CommonResult<Boolean> test(HttpServletRequest request) {
  85 + // 打印查询参数
  86 + log.info("Query: {}", ServletUtils.getParamMap(request));
  87 + // 打印请求头
  88 + log.info("Header: {}", ServletUtils.getHeaderMap(request));
  89 + // 打印请求体
  90 + log.info("Body: {}", ServletUtils.getBody(request));
  91 + return CommonResult.success(true);
  92 + }
  93 +
74 } 94 }