完成的商品搜索和条件功能

This commit is contained in:
YunaiV
2020-08-04 19:42:54 +08:00
parent f3316d14c7
commit b83262af5f
240 changed files with 246 additions and 859 deletions

View File

@@ -0,0 +1,162 @@
package cn.iocoder.mall.admin.client;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Collections;
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 {
private static final Logger LOGGER = LoggerFactory.getLogger(SmsAliYunClient.class);
private static final String DOMAIN = "dysmsapi.aliyuncs.com";
private static final String SUCCESS_CODE = "OK";
private static final String SUCCESS_MESSAGE = "OK";
/**
* 阿里云短信 - 批量推送最大数 500支持 1000
*/
private static final int MAX_BATCH_SIZE = 500;
@Value("${sms.aliYun.accessKeyId?:'default_value'}")
private String accessKeyId;
@Value("${sms.aliYun.accessSecret?:'default_value'}")
private String accessSecret;
@Data
@Accessors(chain = true)
public static class Result {
/**
* 发送回执ID可根据该ID在接口QuerySendDetails中查询具体的发送状态。
*/
private String BizId;
/**
* 请求状态码。
*
* - OK 蔡成功
*/
private String Code;
/**
* 状态码的描述。
*/
private String Message;
/**
* 请求ID。
*/
private String RequestId;
}
@Override
public SendResult singleSend(String mobile, String sign, String templateCode,
String template, Map<String, String> templateParams) {
// params
CommonRequest request = new CommonRequest();
request.setMethod(MethodType.POST);
request.setDomain(DOMAIN);
request.setVersion("2017-05-25");
request.setAction("SendSms");
request.putQueryParameter("PhoneNumbers", mobile);
request.putQueryParameter("SignName", sign);
request.putQueryParameter("TemplateCode", templateCode);
request.putQueryParameter("TemplateParam", JSON.toJSONString(templateParams));
// 发送请求
return doSend(request);
}
@Override
public SendResult batchSend(List<String> mobileList, String sign, String templateCode,
String template, Map<String, String> templateParams) {
// 最大发送数为 1000我们设置为 500 个, 分段发送
int maxSendSize = MAX_BATCH_SIZE;
int maxSendSizeCount = mobileList.size() % maxSendSize == 0
? mobileList.size() / maxSendSize
: mobileList.size() / maxSendSize + 1;
SendResult sendResult = null;
for (int i = 0; i < maxSendSizeCount; i++) {
// 分批发送
List<String> batchSendMobile = mobileList
.subList(i * maxSendSize, (i + 1) * maxSendSize);
// params
CommonRequest request = new CommonRequest();
request.setMethod(MethodType.POST);
request.setDomain(DOMAIN);
request.setVersion("2017-05-25");
request.setAction("SendBatchSms");
request.putQueryParameter("PhoneNumberJson", JSON.toJSONString(batchSendMobile));
request.putQueryParameter("SignNameJson", JSON.toJSONString(Collections.singletonList(sign)));
request.putQueryParameter("TemplateCode", templateCode);
request.putQueryParameter("TemplateParamJson", JSON.toJSONString(Collections.singletonList(templateParams)));
// 发送请求
sendResult = doSend(request);
}
return sendResult;
}
private SendResult doSend(CommonRequest request) {
// 获取 client
IAcsClient client = getClient();
try {
CommonResponse response = client.getCommonResponse(request);
Result result = JSON.parseObject(response.getData(), Result.class);
if (!SUCCESS_CODE.equals(result.getCode())) {
LOGGER.info("发送验证码失败 params {} res {}", JSON.toJSON(request), JSON.toJSON(result));
// 错误发送失败
return new SendResult()
.setIsSuccess(false)
.setCode(SendResult.ERROR_CODE)
.setMessage(result.getMessage());
} else {
LOGGER.info("发送验证码失败 params {} res", JSON.toJSON(request), JSON.toJSON(result));
// 发送成功
return new SendResult()
.setIsSuccess(true)
.setCode(SendResult.SUCCESS_CODE)
.setMessage(result.getMessage());
}
} catch (ClientException e) {
LOGGER.error("发送验证码异常 {}", ExceptionUtils.getMessage(e));
return new SendResult()
.setIsSuccess(false)
.setCode(SendResult.ERROR_CODE)
.setMessage(ExceptionUtils.getMessage(e));
}
}
/**
* 获取 client
*
* @return
*/
private IAcsClient getClient() {
return new DefaultAcsClient(DefaultProfile.getProfile("default", accessKeyId, accessSecret));
}
}

