定义短信回调的结果

pull/2/head
YunaiV 2021-04-04 01:44:18 +08:00
parent 0d0110ec08
commit c91833a504
17 changed files with 225 additions and 187 deletions

View File

@ -128,13 +128,13 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// 设置每个请求的权限 // 设置每个请求的权限
.authorizeRequests() .authorizeRequests()
// 登陆的接口,可匿名访问 // 登陆的接口,可匿名访问
.antMatchers(webProperties.getApiPrefix() + "/login").anonymous() .antMatchers(api("/login")).anonymous()
// 通用的接口,可匿名访问 // 通用的接口,可匿名访问
.antMatchers( webProperties.getApiPrefix() + "/system/captcha/**").anonymous() .antMatchers(api("/system/captcha/**")).anonymous()
// 静态资源,可匿名访问 // 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
// 文件的获取接口,可匿名访问 // 文件的获取接口,可匿名访问
.antMatchers(webProperties.getApiPrefix() + "/infra/file/get/**").anonymous() .antMatchers(api("/infra/file/get/**")).anonymous()
// Swagger 接口文档 // Swagger 接口文档
.antMatchers("/swagger-ui.html").anonymous() .antMatchers("/swagger-ui.html").anonymous()
.antMatchers("/swagger-resources/**").anonymous() .antMatchers("/swagger-resources/**").anonymous()
@ -148,13 +148,19 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.antMatchers("/actuator/**").anonymous() .antMatchers("/actuator/**").anonymous()
// Druid 监控 // Druid 监控
.antMatchers("/druid/**").anonymous() .antMatchers("/druid/**").anonymous()
// 短信回调 API
.antMatchers(api("/system/sms/callback/**")).anonymous()
// 除上面外的所有请求全部需要鉴权认证 // 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated() .anyRequest().authenticated()
.and() .and()
.headers().frameOptions().disable(); .headers().frameOptions().disable();
httpSecurity.logout().logoutUrl(webProperties.getApiPrefix() + "/logout").logoutSuccessHandler(logoutSuccessHandler); httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler);
// 添加 JWT Filter // 添加 JWT Filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
} }
private String api(String url) {
return webProperties.getApiPrefix() + url;
}
} }

View File

@ -1,10 +1,9 @@
package cn.iocoder.dashboard.framework.sms.core.client; package cn.iocoder.dashboard.framework.sms.core.client;
import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.common.core.KeyValue;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
import javax.servlet.ServletRequest;
import java.util.List; import java.util.List;
/** /**
@ -31,15 +30,15 @@ public interface SmsClient {
* @param templateParams * @param templateParams
* @return * @return
*/ */
SmsCommonResult<SmsSendRespDTO> send(Long logId, String mobile, String apiTemplateId, List<KeyValue<String, Object>> templateParams); SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile, String apiTemplateId, List<KeyValue<String, Object>> templateParams);
// TODO FROM 芋艿 to ZZF是不是可以改成意图更明确的解析返回结果例如说 parseXXXX
/** /**
* *
* *
* @param request * @param text
* @return * @return
* @throws Throwable text
*/ */
SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception; SmsCommonResult<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable;
} }

View File

@ -18,6 +18,14 @@ public interface SmsClientFactory {
*/ */
SmsClient getSmsClient(Long channelId); SmsClient getSmsClient(Long channelId);
/**
* Client
*
* @param channelCode
* @return Client
*/
SmsClient getSmsClient(String channelCode);
/** /**
* Client * Client
* *

View File

@ -7,10 +7,12 @@ import java.io.Serializable;
import java.util.Date; import java.util.Date;
/** /**
* * Response DTO
*
* @author
*/ */
@Data @Data
public class SmsResultDetail implements Serializable { public class SmsReceiveRespDTO implements Serializable {
/** /**
* *

View File

@ -4,6 +4,7 @@ import cn.iocoder.dashboard.common.core.KeyValue;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -68,12 +69,12 @@ public abstract class AbstractSmsClient implements SmsClient {
} }
@Override @Override
public final SmsCommonResult<SmsSendRespDTO> send(Long logId, String mobile, public final SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile,
String apiTemplateId, List<KeyValue<String, Object>> templateParams) { String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
// 执行短信发送 // 执行短信发送
SmsCommonResult<SmsSendRespDTO> result; SmsCommonResult<SmsSendRespDTO> result;
try { try {
result = doSend(logId, mobile, apiTemplateId, templateParams); result = doSendSms(logId, mobile, apiTemplateId, templateParams);
} catch (Throwable ex) { } catch (Throwable ex) {
// 打印异常日志 // 打印异常日志
log.error("[send][发送短信异常sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", log.error("[send][发送短信异常sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]",
@ -84,17 +85,20 @@ public abstract class AbstractSmsClient implements SmsClient {
return result; return result;
} }
/** protected abstract SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
*
*
* @param sendLogId
* @param mobile
* @param apiTemplateId API
* @param templateParams
* @return
*/
protected abstract SmsCommonResult<SmsSendRespDTO> doSend(Long sendLogId, String mobile,
String apiTemplateId, List<KeyValue<String, Object>> templateParams) String apiTemplateId, List<KeyValue<String, Object>> templateParams)
throws Throwable; throws Throwable;
@Override
public SmsCommonResult<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable {
try {
return doParseSmsReceiveStatus(text);
} catch (Throwable ex) {
log.error("[parseSmsReceiveStatus][text({}) 解析发生异常]", text, ex);
throw ex;
}
}
protected abstract SmsCommonResult<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable;
} }

View File

@ -10,8 +10,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.util.Map; import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/** /**
* *
@ -26,20 +27,45 @@ public class SmsClientFactoryImpl implements SmsClientFactory {
* Map * Map
* key使 {@link SmsChannelProperties#getId()} * key使 {@link SmsChannelProperties#getId()}
*/ */
private final Map<Long, AbstractSmsClient> clients = new ConcurrentHashMap<>(); private final ConcurrentMap<Long, AbstractSmsClient> channelIdClients = new ConcurrentHashMap<>();
/**
* Map
* key使 {@link SmsChannelProperties#getCode()} ()}
*
* 使
* 使 {@link #channelIdClients}
*/
private final ConcurrentMap<String, AbstractSmsClient> channelCodeClients = new ConcurrentHashMap<>();
public SmsClientFactoryImpl() {
// 初始化 channelCodeClients 集合
Arrays.stream(SmsChannelEnum.values()).forEach(channel -> {
// 创建一个空的 SmsChannelProperties 对象
SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode());
// 创建 Sms 客户端
AbstractSmsClient smsClient = createSmsClient(properties);
channelCodeClients.put(channel.getCode(), smsClient);
});
}
@Override @Override
public SmsClient getSmsClient(Long channelId) { public SmsClient getSmsClient(Long channelId) {
return clients.get(channelId); return channelIdClients.get(channelId);
}
@Override
public SmsClient getSmsClient(String channelCode) {
return channelCodeClients.get(channelCode);
} }
@Override @Override
public void createOrUpdateSmsClient(SmsChannelProperties properties) { public void createOrUpdateSmsClient(SmsChannelProperties properties) {
AbstractSmsClient client = clients.get(properties.getId()); AbstractSmsClient client = channelIdClients.get(properties.getId());
if (client == null) { if (client == null) {
client = this.createSmsClient(properties); client = this.createSmsClient(properties);
client.init(); client.init();
clients.put(client.getId(), client); channelIdClients.put(client.getId(), client);
} else { } else {
client.refresh(properties); client.refresh(properties);
} }

View File

@ -5,7 +5,7 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.common.core.KeyValue;
import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
@ -61,7 +61,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
} }
@Override @Override
protected SmsCommonResult<SmsSendRespDTO> doSend(Long sendLogId, String mobile, protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
String apiTemplateId, List<KeyValue<String, Object>> templateParams) { String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
// 构建参数 // 构建参数
SendSmsRequest request = new SendSmsRequest(); SendSmsRequest request = new SendSmsRequest();
@ -110,11 +110,10 @@ public class AliyunSmsClient extends AbstractSmsClient {
* @return * @return
* @throws Exception * @throws Exception
*/ */
@Override public SmsReceiveRespDTO smsSendCallbackHandle(ServletRequest request) throws Exception {
public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
String paramStr = reader.readLine(); String paramStr = reader.readLine();
List<Map<String, Object>> params = JsonUtils.parseByType(paramStr, new TypeReference<List<Map<String, Object>>>() { List<Map<String, Object>> params = JsonUtils.parseObject(paramStr, new TypeReference<List<Map<String, Object>>>() {
}); });
if (CollectionUtil.isNotEmpty(params)) { if (CollectionUtil.isNotEmpty(params)) {
Map<String, Object> sendResultParamMap = params.get(0); Map<String, Object> sendResultParamMap = params.get(0);
@ -123,6 +122,11 @@ public class AliyunSmsClient extends AbstractSmsClient {
return null; return null;
} }
@Override
protected SmsCommonResult<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
return null;
}
/** /**
* *
*/ */
@ -168,8 +172,8 @@ public class AliyunSmsClient extends AbstractSmsClient {
return sendResultParamMap.get(CallbackField.OUT_ID).toString(); return sendResultParamMap.get(CallbackField.OUT_ID).toString();
} }
public SmsResultDetail toResultDetail() { public SmsReceiveRespDTO toResultDetail() {
SmsResultDetail resultDetail = new SmsResultDetail(); SmsReceiveRespDTO resultDetail = new SmsReceiveRespDTO();
resultDetail.setSendStatus(getSendStatus()); resultDetail.setSendStatus(getSendStatus());
resultDetail.setApiId(getBizId()); resultDetail.setApiId(getBizId());
resultDetail.setSendTime(getSendTime()); resultDetail.setSendTime(getSendTime());

View File

@ -2,33 +2,31 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil; import cn.hutool.core.util.URLUtil;
import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.common.core.KeyValue;
import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsConstants;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.date.DateUtils;
import cn.iocoder.dashboard.util.json.JsonUtils; import cn.iocoder.dashboard.util.json.JsonUtils;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.yunpian.sdk.YunpianClient; import com.yunpian.sdk.YunpianClient;
import com.yunpian.sdk.constant.YunpianConstant; import com.yunpian.sdk.constant.YunpianConstant;
import com.yunpian.sdk.model.Result; import com.yunpian.sdk.model.Result;
import com.yunpian.sdk.model.SmsSingleSend; import com.yunpian.sdk.model.SmsSingleSend;
import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
/** /**
* *
@ -65,7 +63,7 @@ public class YunpianSmsClient extends AbstractSmsClient {
} }
@Override @Override
protected SmsCommonResult<SmsSendRespDTO> doSend(Long sendLogId, String mobile, protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable { String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
// 构建参数 // 构建参数
Map<String, String> request = new HashMap<>(); Map<String, String> request = new HashMap<>();
@ -74,7 +72,7 @@ public class YunpianSmsClient extends AbstractSmsClient {
request.put(YunpianConstant.TPL_ID, apiTemplateId); request.put(YunpianConstant.TPL_ID, apiTemplateId);
request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams)); request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams));
request.put(YunpianConstant.UID, String.valueOf(sendLogId)); request.put(YunpianConstant.UID, String.valueOf(sendLogId));
request.put(Helper.CALLBACK, properties.getCallbackUrl()); request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl());
// 执行发送 // 执行发送
Result<SmsSingleSend> sendResult = client.sms().tpl_single_send(request); Result<SmsSingleSend> sendResult = client.sms().tpl_single_send(request);
@ -107,15 +105,6 @@ public class YunpianSmsClient extends AbstractSmsClient {
return sendResult.getMsg() + " => " + sendResult.getDetail(); return sendResult.getMsg() + " => " + sendResult.getDetail();
} }
/**
*
*/
@Override
public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws UnsupportedEncodingException {
Map<String, String> map = getRequestParams(request);
return Helper.getSmsResultDetailByParam(map);
}
/** /**
* request * request
* *
@ -127,7 +116,7 @@ public class YunpianSmsClient extends AbstractSmsClient {
Map<String, String[]> parameterMap = request.getParameterMap(); Map<String, String[]> parameterMap = request.getParameterMap();
String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS); String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS);
String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8); String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8);
List<Map<String, String>> paramList = JsonUtils.parseByType(encode, callbackType); List<Map<String, String>> paramList = JsonUtils.parseObject(encode, callbackType);
if (CollectionUtil.isNotEmpty(paramList)) { if (CollectionUtil.isNotEmpty(paramList)) {
return paramList.get(0); return paramList.get(0);
} }
@ -135,46 +124,63 @@ public class YunpianSmsClient extends AbstractSmsClient {
+ JsonUtils.toJsonString(request.getParameterMap())); + JsonUtils.toJsonString(request.getParameterMap()));
} }
@Override
protected SmsCommonResult<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
return null;
}
/** /**
* *
*
* https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档
*
* @author
*/ */
private static class Helper { @Data
public static class SmsReceiveStatus {
//短信唯一标识 /**
private final static String API_ID = "sid"; *
*
*
*/
@JsonProperty("error_detail")
private String errorDetail;
/**
*
*/
private Long sid;
/**
* id
*
* SysSmsLogDO
*/
private Long uid;
/**
*
*/
@JsonProperty("user_receive_time")
@JsonFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date userReceiveTime;
/**
* "DB:0103"
*
*
*/
@JsonProperty("error_msg")
private String errorMsg;
/**
*
*/
private String mobile;
/**
*
*
* SUCCESS / FAIL使 Boolean
*/
@JsonProperty("report_status")
private String reportStatus;
//回调地址·
private final static String CALLBACK = "callback";
//手机号
private final static String MOBILE = "mobile";
//错误信息
private final static String ERROR_MSG = "error_msg";
//用户接收时间 字符串 标准格式
private final static String USER_RECEIVE_TIME = "user_receive_time";
//发送状态
private final static String REPORT_STATUS = "report_status";
private static int getSendStatus(Map<String, String> map) {
String reportStatus = map.get(REPORT_STATUS);
return SmsConstants.SUCCESS.equals(reportStatus)
? SysSmsSendStatusEnum.SUCCESS.getStatus()
: SysSmsSendStatusEnum.FAILURE.getStatus();
} }
public static SmsResultDetail getSmsResultDetailByParam(Map<String, String> map) {
SmsResultDetail detail = new SmsResultDetail();
detail.setPhone(map.get(MOBILE));
detail.setMessage(map.get(ERROR_MSG));
detail.setSendTime(DateUtil.parseTime(map.get(USER_RECEIVE_TIME)));
detail.setSendStatus(getSendStatus(map));
detail.setApiId(API_ID);
detail.setCallbackResponseBody(SmsConstants.SUCCESS);
return detail;
}
}
} }

View File

@ -16,8 +16,9 @@ public enum SmsChannelEnum {
YUN_PIAN("YUN_PIAN", "云片"), YUN_PIAN("YUN_PIAN", "云片"),
ALIYUN("ALIYUN", "阿里云"), ALIYUN("ALIYUN", "阿里云"),
TENCENT("TENCENT", "腾讯云"), // TENCENT("TENCENT", "腾讯云"),
HUA_WEI("HUA_WEI", "华为云"),; // HUA_WEI("HUA_WEI", "华为云"),
;
/** /**
* *

View File

@ -1,16 +0,0 @@
package cn.iocoder.dashboard.framework.sms.core.enums;
/**
*
*
* @author zzf
* @date 2021/3/5 10:42
*/
public interface SmsConstants {
String COMMA = ",";
String SUCCESS = "SUCCESS";
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.dashboard.modules.system.controller.sms;
import cn.hutool.core.util.URLUtil;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Api(tags = "短信回调")
@RestController
@RequestMapping("/system/sms/callback")
public class SmsCallbackController {
@Resource
private SysSmsService smsService;
@PostMapping("/sms/yunpian")
@ApiOperation(value = "云片短信的回调", notes = "参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档")
@ApiImplicitParam(name = "sms_status", value = "发送状态", required = true, example = "[{具体内容}]", dataTypeClass = Long.class)
public CommonResult<Boolean> receiveYunpianSmsStatus(@RequestParam("sms_status") String smsStatus) throws Throwable {
String text = URLUtil.decode(smsStatus); // decode 解码参数,因为它被 encode
smsService.receiveSmsStatus(SmsChannelEnum.YUN_PIAN.getCode(), text);
return CommonResult.success(true);
}
}

View File

@ -1,48 +0,0 @@
package cn.iocoder.dashboard.modules.system.controller.sms;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
/**
*
*
* @author zzf
* @date 2021/3/5 8:59
*/
@Api(tags = "短信回调api")
@RestController
@RequestMapping("/sms/callback")
public class SmsDefaultCallbackController {
@Resource
private SysSmsService smsService;
@ApiOperation(value = "短信发送回调接口")
@PostMapping("/sms-send")
public Object sendSmsCallback(ServletRequest request) {
return smsService.smsSendCallbackHandle(request);
}
/*
@Resource
private SmsSendStreamProducer smsSendStreamProducer;
@ApiOperation("redis stream测试")
@GetMapping("/test/redis/stream")
public void test() {
SmsBody smsBody = new SmsBody();
smsBody.setSmsLogId(1L);
smsBody.setTemplateCode("sdf");
smsBody.setTemplateContent("sdf");
smsSendStreamProducer.sendSmsSendMessage(smsBody, "18216466755");
}*/
}

View File

@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.sms;
import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
import javax.servlet.ServletRequest;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -24,11 +23,12 @@ public interface SysSmsService {
void doSendSms(SysSmsSendMessage message); void doSendSms(SysSmsSendMessage message);
/** /**
* *
* *
* @param request * @param channelCode
* @return * @param text
* @throws Throwable
*/ */
Object smsSendCallbackHandle(ServletRequest request); void receiveSmsStatus(String channelCode, String text) throws Throwable;
} }

View File

@ -7,6 +7,7 @@ import cn.iocoder.dashboard.common.enums.UserTypeEnum;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
@ -21,7 +22,6 @@ import org.springframework.stereotype.Service;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -139,7 +139,7 @@ public class SysSmsServiceImpl implements SysSmsService {
SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId()); SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId());
Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId())); Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId()));
// 发送短信 // 发送短信
SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.send(message.getLogId(), message.getMobile(), SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.sendSms(message.getLogId(), message.getMobile(),
message.getApiTemplateId(), message.getTemplateParams()); message.getApiTemplateId(), message.getTemplateParams());
smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(), smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(),
sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(), sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(),
@ -147,11 +147,12 @@ public class SysSmsServiceImpl implements SysSmsService {
} }
@Override @Override
public Object smsSendCallbackHandle(ServletRequest request) { public void receiveSmsStatus(String channelCode, String text) throws Throwable {
// SmsResultDetail smsResultDetail = smsClientFactory.getSmsResultDetailFromCallbackQuery(request); // 获得渠道对应的 SmsClient 客户端
// logService.updateSendLogByResultDetail(smsResultDetail); SmsClient smsClient = smsClientFactory.getSmsClient(channelCode);
// return smsResultDetail.getCallbackResponseBody(); Assert.notNull(smsClient, String.format("短信客户端(%s) 不存在", channelCode));
return null; // 解析内容
SmsCommonResult<SmsReceiveRespDTO> receiveResult = smsClient.parseSmsReceiveStatus(text);
} }
} }

