【功能新增】IoT:实现 IotRuleSceneDataBridgeAction 的 http 部分的逻辑
This commit is contained in:
parent
5e71d1fc85
commit
7168e60fdd
|
@ -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());
|
||||
|
|
|
@ -98,4 +98,8 @@ public class ServletUtils {
|
|||
return JakartaServletUtil.getParamMap(request);
|
||||
}
|
||||
|
||||
public static Map<String, String> getHeaderMap(HttpServletRequest request) {
|
||||
return JakartaServletUtil.getHeaderMap(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,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 的特殊处理,解决视频地址在移动端播放的兼容性问题
|
||||
|
|
|
@ -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> {
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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" 被替换为 "~"
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue