JAVA邮箱绑定链接激活验证
1:业务控制类
@RestController
@RequestMapping("/v2/yuan/my")
public class YuanMyApi extends BaseController {
@Autowired
private YuanMailRecordingService yuanMailRecordingService;
@Autowired
private ISysUserService sysUserService;
@ApiOperation("邮箱绑定")
@ApiImplicitParams({
@ApiImplicitParam(name = "email", value = "邮箱账号", dataType = "string", paramType = "query", required = true)
})
@PostMapping("/relateEmail")
public AjaxResult relateEmail(String email, String token) {
Long userId = JwtUtils.getUserId(token);
if (userId == null) {
return AjaxResult.fail("登录错误").code(401).build();
}
SysUser sysUser = ShiroUtils.getSysUser();
if (!sysUser.getEmail().isEmpty()) {
return AjaxResult.ok("邮箱已绑定").build();
}
//邮件内容 邮箱+随机uuid的方式组成激活链接
String link = email + UUID.randomUUID().toString().toLowerCase();
boolean b;
b = yuanMailRecordingService.htmlEmail(email, link);
if (!b) {
return AjaxResult.success("邮件发送失败");
}
LocalDateTime expireTime = LocalDateTime.now().plusMinutes(5);
YuanMailRecording yuanMailRecording = YuanMailRecording.builder()
.userId(sysUser.getUserId())
.mail(email)
.link(link)
.expireTime(expireTime)
.status(0)
.build();
boolean save = yuanMailRecordingService.save(yuanMailRecording);
return AjaxResult.ok().result(save).build();
}
@GetMapping("/checkLink")
public AjaxResult checkLink(String link) {
YuanMailRecording mailRecording = yuanMailRecordingService.getOne(
new LambdaQueryWrapper<YuanMailRecording>().eq(StringUtils.isNotBlank(link), YuanMailRecording::getLink, link));
if (mailRecording == null) {
return AjaxResult.ok("激活失败").build();
}
if (mailRecording.getExpireTime().isBefore(LocalDateTime.now())) {
return AjaxResult.ok("激活链接已过期").build();
}
//激活成功更改表里状态为1
mailRecording.setStatus(1);
//激活成功则删除link字段数据
mailRecording.setLink("");
boolean update = yuanMailRecordingService.updateById(mailRecording);
SysUser sysUser = sysUserService.selectUserById(mailRecording.getUserId());
sysUser.setEmail(mailRecording.getMail());
sysUserService.updateUser(sysUser);
return AjaxResult.ok("激活成功").result(update).build();
}
}

