1. 新增 api 绑定客户凭证进行权限校验
2. 去除 api 定义的缓存策略 3. 新增短信渠道 4. 新增用户信息模糊查询 5. 修复全局的单元测试
This commit is contained in:
@@ -2,12 +2,15 @@ package com.zt.plat.module.system.api.sms;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
|
||||
import com.zt.plat.module.system.api.sms.dto.log.SmsLogRespDTO;
|
||||
import com.zt.plat.module.system.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
@@ -25,4 +28,8 @@ public interface SmsSendApi {
|
||||
@Operation(summary = "发送单条短信给 Member 用户", description = "在 mobile 为空时,使用 userId 加载对应 Member 的手机号")
|
||||
CommonResult<Long> sendSingleSmsToMember(@Valid @RequestBody SmsSendSingleToUserReqDTO reqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/log/get")
|
||||
@Operation(summary = "根据日志编号查询短信状态")
|
||||
CommonResult<SmsLogRespDTO> getSmsLog(@RequestParam("id") Long id);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.zt.plat.module.system.api.sms.dto.log;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Schema(description = "RPC 服务 - 短信日志返回 DTO")
|
||||
public class SmsLogRespDTO {
|
||||
|
||||
@Schema(description = "日志编号", example = "123")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "短信渠道编码", example = "HL95")
|
||||
private String channelCode;
|
||||
|
||||
@Schema(description = "模板编码", example = "HL95_TEST")
|
||||
private String templateCode;
|
||||
|
||||
@Schema(description = "短信类型")
|
||||
private Integer templateType;
|
||||
|
||||
@Schema(description = "模板内容")
|
||||
private String templateContent;
|
||||
|
||||
@Schema(description = "模板参数")
|
||||
private Map<String, Object> templateParams;
|
||||
|
||||
@Schema(description = "短信 API 模板编号")
|
||||
private String apiTemplateId;
|
||||
|
||||
@Schema(description = "手机号", example = "13800138000")
|
||||
private String mobile;
|
||||
|
||||
@Schema(description = "用户编号", example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "用户类型")
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "发送状态")
|
||||
private Integer sendStatus;
|
||||
|
||||
@Schema(description = "发送时间")
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
@Schema(description = "发送结果编码")
|
||||
private String apiSendCode;
|
||||
|
||||
@Schema(description = "发送结果信息")
|
||||
private String apiSendMsg;
|
||||
|
||||
@Schema(description = "发送请求ID")
|
||||
private String apiRequestId;
|
||||
|
||||
@Schema(description = "发送序列号")
|
||||
private String apiSerialNo;
|
||||
|
||||
@Schema(description = "接收状态")
|
||||
private Integer receiveStatus;
|
||||
|
||||
@Schema(description = "接收时间")
|
||||
private LocalDateTime receiveTime;
|
||||
|
||||
@Schema(description = "接收结果编码")
|
||||
private String apiReceiveCode;
|
||||
|
||||
@Schema(description = "接收结果信息")
|
||||
private String apiReceiveMsg;
|
||||
|
||||
}
|
||||
@@ -107,6 +107,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1_002_011_000, "短信渠道不存在");
|
||||
ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1_002_011_001, "短信渠道不处于开启状态,不允许选择");
|
||||
ErrorCode SMS_CHANNEL_HAS_CHILDREN = new ErrorCode(1_002_011_002, "无法删除,该短信渠道还有短信模板");
|
||||
ErrorCode SMS_CHANNEL_BALANCE_UNSUPPORTED = new ErrorCode(1_002_011_003, "该短信渠道不支持余额查询");
|
||||
|
||||
// ========== 短信模板 1-002-012-000 ==========
|
||||
ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在");
|
||||
@@ -120,6 +121,7 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1_002_013_000, "手机号不存在");
|
||||
ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_013_001, "模板参数({})缺失");
|
||||
ErrorCode SMS_SEND_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_013_002, "短信模板不存在");
|
||||
ErrorCode SMS_CALLBACK_SIGN_INVALID = new ErrorCode(1_002_013_100, "短信回调签名校验失败");
|
||||
|
||||
// ========== 短信验证码 1-002-014-000 ==========
|
||||
ErrorCode SMS_CODE_NOT_FOUND = new ErrorCode(1_002_014_000, "验证码不存在");
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.zt.plat.module.system.api.sms;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.module.system.api.sms.dto.log.SmsLogRespDTO;
|
||||
import com.zt.plat.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
|
||||
import com.zt.plat.module.system.service.sms.SmsLogService;
|
||||
import com.zt.plat.module.system.service.sms.SmsSendService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -16,6 +19,8 @@ public class SmsSendApiImpl implements SmsSendApi {
|
||||
|
||||
@Resource
|
||||
private SmsSendService smsSendService;
|
||||
@Resource
|
||||
private SmsLogService smsLogService;
|
||||
|
||||
@Override
|
||||
public CommonResult<Long> sendSingleSmsToAdmin(SmsSendSingleToUserReqDTO reqDTO) {
|
||||
@@ -29,4 +34,9 @@ public class SmsSendApiImpl implements SmsSendApi {
|
||||
reqDTO.getTemplateCode(), reqDTO.getTemplateParams()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<SmsLogRespDTO> getSmsLog(Long id) {
|
||||
return success(BeanUtils.toBean(smsLogService.getSmsLog(id), SmsLogRespDTO.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -71,6 +71,14 @@ public class SmsChannelController {
|
||||
return success(BeanUtils.toBean(pageResult, SmsChannelRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/balance")
|
||||
@Operation(summary = "查询短信渠道余额")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:sms-channel:query')")
|
||||
public CommonResult<Integer> getBalance(@RequestParam("id") Long id) {
|
||||
return success(smsChannelService.queryBalance(id));
|
||||
}
|
||||
|
||||
@GetMapping({"/list-all-simple", "/simple-list"})
|
||||
@Operation(summary = "获得短信渠道精简列表", description = "包含被禁用的短信渠道")
|
||||
public CommonResult<List<SmsChannelSimpleRespVO>> getSimpleSmsChannelList() {
|
||||
|
||||
@@ -32,6 +32,9 @@ public class SmsChannelRespVO {
|
||||
@NotNull(message = "短信 API 的账号不能为空")
|
||||
private String apiKey;
|
||||
|
||||
@Schema(description = "企业编号(epid)", example = "123456")
|
||||
private String epid;
|
||||
|
||||
@Schema(description = "短信 API 的密钥", example = "yuanma")
|
||||
private String apiSecret;
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ public class SmsChannelSaveReqVO {
|
||||
@NotNull(message = "短信签名不能为空")
|
||||
private String signature;
|
||||
|
||||
@Schema(description = "企业编号(epid)", example = "123456")
|
||||
private String epid;
|
||||
|
||||
@Schema(description = "渠道编码,参见 SmsChannelEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "YUN_PIAN")
|
||||
@NotNull(message = "渠道编码不能为空")
|
||||
private String code;
|
||||
|
||||
@@ -29,6 +29,9 @@ public class UserPageReqVO extends PageParam {
|
||||
@Schema(description = "手机号码,模糊匹配", example = "zt")
|
||||
private String mobile;
|
||||
|
||||
@Schema(description = "关键词(昵称/账号/手机号模糊匹配)", example = "张三")
|
||||
private String keyword;
|
||||
|
||||
@Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
|
||||
private Integer status;
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.zt.plat.module.system.controller.app.sms;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import com.zt.plat.framework.common.util.json.JsonUtils;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsChannelDO;
|
||||
import com.zt.plat.module.system.enums.ErrorCodeConstants;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.SmsChannelEnum;
|
||||
import com.zt.plat.module.system.service.sms.SmsChannelService;
|
||||
import com.zt.plat.module.system.service.sms.SmsSendService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RestController
|
||||
@Tag(name = "鸿联九五 - 短信回调")
|
||||
@RequestMapping("/system/sms/callback/hl95")
|
||||
public class Hl95SmsCallbackController {
|
||||
|
||||
@Resource
|
||||
private SmsSendService smsSendService;
|
||||
@Resource
|
||||
private SmsChannelService smsChannelService;
|
||||
|
||||
@RequestMapping(value = "/status", method = {RequestMethod.GET, RequestMethod.POST})
|
||||
@Operation(summary = "状态报告回调")
|
||||
@PermitAll
|
||||
public String statusCallback(@RequestParam Map<String, String> params) {
|
||||
try {
|
||||
checkSign(params);
|
||||
smsSendService.receiveSmsStatus(SmsChannelEnum.HL95.getCode(), JsonUtils.toJsonString(params));
|
||||
return "OK";
|
||||
} catch (Throwable e) {
|
||||
log.warn("[statusCallback][鸿联九五回调处理失败 params={} error={}]", params, e.getMessage(), e);
|
||||
return "FAIL";
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/mo", method = {RequestMethod.GET, RequestMethod.POST})
|
||||
@Operation(summary = "上行短信回调")
|
||||
@PermitAll
|
||||
public String moCallback(@RequestParam Map<String, String> params) {
|
||||
try {
|
||||
checkSign(params);
|
||||
log.info("[moCallback][收到鸿联九五上行:{}]", params);
|
||||
return "OK";
|
||||
} catch (Throwable e) {
|
||||
log.warn("[moCallback][鸿联九五上行处理失败 params={} error={}]", params, e.getMessage(), e);
|
||||
return "FAIL";
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSign(Map<String, String> params) {
|
||||
String sign = params.get("sign");
|
||||
if (StrUtil.isBlank(sign)) {
|
||||
throw exception(ErrorCodeConstants.SMS_CALLBACK_SIGN_INVALID);
|
||||
}
|
||||
SmsChannelDO channel = smsChannelService.getSmsChannelList().stream()
|
||||
.filter(item -> StrUtil.equals(item.getCode(), SmsChannelEnum.HL95.getCode()))
|
||||
.min(Comparator.comparing(SmsChannelDO::getId))
|
||||
.orElse(null);
|
||||
if (channel == null) {
|
||||
throw exception(ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS);
|
||||
}
|
||||
String expect = buildSign(params, channel.getApiSecret());
|
||||
if (!StrUtil.equalsIgnoreCase(sign, expect)) {
|
||||
throw exception(ErrorCodeConstants.SMS_CALLBACK_SIGN_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
private static String buildSign(Map<String, String> params, String secret) {
|
||||
SortedMap<String, String> sorted = new TreeMap<>();
|
||||
params.forEach((k, v) -> {
|
||||
if (!"sign".equalsIgnoreCase(k)) {
|
||||
sorted.put(k, StrUtil.nullToEmpty(v));
|
||||
}
|
||||
});
|
||||
String base = sorted.entrySet().stream()
|
||||
.map(e -> e.getKey() + "=" + e.getValue())
|
||||
.collect(Collectors.joining("&"));
|
||||
return DigestUtil.md5Hex(base + "&key=" + secret);
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,10 @@ public class SmsChannelDO extends BaseDO {
|
||||
* 短信签名
|
||||
*/
|
||||
private String signature;
|
||||
/**
|
||||
* 企业编号(epid)
|
||||
*/
|
||||
private String epid;
|
||||
/**
|
||||
* 渠道编码
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.zt.plat.module.system.dal.mysql.user;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
@@ -36,18 +37,27 @@ public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
|
||||
}
|
||||
|
||||
default PageResult<AdminUserDO> selectPage(UserPageReqVO reqVO, Collection<Long> deptIds, Collection<Long> userIds) {
|
||||
MPJLambdaWrapperX<AdminUserDO> query = new MPJLambdaWrapperX<>();
|
||||
query.leftJoin(UserDeptDO.class, UserDeptDO::getUserId, AdminUserDO::getId);
|
||||
query.likeIfPresent(AdminUserDO::getUsername, reqVO.getUsername());
|
||||
query.likeIfPresent(AdminUserDO::getWorkcode, reqVO.getWorkcode());
|
||||
query.likeIfPresent(AdminUserDO::getMobile, reqVO.getMobile());
|
||||
query.eqIfPresent(AdminUserDO::getStatus, reqVO.getStatus());
|
||||
query.betweenIfPresent(AdminUserDO::getCreateTime, reqVO.getCreateTime());
|
||||
query.inIfPresent(UserDeptDO::getDeptId, deptIds);
|
||||
query.inIfPresent(AdminUserDO::getId, userIds);
|
||||
query.distinct();
|
||||
query.orderByDesc(AdminUserDO::getId);
|
||||
|
||||
return selectJoinPage(reqVO, AdminUserDO.class, new MPJLambdaWrapperX<AdminUserDO>()
|
||||
.leftJoin(UserDeptDO.class, UserDeptDO::getUserId, AdminUserDO::getId)
|
||||
.likeIfPresent(AdminUserDO::getUsername, reqVO.getUsername())
|
||||
.likeIfPresent(AdminUserDO::getWorkcode, reqVO.getWorkcode())
|
||||
.likeIfPresent(AdminUserDO::getMobile, reqVO.getMobile())
|
||||
.eqIfPresent(AdminUserDO::getStatus, reqVO.getStatus())
|
||||
.betweenIfPresent(AdminUserDO::getCreateTime, reqVO.getCreateTime())
|
||||
.inIfPresent(UserDeptDO::getDeptId, deptIds)
|
||||
.inIfPresent(AdminUserDO::getId, userIds)
|
||||
.distinct()
|
||||
.orderByDesc(AdminUserDO::getId));
|
||||
if (StrUtil.isNotBlank(reqVO.getKeyword())) {
|
||||
String keyword = reqVO.getKeyword().trim();
|
||||
query.and(w -> w.like(AdminUserDO::getNickname, keyword)
|
||||
.or().like(AdminUserDO::getUsername, keyword)
|
||||
.or().like(AdminUserDO::getMobile, keyword)
|
||||
.or().like(AdminUserDO::getWorkcode, keyword));
|
||||
}
|
||||
|
||||
return selectJoinPage(reqVO, AdminUserDO.class, query);
|
||||
}
|
||||
|
||||
default List<AdminUserDO> selectList(UserPageReqVO reqVO, Collection<Long> deptIds, Collection<Long> userIds) {
|
||||
|
||||
@@ -31,7 +31,7 @@ public interface SmsClient {
|
||||
* @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序
|
||||
* @return 短信发送结果
|
||||
*/
|
||||
SmsSendRespDTO sendSms(Long logId, String mobile, String apiTemplateId,
|
||||
SmsSendRespDTO sendSms(Long logId, String mobile, String content, String apiTemplateId,
|
||||
List<KeyValue<String, Object>> templateParams) throws Throwable;
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId,
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String content, String apiTemplateId,
|
||||
List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||
Assert.notBlank(properties.getSignature(), "短信签名不能为空");
|
||||
// 1. 执行请求
|
||||
|
||||
@@ -36,16 +36,16 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient {
|
||||
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
|
||||
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||
@Override
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String content,
|
||||
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||
// 构建请求
|
||||
String url = buildUrl("robot/send");
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("msgtype", "text");
|
||||
String content = String.format("【模拟短信】\n手机号:%s\n短信日志编号:%d\n模板参数:%s",
|
||||
mobile, sendLogId, MapUtils.convertMap(templateParams));
|
||||
params.put("text", MapUtil.builder().put("content", content).build());
|
||||
String sendContent = String.format("【模拟短信】\n手机号:%s\n短信日志编号:%d\n模板参数:%s\n内容:%s",
|
||||
mobile, sendLogId, MapUtils.convertMap(templateParams), content);
|
||||
params.put("text", MapUtil.builder().put("content", sendContent).build());
|
||||
// 执行请求
|
||||
String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params));
|
||||
// 解析结果
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.impl;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.zt.plat.framework.common.core.KeyValue;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.impl.extra.SmsBalanceClient;
|
||||
import com.zt.plat.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||
import com.zt.plat.module.system.framework.sms.core.property.SmsChannelProperties;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
public class Hl95SmsClient extends AbstractSmsClient implements SmsBalanceClient {
|
||||
|
||||
private static final String SEND_URL = "https://api.sms.95ytx.com:9091/mxt/send";
|
||||
private static final String BALANCE_URL = "https://api.sms.95ytx.com:9091/mxt/getfee";
|
||||
private static final DateTimeFormatter STATUS_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
||||
|
||||
public Hl95SmsClient(SmsChannelProperties properties) {
|
||||
super(properties);
|
||||
Assert.notEmpty(properties.getApiKey(), "用户名(apiKey) 不能为空");
|
||||
Assert.notEmpty(properties.getApiSecret(), "密码(apiSecret) 不能为空");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsSendRespDTO sendSms(Long logId, String mobile, String content, String apiTemplateId,
|
||||
List<KeyValue<String, Object>> templateParams) {
|
||||
Assert.notEmpty(properties.getEpid(), "鸿联九五需要配置 epid");
|
||||
Assert.notEmpty(properties.getSignature(), "短信签名不能为空");
|
||||
String finalContent = appendSignatureIfMissing(content, properties.getSignature());
|
||||
String linkId = buildLinkId(logId);
|
||||
|
||||
Map<String, Object> form = new HashMap<>();
|
||||
form.put("username", properties.getApiKey());
|
||||
form.put("password", properties.getApiSecret());
|
||||
form.put("epid", properties.getEpid());
|
||||
form.put("phone", mobile);
|
||||
form.put("message", finalContent);
|
||||
form.put("linkid", linkId);
|
||||
// subcode 可为空
|
||||
|
||||
String resp;
|
||||
try (HttpResponse response = HttpRequest.post(SEND_URL)
|
||||
.form(form)
|
||||
.charset(StandardCharsets.UTF_8)
|
||||
.execute()) {
|
||||
resp = StrUtil.trim(response.body());
|
||||
}
|
||||
|
||||
boolean success = StrUtil.equals(resp, "00");
|
||||
return new SmsSendRespDTO()
|
||||
.setSuccess(success)
|
||||
.setApiCode(resp)
|
||||
.setApiMsg(resp)
|
||||
.setApiRequestId(linkId)
|
||||
.setSerialNo(linkId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
|
||||
JSONObject obj = JSONUtil.parseObj(text, false);
|
||||
String reportCode = obj.getStr("FReportCode");
|
||||
String linkId = obj.getStr("FLinkID");
|
||||
LocalDateTime deliverTime = parseDeliverTime(obj.getStr("FDeliverTime"));
|
||||
String mobile = obj.getStr("FDestAddr");
|
||||
boolean success = StrUtil.equalsIgnoreCase(reportCode, "DELIVRD") || StrUtil.equals(reportCode, "0");
|
||||
Long logId = parseLongSafely(linkId);
|
||||
|
||||
SmsReceiveRespDTO dto = new SmsReceiveRespDTO()
|
||||
.setSuccess(success)
|
||||
.setErrorCode(reportCode)
|
||||
.setErrorMsg(reportCode)
|
||||
.setMobile(mobile)
|
||||
.setReceiveTime(deliverTime)
|
||||
.setSerialNo(linkId)
|
||||
.setLogId(logId);
|
||||
return Collections.singletonList(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) {
|
||||
// 鸿联九五无模板审核接口,直接返回可用
|
||||
return new SmsTemplateRespDTO()
|
||||
.setId(apiTemplateId)
|
||||
.setContent(apiTemplateId)
|
||||
.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer queryBalance() {
|
||||
Assert.notEmpty(properties.getEpid(), "鸿联九五需要配置 epid");
|
||||
Map<String, Object> form = MapUtil.<String, Object>builder()
|
||||
.put("username", properties.getApiKey())
|
||||
.put("password", properties.getApiSecret())
|
||||
.put("epid", properties.getEpid())
|
||||
.build();
|
||||
String resp;
|
||||
try (HttpResponse response = HttpRequest.get(BALANCE_URL)
|
||||
.form(form)
|
||||
.charset(StandardCharsets.UTF_8)
|
||||
.execute()) {
|
||||
if (response.getStatus() != HttpURLConnection.HTTP_OK) {
|
||||
throw new IllegalStateException("余额查询失败,HTTP 状态码:" + response.getStatus());
|
||||
}
|
||||
resp = StrUtil.trim(response.body());
|
||||
}
|
||||
if (!StrUtil.isNumeric(resp)) {
|
||||
throw new IllegalStateException("余额查询失败,返回值:" + resp);
|
||||
}
|
||||
return Integer.valueOf(resp);
|
||||
}
|
||||
|
||||
private static String appendSignatureIfMissing(String content, String signature) {
|
||||
if (StrUtil.isBlank(signature)) {
|
||||
return content;
|
||||
}
|
||||
String wrapped = StrUtil.startWithAny(signature, "【", "[") ? signature : "【" + signature + "】";
|
||||
return StrUtil.startWith(content, wrapped) ? content : wrapped + content;
|
||||
}
|
||||
|
||||
private static String buildLinkId(Long logId) {
|
||||
String raw = String.valueOf(logId);
|
||||
return raw.length() > 20 ? raw.substring(raw.length() - 20) : raw;
|
||||
}
|
||||
|
||||
private static LocalDateTime parseDeliverTime(String timeText) {
|
||||
if (StrUtil.isBlank(timeText)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return LocalDateTime.parse(timeText, STATUS_TIME_FORMATTER);
|
||||
} catch (Exception ex) {
|
||||
log.warn("[parseDeliverTime][无法解析时间:{}]", timeText, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Long parseLongSafely(String text) {
|
||||
try {
|
||||
return Long.parseLong(text);
|
||||
} catch (Exception ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public class HuaweiSmsClient extends AbstractSmsClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId,
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String content, String apiTemplateId,
|
||||
List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||
StringBuilder requestBody = new StringBuilder();
|
||||
appendToBody(requestBody, "from=", getSender());
|
||||
|
||||
@@ -41,7 +41,7 @@ public class QiniuSmsClient extends AbstractSmsClient {
|
||||
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
||||
}
|
||||
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId,
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String content, String apiTemplateId,
|
||||
List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||
// 1. 执行请求
|
||||
// 参考链接 https://developer.qiniu.com/sms/5824/through-the-api-send-text-messages
|
||||
|
||||
@@ -81,6 +81,7 @@ public class SmsClientFactoryImpl implements SmsClientFactory {
|
||||
case TENCENT: return new TencentSmsClient(properties);
|
||||
case HUAWEI: return new HuaweiSmsClient(properties);
|
||||
case QINIU: return new QiniuSmsClient(properties);
|
||||
case HL95: return new Hl95SmsClient(properties);
|
||||
}
|
||||
// 创建失败,错误日志 + 抛出异常
|
||||
log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
|
||||
|
||||
@@ -82,7 +82,7 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
|
||||
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String content,
|
||||
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||
// 1. 执行请求
|
||||
// 参考链接 https://cloud.tencent.com/document/product/382/55981
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.zt.plat.module.system.framework.sms.core.client.impl.extra;
|
||||
|
||||
/**
|
||||
* 支持查询余额的短信客户端扩展接口
|
||||
*/
|
||||
public interface SmsBalanceClient {
|
||||
|
||||
/**
|
||||
* 查询当前渠道可用余额(条数)
|
||||
*
|
||||
* @return 余额条数
|
||||
* @throws Throwable 查询失败时抛出异常
|
||||
*/
|
||||
Integer queryBalance() throws Throwable;
|
||||
}
|
||||
@@ -19,6 +19,7 @@ public enum SmsChannelEnum {
|
||||
TENCENT("TENCENT", "腾讯云"),
|
||||
HUAWEI("HUAWEI", "华为云"),
|
||||
QINIU("QINIU", "七牛云"),
|
||||
HL95("HL95", "鸿联九五"),
|
||||
;
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,10 @@ public class SmsChannelProperties {
|
||||
*/
|
||||
@NotEmpty(message = "短信签名不能为空")
|
||||
private String signature;
|
||||
/**
|
||||
* 企业编号(epid)。部分渠道需要,例如鸿联九五
|
||||
*/
|
||||
private String epid;
|
||||
/**
|
||||
* 渠道编码
|
||||
*
|
||||
|
||||
@@ -25,6 +25,10 @@ public class SmsSendMessage {
|
||||
*/
|
||||
@NotNull(message = "手机号不能为空")
|
||||
private String mobile;
|
||||
/**
|
||||
* 短信内容(已按模板格式化后的文本)
|
||||
*/
|
||||
private String content;
|
||||
/**
|
||||
* 短信渠道编号
|
||||
*/
|
||||
|
||||
@@ -32,9 +32,9 @@ public class SmsProducer {
|
||||
* @param apiTemplateId 短信模板编号
|
||||
* @param templateParams 短信模板参数
|
||||
*/
|
||||
public void sendSmsSendMessage(Long logId, String mobile,
|
||||
public void sendSmsSendMessage(Long logId, String mobile, String content,
|
||||
Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
|
||||
SmsSendMessage message = new SmsSendMessage().setLogId(logId).setMobile(mobile);
|
||||
SmsSendMessage message = new SmsSendMessage().setLogId(logId).setMobile(mobile).setContent(content);
|
||||
message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
|
||||
rocketMQTemplate.syncSend(SmsSendMessage.TOPIC, message);
|
||||
}
|
||||
|
||||
@@ -78,4 +78,11 @@ public interface SmsChannelService {
|
||||
*/
|
||||
SmsClient getSmsClient(String code);
|
||||
|
||||
/**
|
||||
* 查询渠道余额(条数)
|
||||
* @param id 渠道编号
|
||||
* @return 余额条数
|
||||
*/
|
||||
Integer queryBalance(Long id);
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.zt.plat.module.system.dal.dataobject.sms.SmsChannelDO;
|
||||
import com.zt.plat.module.system.dal.mysql.sms.SmsChannelMapper;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.SmsClient;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.SmsClientFactory;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.impl.extra.SmsBalanceClient;
|
||||
import com.zt.plat.module.system.framework.sms.core.property.SmsChannelProperties;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -16,8 +17,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.zt.plat.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN;
|
||||
import static com.zt.plat.module.system.enums.ErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
|
||||
import static com.zt.plat.module.system.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 短信渠道 Service 实现类
|
||||
@@ -100,4 +100,19 @@ public class SmsChannelServiceImpl implements SmsChannelService {
|
||||
return smsClientFactory.getSmsClient(code);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer queryBalance(Long id) {
|
||||
SmsChannelDO channel = validateSmsChannelExists(id);
|
||||
SmsChannelProperties properties = BeanUtils.toBean(channel, SmsChannelProperties.class);
|
||||
SmsClient client = smsClientFactory.createOrUpdateSmsClient(properties);
|
||||
if (client instanceof SmsBalanceClient) {
|
||||
try {
|
||||
return ((SmsBalanceClient) client).queryBalance();
|
||||
} catch (Throwable e) {
|
||||
throw exception(SMS_TEMPLATE_API_ERROR, "查询余额失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
throw exception(SMS_CHANNEL_BALANCE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,4 +65,12 @@ public interface SmsLogService {
|
||||
*/
|
||||
PageResult<SmsLogDO> getSmsLogPage(SmsLogPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 根据日志编号查询短信日志
|
||||
*
|
||||
* @param id 日志编号
|
||||
* @return 短信日志
|
||||
*/
|
||||
SmsLogDO getSmsLog(Long id);
|
||||
|
||||
}
|
||||
|
||||
@@ -76,4 +76,8 @@ public class SmsLogServiceImpl implements SmsLogService {
|
||||
return smsLogMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsLogDO getSmsLog(Long id) {
|
||||
return smsLogMapper.selectById(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class SmsSendServiceImpl implements SmsSendService {
|
||||
|
||||
// 发送 MQ 消息,异步执行发送短信
|
||||
if (isSend) {
|
||||
smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(),
|
||||
smsProducer.sendSmsSendMessage(sendLogId, mobile, content, template.getChannelId(),
|
||||
template.getApiTemplateId(), newTemplateParams);
|
||||
}
|
||||
return sendLogId;
|
||||
@@ -161,8 +161,8 @@ public class SmsSendServiceImpl implements SmsSendService {
|
||||
Assert.notNull(smsClient, "短信客户端({}) 不存在", message.getChannelId());
|
||||
// 发送短信
|
||||
try {
|
||||
SmsSendRespDTO sendResponse = smsClient.sendSms(message.getLogId(), message.getMobile(),
|
||||
message.getApiTemplateId(), message.getTemplateParams());
|
||||
SmsSendRespDTO sendResponse = smsClient.sendSms(message.getLogId(), message.getMobile(),
|
||||
message.getContent(), message.getApiTemplateId(), message.getTemplateParams());
|
||||
smsLogService.updateSmsSendResult(message.getLogId(), sendResponse.getSuccess(),
|
||||
sendResponse.getApiCode(), sendResponse.getApiMsg(),
|
||||
sendResponse.getApiRequestId(), sendResponse.getSerialNo());
|
||||
|
||||
@@ -197,9 +197,8 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
if (StrUtil.isNotBlank(updateReqVO.getNickname())) {
|
||||
updateObj.setNickname(updateReqVO.getNickname());
|
||||
}
|
||||
if (updateReqVO.getWorkcode() != null) {
|
||||
updateObj.setWorkcode(normalizeWorkcode(updateReqVO.getWorkcode()));
|
||||
}
|
||||
// 工号允许清空,因此直接归一化后写入
|
||||
updateObj.setWorkcode(normalizeWorkcode(updateReqVO.getWorkcode()));
|
||||
if (StrUtil.isNotBlank(updateReqVO.getMobile())) {
|
||||
updateObj.setMobile(updateReqVO.getMobile());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.zt.plat.module.system.dal.mysql.user;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.test.core.ut.BaseDbUnitTest;
|
||||
import com.zt.plat.module.system.controller.admin.user.vo.user.UserPageReqVO;
|
||||
import com.zt.plat.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.zt.plat.module.system.dal.dataobject.userdept.UserDeptDO;
|
||||
import com.zt.plat.module.system.dal.mysql.userdept.UserDeptMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
|
||||
import static com.zt.plat.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
import static com.zt.plat.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* {@link AdminUserMapper} 单元测试
|
||||
*/
|
||||
public class AdminUserMapperTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private AdminUserMapper adminUserMapper;
|
||||
@Resource
|
||||
private UserDeptMapper userDeptMapper;
|
||||
|
||||
@Test
|
||||
public void testSelectPage_keywordMatch() {
|
||||
// 准备数据:两个用户,只有第一个命中 keyword
|
||||
AdminUserDO matchUser = randomUser("key-nick", "key-user", "13800000000", "WK001");
|
||||
AdminUserDO otherUser = randomUser("other", "otherUser", "13900000000", "WK002");
|
||||
adminUserMapper.insert(matchUser);
|
||||
adminUserMapper.insert(otherUser);
|
||||
|
||||
// 调用
|
||||
UserPageReqVO reqVO = new UserPageReqVO();
|
||||
reqVO.setPageNo(1);
|
||||
reqVO.setPageSize(10);
|
||||
reqVO.setKeyword("key");
|
||||
PageResult<AdminUserDO> page = adminUserMapper.selectPage(reqVO, null, (java.util.Collection<Long>) null);
|
||||
|
||||
// 断言:只返回命中的用户
|
||||
assertEquals(1, page.getList().size());
|
||||
assertPojoEquals(matchUser, page.getList().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectPage_filterByDeptIds() {
|
||||
// 用户 A 属于部门 1,用户 B 属于部门 2
|
||||
AdminUserDO dept1User = randomUser("dept1", "dept1User", "13000000001", "WK101");
|
||||
AdminUserDO dept2User = randomUser("dept2", "dept2User", "13000000002", "WK102");
|
||||
adminUserMapper.insert(dept1User);
|
||||
adminUserMapper.insert(dept2User);
|
||||
UserDeptDO ud1 = new UserDeptDO();
|
||||
ud1.setUserId(dept1User.getId());
|
||||
ud1.setDeptId(1L);
|
||||
userDeptMapper.insert(ud1);
|
||||
|
||||
UserDeptDO ud2 = new UserDeptDO();
|
||||
ud2.setUserId(dept2User.getId());
|
||||
ud2.setDeptId(2L);
|
||||
userDeptMapper.insert(ud2);
|
||||
|
||||
UserPageReqVO reqVO = new UserPageReqVO();
|
||||
reqVO.setPageNo(1);
|
||||
reqVO.setPageSize(10);
|
||||
|
||||
// 仅过滤部门 1
|
||||
PageResult<AdminUserDO> page = adminUserMapper.selectPage(reqVO, Collections.singletonList(1L), null);
|
||||
|
||||
assertEquals(1, page.getList().size());
|
||||
assertEquals(dept1User.getId(), page.getList().get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectPage_filterByUserIds() {
|
||||
AdminUserDO user1 = randomUser("u1", "u1", "15000000001", "WK201");
|
||||
AdminUserDO user2 = randomUser("u2", "u2", "15000000002", "WK202");
|
||||
adminUserMapper.insert(user1);
|
||||
adminUserMapper.insert(user2);
|
||||
|
||||
UserPageReqVO reqVO = new UserPageReqVO();
|
||||
reqVO.setPageNo(1);
|
||||
reqVO.setPageSize(10);
|
||||
|
||||
PageResult<AdminUserDO> page = adminUserMapper.selectPage(reqVO, null, Collections.singletonList(user2.getId()));
|
||||
|
||||
assertEquals(1, page.getList().size());
|
||||
assertEquals(user2.getId(), page.getList().get(0).getId());
|
||||
}
|
||||
|
||||
private AdminUserDO randomUser(String nickname, String username, String mobile, String workcode) {
|
||||
AdminUserDO user = randomPojo(AdminUserDO.class, o -> {
|
||||
o.setId(null);
|
||||
o.setNickname(nickname);
|
||||
o.setUsername(username);
|
||||
o.setMobile(mobile);
|
||||
o.setWorkcode(workcode);
|
||||
o.setSex(1);
|
||||
o.setStatus(0);
|
||||
o.setUserSource(1);
|
||||
// 这些字段仅用于展示,不参与持久化,避免断言时与查询结果不一致
|
||||
o.setDeptIds(null);
|
||||
o.setDeptNames(null);
|
||||
o.setCompanyIds(null);
|
||||
o.setCompanyDeptInfos(null);
|
||||
o.setCreateTime(LocalDateTime.now().withNano(0));
|
||||
});
|
||||
// 保证关键字段非空
|
||||
if (!StringUtils.hasText(user.getPassword())) {
|
||||
user.setPassword("pwd");
|
||||
}
|
||||
if (user.getTenantId() == null) {
|
||||
user.setTenantId(1L);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("code", 1234), new KeyValue<>("op", "login"));
|
||||
// mock 方法
|
||||
@@ -55,7 +56,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||
.then((Answer<String>) invocationOnMock -> (String) invocationOnMock.getArguments()[0]);
|
||||
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content,
|
||||
apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertTrue(result.getSuccess());
|
||||
@@ -73,6 +74,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("code", 1234), new KeyValue<>("op", "login"));
|
||||
// mock 方法
|
||||
@@ -82,7 +84,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||
.then((Answer<String>) invocationOnMock -> (String) invocationOnMock.getArguments()[0]);
|
||||
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content, apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertFalse(result.getSuccess());
|
||||
assertEquals("B7700B8E-227E-5886-9564-26036172F01F", result.getApiRequestId());
|
||||
|
||||
@@ -43,6 +43,7 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString() + " " + randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
|
||||
|
||||
@@ -51,7 +52,7 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
|
||||
.thenReturn("{\"result\":[{\"originTo\":\"+86155****5678\",\"createTime\":\"2018-05-25T16:34:34Z\",\"from\":\"1069********0012\",\"smsMsgId\":\"d6e3cdd0-522b-4692-8304-a07553cdf591_8539659\",\"status\":\"000000\",\"countryId\":\"CN\",\"total\":2}],\"code\":\"000000\",\"description\":\"Success\"}\n");
|
||||
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content,
|
||||
apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertTrue(result.getSuccess());
|
||||
@@ -67,6 +68,7 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString() + " " + randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
|
||||
|
||||
@@ -75,7 +77,7 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
|
||||
.thenReturn("{\"result\":[{\"total\":1,\"originTo\":\"17321315478\",\"createTime\":\"2024-08-18T11:32:20Z\",\"from\":\"x8824060312575\",\"smsMsgId\":\"06e4b966-ad87-479f-8b74-f57fb7aafb60_304613461\",\"countryId\":\"CN\",\"status\":\"E200033\"}],\"code\":\"E000510\",\"description\":\"The SMS fails to be sent. For details, see status.\"}");
|
||||
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content,
|
||||
apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertFalse(result.getSuccess());
|
||||
@@ -91,6 +93,7 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString() + " " + randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
|
||||
|
||||
@@ -99,7 +102,7 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
|
||||
.thenReturn("{\"code\":\"E000102\",\"description\":\"Invalid app_key.\"}");
|
||||
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content,
|
||||
apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertFalse(result.getSuccess());
|
||||
|
||||
@@ -45,13 +45,14 @@ public class QiniuSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString() + " " + randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
|
||||
// mock 方法
|
||||
httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString()))
|
||||
.thenReturn("{\"message_id\":\"17245678901\"}");
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content,
|
||||
apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertTrue(result.getSuccess());
|
||||
@@ -66,13 +67,14 @@ public class QiniuSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString() + " " + randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
|
||||
// mock 方法
|
||||
httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString()))
|
||||
.thenReturn("{\"error\":\"BadToken\",\"message\":\"Your authorization token is invalid\",\"request_id\":\"etziWcJFo1C8Ne8X\"}");
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content,
|
||||
apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertFalse(result.getSuccess());
|
||||
|
||||
@@ -29,6 +29,7 @@ public class SmsClientTests {
|
||||
AliyunSmsClient client = new AliyunSmsClient(properties);
|
||||
// 准备参数
|
||||
String apiTemplateId = "SMS_207945135";
|
||||
String content = "test";
|
||||
// 调用
|
||||
SmsTemplateRespDTO template = client.getSmsTemplate(apiTemplateId);
|
||||
// 打印结果
|
||||
@@ -47,8 +48,9 @@ public class SmsClientTests {
|
||||
Long sendLogId = System.currentTimeMillis();
|
||||
String mobile = "15601691323";
|
||||
String apiTemplateId = "SMS_207945135";
|
||||
String content = "test";
|
||||
// 调用
|
||||
SmsSendRespDTO sendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, ListUtil.of(new KeyValue<>("code", "1024")));
|
||||
SmsSendRespDTO sendRespDTO = client.sendSms(sendLogId, mobile, content, apiTemplateId, ListUtil.of(new KeyValue<String, Object>("code", "1024")));
|
||||
// 打印结果
|
||||
System.out.println(sendRespDTO);
|
||||
}
|
||||
@@ -68,8 +70,9 @@ public class SmsClientTests {
|
||||
Long sendLogId = System.currentTimeMillis();
|
||||
String mobile = "15601691323";
|
||||
String apiTemplateId = "358212";
|
||||
String content = "test";
|
||||
// 调用
|
||||
SmsSendRespDTO sendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, ListUtil.of(new KeyValue<>("code", "1024")));
|
||||
SmsSendRespDTO sendRespDTO = client.sendSms(sendLogId, mobile, content, apiTemplateId, ListUtil.of(new KeyValue<String, Object>("code", "1024")));
|
||||
// 打印结果
|
||||
System.out.println(sendRespDTO);
|
||||
}
|
||||
@@ -106,9 +109,10 @@ public class SmsClientTests {
|
||||
Long sendLogId = System.currentTimeMillis();
|
||||
String mobile = "17321315478";
|
||||
String apiTemplateId = "3644cdab863546a3b718d488659a99ef";
|
||||
List<KeyValue<String, Object>> templateParams = ListUtil.of(new KeyValue<>("code", "1024"));
|
||||
String content = "test";
|
||||
List<KeyValue<String, Object>> templateParams = ListUtil.of(new KeyValue<String, Object>("code", "1024"));
|
||||
// 调用
|
||||
SmsSendRespDTO smsSendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
|
||||
SmsSendRespDTO smsSendRespDTO = client.sendSms(sendLogId, mobile, content, apiTemplateId, templateParams);
|
||||
// 打印结果
|
||||
System.out.println(smsSendRespDTO);
|
||||
}
|
||||
@@ -126,9 +130,10 @@ public class SmsClientTests {
|
||||
Long sendLogId = System.currentTimeMillis();
|
||||
String mobile = "17321315478";
|
||||
String apiTemplateId = "3644cdab863546a3b718d488659a99ef";
|
||||
List<KeyValue<String, Object>> templateParams = ListUtil.of(new KeyValue<>("code", "1122"));
|
||||
String content = "test";
|
||||
List<KeyValue<String, Object>> templateParams = ListUtil.of(new KeyValue<String, Object>("code", "1122"));
|
||||
// 调用
|
||||
SmsSendRespDTO smsSendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
|
||||
SmsSendRespDTO smsSendRespDTO = client.sendSms(sendLogId, mobile, content, apiTemplateId, templateParams);
|
||||
// 打印结果
|
||||
System.out.println(smsSendRespDTO);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
|
||||
// mock 方法
|
||||
@@ -67,7 +68,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||
"}");
|
||||
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content,
|
||||
apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertTrue(result.getSuccess());
|
||||
@@ -84,6 +85,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
|
||||
|
||||
@@ -107,7 +109,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||
"}");
|
||||
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content,
|
||||
apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertFalse(result.getSuccess());
|
||||
@@ -124,6 +126,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||
Long sendLogId = randomLongId();
|
||||
String mobile = randomString();
|
||||
String apiTemplateId = randomString();
|
||||
String content = randomString();
|
||||
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
|
||||
|
||||
@@ -132,7 +135,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||
.thenReturn("{\"Response\":{\"Error\":{\"Code\":\"AuthFailure.SecretIdNotFound\",\"Message\":\"The SecretId is not found, please ensure that your SecretId is correct.\"},\"RequestId\":\"2a88f82a-261c-4ac6-9fa9-c7d01aaa486a\"}}");
|
||||
|
||||
// 调用
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, content,
|
||||
apiTemplateId, templateParams);
|
||||
// 断言
|
||||
assertFalse(result.getSuccess());
|
||||
|
||||
@@ -85,7 +85,7 @@ public class DictDataServiceImplTest extends BaseDbUnitTest {
|
||||
dictDataMapper.insert(cloneIgnoreId(dbDictData, o -> o.setValue("otherValue")));
|
||||
// 准备参数
|
||||
DictDataPageReqVO reqVO = new DictDataPageReqVO();
|
||||
reqVO.setLabel("芋");
|
||||
reqVO.setLabel("ZT");
|
||||
reqVO.setDictType("yunai");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
reqVO.setValue("testValue");
|
||||
|
||||
@@ -59,8 +59,8 @@ public class DictTypeServiceImplTest extends BaseDbUnitTest {
|
||||
dictTypeMapper.insert(cloneIgnoreId(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1))));
|
||||
// 准备参数
|
||||
DictTypePageReqVO reqVO = new DictTypePageReqVO();
|
||||
reqVO.setName("nai");
|
||||
reqVO.setType("艿");
|
||||
reqVO.setName("yunai");
|
||||
reqVO.setType("ZT");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
reqVO.setCreateTime(buildBetweenTime(2021, 1, 10, 2021, 1, 20));
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
||||
// 测试 name 不匹配
|
||||
menuMapper.insert(cloneIgnoreId(menuDO, o -> o.setName("艿")));
|
||||
// 准备参数
|
||||
MenuListReqVO reqVO = new MenuListReqVO().setName("芋").setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
MenuListReqVO reqVO = new MenuListReqVO().setName("ZT").setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
|
||||
// 调用
|
||||
List<MenuDO> result = menuService.getMenuList(reqVO);
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.zt.plat.module.system.service.sms;
|
||||
|
||||
import com.zt.plat.framework.common.exception.ServiceException;
|
||||
import com.zt.plat.module.system.dal.dataobject.sms.SmsChannelDO;
|
||||
import com.zt.plat.module.system.dal.mysql.sms.SmsChannelMapper;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.SmsClient;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.SmsClientFactory;
|
||||
import com.zt.plat.module.system.framework.sms.core.client.impl.extra.SmsBalanceClient;
|
||||
import com.zt.plat.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import static com.zt.plat.framework.test.core.util.RandomUtils.randomLongId;
|
||||
import static com.zt.plat.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static com.zt.plat.module.system.enums.ErrorCodeConstants.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class SmsChannelServiceImplTest extends BaseMockitoUnitTest {
|
||||
|
||||
@InjectMocks
|
||||
private SmsChannelServiceImpl smsChannelService;
|
||||
|
||||
@Mock
|
||||
private SmsClientFactory smsClientFactory;
|
||||
@Mock
|
||||
private SmsChannelMapper smsChannelMapper;
|
||||
@Mock
|
||||
private SmsTemplateService smsTemplateService;
|
||||
|
||||
@Test
|
||||
public void testQueryBalance_success() throws Throwable {
|
||||
Long channelId = randomLongId();
|
||||
SmsChannelDO channel = randomPojo(SmsChannelDO.class, o -> o.setId(channelId));
|
||||
when(smsChannelMapper.selectById(eq(channelId))).thenReturn(channel);
|
||||
|
||||
SmsClient client = mock(SmsClient.class, withSettings().extraInterfaces(SmsBalanceClient.class));
|
||||
when(smsClientFactory.createOrUpdateSmsClient(any())).thenReturn(client);
|
||||
when(((SmsBalanceClient) client).queryBalance()).thenReturn(88);
|
||||
|
||||
Integer balance = smsChannelService.queryBalance(channelId);
|
||||
|
||||
assertThat(balance).isEqualTo(88);
|
||||
verify((SmsBalanceClient) client, times(1)).queryBalance();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryBalance_unsupported() {
|
||||
Long channelId = randomLongId();
|
||||
when(smsChannelMapper.selectById(eq(channelId))).thenReturn(randomPojo(SmsChannelDO.class, o -> o.setId(channelId)));
|
||||
SmsClient client = mock(SmsClient.class); // 未实现 SmsBalanceClient
|
||||
when(smsClientFactory.createOrUpdateSmsClient(any())).thenReturn(client);
|
||||
|
||||
ServiceException ex = assertThrows(ServiceException.class, () -> smsChannelService.queryBalance(channelId));
|
||||
assertThat(ex.getCode()).isEqualTo(SMS_CHANNEL_BALANCE_UNSUPPORTED.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryBalance_apiError() throws Throwable {
|
||||
Long channelId = randomLongId();
|
||||
when(smsChannelMapper.selectById(eq(channelId))).thenReturn(randomPojo(SmsChannelDO.class, o -> o.setId(channelId)));
|
||||
SmsClient client = mock(SmsClient.class, withSettings().extraInterfaces(SmsBalanceClient.class));
|
||||
when(smsClientFactory.createOrUpdateSmsClient(any())).thenReturn(client);
|
||||
when(((SmsBalanceClient) client).queryBalance()).thenThrow(new RuntimeException("boom"));
|
||||
|
||||
ServiceException ex = assertThrows(ServiceException.class, () -> smsChannelService.queryBalance(channelId));
|
||||
assertThat(ex.getCode()).isEqualTo(SMS_TEMPLATE_API_ERROR.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryBalance_channelNotFound() {
|
||||
Long channelId = randomLongId();
|
||||
when(smsChannelMapper.selectById(eq(channelId))).thenReturn(null);
|
||||
|
||||
ServiceException ex = assertThrows(ServiceException.class, () -> smsChannelService.queryBalance(channelId));
|
||||
assertThat(ex.getCode()).isEqualTo(SMS_CHANNEL_NOT_EXISTS.getCode());
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(user.getMobile()),
|
||||
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(user.getMobile()), eq(content),
|
||||
eq(template.getChannelId()), eq(template.getApiTemplateId()),
|
||||
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile),
|
||||
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile), eq(content),
|
||||
eq(template.getChannelId()), eq(template.getApiTemplateId()),
|
||||
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
|
||||
}
|
||||
@@ -164,7 +164,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile),
|
||||
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile), eq(content),
|
||||
eq(template.getChannelId()), eq(template.getApiTemplateId()),
|
||||
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
|
||||
}
|
||||
@@ -204,7 +204,7 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsProducer, times(0)).sendSmsSendMessage(anyLong(), anyString(),
|
||||
verify(smsProducer, times(0)).sendSmsSendMessage(anyLong(), anyString(), anyString(),
|
||||
anyLong(), any(), anyList());
|
||||
}
|
||||
|
||||
@@ -260,13 +260,13 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testDoSendSms() throws Throwable {
|
||||
// 准备参数
|
||||
SmsSendMessage message = randomPojo(SmsSendMessage.class);
|
||||
SmsSendMessage message = randomPojo(SmsSendMessage.class, o -> o.setContent(randomString()));
|
||||
// mock SmsClientFactory 的方法
|
||||
SmsClient smsClient = spy(SmsClient.class);
|
||||
when(smsChannelService.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient);
|
||||
// mock SmsClient 的方法
|
||||
SmsSendRespDTO sendResult = randomPojo(SmsSendRespDTO.class);
|
||||
when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()),
|
||||
when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getContent()), eq(message.getApiTemplateId()),
|
||||
eq(message.getTemplateParams()))).thenReturn(sendResult);
|
||||
|
||||
// 调用
|
||||
@@ -287,12 +287,15 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
|
||||
when(smsChannelService.getSmsClient(eq(channelCode))).thenReturn(smsClient);
|
||||
// mock SmsClient 的方法
|
||||
List<SmsReceiveRespDTO> receiveResults = randomPojoList(SmsReceiveRespDTO.class);
|
||||
when(smsClient.parseSmsReceiveStatus(eq(text))).thenReturn(receiveResults);
|
||||
|
||||
// 调用
|
||||
smsSendService.receiveSmsStatus(channelCode, text);
|
||||
// 断言
|
||||
receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(eq(result.getLogId()), eq(result.getSuccess()),
|
||||
eq(result.getReceiveTime()), eq(result.getErrorCode()), eq(result.getErrorCode())));
|
||||
for (SmsReceiveRespDTO result : receiveResults) {
|
||||
verify(smsLogService).updateSmsReceiveResult(eq(result.getLogId()), eq(result.getSuccess()),
|
||||
eq(result.getReceiveTime()), eq(result.getErrorCode()), eq(result.getErrorMsg()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ public class SocialUserServiceImplTest extends BaseDbUnitTest {
|
||||
// 准备参数
|
||||
SocialUserPageReqVO reqVO = new SocialUserPageReqVO();
|
||||
reqVO.setType(SocialTypeEnum.GITEE.getType());
|
||||
reqVO.setNickname("芋");
|
||||
reqVO.setNickname("ZT");
|
||||
reqVO.setOpenid("zt");
|
||||
reqVO.setCreateTime(buildBetweenTime(2020, 1, 10, 2020, 1, 20));
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.zt.plat.module.system.service.sso.client;
|
||||
|
||||
import com.zt.plat.module.system.framework.sso.config.ExternalSsoProperties;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
@@ -16,7 +18,6 @@ import static org.mockito.Mockito.mock;
|
||||
* 使用 Mock 的 RedisTemplate,避免外部依赖。
|
||||
*/
|
||||
@SpringBootTest(classes = { ExternalSsoClientConfiguration.class, ExternalSsoClientConfigurationLoadTest.TestBeans.class })
|
||||
@Import(ExternalSsoProperties.class)
|
||||
class ExternalSsoClientConfigurationLoadTest {
|
||||
|
||||
@TestConfiguration
|
||||
@@ -33,6 +34,16 @@ class ExternalSsoClientConfigurationLoadTest {
|
||||
props.getRemote().setBaseUrl("http://localhost");
|
||||
return props;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
return new ObjectMapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestTemplateBuilder restTemplateBuilder() {
|
||||
return new RestTemplateBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -306,7 +306,7 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
|
||||
// 准备参数
|
||||
TenantPageReqVO reqVO = new TenantPageReqVO();
|
||||
reqVO.setName("ZT");
|
||||
reqVO.setContactName("艿");
|
||||
reqVO.setContactName("ZT");
|
||||
reqVO.setContactMobile("1560");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24));
|
||||
|
||||
@@ -681,6 +681,7 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
|
||||
o.setDeptNames("-");
|
||||
o.setCompanyDeptInfos(null);// 保证 deptIds 的范围
|
||||
o.setUserSource(null);
|
||||
o.setWorkcode(null);
|
||||
};
|
||||
return randomPojo(AdminUserDO.class, ArrayUtils.append(consumer, consumers));
|
||||
}
|
||||
|
||||
@@ -242,6 +242,7 @@ CREATE TABLE IF NOT EXISTS `system_operate_log` (
|
||||
CREATE TABLE IF NOT EXISTS "system_users" (
|
||||
"id" bigint not null GENERATED BY DEFAULT AS IDENTITY,
|
||||
"username" varchar(30) not null,
|
||||
"workcode" varchar(100) default null,
|
||||
"password" varchar(100) not null default '',
|
||||
"nickname" varchar(30) not null,
|
||||
"remark" varchar(500) default null,
|
||||
@@ -267,6 +268,7 @@ CREATE TABLE IF NOT EXISTS "system_users" (
|
||||
CREATE TABLE IF NOT EXISTS "system_sms_channel" (
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"signature" varchar(10) NOT NULL,
|
||||
"epid" varchar(63) DEFAULT NULL,
|
||||
"code" varchar(63) NOT NULL,
|
||||
"status" tinyint NOT NULL,
|
||||
"remark" varchar(255) DEFAULT NULL,
|
||||
|
||||
Reference in New Issue
Block a user