ConmmonController层
@ApiOperation(value = "发送验证码V2")
@ApiImplicitParam(name = "param", value = "发送验证码参数", required = true, dataType = "SendCodeParam", paramType = "body")
@PostMapping("send_code/v2")
//@RequestHeader(Constant.LANGUAGE_HEADER) String language 语言功能并没有用上
public ResponseData<String> sendCodeV2(@RequestBody @Valid SendCodeParamV2 param, BindingResult bindingResult,
@RequestHeader(Constant.LANGUAGE_HEADER) String language) {
if (bindingResult.hasErrors()) {
return errorMsg(bindingResult);
}
boolean isEmail = false;
boolean isPhone = false;
//注意这里的ReUtil类是package cn.hutool.core.util;
if (ReUtil.isMatch(Constant.PHONE_REGEXP, param.getPhone())) {
isPhone = true;
}
if (ReUtil.isMatch(Constant.EMAIL_REGEXP, param.getPhone())) {
isEmail = true;
}
if (!isEmail && !isPhone) {
throw new BusinessException(ApiResult.PARAM_IS_ILLEGAL);
}
if(isPhone){
commonService.sendSms(param.getType(), param.getPhone(), null);
return ResponseData.okMsg("验证码已发送至" + StringUtils.overlay(param.getPhone(), "****", 3, 7) + "手机上");
}else {
commonService.sendEmailCode(param.getType(), param.getPhone(), null);
return ResponseData.okMsg("验证码已发送至" + StringUtils.overlay(param.getPhone(), "****", 3, 7) + "邮箱上");
}
}
ConmmonService层
发送短信功能:
@Override
public ApiResult sendSms(Integer type, String phone, Map<String, Object> templateParam) {
String sendCodePrefix;
Example example = Example.builder(User.class).andWhere(Sqls.custom().andEqualTo("username", phone).andEqualTo("deleted", false)).build();
User user = userMapper.selectOneByExample(example);
//通用的发送验证码的接口 不论数据库里面是否有用户 都有发送验证码的情况(没有用户:注册;有用户:修改密码忘记密码绑定手机号)
if (Objects.nonNull(user)) {
//发送短信的类型:目的是为了注册 那用户为空则已经注册
if (type.equals(SendCodeType.REGISTER.ordinal())) {
throw new BusinessException(ApiResult.USERNAME_IS_REGISTERED);
}
//用户注册过 但是被锁定
if (user.getStatus().equals(UserStatus.LOCKED.ordinal())) {
throw new BusinessException(ApiResult.BE_LOCKED);
}
if (type.equals(SendCodeType.FORGET_PWD.ordinal())) {
sendCodePrefix = RedisKeyPrefix.USER_FORGET_PWD_PREFIX + phone;
} else if (type.equals(SendCodeType.BIND.ordinal())) {
// 手机号被绑定,无法发送
Example userAuthExample = Example.builder(UserAuth.class).where(Sqls.custom().andEqualTo("userId", user.getId())).build();
if (userAuthMapper.selectCountByExample(userAuthExample) > 0) {
throw new BusinessException(ApiResult.USER_AUTH_BIND);
}
sendCodePrefix = RedisKeyPrefix.USER_BIND_PHONE_PREFIX + phone;
} else {
sendCodePrefix = RedisKeyPrefix.USER_UPDATE_PREFIX + phone;
}
} else {
//用户为空
if (type.equals(SendCodeType.FORGET_PWD.ordinal())) {
throw new BusinessException(ApiResult.USERNAME_IS_NOT_EXIST);
} else if (type.equals(SendCodeType.BIND.ordinal())) {
sendCodePrefix = RedisKeyPrefix.USER_BIND_PHONE_PREFIX + phone;
} else {
sendCodePrefix = RedisKeyPrefix.USER_REGISTER_PREFIX + phone;
}
}
if (templateParam == null) {
//设置初始容量
templateParam = new HashMap<>(2);
}
Long nowTime = System.currentTimeMillis();
String code;
List<Object> list = redisTemplate.boundHashOps(sendCodePrefix).multiGet(Arrays.asList(CODE, "lastSendTime"));
if (Objects.isNull(list.get(0)) || Objects.isNull(list.get(1))) {
code = getSixRandom();
Map<String, Object> map = ImmutableMap.of(CODE, code, "lastSendTime", String.valueOf(nowTime));
redisTemplate.opsForHash().putAll(sendCodePrefix, map);
} else {
Long lastSendTime = Long.valueOf((String) list.get(1));
// 一分钟发送一次
if (nowTime - lastSendTime < 60000L) {
throw new BusinessException(ApiResult.SEND_SMS_FREQUENTLY);
}
redisTemplate.opsForHash().put(sendCodePrefix, "lastSendTime", String.valueOf(nowTime));
code = (String) redisTemplate.opsForHash().get(sendCodePrefix, CODE);
}
// 5分钟后失效
redisTemplate.expireAt(sendCodePrefix, DateUtils.addMinutes(new Date(), 5));
templateParam.put(CODE, code);
List<String> phoneList = new ArrayList<>();
phoneList.add(phone);
//调用sdk
String result = smsCore.send("智能炒锅", SendCodeType.values()[type].getTemplateCode(), templateParam, phoneList, null);
if (result != null) {
return ApiResult.SUCCESS;
} else {
throw new BusinessException(ApiResult.SEND_MAX_SMS);
}
}
@Override
public ApiResult sendEmailCode(Integer type, String email, Map<String, Object> templateParam) {
String sendCodePrefix;
Example example =Example.builder(User.class).andWhere(Sqls.custom().andEqualTo("email",email).andEqualTo("deleted",false)).build();
User user = userMapper.selectOneByExample(example);
if(Objects.nonNull(user)){
//发送短信的类型:目的是为了注册 那用户为空则已经注册
if (type.equals(SendCodeType.REGISTER.ordinal())) {
throw new BusinessException(ApiResult.USERNAME_IS_REGISTERED);
}
//用户注册过 但是被锁定
if (user.getStatus().equals(UserStatus.LOCKED.ordinal())) {
throw new BusinessException(ApiResult.BE_LOCKED);
}
if (type.equals(SendCodeType.FORGET_PWD.ordinal())) {
sendCodePrefix = RedisKeyPrefix.USER_FORGET_PWD_PREFIX + email;
} else if (type.equals(SendCodeType.BIND.ordinal())) {
// 手机号被绑定,无法发送
Example userAuthExample = Example.builder(UserAuth.class).where(Sqls.custom().andEqualTo("userId", user.getId())).build();
if (userAuthMapper.selectCountByExample(userAuthExample) > 0) {
throw new BusinessException(ApiResult.USER_AUTH_BIND);
}
sendCodePrefix = RedisKeyPrefix.USER_BIND_PHONE_PREFIX + email;
} else {
sendCodePrefix = RedisKeyPrefix.USER_UPDATE_PREFIX + email;
}
}else {
//用户为空
if (type.equals(SendCodeType.FORGET_PWD.ordinal())) {
throw new BusinessException(ApiResult.USERNAME_IS_NOT_EXIST);
} else if (type.equals(SendCodeType.BIND.ordinal())) {
sendCodePrefix = RedisKeyPrefix.USER_BIND_PHONE_PREFIX + email;
} else {
sendCodePrefix = RedisKeyPrefix.USER_REGISTER_PREFIX + email;
}
}
if (templateParam == null) {
//设置初始容量
templateParam = new HashMap<>(2);
}
Long nowTime = System.currentTimeMillis();
String code;
List<Object> list = redisTemplate.boundHashOps(sendCodePrefix).multiGet(Arrays.asList(CODE, "lastSendTime"));
if (Objects.isNull(list.get(0)) || Objects.isNull(list.get(1))) {
code = getSixRandom();
Map<String, Object> map = ImmutableMap.of(CODE, code, "lastSendTime", String.valueOf(nowTime));
redisTemplate.opsForHash().putAll(sendCodePrefix, map);
} else {
Long lastSendTime = Long.valueOf((String) list.get(1));
// 一分钟发送一次
// if (nowTime - lastSendTime < 60000L) {
// throw new BusinessException(ApiResult.SEND_SMS_FREQUENTLY);
// }
redisTemplate.opsForHash().put(sendCodePrefix, "lastSendTime", String.valueOf(nowTime));
code = (String) redisTemplate.opsForHash().get(sendCodePrefix, CODE);
}
// 5分钟后失效
redisTemplate.expireAt(sendCodePrefix, DateUtils.addMinutes(new Date(), 5));
templateParam.put(CODE, code);
//调用发送邮件接口
String result = emailService.sendCodeMail(email, code, "5", type, "zh");
if(result!=null){
return ApiResult.SUCCESS;
}
return ApiResult.BUSINESS_FAIL;
}
发送邮件EmailService
@Override
public String sendCodeMail(String email, String code, String minute, Integer type, String language) {
String result = null;
if (type.equals(SendCodeType.REGISTER.ordinal())) {
result = sendRegisteredMail(email, code, minute, type, language);
}
if (type.equals(SendCodeType.UPDATE_PWS.ordinal())) {
result = sendUpdatePwdMail(email, code, minute, type, language);
}
if (type.equals(SendCodeType.FORGET_PWD.ordinal())) {
result = sendUpdatePwdMail(email, code, minute, type, language);
}
if (Objects.isNull(result)) {
throw new BusinessException(ApiResult.FAILED_TO_SEND_MAIL);
}
return result;
}
String sendUpdatePwdMail(String email, String code, String minute, Integer type, String language) {
boolean ch = FeiyueUtils.languageIsCh(language);
StringBuilder content = new StringBuilder();
if (ch) {
content.append("您正在尝试修改登录密码,验证码为:[").
append(code).
append("],有效期为[").
append(minute).
append("分钟],请妥善保管账户信息!");
String bzId = MailUtil.send(mailAccount, email, "密码修改", content.toString(), false);
log.info("\n----------发送邮件成功,业务编号:{}", bzId);
if (StrUtil.isNotBlank(bzId)) {
return "验证码已发送至" + email + "邮箱上";
}
}
content.append("You are trying to modify the login password, the verification code is: [").
append(code).
append("], the validity period is[").
append(minute).
append(" minutes],please keep your account information properly!");
String bzId = MailUtil.send(mailEnAccount, email, "ChangePassword", content.toString(), false);
if (StrUtil.isNotBlank(bzId)) {
return "The verification code has been sent to the " + email + " mailbox";
}
return null;
}
String sendRegisteredMail(String email, String code, String minute, Integer type, String language) {
boolean ch = FeiyueUtils.languageIsCh(language);
StringBuilder content = new StringBuilder();
if (ch) {
content.append("您正在注册成为智能炒锅新用户,验证码为:[").
append(code).
append("],有效期为[").
append(minute).
append("分钟],感谢您的支持!");
String bzId = MailUtil.send(mailAccount, email, "注册验证", content.toString(), false);
log.info("\n----------发送邮件成功,业务编号:{}", bzId);
if (StrUtil.isNotBlank(bzId)) {
return "验证码已发送至" + email + "邮箱上";
}
}
content.append("You are registering as a new WorldValue user, the verification code is: [").
append(code).
append("], the validity period is [").
append(minute).
append(" minutes],thank you for your support!");
String bzId = MailUtil.send(mailEnAccount, email, "RegistrationVerification", content.toString(), false);
log.info("\n----------发送邮件成功,业务编号:{}", bzId);
if (StrUtil.isNotBlank(bzId)) {
return "The verification code has been sent to the " + email + " mailbox";
}
return null;
}
package com.zskj.smart_wok.service.properties;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.extra.mail.MailAccount;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
/**
* @author dongyao
* @date 2020/12/15 15:40
*/
@Getter
@Setter
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "service.email")
@EnableConfigurationProperties(ServiceEmailProperties.class)
public class ServiceEmailProperties{
/**
* # 邮件服务器的SMTP地址,可选,默认为smtp.<发件人邮箱后缀>
* host = c1.icoremail.net
* # 邮件服务器的SMTP端口,可选,默认25
* port = 25
* # 发件人(必须正确,否则发送失败)
* from = *********
* user =
* # 密码(注意,某些邮箱需要为SMTP服务单独设置授权码,详情查看相关帮助)
* # pass = FbMjkjbNwa5RPdbj
* pass = Kg2W3h5UT0%0!Pm=
* # 使用SSL安全连接
* # sslEnable = true
*/
private String host;
private Integer port;
private String from;
private String fromEn;
private String fromInfo;
private String user;
private String pass;
private Boolean auth;
private Boolean sslEnable;
private Long timeout;
private Long connectionTimeout;
private String socketFactoryClass;
private Boolean socketFactoryFallback;
private Integer socketFactoryPort;
@PostConstruct
@Bean(name = "mailAccount")
public MailAccount mailAccount() {
log.info("\n-------初始化mailAccount");
MailAccount account = new MailAccount();
account.setHost(this.host);
account.setPort(this.port);
account.setFrom(this.from);
account.setUser(this.user);
account.setPass(this.pass);
account.setAuth(this.auth);
account.setSslEnable(this.sslEnable);
account.setTimeout(this.timeout);
account.setConnectionTimeout(this.connectionTimeout);
account.setStarttlsEnable(true);
// account.setSocketFactoryClass(this.socketFactoryClass);
// account.setSocketFactoryFallback(this.socketFactoryFallback);
// account.setSocketFactoryPort(this.socketFactoryPort);
return account;
}
@PostConstruct
@Bean(name = "mailEnAccount")
public MailAccount mailEnAccount() {
log.info("\n-------初始化mailEnAccount");
MailAccount account = new MailAccount();
account.setHost(this.host);
account.setPort(this.port);
account.setFrom(this.fromEn);
account.setUser(this.user);
account.setPass(this.pass);
account.setAuth(this.auth);
account.setSslEnable(this.sslEnable);
account.setTimeout(this.timeout);
account.setConnectionTimeout(this.connectionTimeout);
account.setStarttlsEnable(true);
// account.setSocketFactoryClass(this.socketFactoryClass);
// account.setSocketFactoryFallback(this.socketFactoryFallback);
// account.setSocketFactoryPort(this.socketFactoryPort);
return account;
}
@PostConstruct
@Bean(name = "mailInfoAccount")
public MailAccount mailInfoAccount() {
log.info("\n-------初始化mailInfoAccount");
MailAccount account = new MailAccount();
account.setHost(this.host);
account.setPort(this.port);
account.setFrom(this.fromInfo);
account.setUser(this.user);
account.setPass(this.pass);
account.setAuth(this.auth);
account.setSslEnable(this.sslEnable);
account.setTimeout(this.timeout);
account.setConnectionTimeout(this.connectionTimeout);
account.setStarttlsEnable(true);
// account.setSocketFactoryClass(this.socketFactoryClass);
// account.setSocketFactoryFallback(this.socketFactoryFallback);
// account.setSocketFactoryPort(this.socketFactoryPort);
return account;
}
}
spring.profiles.active=dev
spring.jackson.default-property-inclusion=non_null
spring.jackson.time-zone=GMT+8
#freemarker
spring.freemarker.suffix=.html
spring.freemarker.content-type=text/html
spring.freemarker.template-loader-path=classpath:/templates/
spring.freemarker.charset=utf-8
spring.freemarker.checkTemplateLocation=true
mybatis.config-location=classpath:mybatis-config.xml
mybatis.mapper-locations=classpath:mapper/*.xml
wx.app-id=wxb989b47d3af39aca
wx.app-secret=1486b350bfa4a5b7e2705cd1ff31159e
spring.messages.basename=static/i18n/messages
# 邮件服务器的SMTP地址,可选,默认为smtp.<发件人邮箱后缀>
service.email.host=smtp.qq.com
# 邮件服务器的SMTP端口,可选,默认25
service.email.port=465
# 发件人(必须正确,否则发送失败)
service.email.from=xxxx<11*****11@qq.com>
service.email.from-info=xxxx<11******11@qq.com>
service.email.from-en=WorldValueUserService<11*******11@qq.com>
# 用户名,默认为发件人邮箱前缀
service.email.user=11*****11
# 密码(注意,某些邮箱需要为SMTP服务单独设置授权码,详情查看相关帮助)
service.email.pass=lxbtxlyoycboifjf
service.email.ssl-enable=true
service.email.auth=true
service.email.timeout=25000
service.email.connection-timeout=25000
service.email.socket-factory-class=javax.net.ssl.SSLSocketFactory
#service.email.socket-factory-fallback=false
#service.email.socket-factory-port=465