27 changed files with 809 additions and 7 deletions
@ -0,0 +1,64 @@ |
|||||
|
package com.zdxt.enforcementcode.common.util.siq; |
||||
|
|
||||
|
import cn.hutool.http.HttpRequest; |
||||
|
import cn.hutool.http.HttpResponse; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.esotericsoftware.minlog.Log; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Component |
||||
|
public class SIQHttpUtil { |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* POST带签名通用请求 |
||||
|
* @param url 完整地址 |
||||
|
* @param bodyJson 请求体,无参数传 "" |
||||
|
* @param secretKey 平台分配的密钥 |
||||
|
* @param appId 应用编号 |
||||
|
* @return 响应字符串 |
||||
|
*/ |
||||
|
public static String postWithSign(String url, String bodyJson, String secretKey, String appId) throws Exception { |
||||
|
Log.info("请求URL:{}", url); |
||||
|
Log.info("请求参数:{}", bodyJson); |
||||
|
SIQSignUtil.SignInfo signInfo = SIQSignUtil.generateSign(secretKey, appId, bodyJson); |
||||
|
|
||||
|
HttpRequest request = HttpRequest.post(url); |
||||
|
request.header("App-Id", signInfo.getAppId()); |
||||
|
request.header("App-Secret", signInfo.getAppSecret()); |
||||
|
request.header("Timestamp", String.valueOf(signInfo.getTimestamp())); |
||||
|
request.header("Nonce", signInfo.getNonce()); |
||||
|
request.header("Signature", signInfo.getSignature()); |
||||
|
request.header("Content-Type", "application/json;charset=utf-8"); |
||||
|
request.body(bodyJson); |
||||
|
|
||||
|
Map<String, String> headerMap = new HashMap<>(); |
||||
|
request.headers().forEach((key, values) -> { |
||||
|
if (values != null && !values.isEmpty()) { |
||||
|
headerMap.put(key, String.join(", ", values)); |
||||
|
} |
||||
|
}); |
||||
|
System.out.println("========== 完整请求头 =========="); |
||||
|
System.out.println(JSONObject.toJSONString(headerMap, true)); |
||||
|
System.out.println("========== 请求头结束 =========="); |
||||
|
|
||||
|
Log.info("深I企发送请求body:"); |
||||
|
Log.info( bodyJson); |
||||
|
|
||||
|
Log.info("深I企发送请求:"); |
||||
|
System.out.println(JSONObject.toJSONString(request,true)); |
||||
|
HttpResponse response = request.execute(); |
||||
|
Log.info("深I企返回参数:{}", JSONObject.toJSONString(response)); |
||||
|
if (!response.isOk()) { |
||||
|
response.close(); |
||||
|
throw new RuntimeException("调用深I企消息中心接口失败,http状态码:" + response.getStatus()); |
||||
|
} |
||||
|
String result = response.body(); |
||||
|
response.close(); |
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,107 @@ |
|||||
|
package com.zdxt.enforcementcode.common.util.siq; |
||||
|
|
||||
|
import com.esotericsoftware.minlog.Log; |
||||
|
|
||||
|
import javax.crypto.Mac; |
||||
|
import javax.crypto.spec.SecretKeySpec; |
||||
|
import javax.xml.bind.DatatypeConverter; |
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
import java.security.MessageDigest; |
||||
|
import java.security.SecureRandom; |
||||
|
|
||||
|
/** |
||||
|
* 深i企二期开放接口签名工具 |
||||
|
*/ |
||||
|
public class SIQSignUtil { |
||||
|
|
||||
|
/** |
||||
|
* HmacSHA256加密 |
||||
|
* @param key hmac密钥(文档要求用nonce) |
||||
|
* @param msg 待加密原文 |
||||
|
* @return 加密字节数组 |
||||
|
*/ |
||||
|
public static byte[] hmac256(byte[] key, String msg) throws Exception { |
||||
|
Mac mac = Mac.getInstance("HmacSHA256"); |
||||
|
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm()); |
||||
|
mac.init(secretKeySpec); |
||||
|
return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* SHA256 转小写16进制 |
||||
|
*/ |
||||
|
public static String sha256Hex(String s) throws Exception { |
||||
|
MessageDigest md = MessageDigest.getInstance("SHA-256"); |
||||
|
byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8)); |
||||
|
return DatatypeConverter.printHexBinary(d).toLowerCase(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成完整签名对象,包含timestamp、nonce、signature |
||||
|
* @param secretKey 平台分配的密钥(对应配置 siq.msgSecretKey) |
||||
|
* @param appId 应用编号(对应配置 siq.msgAppId) |
||||
|
* @param requestBody 请求体完整JSON字符串 |
||||
|
* @return 签名信息 |
||||
|
*/ |
||||
|
public static SignInfo generateSign(String secretKey, String appId, String requestBody) throws Exception { |
||||
|
// 1. 秒级时间戳
|
||||
|
long timestamp = System.currentTimeMillis() / 1000; |
||||
|
// 2. 6位随机数字Nonce
|
||||
|
String nonce = get6RandomNum(); |
||||
|
// 3. 请求体sha256
|
||||
|
String bodySha256 = sha256Hex(requestBody); |
||||
|
// 4. 拼接原文:secretKey + timestamp + nonce + bodySha256
|
||||
|
String hmacSource = secretKey + timestamp + nonce + bodySha256; |
||||
|
|
||||
|
// 5. hmac密钥为nonce字节数组
|
||||
|
byte[] hmacResult = hmac256(hmacSource.getBytes(StandardCharsets.UTF_8), nonce); |
||||
|
// 6. 转小写16进制签名
|
||||
|
String signature = DatatypeConverter.printHexBinary(hmacResult).toLowerCase(); |
||||
|
Log.info("Signature: " + signature); |
||||
|
SignInfo info = new SignInfo(); |
||||
|
info.setAppId(appId); |
||||
|
info.setAppSecret(secretKey); |
||||
|
info.setTimestamp(timestamp); |
||||
|
info.setNonce(nonce); |
||||
|
info.setSignature(signature); |
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成6位随机数字字符串 |
||||
|
*/ |
||||
|
private static String get6RandomNum() { |
||||
|
SecureRandom random = new SecureRandom(); |
||||
|
int num = random.nextInt(900000) + 100000; |
||||
|
return String.valueOf(num); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 签名结果实体,用于填充HTTP Header |
||||
|
*/ |
||||
|
public static class SignInfo { |
||||
|
private String appId; |
||||
|
private long timestamp; |
||||
|
private String nonce; |
||||
|
private String signature; |
||||
|
private String appSecret; |
||||
|
|
||||
|
// getter setter
|
||||
|
public String getAppId() { return appId; } |
||||
|
public void setAppId(String appId) { this.appId = appId; } |
||||
|
public long getTimestamp() { return timestamp; } |
||||
|
public void setTimestamp(long timestamp) { this.timestamp = timestamp; } |
||||
|
public String getNonce() { return nonce; } |
||||
|
public void setNonce(String nonce) { this.nonce = nonce; } |
||||
|
public String getSignature() { return signature; } |
||||
|
public void setSignature(String signature) { this.signature = signature; } |
||||
|
|
||||
|
public String getAppSecret() { |
||||
|
return appSecret; |
||||
|
} |
||||
|
|
||||
|
public void setAppSecret(String appSecret) { |
||||
|
this.appSecret = appSecret; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.bo.thirdparty; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Data |
||||
|
public class SIQMsgParamBo { |
||||
|
|
||||
|
/** |
||||
|
* 创建人 |
||||
|
*/ |
||||
|
private String createBy; |
||||
|
|
||||
|
/** |
||||
|
* 接收人 |
||||
|
*/ |
||||
|
private String receiveAccount; |
||||
|
|
||||
|
/** |
||||
|
* 内容 |
||||
|
*/ |
||||
|
private Map<String, String> additionalData; |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.bo.thirdparty; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class SIQSendMsgBo { |
||||
|
|
||||
|
/** |
||||
|
* 消息任务类型。delay:定时发送,planSendTime 不能 |
||||
|
* 为空,now:立即发送,planSendTime 为空 |
||||
|
*/ |
||||
|
private String sendType; |
||||
|
/** |
||||
|
* 通道:0短信 1邮件 2企微 3语音 4公众号 5小程序 6站内信 |
||||
|
*/ |
||||
|
private Integer sendChannel; |
||||
|
/** 模板授权ID */ |
||||
|
private String templateId; |
||||
|
/** 超时秒数 */ |
||||
|
private Integer expire; |
||||
|
/** 发送人 */ |
||||
|
private String createBy; |
||||
|
/** 接收人数组 */ |
||||
|
private ToUserMetaBo[] toUser; |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.bo.thirdparty; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Data |
||||
|
public class ToUserMetaBo { |
||||
|
/** 消息序号,业务自行生成唯一 */ |
||||
|
private String messageId; |
||||
|
/** 接收账号 */ |
||||
|
private String receiveAccount; |
||||
|
/** 模板变量 */ |
||||
|
private Map<String, String> variables; |
||||
|
/** 附加业务数据 */ |
||||
|
private Map<String, String> additionalData; |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public class AnalyzeResultVo { |
||||
|
/** 总数量 */ |
||||
|
private Integer totalCount; |
||||
|
/** 成功数量 */ |
||||
|
private Integer successCount; |
||||
|
/** 失败数量 */ |
||||
|
private Integer failedCount; |
||||
|
/** 失败详情 */ |
||||
|
private List<Object> failedResults; |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class LimitPeriod { |
||||
|
/** 周期类型:日/周/月/年等编码 */ |
||||
|
private Integer periodType; |
||||
|
|
||||
|
/** 周期数值,如type=月、value=1代表每月 */ |
||||
|
private Integer periodValue; |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class MessageDetailVo { |
||||
|
/** 消息序号 */ |
||||
|
private String messageId; |
||||
|
/** 接收时间 */ |
||||
|
private Long createTime; |
||||
|
/** 超期时间 */ |
||||
|
private Long expireTime; |
||||
|
/** 发送完成时间 */ |
||||
|
private Long sendFinishedTime; |
||||
|
/** 消息发送类型:delay/now */ |
||||
|
private String sendType; |
||||
|
/** 接收人姓名 */ |
||||
|
private String principalName; |
||||
|
/** 接收人账号 */ |
||||
|
private String receiveAccount; |
||||
|
/** 解析结果 */ |
||||
|
private String analyzeResult; |
||||
|
/** 解析说明 */ |
||||
|
private String analyzeRemarks; |
||||
|
/** 发送状态:0待发送 1成功 2正在发送 3异常 4失败 5取消 */ |
||||
|
private Integer sendStatus; |
||||
|
/** 发送消息内容 */ |
||||
|
private String sendContent; |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
public class MessageTaskItemVo { |
||||
|
/** 消息任务唯一标示 */ |
||||
|
private String taskId; |
||||
|
/** 发送类型:now立即发送,delay定时发送 */ |
||||
|
private String sendType; |
||||
|
/** 解析结果 */ |
||||
|
private AnalyzeResultVo analyzeResult; |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
public class SIQResult { |
||||
|
String errcode; //响应编码
|
||||
|
String errmsg ;//响应编码
|
||||
|
String data; //返回的数据
|
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class SIQTaskQueryBo { |
||||
|
/** 消息任务唯一标示 */ |
||||
|
private String taskId; |
||||
|
/** 消息序号数组,为空则查询该任务下所有消息 */ |
||||
|
private String[] messageIds; |
||||
|
/** 页数 */ |
||||
|
private Integer pageNo; |
||||
|
/** 每页大小 */ |
||||
|
private Integer pageSize; |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public class SIQTemplateVo { |
||||
|
/** |
||||
|
* 模板授权ID |
||||
|
* 唯一标识模板与应用授权匹配关系 |
||||
|
*/ |
||||
|
private String templateId; |
||||
|
|
||||
|
/** 授权模板名称 */ |
||||
|
private String templateName; |
||||
|
|
||||
|
/** |
||||
|
* 模板归属渠道分类 |
||||
|
* 0-短信,1-邮件,2-企业微信,3-语音,4-微信公众号,5-小程序,6-站内信 |
||||
|
*/ |
||||
|
private Integer sendChannel; |
||||
|
|
||||
|
/** |
||||
|
* 模板授权状态 |
||||
|
* 1-正常,2-禁用,3-冻结 |
||||
|
*/ |
||||
|
private Integer authorizationStatus; |
||||
|
|
||||
|
/** 授权开始时间戳(Long类型秒级时间) */ |
||||
|
private Long authorizationTimeForm; |
||||
|
|
||||
|
/** 授权截止时间戳(Long类型秒级时间) */ |
||||
|
private Long authorizationTimeTo; |
||||
|
|
||||
|
/** 当前周期内剩余可发送限额次数 */ |
||||
|
private Integer limitNumber; |
||||
|
|
||||
|
/** 限额统计方式编码 */ |
||||
|
private Integer limitType; |
||||
|
|
||||
|
/** 限额周期配置对象 */ |
||||
|
private LimitPeriod limitPeriod; |
||||
|
|
||||
|
/** 模板展示示例文案 */ |
||||
|
private String templateDemo; |
||||
|
|
||||
|
/** 模板实际发送正文内容 */ |
||||
|
private String templateContent; |
||||
|
|
||||
|
/** 模板占位变量参数数组 */ |
||||
|
private List<TemplateVariable> templateVariable; |
||||
|
|
||||
|
/** 授权说明备注,非必填 */ |
||||
|
private String authorizationRemarks; |
||||
|
|
||||
|
/** 异常/冻结原因说明,非必填 */ |
||||
|
private String errorRemarks; |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
public class SendMsgDataVo { |
||||
|
/** 消息任务列表 */ |
||||
|
private List<MessageTaskItemVo> list; |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class SendMsgVo { |
||||
|
/** 响应编码,0表示成功 */ |
||||
|
private Integer errcode; |
||||
|
/** 响应消息 */ |
||||
|
private String errmsg; |
||||
|
/** 响应数据 */ |
||||
|
private Object data; |
||||
|
|
||||
|
public boolean isSuccess() { |
||||
|
return errcode == 0; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
public class TaskQueryResultVo { |
||||
|
/** 消息任务唯一标示 */ |
||||
|
private String taskId; |
||||
|
/** 发送状态:0待发送 1成功 2正在发送 3异常 4失败 5取消 */ |
||||
|
private Integer sendStatus; |
||||
|
/** 总消息数量 */ |
||||
|
private Integer totalCount; |
||||
|
/** 发送成功数量 */ |
||||
|
private Integer sendSuccessCount; |
||||
|
/** 发送失败数量 */ |
||||
|
private Integer sendFailedCount; |
||||
|
/** 创建人 */ |
||||
|
private String createBy; |
||||
|
/** 创建时间 */ |
||||
|
private Long createTime; |
||||
|
/** 消息发送类型:DELAY/now */ |
||||
|
private String sendType; |
||||
|
/** 预约发送开始时间 */ |
||||
|
private Long planSendTime; |
||||
|
/** 发送完成时间 */ |
||||
|
private Long sendFinishedTime; |
||||
|
/** 超时时间(秒) */ |
||||
|
private Integer expire; |
||||
|
/** 消息详情列表 */ |
||||
|
private MessageDetailVo[] messageDetails; |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
package com.zdxt.enforcementcode.domain.vo.siq; |
||||
|
|
||||
|
public class TemplateVariable { |
||||
|
/** |
||||
|
* 变量名称,模板内占位标识 |
||||
|
*/ |
||||
|
private String varName; |
||||
|
|
||||
|
/** |
||||
|
* 变量业务描述 |
||||
|
*/ |
||||
|
private String varDesc; |
||||
|
|
||||
|
/** |
||||
|
* 变量示例填充值 |
||||
|
*/ |
||||
|
private String example; |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
package com.zdxt.enforcementcode.service.thirdparty; |
||||
|
|
||||
|
import com.zdxt.enforcementcode.domain.bo.thirdparty.SIQMsgParamBo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.siq.SIQTaskQueryBo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.siq.SIQTemplateVo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.siq.TaskQueryResultVo; |
||||
|
|
||||
|
/** |
||||
|
* 投诉事项Service接口 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2026-04-17 |
||||
|
*/ |
||||
|
public interface ISIQService { |
||||
|
|
||||
|
/** |
||||
|
* |
||||
|
* @param templateId |
||||
|
* @return |
||||
|
* @throws Exception |
||||
|
*/ |
||||
|
SIQTemplateVo getTemplateById(String templateId); |
||||
|
|
||||
|
void sendMsg(SIQMsgParamBo paramBo); |
||||
|
|
||||
|
/** |
||||
|
* 按批次查询消息发送结果 |
||||
|
* @param queryBo 查询参数 |
||||
|
* @return 任务查询结果 |
||||
|
*/ |
||||
|
TaskQueryResultVo queryTaskResult(SIQTaskQueryBo queryBo); |
||||
|
} |
||||
@ -0,0 +1,116 @@ |
|||||
|
package com.zdxt.enforcementcode.service.thirdparty.impl; |
||||
|
|
||||
|
import cn.hutool.core.collection.CollectionUtil; |
||||
|
import cn.hutool.core.util.IdUtil; |
||||
|
import com.alibaba.fastjson.JSON; |
||||
|
import com.alibaba.fastjson.JSONObject; |
||||
|
import com.esotericsoftware.minlog.Log; |
||||
|
import com.zdxt.enforcementcode.common.config.SiqConfig; |
||||
|
import com.zdxt.enforcementcode.common.util.StringUtils; |
||||
|
import com.zdxt.enforcementcode.common.util.siq.SIQHttpUtil; |
||||
|
import com.zdxt.enforcementcode.domain.bo.thirdparty.SIQMsgParamBo; |
||||
|
import com.zdxt.enforcementcode.domain.bo.thirdparty.SIQSendMsgBo; |
||||
|
import com.zdxt.enforcementcode.domain.bo.thirdparty.ToUserMetaBo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.siq.*; |
||||
|
import com.zdxt.enforcementcode.service.thirdparty.ISIQService; |
||||
|
import jakarta.annotation.Resource; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.dromara.common.core.exception.base.BaseException; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.*; |
||||
|
|
||||
|
/** |
||||
|
* 投诉事项Service业务层处理 |
||||
|
* |
||||
|
* @author Lion Li |
||||
|
* @date 2026-04-17 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@RequiredArgsConstructor |
||||
|
@Service |
||||
|
public class SIQServiceImpl implements ISIQService { |
||||
|
|
||||
|
@Resource |
||||
|
private SiqConfig siqConfig; |
||||
|
@Override |
||||
|
public SIQTemplateVo getTemplateById(String templateId) { |
||||
|
try{ |
||||
|
// 拼接查询模板详情接口完整地址
|
||||
|
String url = siqConfig.getSiqBaseUrl() + "/mpc/api/messageTemplate/v1/" + templateId + "/get"; |
||||
|
// 当前接口无业务请求体,固定传入空字符串参与签名计算
|
||||
|
String emptyBody = ""; |
||||
|
// 发起带签名POST请求
|
||||
|
String respJson = SIQHttpUtil.postWithSign(url, emptyBody, siqConfig.getMsgSecretKey(), siqConfig.getMsgAppId()); |
||||
|
// JSON字符串转换为实体对象返回
|
||||
|
return JSON.parseObject(respJson, SIQTemplateVo.class); |
||||
|
}catch (Exception e){ |
||||
|
throw new BaseException("获取模板详情失败"); |
||||
|
} |
||||
|
} |
||||
|
@Override |
||||
|
public void sendMsg(SIQMsgParamBo paramBo) { |
||||
|
try { |
||||
|
if (StringUtils.isBlank(paramBo.getReceiveAccount())) { |
||||
|
throw new BaseException("接收账号不能为空"); |
||||
|
} |
||||
|
SIQSendMsgBo sendMsgBo = new SIQSendMsgBo(); |
||||
|
sendMsgBo.setSendChannel(6); |
||||
|
sendMsgBo.setSendType("now"); |
||||
|
sendMsgBo.setTemplateId(siqConfig.getMsgTemplateId()); |
||||
|
sendMsgBo.setExpire(120); |
||||
|
sendMsgBo.setCreateBy(paramBo.getCreateBy()); |
||||
|
|
||||
|
ToUserMetaBo toUserMetaBo = new ToUserMetaBo(); |
||||
|
toUserMetaBo.setMessageId(IdUtil.simpleUUID()); |
||||
|
toUserMetaBo.setVariables(paramBo.getAdditionalData()); |
||||
|
toUserMetaBo.setReceiveAccount(paramBo.getReceiveAccount()); |
||||
|
sendMsgBo.setToUser(new ToUserMetaBo[]{toUserMetaBo}); |
||||
|
|
||||
|
String url = siqConfig.getSiqBaseUrl() + "/egb/api/mpc/api/messageTask/v1/singleCreate"; |
||||
|
String body = JSONObject.toJSONString(sendMsgBo); |
||||
|
log.info("单条发送站内信请求参数: {}", body); |
||||
|
String respJson = SIQHttpUtil.postWithSign(url, body, siqConfig.getMsgSecretKey(), siqConfig.getMsgAppId()); |
||||
|
log.info("单条发送站内信响应结果: {}", respJson); |
||||
|
SendMsgVo sendMsg = JSON.parseObject(respJson, SendMsgVo.class); |
||||
|
if(sendMsg.isSuccess()){ |
||||
|
SendMsgDataVo sendMsgDataVo = JSON.parseObject(JSON.toJSONString(sendMsg.getData()), SendMsgDataVo.class); |
||||
|
List<MessageTaskItemVo> list = sendMsgDataVo.getList(); |
||||
|
if(CollectionUtil.isNotEmpty(list)){ |
||||
|
MessageTaskItemVo messageTaskItemVo = list.get(0); |
||||
|
log.info("单条发送站内信成功,taskId: {}", messageTaskItemVo.getTaskId()); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
log.error("单条发送站内信失败", e); |
||||
|
throw new BaseException("单条发送站内信失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public TaskQueryResultVo queryTaskResult(SIQTaskQueryBo queryBo) { |
||||
|
try { |
||||
|
if (StringUtils.isBlank(queryBo.getTaskId())) { |
||||
|
throw new BaseException("taskId不能为空"); |
||||
|
} |
||||
|
String url = siqConfig.getSiqBaseUrl() + "/egb/api/mpc/api/messageTask/v1/byTaskId/get"; |
||||
|
String body = JSONObject.toJSONString(queryBo); |
||||
|
log.info("查询消息任务结果请求参数: {}", body); |
||||
|
String respJson = SIQHttpUtil.postWithSign(url, body, siqConfig.getMsgSecretKey(), siqConfig.getMsgAppId()); |
||||
|
log.info("查询消息任务结果响应: {}", respJson); |
||||
|
TaskQueryResultVo sendMsgDataVo = null; |
||||
|
SendMsgVo sendMsg = JSON.parseObject(respJson, SendMsgVo.class); |
||||
|
if (sendMsg.isSuccess()) { |
||||
|
sendMsgDataVo = JSON.parseObject(JSON.toJSONString(sendMsg.getData()), TaskQueryResultVo.class); |
||||
|
Log.info("查询消息任务结果成功,消息: {}", JSONObject.toJSONString(sendMsgDataVo)); |
||||
|
} |
||||
|
return sendMsgDataVo; |
||||
|
} catch (Exception e) { |
||||
|
log.error("查询消息任务结果失败", e); |
||||
|
throw new BaseException("查询消息任务结果失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,118 @@ |
|||||
|
package com.zdxt.rest.test.siq; |
||||
|
|
||||
|
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil; |
||||
|
import cn.dev33.satoken.stp.parameter.SaLoginParameter; |
||||
|
import cn.dev33.satoken.stp.StpUtil; |
||||
|
import com.zdxt.enforcementcode.common.util.siq.SIQHttpUtil; |
||||
|
import com.zdxt.enforcementcode.domain.bo.thirdparty.SIQMsgParamBo; |
||||
|
import com.zdxt.enforcementcode.domain.bo.thirdparty.SIQSendMsgBo; |
||||
|
import com.zdxt.enforcementcode.domain.bo.thirdparty.ToUserMetaBo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.siq.SIQTaskQueryBo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.siq.SIQTemplateVo; |
||||
|
import com.zdxt.enforcementcode.domain.vo.siq.TaskQueryResultVo; |
||||
|
import com.zdxt.enforcementcode.service.thirdparty.ISIQService; |
||||
|
import org.dromara.ZdxtAdminApplication; |
||||
|
import org.dromara.common.core.domain.model.LoginUser; |
||||
|
import org.dromara.common.satoken.utils.LoginHelper; |
||||
|
import org.junit.jupiter.api.*; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; |
||||
|
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
import org.springframework.mock.web.MockHttpServletRequest; |
||||
|
import org.springframework.web.context.request.RequestContextHolder; |
||||
|
import org.springframework.web.context.request.ServletRequestAttributes; |
||||
|
|
||||
|
import java.util.*; |
||||
|
|
||||
|
import static org.junit.jupiter.api.Assertions.*; |
||||
|
|
||||
|
/** |
||||
|
* ISIQService 深i企消息中心接口测试 |
||||
|
* <p> |
||||
|
* 包含三类测试: |
||||
|
* 1. getTemplateById - 查询模板详情 |
||||
|
* 2. sendMsg - 发送单条消息 |
||||
|
* 3. queryTaskResult - 按批次查询发送结果 |
||||
|
* </p> |
||||
|
* |
||||
|
* @author zdxt |
||||
|
*/ |
||||
|
@SpringBootTest(classes = ZdxtAdminApplication.class) |
||||
|
@AutoConfigureMockMvc |
||||
|
@DisplayName("ISIQService 深i企消息中心接口测试") |
||||
|
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) |
||||
|
public class SiqControllerTest { |
||||
|
|
||||
|
@Autowired |
||||
|
private ISIQService siqService; |
||||
|
|
||||
|
private static final String TEST_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e"; |
||||
|
|
||||
|
@BeforeEach |
||||
|
public void setUp() { |
||||
|
SaTokenContextMockUtil.setMockContext(); |
||||
|
|
||||
|
MockHttpServletRequest mockRequest = new MockHttpServletRequest(); |
||||
|
mockRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"); |
||||
|
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(mockRequest)); |
||||
|
|
||||
|
LoginUser loginUser = new LoginUser(); |
||||
|
loginUser.setUserId(1L); |
||||
|
loginUser.setUserType("sys_user"); |
||||
|
loginUser.setTenantId("000000"); |
||||
|
loginUser.setUsername("test_admin"); |
||||
|
loginUser.setNickname("测试管理员"); |
||||
|
loginUser.setDeptId("103"); |
||||
|
loginUser.setDeptName("测试部门"); |
||||
|
loginUser.setRolePermission(new HashSet<>()); |
||||
|
loginUser.setMenuPermission(new HashSet<>()); |
||||
|
|
||||
|
SaLoginParameter param = new SaLoginParameter(); |
||||
|
param.setExtra(LoginHelper.CLIENT_KEY, TEST_CLIENT_ID); |
||||
|
LoginHelper.login(loginUser, param); |
||||
|
} |
||||
|
|
||||
|
@AfterEach |
||||
|
public void tearDown() { |
||||
|
try { |
||||
|
StpUtil.logout(); |
||||
|
} catch (Exception ignored) { |
||||
|
} |
||||
|
RequestContextHolder.resetRequestAttributes(); |
||||
|
SaTokenContextMockUtil.clearContext(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@DisplayName("发送消息 - 固定参数直接请求深I企接口") |
||||
|
@Test |
||||
|
@Order(7) |
||||
|
public void testSendMsg_smsChannel() throws Exception { |
||||
|
SIQMsgParamBo paramBo = new SIQMsgParamBo(); |
||||
|
paramBo.setReceiveAccount("3846cbc20dce4140a42e33254414e02f"); |
||||
|
Map<String, String> variables = new HashMap<>(); |
||||
|
variables.put("enterName", "深圳市腾讯计算机系统有限公司"); |
||||
|
variables.put("dept", "深圳市司法局"); |
||||
|
variables.put("time", "2026-07-30"); |
||||
|
paramBo.setAdditionalData(variables); |
||||
|
siqService.sendMsg(paramBo); |
||||
|
} |
||||
|
//
|
||||
|
// @DisplayName("查询任务结果 - 按taskId查询发送状态")
|
||||
|
// @Test
|
||||
|
// @Order(8)
|
||||
|
// public void testQueryTaskResult() throws Exception {
|
||||
|
// SIQTaskQueryBo queryBo = new SIQTaskQueryBo();
|
||||
|
// queryBo.setTaskId("a3514ac05fd74d9a92abea91cd2395b9");
|
||||
|
// queryBo.setPageNo(1);
|
||||
|
// queryBo.setPageSize(10);
|
||||
|
//
|
||||
|
// TaskQueryResultVo result = siqService.queryTaskResult(queryBo);
|
||||
|
// assertNotNull(result, "查询结果不应为空");
|
||||
|
// System.out.println("任务ID: " + result.getTaskId());
|
||||
|
// System.out.println("发送状态: " + result.getSendStatus());
|
||||
|
// System.out.println("总数: " + result.getTotalCount());
|
||||
|
// System.out.println("成功数: " + result.getSendSuccessCount());
|
||||
|
// System.out.println("失败数: " + result.getSendFailedCount());
|
||||
|
// }
|
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue