diff --git a/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/OrderServiceImpl.java b/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/OrderServiceImpl.java index 8535612c1..87a23ba3d 100644 --- a/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/OrderServiceImpl.java +++ b/order/order-service-impl/src/main/java/cn/iocoder/mall/order/biz/service/OrderServiceImpl.java @@ -330,7 +330,7 @@ public class OrderServiceImpl implements OrderService { // if (commonResult.isError()) { // //手动开启事务回滚 // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); -// return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_GET_PAY_FAIL.getCode()); +// return ServiceExceptionUtil.error(OrderErrorCodeEnum.ORDER_GET_PAY_FAIL.getValue()); // } // TODO: 2019-03-17 Sin 需要发送 创建成果 MQ 消息,业务扩展和统计 diff --git a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/SmsPlatform.java b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/SmsPlatform.java deleted file mode 100644 index b9e927754..000000000 --- a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/SmsPlatform.java +++ /dev/null @@ -1,116 +0,0 @@ -package cn.iocoder.mall.admin.api; - -import lombok.Data; -import lombok.experimental.Accessors; - -import java.util.List; - -/** - * 短信平台 - * - * @author Sin - * @time 2019/5/16 6:33 PM - */ -public interface SmsPlatform { - - @Data - @Accessors(chain = true) - class Result { - /** - * 编号 - */ - private String id; - /** - * 审核状态 - */ - private Integer applyStatus; - /** - * 审核内容 - */ - private String applyMessage; - } - - /** - * 签名 - 创建 - * - * @param sign - */ - Result createSign(String sign); - - /** - * 签名 - 获取 - * - * @param sign - */ - Result getSign(String sign); - - /** - * 签名 - 更新 - * - * @param oldSign - * @param sign - */ - Result updateSign(String oldSign, String sign); - - /** - * 模板 - 创建 - * - * @param template 模板内容 - * @param tplType 1 为验证码类型,其他为 null - */ - Result createTemplate(String template, Integer tplType); - - /** - * 模板 - 获取 - * - * @param tplId - */ - Result getTemplate(String tplId); - - /** - * 模板 - 更新 - * - * @param tplId 选用的哪个签名 - * @param template 模板内容 - * @param tplType 1 为验证码类型,其他为 null - */ - Result updateTemplate(String tplId, String template, Integer tplType); - - /** - * 模板 - 删除 - * - * @param tplId - * @return - */ - Result deleteTemplate(String tplId); - - - @Data - @Accessors(chain = true) - class SendResult { - - private Boolean hasSuccess; - - private Integer code; - - private String message; - - private List success; - - private List fail; - } - - /** - * 短信发送 - 单个 - * - * @return - */ - SendResult singleSend(String mobile, String template); - - /** - * 短信发送 - 批量 - * - * @return - */ - SendResult batchSend(List mobileList, String template); -} diff --git a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/SmsService.java b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/SmsService.java index 78f52b9aa..73561b6a0 100644 --- a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/SmsService.java +++ b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/SmsService.java @@ -39,47 +39,56 @@ public interface SmsService { * * @param sign */ - void createSign(String sign); + void createSign(String sign, Integer platform); /** * 签名 - 获取 * - * @param sign + * @param id */ - SmsSignBO getSign(String sign); + SmsSignBO getSign(Integer id); /** * 签名 - 更新 * - * @param oldSign - * @param sign + * @param id + * @param newSign + * @param platform */ - void updateSign(String oldSign, String sign); + void updateSign(Integer id, String newSign, Integer platform); + + /** + * 签名 - 更新 + * + * @param id + */ + void deleteSign(Integer id); /** * 模板 - 创建 * * @param smsSignId 选用的哪个签名 * @param template 模板内容 - * @param tplType 1 为验证码类型,其他为 null + * @param platform 平台 */ - void createTemplate(Integer smsSignId, String template, Integer tplType); + void createTemplate(Integer smsSignId, String template, Integer platform, Integer smsType); /** * 模板 - 获取 * * @param id */ - SmsTemplateBO getTemplate(Integer id); + SmsTemplateBO getTemplate(Integer id, Integer platform); /** * 模板 - 更新 * * @param id 模板id + * @param smsSignId 短期签名 * @param template 模板内容 - * @param tplType 1 为验证码类型,其他为 null + * @param platform 短信平台 */ - void updateTemplate(Integer id, String template, Integer tplType); + void updateTemplate(Integer id, Integer smsSignId, String template, Integer platform, Integer smsType); /** * 模板 - 删除 diff --git a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/AdminErrorCodeEnum.java b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/AdminErrorCodeEnum.java index bde9139ee..df9949f48 100644 --- a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/AdminErrorCodeEnum.java +++ b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/AdminErrorCodeEnum.java @@ -56,6 +56,7 @@ public enum AdminErrorCodeEnum { SMS_SIGN_IS_EXISTENT(1002006002, "短信签名已存在"), SMS_TEMPLATE_NOT_EXISTENT(1002006020, "短信签名不存在"), SMS_TEMPLATE_IS_EXISTENT(1002006021, "短信签名不存在"), + SMS_NOT_SEND_CLIENT(1002006030, "短信没有发送的client"), ; private final int code; diff --git a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/DictKeyConstants.java b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/DictKeyConstants.java new file mode 100644 index 000000000..363206126 --- /dev/null +++ b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/DictKeyConstants.java @@ -0,0 +1,11 @@ +package cn.iocoder.mall.admin.api.constant; + +/** + * 字典 key + * + * @author Sin + * @time 2019/5/25 3:36 PM + */ +public class DictKeyConstants { + +} diff --git a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsApplyStatusEnum.java b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsApplyStatusEnum.java index eaf685687..598ca98b6 100644 --- a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsApplyStatusEnum.java +++ b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsApplyStatusEnum.java @@ -13,19 +13,19 @@ public enum SmsApplyStatusEnum { FAIL(3, "审核失败"), ; - private final int code; - private final String message; + private final Integer value; + private final String name; SmsApplyStatusEnum(int code, String message) { - this.code = code; - this.message = message; + this.value = code; + this.name = message; } - public int getCode() { - return code; + public int getValue() { + return value; } - public String getMessage() { - return message; + public String getName() { + return name; } } diff --git a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsPlatformEnum.java b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsPlatformEnum.java new file mode 100644 index 000000000..f7cf493c2 --- /dev/null +++ b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsPlatformEnum.java @@ -0,0 +1,30 @@ +package cn.iocoder.mall.admin.api.constant; + +/** + * 短信审核状态 + * + * @author Sin + * @time 2019/5/16 12:48 PM + */ +public enum SmsPlatformEnum { + + YunPian(1, "云片"), + AliYun(2, "阿里云"), + ; + + private final Integer value; + private final String name; + + SmsPlatformEnum(Integer code, String message) { + this.value = code; + this.name = message; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsTypeEnum.java b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsTypeEnum.java new file mode 100644 index 000000000..d29c6b104 --- /dev/null +++ b/system/system-service-api/src/main/java/cn/iocoder/mall/admin/api/constant/SmsTypeEnum.java @@ -0,0 +1,31 @@ +package cn.iocoder.mall.admin.api.constant; + +/** + * 短信审核状态 + * + * @author Sin + * @time 2019/5/16 12:48 PM + */ +public enum SmsTypeEnum { + + VERIFICATION_CODE(1, "验证码"), + NOTICE(1, "通知"), + MARKETING(2, "营销"), + ; + + private final Integer value; + private final String name; + + SmsTypeEnum(Integer code, String message) { + this.value = code; + this.name = message; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } +} diff --git a/system/system-service-impl/pom.xml b/system/system-service-impl/pom.xml index 344d93443..d33d2ad3f 100644 --- a/system/system-service-impl/pom.xml +++ b/system/system-service-impl/pom.xml @@ -31,7 +31,6 @@ org.springframework spring-jdbc - com.alibaba druid-spring-boot-starter @@ -72,12 +71,22 @@ yunpian-java-sdk 1.2.7 + + com.aliyun + aliyun-java-sdk-core + 4.1.0 + org.springframework.boot spring-boot-starter-test + + org.junit.jupiter + junit-jupiter-api + 5.4.0 + diff --git a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/client/SmsAliYunClient.java b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/client/SmsAliYunClient.java new file mode 100644 index 000000000..e9e6bc77e --- /dev/null +++ b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/client/SmsAliYunClient.java @@ -0,0 +1,83 @@ +package cn.iocoder.mall.admin.client; + +import com.aliyuncs.CommonRequest; +import com.aliyuncs.CommonResponse; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.exceptions.ServerException; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +/** + * 短信 AliYun client + * + * @author Sin + * @time 2019/5/25 12:28 PM + */ +@Component +public class SmsAliYunClient implements SmsClient { + + @Value("sms.aliYun.accessKeyId") + private String accessKeyId; + @Value("sms.aliYun.accessSecret") + private String accessSecret; + + private static final String DOMAIN = "dysmsapi.aliyuncs.com"; + + @Override + public SendResult singleSend(String mobile, String sign, String template, Map params) { + IAcsClient client = getClient(); + CommonRequest request = new CommonRequest(); + request.setMethod(MethodType.POST); + request.setDomain(DOMAIN); + request.setVersion("2017-05-25"); + request.setAction("SendSms"); + + try { + CommonResponse response = client.getCommonResponse(request); + System.out.println(response.getData()); + } catch (ClientException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public SendResult batchSend(List mobileList, String sign, String template, Map params) { + + // 获取 client + IAcsClient client = getClient(); + + // params + CommonRequest request = new CommonRequest(); + request.setMethod(MethodType.POST); + request.setDomain(DOMAIN); + request.setVersion("2017-05-25"); + request.setAction("SendBatchSms"); + + try { + CommonResponse response = client.getCommonResponse(request); + System.out.println(response.getData()); + } catch (ServerException e) { + e.printStackTrace(); + } catch (ClientException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 获取 client + * + * @return + */ + private IAcsClient getClient() { + return new DefaultAcsClient(DefaultProfile.getProfile("default", accessKeyId, accessSecret)); + } +} diff --git a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/client/SmsClient.java b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/client/SmsClient.java new file mode 100644 index 000000000..ddecc399e --- /dev/null +++ b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/client/SmsClient.java @@ -0,0 +1,41 @@ +package cn.iocoder.mall.admin.client; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; +import java.util.Map; + +/** + * 短信平台 + * + * @author Sin + * @time 2019/5/16 6:33 PM + */ +public interface SmsClient { + + @Data + @Accessors(chain = true) + class SendResult { + + private Boolean isSuccess; + + private Integer code; + + private String message; + } + + /** + * 短信发送 - 单个 + * + * @return + */ + SendResult singleSend(String mobile, String sign, String template, Map params); + + /** + * 短信发送 - 批量 + * + * @return + */ + SendResult batchSend(List mobileList, String sign, String template, Map params); +} diff --git a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/client/SmsYunPianClient.java b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/client/SmsYunPianClient.java new file mode 100644 index 000000000..3e10746cc --- /dev/null +++ b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/client/SmsYunPianClient.java @@ -0,0 +1,264 @@ +package cn.iocoder.mall.admin.client; + +import cn.iocoder.common.framework.exception.ServiceException; +import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum; +import cn.iocoder.mall.admin.api.constant.SmsApplyStatusEnum; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.apache.http.HttpEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * 云片 短信平台 + * + * @author Sin + * @time 2019/5/16 6:34 PM + */ +@Component +public class SmsYunPianClient implements SmsClient { + + protected static final Logger LOGGER = LoggerFactory.getLogger(SmsYunPianClient.class); + + private static final int SUCCESS_CODE = 0; + + /** + * 云片短信 - 批量推送最大数 500,支持 1000 + */ + private static final int MAX_BATCH_SIZE = 500; + /** + * 模板 - 参数拼接 + */ + private static final String PARAM_TEMPLATE = "#%s#"; + /** + * 模板 - 签名拼接 + */ + private static final String SIGN_TEMPLATE = "【%s】%s"; + + /** + * 签名 - 添加 + */ + private static final String URL_SIGN_ADD = "https://sms.yunpian.com/v2/sign/add.json"; + /** + * 签名 - 获取 + */ + private static final String URL_SIGN_GET = "https://sms.yunpian.com/v2/sign/get.json"; + /** + * 签名 - 更新 + */ + private static final String URL_SIGN_UPDATE = "https://sms.yunpian.com/v2/sign/update.json"; + /** + * 模板 - 添加 + */ + private static final String URL_TEMPLATE_ADD = "https://sms.yunpian.com/v2/tpl/add.json"; + /** + * 模板 - 获取 + */ + private static final String URL_TEMPLATE_GET = "https://sms.yunpian.com/v2/tpl/get.json"; + /** + * 模板 - 更新 + */ + private static final String URL_TEMPLATE_UPDATE = "https://sms.yunpian.com/v2/tpl/update.json"; + /** + * 模板 - 删除 + */ + private static final String URL_TEMPLATE_DELETE = "https://sms.yunpian.com/v2/tpl/del.json"; + /** + * 短信发送 - 单个 + */ + private static final String URL_SEND_SINGLE = "https://sms.yunpian.com/v2/sms/single_send.json"; + /** + * 短信发送 - 批量 + */ + private static final String URL_SEND_BATCH = "https://sms.yunpian.com/v2/sms/batch_send.json"; + + + //编码格式。发送编码格式统一用UTF-8 + private static String ENCODING = "UTF-8"; + + @Value("${sms.yunPian.apiKey}") + private String apiKey; + + @Override + public SendResult singleSend(String mobile, String sign, String template, Map templateParams) { + + // build 模板 + template = buildTemplate(sign, template, templateParams); + + // 请求参数 + Map params = new LinkedHashMap<>(); + params.put("apikey", apiKey); + params.put("mobile", mobile); + params.put("text", template); + // TODO: 2019/5/19 sin 运营商发送报告 回调 + // params.put("callback_url", template); + String result = post(URL_SEND_SINGLE, params); + JSONObject jsonObject = JSON.parseObject(result); + if (jsonObject.containsKey("code") + && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { + throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), + jsonObject.getString("detail")); + } + + return new SendResult() + .setIsSuccess(SUCCESS_CODE == jsonObject.getInteger("code")) + .setCode(jsonObject.getInteger("code")) + .setMessage(jsonObject.getString("detail")); + } + + @Override + public SendResult batchSend(List mobileList, String sign, String template, Map templateParams) { + + // build 模板 + template = buildTemplate(sign, template, templateParams); + + // 最大发送数为 1000,我们设置为 500 个, 分段发送 + int maxSendSize = MAX_BATCH_SIZE; + int maxSendSizeCount = mobileList.size() % maxSendSize; + int j = 0; + int j2 = mobileList.size(); + + for (int i = 0; i < maxSendSizeCount; i++) { + StringBuffer sendMobileStr = new StringBuffer(); + for (int k = j; k < j2; k++) { + sendMobileStr.append(","); + sendMobileStr.append(mobileList.get(k)); + } + + String dividedMobile = sendMobileStr.toString().substring(1); + + // 发送手机号 + Map params = new LinkedHashMap<>(); + params.put("apikey", apiKey); + params.put("mobile", dividedMobile); + params.put("text", template); + // TODO: 2019/5/19 sin 运营商发送报告 回调 + // params.put("callback_url", template); + String result = post(URL_SEND_BATCH, params); + JSONObject jsonObject = JSON.parseObject(result); + if (jsonObject.containsKey("code") + && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { + throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), + jsonObject.getString("detail")); + } + + // 用于递增 maxSendSize + j = j2; + j2 = j + maxSendSize; + } + + return new SendResult() + .setIsSuccess(true) + .setCode(SUCCESS_CODE) + .setMessage(null); + } + + /** + * 构建模板 + * + * @param sign + * @param template + * @param params + * @return + */ + private static String buildTemplate(String sign, String template, Map params) { + if (CollectionUtils.isEmpty(params)) { + return template; + } + + LOGGER.debug("模板构建 before -> {}", template); + + for (Map.Entry entry : params.entrySet()) { + String paramsKey = entry.getKey(); + String value = entry.getValue(); + String paramPlace = String.format(PARAM_TEMPLATE, paramsKey); + template = template.replaceAll(paramPlace, value); + } + + template = String.format(SIGN_TEMPLATE, sign, template); + LOGGER.debug("模板构建 after -> {}", template); + return template; + } + + /** + * 短信 status 和 云片状态 映射关系 + * + * @param checkStatus + * @return + */ + private static Integer smsStatusMapping(String checkStatus) { + Integer applyStatus; + switch (checkStatus) { + case "SUCCESS": + applyStatus = SmsApplyStatusEnum.SUCCESS.getValue(); + break; + case "FAIL": + applyStatus = SmsApplyStatusEnum.FAIL.getValue(); + break; + default: + applyStatus = SmsApplyStatusEnum.CHECKING.getValue(); + break; + } + return applyStatus; + } + + /** + * 基于HttpClient 4.3的通用POST方法 + * + * @param url 提交的URL + * @param paramsMap 提交<参数,值>Map + * @return 提交响应 + */ + + public static String post(String url, Map paramsMap) { + + // TODO: 2019/5/25 Sin 这个地方需要 记录日志 + CloseableHttpClient client = HttpClients.createDefault(); + String responseText = ""; + CloseableHttpResponse response = null; + try { + HttpPost method = new HttpPost(url); + if (paramsMap != null) { + List paramList = new ArrayList<>(); + for (Map.Entry param : paramsMap.entrySet()) { + NameValuePair pair = new BasicNameValuePair(param.getKey(), + param.getValue()); + paramList.add(pair); + } + method.setEntity(new UrlEncodedFormEntity(paramList, ENCODING)); + } + response = client.execute(method); + HttpEntity entity = response.getEntity(); + if (entity != null) { + responseText = EntityUtils.toString(entity, ENCODING); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + response.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + LOGGER.debug("云片短信平台 res: {}", responseText); + return responseText; + } +} diff --git a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsClientLog.java b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsClientLog.java new file mode 100644 index 000000000..5eb7874ea --- /dev/null +++ b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsClientLog.java @@ -0,0 +1,33 @@ +package cn.iocoder.mall.admin.dataobject; + +import cn.iocoder.common.framework.dataobject.BaseDO; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 短信 client log + * + * @author Sin + * @time 2019/5/25 12:36 PM + */ +@Data +@Accessors(chain = true) +public class SmsClientLog extends BaseDO { + + /** + * 编号 + */ + private Integer id; + /** + * 短信模板 + */ + private Integer templateId; + /** + * 短信 + */ + private String template; + /** + * 发送信息 + */ + private String message; +} diff --git a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsSignDO.java b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsSignDO.java index 300ebb329..eb9147f57 100644 --- a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsSignDO.java +++ b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsSignDO.java @@ -22,14 +22,17 @@ public class SmsSignDO extends DeletableDO { * 编号 */ private Integer id; - /** - * 签名id 这个是第三方的 - */ - private String platformId; /** * 签名名称 */ private String sign; + /** + * 平台 + * + * 1、云片 + * 2、阿里云 + */ + private Integer platform; /** * 审核状态 * diff --git a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsTemplateDO.java b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsTemplateDO.java index 4fd3f4fb9..1975e7338 100644 --- a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsTemplateDO.java +++ b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/dataobject/SmsTemplateDO.java @@ -28,11 +28,19 @@ public class SmsTemplateDO extends DeletableDO { /** * 短信签名 id */ - private String platformId; + private Integer platform; /** * 短信模板 */ private String template; + /** + * 短信类型 + * + * - 验证码类 + * - 通知类 + * - 营销类 + */ + private Integer smsType; /** * 审核状态 * diff --git a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/service/SmsServiceImpl.java b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/service/SmsServiceImpl.java index 77f342799..24e4ab926 100644 --- a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/service/SmsServiceImpl.java +++ b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/service/SmsServiceImpl.java @@ -2,7 +2,10 @@ package cn.iocoder.mall.admin.service; import cn.iocoder.common.framework.constant.DeletedStatusEnum; import cn.iocoder.common.framework.exception.ServiceException; -import cn.iocoder.mall.admin.api.SmsPlatform; +import cn.iocoder.mall.admin.api.DataDictService; +import cn.iocoder.mall.admin.api.constant.SmsApplyStatusEnum; +import cn.iocoder.mall.admin.api.constant.SmsPlatformEnum; +import cn.iocoder.mall.admin.client.SmsClient; import cn.iocoder.mall.admin.api.SmsService; import cn.iocoder.mall.admin.api.bo.sms.SmsSignBO; import cn.iocoder.mall.admin.api.bo.sms.PageSmsSignBO; @@ -49,8 +52,13 @@ public class SmsServiceImpl implements SmsService { private SmsTemplateMapper smsTemplateMapper; @Autowired - @Qualifier("smsYunPianPlatform") - private SmsPlatform smsPlatform; + @Qualifier("smsYunPianClient") + private SmsClient smsYunPianClient; + @Autowired + @Qualifier("smsAliYunClient") + private SmsClient smsAliYunClient; + @Autowired + private DataDictService dataDictService; @Override public PageSmsSignBO pageSmsSign(PageQuerySmsSignDTO queryDTO) { @@ -108,26 +116,26 @@ public class SmsServiceImpl implements SmsService { @Override @Transactional - public void createSign(String sign) { + public void createSign(String sign, Integer platform) { // 避免重复 SmsSignDO smsSignDO = smsSignMapper.selectOne( - new QueryWrapper().eq("sign", sign)); + new QueryWrapper() + .eq("platform", platform) + .eq("sign", sign) + ); if (smsSignDO != null) { throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_IS_EXISTENT.getCode(), AdminErrorCodeEnum.SMS_SIGN_IS_EXISTENT.getMessage()); } - // 创建平台 sign - SmsPlatform.Result result = smsPlatform.createSign(sign); - // 保存数据库 smsSignMapper.insert( (SmsSignDO) new SmsSignDO() .setSign(sign) - .setPlatformId(result.getId()) - .setApplyStatus(result.getApplyStatus()) + .setPlatform(platform) + .setApplyStatus(SmsApplyStatusEnum.SUCCESS.getValue()) .setDeleted(DeletedStatusEnum.DELETED_NO.getValue()) .setUpdateTime(new Date()) .setCreateTime(new Date()) @@ -135,9 +143,11 @@ public class SmsServiceImpl implements SmsService { } @Override - public SmsSignBO getSign(String sign) { + public SmsSignBO getSign(Integer signId) { SmsSignDO smsSignDO = smsSignMapper.selectOne( - new QueryWrapper().eq("sign", sign)); + new QueryWrapper() + .eq("id", signId) + .eq("deleted", DeletedStatusEnum.DELETED_NO.getValue())); if (smsSignDO == null) { throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(), @@ -149,33 +159,49 @@ public class SmsServiceImpl implements SmsService { @Override @Transactional - public void updateSign(String oldSign, String sign) { + public void updateSign(Integer id, String newSign, Integer platform) { // 避免重复 SmsSignDO smsSignDO = smsSignMapper.selectOne( - new QueryWrapper().eq("sign", oldSign)); + new QueryWrapper() + .eq("sign", newSign) + .eq("platform", platform)); + + if (smsSignDO != null) { + throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_IS_EXISTENT.getCode(), + AdminErrorCodeEnum.SMS_SIGN_IS_EXISTENT.getMessage()); + } + + // 更新 + smsSignMapper.update( + (SmsSignDO) new SmsSignDO() + .setSign(newSign) + .setPlatform(platform) + .setUpdateTime(new Date()), + new QueryWrapper().eq("id", id) + ); + } + + @Override + public void deleteSign(Integer id) { + SmsSignDO smsSignDO = smsSignMapper.selectOne( + new QueryWrapper() + .eq("id", id)); if (smsSignDO == null) { throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(), AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage()); } - // 更新平台 - SmsPlatform.Result result = smsPlatform.updateSign(oldSign, sign); - - // 更新 - smsSignMapper.updateById( - (SmsSignDO) new SmsSignDO() - .setId(smsSignDO.getId()) - .setPlatformId(result.getId()) - .setSign(sign) - .setApplyStatus(result.getApplyStatus()) - .setUpdateTime(new Date()) + // 更新 deleted 为 YES + smsSignMapper.delete(new UpdateWrapper() + .set("deleted", DeletedStatusEnum.DELETED_YES.getName()) + .eq("id", id) ); } @Override @Transactional - public void createTemplate(Integer smsSignId, String template, Integer tplType) { + public void createTemplate(Integer smsSignId, String template, Integer platform, Integer smsType) { SmsSignDO smsSignDO = smsSignMapper.selectOne( new QueryWrapper().eq("id", smsSignId)); @@ -185,28 +211,27 @@ public class SmsServiceImpl implements SmsService { AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage()); } - // 调用平台 - SmsPlatform.Result result = smsPlatform - .createTemplate(String.format(SMS_TEMPLATE, smsSignDO.getSign(), template), tplType); - // 保存数据库 smsTemplateMapper.insert( (SmsTemplateDO) new SmsTemplateDO() .setId(null) .setSmsSignId(smsSignId) - .setPlatformId(result.getId()) .setTemplate(template) - .setApplyStatus(result.getApplyStatus()) - .setApplyMessage(result.getApplyMessage()) + .setPlatform(platform) + .setSmsType(smsType) + .setApplyStatus(SmsApplyStatusEnum.SUCCESS.getValue()) + .setApplyMessage("") .setDeleted(DeletedStatusEnum.DELETED_NO.getValue()) .setCreateTime(new Date()) ); } @Override - public SmsTemplateBO getTemplate(Integer id) { + public SmsTemplateBO getTemplate(Integer id, Integer platform) { SmsTemplateDO smsTemplateDO = smsTemplateMapper.selectOne( - new QueryWrapper().eq("id", id)); + new QueryWrapper() + .eq("platform", platform) + .eq("id", id)); if (smsTemplateDO == null) { throw new ServiceException(AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getCode(), @@ -218,7 +243,7 @@ public class SmsServiceImpl implements SmsService { @Override @Transactional - public void updateTemplate(Integer id, String template, Integer tplType) { + public void updateTemplate(Integer id, Integer smsSignId, String template, Integer platform, Integer smsType) { SmsTemplateDO smsTemplateDO = smsTemplateMapper.selectOne( new QueryWrapper().eq("id", id)); @@ -230,16 +255,17 @@ public class SmsServiceImpl implements SmsService { SmsSignDO smsSignDO = smsSignMapper.selectOne( new QueryWrapper().eq("id", smsTemplateDO.getSmsSignId())); - - SmsPlatform.Result result = smsPlatform.updateTemplate( - smsTemplateDO.getPlatformId(), - String.format(SMS_TEMPLATE, smsSignDO.getSign(), template), tplType); + if (smsSignDO == null) { + throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(), + AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage()); + } smsTemplateMapper.update( (SmsTemplateDO) new SmsTemplateDO() + .setSmsSignId(smsSignId) .setTemplate(template) - .setApplyStatus(result.getApplyStatus()) - .setApplyMessage(result.getApplyMessage()) + .setPlatform(platform) + .setSmsType(smsType) .setUpdateTime(new Date()), new QueryWrapper().eq("id", id) ); @@ -257,20 +283,17 @@ public class SmsServiceImpl implements SmsService { AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getMessage()); } - // 删除 平台的模板 - smsPlatform.deleteTemplate(smsTemplateDO.getPlatformId()); - // 删除 数据库模板 SmsTemplateDO updateTemplate =new SmsTemplateDO(); updateTemplate.setDeleted(DeletedStatusEnum.DELETED_YES.getValue()); - smsTemplateMapper.delete(new UpdateWrapper() - .set("deleted", DeletedStatusEnum.DELETED_YES).eq("id", id)); + smsTemplateMapper.delete( + new UpdateWrapper() + .set("deleted", DeletedStatusEnum.DELETED_YES) + .eq("id", id)); } @Override public void singleSend(String mobile, Integer smsTemplateId, Map params) { - - // TODO: 2019/5/21 Sin params 参数为特换到模板中 SmsTemplateDO smsTemplateDO = smsTemplateMapper.selectOne( new QueryWrapper().eq("id", smsTemplateId)); @@ -283,14 +306,19 @@ public class SmsServiceImpl implements SmsService { SmsSignDO smsSignDO = smsSignMapper.selectOne( new QueryWrapper().eq("id", smsTemplateDO.getSmsSignId())); - smsPlatform.singleSend(mobile, - String.format(SMS_TEMPLATE, smsSignDO.getSign(), smsTemplateDO.getTemplate())); + if (smsSignDO == null) { + throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(), + AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage()); + } + + // 获取 client + SmsClient smsClient = getSmsClient(smsTemplateDO.getPlatform()); + // 发送短信 + smsClient.singleSend(mobile, smsSignDO.getSign(), smsTemplateDO.getTemplate(), params); } @Override public void batchSend(List mobileList, Integer smsTemplateId, Map params) { - // TODO: 2019/5/21 Sin params 参数为特换到模板中 - SmsTemplateDO smsTemplateDO = smsTemplateMapper.selectOne( new QueryWrapper().eq("id", smsTemplateId)); @@ -303,7 +331,37 @@ public class SmsServiceImpl implements SmsService { SmsSignDO smsSignDO = smsSignMapper.selectOne( new QueryWrapper().eq("id", smsTemplateDO.getSmsSignId())); - smsPlatform.batchSend(mobileList, - String.format(SMS_TEMPLATE, smsSignDO.getSign(), smsTemplateDO.getTemplate())); + if (smsSignDO == null) { + throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(), + AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage()); + } + + // 获取 client + SmsClient smsClient = getSmsClient(smsTemplateDO.getPlatform()); + // 发送短信 + smsClient.batchSend(mobileList, smsSignDO.getSign(), smsTemplateDO.getTemplate(), params); + } + + /** + * 获取 sms 对于的 client + * + * @param platform + * @return + */ + private SmsClient getSmsClient(Integer platform) { + SmsClient smsClient = null; + if (SmsPlatformEnum.YunPian.getValue().equals(platform)) { + smsClient = smsYunPianClient; + } else if (SmsPlatformEnum.AliYun.getValue().equals(platform)) { + smsClient = smsAliYunClient; + } + + if (smsClient == null) { + throw new ServiceException( + AdminErrorCodeEnum.SMS_NOT_SEND_CLIENT.getCode(), + AdminErrorCodeEnum.SMS_NOT_SEND_CLIENT.getMessage()); + } + + return smsClient; } } diff --git a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/service/SmsYunPianPlatform.java b/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/service/SmsYunPianPlatform.java deleted file mode 100644 index 8c82fef4f..000000000 --- a/system/system-service-impl/src/main/java/cn/iocoder/mall/admin/service/SmsYunPianPlatform.java +++ /dev/null @@ -1,419 +0,0 @@ -package cn.iocoder.mall.admin.service; - -import cn.iocoder.common.framework.exception.ServiceException; -import cn.iocoder.mall.admin.api.SmsPlatform; -import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum; -import cn.iocoder.mall.admin.api.constant.SmsApplyStatusEnum; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import org.apache.http.HttpEntity; -import org.apache.http.NameValuePair; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.assertj.core.util.Lists; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import java.util.*; - -/** - * 云片 短信平台 - * - * @author Sin - * @time 2019/5/16 6:34 PM - */ -@Service -public class SmsYunPianPlatform implements SmsPlatform { - - protected static final Logger LOGGER = LoggerFactory.getLogger(SmsPlatform.class); - - private static final int SUCCESS_CODE = 0; - - //查账户信息的http地址 - private static final String URI_GET_USER_INFO = - "https://sms.yunpian.com/v2/user/get.json"; - - //智能匹配模板发送接口的http地址 - - //模板发送接口的http地址 - private static final String URI_TPL_SEND_SMS = - "https://sms.yunpian.com/v2/sms/tpl_single_send.json"; - - //发送语音验证码接口的http地址 - private static final String URI_SEND_VOICE = - "https://voice.yunpian.com/v2/voice/send.json"; - - //绑定主叫、被叫关系的接口http地址 - private static final String URI_SEND_BIND = - "https://call.yunpian.com/v2/call/bind.json"; - - //解绑主叫、被叫关系的接口http地址 - private static final String URI_SEND_UNBIND = - "https://call.yunpian.com/v2/call/unbind.json"; - - /** - * 签名 - 添加 - */ - private static final String URL_SIGN_ADD = "https://sms.yunpian.com/v2/sign/add.json"; - /** - * 签名 - 获取 - */ - private static final String URL_SIGN_GET = "https://sms.yunpian.com/v2/sign/get.json"; - /** - * 签名 - 更新 - */ - private static final String URL_SIGN_UPDATE = "https://sms.yunpian.com/v2/sign/update.json"; - /** - * 模板 - 添加 - */ - private static final String URL_TEMPLATE_ADD = "https://sms.yunpian.com/v2/tpl/add.json"; - /** - * 模板 - 获取 - */ - private static final String URL_TEMPLATE_GET = "https://sms.yunpian.com/v2/tpl/get.json"; - /** - * 模板 - 更新 - */ - private static final String URL_TEMPLATE_UPDATE = "https://sms.yunpian.com/v2/tpl/update.json"; - /** - * 模板 - 删除 - */ - private static final String URL_TEMPLATE_DELETE = "https://sms.yunpian.com/v2/tpl/del.json"; - /** - * 短信发送 - 单个 - */ - private static final String URL_SEND_SINGLE = "https://sms.yunpian.com/v2/sms/single_send.json"; - /** - * 短信发送 - 批量 - */ - private static final String URL_SEND_BATCH = "https://sms.yunpian.com/v2/sms/batch_send.json"; - - - //编码格式。发送编码格式统一用UTF-8 - private static String ENCODING = "UTF-8"; - - @Value("${sms.apiKey}") - private String apiKey; - - @Override - public Result createSign(String sign) { - try { - // 存在直接 return 相当于,创建了 - return getSign(sign); - } catch (ServiceException e) { - // skip 不存在会进这里,不错任何操作 - } - - // 调用 短信平台 - Map params = new LinkedHashMap<>(); - params.put("apikey", apiKey); - params.put("sign", sign); - params.put("notify", "true"); - String result = post(URL_SIGN_ADD, params); - JSONObject jsonObject = JSON.parseObject(result); - if (jsonObject.containsKey("code") - && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { - throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), - jsonObject.getString("detail")); - } - - JSONObject signJSONObject = (JSONObject) jsonObject.get("sign"); - Integer applyState = smsStatusMapping(signJSONObject.getString("apply_state")); - return new Result().setId(null).setApplyStatus(applyState).setApplyMessage(null); - } - - @Override - public Result getSign(String sign) { - Map params = new LinkedHashMap<>(); - params.put("apikey", apiKey); - params.put("sign", sign); - params.put("page_num", "1"); - params.put("page_size", "20"); - String result = post(URL_SIGN_GET, params); - JSONObject jsonObject = JSON.parseObject(result); - - if (jsonObject.containsKey("code") - && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { - throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), - jsonObject.getString("detail")); - } - - JSONArray jsonArray = jsonObject.getJSONArray("sign"); - if (jsonArray.size() <= 0) { - throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(), - AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage()); - } - - JSONObject signJSONObject = (JSONObject) jsonArray.get(0); - String checkStatus = signJSONObject.getString("check_status"); - String applyMessage = signJSONObject.getString("remark"); - Integer applyStatus = smsStatusMapping(checkStatus); - return new Result().setId(null).setApplyStatus(applyStatus).setApplyMessage(applyMessage); - } - - @Override - public Result updateSign(String oldSign, String sign) { - Map params = new LinkedHashMap<>(); - params.put("apikey", apiKey); - params.put("old_sign", oldSign); - params.put("sign", sign); - String result = post(URL_SIGN_UPDATE, params); - JSONObject jsonObject = JSON.parseObject(result); - - if (jsonObject.containsKey("code") - && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { - throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), - jsonObject.getString("detail")); - } - - JSONObject signJSONObject = (JSONObject) jsonObject.get("sign"); - Integer applyState = smsStatusMapping(signJSONObject.getString("apply_state")); - return new Result().setId(null).setApplyStatus(applyState).setApplyMessage(null); - } - - @Override - public Result createTemplate(String template, Integer tplType) { - Map params = new LinkedHashMap<>(); - params.put("apikey", apiKey); - params.put("tpl_content", template); - if (tplType != null) { - params.put("tplType", String.valueOf(tplType)); - } - String result = post(URL_TEMPLATE_ADD, params); - JSONObject jsonObject = JSON.parseObject(result); - - if (jsonObject.containsKey("code") - && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { - throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), - jsonObject.getString("detail")); - } - - String tipId = jsonObject.getString("tpl_id"); - String checkStatus = jsonObject.getString("check_status"); - String reason = jsonObject.getString("reason"); - Integer applyStatus = smsStatusMapping(checkStatus); - return new Result().setId(tipId).setApplyStatus(applyStatus).setApplyMessage(reason); - } - - @Override - public Result getTemplate(String tplId) { - Map params = new LinkedHashMap<>(); - params.put("apikey", apiKey); - params.put("tpl_id", tplId); - String result = post(URL_TEMPLATE_GET, params); - JSONObject jsonObject = JSON.parseObject(result); - - if (jsonObject.containsKey("code") - && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { - throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), - jsonObject.getString("detail")); - } - - String checkStatus = jsonObject.getString("check_status"); - Integer applyStatus = smsStatusMapping(checkStatus); - String reason = jsonObject.getString("reason"); - return new Result().setId(tplId).setApplyStatus(applyStatus).setApplyMessage(reason); - } - - @Override - public Result updateTemplate(String tplId, String template, Integer tplType) { - Map params = new LinkedHashMap<>(); - params.put("apikey", apiKey); - params.put("tpl_id", tplId); - params.put("tpl_content", template); - String result = post(URL_TEMPLATE_UPDATE, params); - JSONObject jsonObject = JSON.parseObject(result); - - if (jsonObject.containsKey("code") - && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { - throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), - jsonObject.getString("detail")); - } - - JSONObject templateJSONObject = (JSONObject) jsonObject.get("template"); - String checkStatus = templateJSONObject.getString("check_status"); - Integer applyStatus = smsStatusMapping(checkStatus); - String reason = jsonObject.getString("reason"); - return new Result().setId(tplId).setApplyStatus(applyStatus).setApplyMessage(reason); - } - - @Override - public Result deleteTemplate(String tplId) { - - // 如果不存在/已删除,直接返回 - try { - getTemplate(tplId); - } catch (ServiceException e) { - // skip - return new Result().setId(tplId).setApplyStatus(null).setApplyMessage(null); - } - - Map params = new LinkedHashMap<>(); - params.put("apikey", apiKey); - params.put("tpl_id", tplId); - String result = post(URL_TEMPLATE_DELETE, params); - JSONObject jsonObject = JSON.parseObject(result); - - if (jsonObject.containsKey("code") - && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { - throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), - jsonObject.getString("detail")); - } - - return new Result().setId(tplId).setApplyStatus(null).setApplyMessage(null); - } - - @Override - public SendResult singleSend(String mobile, String template) { - Map params = new LinkedHashMap<>(); - params.put("apikey", apiKey); - params.put("mobile", mobile); - params.put("text", template); - // TODO: 2019/5/19 sin 运营商发送报告 回调 - // params.put("callback_url", template); - String result = post(URL_TEMPLATE_DELETE, params); - JSONObject jsonObject = JSON.parseObject(result); - if (jsonObject.containsKey("code") - && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { - throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), - jsonObject.getString("detail")); - } - - return new SendResult() - .setHasSuccess(SUCCESS_CODE == jsonObject.getInteger("code")) - .setCode(jsonObject.getInteger("code")) - .setMessage(jsonObject.getString("detail")) - .setSuccess(Lists.newArrayList(mobile)) - .setFail(Collections.EMPTY_LIST); - } - - @Override - public SendResult batchSend(List mobileList, String template) { - - // 最大发送数为 1000,我们设置为 500 个, 分段发送 - int maxSendSize = 500; - int maxSendSizeCount = mobileList.size() % maxSendSize; - int j = 0; - int j2 = maxSendSize; - - List successList = new ArrayList<>(); - List failList = new ArrayList<>(); - for (int i = 0; i < maxSendSizeCount; i++) { - StringBuffer sendMobileStr = new StringBuffer(); - for (int k = j; k < j2; k++) { - sendMobileStr.append(","); - sendMobileStr.append(mobileList.get(k)); - } - - String dividedMobile = sendMobileStr.toString().substring(1); - - // 发送手机号 - Map params = new LinkedHashMap<>(); - params.put("apikey", apiKey); - params.put("mobile", dividedMobile); - params.put("text", template); - // TODO: 2019/5/19 sin 运营商发送报告 回调 - // params.put("callback_url", template); - String result = post(URL_SEND_BATCH, params); - JSONObject jsonObject = JSON.parseObject(result); - if (jsonObject.containsKey("code") - && !(jsonObject.getInteger("code") == SUCCESS_CODE)) { - throw new ServiceException(AdminErrorCodeEnum.SMS_PLATFORM_FAIL.getCode(), - jsonObject.getString("detail")); - } - - JSONArray jsonArray = jsonObject.getJSONArray("data"); - for (Object o : jsonArray) { - JSONObject dataJSONObject = (JSONObject) o; - if (SUCCESS_CODE == dataJSONObject.getInteger("code")) { - successList.add(dataJSONObject.getString("mobile")); - } else { - failList.add(dataJSONObject.getString("mobile")); - } - } - - // 用于递增 maxSendSize - j = j2; - j2 = j + maxSendSize; - } - - return new SendResult() - .setHasSuccess(true) - .setCode(SUCCESS_CODE) - .setMessage(null) - .setSuccess(successList) - .setFail(failList); - } - - /** - * 短信 status 和 云片状态 映射关系 - * - * @param checkStatus - * @return - */ - private Integer smsStatusMapping(String checkStatus) { - Integer applyStatus; - switch (checkStatus) { - case "SUCCESS": - applyStatus = SmsApplyStatusEnum.SUCCESS.getCode(); - break; - case "FAIL": - applyStatus = SmsApplyStatusEnum.FAIL.getCode(); - break; - default: - applyStatus = SmsApplyStatusEnum.CHECKING.getCode(); - break; - } - return applyStatus; - } - - /** - * 基于HttpClient 4.3的通用POST方法 - * - * @param url 提交的URL - * @param paramsMap 提交<参数,值>Map - * @return 提交响应 - */ - - public static String post(String url, Map paramsMap) { - CloseableHttpClient client = HttpClients.createDefault(); - String responseText = ""; - CloseableHttpResponse response = null; - try { - HttpPost method = new HttpPost(url); - if (paramsMap != null) { - List paramList = new ArrayList<>(); - for (Map.Entry param : paramsMap.entrySet()) { - NameValuePair pair = new BasicNameValuePair(param.getKey(), - param.getValue()); - paramList.add(pair); - } - method.setEntity(new UrlEncodedFormEntity(paramList, ENCODING)); - } - response = client.execute(method); - HttpEntity entity = response.getEntity(); - if (entity != null) { - responseText = EntityUtils.toString(entity, ENCODING); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - response.close(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - LOGGER.debug("云片短信平台 res: {}", responseText); - return responseText; - } -} diff --git a/system/system-service-impl/src/main/resources/config/application.yaml b/system/system-service-impl/src/main/resources/config/application.yaml index 7b8f80fb4..6f12e70b0 100644 --- a/system/system-service-impl/src/main/resources/config/application.yaml +++ b/system/system-service-impl/src/main/resources/config/application.yaml @@ -26,7 +26,13 @@ mybatis-plus: # sms sms: - apiKey: d4705399e71e822fe3a90f801ed95bd9 + yunPian: + apiKey: d4705399e71e822fe3a90f801ed95bd9 + aliYun: + accessKeyId: d4705399e71e822fe3a90f801ed95bd9 + accessSecret: d4705399e71e822fe3a90f801ed95bd9 + + # dubbo dubbo: diff --git a/system/system-service-impl/src/test/java/cn/iocoder/mall/admin/client/SmsYunPianClientTest.java b/system/system-service-impl/src/test/java/cn/iocoder/mall/admin/client/SmsYunPianClientTest.java new file mode 100644 index 000000000..846f0df77 --- /dev/null +++ b/system/system-service-impl/src/test/java/cn/iocoder/mall/admin/client/SmsYunPianClientTest.java @@ -0,0 +1,56 @@ +package cn.iocoder.mall.admin.client; + +import cn.iocoder.mall.admin.SystemApplicationTest; +import com.aliyuncs.CommonRequest; +import com.aliyuncs.CommonResponse; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.exceptions.ServerException; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import com.google.common.collect.ImmutableMap; +import org.assertj.core.util.Lists; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Map; + +/** + * 短信 sms client test + * + * @author Sin + * @time 2019/5/25 12:46 PM + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SystemApplicationTest.class) +public class SmsYunPianClientTest { + + @Autowired + private SmsYunPianClient smsYunPianClient; + + private String sign = null; + + @Before + public void setup() { + sign = "悦跑运动"; + } + + @Test + public void sendMobileTest() { + String mobile = "13302926050"; + String template = "您的验证码是#code#,打死也不告诉别人哦。"; + smsYunPianClient.singleSend(mobile, sign, template, ImmutableMap.of("code", "1111")); + } + + @Test + public void batchSendTest() { + String mobile = "13302926050"; + String template = "您的验证码是#code#,打死也不告诉别人哦。"; + smsYunPianClient.batchSend(Lists.newArrayList(mobile), sign, template, ImmutableMap.of("code", "2222")); + } +} diff --git a/system/system-service-impl/src/test/java/cn/iocoder/mall/admin/service/SmsServiceImplTest.java b/system/system-service-impl/src/test/java/cn/iocoder/mall/admin/service/SmsServiceImplTest.java index 40edf35ba..29f94c775 100644 --- a/system/system-service-impl/src/test/java/cn/iocoder/mall/admin/service/SmsServiceImplTest.java +++ b/system/system-service-impl/src/test/java/cn/iocoder/mall/admin/service/SmsServiceImplTest.java @@ -1,10 +1,16 @@ package cn.iocoder.mall.admin.service; +import cn.iocoder.common.framework.exception.ServiceException; import cn.iocoder.mall.admin.SystemApplicationTest; +import cn.iocoder.mall.admin.api.SmsService; import cn.iocoder.mall.admin.api.bo.sms.SmsSignBO; -import cn.iocoder.mall.admin.api.bo.sms.SmsTemplateBO; +import cn.iocoder.mall.admin.api.constant.SmsPlatformEnum; +import cn.iocoder.mall.admin.api.constant.SmsTypeEnum; +import com.google.common.collect.ImmutableMap; +import org.assertj.core.util.Lists; import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -21,55 +27,57 @@ import org.springframework.test.context.junit4.SpringRunner; public class SmsServiceImplTest { @Autowired - private SmsServiceImpl smsService; + private SmsService smsService; @Test public void createSignTest() { - smsService.createSign("测试签名1"); -// smsService.createSign("悦跑会"); + smsService.createSign("悦跑运动", SmsPlatformEnum.YunPian.getValue()); + } @Test public void getSignTest() { - SmsSignBO smsSignBO = smsService.getSign("悦跑会"); - Assert.assertNotNull(smsSignBO); + SmsSignBO smsSignBO = smsService.getSign(3); + Assert.assertNotNull("不能为空!", smsSignBO); } @Test public void updateSignTest() { - smsService.updateSign("测试签名2", "测试签名3"); - SmsSignBO newSmsSignBO = smsService.getSign("测试签名3"); - Assert.assertNotNull(newSmsSignBO); + String oldSign = "悦跑运动2"; + String newSign = "悦跑运动"; + smsService.updateSign(3, newSign, SmsPlatformEnum.YunPian.getValue()); + SmsSignBO smsSignBO = smsService.getSign(3); + Assert.assertTrue("更新不成功!", smsSignBO.getSign().equals(newSign)); } - /// - /// template + @Test + public void deletedSignTest() { + smsService.deleteSign(3); + Assertions.assertThrows(ServiceException.class, () -> { + smsService.getSign(3); + }); + } @Test public void createTemplateTest() { - smsService.createTemplate(1, "打死也不要告诉别人哦002 #code# ", 1); - } - - @Test - public void getTemplateTest() { - SmsTemplateBO smsTemplateBO = smsService.getTemplate(3); - Assert.assertNotNull(smsTemplateBO); - } - - @Test - public void updateTemplateTest() { - smsService.updateTemplate(3, "打死也不要告诉别人哦444 #code# ", 1); - } - - @Test - public void deleteTemplateTest() { - smsService.deleteTemplate(3); + String template = "您的验证码是#code#,打死也不告诉别人哦。"; + smsService.createTemplate(3, template, + SmsPlatformEnum.YunPian.getValue(), + SmsTypeEnum.VERIFICATION_CODE.getValue()); } @Test public void singleSendTest() { String mobile = "13302926050"; - smsService.singleSend(mobile, 1); + Integer templateId = 5; + smsService.singleSend(mobile, templateId, ImmutableMap.of("code", "8888")); + } + + @Test + public void batchSendTest() { + String mobile = "13302926050"; + Integer templateId = 5; + smsService.batchSend(Lists.newArrayList(mobile), templateId, ImmutableMap.of("code", "8888")); } }