实现短信、系统邮件发送功能

This commit is contained in:
wanggeng888 2021-05-01 23:23:14 +08:00
parent e3280bf909
commit 1b1f809cba
28 changed files with 2553 additions and 0 deletions

View File

@ -13,6 +13,28 @@
<description>消息模块,短信,邮件</description>
<dependencies>
<!-- email start -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
</dependency>
<!-- email end -->
<!-- json start -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
</dependency>
<!-- json end -->
<!-- tencent sms start -->
<dependency>
<groupId>com.github.qcloudsms</groupId>
<artifactId>qcloudsms</artifactId>
<version>1.0.6</version>
</dependency>
<!-- tencent sms end -->
<dependency>
<groupId>ink.wgink</groupId>
<artifactId>common</artifactId>

View File

@ -0,0 +1,62 @@
package ink.wgink.module.sms.builder.email;
import javax.mail.*;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: EmailSendImpl
* @Description: 发送邮件
* @Author: wanggeng
* @Date: 2021/5/1 5:36 下午
* @Version: 1.0
*/
public class EmailSend {
private Message message;
public EmailSend(Message message) {
this.message = message;
}
/**
* 文本邮件
*
* @param subject
* @param text
* @throws MessagingException
*/
public void text(String subject, String text) throws MessagingException {
message.setSubject(subject);
// 设置邮件消息的主要内容
message.setText(text);
// 发送邮件
Transport.send(message);
}
/**
* html邮件
*
* @param subject
* @param content
* @throws MessagingException
*/
public void html(String subject, String content) throws MessagingException {
// MiniMultipart类是一个容器类包含MimeBodyPart类型的对象
Multipart mainPart = new MimeMultipart();
// 创建一个包含HTML内容的MimeBodyPart
BodyPart html = new MimeBodyPart();
// 设置HTML内容
html.setContent(content, "text/html; charset=utf-8");
mainPart.addBodyPart(html);
message.setSubject(subject);
// 将MiniMultipart对象设置为邮件内容
message.setContent(mainPart);
// 发送邮件
Transport.send(message);
}
}

View File

@ -0,0 +1,104 @@
package ink.wgink.module.sms.builder.email;
import ink.wgink.module.sms.pojo.MailAuthenticator;
import ink.wgink.module.sms.pojo.MailSenderInfo;
import ink.wgink.properties.sms.EmailProperties;
import org.apache.commons.lang3.StringUtils;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Date;
import java.util.Properties;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: EmailBuilder
* @Description: 邮件构建
* @Author: wanggeng
* @Date: 2021/5/1 5:35 下午
* @Version: 1.0
*/
public class EmailSendBuilder {
/**
* 邮件发送
*
* @param emailProperties
* @return
*/
public static EmailSend getEmailSend(EmailProperties emailProperties, String toEmail) {
try {
return new EmailSend(getMessage(getMailSenderInfo(emailProperties, toEmail)));
} catch (MessagingException e) {
e.printStackTrace();
return null;
}
}
/**
* 邮件发送者信息
*
* @return
*/
private static MailSenderInfo getMailSenderInfo(EmailProperties emailProperties, String toEmail) {
MailSenderInfo mailInfo = new MailSenderInfo();
mailInfo.setMailServerHost(emailProperties.getSmtp());
mailInfo.setMailServerPort(emailProperties.getPort());
mailInfo.setValidate(true);
mailInfo.setUserName(emailProperties.getSenderEmail());
mailInfo.setPassword(emailProperties.getSenderPassword());
mailInfo.setFromAddress(emailProperties.getSenderEmail());
mailInfo.setToAddress(toEmail);
StringBuilder ccSB = new StringBuilder();
emailProperties.getCcPersons().forEach(cc -> {
if (ccSB.length() > 0) {
ccSB.append(",");
}
ccSB.append(cc);
});
mailInfo.setToCc(ccSB.toString());
return mailInfo;
}
/**
* 邮件消息
*
* @param mailInfo
* @return
* @throws MessagingException
*/
private static Message getMessage(MailSenderInfo mailInfo) throws MessagingException {
// 判断是否需要身份认证
MailAuthenticator authenticator = null;
Properties pro = mailInfo.getProperties();
if (mailInfo.isValidate()) {
// 如果需要身份认证则创建一个密码验证器
authenticator = new MailAuthenticator(mailInfo.getUserName(), mailInfo.getPassword());
}
// 根据邮件会话属性和密码验证器构造一个发送邮件的session
Session sendMailSession = Session.getDefaultInstance(pro, authenticator);
// 根据session创建一个邮件消息
Message mailMessage = new MimeMessage(sendMailSession);
// 创建邮件发送者地址
Address from = new InternetAddress(mailInfo.getFromAddress());
// 设置邮件消息的发送者
mailMessage.setFrom(from);
// 创建邮件的接收者地址并设置到邮件消息中
InternetAddress[] to = InternetAddress.parse(mailInfo.getToAddress());
mailMessage.setRecipients(Message.RecipientType.TO, to);
if (!StringUtils.isBlank(mailInfo.getToCc())) {
InternetAddress[] cc = InternetAddress.parse(mailInfo.getToCc());
mailMessage.setRecipients(Message.RecipientType.CC, cc);
}
// 设置邮件消息发送的时间
mailMessage.setSentDate(new Date());
return mailMessage;
}
}

View File

@ -0,0 +1,97 @@
package ink.wgink.module.sms.controller.api.sms;
import ink.wgink.annotation.CheckRequestBodyAnnotation;
import ink.wgink.common.base.DefaultBaseController;
import ink.wgink.exceptions.ParamsException;
import ink.wgink.exceptions.RemoveException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.sms.pojo.dtos.sms.SmsDTO;
import ink.wgink.module.sms.pojo.vos.sms.SmsVO;
import ink.wgink.module.sms.service.sms.ISmsService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.result.ErrorResult;
import ink.wgink.pojo.result.SuccessResult;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.util.RegexUtil;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.AbstractController;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: VerificationCodeController
* @Description: 验证码
* @Author: WangGeng
* @Date: 2020/3/4 7:13 下午
* @Version: 1.0
**/
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "短信")
@RestController
@RequestMapping(ISystemConstant.API_PREFIX + "/sms")
public class SmsController extends DefaultBaseController {
@Autowired
private ISmsService smsService;
@ApiOperation(value = "新增短信", notes = "新增短信接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@PostMapping("save")
@CheckRequestBodyAnnotation
public SuccessResult save(@RequestBody SmsVO smsVO) {
smsService.save(smsVO);
return new SuccessResult();
}
@ApiOperation(value = "删除短信(id列表)", notes = "删除短信(id列表)接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "ids", value = "ID列表用下划线分隔", paramType = "path", example = "1_2_3")
})
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@DeleteMapping("remove/{ids}")
public SuccessResult remove(@PathVariable("ids") String ids) {
smsService.remove(Arrays.asList(ids.split("\\_")));
return new SuccessResult();
}
@ApiOperation(value = "短信详情(通过ID)", notes = "短信详情(通过ID)接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "smsId", value = "短信ID", paramType = "path")
})
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@GetMapping("get/{smsId}")
public SmsDTO getById(@PathVariable("smsId") String smsId) {
return smsService.get(smsId);
}
@ApiOperation(value = "短信列表", notes = "短信列表接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@GetMapping("list")
public List<SmsDTO> list() {
Map<String, Object> params = requestParams();
return smsService.list(params);
}
@ApiOperation(value = "短信分页列表", notes = "短信分页列表接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "当前页码", paramType = "query", dataType = "int", defaultValue = "1"),
@ApiImplicitParam(name = "rows", value = "显示数量", paramType = "query", dataType = "int", defaultValue = "20"),
@ApiImplicitParam(name = "keywords", value = "关键字", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "startTime", value = "开始时间", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "endTime", value = "结束时间", paramType = "query", dataType = "String")
})
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@GetMapping("listpage")
public SuccessResultList<List<SmsDTO>> listPage(ListPage page) {
Map<String, Object> params = requestParams();
page.setParams(params);
return smsService.listPage(page);
}
}

