1.添加邮箱登录,注册接口
This commit is contained in:
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
Binary file not shown.
44
pom.xml
44
pom.xml
@@ -1,5 +1,5 @@
|
||||
<?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"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.vv.pk.assistant</groupId>
|
||||
@@ -102,6 +102,48 @@
|
||||
<version>5.6.227</version>
|
||||
</dependency>
|
||||
|
||||
<!-- mailgun 邮件服务 -->
|
||||
<dependency>
|
||||
<groupId>com.mailgun</groupId>
|
||||
<artifactId>mailgun-java</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- caffeine 本地缓存 -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.9.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- crypto 加密 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-crypto</artifactId>
|
||||
<version>5.5.1</version> <!-- 请检查最新版本 -->
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.44.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- hu-tool -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.38</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
22
src/main/java/vvpkassistant/Tools/BcryptUtils.java
Normal file
22
src/main/java/vvpkassistant/Tools/BcryptUtils.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package vvpkassistant.Tools;
|
||||
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 18:19
|
||||
*/
|
||||
public class BcryptUtils {
|
||||
|
||||
|
||||
|
||||
public static String encryptPassword(String password) {
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.encode(password);
|
||||
}
|
||||
|
||||
public static Boolean matchPassword(String rawPassWord,String encodePassword){
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.matches(encodePassword, rawPassWord);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
package vvpkassistant.User.controller;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import vvpkassistant.CoinRecords.CoinRecords;
|
||||
@@ -7,16 +8,23 @@ import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.Data.WxChatParam;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.User.model.DTO.UserModelDTO;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.User.model.UserModelVO;
|
||||
import vvpkassistant.User.service.UserService;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.config.FunctionConfigHolder;
|
||||
import vvpkassistant.Tools.VVRequester;
|
||||
import vvpkassistant.Tools.VVTools;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.mail.model.MailModel;
|
||||
import vvpkassistant.mail.service.MailService;
|
||||
import vvpkassistant.pk.mapper.PkInfoDao;
|
||||
import vvpkassistant.pk.model.PkInfoModel;
|
||||
import vvpkassistant.pk.model.PkRecordDetail;
|
||||
import vvpkassistant.pk.mapper.PkRecordDetailDao;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -43,6 +51,10 @@ public class UserController {
|
||||
@Autowired
|
||||
private VVRequester vvRequester;
|
||||
|
||||
|
||||
@Resource
|
||||
private UserService userService;
|
||||
|
||||
// 配置用户信息
|
||||
@PostMapping("inputUserInfo")
|
||||
public ResponseData<Object> inputUserInfo(@RequestBody Map<String,Object> param) {
|
||||
@@ -165,29 +177,12 @@ public class UserController {
|
||||
|
||||
}
|
||||
|
||||
//todo 修改用户返回结果
|
||||
|
||||
// 修改用户信息
|
||||
@PostMapping("updateUserInfo")
|
||||
public ResponseData<Object> updateUserInfo(@RequestBody Map<String,Object> map) {
|
||||
UserModel userModel = new UserModel();
|
||||
//设置用户id
|
||||
userModel.setId(Integer.valueOf(map.get("id").toString()));
|
||||
//设置用户头像
|
||||
userModel.setHeaderIcon(map.get("headerIcon").toString());
|
||||
//设置用户昵称
|
||||
userModel.setNickName(map.get("nickName").toString());
|
||||
|
||||
int i = userDao.updateById(userModel);
|
||||
// 返回结果
|
||||
Map<String,Object> result = new HashMap<>();
|
||||
result.put("info", userDao.selectById(map.get("id").toString()));
|
||||
result.put("newAccount", false);
|
||||
if (i == 1){
|
||||
return ResponseData.success(result);
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
public ResponseData<Object> updateUserInfo(@RequestBody UserModelDTO userModelDTO) {
|
||||
UserModelVO userModelVO = userService.updateUserInfo( userModelDTO);
|
||||
return ResponseData.success(userModelVO);
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
@@ -367,5 +362,13 @@ public class UserController {
|
||||
return ResponseData.success(coinRecords);
|
||||
}
|
||||
|
||||
@PostMapping("/loginWithMail")
|
||||
public ResponseData<Object> loginWithMail(@RequestBody UserModelDTO model) {
|
||||
return ResponseData.success(userService.loginWithMail(model));
|
||||
}
|
||||
|
||||
@PostMapping("/registerWithMail")
|
||||
public ResponseData<Object> mailRegister(@RequestBody UserModelDTO model){
|
||||
return ResponseData.success(userService.addUserWithMail(model));
|
||||
}
|
||||
}
|
||||
|
||||
28
src/main/java/vvpkassistant/User/model/DTO/UserModelDTO.java
Normal file
28
src/main/java/vvpkassistant/User/model/DTO/UserModelDTO.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package vvpkassistant.User.model.DTO;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
|
||||
public class UserModelDTO {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id; // 主键
|
||||
private String nickName; // 昵称
|
||||
private String phoneNumber; // 手机号码
|
||||
private String headerIcon; // 头像
|
||||
private String openid; // openid
|
||||
private String sessionKey; // session key
|
||||
private Integer status; // 用户状态 0 正常 其他业务逻辑待定
|
||||
private Long createTime; // 创建时间
|
||||
private String userChatId; // 聊天使用的id,使用微信的openid作为标识
|
||||
private Integer points; // 用户积分
|
||||
private Integer inviterId; // 邀请人id
|
||||
private String email;
|
||||
private String newPassword;
|
||||
private String oldPassword;
|
||||
private String password;
|
||||
|
||||
}
|
||||
@@ -20,4 +20,7 @@ public class UserModel {
|
||||
private String userChatId; // 聊天使用的id,使用微信的openid作为标识
|
||||
private Integer points; // 用户积分
|
||||
private Integer inviterId; // 邀请人id
|
||||
private String email;
|
||||
private String password;
|
||||
|
||||
}
|
||||
|
||||
26
src/main/java/vvpkassistant/User/model/UserModelVO.java
Normal file
26
src/main/java/vvpkassistant/User/model/UserModelVO.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package vvpkassistant.User.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import vvpkassistant.Data.WxChatParam;
|
||||
|
||||
@Data
|
||||
public class UserModelVO {
|
||||
private Integer id; // 主键
|
||||
private String nickName; // 昵称
|
||||
private String phoneNumber; // 手机号码
|
||||
private String headerIcon; // 头像
|
||||
private String openid; // openid
|
||||
private String sessionKey; // session key
|
||||
private Integer status; // 用户状态 0 正常 其他业务逻辑待定
|
||||
private Long createTime; // 创建时间
|
||||
private String userChatId; // 聊天使用的id,使用微信的openid作为标识
|
||||
private Integer points; // 用户积分
|
||||
private Integer inviterId; // 邀请人id
|
||||
private String email;
|
||||
private String token;
|
||||
private Boolean newAccount;
|
||||
private WxChatParam chatInfo;
|
||||
}
|
||||
20
src/main/java/vvpkassistant/User/service/UserService.java
Normal file
20
src/main/java/vvpkassistant/User/service/UserService.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package vvpkassistant.User.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import vvpkassistant.User.model.DTO.UserModelDTO;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.User.model.UserModelVO;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 16:19
|
||||
*/
|
||||
public interface UserService extends IService<UserModel> {
|
||||
UserModelVO loginWithMail(UserModelDTO model);
|
||||
|
||||
UserModelVO updateUserInfo(UserModelDTO userModelDTO);
|
||||
|
||||
UserModelVO addUserWithMail(UserModelDTO model);
|
||||
}
|
||||
128
src/main/java/vvpkassistant/User/service/UserServiceImpl.java
Normal file
128
src/main/java/vvpkassistant/User/service/UserServiceImpl.java
Normal file
@@ -0,0 +1,128 @@
|
||||
package vvpkassistant.User.service;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vvpkassistant.Data.WxChatParam;
|
||||
import vvpkassistant.Tools.BcryptUtils;
|
||||
import vvpkassistant.Tools.VVTools;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.User.model.DTO.UserModelDTO;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.User.model.UserModelVO;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.mail.model.MailModel;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 16:19
|
||||
*/
|
||||
@Service
|
||||
public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements UserService {
|
||||
|
||||
@Resource
|
||||
private UserDao userDao;
|
||||
|
||||
@Resource
|
||||
private WxChatParam wxChatParam;
|
||||
|
||||
@Override
|
||||
public UserModelVO loginWithMail(UserModelDTO model) {
|
||||
|
||||
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.eq(UserModel::getEmail,model.getEmail())
|
||||
.in(UserModel::getStatus, 0,2);
|
||||
|
||||
UserModel userModel = userDao.selectOne(lambdaQueryWrapper);
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
|
||||
String password = userModel.getPassword();
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(userModel, UserModelVO.class);
|
||||
if (BcryptUtils.matchPassword(password, model.getPassword())) {
|
||||
StpUtil.login(userModel.getId());
|
||||
userModelVO.setToken(StpUtil.getTokenValue());
|
||||
userModelVO.setChatInfo(wxChatParam);
|
||||
return userModelVO;
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.PASSWORD_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModelVO updateUserInfo(UserModelDTO userModelDTO) {
|
||||
|
||||
UserModel userInfo = userDao.selectById(userModelDTO.getId());
|
||||
if (userInfo == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
// 用户没有密码的情况下设置密码
|
||||
if (userInfo.getPassword() == null) {
|
||||
if (!userModelDTO.getNewPassword().isEmpty()){
|
||||
if (userModelDTO.getNewPassword().length()<6){
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
|
||||
}
|
||||
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
|
||||
}
|
||||
}
|
||||
// 用户有密码的情况下重新设置密码
|
||||
if (userInfo.getPassword() != null && userModelDTO.getOldPassword() != null) {
|
||||
if (BcryptUtils.matchPassword(userModelDTO.getOldPassword(), userInfo.getPassword())) {
|
||||
userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.PASSWORD_ERROR,"旧密码不正确");
|
||||
}
|
||||
}
|
||||
|
||||
UserModel userModel = new UserModel();
|
||||
BeanUtil.copyProperties(userModelDTO, userModel);
|
||||
int i = userDao.updateById(userModel);
|
||||
// 返回结果
|
||||
userDao.selectById(userModel.getId());
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(userModel, UserModelVO.class);
|
||||
userModelVO.setNewAccount(false);
|
||||
if (i == 1){
|
||||
return userModelVO;
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModelVO addUserWithMail(UserModelDTO model) {
|
||||
|
||||
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.eq(UserModel::getEmail,model.getEmail());
|
||||
UserModel userModel = userDao.selectOne(lambdaQueryWrapper);
|
||||
if (userModel != null) {
|
||||
throw new BusinessException(ErrorCode.MAIL_ALREADY_EXIST);
|
||||
}
|
||||
if (model.getPassword().length() < 6 ){
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
|
||||
}
|
||||
model.setPassword(BcryptUtils.encryptPassword(model.getPassword()));
|
||||
model.setCreateTime(VVTools.currentTimeStamp());
|
||||
//设置状态为正常
|
||||
model.setStatus(2);
|
||||
//设置积分为0
|
||||
model.setPoints(0);
|
||||
userDao.insert(BeanUtil.copyProperties(model, UserModel.class));
|
||||
// 判断用户是否为邀请用户
|
||||
if (model.getInviterId() != null) {
|
||||
UserModel oldUser = userDao.selectById(model.getInviterId());
|
||||
oldUser.setPoints(oldUser.getPoints() + 10);
|
||||
userDao.updateById(oldUser);
|
||||
}
|
||||
UserModelVO userModelVO = BeanUtil.copyProperties(model, UserModelVO.class);
|
||||
userModelVO.setNewAccount(true);
|
||||
userModelVO.setChatInfo(wxChatParam);
|
||||
return userModelVO;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,11 @@ public enum ErrorCode {
|
||||
WX_SYSTEM_BUSY(-1, "系统繁忙"),
|
||||
|
||||
/* =============== 登录/用户信息 =============== */
|
||||
WX_GET_USER_INFO_FAILED(50001, "获取用户信息失败,请稍后再试");
|
||||
WX_GET_USER_INFO_FAILED(50001, "获取用户信息失败,请稍后再试"),
|
||||
USER_DOES_NOT_EXIST(5002,"用户不存在"),
|
||||
MAIL_ALREADY_EXIST(5003,"邮箱已存在"),
|
||||
PASSWORD_ERROR(5004, "用户名或密码错误" ),
|
||||
TOKEN_INVALID(40400, "Token无效,请重新登录");
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
|
||||
69
src/main/java/vvpkassistant/config/SaTokenConfigure.java
Normal file
69
src/main/java/vvpkassistant/config/SaTokenConfigure.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package vvpkassistant.config;
|
||||
|
||||
import cn.dev33.satoken.fun.strategy.SaCorsHandleFunction;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
import cn.dev33.satoken.router.SaHttpMethod;
|
||||
import cn.dev33.satoken.router.SaRouter;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 注册Sa-Token的拦截器
|
||||
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns(getExcludePaths());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需要放行的路径
|
||||
*/
|
||||
private String[] getExcludePaths() {
|
||||
return new String[]{
|
||||
// Swagger & Knife4j 相关
|
||||
"/doc.html",
|
||||
"/webjars/**",
|
||||
"/swagger-resources/**",
|
||||
"/v2/api-docs",
|
||||
"/v3/api-docs",
|
||||
"/v3/api-docs/**",
|
||||
"/swagger-ui.html",
|
||||
"/swagger-ui/**",
|
||||
"/favicon.ico",
|
||||
// 你的其他放行路径,例如登录接口
|
||||
"/user/loginWithPhoneNumber",
|
||||
"/user/registerWithMail",
|
||||
"/user/loginWithMail"
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SaCorsHandleFunction corsHandle() {
|
||||
return (req, res, sto) -> {
|
||||
res.
|
||||
// 允许指定域访问跨域资源
|
||||
setHeader("Access-Control-Allow-Origin", "*")
|
||||
// 允许所有请求方式
|
||||
.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
|
||||
// 有效时间
|
||||
.setHeader("Access-Control-Max-Age", "3600")
|
||||
// 允许的header参数
|
||||
.setHeader("Access-Control-Allow-Headers", "*");
|
||||
|
||||
// 如果是预检请求,则立即返回到前端
|
||||
SaRouter.match(SaHttpMethod.OPTIONS)
|
||||
.back();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package vvpkassistant.exception;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
@@ -28,6 +29,44 @@ public class GlobalExceptionHandler {
|
||||
log.error("RuntimeException", e);
|
||||
return ResponseData.error(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
// 全局异常拦截(拦截项目中的NotLoginException异常)
|
||||
@ExceptionHandler(NotLoginException.class)
|
||||
public ResponseData<?> handlerNotLoginException(NotLoginException nle)
|
||||
throws Exception {
|
||||
|
||||
// 打印堆栈,以供调试
|
||||
nle.printStackTrace();
|
||||
|
||||
// 判断场景值,定制化异常信息
|
||||
String message = "";
|
||||
if(nle.getType().equals(NotLoginException.NOT_TOKEN)) {
|
||||
message = "未能读取到有效用户令牌";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.INVALID_TOKEN)) {
|
||||
message = "令牌无效";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
|
||||
message = "令牌已过期";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.BE_REPLACED)) {
|
||||
message = "令牌已被顶下线";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.KICK_OUT)) {
|
||||
message = "令牌已被踢下线";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.TOKEN_FREEZE)) {
|
||||
message = "令牌已被冻结";
|
||||
}
|
||||
else if(nle.getType().equals(NotLoginException.NO_PREFIX)) {
|
||||
message = "未按照指定前缀提交令牌";
|
||||
}
|
||||
else {
|
||||
message = "当前会话未登录";
|
||||
}
|
||||
|
||||
// 返回给前端
|
||||
return ResponseData.error(ErrorCode.TOKEN_INVALID.getCode(),message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
13
src/main/java/vvpkassistant/mail/model/MailModel.java
Normal file
13
src/main/java/vvpkassistant/mail/model/MailModel.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package vvpkassistant.mail.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 15:48
|
||||
*/
|
||||
@Data
|
||||
public class MailModel {
|
||||
private String mailAddress;
|
||||
private Integer code;
|
||||
}
|
||||
11
src/main/java/vvpkassistant/mail/service/MailService.java
Normal file
11
src/main/java/vvpkassistant/mail/service/MailService.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package vvpkassistant.mail.service;
|
||||
|
||||
import vvpkassistant.mail.model.MailModel;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 15:42
|
||||
*/
|
||||
public interface MailService {
|
||||
Boolean sendMail(MailModel model);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package vvpkassistant.mail.service;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.mailgun.api.v3.MailgunMessagesApi;
|
||||
import com.mailgun.client.MailgunClient;
|
||||
import com.mailgun.model.message.Message;
|
||||
import com.mailgun.model.message.MessageResponse;
|
||||
import feign.AsyncClient;
|
||||
import feign.Client;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vvpkassistant.mail.model.MailModel;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2025/8/4 15:42
|
||||
*/
|
||||
@Service
|
||||
public class MailServiceImpl implements MailService {
|
||||
|
||||
@Value("${mailgun}")
|
||||
private String mailgunKey;
|
||||
|
||||
public final Cache<String, String> codeCache = Caffeine.newBuilder()
|
||||
.expireAfterWrite(10, TimeUnit.MINUTES) // 5 分钟过期
|
||||
.maximumSize(10_000) // 防止内存暴涨
|
||||
.build();
|
||||
|
||||
|
||||
@Override
|
||||
public Boolean sendMail(MailModel model) {
|
||||
ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||
AsyncClient.Default<Object> asyncClient = new AsyncClient.Default<>(
|
||||
new Client.Default(null, null), executor);
|
||||
|
||||
MailgunMessagesApi mailgunAsyncMessagesApi = MailgunClient.config(mailgunKey)
|
||||
.client(asyncClient)
|
||||
.createAsyncApi(MailgunMessagesApi.class);
|
||||
|
||||
Message message = Message.builder()
|
||||
.from("")
|
||||
.to(model.getMailAddress())
|
||||
.subject("your mail address Verification code is : ")
|
||||
.html("<html>\n" +
|
||||
"<body>\n" +
|
||||
"\t<h1>Sending HTML emails with Mailgun</h1>\n" +
|
||||
"\t<p style=\"color:blue; font-size:30px;\">Hello world</p>\n" +
|
||||
"\t<p style=\"font-size:30px;\">More examples can be found <a href=\"https://documentation.mailgun.com/en/latest/api-sending.html#examples\">here</a></p>\n" +
|
||||
"</body>\n" +
|
||||
"</html>")
|
||||
.build();
|
||||
|
||||
MessageResponse messageResponse = mailgunAsyncMessagesApi.sendMessage("www.baidu.com", message);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -7,3 +7,22 @@ spring:
|
||||
|
||||
|
||||
|
||||
mailgun: b4888f65c7fd452213f3a8aea9d88269-812b35f5-006d7fd6
|
||||
|
||||
|
||||
############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
|
||||
sa-token:
|
||||
# token 名称(同时也是 cookie 名称)
|
||||
token-name: token
|
||||
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
|
||||
timeout: 2592000
|
||||
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
|
||||
active-timeout: -1
|
||||
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
|
||||
is-share: false
|
||||
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
|
||||
token-style: random-128
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
|
||||
@@ -7,3 +7,22 @@ spring:
|
||||
|
||||
|
||||
|
||||
mailgun: b4888f65c7fd452213f3a8aea9d88269-812b35f5-006d7fd6
|
||||
|
||||
|
||||
############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
|
||||
sa-token:
|
||||
# token 名称(同时也是 cookie 名称)
|
||||
token-name: token
|
||||
# token 有效期(单位:秒) 默认30天,-1 代表永久有效
|
||||
timeout: 2592000
|
||||
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
|
||||
active-timeout: -1
|
||||
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
|
||||
is-share: false
|
||||
# token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
|
||||
token-style: random-128
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
|
||||
Reference in New Issue
Block a user