1. 新增 api 绑定客户凭证进行权限校验

2. 去除 api 定义的缓存策略
3. 新增短信渠道
4. 新增用户信息模糊查询
5. 修复全局的单元测试
This commit is contained in:
chenbowen
2025-12-12 10:03:10 +08:00
parent 99645c5ac8
commit cae0b9e4af
66 changed files with 1323 additions and 211 deletions

View File

@@ -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));
}
}

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -35,6 +35,10 @@ public class SmsChannelDO extends BaseDO {
* 短信签名
*/
private String signature;
/**
* 企业编号epid
*/
private String epid;
/**
* 渠道编码
*

View File

@@ -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) {

View File

@@ -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;
/**

View File

@@ -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. 执行请求

View File

@@ -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));
// 解析结果

View File

@@ -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;
}
}
}

View File

@@ -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());

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -19,6 +19,7 @@ public enum SmsChannelEnum {
TENCENT("TENCENT", "腾讯云"),
HUAWEI("HUAWEI", "华为云"),
QINIU("QINIU", "七牛云"),
HL95("HL95", "鸿联九五"),
;
/**

View File

@@ -26,6 +26,10 @@ public class SmsChannelProperties {
*/
@NotEmpty(message = "短信签名不能为空")
private String signature;
/**
* 企业编号epid。部分渠道需要例如鸿联九五
*/
private String epid;
/**
* 渠道编码
*

View File

@@ -25,6 +25,10 @@ public class SmsSendMessage {
*/
@NotNull(message = "手机号不能为空")
private String mobile;
/**
* 短信内容(已按模板格式化后的文本)
*/
private String content;
/**
* 短信渠道编号
*/

View File

@@ -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);
}

View File

@@ -78,4 +78,11 @@ public interface SmsChannelService {
*/
SmsClient getSmsClient(String code);
/**
* 查询渠道余额(条数)
* @param id 渠道编号
* @return 余额条数
*/
Integer queryBalance(Long id);
}

View File

@@ -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);
}
}

View File

@@ -65,4 +65,12 @@ public interface SmsLogService {
*/
PageResult<SmsLogDO> getSmsLogPage(SmsLogPageReqVO pageReqVO);
/**
* 根据日志编号查询短信日志
*
* @param id 日志编号
* @return 短信日志
*/
SmsLogDO getSmsLog(Long id);
}

View File

@@ -76,4 +76,8 @@ public class SmsLogServiceImpl implements SmsLogService {
return smsLogMapper.selectPage(pageReqVO);
}
@Override
public SmsLogDO getSmsLog(Long id) {
return smsLogMapper.selectById(id);
}
}

View File

@@ -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());

View File

@@ -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());
}