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