View File

@ -2,12 +2,14 @@ package cn.iocoder.dashboard.util.json;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException; import java.io.IOException;
import java.util.Set; import java.util.ArrayList;
import java.util.List;
/** /**
* JSON * JSON
@ -59,7 +61,7 @@ public class JsonUtils {
} }
} }
public static Object parseObject(String text, TypeReference<Set<Long>> typeReference) { public static <T> T parseObject(String text, TypeReference<T> typeReference) {
try { try {
return objectMapper.readValue(text, typeReference); return objectMapper.readValue(text, typeReference);
} catch (IOException e) { } catch (IOException e) {
@ -67,12 +69,21 @@ public class JsonUtils {
} }
} }
public static <T> T parseByType(String text, TypeReference<T> typeReference) { public static <T> List<T> parseArray(String text, Class<T> clazz) {
if (StrUtil.isEmpty(text)) {
return new ArrayList<>();
}
try { try {
return objectMapper.readValue(text, typeReference); return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public static void main(String[] args) {
String text = "[{\"sid\":9527,\"uid\":null,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"},{\"sid\":9528,\"uid\":null,\"user_receive_time\":\"2014-03-17 22:55:23\",\"error_msg\":\"\",\"mobile\":\"15212341234\",\"report_status\":\"SUCCESS\"}]";
List<YunpianSmsClient.SmsReceiveStatus> result = parseArray(text, YunpianSmsClient.SmsReceiveStatus.class);
System.out.println(result);
}
} }

View File

@ -32,7 +32,7 @@ public class AliyunSmsClientTest {
templateParams.add(new KeyValue<>("code", "1024")); templateParams.add(new KeyValue<>("code", "1024"));
// templateParams.put("operation", "嘿嘿"); // templateParams.put("operation", "嘿嘿");
// SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams);
SmsCommonResult<SmsSendRespDTO> result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams); SmsCommonResult<SmsSendRespDTO> result = smsClient.sendSms(1L, "15601691399", "SMS_207945135", templateParams);
System.out.println(result); System.out.println(result);
} }

View File

@ -31,7 +31,7 @@ public class YunpianSmsClientIntegrationTest {
templateParams.add(new KeyValue<>("code", "1024")); templateParams.add(new KeyValue<>("code", "1024"));
templateParams.add(new KeyValue<>("operation", "嘿嘿")); templateParams.add(new KeyValue<>("operation", "嘿嘿"));
// SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams);
SmsCommonResult<SmsSendRespDTO> result = smsClient.send(1L, "15601691399", "4383920", templateParams); SmsCommonResult<SmsSendRespDTO> result = smsClient.sendSms(1L, "15601691399", "4383920", templateParams);
System.out.println(result); System.out.println(result);
} }