Переглянути джерело

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

YunaiV 6 місяців тому
батько
коміт
7168e60fdd
12 змінених файлів з 229 додано та 21 видалено
  1. 13 1
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java
  2. 4 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
  3. 2 3
      yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
  4. 2 2
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java
  5. 9 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java
  6. 20 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java
  7. 45 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java
  8. 7 1
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotRuleSceneServiceImpl.java
  9. 98 1
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java
  10. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/AliyunSmsClient.java
  11. 2 6
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/HuaweiSmsClient.java
  12. 26 6
      yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java

+ 13 - 1
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;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpRequest;
 import cn.hutool.http.HttpResponse;
+import jakarta.servlet.http.HttpServletRequest;
 import org.springframework.util.StringUtils;
 import org.springframework.web.util.UriComponents;
 import org.springframework.web.util.UriComponentsBuilder;
 
-import jakarta.servlet.http.HttpServletRequest;
 import java.net.URI;
+import java.net.URLEncoder;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
 /**
@@ -23,6 +25,16 @@ import java.util.Map;
  */
 public class HttpUtils {
 
+    /**
+     * 编码 URL 参数
+     *
+     * @param value 参数
+     * @return 编码后的参数
+     */
+    public static String encodeUtf8(String value) {
+        return URLEncoder.encode(value, StandardCharsets.UTF_8);
+    }
+
     @SuppressWarnings("unchecked")
     public static String replaceUrlQuery(String url, String key, String value) {
         UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());

+ 4 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java

@@ -98,4 +98,8 @@ public class ServletUtils {
         return JakartaServletUtil.getParamMap(request);
     }
 
+    public static Map<String, String> getHeaderMap(HttpServletRequest request) {
+        return JakartaServletUtil.getHeaderMap(request);
+    }
+
 }

+ 2 - 3
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.framework.excel.core.util;
 
+import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
 import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.converters.longconverter.LongStringConverter;
@@ -8,8 +9,6 @@ import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
 import java.util.List;
 
 /**
@@ -40,7 +39,7 @@ public class ExcelUtils {
                 .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
                 .sheet(sheetName).doWrite(data);
         // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了
-        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
+        response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
         response.setContentType("application/vnd.ms-excel;charset=UTF-8");
     }
 

+ 2 - 2
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;
 
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
 import com.alibaba.ttl.TransmittableThreadLocal;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.SneakyThrows;
 import org.apache.tika.Tika;
 
 import java.io.IOException;
-import java.net.URLEncoder;
 
 /**
  * 文件类型 Utils
@@ -60,7 +60,7 @@ public class FileTypeUtils {
      */
     public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
         // 设置 header 和 contentType
-        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
+        response.setHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
         String contentType = getMineType(content, filename);
         response.setContentType(contentType);
         // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题

+ 9 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotDataBridgeMapper.java

@@ -0,0 +1,9 @@
+package cn.iocoder.yudao.module.iot.dal.mysql.rule;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface IotDataBridgeMapper extends BaseMapperX<IotDataBridgeDO> {
+}

+ 20 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeService.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.iot.service.rule;
+
+import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
+
+/**
+ * IoT 数据桥梁的 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface IotDataBridgeService {
+
+    /**
+     * 获得指定数据桥梁
+     *
+     * @param id 数据桥梁编号
+     * @return 数据桥梁
+     */
+    IotDataBridgeDO getIotDataBridge(Long id);
+
+}

+ 45 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/IotDataBridgeServiceImpl.java