2:操作类
package com.ruoyi.common.core.domain;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.common.utils.StringUtils;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 操作消息提醒
*
* @author ruoyi
*/
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
/** 状态码 */
public static final String CODE_TAG = "code";
/** 返回内容 */
public static final String MSG_TAG = "msg";
/** 数据对象 */
public static final String DATA_TAG = "data";
/**
* 时间戳
*/
public static final String TIMESTAMP_TAG = "timestamp";
/**
* 状态类型
*/
public enum Type
{
/** 成功 */
SUCCESS(0),
/** 警告 */
WARN(301),
/** 错误 */
ERROR(500);
private final int value;
Type(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult()
{
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param type 状态类型
* @param msg 返回内容
*/
public AjaxResult(Type type, String msg)
{
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param type 状态类型
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(Type type, String msg, Object data)
{
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
if (StringUtils.isNotNull(data))
{
super.put(DATA_TAG, data);
}
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success()
{
return AjaxResult.success("操作成功");
}
/**
* 返回成功数据
*
* @return 成功消息
*/
public static AjaxResult success(Object data)
{
return AjaxResult.success("操作成功", data);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult success(String msg)
{
return AjaxResult.success(msg, null);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data)
{
return new AjaxResult(Type.SUCCESS, msg, data);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult warn(String msg)
{
return AjaxResult.warn(msg, null);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult warn(String msg, Object data)
{
return new AjaxResult(Type.WARN, msg, data);
}
/**
* 返回错误消息
*
* @return
*/
public static AjaxResult error()
{
return AjaxResult.error("操作失败");
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult error(String msg)
{
return AjaxResult.error(msg, null);
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult error(String msg, Object data)
{
return new AjaxResult(Type.ERROR, msg, data);
}
private AjaxResult(Map<String, Object> propertiesMap) {
for(Map.Entry<String, Object> entry : propertiesMap.entrySet()){
this.put(entry.getKey(), entry.getValue());
}
}
public static RetBuild ok(){
return getBuild().ok();
}
public static RetBuild ok(String msg){
return getBuild().ok(msg);
}
public static RetBuild fail(){
return getBuild().fail();
}
public static RetBuild fail(String msg){
return getBuild().fail(msg);
}
public static RetBuild getBuild(){
return new RetBuild();
}
public static class RetBuild {
private static final String RESULT_TAG = "result";
private static final String LIST_TAG = "list";
private Map<String, Object> propertiesMap = new HashMap<String, Object>();
private Map<String, Object> dataMap = new HashMap<>();
public RetBuild ok() {
propertiesMap.put(CODE_TAG, Type.SUCCESS.value);
propertiesMap.put(MSG_TAG, "操作成功");
return this;
}
public RetBuild ok(String msg) {
propertiesMap.put(CODE_TAG, Type.SUCCESS.value);
propertiesMap.put(MSG_TAG, msg);
return this;
}
public RetBuild code(int code){
propertiesMap.put(CODE_TAG, code);
return this;
}
public RetBuild fail() {
propertiesMap.put(CODE_TAG, Type.ERROR.value);
propertiesMap.put(MSG_TAG, "操作失败");
return this;
}
public RetBuild fail(String msg) {
propertiesMap.put(CODE_TAG, Type.ERROR.value);
propertiesMap.put(MSG_TAG, msg);
return this;
}
public RetBuild result(boolean result) {
propertiesMap.put(RESULT_TAG, result);
return this;
}
public RetBuild data(Object data) {
propertiesMap.put(DATA_TAG, data);
return this;
}
public RetBuild list(Collection<?> collection) {
propertiesMap.put(LIST_TAG, collection);
return this;
}
public RetBuild page(IPage<?> page, List<?> list){
propertiesMap.put("total", page.getTotal());
propertiesMap.put("rows", list);
propertiesMap.put("pages", page.getPages());
propertiesMap.put("current", page.getCurrent());
propertiesMap.put("size", page.getSize());
return this;
}
public RetBuild page(IPage<?> page){
propertiesMap.put("total", page.getTotal());
propertiesMap.put("rows", page.getRecords());
propertiesMap.put("pages", page.getPages());
propertiesMap.put("current", page.getCurrent());
propertiesMap.put("size", page.getSize());
return this;
}
public RetBuild proPut(String key, Object value) {
propertiesMap.put(key, value);
return this;
}
public RetBuild put(String key, Object value) {
dataMap.put(key, value);
return this;
}
public RetBuild put(Map<String, Object> map) {
dataMap.putAll(map);
return this;
}
public AjaxResult build() {
if (StringUtils.isNotEmpty(dataMap)){
propertiesMap.put(DATA_TAG, dataMap);
}
propertiesMap.put(TIMESTAMP_TAG, System.currentTimeMillis());
return new AjaxResult(propertiesMap);
}
}
}

3:权限验证工具类
package com.ruoyi.framework.jwt.utils;
import java.util.Date;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
/**
* jwt 工具类
*
* @author Licl
*/
public class JwtUtils {
private static final long EXPIRE_TIME = 30 * 60 * 1000;
private static final String CLAIM_NAME = "username";
private static final String CLAIM_ID = "userId";
public static String createToken(Long userId, String username, String password) {
return createToken(userId, username, password, EXPIRE_TIME);
}
public static String createToken(Long userId, String username, String password, long expireTime) {
Date date = new Date(System.currentTimeMillis() + expireTime);
// 加密处理密码
Algorithm algorithm = Algorithm.HMAC256(password);
return JWT.create()
.withClaim(CLAIM_NAME, username)
.withClaim(CLAIM_ID, userId)
.withExpiresAt(date).sign(algorithm);
}
public static void verify(String username, String dbPwd, String token)
{
Algorithm algorithm = Algorithm.HMAC256(dbPwd);
JWTVerifier jwtVerifier = JWT.require(algorithm).withClaim(CLAIM_NAME, username).build();
try
{
jwtVerifier.verify(token);
}
catch (TokenExpiredException e)
{
throw new TokenExpiredException("token已过期");
}
catch (JWTVerificationException e)
{
throw new JWTVerificationException("token验证失败");
}
}
public static String getUserName(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim(CLAIM_NAME).asString();
} catch (JWTDecodeException e) {
return null;
}
}
public static Long getUserId(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim(CLAIM_ID).asLong();
} catch (JWTDecodeException e) {
return null;
}
}
}

4:服务层接口
package com.ruoyi.yuan.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.yuan.domain.YuanMailRecording;
import org.springframework.web.multipart.MultipartFile;
/**
* 邮箱验证记录表(YuanMailRecording)表服务接口
*
* @author JingLing
* @since 2021-12-16 13:49:11
*/
public interface YuanMailRecordingService extends IService<YuanMailRecording> {
/**
* 发送普通邮件 (无其他资源 无html 无附件)
*
* @param email 发送对象
*/
boolean commonEmail(String email, String link);
/**
* 发送html形式的邮件
*
* @param email 发送对象
* @param link 激活链接
* @return 统一返回ajax
*/
boolean htmlEmail(String email, String link);
/**
* 带附件 邮件发送
*/
void enclosureEmail(YuanMailRecording yuanMailRecording, MultipartFile multipartFile);
}

5:接口实现类
package com.ruoyi.yuan.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.yuan.mapper.YuanMailRecordingMapper;
import com.ruoyi.yuan.domain.YuanMailRecording;
import com.ruoyi.yuan.service.YuanMailRecordingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.mail.internet.MimeMessage;
import java.io.File;
/**
* 邮箱验证记录表(YuanMailRecording)表服务实现类
*
* @author JingLing
* @since 2021-12-16 13:49:11
*/
@Service
@Slf4j
public class YuanMailRecordingServiceImpl extends ServiceImpl<YuanMailRecordingMapper, YuanMailRecording> implements YuanMailRecordingService {
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String from;
@Value("${spring.mail.request}")
private String request;
/**
* 发送普通邮件
*
* @param email 发送对象
*/
@Override
public boolean commonEmail(String email, String link) {
//创建简单邮件消息
SimpleMailMessage message = new SimpleMailMessage();
//谁发的
message.setFrom(from);
//接收方
message.setTo(email);
//激活链接
message.setText(link);
try {
mailSender.send(message);
log.info("邮件发送成功");
return true;
} catch (MailException e) {
e.printStackTrace();
log.error("邮件发送失败");
return false;
}
}
/**
* 发送html邮件
*
* @param email 发送对象
* @param link 激活链接
*/
@Override
public boolean htmlEmail(String email, String link) {
MimeMessage mimeMessage = mailSender.createMimeMessage();
try {
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
//邮件内容
StringBuilder sb = new StringBuilder();
sb.append("<html><head></head><body>");
sb.append("<a href=").append(request).append("v2/yuan/my/checkLink?link=");
sb.append(link);
sb.append(">点击激活</a></body>");
messageHelper.setFrom(from);
messageHelper.setTo(email);
messageHelper.setSubject("一封激活邮件");
messageHelper.setText(sb.toString(), true);
mailSender.send(mimeMessage);
log.info("HTML邮件成功");
return true;
} catch (javax.mail.MessagingException e) {
e.printStackTrace();
}
log.error("HTML邮件发送失败");
return false;
}
/**
* 带附件邮件发送
*/
@Override
public void enclosureEmail(YuanMailRecording yuanMailRecording, MultipartFile multipartFile) {
//创建一个MINE消息
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message, true);
//谁发
helper.setFrom(from);
//谁接收
helper.setTo(yuanMailRecording.getMail());
//邮件内容 true 表示带有附件或html
helper.setText(yuanMailRecording.getLink(), true);
File multipartFileToFile = multipartFileToFile(multipartFile);
assert multipartFileToFile != null;
FileSystemResource file = new FileSystemResource(multipartFileToFile);
String filename = file.getFilename();
//添加附件
assert filename != null;
helper.addAttachment(filename, file);
mailSender.send(message);
log.info("邮件成功", yuanMailRecording.getMail() + yuanMailRecording.getLink());
} catch (javax.mail.MessagingException e) {
e.printStackTrace();
log.error("附件邮件发送失败" + e.getMessage());
}
}
/**
* 将 multpartfile 转为file
*
* @return file
*/
private File multipartFileToFile(MultipartFile multiFile) {
// 获取文件名
String fileName = multiFile.getOriginalFilename();
// 获取文件后缀
assert fileName != null;
String prefix = fileName.substring(fileName.lastIndexOf("."));
// 若需要防止生成的临时文件重复,可以在文件名后添加随机码
try {
File file = File.createTempFile(fileName, prefix);
multiFile.transferTo(file);
return file;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

浙公网安备 33010602011771号