View File

@ -0,0 +1,48 @@
package ink.wgink.module.sms.controller.app.api.sms;
import ink.wgink.exceptions.ParamsException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.sms.service.sms.ISmsService;
import ink.wgink.pojo.result.ErrorResult;
import ink.wgink.pojo.result.SuccessResult;
import ink.wgink.util.RegexUtil;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: SmsAppController
* @Description: 短信
* @Author: wanggeng
* @Date: 2021/5/1 3:05 下午
* @Version: 1.0
*/
@Api(tags = ISystemConstant.API_TAGS_APP_PREFIX + "验证码接口")
@RestController
@RequestMapping(ISystemConstant.APP_PREFIX + "/sms")
public class SmsAppController {
@Autowired
private ISmsService smsService;
@ApiOperation(value = "获取短信验证码", notes = "获取短信验证码接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "phone", value = "手机", paramType = "path"),
})
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@GetMapping("verify-code/{phone}")
public SuccessResult verifyCode(@PathVariable("phone") String phone) {
if (!RegexUtil.isPhone(phone)) {
throw new ParamsException("手机号格式错误");
}
smsService.sendVerifyCode(phone);
return new SuccessResult();
}
}

View File

@ -0,0 +1,32 @@
package ink.wgink.module.sms.controller.route.sms;
import ink.wgink.interfaces.consts.ISystemConstant;
import io.swagger.annotations.Api;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: SmsRouteController
* @Description: sms页面
* @Author: WangGeng
* @Date: 2020/3/14 16:13
* @Version: 1.0
**/
@Api(tags = ISystemConstant.ROUTE_TAGS_PREFIX + "短信")
@Controller
@RequestMapping(ISystemConstant.ROUTE_PREFIX + "/sms")
public class SmsRouteController {
@GetMapping("list")
public ModelAndView listSms() {
ModelAndView mv = new ModelAndView();
mv.setViewName("sms/list");
return mv;
}
}

View File

@ -0,0 +1,75 @@
package ink.wgink.module.sms.dao.email;
import ink.wgink.exceptions.RemoveException;
import ink.wgink.exceptions.SaveException;
import ink.wgink.exceptions.SearchException;
import ink.wgink.exceptions.UpdateException;
import ink.wgink.module.sms.pojo.dtos.email.EmailDTO;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: IEmailDao
* @Description: 邮件
* @Author: WangGeng
* @Date: 2020/7/31 4:20 下午
* @Version: 1.0
**/
@Repository
public interface IEmailDao {
/**
* 建表
*
* @throws UpdateException
*/
void createTable() throws UpdateException;
/**
* 保存Email
*
* @param params
* @throws SaveException
*/
void save(Map<String, Object> params) throws SaveException;
/**
* 删除Email
*
* @param params
* @throws RemoveException
*/
void remove(Map<String, Object> params) throws RemoveException;
/**
* 更新邮件发送状态
*
* @param params
* @throws UpdateException
*/
void updateSendingStatus(Map<String, Object> params) throws UpdateException;
/**
* Email详情
*
* @param params
* @return
* @throws SearchException
*/
EmailDTO get(Map<String, Object> params) throws SearchException;
/**
* Email列表
*
* @param params
* @return
* @throws SearchException
*/
List<EmailDTO> list(Map<String, Object> params) throws SearchException;
}

View File

@ -0,0 +1,75 @@
package ink.wgink.module.sms.dao.sms;
import ink.wgink.exceptions.RemoveException;
import ink.wgink.exceptions.SaveException;
import ink.wgink.exceptions.SearchException;
import ink.wgink.exceptions.UpdateException;
import ink.wgink.module.sms.pojo.dtos.sms.SmsDTO;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ISmsDao
* @Description: 短信
* @Author: wanggeng
* @Date: 2021/5/1 3:31 下午
* @Version: 1.0
*/
@Repository
public interface ISmsDao {
/**
* 建表
*
* @throws UpdateException
*/
void createTable() throws UpdateException;
/**
* 新增短信
*
* @param params
* @throws SaveException
*/
void save(Map<String, Object> params) throws SaveException;
/**
* 删除短信
*
* @param params
* @throws RemoveException
*/
void remove(Map<String, Object> params) throws RemoveException;
/**
* 修改短信
*
* @param params
* @throws UpdateException
*/
void update(Map<String, Object> params) throws UpdateException;
/**
* 短信详情
*
* @param params
* @return
* @throws SearchException
*/
SmsDTO get(Map<String, Object> params) throws SearchException;
/**
* 短信列表
*
* @param params
* @return
* @throws SearchException
*/
List<SmsDTO> list(Map<String, Object> params) throws SearchException;
}

View File

@ -0,0 +1,31 @@
package ink.wgink.module.sms.factory.sms;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ISendSms
* @Description: 发送短信
* @Author: wanggeng
* @Date: 2021/5/1 3:49 下午
* @Version: 1.0
*/
public interface ISmsSend {
/**
* 发送验证码
*
* @param phone
* @param code
*/
void code(String phone, String code);
/**
* 发送短信
*
* @param phone
* @param content
*/
void content(String phone, String content);
}

View File

@ -0,0 +1,48 @@
package ink.wgink.module.sms.factory.sms;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.module.sms.factory.sms.impl.DefaultSmsSendImpl;
import ink.wgink.module.sms.factory.sms.impl.TencentSmsSendImpl;
import ink.wgink.properties.sms.SmsProperties;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: SendFactory
* @Description: 短信工厂
* @Author: wanggeng
* @Date: 2021/5/1 4:14 下午
* @Version: 1.0
*/
public class SmsSendFactory {
/**
* 腾讯类别
*/
public static String TENCENT_TYPE = "tencent";
/**
* 自定义类别
*/
public static String CUSTOM_TYPE = "custom";
/**
* 默认发送短信
*
* @param smsProperties
* @return
*/
public static ISmsSend getSendSms(SmsProperties smsProperties) {
if (!smsProperties.getActive()) {
throw new SystemException("短信配置未激活");
}
if (StringUtils.equals(TENCENT_TYPE, smsProperties.getType())) {
return new TencentSmsSendImpl(smsProperties.getTencentSms());
}
return new DefaultSmsSendImpl(smsProperties.getDefaultSms());
}
}

View File

@ -0,0 +1,70 @@
package ink.wgink.module.sms.factory.sms.impl;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.module.sms.factory.sms.ISmsSend;
import ink.wgink.properties.sms.SmsDefaultProperties;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.json.XML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: DefaultSendSmsImpl
* @Description: 默认发请求
* @Author: wanggeng
* @Date: 2021/5/1 3:52 下午
* @Version: 1.0
*/
public class DefaultSmsSendImpl implements ISmsSend {
private static final Logger LOG = LoggerFactory.getLogger(DefaultSmsSendImpl.class);
private static final String URL_SMS = "https://dx.ipyy.net/sms.aspx?action=send&userid=&account={account}&password={password}&mobile={mobile}&content={content}&sendTime=&extno={extno}";
private SmsDefaultProperties smsDefaultProperties;
public DefaultSmsSendImpl(SmsDefaultProperties smsDefaultProperties) {
this.smsDefaultProperties = smsDefaultProperties;
}
@Override
public void code(String phone, String code) {
String content = smsDefaultProperties.getTemplate().getVerificationCode().replace("{sign}", smsDefaultProperties.getSign()).replace("{content}", code);
send(phone, content);
}
@Override
public void content(String phone, String content) {
StringBuilder contentSB = new StringBuilder(smsDefaultProperties.getSign()).append(content);
send(phone, contentSB.toString());
}
/**
* 发送
*
* @param phone
* @param content
*/
private void send(String phone, String content) {
String[] paramArray = new String[]{
smsDefaultProperties.getAccount(),
smsDefaultProperties.getPassword(),
phone,
content,
phone
};
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(URL_SMS, String.class, paramArray);
JSONObject jsonObject = XML.toJSONObject(result);
if (StringUtils.equals("Success", jsonObject.getJSONObject("returnsms").getString("returnstatus"))) {
LOG.info("验证码发送成功");
} else {
LOG.error("验证码发送失败,原因:{}。", jsonObject);
throw new SystemException(jsonObject.toString());
}
}
}

View File

@ -0,0 +1,53 @@
package ink.wgink.module.sms.factory.sms.impl;
import com.github.qcloudsms.SmsMultiSender;
import com.github.qcloudsms.SmsMultiSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.module.sms.factory.sms.ISmsSend;
import ink.wgink.properties.sms.SmsTencentProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: TencentSendSmsImpl
* @Description: 腾讯发短信
* @Author: wanggeng
* @Date: 2021/5/1 4:35 下午
* @Version: 1.0
*/
public class TencentSmsSendImpl implements ISmsSend {
private static final Logger LOG = LoggerFactory.getLogger(TencentSmsSendImpl.class);
private SmsTencentProperties smsTencentProperties;
public TencentSmsSendImpl(SmsTencentProperties smsTencentProperties) {
this.smsTencentProperties = smsTencentProperties;
}
@Override
public void code(String phone, String code) {
String[] params = {code};
SmsMultiSender sender = new SmsMultiSender(Integer.parseInt(smsTencentProperties.getAppId()), smsTencentProperties.getAppKey());
try {
SmsMultiSenderResult result = sender.sendWithParam("86", new String[]{phone}, Integer.parseInt(smsTencentProperties.getVerificationCodeTemplateId()), params, smsTencentProperties.getSmsSign(), "", "");
LOG.debug("Tencent sms result: {}", result);
} catch (HTTPException e) {
LOG.error(e.getMessage(), e);
throw new SystemException("发送验证码失败");
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw new SystemException("发送验证码失败");
}
}
@Override
public void content(String phone, String content) {
throw new SystemException("短信发送失败,未配置腾讯短信服务");
}
}

View File

@ -0,0 +1,130 @@
package ink.wgink.module.sms.manager;
import ink.wgink.exceptions.ParamsException;
import ink.wgink.module.sms.pojo.VerifyCode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: VerifyCodeManager
* @Description: 验证码管理
* @Author: WangGeng
* @Date: 2020/3/4 5:34 下午
* @Version: 1.0
**/
public class VerifyCodeManager {
private static final Logger LOG = LoggerFactory.getLogger(VerifyCodeManager.class);
private static final VerifyCodeManager verifyCodeManager = VerifyCodeManagerBuilder.verifyCodeManager;
private Map<String, VerifyCode> verifyCodeMap = new ConcurrentHashMap<>();
/**
* 有效时间60s
*/
public static final long EXPIRE_TIME = 120000L;
private VerifyCodeManager() {
}
public static VerifyCodeManager getInstance() {
return verifyCodeManager;
}
/**
* 设置验证码
*
* @param key
* @param code
*/
public void setVerificationCode(String key, String code) {
VerifyCode verifyCode = new VerifyCode();
verifyCode.setCode(code);
verifyCode.setTime(System.currentTimeMillis());
verifyCodeMap.put(key, verifyCode);
}
/**
* 获取验证码
*
* @param key
* @return
*/
public String getVerifyCode(String key) {
VerifyCode verifyCode = verifyCodeMap.get(key);
if (verifyCode != null && (System.currentTimeMillis() - verifyCode.getTime() < EXPIRE_TIME)) {
return verifyCode.getCode();
}
return null;
}
/**
* 是否有有效的验证码
*
* @param key
* @return
*/
public long effectiveVerificationCodeTimeRemaining(String key) {
VerifyCode verifyCode = verifyCodeMap.get(key);
if (verifyCode == null) {
return 0;
}
long timeRemaining = System.currentTimeMillis() - verifyCode.getTime();
if (timeRemaining >= EXPIRE_TIME) {
return 0;
}
return EXPIRE_TIME - timeRemaining;
}
/**
* 清理使用后的验证码
*
* @param key
*/
public void clearUsedVerifyCode(String key) {
verifyCodeMap.remove(key);
}
/**
* 校验验证码
*
* @param key
* @param code
*/
public void checkVerifyCode(String key, String code) {
String verificationCode = getVerifyCode(key);
if (StringUtils.isBlank(verificationCode)) {
throw new ParamsException("验证码无效");
}
if (!StringUtils.equals(code, verificationCode)) {
throw new ParamsException("验证码不匹配");
}
clearUsedVerifyCode(key);
}
/**
* 删除过期验证码
*/
public void clearExpireTimeCode() {
int size = 0;
long currentTime = System.currentTimeMillis();
for (Map.Entry<String, VerifyCode> kv : verifyCodeMap.entrySet()) {
VerifyCode verifyCode = kv.getValue();
if (currentTime - verifyCode.getTime() > EXPIRE_TIME) {
verifyCodeMap.remove(kv.getKey());
size++;
}
}
LOG.debug("本次清除超时验证码:{}个", size);
}
private static class VerifyCodeManagerBuilder {
public static VerifyCodeManager verifyCodeManager = new VerifyCodeManager();
}
}

View File

@ -0,0 +1,32 @@
package ink.wgink.module.sms.pojo;
/**
* 发送邮件需要使用的基本信息
*
* @version 2.0
*/
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
/**
* 邮件认证
* @author wanggeng
*/
public class MailAuthenticator extends Authenticator {
String userName = null;
String password = null;
public MailAuthenticator() {
}
public MailAuthenticator(String username, String password) {
this.userName = username;
this.password = password;
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(this.userName, this.password);
}
}

View File

@ -0,0 +1,180 @@
package ink.wgink.module.sms.pojo;
/**
* 发送邮件需要使用的基本信息
*
* @author FH QQ 313596790[青苔]
* 修改时间2015年7月27日
* @version 2.0
*/
import java.util.Arrays;
import java.util.Properties;
public class MailSenderInfo {
/**
* 发送邮件的服务器的IP和端口
*/
private String mailServerHost;
private Integer mailServerPort = 25;
/**
* 邮件发送者的地址
*/
private String fromAddress;
/**
* 邮件接收者的地址
*/
private String toAddress;
/**
* 抄送人
*/
private String toCc;
/**
* 登陆邮件发送服务器的用户名和密码
*/
private String userName;
private String password;
/**
* 是否需要身份验证
*/
private boolean validate = false;
/**
* 邮件主题
*/
private String subject;
/**
* 邮件的文本内容
*/
private String content;
/**
* 邮件附件的文件名
*/
private String[] attachFileNames;
/**
* 获得邮件会话属性
*/
public Properties getProperties() {
Properties properties = new Properties();
properties.put("mail.smtp.host", this.mailServerHost);
properties.put("mail.smtp.port", this.mailServerPort);
properties.put("mail.smtp.auth", validate ? "true" : "false");
return properties;
}
public String getMailServerHost() {
return mailServerHost == null ? "" : mailServerHost.trim();
}
public void setMailServerHost(String mailServerHost) {
this.mailServerHost = mailServerHost;
}
public Integer getMailServerPort() {
return mailServerPort;
}
public void setMailServerPort(Integer mailServerPort) {
this.mailServerPort = mailServerPort;
}
public String getFromAddress() {
return fromAddress == null ? "" : fromAddress.trim();
}
public void setFromAddress(String fromAddress) {
this.fromAddress = fromAddress;
}
public String getToAddress() {
return toAddress == null ? "" : toAddress.trim();
}
public void setToAddress(String toAddress) {
this.toAddress = toAddress;
}
public String getToCc() {
return toCc == null ? "" : toCc.trim();
}
public void setToCc(String toCc) {
this.toCc = toCc;
}
public String getUserName() {
return userName == null ? "" : userName.trim();
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password == null ? "" : password.trim();
}
public void setPassword(String password) {
this.password = password;
}
public boolean isValidate() {
return validate;
}
public void setValidate(boolean validate) {
this.validate = validate;
}
public String getSubject() {
return subject == null ? "" : subject.trim();
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getContent() {
return content == null ? "" : content.trim();
}
public void setContent(String content) {
this.content = content;
}
public String[] getAttachFileNames() {
return attachFileNames;
}
public void setAttachFileNames(String[] attachFileNames) {
this.attachFileNames = attachFileNames;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"mailServerHost\":")
.append("\"").append(mailServerHost).append("\"");
sb.append(",\"mailServerPort\":")
.append("\"").append(mailServerPort).append("\"");
sb.append(",\"fromAddress\":")
.append("\"").append(fromAddress).append("\"");
sb.append(",\"toAddress\":")
.append("\"").append(toAddress).append("\"");
sb.append(",\"toCc\":")
.append("\"").append(toCc).append("\"");
sb.append(",\"userName\":")
.append("\"").append(userName).append("\"");
sb.append(",\"password\":")
.append("\"").append(password).append("\"");
sb.append(",\"validate\":")
.append(validate);
sb.append(",\"subject\":")
.append("\"").append(subject).append("\"");
sb.append(",\"content\":")
.append("\"").append(content).append("\"");
sb.append(",\"attachFileNames\":")
.append(Arrays.toString(attachFileNames));
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,134 @@
package ink.wgink.module.sms.pojo.dtos.email;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: EmailDTO
* @Description: 邮箱
* @Author: WangGeng
* @Date: 2020/7/31 4:37 下午
* @Version: 1.0
**/
@ApiModel
public class EmailDTO {
@ApiModelProperty(name = "emailId", value = "ID")
private String emailId;
@ApiModelProperty(name = "emailSender", value = "发送人")
private String emailSender;
@ApiModelProperty(name = "emailReceiver", value = "接收人")
private String emailReceiver;
@ApiModelProperty(name = "emailCc", value = "抄送人")
private String emailCc;
@ApiModelProperty(name = "emailType", value = "邮件类型")
private String emailType;
@ApiModelProperty(name = "emailSubject", value = "主题")
private String emailSubject;
@ApiModelProperty(name = "emailContent", value = "内容")
private String emailContent;
@ApiModelProperty(name = "sendingStatus", value = "发送状态")
private Integer sendingStatus;
@ApiModelProperty(name = "gmtCreate", value = "发送时间")
private String gmtCreate;
public String getEmailId() {
return emailId == null ? "" : emailId.trim();
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public String getEmailSender() {
return emailSender == null ? "" : emailSender.trim();
}
public void setEmailSender(String emailSender) {
this.emailSender = emailSender;
}
public String getEmailReceiver() {
return emailReceiver == null ? "" : emailReceiver.trim();
}
public void setEmailReceiver(String emailReceiver) {
this.emailReceiver = emailReceiver;
}
public String getEmailCc() {
return emailCc == null ? "" : emailCc.trim();
}
public void setEmailCc(String emailCc) {
this.emailCc = emailCc;
}
public String getEmailType() {
return emailType == null ? "" : emailType.trim();
}
public void setEmailType(String emailType) {
this.emailType = emailType;
}
public String getEmailSubject() {
return emailSubject == null ? "" : emailSubject.trim();
}
public void setEmailSubject(String emailSubject) {
this.emailSubject = emailSubject;
}
public String getEmailContent() {
return emailContent == null ? "" : emailContent.trim();
}
public void setEmailContent(String emailContent) {
this.emailContent = emailContent;
}
public Integer getSendingStatus() {
return sendingStatus;
}
public void setSendingStatus(Integer sendingStatus) {
this.sendingStatus = sendingStatus;
}
public String getGmtCreate() {
return gmtCreate == null ? "" : gmtCreate.trim();
}
public void setGmtCreate(String gmtCreate) {
this.gmtCreate = gmtCreate;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"emailId\":")
.append("\"").append(emailId).append("\"");
sb.append(",\"emailSender\":")
.append("\"").append(emailSender).append("\"");
sb.append(",\"emailReceiver\":")
.append("\"").append(emailReceiver).append("\"");
sb.append(",\"emailCc\":")
.append("\"").append(emailCc).append("\"");
sb.append(",\"emailType\":")
.append("\"").append(emailType).append("\"");
sb.append(",\"emailSubject\":")
.append("\"").append(emailSubject).append("\"");
sb.append(",\"emailContent\":")
.append("\"").append(emailContent).append("\"");
sb.append(",\"sendingStatus\":")
.append(sendingStatus);
sb.append(",\"gmtCreate\":")
.append("\"").append(gmtCreate).append("\"");
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,95 @@
package ink.wgink.module.sms.pojo.dtos.sms;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
*
* @ClassName: SmsDTO
* @Description: 短信
* @Author: WenG
* @Date: 2020-03-14 16:01
* @Version: 1.0
**/
@ApiModel
public class SmsDTO {
@ApiModelProperty(name = "smsId", value = "主键")
private String smsId;
@ApiModelProperty(name = "phone", value = "电话")
private String phone;
@ApiModelProperty(name = "content", value = "发送内容")
private String content;
@ApiModelProperty(name = "sendStatus", value = "发送状态")
private Integer sendStatus;
@ApiModelProperty(name = "errorMessage", value = "错误信息")
private String errorMessage;
@ApiModelProperty(name = "gmtCreate", value = "发送时间")
private String gmtCreate;
public String getSmsId() {
return smsId == null ? "" : smsId;
}
public void setSmsId(String smsId) {
this.smsId = smsId;
}
public String getPhone() {
return phone == null ? "" : phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getContent() {
return content == null ? "" : content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getSendStatus() {
return sendStatus == null ? 0 : sendStatus;
}
public void setSendStatus(Integer sendStatus) {
this.sendStatus = sendStatus;
}
public String getErrorMessage() {
return errorMessage == null ? "" : errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getGmtCreate() {
return gmtCreate == null ? "" : gmtCreate;
}
public void setGmtCreate(String gmtCreate) {
this.gmtCreate = gmtCreate;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"smsId\":\"")
.append(smsId).append('\"');
sb.append(",\"phone\":\"")
.append(phone).append('\"');
sb.append(",\"content\":\"")
.append(content).append('\"');
sb.append(",\"sendStatus\":")
.append(sendStatus);
sb.append(",\"errorMessage\":\"")
.append(errorMessage).append('\"');
sb.append(",\"gmtCreate\":\"")
.append(gmtCreate).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,124 @@
package ink.wgink.module.sms.pojo.pos.email;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: EmailDTO
* @Description: 邮箱
* @Author: WangGeng
* @Date: 2020/7/31 4:37 下午
* @Version: 1.0
**/
public class EmailPO {
private String emailId;
private String emailSender;
private String emailReceiver;
private String emailCc;
private String emailType;
private String emailSubject;
private String emailContent;
private Integer sendingStatus;
private String gmtCreate;
public String getEmailId() {
return emailId == null ? "" : emailId.trim();
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public String getEmailSender() {
return emailSender == null ? "" : emailSender.trim();
}
public void setEmailSender(String emailSender) {
this.emailSender = emailSender;
}
public String getEmailReceiver() {
return emailReceiver == null ? "" : emailReceiver.trim();
}
public void setEmailReceiver(String emailReceiver) {
this.emailReceiver = emailReceiver;
}
public String getEmailCc() {
return emailCc == null ? "" : emailCc.trim();
}
public void setEmailCc(String emailCc) {
this.emailCc = emailCc;
}
public String getEmailType() {
return emailType == null ? "" : emailType.trim();
}
public void setEmailType(String emailType) {
this.emailType = emailType;
}
public String getEmailSubject() {
return emailSubject == null ? "" : emailSubject.trim();
}
public void setEmailSubject(String emailSubject) {
this.emailSubject = emailSubject;
}
public String getEmailContent() {
return emailContent == null ? "" : emailContent.trim();
}
public void setEmailContent(String emailContent) {
this.emailContent = emailContent;
}
public Integer getSendingStatus() {
return sendingStatus;
}
public void setSendingStatus(Integer sendingStatus) {
this.sendingStatus = sendingStatus;
}
public String getGmtCreate() {
return gmtCreate == null ? "" : gmtCreate.trim();
}
public void setGmtCreate(String gmtCreate) {
this.gmtCreate = gmtCreate;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"emailId\":")
.append("\"").append(emailId).append("\"");
sb.append(",\"emailSender\":")
.append("\"").append(emailSender).append("\"");
sb.append(",\"emailReceiver\":")
.append("\"").append(emailReceiver).append("\"");
sb.append(",\"emailCc\":")
.append("\"").append(emailCc).append("\"");
sb.append(",\"emailType\":")
.append("\"").append(emailType).append("\"");
sb.append(",\"emailSubject\":")
.append("\"").append(emailSubject).append("\"");
sb.append(",\"emailContent\":")
.append("\"").append(emailContent).append("\"");
sb.append(",\"sendingStatus\":")
.append(sendingStatus);
sb.append(",\"gmtCreate\":")
.append("\"").append(gmtCreate).append("\"");
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,88 @@
package ink.wgink.module.sms.pojo.pos.sms;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
*
* @ClassName: SmsDTO
* @Description: 短信
* @Author: WenG
* @Date: 2020-03-14 16:01
* @Version: 1.0
**/
public class SmsPO {
private String smsId;
private String phone;
private String content;
private Integer sendStatus;
private String errorMessage;
private String gmtCreate;
public String getSmsId() {
return smsId == null ? "" : smsId;
}
public void setSmsId(String smsId) {
this.smsId = smsId;
}
public String getPhone() {
return phone == null ? "" : phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getContent() {
return content == null ? "" : content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getSendStatus() {
return sendStatus == null ? 0 : sendStatus;
}
public void setSendStatus(Integer sendStatus) {
this.sendStatus = sendStatus;
}
public String getErrorMessage() {
return errorMessage == null ? "" : errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public String getGmtCreate() {
return gmtCreate == null ? "" : gmtCreate;
}
public void setGmtCreate(String gmtCreate) {
this.gmtCreate = gmtCreate;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"smsId\":\"")
.append(smsId).append('\"');
sb.append(",\"phone\":\"")
.append(phone).append('\"');
sb.append(",\"content\":\"")
.append(content).append('\"');
sb.append(",\"sendStatus\":")
.append(sendStatus);
sb.append(",\"errorMessage\":\"")
.append(errorMessage).append('\"');
sb.append(",\"gmtCreate\":\"")
.append(gmtCreate).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,110 @@
package ink.wgink.module.sms.pojo.vos.email;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: EmailVO
* @Description: 邮件
* @Author: WangGeng
* @Date: 2020/7/31 4:31 下午
* @Version: 1.0
**/
@ApiModel
public class EmailVO {
@ApiModelProperty(name = "emailSender", value = "发送人")
private String emailSender;
@ApiModelProperty(name = "emailReceiver", value = "接收人")
private String emailReceiver;
@ApiModelProperty(name = "emailCc", value = "抄送人")
private String emailCc;
@ApiModelProperty(name = "emailType", value = "邮件类型")
private String emailType;
@ApiModelProperty(name = "emailSubject", value = "主题")
private String emailSubject;
@ApiModelProperty(name = "emailContent", value = "内容")
private String emailContent;
@ApiModelProperty(name = "sendingStatus", value = "发送状态")
private Integer sendingStatus;
public String getEmailSender() {
return emailSender == null ? "" : emailSender.trim();
}
public void setEmailSender(String emailSender) {
this.emailSender = emailSender;
}
public String getEmailReceiver() {
return emailReceiver == null ? "" : emailReceiver.trim();
}
public void setEmailReceiver(String emailReceiver) {
this.emailReceiver = emailReceiver;
}
public String getEmailCc() {
return emailCc == null ? "" : emailCc.trim();
}
public void setEmailCc(String emailCc) {
this.emailCc = emailCc;
}
public String getEmailType() {
return emailType == null ? "" : emailType.trim();
}
public void setEmailType(String emailType) {
this.emailType = emailType;
}
public String getEmailSubject() {
return emailSubject == null ? "" : emailSubject.trim();
}
public void setEmailSubject(String emailSubject) {
this.emailSubject = emailSubject;
}
public String getEmailContent() {
return emailContent == null ? "" : emailContent.trim();
}
public void setEmailContent(String emailContent) {
this.emailContent = emailContent;
}
public Integer getSendingStatus() {
return sendingStatus;
}
public void setSendingStatus(Integer sendingStatus) {
this.sendingStatus = sendingStatus;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"emailSender\":")
.append("\"").append(emailSender).append("\"");
sb.append(",\"emailReceiver\":")
.append("\"").append(emailReceiver).append("\"");
sb.append(",\"emailCc\":")
.append("\"").append(emailCc).append("\"");
sb.append(",\"emailType\":")
.append("\"").append(emailType).append("\"");
sb.append(",\"emailSubject\":")
.append("\"").append(emailSubject).append("\"");
sb.append(",\"emailContent\":")
.append("\"").append(emailContent).append("\"");
sb.append(",\"sendingStatus\":")
.append(sendingStatus);
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,75 @@
package ink.wgink.module.sms.pojo.vos.sms;
import ink.wgink.annotation.CheckEmptyAnnotation;
import ink.wgink.annotation.CheckNumberAnnotation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* @ClassName: SmsVO
* @Description: 短信
* @Author: WenG
* @Date: 2020-03-14 16:01
* @Version: 1.0
**/
@ApiModel
public class SmsVO {
@ApiModelProperty(name = "phone", value = "电话")
@CheckEmptyAnnotation(name = "电话", verifyType = "phone")
private String phone;
@ApiModelProperty(name = "content", value = "发送内容")
private String content;
@ApiModelProperty(name = "sendStatus", value = "发送状态")
@CheckNumberAnnotation(name = "发送状态")
private Integer sendStatus;
@ApiModelProperty(name = "errorMessage", value = "错误信息")
private String errorMessage;
public String getPhone() {
return phone == null ? "" : phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getContent() {
return content == null ? "" : content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getSendStatus() {
return sendStatus == null ? 0 : sendStatus;
}
public void setSendStatus(Integer sendStatus) {
this.sendStatus = sendStatus;
}
public String getErrorMessage() {
return errorMessage == null ? "" : errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"phone\":\"")
.append(phone).append('\"');
sb.append(",\"content\":\"")
.append(content).append('\"');
sb.append(",\"sendStatus\":")
.append(sendStatus);
sb.append(",\"errorMessage\":\"")
.append(errorMessage).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,93 @@
package ink.wgink.module.sms.service.email;
import ink.wgink.module.sms.pojo.dtos.email.EmailDTO;
import ink.wgink.module.sms.pojo.vos.email.EmailVO;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.result.SuccessResultList;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: IEmailService
* @Description: 邮件服务
* @Author: WangGeng
* @Date: 2020/7/31 4:19 下午
* @Version: 1.0
**/
public interface IEmailService {
/**
* 保存并发送系统邮件
*
* @param emailVO
* @return
*/
void save(EmailVO emailVO);
/**
* 删除邮件
*
* @param ids
* @return
*/
void remove(List<String> ids);
/**
* 修改发送状态
*
* @param emailId
* @param sendingStatus
*/
void updateSendingStatus(String emailId, int sendingStatus);
/**
* 详情
*
* @param params
* @return
*/
EmailDTO get(Map<String, Object> params);
/**
* 邮件详情(通过ID)
*
* @param emailId
* @return
*/
EmailDTO get(String emailId);
/**
* 邮件列表
*
* @param params
* @return
*/
List<EmailDTO> list(Map<String, Object> params);
/**
* 邮件分页列表
*
* @param page
* @return
*/
SuccessResultList<List<EmailDTO>> listPage(ListPage page);
/**
* 发送邮件
*
* @param emailVO
*/
void send(EmailVO emailVO);
/**
* 重新发送邮件
*
* @param emailId
*/
void reSend(String emailId);
}

View File

@ -0,0 +1,127 @@
package ink.wgink.module.sms.service.email.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.PropertiesException;
import ink.wgink.exceptions.SearchException;
import ink.wgink.module.sms.builder.email.EmailSendBuilder;
import ink.wgink.module.sms.dao.email.IEmailDao;
import ink.wgink.module.sms.pojo.dtos.email.EmailDTO;
import ink.wgink.module.sms.pojo.vos.email.EmailVO;
import ink.wgink.module.sms.service.email.IEmailService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.properties.sms.EmailProperties;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.map.HashMapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: EmailServiceImpl
* @Description: 右键
* @Author: wanggeng
* @Date: 2021/5/1 5:26 下午
* @Version: 1.0
*/
@Service
public class EmailServiceImpl extends DefaultBaseService implements IEmailService {
@Autowired
private EmailProperties emailProperties;
@Autowired
private IEmailDao emailDao;
@Override
public void save(EmailVO emailVO) {
Map<String, Object> params = HashMapUtil.beanToMap(emailVO);
params.put("emailId", UUIDUtil.getUUID());
setSaveInfoByUserId(params, "1");
emailDao.save(params);
}
@Override
public void remove(List<String> ids) {
Map<String, Object> params = getHashMap(6);
params.put("emailIds", ids);
setUpdateInfo(params);
emailDao.remove(params);
}
@Override
public void updateSendingStatus(String emailId, int sendingStatus) {
Map<String, Object> params = getHashMap(4);
params.put("emailId", emailId);
params.put("sendingStatus", sendingStatus);
emailDao.updateSendingStatus(params);
}
@Override
public EmailDTO get(Map<String, Object> params) {
return emailDao.get(params);
}
@Override
public EmailDTO get(String emailId) {
Map<String, Object> params = getHashMap(2);
params.put("emailId", emailId);
return get(params);
}
@Override
public List<EmailDTO> list(Map<String, Object> params) {
return emailDao.list(params);
}
@Override
public SuccessResultList<List<EmailDTO>> listPage(ListPage page) {
PageHelper.startPage(page.getPage(), page.getRows());
List<EmailDTO> emailDTOs = list(page.getParams());
PageInfo<EmailDTO> pageInfo = new PageInfo<>(emailDTOs);
return new SuccessResultList<>(emailDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
}
@Override
public void send(EmailVO emailVO) {
if (!emailProperties.getActive()) {
throw new PropertiesException("邮件未激活");
}
try {
EmailSendBuilder.getEmailSend(emailProperties, emailVO.getEmailReceiver()).html(emailVO.getEmailSubject(), emailVO.getEmailContent());
emailVO.setSendingStatus(1);
} catch (MessagingException e) {
LOG.error(e.getMessage(), e);
emailVO.setSendingStatus(0);
} finally {
save(emailVO);
}
}
@Override
public void reSend(String emailId) {
if (!emailProperties.getActive()) {
throw new PropertiesException("邮件未激活");
}
EmailDTO emailDTO = get(emailId);
if (emailDTO == null) {
throw new SearchException("邮件不存在");
}
int sendingStatus = 0;
try {
EmailSendBuilder.getEmailSend(emailProperties, emailDTO.getEmailReceiver()).html(emailDTO.getEmailSubject(), emailDTO.getEmailContent());
sendingStatus = 1;
} catch (MessagingException e) {
LOG.error(e.getMessage(), e);
} finally {
updateSendingStatus(emailId, sendingStatus);
}
}
}

View File

@ -0,0 +1,87 @@
package ink.wgink.module.sms.service.sms;
import ink.wgink.interfaces.sms.ISmsBaseService;
import ink.wgink.module.sms.pojo.dtos.sms.SmsDTO;
import ink.wgink.module.sms.pojo.vos.sms.SmsVO;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.result.SuccessResultList;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ISmsService
* @Description: 短信
* @Author: wanggeng
* @Date: 2021/5/1 3:06 下午
* @Version: 1.0
*/
public interface ISmsService extends ISmsBaseService {
/**
* 新增短信
*
* @param smsVO
*/
void save(SmsVO smsVO);
/**
* 删除短信
*
* @param ids
* @return
*/
void remove(List<String> ids);
/**
* 短信详情
*
* @param params
* @return
*/
SmsDTO get(Map<String, Object> params);
/**
* 短信详情(通过ID)
*
* @param smsId
* @return
*/
SmsDTO get(String smsId);
/**
* 短信列表
*
* @param params
* @return
*/
List<SmsDTO> list(Map<String, Object> params);
/**
* 短信分页列表
*
* @param page
* @return
*/
SuccessResultList<List<SmsDTO>> listPage(ListPage page);
/**
* 发送短信
*
* @param phone
* @param content
*/
void sendContent(String phone, String content);
/**
* 发送验证码
*
* @param phone
*/
void sendVerifyCode(String phone);
}

View File

@ -0,0 +1,136 @@
package ink.wgink.module.sms.service.sms.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.ParamsException;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.module.sms.dao.sms.ISmsDao;
import ink.wgink.module.sms.factory.sms.SmsSendFactory;
import ink.wgink.module.sms.manager.VerifyCodeManager;
import ink.wgink.module.sms.pojo.dtos.sms.SmsDTO;
import ink.wgink.module.sms.pojo.vos.sms.SmsVO;
import ink.wgink.module.sms.service.sms.ISmsService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.properties.sms.SmsProperties;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.map.HashMapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: SmsServiceImpl
* @Description: 短信
* @Author: wanggeng
* @Date: 2021/5/1 3:07 下午
* @Version: 1.0
*/
@Service
public class SmsServiceImpl extends DefaultBaseService implements ISmsService {
@Autowired
private SmsProperties smsProperties;
@Autowired
private ISmsDao smsDao;
@Override
public void save(SmsVO smsVO) {
Map<String, Object> params = HashMapUtil.beanToMap(smsVO);
params.put("smsId", UUIDUtil.getUUID());
setSaveInfoByUserId(params, "1");
smsDao.save(params);
}
@Override
public void remove(List<String> ids) {
Map<String, Object> params = getHashMap(6);
params.put("smsIds", ids);
setUpdateInfo(params);
smsDao.remove(params);
}
@Override
public SmsDTO get(Map<String, Object> params) {
return smsDao.get(params);
}
@Override
public SmsDTO get(String smsId) {
Map<String, Object> params = getHashMap(2);
params.put("smsId", smsId);
return get(params);
}
@Override
public List<SmsDTO> list(Map<String, Object> params) {
return smsDao.list(params);
}
@Override
public SuccessResultList<List<SmsDTO>> listPage(ListPage page) {
PageHelper.startPage(page.getPage(), page.getRows());
List<SmsDTO> smsDTOs = list(page.getParams());
PageInfo<SmsDTO> pageInfo = new PageInfo<>(smsDTOs);
return new SuccessResultList<>(smsDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
}
@Override
public void sendContent(String phone, String content) {
SmsVO smsVO = new SmsVO();
smsVO.setPhone(phone);
smsVO.setContent(content);
try {
LOG.info(">>>>> 向手机号:{},发送内容:{}", phone, content);
SmsSendFactory.getSendSms(smsProperties).content(phone, content);
smsVO.setSendStatus(1);
} catch (Exception e) {
String errorMessage = e.getMessage();
smsVO.setSendStatus(0);
smsVO.setErrorMessage(errorMessage);
throw new SystemException("短信发送失败");
} finally {
save(smsVO);
}
}
@Override
public void sendVerifyCode(String phone) {
VerifyCodeManager verifyCodeManager = VerifyCodeManager.getInstance();
long timeRemaining = verifyCodeManager.effectiveVerificationCodeTimeRemaining(phone);
if (timeRemaining > 0) {
throw new ParamsException(String.format("验证码已发送,若没有收到,请在%d秒后重试", (timeRemaining / 1000)));
}
String currentTimeStr = String.valueOf(System.currentTimeMillis());
String code = currentTimeStr.substring(currentTimeStr.length() - 6);
LOG.info(">>>>> 向手机号:{},发送验证码:{}", phone, code);
SmsVO smsVO = new SmsVO();
smsVO.setPhone(phone);
smsVO.setContent(code);
try {
SmsSendFactory.getSendSms(smsProperties).code(phone, code);
verifyCodeManager.setVerificationCode(phone, code);
smsVO.setSendStatus(1);
} catch (Exception e) {
String errorMessage = e.getMessage();
smsVO.setSendStatus(0);
smsVO.setErrorMessage(errorMessage);
throw new SystemException("短信发送失败");
} finally {
save(smsVO);
}
}
@Override
public String getVerifyCode(String phone) {
return VerifyCodeManager.getInstance().getVerifyCode(phone);
}
}

View File

@ -0,0 +1,62 @@
package ink.wgink.module.sms.startup;
import ink.wgink.module.sms.dao.email.IEmailDao;
import ink.wgink.module.sms.dao.sms.ISmsDao;
import ink.wgink.module.sms.manager.VerifyCodeManager;
import ink.wgink.properties.sms.EmailProperties;
import ink.wgink.properties.sms.SmsProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: SmsStartUp
* @Description: 短信模块启动
* @Author: wanggeng
* @Date: 2021/5/1 4:52 下午
* @Version: 1.0
*/
@Component
public class SmsStartUp implements ApplicationRunner {
private static final Logger LOG = LoggerFactory.getLogger(SmsStartUp.class);
@Autowired
private SmsProperties smsProperties;
@Autowired
private EmailProperties emailProperties;
@Autowired
private ISmsDao smsDao;
@Autowired
private IEmailDao emailDao;
@Override
public void run(ApplicationArguments args) throws Exception {
initTable();
}
public void initTable() {
if (smsProperties.getActive()) {
LOG.debug("创建 sms_sms 表");
smsDao.createTable();
}
if(emailProperties.getActive()) {
LOG.debug("创建 sms_email 表");
emailDao.createTable();
}
}
/**
* 清除过期验证码任务
*/
@Scheduled(cron = "30 * * * * ?")
public void verificationCodeExpireTimeClearTask() {
VerifyCodeManager.getInstance().clearExpireTimeCode();
}
}

View File

@ -0,0 +1,168 @@
<?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="ink.wgink.module.sms.dao.email.IEmailDao">
<resultMap id="emailDTO" type="ink.wgink.module.sms.pojo.dtos.email.EmailDTO">
<id column="email_id" property="emailId"/>
<result column="email_sender" property="emailSender"/>
<result column="email_receiver" property="emailReceiver"/>
<result column="email_cc" property="emailCc"/>
<result column="email_type" property="emailType"/>
<result column="email_subject" property="emailSubject"/>
<result column="email_content" property="emailContent"/>
<result column="sending_status" property="sendingStatus"/>
</resultMap>
<!-- 建表 -->
<update id="createTable">
CREATE TABLE IF NOT EXISTS `sms_email` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`email_id` char(36) NOT NULL,
`email_sender` varchar(255) DEFAULT NULL COMMENT '发送人',
`email_receiver` varchar(255) DEFAULT NULL COMMENT '接收人',
`email_cc` varchar(500) DEFAULT NULL COMMENT '抄送人',
`email_type` varchar(10) DEFAULT NULL COMMENT '邮件类型',
`email_subject` varchar(255) DEFAULT NULL COMMENT '主题',
`email_content` longtext COMMENT '发送内容',
`sending_status` int(1) DEFAULT '0' COMMENT '发送状态',
`creator` char(36) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`modifier` char(36) DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
`is_delete` int(1) DEFAULT '0',
PRIMARY KEY (`id`,`email_id`),
KEY `email_id` (`email_id`),
KEY `email_sender` (`email_sender`),
KEY `email_receiver` (`email_receiver`),
KEY `sending_status` (`sending_status`),
KEY `is_delete` (`is_delete`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
</update>
<!-- 新增短信 -->
<insert id="save" parameterType="map">
INSERT INTO sms_email(
email_id,
email_sender,
email_receiver,
email_cc,
email_type,
email_subject,
email_content,
sending_status,
creator,
gmt_create,
modifier,
gmt_modified,
is_delete
) VALUES(
#{emailId},
#{emailSender},
#{emailReceiver},
#{emailCc},
#{emailType},
#{emailSubject},
#{emailContent},
#{sendingStatus},
#{creator},
#{gmtCreate},
#{modifier},
#{gmtModified},
#{isDelete}
)
</insert>
<!-- 删除短信 -->
<update id="remove" parameterType="map">
UPDATE
sms_email
SET
is_delete = 1,
modifier = #{modifier},
gmt_modified = #{gmtModified}
WHERE
email_id IN
<foreach collection="smsIds" index="index" open="(" separator="," close=")">
#{smsIds[${index}]}
</foreach>
</update>
<!-- 更新邮件发送状态 -->
<update id="updateSendingStatus" parameterType="map">
UPDATE
sms_email
SET
sending_status = #{sendingStatus}
WHERE
is_delete = 0
AND
email_id = #{emailId}
</update>
<!-- 短信详情 -->
<select id="get" parameterType="map" resultMap="emailDTO">
SELECT
t1.email_id,
t1.email_sender,
t1.email_receiver,
t1.email_cc,
t1.email_type,
t1.email_subject,
t1.email_content,
t1.sending_status,
t1.gmt_create
FROM
sms_email t1
WHERE
t1.is_delete = 0
<if test="emailId != null and emailId != ''">
AND
t1.email_id = #{emailId}
</if>
</select>
<!-- 短信列表 -->
<select id="list" parameterType="map" resultMap="emailDTO">
SELECT
t1.email_id,
t1.email_sender,
t1.email_receiver,
t1.email_cc,
t1.email_type,
t1.email_subject,
t1.email_content,
t1.sending_status,
t1.gmt_create
FROM
sms_email t1
WHERE
t1.is_delete = 0
<if test="keywords != null and keywords != ''">
AND (
t1.email_sender LIKE CONCAT('%', #{keywords}, '%')
OR
t1.email_receiver LIKE CONCAT('%', #{keywords}, '%')
OR
t1.email_cc LIKE CONCAT('%', #{keywords}, '%')
OR
t1.email_subject LIKE CONCAT('%', #{keywords}, '%')
)
</if>
<if test="startTime != null and startTime != ''">
AND
LEFT(t1.gmt_create, 10) <![CDATA[ >= ]]> #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND
LEFT(t1.gmt_create, 10) <![CDATA[ <= ]]> #{endTime}
</if>
<if test="smsIds != null and smsIds.size > 0">
AND
t1.email_id IN
<foreach collection="smsIds" index="index" open="(" separator="," close=")">
#{emailIds[${index}]}
</foreach>
</if>
</select>
</mapper>

View File

@ -0,0 +1,195 @@
<?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="ink.wgink.module.sms.dao.sms.ISmsDao">
<resultMap id="smsDTO" type="ink.wgink.module.sms.pojo.dtos.sms.SmsDTO">
<id column="sms_id" property="smsId"/>
<result column="phone" property="phone"/>
<result column="content" property="content"/>
<result column="send_status" property="sendStatus"/>
<result column="error_message" property="errorMessage"/>
</resultMap>
<resultMap id="smsPO" type="ink.wgink.module.sms.pojo.pos.sms.SmsPO">
<id column="sms_id" property="smsId"/>
<result column="phone" property="phone"/>
<result column="content" property="content"/>
<result column="send_status" property="sendStatus"/>
<result column="error_message" property="errorMessage"/>
<result column="gmt_create" property="gmtCreate"/>
</resultMap>
<!-- 建表 -->
<update id="createTable">
CREATE TABLE IF NOT EXISTS `sms_sms` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`sms_id` char(36) NOT NULL COMMENT '主键',
`phone` varchar(255) DEFAULT NULL COMMENT '电话',
`content` varchar(255) DEFAULT NULL COMMENT '发送内容',
`send_status` int(11) DEFAULT NULL COMMENT '发送状态',
`error_message` varchar(255) DEFAULT NULL COMMENT '错误信息',
`creator` char(36) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`modifier` char(36) DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
`is_delete` int(1) DEFAULT '0',
PRIMARY KEY (`id`,`sms_id`),
KEY `sms_id` (`sms_id`),
KEY `phone` (`phone`),
KEY `send_status` (`send_status`),
KEY `is_delete` (`is_delete`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
</update>
<!-- 新增短信 -->
<insert id="save" parameterType="map">
INSERT INTO sms_sms(
sms_id,
phone,
content,
send_status,
error_message,
creator,
gmt_create,
modifier,
gmt_modified,
is_delete
) VALUES(
#{smsId},
#{phone},
#{content},
#{sendStatus},
#{errorMessage},
#{creator},
#{gmtCreate},
#{modifier},
#{gmtModified},
#{isDelete}
)
</insert>
<!-- 删除短信 -->
<update id="remove" parameterType="map">
UPDATE
sms_sms
SET
is_delete = 1,
modifier = #{modifier},
gmt_modified = #{gmtModified}
WHERE
sms_id IN
<foreach collection="smsIds" index="index" open="(" separator="," close=")">
#{smsIds[${index}]}
</foreach>
</update>
<!-- 修改短信 -->
<update id="update" parameterType="map">
UPDATE
sms_sms
SET
<if test="phone != null and phone != ''">
phone = #{phone},
</if>
<if test="content != null and content != ''">
content = #{content},
</if>
<if test="sendStatus != null">
send_status = #{sendStatus},
</if>
<if test="errorMessage != null and errorMessage != ''">
error_message = #{errorMessage},
</if>
modifier = #{modifier},
gmt_modified = #{gmtModified}
WHERE
sms_id = #{smsId}
</update>
<!-- 短信详情 -->
<select id="get" parameterType="map" resultMap="smsDTO">
SELECT
t1.phone,
t1.content,
t1.send_status,
t1.error_message,
t1.sms_id
FROM
sms_sms t1
WHERE
t1.is_delete = 0
<if test="smsId != null and smsId != ''">
AND
t1.sms_id = #{smsId}
</if>
</select>
<!-- 短信详情 -->
<select id="getPO" parameterType="map" resultMap="smsPO">
SELECT
t1.phone,
t1.content,
t1.send_status,
t1.error_message,
t1.sms_id
FROM
sms_sms t1
WHERE
t1.is_delete = 0
<if test="smsId != null and smsId != ''">
AND
t1.sms_id = #{smsId}
</if>
</select>
<!-- 短信列表 -->
<select id="list" parameterType="map" resultMap="smsDTO">
SELECT
t1.phone,
t1.content,
t1.send_status,
t1.error_message,
t1.sms_id
FROM
sms_sms t1
WHERE
t1.is_delete = 0
<if test="keywords != null and keywords != ''">
AND (
t1.phone LIKE CONCAT('%', #{keywords}, '%')
OR
t1.content LIKE CONCAT('%', #{keywords}, '%')
)
</if>
<if test="startTime != null and startTime != ''">
AND
LEFT(t1.gmt_create, 10) <![CDATA[ >= ]]> #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND
LEFT(t1.gmt_create, 10) <![CDATA[ <= ]]> #{endTime}
</if>
<if test="smsIds != null and smsIds.size > 0">
AND
t1.sms_id IN
<foreach collection="smsIds" index="index" open="(" separator="," close=")">
#{smsIds[${index}]}
</foreach>
</if>
</select>
<!-- 短信列表 -->
<select id="listPO" parameterType="map" resultMap="smsPO">
SELECT
t1.phone,
t1.content,
t1.send_status,
t1.error_message,
t1.sms_id
FROM
sms_sms t1
WHERE
t1.is_delete = 0
</select>
</mapper>