@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.iot.service.rule;
+
+import cn.hutool.core.map.MapUtil;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
+import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotDataBridgeMapper;
+import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Objects;
+
+/**
+ * IoT 数据桥梁的 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+@Slf4j
+public class IotDataBridgeServiceImpl implements IotDataBridgeService {
+
+    @Resource
+    private IotDataBridgeMapper dataBridgeMapper;
+
+    // TODO @芋艿:临时测试
+    @Override
+    public IotDataBridgeDO getIotDataBridge(Long id) {
+        if (Objects.equals(id, 1L)) {
+            IotDataBridgeDO.HttpConfig config = new IotDataBridgeDO.HttpConfig()
+                    .setUrl("http://127.0.0.1:48080/test")
+//                    .setMethod("POST")
+                    .setMethod("GET")
+                    .setQuery(MapUtil.of("aaa", "bbb"))
+                    .setHeaders(MapUtil.of("ccc", "ddd"))
+                    .setBody(JsonUtils.toJsonString(MapUtil.of("eee", "fff")));
+            return IotDataBridgeDO.builder().id(1L).name("芋道").description("芋道源码").status(0).direction(1)
+                    .type(IotDataBridgTypeEnum.HTTP.getType()).config(config).build();
+        }
+        return dataBridgeMapper.selectById(id);
+    }
+
+}

+ 7 - 1
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 {
             ruleScene01.getTriggers().add(trigger01);
             // 动作
             ruleScene01.setActions(CollUtil.newArrayList());
+            // 设备控制
             IotRuleSceneDO.ActionConfig action01 = new IotRuleSceneDO.ActionConfig();
             action01.setType(IotRuleSceneActionTypeEnum.DEVICE_CONTROL.getType());
             IotRuleSceneDO.ActionDeviceControl actionDeviceControl01 = new IotRuleSceneDO.ActionDeviceControl();
@@ -151,7 +152,12 @@ public class IotRuleSceneServiceImpl implements IotRuleSceneService {
                     .put("color", "red")
                     .build());
             action01.setDeviceControl(actionDeviceControl01);
-            ruleScene01.getActions().add(action01);
+//            ruleScene01.getActions().add(action01); // TODO 芋艿:先不测试了
+            // 数据桥接(http)
+            IotRuleSceneDO.ActionConfig action02 = new IotRuleSceneDO.ActionConfig();
+            action02.setType(IotRuleSceneActionTypeEnum.DATA_BRIDGE.getType());
+            action02.setDataBridgeId(1L);
+            ruleScene01.getActions().add(action02);
             return ListUtil.toList(ruleScene01);
         }
 

+ 98 - 1
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/IotRuleSceneDataBridgeAction.java

@@ -1,9 +1,28 @@
 package cn.iocoder.yudao.module.iot.service.rule.action;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.lang.Assert;
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotRuleSceneDO;
+import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum;
 import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum;
 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
+import cn.iocoder.yudao.module.iot.service.rule.IotDataBridgeService;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.*;
 import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
 
 /**
  * IoT 数据桥梁的 {@link IotRuleSceneAction} 实现类
@@ -11,11 +30,38 @@ import org.springframework.stereotype.Component;
  * @author 芋道源码
  */
 @Component
+@Slf4j
 public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction {
 
+    @Resource
+    private RestTemplate restTemplate;
+
+    @Resource
+    private IotDataBridgeService dataBridgeService;
+
+    private final ObjectMapper objectMapper = new ObjectMapper();
+
     @Override
     public void execute(IotDeviceMessage message, IotRuleSceneDO.ActionConfig config) {
-        // TODO @芋艿:http
+        // 1. 获得数据桥梁
+        Assert.notNull(config.getDataBridgeId(), "数据桥梁编号不能为空");
+        IotDataBridgeDO dataBridge = dataBridgeService.getIotDataBridge(config.getDataBridgeId());
+        if (dataBridge == null || dataBridge.getConfig() == null) {
+            log.error("[execute][message({}) config({}) 对应的数据桥梁不存在]", message, config);
+            return;
+        }
+        if (CommonStatusEnum.isDisable(dataBridge.getStatus())) {
+            log.info("[execute][message({}) config({}) 对应的数据桥梁({}) 状态为禁用]", message, config, dataBridge);
+            return;
+        }
+
+        // 2.1 执行 HTTP 请求
+        // TODO @芋艿:groovy 或者 javascript 实现数据的转换;可以考虑基于 hutool 的 ScriptUtil 做
+        if (IotDataBridgTypeEnum.HTTP.getType().equals(dataBridge.getType())) {
+            executeHttp(message, (IotDataBridgeDO.HttpConfig) dataBridge.getConfig());
+            return;
+        }
+
         // TODO @芋艿:mq-redis
         // TODO @芋艿:mq-数据库
         // TODO @芋艿:kafka
@@ -23,6 +69,7 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction {
         // TODO @芋艿:rabbitmq
         // TODO @芋艿:mqtt
         // TODO @芋艿:tcp
+        // TODO @芋艿:websocket
     }
 
     @Override
@@ -30,4 +77,54 @@ public class IotRuleSceneDataBridgeAction implements IotRuleSceneAction {
         return IotRuleSceneActionTypeEnum.DATA_BRIDGE;
     }
 
+    @SuppressWarnings({"unchecked", "deprecation"})
+    private void executeHttp(IotDeviceMessage message, IotDataBridgeDO.HttpConfig config) {
+        String url = null;
+        HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase());
+        HttpEntity<String> requestEntity = null;
+        ResponseEntity<String> responseEntity = null;
+        try {
+            // 1.1 构建 Header
+            HttpHeaders headers = new HttpHeaders();
+            if (CollUtil.isNotEmpty(config.getHeaders())) {
+                config.getHeaders().putAll(config.getHeaders());
+            }
+            headers.add(HEADER_TENANT_ID, message.getTenantId().toString());
+            // 1.2 构建 URL
+            UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(config.getUrl());
+            if (CollUtil.isNotEmpty(config.getQuery())) {
+                config.getQuery().forEach(uriBuilder::queryParam);
+            }
+            // 1.3 构建请求体
+            if (method == HttpMethod.GET) {
+                uriBuilder.queryParam("message", HttpUtils.encodeUtf8(JsonUtils.toJsonString(message)));
+                url = uriBuilder.build().toUriString();
+                requestEntity = new HttpEntity<>(headers);
+            } else {
+                url = uriBuilder.build().toUriString();
+                Map<String, Object> requestBody = JsonUtils.parseObject(config.getBody(), Map.class);
+                if (requestBody == null) {
+                    requestBody = new HashMap<>();
+                }
+                requestBody.put("message", message);
+                headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
+                requestEntity = new HttpEntity<>(JsonUtils.toJsonString(requestBody), headers);
+            }
+
+            // 2.1 发送请求
+            responseEntity = restTemplate.exchange(url, method, requestEntity, String.class);
+            // 2.2 记录日志
+            if (responseEntity.getStatusCode().is2xxSuccessful()) {
+                log.info("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求成功({})]",
+                        message, config, url, method, requestEntity, responseEntity);
+            } else {
+                log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求失败({})]",
+                        message, config, url, method, requestEntity, responseEntity);
+            }
+        } catch (Exception e) {
+            log.error("[executeHttp][message({}) config({}) url({}) method({}) requestEntity({}) 请求异常({})]",
+                    message, config, url, method, requestEntity, responseEntity, e);
+        }
+    }
+
 }

