Commit 7f4f3d7c by fengshuonan

更新邮件和短信发送

parent 554f4d22
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.stylefeng</groupId>
<artifactId>guns-vip</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>guns-base-email</artifactId>
<packaging>jar</packaging>
<dependencies>
<!--基础组件-->
<dependency>
<groupId>cn.stylefeng</groupId>
<artifactId>guns-base</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
package cn.stylefeng.guns.email.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.stylefeng.guns.email.provider.MailServiceProvider;
/**
* 邮件服务的配置
*
* @author fengshuonan
* @Date 2018/7/6 下午3:24
*/
@Configuration
public class ServiceAutoConfiguration {
@Bean
public MailServiceProvider mailServiceProvider() {
return new MailServiceProvider();
}
}
\ No newline at end of file
package cn.stylefeng.guns.email.core.enums;
import cn.stylefeng.roses.kernel.model.exception.AbstractBaseExceptionEnum;
/**
* 邮件发送失败的异常枚举
*
* @author stylefeng
* @Date 2018年07月08日18:39:47
*/
public enum MailSendResultEnum implements AbstractBaseExceptionEnum {
MAIL_SEND_ERROR(500, "邮件发送失败");
MailSendResultEnum(int code, String message) {
this.code = code;
this.message = message;
}
private Integer code;
private String message;
@Override
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
package cn.stylefeng.guns.email.core.exception;
/**
* 邮件发送异常
*
* @author fengshuonan
* @date 2018-07-06-下午3:00
*/
public class MailException extends RuntimeException {
private String code;
private String errorMessage;
public MailException(String code, String errorMessage) {
super(errorMessage);
this.code = code;
this.errorMessage = errorMessage;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
package cn.stylefeng.guns.email.core.mail;
import cn.stylefeng.guns.email.core.model.SendMailParam;
/**
* 邮件收发统一接口
*
* @author fengshuonan
* @date 2018-07-08-下午3:26
*/
public interface MailManager {
/**
* 发送普通邮件
*
* @author fengshuonan
* @Date 2018/7/8 下午3:34
*/
void sendMail(SendMailParam sendMailParam);
}
package cn.stylefeng.guns.email.core.mail.service;
import cn.stylefeng.guns.email.core.enums.MailSendResultEnum;
import cn.stylefeng.guns.email.core.mail.MailManager;
import cn.stylefeng.guns.email.core.model.SendMailParam;
import cn.stylefeng.roses.kernel.model.exception.RequestEmptyException;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import cn.stylefeng.roses.kernel.model.util.ValidateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
/**
* java默认的邮件发送方式实现
*
* @author fengshuonan
* @date 2018-07-08-下午3:34
*/
@Service
@Slf4j
public class JavaMailManager implements MailManager {
@Autowired
private JavaMailSender javaMailSender;
@Value("${mail.from}")
private String from;
@Override
public void sendMail(SendMailParam sendMailParam) {
//校验发送邮件的参数
assertSendMailParams(sendMailParam);
log.info("参数校验成功。。。。");
//spring发送邮件
try {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
mimeMessageHelper.setFrom(from);
mimeMessageHelper.setTo(sendMailParam.getTo());
mimeMessageHelper.setSubject(sendMailParam.getTitle());
mimeMessageHelper.setText(sendMailParam.getContent(), true);
javaMailSender.send(mimeMessage);
} catch (MessagingException e) {
log.error("发送邮件异常", e);
throw new ServiceException(MailSendResultEnum.MAIL_SEND_ERROR);
}
}
/**
* 校验发送邮件的请求参数
*
* @author fengshuonan
* @Date 2018/7/8 下午6:41
*/
private void assertSendMailParams(SendMailParam sendMailParam) {
if (sendMailParam == null ||
ValidateUtil.isOneEmpty(
sendMailParam.getTo(), sendMailParam.getTitle(), sendMailParam.getContent())) {
throw new RequestEmptyException();
}
}
}
package cn.stylefeng.guns.email.core.model;
import lombok.Data;
/**
* 发送邮件的请求参数
*
* @author fengshuonan
* @date 2018-07-05 21:19
*/
@Data
public class SendMailParam {
/**
* 发送给某人的邮箱
*/
private String to;
/**
* 邮件标题
*/
private String title;
/**
* 邮件内容(经过base64编码后的)
*/
private String content;
}
package cn.stylefeng.guns.email.provider;
import cn.stylefeng.guns.email.core.model.SendMailParam;
/**
* 邮件发送的api
*
* @author fengshuonan
* @date 2018-07-08-下午3:47
*/
public interface MailServiceApi {
/**
* 发送邮件
*
* @author fengshuonan
* @Date 2018/7/8 下午6:28
*/
void sendMail(SendMailParam sendMailParam);
}
package cn.stylefeng.guns.email.provider;
import cn.stylefeng.guns.email.core.mail.MailManager;
import cn.stylefeng.guns.email.core.model.SendMailParam;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 短信通知接口
*
* @author stylefeng
* @Date 2018/7/5 21:05
*/
public class MailServiceProvider implements MailServiceApi {
private static Logger logger = LoggerFactory.getLogger(MailServiceProvider.class);
@Autowired
private MailManager mailManager;
@Override
public void sendMail(SendMailParam sendMailParam) {
logger.info("email调用入参:" + JSONObject.toJSON(sendMailParam).toString());
mailManager.sendMail(sendMailParam);
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.stylefeng.guns.email.config.ServiceAutoConfiguration
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.stylefeng</groupId>
<artifactId>guns-vip</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>guns-base-sms</artifactId>
<packaging>jar</packaging>
<dependencies>
<!--基础组件-->
<dependency>
<groupId>cn.stylefeng</groupId>
<artifactId>guns-base</artifactId>
<version>1.0.0</version>
</dependency>
<!--短信发送的sdk-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.7.1</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
</build>
</project>
package cn.stylefeng.guns.sms.config;
import cn.stylefeng.guns.sms.core.db.SmsInfoInitizlizer;
import cn.stylefeng.guns.sms.core.sms.SmsManager;
import cn.stylefeng.guns.sms.core.sms.service.AliyunSmsManager;
import cn.stylefeng.guns.sms.modular.provider.SmsServiceProvider;
import cn.stylefeng.guns.sms.modular.service.SmsInfoService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 短信服务的配置
*
* @author fengshuonan
* @Date 2018/7/6 下午3:24
*/
@Configuration
public class ServiceAutoConfiguration {
@Bean
public SmsServiceProvider smsServiceProvider() {
return new SmsServiceProvider();
}
@Bean
public SmsInfoService smsInfoService() {
return new SmsInfoService();
}
@Bean
public SmsManager smsManager() {
return new AliyunSmsManager();
}
@Bean
public SmsInfoInitizlizer smsInfoInitizlizer() {
return new SmsInfoInitizlizer();
}
}
\ No newline at end of file
package cn.stylefeng.guns.sms.config;
import cn.stylefeng.guns.sms.config.properties.AliyunSmsProperties;
import cn.stylefeng.guns.sms.core.cache.impl.MapSignManager;
import cn.stylefeng.guns.sms.core.sms.service.AliyunSmsManager;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* aliyun短信发送的配置
*
* @author fengshuonan
* @Date 2018/7/6 下午3:24
*/
@Configuration
public class SmsAutoConfiguration {
/**
* 阿里云短信发送的配置
*
* @author fengshuonan
* @Date 2018/7/6 下午3:24
*/
@Bean
@ConfigurationProperties(prefix = "aliyun.sms")
public AliyunSmsProperties aliyunSmsProperties() {
return new AliyunSmsProperties();
}
/**
* 短信发送管理器
*
* @author fengshuonan
* @Date 2018/9/21 上午10:07
*/
@Bean
public AliyunSmsManager aliyunSmsManager() {
return new AliyunSmsManager();
}
/**
* 缓存的管理
*
* @author fengshuonan
* @Date 2018/9/21 上午10:59
*/
@Bean
public MapSignManager mapSignManager() {
return new MapSignManager();
}
}
\ No newline at end of file
package cn.stylefeng.guns.sms.config.properties;
import lombok.Data;
/**
* oss相关配置
*
* @author fengshuonan
* @date 2018-06-27-下午1:20
*/
@Data
public class AliyunSmsProperties {
/**
* accessKeyId
*/
private String accessKeyId;
/**
* accessKeySecret
*/
private String accessKeySecret;
/**
* 签名名称
*/
private String signName;
/**
* 登录验证码的模板
*/
private String loginTemplateCode;
/**
* 短信失效时间(分钟)
*/
private Integer invalidateMinutes = 2;
}
package cn.stylefeng.guns.sms.core.cache;
/**
* 多个签名的缓存管理
*
* @author fengshuonan
* @date 2018-09-21-上午10:47
*/
public interface MultiSignManager {
/**
* 获取签名
*
* @param phone 电话
* @param signName 发送短信用的签名,是一个以逗号隔开的字符串
* @author fengshuonan
* @Date 2018/9/21 上午10:51
*/
String getSign(String phone, String signName);
}
package cn.stylefeng.guns.sms.core.cache.impl;
import cn.stylefeng.guns.sms.core.cache.MultiSignManager;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 使用map缓存的实现
*
* @author fengshuonan
* @date 2018-09-21-上午10:49
*/
@Slf4j
public class MapSignManager implements MultiSignManager {
private static final Long EXPIRED_TIME = 86400L;
private Map<String, String> cacheMap = new ConcurrentHashMap<>();
@Override
public String getSign(String phone, String signName) {
clearMap();
String[] signNames = signName.split(",");
//获取上次发送的时候用的哪个签名,这次换一个
Object lastSignName = cacheMap.get(phone);
if (lastSignName == null) {
cacheMap.put(phone, signNames[0]);
log.info("发送短信,签名为:" + signNames[0] + ",电话为:" + phone);
return signNames[0];
} else {
for (String name : signNames) {
if (!name.equals(lastSignName)) {
cacheMap.put(phone, name);
log.info("发送短信,签名为:" + name + ",电话为:" + phone);
return name;
}
}
cacheMap.put(phone, signNames[0]);
log.info("发送短信,签名为:" + signNames[0] + ",电话为:" + phone);
return signNames[0];
}
}
/**
* 每隔一段时间清除下map
*
* @author fengshuonan
* @Date 2018/9/21 上午10:57
*/
private void clearMap() {
if (cacheMap.size() >= 1000) {
cacheMap.clear();
}
}
}
package cn.stylefeng.guns.sms.core.db;
import cn.stylefeng.guns.sms.modular.entity.SmsInfo;
import cn.stylefeng.roses.core.db.DbInitializer;
/**
* 短信发送表的初始化程序
*
* @author fengshuonan
* @date 2018-07-30-上午9:29
*/
public class SmsInfoInitizlizer extends DbInitializer {
@Override
public String getTableInitSql() {
return "CREATE TABLE `sms_info` (\n" +
" `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',\n" +
" `PHONE_NUMBERS` varchar(200) COLLATE utf8_bin NOT NULL COMMENT '手机号',\n" +
" `VALIDATE_CODE` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '短信验证码',\n" +
" `TEMPLATE_CODE` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '短信模板ID',\n" +
" `BIZID` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '回执ID,可根据该ID查询具体的发送状态',\n" +
" `STATUS` smallint(3) NOT NULL COMMENT '0=未发送,1=发送成功,2=发送失败,3=失效',\n" +
" `SOURCE` smallint(3) NOT NULL COMMENT '0=app,1=pc,2=其它',\n" +
" `INVALID_TIME` timestamp NULL DEFAULT NULL COMMENT '失效时间',\n" +
" `MODIFY_TIME` timestamp NULL DEFAULT NULL COMMENT '修改时间',\n" +
" `CREATE_TIME` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n" +
" PRIMARY KEY (`ID`)\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='短信信息发送表'";
}
@Override
public String getTableName() {
return "sms_info";
}
@Override
public Class<?> getEntityClass() {
return SmsInfo.class;
}
}
package cn.stylefeng.guns.sms.core.enums;
/**
* 消息类型
*
* @author stylefeng
* @Date 2018年5月6日 12:30:48
*/
public enum MessageType {
SMS(1, "验证类消息"),
MESSAGE(2, "纯发送消息");
private Integer code;
private String desc;
MessageType(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package cn.stylefeng.guns.sms.core.enums;
/**
* core模块的异常集合
*
* @author stylefeng
* @Date 2018/1/4 22:40
*/
public enum SmsResultEnum {
INIT_SMS_CLIENT_ERROR("SMS_CLIENT_INIT_ERROR", "初始化sms客户端错误,accessKey错误"),
PARAM_NULL("NULL", "请求参数为空"),
OK("OK", "请求成功"),
RAM_PERMISSION_DENY("isp.RAM_PERMISSION_DENY", "RAM权限DENY"),
PRODUCT_UNSUBSCRIBE("isv.PRODUCT_UNSUBSCRIBE", "产品未开通"),
ACCOUNT_NOT_EXISTS("isv.ACCOUNT_NOT_EXISTS", "账户不存在"),
ACCOUNT_ABNORMAL("isv.ACCOUNT_ABNORMAL", "账户异常"),
SMS_TEMPLATE_ILLEGAL("isv.SMS_TEMPLATE_ILLEGAL", "短信模板不合法"),
SMS_SIGNATURE_ILLEGAL("isv.SMS_SIGNATURE_ILLEGAL", "短信签名不合法"),
INVALID_PARAMETERS("isv.INVALID_PARAMETERS", "参数异常"),
SYSTEM_ERROR("isp.SYSTEM_ERROR", "系统错误"),
MOBILE_NUMBER_ILLEGAL("isv.MOBILE_NUMBER_ILLEGAL", "非法手机号"),
MOBILE_COUNT_OVER_LIMIT("isv.MOBILE_COUNT_OVER_LIMIT", "手机号码数量超过限制"),
TEMPLATE_MISSING_PARAMETERS("isv.TEMPLATE_MISSING_PARAMETERS", "模板缺少变量"),
BUSINESS_LIMIT_CONTROL("isv.BUSINESS_LIMIT_CONTROL", "发送短信过于频繁,请稍后再试"),
INVALID_JSON_PARAM("isv.INVALID_JSON_PARAM", "JSON参数不合法,只接受字符串值"),
BLACK_KEY_CONTROL_LIMIT("isv.BLACK_KEY_CONTROL_LIMIT", "黑名单管控"),
PARAM_LENGTH_LIMIT("isv.PARAM_LENGTH_LIMIT", "参数超出长度限制"),
PARAM_NOT_SUPPORT_URL("isv.PARAM_NOT_SUPPORT_URL", "不支持URL"),
AMOUNT_NOT_ENOUGH("isv.AMOUNT_NOT_ENOUGH", "账户余额不足");
SmsResultEnum(String code, String message) {
this.code = code;
this.message = message;
}
private String code;
private String message;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
package cn.stylefeng.guns.sms.core.enums;
/**
* 短信发送业务枚举
*
* @author stylefeng
* @Date 2018年5月6日 12:30:48
*/
public enum SmsSendSource {
WEB(0),
PC(1),
OTHER(2);
private Integer code;
SmsSendSource(Integer code) {
this.code = code;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public static SmsSendSource toEnum(Integer type) {
if (type == null) {
return null;
} else {
for (SmsSendSource item : SmsSendSource.values()) {
if (item.getCode().equals(type)) {
return item;
}
}
return null;
}
}
}
package cn.stylefeng.guns.sms.core.enums;
/**
* 短信发送状态枚举
*
* @author stylefeng
* @Date 2018年5月6日 12:30:48
*/
public enum SmsSendStatus {
WAITING(0, "未发送"),
SUCCESS(1, "发送成功"),
INVALID(3, "失效"),
FAILED(2, "发送失败");
private Integer code;
private String desc;
SmsSendStatus(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package cn.stylefeng.guns.sms.core.enums;
/**
* 短信验证结果
*
* @author stylefeng
* @Date 2018年5月6日 12:30:48
*/
public enum SmsVerifyResult {
SUCCESS(10, "验证成功"),
ERROR(20, "验证码错误"),
EXPIRED(30, "验证码超时"),
TIMES_UP(40, "超过验证次数");
private Integer code;
private String desc;
SmsVerifyResult(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
package cn.stylefeng.guns.sms.core.exception;
/**
* 短信发送异常
*
* @author fengshuonan
* @date 2018-07-06-下午3:00
*/
public class SmsException extends RuntimeException {
private String code;
private String errorMessage;
public SmsException(String code, String errorMessage) {
super(errorMessage);
this.code = code;
this.errorMessage = errorMessage;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
package cn.stylefeng.guns.sms.core.sms;
import cn.stylefeng.guns.sms.modular.model.SmsSendRecord;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 短信发送服务
*
* @author fengshuonan
* @date 2018-07-06-下午2:14
*/
public interface SmsManager {
/**
* 发送短信
*
* @param phoneNumber 电话号码
* @param templateCode 模板号码
* @param params 模板里参数的集合
* @author fengshuonan
* @Date 2018/7/6 下午2:32
*/
void sendSms(String phoneNumber, String templateCode, Map<String, Object> params);
/**
* 获取某个手机号已发送短信列表
*
* @param phoneNumber 手机号码
* @param sendDate 发送日期
* @param pageNo 分页(第几页)不传递返回第一页,默认分页大小50
* @author fengshuonan
* @Date 2018/7/6 下午3:54
*/
List<SmsSendRecord> getAlreadySendList(String phoneNumber, Date sendDate, Integer pageNo);
}
package cn.stylefeng.guns.sms.modular.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 短信信息表
* </p>
*
* @author fengshuonan
* @since 2018-07-05
*/
@TableName("sms_info")
public class SmsInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "ID", type = IdType.AUTO)
private Integer id;
/**
* 手机号
*/
@TableField("PHONE_NUMBERS")
private String phoneNumbers;
/**
* 短信验证码
*/
@TableField("VALIDATE_CODE")
private String validateCode;
/**
* 短信模板ID
*/
@TableField("TEMPLATE_CODE")
private String templateCode;
/**
* 回执ID,可根据该ID查询具体的发送状态
*/
@TableField("BIZID")
private String bizid;
/**
* 0=未发送,1=发送成功,2=发送失败
*/
@TableField("STATUS")
private Integer status;
/**
* 0=app,1=pc,2=其它
*/
@TableField("SOURCE")
private Integer source;
/**
* 失效时间
*/
@TableField("INVALID_TIME")
private Date invalidTime;
/**
* 修改时间
*/
@TableField("MODIFY_TIME")
private Date modifyTime;
/**
* 创建时间
*/
@TableField("CREATE_TIME")
private Date createTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(String phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
public String getValidateCode() {
return validateCode;
}
public void setValidateCode(String validateCode) {
this.validateCode = validateCode;
}
public String getTemplateCode() {
return templateCode;
}
public void setTemplateCode(String templateCode) {
this.templateCode = templateCode;
}
public String getBizid() {
return bizid;
}
public void setBizid(String bizid) {
this.bizid = bizid;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Integer getSource() {
return source;
}
public void setSource(Integer source) {
this.source = source;
}
public Date getInvalidTime() {
return invalidTime;
}
public void setInvalidTime(Date invalidTime) {
this.invalidTime = invalidTime;
}
public Date getModifyTime() {
return modifyTime;
}
public void setModifyTime(Date modifyTime) {
this.modifyTime = modifyTime;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "TcSmsInfo{" +
"id=" + id +
", phoneNumbers=" + phoneNumbers +
", validateCode=" + validateCode +
", templateCode=" + templateCode +
", bizid=" + bizid +
", status=" + status +
", source=" + source +
", invalidTime=" + invalidTime +
", modifyTime=" + modifyTime +
", createTime=" + createTime +
"}";
}
}
package cn.stylefeng.guns.sms.modular.mapper;
import cn.stylefeng.guns.sms.modular.entity.SmsInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 短信信息表 Mapper 接口
* </p>
*
* @author fengshuonan
* @since 2018-07-05
*/
public interface SmsInfoMapper extends BaseMapper<SmsInfo> {
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.stylefeng.guns.sms.modular.mapper.SmsInfoMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.stylefeng.guns.sms.modular.entity.SmsInfo">
<id column="ID" property="id"/>
<result column="PHONE_NUMBERS" property="phoneNumbers"/>
<result column="VALIDATE_CODE" property="validateCode"/>
<result column="TEMPLATE_CODE" property="templateCode"/>
<result column="BIZID" property="bizid"/>
<result column="STATUS" property="status"/>
<result column="SOURCE" property="source"/>
<result column="INVALID_TIME" property="invalidTime"/>
<result column="MODIFY_TIME" property="modifyTime"/>
<result column="CREATE_TIME" property="createTime"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
ID as id, PHONE_NUMBERS AS phoneNumbers, VALIDATE_CODE AS validateCode, TEMPLATE_CODE AS templateCode, BIZID as bizid, STATUS as status, SOURCE as source, INVALID_TIME AS invalidTime, MODIFY_TIME AS modifyTime, CREATE_TIME AS createTime
</sql>
</mapper>
package cn.stylefeng.guns.sms.modular.model;
import cn.stylefeng.guns.sms.core.enums.MessageType;
import cn.stylefeng.guns.sms.core.enums.SmsSendSource;
import lombok.Data;
import java.util.Map;
/**
* 发送短信的参数
*
* @author fengshuonan
* @date 2018-07-05 21:19
*/
@Data
public class SendMessageParam {
/**
* 手机号
*/
private String phoneNumbers;
/**
* 模板号
*/
private String templateCode;
/**
* 模板中的参数
*/
private Map<String, Object> params;
/**
* sms发送源
*/
private SmsSendSource smsSendSource = SmsSendSource.PC;
/**
* 消息类型,1=验证码,2=消息,默认不传为验证码
*/
private MessageType messageType = MessageType.SMS;
}
package cn.stylefeng.guns.sms.modular.model;
import lombok.Data;
/**
* 消息发送记录
*
* @author fengshuonan
* @date 2018-07-06-下午4:07
*/
@Data
public class SmsSendRecord {
/**
* 手机号码
*/
private String phoneNum;
/**
* 发送状态 1:等待回执,2:发送失败,3:发送成功
*/
private Long sendStatus;
/**
* 运营商短信错误码
*/
private String errCode;
/**
* 模板ID
*/
private String templateCode;
/**
* 短信内容
*/
private String content;
/**
* 发送时间
*/
private String sendDate;
/**
* 接收时间
*/
private String receiveDate;
/**
* 外部流水扩展字段
*/
private String outId;
}
package cn.stylefeng.guns.sms.modular.model;
import cn.stylefeng.guns.sms.core.enums.SmsSendSource;
import lombok.Data;
/**
* 发送短信的参数
*
* @author fengshuonan
* @date 2018-07-05 21:19
*/
@Data
public class VerifySMSParam {
/**
* 手机号
*/
private String phoneNumbers;
/**
* 验证码
*/
private String code;
/**
* 模板号
*/
private String templateCode;
/**
* 来源
*/
private SmsSendSource smsSendSource;
}
package cn.stylefeng.guns.sms.modular.provider;
import cn.stylefeng.guns.sms.core.enums.SmsSendStatus;
import cn.stylefeng.guns.sms.core.enums.SmsVerifyResult;
import cn.stylefeng.guns.sms.modular.model.SendMessageParam;
import cn.stylefeng.guns.sms.modular.model.VerifySMSParam;
/**
* 短信通知接口
*
* @author stylefeng
* @Date 2018/7/5 21:05
*/
public interface SmsServiceApi {
/**
* 发送短信
*
* @author fengshuonan
* @Date 2018/7/6 下午4:32
*/
Boolean sendShortMessage(SendMessageParam sendMessageParam);
/**
* 验证短信
*
* @author fengshuonan
* @Date 2018/7/6 下午4:30
*/
SmsVerifyResult verifyShortMessage(VerifySMSParam verifySMSParam);
/**
* <pre>
* 查看短信发送状态
*
* 0=未发送,1=发送成功,2=发送失败
* </pre>
*
* @author fengshuonan
* @Date 2018/7/6 下午4:32
*/
SmsSendStatus getMessageSendStatus(Integer smsId);
}
package cn.stylefeng.guns.sms.modular.provider;
import cn.hutool.core.util.RandomUtil;
import cn.stylefeng.guns.sms.core.enums.MessageType;
import cn.stylefeng.guns.sms.core.enums.SmsSendStatus;
import cn.stylefeng.guns.sms.core.enums.SmsVerifyResult;
import cn.stylefeng.guns.sms.core.sms.SmsManager;
import cn.stylefeng.guns.sms.modular.model.SendMessageParam;
import cn.stylefeng.guns.sms.modular.model.VerifySMSParam;
import cn.stylefeng.guns.sms.modular.service.SmsInfoService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
/**
* 短信通知接口
*
* @author stylefeng
* @Date 2018/7/5 21:05
*/
@Slf4j
public class SmsServiceProvider implements SmsServiceApi {
@Autowired
private SmsManager smsManager;
@Autowired
private SmsInfoService smsInfoService;
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean sendShortMessage(SendMessageParam sendMessageParam) {
Map<String, Object> params = sendMessageParam.getParams();
log.info("发送短信Provider接口,参数为:" + JSON.toJSONString(sendMessageParam));
//如果是纯消息发送
if (MessageType.MESSAGE.equals(sendMessageParam.getMessageType())) {
smsManager.sendSms(sendMessageParam.getPhoneNumbers(), sendMessageParam.getTemplateCode(), params);
log.info("发送短信Provider接口--message,params的map具体为:" + JSON.toJSONString(params));
} else {
//初始化短信发送参数
String validateCode = null;
//如果传的参数中没有code,就初始化一个code放到参数map里
if (params != null && params.get("code") != null) {
validateCode = params.get("code").toString();
} else {
validateCode = RandomUtil.randomNumbers(6);
if (params == null) {
params = new HashMap<>();
}
params.put("code", validateCode);
}
log.info("发送短信Provider接口,params的map具体为:" + JSON.toJSONString(params));
log.info("发送短信Provider接口,验证码为:" + validateCode);
//存储短信到数据库
Integer keyId = smsInfoService.saveSmsInfo(sendMessageParam, validateCode);
log.info("开始发送短信:发送的电话号码= " + sendMessageParam.getPhoneNumbers() + ",发送的模板号=" + sendMessageParam.getTemplateCode() + ",发送的参数是:" + JSON.toJSONString(params));
//发送短信
smsManager.sendSms(sendMessageParam.getPhoneNumbers(), sendMessageParam.getTemplateCode(), params);
//更新短信发送状态
smsInfoService.updateSmsInfo(keyId, SmsSendStatus.SUCCESS);
}
return true;
}
@Override
public SmsVerifyResult verifyShortMessage(VerifySMSParam verifySMSParam) {
log.info("验证短信Provider接口,参数为:" + JSON.toJSONString(verifySMSParam));
SmsVerifyResult smsVerifyResult = smsInfoService.validateSmsInfo(verifySMSParam);
log.info("验证短信Provider接口,响应结果为:" + JSON.toJSONString(smsVerifyResult));
return smsVerifyResult;
//return SmsVerifyResult.SUCCESS;
}
@Override
public SmsSendStatus getMessageSendStatus(Integer smsId) {
return null;
}
}
package cn.stylefeng.guns.sms.modular.service;
import cn.stylefeng.guns.sms.config.properties.AliyunSmsProperties;
import cn.stylefeng.guns.sms.core.enums.SmsResultEnum;
import cn.stylefeng.guns.sms.core.enums.SmsSendStatus;
import cn.stylefeng.guns.sms.core.enums.SmsVerifyResult;
import cn.stylefeng.guns.sms.core.exception.SmsException;
import cn.stylefeng.guns.sms.modular.entity.SmsInfo;
import cn.stylefeng.guns.sms.modular.mapper.SmsInfoMapper;
import cn.stylefeng.guns.sms.modular.model.SendMessageParam;
import cn.stylefeng.guns.sms.modular.model.VerifySMSParam;
import cn.stylefeng.roses.kernel.model.util.ValidateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
/**
* <p>
* 短信信息表 服务实现类
* </p>
*
* @author fengshuonan
* @since 2018-07-05
*/
@Slf4j
public class SmsInfoService extends ServiceImpl<SmsInfoMapper, SmsInfo> {
@Autowired
private AliyunSmsProperties aliyunSmsProperties;
/**
* 存储短信验证信息
*
* @author fengshuonan
* @Date 2018/7/6 下午4:47
*/
public Integer saveSmsInfo(SendMessageParam sendMessageParam, String validateCode) {
if (ValidateUtil.isOneEmpty(sendMessageParam.getPhoneNumbers(), validateCode, sendMessageParam.getTemplateCode())) {
log.error("存储短信到数据库失败!有参数为空!");
throw new SmsException(SmsResultEnum.PARAM_NULL.getCode(), SmsResultEnum.PARAM_NULL.getMessage());
}
//当前时间
Date nowDate = new Date();
//短信失效时间
long invalidateTime = nowDate.getTime() + aliyunSmsProperties.getInvalidateMinutes() * 60 * 1000;
Date invalidate = new Date(invalidateTime);
SmsInfo smsInfo = new SmsInfo();
smsInfo.setCreateTime(nowDate);
smsInfo.setInvalidTime(invalidate);
smsInfo.setPhoneNumbers(sendMessageParam.getPhoneNumbers());
smsInfo.setStatus(SmsSendStatus.WAITING.getCode());
smsInfo.setSource(sendMessageParam.getSmsSendSource().getCode());
smsInfo.setTemplateCode(sendMessageParam.getTemplateCode());
smsInfo.setValidateCode(validateCode);
this.save(smsInfo);
log.info("发送短信,存储短信到数据库,数据为:" + JSON.toJSONString(smsInfo));
return smsInfo.getId();
}
/**
* 更新短息发送状态
*
* @author fengshuonan
* @Date 2018/7/6 下午5:12
*/
public void updateSmsInfo(Integer keyId, SmsSendStatus smsSendStatus) {
SmsInfo smsInfo = this.getById(keyId);
smsInfo.setStatus(smsSendStatus.getCode());
this.updateById(smsInfo);
}
/**
* 校验验证码是否正确
*
* @author fengshuonan
* @Date 2018/7/6 下午5:16
*/
@Transactional(rollbackFor = Exception.class)
public SmsVerifyResult validateSmsInfo(VerifySMSParam verifySMSParam) {
//校验请求是否为空
if (ValidateUtil.isOneEmpty(verifySMSParam.getPhoneNumbers(), verifySMSParam.getCode(), verifySMSParam.getTemplateCode())) {
log.error("校验短信是否正确失败!有参数为空!");
throw new SmsException(SmsResultEnum.PARAM_NULL.getCode(), SmsResultEnum.PARAM_NULL.getMessage());
}
//查询有没有这条记录
QueryWrapper<SmsInfo> wrapper = new QueryWrapper<>();
wrapper.eq("phone_numbers", verifySMSParam.getPhoneNumbers())
.and(f -> f.eq("source", verifySMSParam.getSmsSendSource().getCode()))
.and(f -> f.eq("template_code", verifySMSParam.getTemplateCode()));
wrapper.orderByDesc("create_time");
List<SmsInfo> smsInfos = this.list(wrapper);
log.info("验证短信Provider接口,查询到sms记录:" + JSON.toJSONString(smsInfos));
//如果找不到记录,提示验证失败
if (smsInfos == null || smsInfos.isEmpty()) {
log.info("验证短信Provider接口,找不到验证码记录,响应验证失败!");
return SmsVerifyResult.ERROR;
} else {
//获取最近发送的第一条
SmsInfo smsInfo = smsInfos.get(0);
//先判断状态是不是失效的状态
if (SmsSendStatus.INVALID.getCode().equals(smsInfo.getStatus())) {
log.info("验证短信Provider接口,短信状态是失效,响应验证失败!");
return SmsVerifyResult.ERROR;
}
//如果验证码和传过来的不一致
if (!verifySMSParam.getCode().equals(smsInfo.getValidateCode())) {
log.info("验证短信Provider接口,验证手机号和验证码不一致,响应验证失败!");
return SmsVerifyResult.ERROR;
}
//判断是否超时
Date invalidTime = smsInfo.getInvalidTime();
if (invalidTime == null || new Date().after(invalidTime)) {
log.info("验证短信Provider接口,验证码超时,响应验证失败!");
return SmsVerifyResult.EXPIRED;
}
//验证成功把短信设置成失效
smsInfo.setStatus(SmsSendStatus.INVALID.getCode());
this.updateById(smsInfo);
log.info("验证短信Provider接口,验证码验证成功!");
return SmsVerifyResult.SUCCESS;
}
}
}
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.json;
class JSON {
/**
* Returns the input if it is a JSON-permissible value; throws otherwise.
*/
static double checkDouble(double d) throws JSONException {
if (Double.isInfinite(d) || Double.isNaN(d)) {
throw new JSONException("Forbidden numeric value: " + d);
}
return d;
}
static Boolean toBoolean(Object value) {
if (value instanceof Boolean) {
return (Boolean) value;
} else if (value instanceof String) {
String stringValue = (String) value;
if ("true".equalsIgnoreCase(stringValue)) {
return true;
} else if ("false".equalsIgnoreCase(stringValue)) {
return false;
}
}
return null;
}
static Double toDouble(Object value) {
if (value instanceof Double) {
return (Double) value;
} else if (value instanceof Number) {
return ((Number) value).doubleValue();
} else if (value instanceof String) {
try {
return Double.valueOf((String) value);
} catch (NumberFormatException ignored) {
}
}
return null;
}
static Integer toInteger(Object value) {
if (value instanceof Integer) {
return (Integer) value;
} else if (value instanceof Number) {
return ((Number) value).intValue();
} else if (value instanceof String) {
try {
return (int) Double.parseDouble((String) value);
} catch (NumberFormatException ignored) {
}
}
return null;
}
static Long toLong(Object value) {
if (value instanceof Long) {
return (Long) value;
} else if (value instanceof Number) {
return ((Number) value).longValue();
} else if (value instanceof String) {
try {
return (long) Double.parseDouble((String) value);
} catch (NumberFormatException ignored) {
}
}
return null;
}
static String toString(Object value) {
if (value instanceof String) {
return (String) value;
} else if (value != null) {
return String.valueOf(value);
}
return null;
}
public static JSONException typeMismatch(Object indexOrName, Object actual,
String requiredType) throws JSONException {
if (actual == null) {
throw new JSONException("Value at " + indexOrName + " is null.");
} else {
throw new JSONException("Value " + actual + " at " + indexOrName
+ " of type " + actual.getClass().getName()
+ " cannot be converted to " + requiredType);
}
}
public static JSONException typeMismatch(Object actual, String requiredType)
throws JSONException {
if (actual == null) {
throw new JSONException("Value is null.");
} else {
throw new JSONException("Value " + actual
+ " of type " + actual.getClass().getName()
+ " cannot be converted to " + requiredType);
}
}
}
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.json;
// Note: this class was written without inspecting the non-free org.json sourcecode.
/**
* Thrown to indicate a problem with the JSON API. Such problems include:
* <ul>
* <li>Attempts to parse or construct malformed documents
* <li>Use of null as a name
* <li>Use of numeric types not available to JSON, such as {@link
* Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.
* <li>Lookups using an out of range index or nonexistent name
* <li>Type mismatches on lookups
* </ul>
*
* <p>Although this is a checked exception, it is rarely recoverable. Most
* callers should simply wrap this exception in an unchecked exception and
* rethrow:
* <pre> public JSONArray toJSONObject() {
* try {
* JSONObject result = new JSONObject();
* ...
* } catch (JSONException e) {
* throw new RuntimeException(e);
* }
* }</pre>
*/
public class JSONException extends Exception {
public JSONException(String s) {
super(s);
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.stylefeng.guns.sms.config.ServiceAutoConfiguration,\
cn.stylefeng.guns.sms.config.SmsAutoConfiguration
\ No newline at end of file
...@@ -24,6 +24,20 @@ ...@@ -24,6 +24,20 @@
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
<!-- 短信发送 -->
<dependency>
<groupId>cn.stylefeng</groupId>
<artifactId>guns-base-sms</artifactId>
<version>1.0.0</version>
</dependency>
<!-- 邮件发送 -->
<dependency>
<groupId>cn.stylefeng</groupId>
<artifactId>guns-base-email</artifactId>
<version>1.0.0</version>
</dependency>
<!-- 最新代码生成模块 --> <!-- 最新代码生成模块 -->
<dependency> <dependency>
<groupId>cn.stylefeng</groupId> <groupId>cn.stylefeng</groupId>
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
<modules> <modules>
<module>guns-base</module> <module>guns-base</module>
<module>guns-base-sms</module>
<module>guns-base-email</module>
<module>guns-sys</module> <module>guns-sys</module>
<module>guns-vip-gen</module> <module>guns-vip-gen</module>
<module>guns-vip-main</module> <module>guns-vip-main</module>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment