Commit c91833a504242b511c623ab220c1aa105ac17e59
1 parent
0d0110ec
定义短信回调的结果
Showing
17 changed files
with
222 additions
and
184 deletions
src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java
| @@ -128,13 +128,13 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { | @@ -128,13 +128,13 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { | ||
| 128 | // 设置每个请求的权限 | 128 | // 设置每个请求的权限 |
| 129 | .authorizeRequests() | 129 | .authorizeRequests() |
| 130 | // 登陆的接口,可匿名访问 | 130 | // 登陆的接口,可匿名访问 |
| 131 | - .antMatchers(webProperties.getApiPrefix() + "/login").anonymous() | 131 | + .antMatchers(api("/login")).anonymous() |
| 132 | // 通用的接口,可匿名访问 | 132 | // 通用的接口,可匿名访问 |
| 133 | - .antMatchers( webProperties.getApiPrefix() + "/system/captcha/**").anonymous() | 133 | + .antMatchers(api("/system/captcha/**")).anonymous() |
| 134 | // 静态资源,可匿名访问 | 134 | // 静态资源,可匿名访问 |
| 135 | .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() | 135 | .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() |
| 136 | // 文件的获取接口,可匿名访问 | 136 | // 文件的获取接口,可匿名访问 |
| 137 | - .antMatchers(webProperties.getApiPrefix() + "/infra/file/get/**").anonymous() | 137 | + .antMatchers(api("/infra/file/get/**")).anonymous() |
| 138 | // Swagger 接口文档 | 138 | // Swagger 接口文档 |
| 139 | .antMatchers("/swagger-ui.html").anonymous() | 139 | .antMatchers("/swagger-ui.html").anonymous() |
| 140 | .antMatchers("/swagger-resources/**").anonymous() | 140 | .antMatchers("/swagger-resources/**").anonymous() |
| @@ -148,13 +148,19 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { | @@ -148,13 +148,19 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { | ||
| 148 | .antMatchers("/actuator/**").anonymous() | 148 | .antMatchers("/actuator/**").anonymous() |
| 149 | // Druid 监控 | 149 | // Druid 监控 |
| 150 | .antMatchers("/druid/**").anonymous() | 150 | .antMatchers("/druid/**").anonymous() |
| 151 | + // 短信回调 API | ||
| 152 | + .antMatchers(api("/system/sms/callback/**")).anonymous() | ||
| 151 | // 除上面外的所有请求全部需要鉴权认证 | 153 | // 除上面外的所有请求全部需要鉴权认证 |
| 152 | .anyRequest().authenticated() | 154 | .anyRequest().authenticated() |
| 153 | .and() | 155 | .and() |
| 154 | .headers().frameOptions().disable(); | 156 | .headers().frameOptions().disable(); |
| 155 | - httpSecurity.logout().logoutUrl(webProperties.getApiPrefix() + "/logout").logoutSuccessHandler(logoutSuccessHandler); | 157 | + httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); |
| 156 | // 添加 JWT Filter | 158 | // 添加 JWT Filter |
| 157 | httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); | 159 | httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); |
| 158 | } | 160 | } |
| 159 | 161 | ||
| 162 | + private String api(String url) { | ||
| 163 | + return webProperties.getApiPrefix() + url; | ||
| 164 | + } | ||
| 165 | + | ||
| 160 | } | 166 | } |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java
| 1 | package cn.iocoder.dashboard.framework.sms.core.client; | 1 | package cn.iocoder.dashboard.framework.sms.core.client; |
| 2 | 2 | ||
| 3 | import cn.iocoder.dashboard.common.core.KeyValue; | 3 | import cn.iocoder.dashboard.common.core.KeyValue; |
| 4 | -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; | 4 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 5 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; | 5 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 6 | 6 | ||
| 7 | -import javax.servlet.ServletRequest; | ||
| 8 | import java.util.List; | 7 | import java.util.List; |
| 9 | 8 | ||
| 10 | /** | 9 | /** |
| @@ -31,15 +30,15 @@ public interface SmsClient { | @@ -31,15 +30,15 @@ public interface SmsClient { | ||
| 31 | * @param templateParams 短信模板参数 | 30 | * @param templateParams 短信模板参数 |
| 32 | * @return 短信发送结果 | 31 | * @return 短信发送结果 |
| 33 | */ | 32 | */ |
| 34 | - SmsCommonResult<SmsSendRespDTO> send(Long logId, String mobile, String apiTemplateId, List<KeyValue<String, Object>> templateParams); | 33 | + SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile, String apiTemplateId, List<KeyValue<String, Object>> templateParams); |
| 35 | 34 | ||
| 36 | - // TODO FROM 芋艿 to ZZF:是不是可以改成意图更明确的解析返回结果,例如说 parseXXXX | ||
| 37 | /** | 35 | /** |
| 38 | - * 短信发送回调请求处理 | 36 | + * 解析接收短信的接收结果 |
| 39 | * | 37 | * |
| 40 | - * @param request 请求 | ||
| 41 | - * @return 短信发送结果 | 38 | + * @param text 结果 |
| 39 | + * @return 结果内容 | ||
| 40 | + * @throws Throwable 当解析 text 发生异常时,则会抛出异常 | ||
| 42 | */ | 41 | */ |
| 43 | - SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception; | 42 | + SmsCommonResult<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable; |
| 44 | 43 | ||
| 45 | } | 44 | } |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java
| @@ -19,6 +19,14 @@ public interface SmsClientFactory { | @@ -19,6 +19,14 @@ public interface SmsClientFactory { | ||
| 19 | SmsClient getSmsClient(Long channelId); | 19 | SmsClient getSmsClient(Long channelId); |
| 20 | 20 | ||
| 21 | /** | 21 | /** |
| 22 | + * 获得短信 Client | ||
| 23 | + * | ||
| 24 | + * @param channelCode 渠道编码 | ||
| 25 | + * @return 短信 Client | ||
| 26 | + */ | ||
| 27 | + SmsClient getSmsClient(String channelCode); | ||
| 28 | + | ||
| 29 | + /** | ||
| 22 | * 创建短信 Client | 30 | * 创建短信 Client |
| 23 | * | 31 | * |
| 24 | * @param properties 配置对象 | 32 | * @param properties 配置对象 |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsResultDetail.java renamed to src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java
| @@ -7,10 +7,12 @@ import java.io.Serializable; | @@ -7,10 +7,12 @@ import java.io.Serializable; | ||
| 7 | import java.util.Date; | 7 | import java.util.Date; |
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| 10 | - * 消息内容实体类 | 10 | + * 消息接收 Response DTO |
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 11 | */ | 13 | */ |
| 12 | @Data | 14 | @Data |
| 13 | -public class SmsResultDetail implements Serializable { | 15 | +public class SmsReceiveRespDTO implements Serializable { |
| 14 | 16 | ||
| 15 | /** | 17 | /** |
| 16 | * 唯一标识 | 18 | * 唯一标识 |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java
| @@ -4,6 +4,7 @@ import cn.iocoder.dashboard.common.core.KeyValue; | @@ -4,6 +4,7 @@ import cn.iocoder.dashboard.common.core.KeyValue; | ||
| 4 | import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; | 4 | import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; |
| 5 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; | 5 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; |
| 6 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; | 6 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; |
| 7 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; | ||
| 7 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; | 8 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 8 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; | 9 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; |
| 9 | import lombok.extern.slf4j.Slf4j; | 10 | import lombok.extern.slf4j.Slf4j; |
| @@ -68,12 +69,12 @@ public abstract class AbstractSmsClient implements SmsClient { | @@ -68,12 +69,12 @@ public abstract class AbstractSmsClient implements SmsClient { | ||
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | @Override | 71 | @Override |
| 71 | - public final SmsCommonResult<SmsSendRespDTO> send(Long logId, String mobile, | ||
| 72 | - String apiTemplateId, List<KeyValue<String, Object>> templateParams) { | 72 | + public final SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile, |
| 73 | + String apiTemplateId, List<KeyValue<String, Object>> templateParams) { | ||
| 73 | // 执行短信发送 | 74 | // 执行短信发送 |
| 74 | SmsCommonResult<SmsSendRespDTO> result; | 75 | SmsCommonResult<SmsSendRespDTO> result; |
| 75 | try { | 76 | try { |
| 76 | - result = doSend(logId, mobile, apiTemplateId, templateParams); | 77 | + result = doSendSms(logId, mobile, apiTemplateId, templateParams); |
| 77 | } catch (Throwable ex) { | 78 | } catch (Throwable ex) { |
| 78 | // 打印异常日志 | 79 | // 打印异常日志 |
| 79 | log.error("[send][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", | 80 | log.error("[send][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", |
| @@ -84,17 +85,20 @@ public abstract class AbstractSmsClient implements SmsClient { | @@ -84,17 +85,20 @@ public abstract class AbstractSmsClient implements SmsClient { | ||
| 84 | return result; | 85 | return result; |
| 85 | } | 86 | } |
| 86 | 87 | ||
| 87 | - /** | ||
| 88 | - * 发送消息 | ||
| 89 | - * | ||
| 90 | - * @param sendLogId 发送日志编号 | ||
| 91 | - * @param mobile 手机号 | ||
| 92 | - * @param apiTemplateId 短信 API 的模板编号 | ||
| 93 | - * @param templateParams 短信模板参数 | ||
| 94 | - * @return 短信发送结果 | ||
| 95 | - */ | ||
| 96 | - protected abstract SmsCommonResult<SmsSendRespDTO> doSend(Long sendLogId, String mobile, | ||
| 97 | - String apiTemplateId, List<KeyValue<String, Object>> templateParams) | 88 | + protected abstract SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile, |
| 89 | + String apiTemplateId, List<KeyValue<String, Object>> templateParams) | ||
| 98 | throws Throwable; | 90 | throws Throwable; |
| 99 | 91 | ||
| 92 | + @Override | ||
| 93 | + public SmsCommonResult<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable { | ||
| 94 | + try { | ||
| 95 | + return doParseSmsReceiveStatus(text); | ||
| 96 | + } catch (Throwable ex) { | ||
| 97 | + log.error("[parseSmsReceiveStatus][text({}) 解析发生异常]", text, ex); | ||
| 98 | + throw ex; | ||
| 99 | + } | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + protected abstract SmsCommonResult<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable; | ||
| 103 | + | ||
| 100 | } | 104 | } |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java
| @@ -10,8 +10,9 @@ import lombok.extern.slf4j.Slf4j; | @@ -10,8 +10,9 @@ import lombok.extern.slf4j.Slf4j; | ||
| 10 | import org.springframework.util.Assert; | 10 | import org.springframework.util.Assert; |
| 11 | import org.springframework.validation.annotation.Validated; | 11 | import org.springframework.validation.annotation.Validated; |
| 12 | 12 | ||
| 13 | -import java.util.Map; | 13 | +import java.util.Arrays; |
| 14 | import java.util.concurrent.ConcurrentHashMap; | 14 | import java.util.concurrent.ConcurrentHashMap; |
| 15 | +import java.util.concurrent.ConcurrentMap; | ||
| 15 | 16 | ||
| 16 | /** | 17 | /** |
| 17 | * 短信客户端工厂接口 | 18 | * 短信客户端工厂接口 |
| @@ -26,20 +27,45 @@ public class SmsClientFactoryImpl implements SmsClientFactory { | @@ -26,20 +27,45 @@ public class SmsClientFactoryImpl implements SmsClientFactory { | ||
| 26 | * 短信客户端 Map | 27 | * 短信客户端 Map |
| 27 | * key:渠道编号,使用 {@link SmsChannelProperties#getId()} | 28 | * key:渠道编号,使用 {@link SmsChannelProperties#getId()} |
| 28 | */ | 29 | */ |
| 29 | - private final Map<Long, AbstractSmsClient> clients = new ConcurrentHashMap<>(); | 30 | + private final ConcurrentMap<Long, AbstractSmsClient> channelIdClients = new ConcurrentHashMap<>(); |
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 短信客户端 Map | ||
| 34 | + * key:渠道编码,使用 {@link SmsChannelProperties#getCode()} ()} | ||
| 35 | + * | ||
| 36 | + * 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。 | ||
| 37 | + * 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients} | ||
| 38 | + */ | ||
| 39 | + private final ConcurrentMap<String, AbstractSmsClient> channelCodeClients = new ConcurrentHashMap<>(); | ||
| 40 | + | ||
| 41 | + public SmsClientFactoryImpl() { | ||
| 42 | + // 初始化 channelCodeClients 集合 | ||
| 43 | + Arrays.stream(SmsChannelEnum.values()).forEach(channel -> { | ||
| 44 | + // 创建一个空的 SmsChannelProperties 对象 | ||
| 45 | + SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode()); | ||
| 46 | + // 创建 Sms 客户端 | ||
| 47 | + AbstractSmsClient smsClient = createSmsClient(properties); | ||
| 48 | + channelCodeClients.put(channel.getCode(), smsClient); | ||
| 49 | + }); | ||
| 50 | + } | ||
| 30 | 51 | ||
| 31 | @Override | 52 | @Override |
| 32 | public SmsClient getSmsClient(Long channelId) { | 53 | public SmsClient getSmsClient(Long channelId) { |
| 33 | - return clients.get(channelId); | 54 | + return channelIdClients.get(channelId); |
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Override | ||
| 58 | + public SmsClient getSmsClient(String channelCode) { | ||
| 59 | + return channelCodeClients.get(channelCode); | ||
| 34 | } | 60 | } |
| 35 | 61 | ||
| 36 | @Override | 62 | @Override |
| 37 | public void createOrUpdateSmsClient(SmsChannelProperties properties) { | 63 | public void createOrUpdateSmsClient(SmsChannelProperties properties) { |
| 38 | - AbstractSmsClient client = clients.get(properties.getId()); | 64 | + AbstractSmsClient client = channelIdClients.get(properties.getId()); |
| 39 | if (client == null) { | 65 | if (client == null) { |
| 40 | client = this.createSmsClient(properties); | 66 | client = this.createSmsClient(properties); |
| 41 | client.init(); | 67 | client.init(); |
| 42 | - clients.put(client.getId(), client); | 68 | + channelIdClients.put(client.getId(), client); |
| 43 | } else { | 69 | } else { |
| 44 | client.refresh(properties); | 70 | client.refresh(properties); |
| 45 | } | 71 | } |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java
| @@ -5,7 +5,7 @@ import cn.hutool.core.date.DateUtil; | @@ -5,7 +5,7 @@ import cn.hutool.core.date.DateUtil; | ||
| 5 | import cn.hutool.core.util.StrUtil; | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | import cn.iocoder.dashboard.common.core.KeyValue; | 6 | import cn.iocoder.dashboard.common.core.KeyValue; |
| 7 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; | 7 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; |
| 8 | -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; | 8 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 9 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; | 9 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 10 | import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; | 10 | import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; |
| 11 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; | 11 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; |
| @@ -61,8 +61,8 @@ public class AliyunSmsClient extends AbstractSmsClient { | @@ -61,8 +61,8 @@ public class AliyunSmsClient extends AbstractSmsClient { | ||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | @Override | 63 | @Override |
| 64 | - protected SmsCommonResult<SmsSendRespDTO> doSend(Long sendLogId, String mobile, | ||
| 65 | - String apiTemplateId, List<KeyValue<String, Object>> templateParams) { | 64 | + protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile, |
| 65 | + String apiTemplateId, List<KeyValue<String, Object>> templateParams) { | ||
| 66 | // 构建参数 | 66 | // 构建参数 |
| 67 | SendSmsRequest request = new SendSmsRequest(); | 67 | SendSmsRequest request = new SendSmsRequest(); |
| 68 | request.setSysMethod(MethodType.POST); | 68 | request.setSysMethod(MethodType.POST); |
| @@ -110,11 +110,10 @@ public class AliyunSmsClient extends AbstractSmsClient { | @@ -110,11 +110,10 @@ public class AliyunSmsClient extends AbstractSmsClient { | ||
| 110 | * @return | 110 | * @return |
| 111 | * @throws Exception | 111 | * @throws Exception |
| 112 | */ | 112 | */ |
| 113 | - @Override | ||
| 114 | - public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception { | 113 | + public SmsReceiveRespDTO smsSendCallbackHandle(ServletRequest request) throws Exception { |
| 115 | BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); | 114 | BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); |
| 116 | String paramStr = reader.readLine(); | 115 | String paramStr = reader.readLine(); |
| 117 | - List<Map<String, Object>> params = JsonUtils.parseByType(paramStr, new TypeReference<List<Map<String, Object>>>() { | 116 | + List<Map<String, Object>> params = JsonUtils.parseObject(paramStr, new TypeReference<List<Map<String, Object>>>() { |
| 118 | }); | 117 | }); |
| 119 | if (CollectionUtil.isNotEmpty(params)) { | 118 | if (CollectionUtil.isNotEmpty(params)) { |
| 120 | Map<String, Object> sendResultParamMap = params.get(0); | 119 | Map<String, Object> sendResultParamMap = params.get(0); |
| @@ -123,6 +122,11 @@ public class AliyunSmsClient extends AbstractSmsClient { | @@ -123,6 +122,11 @@ public class AliyunSmsClient extends AbstractSmsClient { | ||
| 123 | return null; | 122 | return null; |
| 124 | } | 123 | } |
| 125 | 124 | ||
| 125 | + @Override | ||
| 126 | + protected SmsCommonResult<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable { | ||
| 127 | + return null; | ||
| 128 | + } | ||
| 129 | + | ||
| 126 | /** | 130 | /** |
| 127 | * 短信发送回调辅助类 | 131 | * 短信发送回调辅助类 |
| 128 | */ | 132 | */ |
| @@ -168,8 +172,8 @@ public class AliyunSmsClient extends AbstractSmsClient { | @@ -168,8 +172,8 @@ public class AliyunSmsClient extends AbstractSmsClient { | ||
| 168 | return sendResultParamMap.get(CallbackField.OUT_ID).toString(); | 172 | return sendResultParamMap.get(CallbackField.OUT_ID).toString(); |
| 169 | } | 173 | } |
| 170 | 174 | ||
| 171 | - public SmsResultDetail toResultDetail() { | ||
| 172 | - SmsResultDetail resultDetail = new SmsResultDetail(); | 175 | + public SmsReceiveRespDTO toResultDetail() { |
| 176 | + SmsReceiveRespDTO resultDetail = new SmsReceiveRespDTO(); | ||
| 173 | resultDetail.setSendStatus(getSendStatus()); | 177 | resultDetail.setSendStatus(getSendStatus()); |
| 174 | resultDetail.setApiId(getBizId()); | 178 | resultDetail.setApiId(getBizId()); |
| 175 | resultDetail.setSendTime(getSendTime()); | 179 | resultDetail.setSendTime(getSendTime()); |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java
| @@ -2,33 +2,31 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; | @@ -2,33 +2,31 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.collection.CollectionUtil; | 4 | import cn.hutool.core.collection.CollectionUtil; |
| 5 | -import cn.hutool.core.date.DateUtil; | ||
| 6 | import cn.hutool.core.util.CharsetUtil; | 5 | import cn.hutool.core.util.CharsetUtil; |
| 7 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 8 | import cn.hutool.core.util.URLUtil; | 7 | import cn.hutool.core.util.URLUtil; |
| 9 | import cn.iocoder.dashboard.common.core.KeyValue; | 8 | import cn.iocoder.dashboard.common.core.KeyValue; |
| 10 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; | 9 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; |
| 11 | -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; | 10 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 12 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; | 11 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 13 | import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; | 12 | import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; |
| 14 | -import cn.iocoder.dashboard.framework.sms.core.enums.SmsConstants; | ||
| 15 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; | 13 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; |
| 16 | -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; | 14 | +import cn.iocoder.dashboard.util.date.DateUtils; |
| 17 | import cn.iocoder.dashboard.util.json.JsonUtils; | 15 | import cn.iocoder.dashboard.util.json.JsonUtils; |
| 16 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
| 17 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
| 18 | import com.fasterxml.jackson.core.type.TypeReference; | 18 | import com.fasterxml.jackson.core.type.TypeReference; |
| 19 | import com.yunpian.sdk.YunpianClient; | 19 | import com.yunpian.sdk.YunpianClient; |
| 20 | import com.yunpian.sdk.constant.YunpianConstant; | 20 | import com.yunpian.sdk.constant.YunpianConstant; |
| 21 | import com.yunpian.sdk.model.Result; | 21 | import com.yunpian.sdk.model.Result; |
| 22 | import com.yunpian.sdk.model.SmsSingleSend; | 22 | import com.yunpian.sdk.model.SmsSingleSend; |
| 23 | +import lombok.Data; | ||
| 23 | import lombok.extern.slf4j.Slf4j; | 24 | import lombok.extern.slf4j.Slf4j; |
| 24 | 25 | ||
| 25 | import javax.servlet.ServletRequest; | 26 | import javax.servlet.ServletRequest; |
| 26 | import java.io.UnsupportedEncodingException; | 27 | import java.io.UnsupportedEncodingException; |
| 27 | import java.net.URLEncoder; | 28 | import java.net.URLEncoder; |
| 28 | -import java.util.HashMap; | ||
| 29 | -import java.util.List; | ||
| 30 | -import java.util.Map; | ||
| 31 | -import java.util.StringJoiner; | 29 | +import java.util.*; |
| 32 | 30 | ||
| 33 | /** | 31 | /** |
| 34 | * 云片短信客户端的实现类 | 32 | * 云片短信客户端的实现类 |
| @@ -65,8 +63,8 @@ public class YunpianSmsClient extends AbstractSmsClient { | @@ -65,8 +63,8 @@ public class YunpianSmsClient extends AbstractSmsClient { | ||
| 65 | } | 63 | } |
| 66 | 64 | ||
| 67 | @Override | 65 | @Override |
| 68 | - protected SmsCommonResult<SmsSendRespDTO> doSend(Long sendLogId, String mobile, | ||
| 69 | - String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable { | 66 | + protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile, |
| 67 | + String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable { | ||
| 70 | // 构建参数 | 68 | // 构建参数 |
| 71 | Map<String, String> request = new HashMap<>(); | 69 | Map<String, String> request = new HashMap<>(); |
| 72 | request.put(YunpianConstant.APIKEY, properties.getApiKey()); | 70 | request.put(YunpianConstant.APIKEY, properties.getApiKey()); |
| @@ -74,7 +72,7 @@ public class YunpianSmsClient extends AbstractSmsClient { | @@ -74,7 +72,7 @@ public class YunpianSmsClient extends AbstractSmsClient { | ||
| 74 | request.put(YunpianConstant.TPL_ID, apiTemplateId); | 72 | request.put(YunpianConstant.TPL_ID, apiTemplateId); |
| 75 | request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams)); | 73 | request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams)); |
| 76 | request.put(YunpianConstant.UID, String.valueOf(sendLogId)); | 74 | request.put(YunpianConstant.UID, String.valueOf(sendLogId)); |
| 77 | - request.put(Helper.CALLBACK, properties.getCallbackUrl()); | 75 | + request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl()); |
| 78 | 76 | ||
| 79 | // 执行发送 | 77 | // 执行发送 |
| 80 | Result<SmsSingleSend> sendResult = client.sms().tpl_single_send(request); | 78 | Result<SmsSingleSend> sendResult = client.sms().tpl_single_send(request); |
| @@ -108,15 +106,6 @@ public class YunpianSmsClient extends AbstractSmsClient { | @@ -108,15 +106,6 @@ public class YunpianSmsClient extends AbstractSmsClient { | ||
| 108 | } | 106 | } |
| 109 | 107 | ||
| 110 | /** | 108 | /** |
| 111 | - * 云片的比较复杂,又是加密又是套娃的 | ||
| 112 | - */ | ||
| 113 | - @Override | ||
| 114 | - public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws UnsupportedEncodingException { | ||
| 115 | - Map<String, String> map = getRequestParams(request); | ||
| 116 | - return Helper.getSmsResultDetailByParam(map); | ||
| 117 | - } | ||
| 118 | - | ||
| 119 | - /** | ||
| 120 | * 从 request 中获取请求中传入的短信发送结果信息 | 109 | * 从 request 中获取请求中传入的短信发送结果信息 |
| 121 | * | 110 | * |
| 122 | * @param request 回调请求 | 111 | * @param request 回调请求 |
| @@ -127,7 +116,7 @@ public class YunpianSmsClient extends AbstractSmsClient { | @@ -127,7 +116,7 @@ public class YunpianSmsClient extends AbstractSmsClient { | ||
| 127 | Map<String, String[]> parameterMap = request.getParameterMap(); | 116 | Map<String, String[]> parameterMap = request.getParameterMap(); |
| 128 | String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS); | 117 | String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS); |
| 129 | String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8); | 118 | String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8); |
| 130 | - List<Map<String, String>> paramList = JsonUtils.parseByType(encode, callbackType); | 119 | + List<Map<String, String>> paramList = JsonUtils.parseObject(encode, callbackType); |
| 131 | if (CollectionUtil.isNotEmpty(paramList)) { | 120 | if (CollectionUtil.isNotEmpty(paramList)) { |
| 132 | return paramList.get(0); | 121 | return paramList.get(0); |
| 133 | } | 122 | } |
| @@ -135,46 +124,63 @@ public class YunpianSmsClient extends AbstractSmsClient { | @@ -135,46 +124,63 @@ public class YunpianSmsClient extends AbstractSmsClient { | ||
| 135 | + JsonUtils.toJsonString(request.getParameterMap())); | 124 | + JsonUtils.toJsonString(request.getParameterMap())); |
| 136 | } | 125 | } |
| 137 | 126 | ||
| 127 | + @Override | ||
| 128 | + protected SmsCommonResult<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable { | ||
| 129 | + return null; | ||
| 130 | + } | ||
| 131 | + | ||
| 138 | /** | 132 | /** |
| 139 | - * 云片的回调函数的一些辅助方法 | 133 | + * 短信接收状态 |
| 134 | + * | ||
| 135 | + * 参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档 | ||
| 136 | + * | ||
| 137 | + * @author 芋道源码 | ||
| 140 | */ | 138 | */ |
| 141 | - private static class Helper { | ||
| 142 | - | ||
| 143 | - //短信唯一标识 | ||
| 144 | - private final static String API_ID = "sid"; | 139 | + @Data |
| 140 | + public static class SmsReceiveStatus { | ||
| 141 | + | ||
| 142 | + /** | ||
| 143 | + * 运营商反馈代码的中文解释 | ||
| 144 | + * | ||
| 145 | + * 默认不推送此字段,如需推送,请联系客服 | ||
| 146 | + */ | ||
| 147 | + @JsonProperty("error_detail") | ||
| 148 | + private String errorDetail; | ||
| 149 | + /** | ||
| 150 | + * 短信编号 | ||
| 151 | + */ | ||
| 152 | + private Long sid; | ||
| 153 | + /** | ||
| 154 | + * 用户自定义 id | ||
| 155 | + * | ||
| 156 | + * 这里我们传递的是 SysSmsLogDO 的日志编号 | ||
| 157 | + */ | ||
| 158 | + private Long uid; | ||
| 159 | + /** | ||
| 160 | + * 用户接收时间 | ||
| 161 | + */ | ||
| 162 | + @JsonProperty("user_receive_time") | ||
| 163 | + @JsonFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||
| 164 | + private Date userReceiveTime; | ||
| 165 | + /** | ||
| 166 | + * 运营商返回的代码,如:"DB:0103" | ||
| 167 | + * | ||
| 168 | + * 由于不同运营商信息不同,此字段仅供参考; | ||
| 169 | + */ | ||
| 170 | + @JsonProperty("error_msg") | ||
| 171 | + private String errorMsg; | ||
| 172 | + /** | ||
| 173 | + * 接收手机号 | ||
| 174 | + */ | ||
| 175 | + private String mobile; | ||
| 176 | + /** | ||
| 177 | + * 接收状态 | ||
| 178 | + * | ||
| 179 | + * 目前仅有 SUCCESS / FAIL,所以使用 Boolean 接收 | ||
| 180 | + */ | ||
| 181 | + @JsonProperty("report_status") | ||
| 182 | + private String reportStatus; | ||
| 145 | 183 | ||
| 146 | - //回调地址· | ||
| 147 | - private final static String CALLBACK = "callback"; | ||
| 148 | - | ||
| 149 | - //手机号 | ||
| 150 | - private final static String MOBILE = "mobile"; | ||
| 151 | - | ||
| 152 | - //错误信息 | ||
| 153 | - private final static String ERROR_MSG = "error_msg"; | ||
| 154 | - | ||
| 155 | - //用户接收时间 字符串 标准格式 | ||
| 156 | - private final static String USER_RECEIVE_TIME = "user_receive_time"; | ||
| 157 | - | ||
| 158 | - //发送状态 | ||
| 159 | - private final static String REPORT_STATUS = "report_status"; | ||
| 160 | - | ||
| 161 | - private static int getSendStatus(Map<String, String> map) { | ||
| 162 | - String reportStatus = map.get(REPORT_STATUS); | ||
| 163 | - return SmsConstants.SUCCESS.equals(reportStatus) | ||
| 164 | - ? SysSmsSendStatusEnum.SUCCESS.getStatus() | ||
| 165 | - : SysSmsSendStatusEnum.FAILURE.getStatus(); | ||
| 166 | - } | ||
| 167 | - | ||
| 168 | - public static SmsResultDetail getSmsResultDetailByParam(Map<String, String> map) { | ||
| 169 | - SmsResultDetail detail = new SmsResultDetail(); | ||
| 170 | - detail.setPhone(map.get(MOBILE)); | ||
| 171 | - detail.setMessage(map.get(ERROR_MSG)); | ||
| 172 | - detail.setSendTime(DateUtil.parseTime(map.get(USER_RECEIVE_TIME))); | ||
| 173 | - detail.setSendStatus(getSendStatus(map)); | ||
| 174 | - detail.setApiId(API_ID); | ||
| 175 | - | ||
| 176 | - detail.setCallbackResponseBody(SmsConstants.SUCCESS); | ||
| 177 | - return detail; | ||
| 178 | - } | ||
| 179 | } | 184 | } |
| 185 | + | ||
| 180 | } | 186 | } |
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java
| @@ -16,8 +16,9 @@ public enum SmsChannelEnum { | @@ -16,8 +16,9 @@ public enum SmsChannelEnum { | ||
| 16 | 16 | ||
| 17 | YUN_PIAN("YUN_PIAN", "云片"), | 17 | YUN_PIAN("YUN_PIAN", "云片"), |
| 18 | ALIYUN("ALIYUN", "阿里云"), | 18 | ALIYUN("ALIYUN", "阿里云"), |
| 19 | - TENCENT("TENCENT", "腾讯云"), | ||
| 20 | - HUA_WEI("HUA_WEI", "华为云"),; | 19 | +// TENCENT("TENCENT", "腾讯云"), |
| 20 | +// HUA_WEI("HUA_WEI", "华为云"), | ||
| 21 | + ; | ||
| 21 | 22 | ||
| 22 | /** | 23 | /** |
| 23 | * 编码 | 24 | * 编码 |
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsConstants.java deleted
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.controller.sms; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.URLUtil; | ||
| 4 | +import cn.iocoder.dashboard.common.pojo.CommonResult; | ||
| 5 | +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; | ||
| 6 | +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; | ||
| 7 | +import io.swagger.annotations.Api; | ||
| 8 | +import io.swagger.annotations.ApiImplicitParam; | ||
| 9 | +import io.swagger.annotations.ApiOperation; | ||
| 10 | +import org.springframework.web.bind.annotation.PostMapping; | ||
| 11 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 12 | +import org.springframework.web.bind.annotation.RequestParam; | ||
| 13 | +import org.springframework.web.bind.annotation.RestController; | ||
| 14 | + | ||
| 15 | +import javax.annotation.Resource; | ||
| 16 | + | ||
| 17 | +@Api(tags = "短信回调") | ||
| 18 | +@RestController | ||
| 19 | +@RequestMapping("/system/sms/callback") | ||
| 20 | +public class SmsCallbackController { | ||
| 21 | + | ||
| 22 | + @Resource | ||
| 23 | + private SysSmsService smsService; | ||
| 24 | + | ||
| 25 | + @PostMapping("/sms/yunpian") | ||
| 26 | + @ApiOperation(value = "云片短信的回调", notes = "参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档") | ||
| 27 | + @ApiImplicitParam(name = "sms_status", value = "发送状态", required = true, example = "[{具体内容}]", dataTypeClass = Long.class) | ||
| 28 | + public CommonResult<Boolean> receiveYunpianSmsStatus(@RequestParam("sms_status") String smsStatus) throws Throwable { | ||
| 29 | + String text = URLUtil.decode(smsStatus); // decode 解码参数,因为它被 encode | ||
| 30 | + smsService.receiveSmsStatus(SmsChannelEnum.YUN_PIAN.getCode(), text); | ||
| 31 | + return CommonResult.success(true); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | +} |
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java deleted
| 1 | -package cn.iocoder.dashboard.modules.system.controller.sms; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; | ||
| 4 | -import io.swagger.annotations.Api; | ||
| 5 | -import io.swagger.annotations.ApiOperation; | ||
| 6 | -import org.springframework.web.bind.annotation.PostMapping; | ||
| 7 | -import org.springframework.web.bind.annotation.RequestMapping; | ||
| 8 | -import org.springframework.web.bind.annotation.RestController; | ||
| 9 | - | ||
| 10 | -import javax.annotation.Resource; | ||
| 11 | -import javax.servlet.ServletRequest; | ||
| 12 | - | ||
| 13 | -/** | ||
| 14 | - * 短信默认回调接口 | ||
| 15 | - * | ||
| 16 | - * @author zzf | ||
| 17 | - * @date 2021/3/5 8:59 | ||
| 18 | - */ | ||
| 19 | -@Api(tags = "短信回调api") | ||
| 20 | -@RestController | ||
| 21 | -@RequestMapping("/sms/callback") | ||
| 22 | -public class SmsDefaultCallbackController { | ||
| 23 | - | ||
| 24 | - @Resource | ||
| 25 | - private SysSmsService smsService; | ||
| 26 | - | ||
| 27 | - | ||
| 28 | - @ApiOperation(value = "短信发送回调接口") | ||
| 29 | - @PostMapping("/sms-send") | ||
| 30 | - public Object sendSmsCallback(ServletRequest request) { | ||
| 31 | - return smsService.smsSendCallbackHandle(request); | ||
| 32 | - } | ||
| 33 | - | ||
| 34 | -/* | ||
| 35 | - @Resource | ||
| 36 | - private SmsSendStreamProducer smsSendStreamProducer; | ||
| 37 | - | ||
| 38 | - @ApiOperation("redis stream测试") | ||
| 39 | - @GetMapping("/test/redis/stream") | ||
| 40 | - public void test() { | ||
| 41 | - SmsBody smsBody = new SmsBody(); | ||
| 42 | - smsBody.setSmsLogId(1L); | ||
| 43 | - smsBody.setTemplateCode("sdf"); | ||
| 44 | - smsBody.setTemplateContent("sdf"); | ||
| 45 | - smsSendStreamProducer.sendSmsSendMessage(smsBody, "18216466755"); | ||
| 46 | - }*/ | ||
| 47 | - | ||
| 48 | -} |
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java
| @@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.sms; | @@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.sms; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; | 3 | import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; |
| 4 | 4 | ||
| 5 | -import javax.servlet.ServletRequest; | ||
| 6 | import java.util.List; | 5 | import java.util.List; |
| 7 | import java.util.Map; | 6 | import java.util.Map; |
| 8 | 7 | ||
| @@ -24,11 +23,12 @@ public interface SysSmsService { | @@ -24,11 +23,12 @@ public interface SysSmsService { | ||
| 24 | void doSendSms(SysSmsSendMessage message); | 23 | void doSendSms(SysSmsSendMessage message); |
| 25 | 24 | ||
| 26 | /** | 25 | /** |
| 27 | - * 处理短信发送回调函数 | 26 | + * 接收短信的接收结果 |
| 28 | * | 27 | * |
| 29 | - * @param request 请求 | ||
| 30 | - * @return 响应数据 | 28 | + * @param channelCode 渠道编码 |
| 29 | + * @param text 结果内容 | ||
| 30 | + * @throws Throwable 处理失败时,抛出异常 | ||
| 31 | */ | 31 | */ |
| 32 | - Object smsSendCallbackHandle(ServletRequest request); | 32 | + void receiveSmsStatus(String channelCode, String text) throws Throwable; |
| 33 | 33 | ||
| 34 | } | 34 | } |
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java
| @@ -7,6 +7,7 @@ import cn.iocoder.dashboard.common.enums.UserTypeEnum; | @@ -7,6 +7,7 @@ import cn.iocoder.dashboard.common.enums.UserTypeEnum; | ||
| 7 | import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; | 7 | import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; |
| 8 | import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; | 8 | import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; |
| 9 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; | 9 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; |
| 10 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; | ||
| 10 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; | 11 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 11 | import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; | 12 | import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; |
| 12 | import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; | 13 | import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; |
| @@ -21,7 +22,6 @@ import org.springframework.stereotype.Service; | @@ -21,7 +22,6 @@ import org.springframework.stereotype.Service; | ||
| 21 | import org.springframework.util.Assert; | 22 | import org.springframework.util.Assert; |
| 22 | 23 | ||
| 23 | import javax.annotation.Resource; | 24 | import javax.annotation.Resource; |
| 24 | -import javax.servlet.ServletRequest; | ||
| 25 | import java.util.List; | 25 | import java.util.List; |
| 26 | import java.util.Map; | 26 | import java.util.Map; |
| 27 | import java.util.Objects; | 27 | import java.util.Objects; |
| @@ -139,7 +139,7 @@ public class SysSmsServiceImpl implements SysSmsService { | @@ -139,7 +139,7 @@ public class SysSmsServiceImpl implements SysSmsService { | ||
| 139 | SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId()); | 139 | SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId()); |
| 140 | Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId())); | 140 | Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId())); |
| 141 | // 发送短信 | 141 | // 发送短信 |
| 142 | - SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.send(message.getLogId(), message.getMobile(), | 142 | + SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.sendSms(message.getLogId(), message.getMobile(), |
| 143 | message.getApiTemplateId(), message.getTemplateParams()); | 143 | message.getApiTemplateId(), message.getTemplateParams()); |
| 144 | smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(), | 144 | smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(), |
| 145 | sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(), | 145 | sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(), |
| @@ -147,11 +147,12 @@ public class SysSmsServiceImpl implements SysSmsService { | @@ -147,11 +147,12 @@ public class SysSmsServiceImpl implements SysSmsService { | ||
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | @Override | 149 | @Override |
| 150 | - public Object smsSendCallbackHandle(ServletRequest request) { | ||
| 151 | -// SmsResultDetail smsResultDetail = smsClientFactory.getSmsResultDetailFromCallbackQuery(request); | ||
| 152 | -// logService.updateSendLogByResultDetail(smsResultDetail); | ||
| 153 | -// return smsResultDetail.getCallbackResponseBody(); | ||
| 154 | - return null; | 150 | + public void receiveSmsStatus(String channelCode, String text) throws Throwable { |
| 151 | + // 获得渠道对应的 SmsClient 客户端 | ||
| 152 | + SmsClient smsClient = smsClientFactory.getSmsClient(channelCode); | ||
| 153 | + Assert.notNull(smsClient, String.format("短信客户端(%s) 不存在", channelCode)); | ||
| 154 | + // 解析内容 | ||
| 155 | + SmsCommonResult<SmsReceiveRespDTO> receiveResult = smsClient.parseSmsReceiveStatus(text); | ||
| 155 | } | 156 | } |
| 156 | 157 | ||
| 157 | } | 158 | } |
src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java
| @@ -2,12 +2,14 @@ package cn.iocoder.dashboard.util.json; | @@ -2,12 +2,14 @@ package cn.iocoder.dashboard.util.json; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.ArrayUtil; | 3 | import cn.hutool.core.util.ArrayUtil; |
| 4 | import cn.hutool.core.util.StrUtil; | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | +import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient; | ||
| 5 | import com.fasterxml.jackson.core.JsonProcessingException; | 6 | import com.fasterxml.jackson.core.JsonProcessingException; |
| 6 | import com.fasterxml.jackson.core.type.TypeReference; | 7 | import com.fasterxml.jackson.core.type.TypeReference; |
| 7 | import com.fasterxml.jackson.databind.ObjectMapper; | 8 | import com.fasterxml.jackson.databind.ObjectMapper; |
| 8 | 9 | ||
| 9 | import java.io.IOException; | 10 | import java.io.IOException; |
| 10 | -import java.util.Set; | 11 | +import java.util.ArrayList; |
| 12 | +import java.util.List; | ||
| 11 | 13 | ||
| 12 | /** | 14 | /** |
| 13 | * JSON 工具类 | 15 | * JSON 工具类 |
| @@ -59,7 +61,7 @@ public class JsonUtils { | @@ -59,7 +61,7 @@ public class JsonUtils { | ||
| 59 | } | 61 | } |
| 60 | } | 62 | } |
| 61 | 63 | ||
| 62 | - public static Object parseObject(String text, TypeReference<Set<Long>> typeReference) { | 64 | + public static <T> T parseObject(String text, TypeReference<T> typeReference) { |
| 63 | try { | 65 | try { |
| 64 | return objectMapper.readValue(text, typeReference); | 66 | return objectMapper.readValue(text, typeReference); |
| 65 | } catch (IOException e) { | 67 | } catch (IOException e) { |
| @@ -67,12 +69,21 @@ public class JsonUtils { | @@ -67,12 +69,21 @@ public class JsonUtils { | ||
| 67 | } | 69 | } |
| 68 | } | 70 | } |
| 69 | 71 | ||
| 70 | - public static <T> T parseByType(String text, TypeReference<T> typeReference) { | 72 | + public static <T> List<T> parseArray(String text, Class<T> clazz) { |
| 73 | + if (StrUtil.isEmpty(text)) { | ||
| 74 | + return new ArrayList<>(); | ||
| 75 | + } | ||
| 71 | try { | 76 | try { |
| 72 | - return objectMapper.readValue(text, typeReference); | 77 | + return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz)); |
| 73 | } catch (IOException e) { | 78 | } catch (IOException e) { |
| 74 | throw new RuntimeException(e); | 79 | throw new RuntimeException(e); |
| 75 | } | 80 | } |
| 76 | } | 81 | } |
| 77 | 82 | ||
| 83 | + public static void main(String[] args) { | ||
| 84 | + 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\"}]"; | ||
| 85 | + List<YunpianSmsClient.SmsReceiveStatus> result = parseArray(text, YunpianSmsClient.SmsReceiveStatus.class); | ||
| 86 | + System.out.println(result); | ||
| 87 | + } | ||
| 88 | + | ||
| 78 | } | 89 | } |
src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java
| @@ -32,7 +32,7 @@ public class AliyunSmsClientTest { | @@ -32,7 +32,7 @@ public class AliyunSmsClientTest { | ||
| 32 | templateParams.add(new KeyValue<>("code", "1024")); | 32 | templateParams.add(new KeyValue<>("code", "1024")); |
| 33 | // templateParams.put("operation", "嘿嘿"); | 33 | // templateParams.put("operation", "嘿嘿"); |
| 34 | // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); | 34 | // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); |
| 35 | - SmsCommonResult<SmsSendRespDTO> result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams); | 35 | + SmsCommonResult<SmsSendRespDTO> result = smsClient.sendSms(1L, "15601691399", "SMS_207945135", templateParams); |
| 36 | System.out.println(result); | 36 | System.out.println(result); |
| 37 | } | 37 | } |
| 38 | 38 |
src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java
| @@ -31,7 +31,7 @@ public class YunpianSmsClientIntegrationTest { | @@ -31,7 +31,7 @@ public class YunpianSmsClientIntegrationTest { | ||
| 31 | templateParams.add(new KeyValue<>("code", "1024")); | 31 | templateParams.add(new KeyValue<>("code", "1024")); |
| 32 | templateParams.add(new KeyValue<>("operation", "嘿嘿")); | 32 | templateParams.add(new KeyValue<>("operation", "嘿嘿")); |
| 33 | // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); | 33 | // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); |
| 34 | - SmsCommonResult<SmsSendRespDTO> result = smsClient.send(1L, "15601691399", "4383920", templateParams); | 34 | + SmsCommonResult<SmsSendRespDTO> result = smsClient.sendSms(1L, "15601691399", "4383920", templateParams); |
| 35 | System.out.println(result); | 35 | System.out.println(result); |
| 36 | } | 36 | } |
| 37 | 37 |