+ 1 - 1
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 {
     @SneakyThrows
     private static String percentCode(String str) {
         Assert.notNull(str, "str 不能为空");
-        return URLEncoder.encode(str, StandardCharsets.UTF_8.name())
+        return HttpUtils.encodeUtf8(str)
                 .replace("+", "%20") // 加号 "+" 被替换为 "%20"
                 .replace("*", "%2A") // 星号 "*" 被替换为 "%2A"
                 .replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~"

+ 2 - 6
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;
 import cn.hutool.core.collection.ListUtil;
 import cn.hutool.core.date.format.FastDateFormat;
 import cn.hutool.core.lang.Assert;
-import cn.hutool.core.util.CharsetUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.crypto.SecureUtil;
 import cn.hutool.http.HttpUtil;
@@ -19,8 +18,6 @@ import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditS
 import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
 import lombok.extern.slf4j.Slf4j;
 
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.time.Instant;
 import java.time.LocalDateTime;
@@ -156,10 +153,9 @@ public class HuaweiSmsClient extends AbstractSmsClient {
                 .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(null);
     }
 
-    @SuppressWarnings("CharsetObjectCanBeUsed")
-    private static void appendToBody(StringBuilder body, String key, String value) throws UnsupportedEncodingException {
+    private static void appendToBody(StringBuilder body, String key, String value) {
         if (StrUtil.isNotEmpty(value)) {
-            body.append(key).append(URLEncoder.encode(value, CharsetUtil.CHARSET_UTF_8.name()));
+            body.append(key).append(HttpUtils.encodeUtf8(value));
         }
     }
 

+ 26 - 6
yudao-server/src/main/java/cn/iocoder/yudao/server/controller/DefaultController.java

@@ -1,6 +1,10 @@
 package cn.iocoder.yudao.server.controller;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+import jakarta.annotation.security.PermitAll;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -13,6 +17,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC
  * @author 芋道源码
  */
 @RestController
+@Slf4j
 public class DefaultController {
 
     @RequestMapping("/admin-api/bpm/**")
@@ -27,9 +32,9 @@ public class DefaultController {
                 "[微信公众号 yudao-module-mp - 已禁用][参考 https://doc.iocoder.cn/mp/build/ 开启]");
     }
 
-    @RequestMapping(value = {"/admin-api/product/**", // 商品中心
+    @RequestMapping(value = { "/admin-api/product/**", // 商品中心
             "/admin-api/trade/**", // 交易中心
-            "/admin-api/promotion/**"})  // 营销中心
+            "/admin-api/promotion/**" }) // 营销中心
     public CommonResult<Boolean> mall404() {
         return CommonResult.error(NOT_IMPLEMENTED.getCode(),
                 "[商城系统 yudao-module-mall - 已禁用][参考 https://doc.iocoder.cn/mall/build/ 开启]");
@@ -47,28 +52,43 @@ public class DefaultController {
                 "[CRM 模块 yudao-module-crm - 已禁用][参考 https://doc.iocoder.cn/crm/build/ 开启]");
     }
 
-    @RequestMapping(value = {"/admin-api/report/**"})
+    @RequestMapping(value = { "/admin-api/report/**"})
     public CommonResult<Boolean> report404() {
         return CommonResult.error(NOT_IMPLEMENTED.getCode(),
                 "[报表模块 yudao-module-report - 已禁用][参考 https://doc.iocoder.cn/report/ 开启]");
     }
 
-    @RequestMapping(value = {"/admin-api/pay/**"})
+    @RequestMapping(value = { "/admin-api/pay/**"})
     public CommonResult<Boolean> pay404() {
         return CommonResult.error(NOT_IMPLEMENTED.getCode(),
                 "[支付模块 yudao-module-pay - 已禁用][参考 https://doc.iocoder.cn/pay/build/ 开启]");
     }
 
-    @RequestMapping(value = {"/admin-api/ai/**"})
+    @RequestMapping(value = { "/admin-api/ai/**"})
     public CommonResult<Boolean> ai404() {
         return CommonResult.error(NOT_IMPLEMENTED.getCode(),
                 "[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]");
     }
 
-    @RequestMapping(value = {"/admin-api/iot/**"})
+    @RequestMapping(value = { "/admin-api/iot/**"})
     public CommonResult<Boolean> iot404() {
         return CommonResult.error(NOT_IMPLEMENTED.getCode(),
                 "[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]");
     }
 
+    /**
+     * 测试接口:打印 query、header、body
+     */
+    @RequestMapping(value = { "/test" })
+    @PermitAll
+    public CommonResult<Boolean> test(HttpServletRequest request) {
+        // 打印查询参数
+        log.info("Query: {}", ServletUtils.getParamMap(request));
+        // 打印请求头
+        log.info("Header: {}", ServletUtils.getHeaderMap(request));
+        // 打印请求体
+        log.info("Body: {}", ServletUtils.getBody(request));
+        return CommonResult.success(true);
+    }
+
 }