View File

@@ -0,0 +1,66 @@
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 {
public static final int SUCCESS_CODE = 0;
public static final int ERROR_CODE = 1;
public static final String SUCCESS_MESSAGE = "SUCCESS";
/**
* 错误码
*/
private Integer code;
/**
* 错误信息
*/
private String message;
/**
* 是否成功
*/
private Boolean isSuccess;
}
/**
* 短信发送 - 单个
*
* @param mobile 手机号
* @param sign 签名
* @param templateCode 短信模板code
* @param template 短信模板
* @param templateParams 短信模板 params
* @return 发送后信息
*/
SendResult singleSend(String mobile, String sign, String templateCode,
String template, Map<String, String> templateParams);
/**
* 短信发送 - 批量
*
* @param mobileList 手机号
* @param sign 签名
* @param templateCode 短信模板 code
* @param template 短信模板
* @param templateParams 短信模板params
* @return 发送后信息
*/
SendResult batchSend(List<String> mobileList, String sign, String templateCode,
String template, Map<String, String> templateParams);
}

View File

@@ -0,0 +1,241 @@
package cn.iocoder.mall.admin.client;
import cn.iocoder.common.framework.exception.ServiceException;
import cn.iocoder.mall.system.api.constant.AdminErrorCodeEnum;
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;
private static final String SUCCESS_MESSAGE = "SUCCESS";
/**
* 云片短信 - 批量推送最大数 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?:'default_value'}")
private String apiKey;
@Override
public SendResult singleSend(String mobile, String sign, String templateCode, String template, Map<String, String> templateParams) {
// build 模板
template = buildTemplate(sign, template, templateParams);
// 请求参数
Map<String, String> 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<String> mobileList, String sign,
String templateCode, String template,
Map<String, String> templateParams) {
// build 模板
template = buildTemplate(sign, template, templateParams);
// 最大发送数为 1000我们设置为 500 个, 分段发送
int maxSendSize = MAX_BATCH_SIZE;
int maxSendSizeCount = mobileList.size() % maxSendSize == 0
? mobileList.size() / maxSendSize
: mobileList.size() / maxSendSize + 1;
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<String, String> 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(SUCCESS_MESSAGE);
}
/**
* 构建模板
*
* @param sign
* @param template
* @param templateParams
* @return
*/
private static String buildTemplate(String sign, String template,
Map<String, String> templateParams) {
if (CollectionUtils.isEmpty(templateParams)) {
return template;
}
for (Map.Entry<String, String> entry : templateParams.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);
return template;
}
/**
* 基于HttpClient 4.3的通用POST方法
*
* @param url 提交的URL
* @param paramsMap 提交<参数,值>Map
* @return 提交响应
*/
public static String post(String url, Map<String, String> paramsMap) {
CloseableHttpClient client = HttpClients.createDefault();
String responseText = "";
CloseableHttpResponse response = null;
try {
HttpPost method = new HttpPost(url);
if (paramsMap != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (Map.Entry<String, String> 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;
}
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.mall.admin.convert;
import cn.iocoder.mall.system.api.bo.sms.PageSmsSignBO;
import cn.iocoder.mall.system.api.bo.sms.SmsSignBO;
import cn.iocoder.mall.admin.dataobject.SmsSignDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 短信 签名
*
* @author Sin
* @time 2019/5/16 6:31 PM
*/
@Mapper
public interface SmsSignConvert {
SmsSignConvert INSTANCE = Mappers.getMapper(SmsSignConvert.class);
@Mappings({})
SmsSignBO convert(SmsSignDO smsSignDO);
@Mappings({})
List<PageSmsSignBO.Sign> convert(List<SmsSignDO> smsSignDOList);
}

View File

@@ -0,0 +1,32 @@
package cn.iocoder.mall.admin.convert;
import cn.iocoder.mall.system.api.bo.sms.PageSmsTemplateBO;
import cn.iocoder.mall.system.api.bo.sms.SmsTemplateBO;
import cn.iocoder.mall.admin.dataobject.SmsSignDO;
import cn.iocoder.mall.admin.dataobject.SmsTemplateDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* 短信 template
*
* @author Sin
* @time 2019/5/16 7:43 PM
*/
@Mapper
public interface SmsTemplateConvert {
SmsTemplateConvert INSTANCE = Mappers.getMapper(SmsTemplateConvert.class);
@Mappings({})
SmsTemplateBO convert(SmsTemplateDO smsTemplateDO);
@Mappings({})
List<PageSmsTemplateBO.Template> convert(List<SmsTemplateDO> smsTemplateDOList);
@Mappings({})
List<PageSmsTemplateBO.Sign> convertTemplateSign(List<SmsSignDO> smsSignDOList);
}

View File

@@ -0,0 +1,15 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.SmsSendLogDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
/**
* 短信
*
* @author Sin
* @time 2019/5/16 6:18 PM
*/
@Repository
public interface SmsSendMapper extends BaseMapper<SmsSendLogDO> {
}

View File

@@ -0,0 +1,15 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.mall.admin.dataobject.SmsSignDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
/**
* 短信
*
* @author Sin
* @time 2019/5/16 6:18 PM
*/
@Repository
public interface SmsSignMapper extends BaseMapper<SmsSignDO> {
}

View File

@@ -0,0 +1,16 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.common.framework.dataobject.BaseDO;
import cn.iocoder.mall.admin.dataobject.SmsTemplateDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
/**
* 短信 template
*
* @author Sin
* @time 2019/5/16 6:18 PM
*/
@Repository
public interface SmsTemplateMapper extends BaseMapper<SmsTemplateDO> {
}

View File

@@ -0,0 +1,37 @@
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 SmsSendLogDO extends BaseDO {
/**
* 编号
*/
private Integer id;
/**
* 短信模板
*/
private Integer templateId;
/**
* 短信
*/
private String template;
/**
* 参数
*/
private String params;
/**
* 发送信息
*/
private String message;
}

View File

@@ -0,0 +1,48 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 短信签名
*
* 签名是短信发送前缀 如:【阿里云】、【小红书】
*
* @author Sin
* @time 2019/5/16 12:28 PM
*/
@Data
@Accessors(chain = true)
@TableName("sms_sign")
public class SmsSignDO extends DeletableDO {
/**
* 编号
*/
private Integer id;
/**
* 签名名称
*/
private String sign;
/**
* 平台
*
* 1、云片
* 2、阿里云
*/
private Integer platform;
/**
* 审核状态
*
* - 1、审核中
* - 2、审核成功
* - 10、审核失败
*/
private Integer applyStatus;
/**
* 审核信息
*/
private String applyMessage;
}

View File

@@ -0,0 +1,59 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 短信 模板
*
* @author Sin
* @time 2019/5/16 12:31 PM
*/
@Data
@Accessors(chain = true)
@TableName("sms_template")
public class SmsTemplateDO extends DeletableDO {
/**
* 编号
*/
private Integer id;
/**
* 模板编号 (第三方的)
*/
private Integer smsSignId;
/**
* 模板 code第三方平台 code
*/
private String templateCode;
/**
* 短信签名 id
*/
private Integer platform;
/**
* 短信模板
*/
private String template;
/**
* 短信类型
*
* - 验证码类
* - 通知类
* - 营销类
*/
private Integer smsType;
/**
* 审核状态
*
* 1、审核中
* 2、审核成功
* 10、审核失败
*/
private Integer applyStatus;
/**
* 审核信息
*/
private String applyMessage;
}

View File

@@ -0,0 +1,436 @@
package cn.iocoder.mall.admin.service;
import cn.iocoder.common.framework.enums.DeletedStatusEnum;
import cn.iocoder.common.framework.exception.ServiceException;
import cn.iocoder.mall.system.api.SmsService;
import cn.iocoder.mall.system.api.bo.sms.PageSmsSignBO;
import cn.iocoder.mall.system.api.bo.sms.PageSmsTemplateBO;
import cn.iocoder.mall.system.api.bo.sms.SmsSignBO;
import cn.iocoder.mall.system.api.bo.sms.SmsTemplateBO;
import cn.iocoder.mall.system.api.constant.AdminErrorCodeEnum;
import cn.iocoder.mall.system.api.constant.SmsApplyStatusEnum;
import cn.iocoder.mall.system.api.constant.SmsPlatformEnum;
import cn.iocoder.mall.system.api.dto.sms.PageQuerySmsSignDTO;
import cn.iocoder.mall.system.api.dto.sms.PageQuerySmsTemplateDTO;
import cn.iocoder.mall.admin.client.SmsClient;
import cn.iocoder.mall.admin.convert.SmsSignConvert;
import cn.iocoder.mall.admin.convert.SmsTemplateConvert;
import cn.iocoder.mall.admin.dao.SmsSendMapper;
import cn.iocoder.mall.admin.dao.SmsSignMapper;
import cn.iocoder.mall.admin.dao.SmsTemplateMapper;
import cn.iocoder.mall.admin.dataobject.SmsSendLogDO;
import cn.iocoder.mall.admin.dataobject.SmsSignDO;
import cn.iocoder.mall.admin.dataobject.SmsTemplateDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* 短信
*
* @author Sin
* @time 2019/5/16 10:30 AM
*/
@Service
@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.SmsService.version}")
public class SmsServiceImpl implements SmsService {
@Autowired
private SmsSignMapper smsSignMapper;
@Autowired
private SmsTemplateMapper smsTemplateMapper;
@Autowired
private SmsSendMapper smsSendMapper;
@Autowired
@Qualifier("smsYunPianClient")
private SmsClient smsYunPianClient;
@Autowired
@Qualifier("smsAliYunClient")
private SmsClient smsAliYunClient;
@Override
public PageSmsSignBO pageSmsSign(PageQuerySmsSignDTO queryDTO) {
QueryWrapper<SmsSignDO> queryWrapper = new QueryWrapper<>();
if (queryDTO.getApplyStatus() != null) {
queryWrapper.eq("apply_status", queryDTO.getApplyStatus());
}
if (!StringUtils.isEmpty(queryDTO.getSign())) {
queryWrapper.like("sign", queryDTO.getSign());
}
if (!StringUtils.isEmpty(queryDTO.getId())) {
queryWrapper.eq("id", queryDTO.getId());
}
Page<SmsSignDO> page = new Page<SmsSignDO>()
.setSize(queryDTO.getSize())
.setCurrent(queryDTO.getCurrent())
.setDesc("create_time");
IPage<SmsSignDO> signPage = smsSignMapper.selectPage(page, queryWrapper);
List<PageSmsSignBO.Sign> signList = SmsSignConvert.INSTANCE.convert(signPage.getRecords());
return new PageSmsSignBO()
.setData(signList)
.setCurrent(signPage.getCurrent())
.setSize(signPage.getSize())
.setTotal(signPage.getTotal());
}
@Override
public PageSmsTemplateBO pageSmsTemplate(PageQuerySmsTemplateDTO queryDTO) {
QueryWrapper<SmsTemplateDO> queryWrapper = new QueryWrapper<>();
if (queryDTO.getApplyStatus() != null) {
queryWrapper.eq("apply_status", queryDTO.getApplyStatus());
}
if (queryDTO.getSmsSignId() != null) {
queryWrapper.eq("sms_sign_id", queryDTO.getSmsSignId());
}
if (!StringUtils.isEmpty(queryDTO.getTemplate())) {
queryWrapper.like("template", queryDTO.getTemplate());
}
if (!StringUtils.isEmpty(queryDTO.getId())) {
queryWrapper.eq("id", queryDTO.getId());
}
Page<SmsTemplateDO> page = new Page<SmsTemplateDO>()
.setSize(queryDTO.getSize())
.setCurrent(queryDTO.getCurrent())
.setDesc("create_time");
IPage<SmsTemplateDO> signPage = smsTemplateMapper.selectPage(page, queryWrapper);
List<PageSmsTemplateBO.Template> templateList
= SmsTemplateConvert.INSTANCE.convert(signPage.getRecords());
if (CollectionUtils.isEmpty(templateList)) {
return new PageSmsTemplateBO()
.setData(Collections.EMPTY_LIST)
.setCurrent(signPage.getCurrent())
.setSize(signPage.getSize())
.setTotal(signPage.getTotal());
}
// 获取 sign
Set<Integer> smsSignIds = templateList.stream().map(
PageSmsTemplateBO.Template::getSmsSignId).collect(Collectors.toSet());
List<SmsSignDO> smsSignDOList = smsSignMapper.selectList(
new QueryWrapper<SmsSignDO>().in("id", smsSignIds));
List<PageSmsTemplateBO.Sign> signList = SmsTemplateConvert.INSTANCE.convertTemplateSign(smsSignDOList);
Map<Integer, PageSmsTemplateBO.Sign> smsSignDOMap = signList
.stream().collect(Collectors.toMap(PageSmsTemplateBO.Sign::getId, o -> o));
// 设置 sign
templateList.forEach(template -> {
if (smsSignDOMap.containsKey(template.getSmsSignId())) {
template.setSign(smsSignDOMap.get(template.getSmsSignId()));
}
});
return new PageSmsTemplateBO()
.setData(templateList)
.setCurrent(signPage.getCurrent())
.setSize(signPage.getSize())
.setTotal(signPage.getTotal());
}
@Override
@Transactional
public void addSign(String sign, Integer platform) {
// 避免重复
SmsSignDO smsSignDO = smsSignMapper.selectOne(
new QueryWrapper<SmsSignDO>()
.eq("platform", platform)
.eq("sign", sign)
);
if (smsSignDO != null) {
throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_IS_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_SIGN_IS_EXISTENT.getMessage());
}
// 保存数据库
smsSignMapper.insert(
(SmsSignDO) new SmsSignDO()
.setSign(sign)
.setPlatform(platform)
.setApplyStatus(SmsApplyStatusEnum.SUCCESS.getValue())
.setDeleted(DeletedStatusEnum.DELETED_NO.getValue())
.setUpdateTime(new Date())
.setCreateTime(new Date())
);
}
@Override
public SmsSignBO getSign(Integer signId) {
SmsSignDO smsSignDO = smsSignMapper.selectOne(
new QueryWrapper<SmsSignDO>()
.eq("id", signId)
.eq("deleted", DeletedStatusEnum.DELETED_NO.getValue()));
if (smsSignDO == null) {
throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage());
}
return SmsSignConvert.INSTANCE.convert(smsSignDO);
}
@Override
@Transactional
public void updateSign(Integer id, String newSign, Integer platform) {
// 避免重复
SmsSignDO smsSignDO = smsSignMapper.selectOne(
new QueryWrapper<SmsSignDO>()
.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<SmsSignDO>().eq("id", id)
);
}
@Override
public void deleteSign(Integer id) {
SmsSignDO smsSignDO = smsSignMapper.selectOne(
new QueryWrapper<SmsSignDO>()
.eq("id", id));
if (smsSignDO == null) {
throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage());
}
// 更新 deleted 为 YES
smsSignMapper.delete(new UpdateWrapper<SmsSignDO>()
.set("deleted", DeletedStatusEnum.DELETED_YES.getName())
.eq("id", id)
);
}
@Override
@Transactional
public void addTemplate(Integer smsSignId, String templateCode,
String template, Integer platform, Integer smsType) {
SmsSignDO smsSignDO = smsSignMapper.selectOne(
new QueryWrapper<SmsSignDO>().eq("id", smsSignId));
if (smsSignDO == null) {
throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage());
}
// 保存数据库
smsTemplateMapper.insert(
(SmsTemplateDO) new SmsTemplateDO()
.setId(null)
.setSmsSignId(smsSignId)
.setTemplateCode(templateCode)
.setTemplate(template)
.setPlatform(platform)
.setSmsType(smsType)
.setApplyStatus(SmsApplyStatusEnum.SUCCESS.getValue())
.setApplyMessage("")
.setDeleted(DeletedStatusEnum.DELETED_NO.getValue())
.setCreateTime(new Date())
);
}
@Override
public SmsTemplateBO getTemplate(Integer id, Integer platform) {
SmsTemplateDO smsTemplateDO = smsTemplateMapper.selectOne(
new QueryWrapper<SmsTemplateDO>()
.eq("platform", platform)
.eq("id", id));
if (smsTemplateDO == null) {
throw new ServiceException(AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getMessage());
}
return SmsTemplateConvert.INSTANCE.convert(smsTemplateDO);
}
@Override
@Transactional
public void updateTemplate(Integer id, Integer smsSignId, String templateCode,
String template, Integer platform, Integer smsType) {
SmsTemplateDO smsTemplateDO = smsTemplateMapper.selectOne(
new QueryWrapper<SmsTemplateDO>().eq("id", id));
if (smsTemplateDO == null) {
throw new ServiceException(AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getMessage());
}
SmsSignDO smsSignDO = smsSignMapper.selectOne(
new QueryWrapper<SmsSignDO>().eq("id", smsTemplateDO.getSmsSignId()));
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)
.setTemplateCode(templateCode)
.setTemplate(template)
.setPlatform(platform)
.setSmsType(smsType)
.setUpdateTime(new Date()),
new QueryWrapper<SmsTemplateDO>().eq("id", id)
);
}
@Override
@Transactional
public void deleteTemplate(Integer id) {
SmsTemplateDO smsTemplateDO = smsTemplateMapper.selectOne(
new QueryWrapper<SmsTemplateDO>().eq("id", id));
if (smsTemplateDO == null
|| smsTemplateDO.getDeleted().equals(DeletedStatusEnum.DELETED_YES.getValue())) {
throw new ServiceException(AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getMessage());
}
// 删除 数据库模板
SmsTemplateDO updateTemplate =new SmsTemplateDO();
updateTemplate.setDeleted(DeletedStatusEnum.DELETED_YES.getValue());
smsTemplateMapper.delete(
new UpdateWrapper<SmsTemplateDO>()
.set("deleted", DeletedStatusEnum.DELETED_YES)
.eq("id", id));
}
@Override
public void singleSend(String mobile, Integer smsTemplateId, Map<String, String> params) {
SmsTemplateDO smsTemplateDO = smsTemplateMapper.selectOne(
new QueryWrapper<SmsTemplateDO>().eq("id", smsTemplateId));
if (smsTemplateDO == null
|| smsTemplateDO.getDeleted().equals(DeletedStatusEnum.DELETED_YES.getValue())) {
throw new ServiceException(AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getMessage());
}
SmsSignDO smsSignDO = smsSignMapper.selectOne(
new QueryWrapper<SmsSignDO>().eq("id", smsTemplateDO.getSmsSignId()));
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.SendResult sendResult = smsClient.singleSend(mobile, smsSignDO.getSign(),
smsTemplateDO.getTemplateCode(), smsTemplateDO.getTemplate(), params);
// 添加日志
smsSendMapper.insert(
(SmsSendLogDO) new SmsSendLogDO()
.setTemplateId(smsTemplateDO.getId())
.setTemplate(smsTemplateDO.getTemplate())
.setMessage(sendResult.getMessage())
.setCreateTime(new Date())
);
}
@Override
public void batchSend(List<String> mobileList, Integer smsTemplateId, Map<String, String> params) {
SmsTemplateDO smsTemplateDO = smsTemplateMapper.selectOne(
new QueryWrapper<SmsTemplateDO>().eq("id", smsTemplateId));
if (smsTemplateDO == null
|| smsTemplateDO.getDeleted().equals(DeletedStatusEnum.DELETED_YES.getValue())) {
throw new ServiceException(AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_TEMPLATE_NOT_EXISTENT.getMessage());
}
SmsSignDO smsSignDO = smsSignMapper.selectOne(
new QueryWrapper<SmsSignDO>().eq("id", smsTemplateDO.getSmsSignId()));
if (smsSignDO == null) {
// 添加日志
smsSendMapper.insert(
(SmsSendLogDO) new SmsSendLogDO()
.setTemplateId(smsTemplateDO.getId())
.setTemplate(smsTemplateDO.getTemplate())
.setMessage("发送成功!")
.setCreateTime(new Date())
);
throw new ServiceException(AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getCode(),
AdminErrorCodeEnum.SMS_SIGN_NOT_EXISTENT.getMessage());
}
// 获取 client
SmsClient smsClient = getSmsClient(smsTemplateDO.getPlatform());
// 发送短信
SmsClient.SendResult sendResult = smsClient.batchSend(mobileList, smsSignDO.getSign(),
smsTemplateDO.getTemplateCode(), smsTemplateDO.getTemplate(), params);
// 添加日志
smsSendMapper.insert(
(SmsSendLogDO) new SmsSendLogDO()
.setTemplateId(smsTemplateDO.getId())
.setTemplate(smsTemplateDO.getTemplate())
.setMessage(sendResult.getMessage())
.setCreateTime(new Date())
);
}
/**
* 获取 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;
}
}

View File

@@ -0,0 +1,73 @@
spring:
# datasource
datasource:
url: jdbc:mysql://s1.iocoder.cn:3306/mall_admin?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 3WLiVUBEwTbvAfsh
# Spring Cloud 配置项
cloud:
nacos:
# Spring Cloud Nacos Discovery 配置项
discovery:
server-addr: s1.iocoder.cn:8848 # Nacos 服务器地址
# mybatis-plus
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
global-config:
db-config:
id-type: auto
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: cn.iocoder.mall.admin.dataobject
# sms
sms:
yunPian:
apiKey:
aliYun:
accessKeyId:
accessSecret:
# Dubbo 配置项
dubbo:
# Dubbo 注册中心
registry:
address: spring-cloud://s1.iocoder.cn:8848 # 指定 Dubbo 服务注册中心的地址
# Spring Cloud Alibaba Dubbo 专属配置
cloud:
subscribed-services: '' # 设置订阅的应用列表,默认为 * 订阅所有应用
# Dubbo 提供者的协议
protocol:
name: dubbo
port: -1
# Dubbo 提供服务的扫描基础包
scan:
base-packages: cn.iocoder.mall.admin.service
# Dubbo 服务提供者的配置
provider:
filter: -exception
AdminAccessLogService:
version: 1.0.0
AdminService:
version: 1.0.0
DataDictService:
version: 1.0.0
OAuth2Service:
version: 1.0.0
ResourceService:
version: 1.0.0
RoleService:
version: 1.0.0
SmsService:
version: 1.0.0
# logging
logging:
level:
# dao 开启 debug 模式 mybatis 输入 sql
cn.iocoder.mall.admin.dao: debug

View File

@@ -0,0 +1,20 @@
package cn.iocoder.mall.admin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 短信 application (test)
*
* @author Sin
* @time 2019/5/16 10:53 AM
*/
@SpringBootApplication(scanBasePackages = {"cn.iocoder.mall.admin"})
@EnableAsync(proxyTargetClass = true)
public class SystemApplicationTest {
public static void main(String[] args) {
SpringApplication.run(SystemApplicationTest.class);
}
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.mall.admin.client;
import cn.iocoder.mall.admin.SystemApplicationTest;
import com.google.common.collect.ImmutableMap;
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;
/**
* 阿里云 短信 test
*
* @author Sin
* @time 2019/5/26 10:08 AM
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SystemApplicationTest.class)
public class SmsAliYunClientTest {
@Autowired
private SmsAliYunClient smsAliYunClient;
@Test
public void singleSendTest() {
String sign = "阿里云短信测试专用";
String mobile = "13302926050";
String templateCode = "SMS_137110043";
String template = "验证码#code#,您正在进行身份验证,打死不要告诉别人哦!";
smsAliYunClient.singleSend(mobile, sign, templateCode,
template, ImmutableMap.of("code", "8888"));
}
}

View File

@@ -0,0 +1,48 @@
package cn.iocoder.mall.admin.client;
import cn.iocoder.mall.admin.SystemApplicationTest;
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;
/**
* 短信 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, null,
template, ImmutableMap.of("code", "1111"));
}
@Test
public void batchSendTest() {
String mobile = "13302926050";
String template = "您的验证码是#code#,打死也不告诉别人哦。";
smsYunPianClient.batchSend(Lists.newArrayList(mobile), sign, null,
template, ImmutableMap.of("code", "2222"));
}
}

View File

@@ -0,0 +1,87 @@
package cn.iocoder.mall.admin.service;
import cn.iocoder.common.framework.exception.ServiceException;
import cn.iocoder.mall.admin.SystemApplicationTest;
import cn.iocoder.mall.system.api.SmsService;
import cn.iocoder.mall.system.api.bo.sms.SmsSignBO;
import cn.iocoder.mall.system.api.constant.SmsPlatformEnum;
import cn.iocoder.mall.system.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;
import org.springframework.test.context.junit4.SpringRunner;
/**
* 短信 test
*
* @author Sin
* @time 2019/5/16 10:52 AM
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SystemApplicationTest.class)
public class SmsServiceImplTest {
@Autowired
private SmsService smsService;
@Test
public void createSignTest() {
// smsService.addSign("悦跑运动", SmsPlatformEnum.YunPian.getValue());
smsService.addSign("登录确认验证码", SmsPlatformEnum.AliYun.getValue());
}
@Test
public void getSignTest() {
SmsSignBO smsSignBO = smsService.getSign(3);
Assert.assertNotNull("不能为空!", smsSignBO);
}
@Test
public void updateSignTest() {
String oldSign = "悦跑运动2";
String newSign = "悦跑运动";
smsService.updateSign(3, newSign, SmsPlatformEnum.YunPian.getValue());
SmsSignBO smsSignBO = smsService.getSign(3);
Assert.assertTrue("更新不成功!", smsSignBO.getSign().equals(newSign));
}
@Test
public void deletedSignTest() {
smsService.deleteSign(3);
Assertions.assertThrows(ServiceException.class, () -> {
smsService.getSign(3);
});
}
@Test
public void createTemplateTest() {
Integer sign = 4;
String templateCode = "SMS_137110043";
String template = "验证码#code#,您正在登录,若非本人操作,请勿泄露。";
smsService.addTemplate(
sign,
templateCode,
template,
SmsPlatformEnum.AliYun.getValue(),
SmsTypeEnum.VERIFICATION_CODE.getValue());
}
@Test
public void singleSendTest() {
String mobile = "13302926050";
Integer templateId = 7;
smsService.singleSend(mobile, templateId, ImmutableMap.of("code", "8888"));
}
@Test
public void batchSendTest() {
String mobile = "13302926050";
Integer templateId = 7;
smsService.batchSend(Lists.newArrayList(mobile), templateId, ImmutableMap.of("code", "8888"));
}
}

View File

@@ -0,0 +1,35 @@
package cn.iocoder.mall.admin.service;
import cn.iocoder.mall.system.api.SystemLogService;
import cn.iocoder.mall.system.api.bo.systemlog.AccessLogPageBO;
import cn.iocoder.mall.system.api.dto.systemlog.AccessLogPageDTO;
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;
/**
* @author:ycjx
* @descriptio
* @create:2019-06-23 18:08
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SystemLogServiceImplTest.class)
public class SystemLogServiceImplTest {
@Autowired
private SystemLogService systemLogService;
@Test
public void getAccessLogPageTest(){
AccessLogPageDTO accessLogPageDTO = new AccessLogPageDTO();
accessLogPageDTO.setPageNo(1);
accessLogPageDTO.setPageSize(10);
AccessLogPageBO accessLogPage = systemLogService.getAccessLogPage(accessLogPageDTO);
System.out.println(accessLogPage.getTotal());
}
}