1.用户邮箱登录注册接口实现

This commit is contained in:
2025-08-05 15:16:03 +08:00
parent f5cbe5cac2
commit e0e733bc27
14 changed files with 326 additions and 62 deletions

25
.idea/MyBatisCodeHelperDatasource.xml generated Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MyBatisCodeHelperDatasource">
<option name="projectProfile">
<ProjectProfile>
<option name="controllerTemplateString" value="&#10;#* @vtlvariable name=&quot;tableName&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;entityPackageName&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;entityClassName&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;servicePackageName&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;serviceInterfacePackage&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;serviceClassName&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;serviceInterfaceClassName&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;mapperPackageName&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;mapperClassName&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;controllerPackage&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;tableRemark&quot; type=&quot;java.lang.String&quot; *#&#10;#* @vtlvariable name=&quot;myDate&quot; type=&quot;java.util.Date&quot; *#&#10;#* @vtlvariable name=&quot;simpleDateFormat&quot; type=&quot;java.text.SimpleDateFormat&quot; *#&#10;package $!{controllerPackage};&#10;import $!{entityPackageName}.$!{entityClassName};&#10;###set($realServiceName = $!{serviceClassName}+'Impl')&#10;import $!{servicePackageName}.$!{serviceClassName};&#10;import org.springframework.web.bind.annotation.*;&#10;&#10;#set($serviceFirstLower = $!{serviceClassName.substring(0,1).toLowerCase()}+$!{serviceClassName.substring(1,$!{serviceClassName.length()})})&#10;import org.springframework.beans.factory.annotation.Autowired;&#10;&#10;/**&#10;* $!{tableRemark}($!{tableName})表控制层&#10;*&#10;* @author xxxxx&#10;*/&#10;@RestController&#10;@RequestMapping(&quot;/$!{tableName}&quot;)&#10;public class $!{entityClassName}Controller {&#10;/**&#10;* 服务对象&#10;*/&#10; @Autowired&#10; private $!{serviceClassName} $!{serviceFirstLower};&#10;&#10; /**&#10; * 通过主键查询单条数据&#10; *&#10; * @param id 主键&#10; * @return 单条数据&#10; */&#10; @GetMapping(&quot;selectOne&quot;)&#10; public $!{entityClassName} selectOne(Integer id) {&#10; return $!{serviceFirstLower}.selectByPrimaryKey(id);&#10; }&#10;&#10;}" />
<option name="tableGenerateConfigs">
<map>
<entry key="vv_assistant:user">
<value>
<TableGenerateConfig>
<option name="generatedKey" value="id" />
<option name="javaModelName" value="User" />
<option name="sequenceColumn" value="" />
<option name="sequenceId" value="" />
<option name="useActualColumnName" value="false" />
</TableGenerateConfig>
</value>
</entry>
</map>
</option>
</ProjectProfile>
</option>
</component>
</project>

View File

@@ -141,7 +141,11 @@
<version>5.8.38</version> <version>5.8.38</version>
</dependency> </dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
</dependencies> </dependencies>

View File

@@ -1,8 +1,10 @@
package vvpkassistant; package vvpkassistant;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication @SpringBootApplication
@EnableAsync
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {

View File

@@ -55,6 +55,9 @@ public class UserController {
@Resource @Resource
private UserService userService; private UserService userService;
@Resource
private MailService mailService;
// 配置用户信息 // 配置用户信息
@PostMapping("inputUserInfo") @PostMapping("inputUserInfo")
public ResponseData<Object> inputUserInfo(@RequestBody Map<String,Object> param) { public ResponseData<Object> inputUserInfo(@RequestBody Map<String,Object> param) {
@@ -371,4 +374,15 @@ public class UserController {
public ResponseData<Object> mailRegister(@RequestBody UserModelDTO model){ public ResponseData<Object> mailRegister(@RequestBody UserModelDTO model){
return ResponseData.success(userService.addUserWithMail(model)); return ResponseData.success(userService.addUserWithMail(model));
} }
@GetMapping("/activate")
public ResponseData<Object> activate(@RequestParam("token") String token){
return ResponseData.success(userService.activateAccount(token));
}
@PostMapping("/resendMail")
public ResponseData<Object> resendMail(@RequestBody UserModelDTO userModelDTO){
return ResponseData.success(mailService.resendMail(userModelDTO));
}
} }

View File

@@ -2,7 +2,6 @@ package vvpkassistant.User.model.DTO;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
@Data @Data
@@ -24,5 +23,4 @@ public class UserModelDTO {
private String newPassword; private String newPassword;
private String oldPassword; private String oldPassword;
private String password; private String password;
} }

View File

@@ -17,4 +17,6 @@ public interface UserService extends IService<UserModel> {
UserModelVO updateUserInfo(UserModelDTO userModelDTO); UserModelVO updateUserInfo(UserModelDTO userModelDTO);
UserModelVO addUserWithMail(UserModelDTO model); UserModelVO addUserWithMail(UserModelDTO model);
Boolean activateAccount(String token);
} }

View File

@@ -1,6 +1,7 @@
package vvpkassistant.User.service; package vvpkassistant.User.service;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempUtil;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -15,7 +16,7 @@ import vvpkassistant.User.model.UserModel;
import vvpkassistant.User.model.UserModelVO; import vvpkassistant.User.model.UserModelVO;
import vvpkassistant.common.ErrorCode; import vvpkassistant.common.ErrorCode;
import vvpkassistant.exception.BusinessException; import vvpkassistant.exception.BusinessException;
import vvpkassistant.mail.model.MailModel; import vvpkassistant.mail.service.MailService;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -31,6 +32,8 @@ public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements
@Resource @Resource
private WxChatParam wxChatParam; private WxChatParam wxChatParam;
@Autowired
private MailService mailService;
@Override @Override
public UserModelVO loginWithMail(UserModelDTO model) { public UserModelVO loginWithMail(UserModelDTO model) {
@@ -96,33 +99,52 @@ public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements
} }
@Override @Override
public UserModelVO addUserWithMail(UserModelDTO model) { public UserModelVO addUserWithMail(UserModelDTO userModelDTO) {
LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(UserModel::getEmail,model.getEmail()); lambdaQueryWrapper.eq(UserModel::getEmail,userModelDTO.getEmail());
UserModel userModel = userDao.selectOne(lambdaQueryWrapper); UserModel userModel = userDao.selectOne(lambdaQueryWrapper);
if (userModel != null) { if (userModel != null) {
throw new BusinessException(ErrorCode.MAIL_ALREADY_EXIST); throw new BusinessException(ErrorCode.MAIL_ALREADY_EXIST);
} }
if (model.getPassword().length() < 6 ){ if (userModelDTO.getPassword().length() < 6 ){
throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位"); throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
} }
model.setPassword(BcryptUtils.encryptPassword(model.getPassword())); userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
model.setCreateTime(VVTools.currentTimeStamp()); userModelDTO.setCreateTime(VVTools.currentTimeStamp());
//设置状态为正常 //设置状态为待验证
model.setStatus(2); userModelDTO.setStatus(2);
//设置积分为0 //设置积分为0
model.setPoints(0); userModelDTO.setPoints(0);
userDao.insert(BeanUtil.copyProperties(model, UserModel.class)); UserModel userModelEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
if ( userDao.insert(userModelEntity) != 1){
throw new BusinessException(ErrorCode.ADD_FAILED,"用户注册失败");
}
mailService.sendMail(userModelDTO.getEmail(),userModelEntity.getId());
// 判断用户是否为邀请用户 // 判断用户是否为邀请用户
if (model.getInviterId() != null) { if (userModelDTO.getInviterId() != null) {
UserModel oldUser = userDao.selectById(model.getInviterId()); UserModel oldUser = userDao.selectById(userModelDTO.getInviterId());
oldUser.setPoints(oldUser.getPoints() + 10); oldUser.setPoints(oldUser.getPoints() + 10);
userDao.updateById(oldUser); userDao.updateById(oldUser);
} }
UserModelVO userModelVO = BeanUtil.copyProperties(model, UserModelVO.class); UserModelVO userModelVO = BeanUtil.copyProperties(userModelEntity, UserModelVO.class);
userModelVO.setNewAccount(true); userModelVO.setNewAccount(true);
userModelVO.setChatInfo(wxChatParam); userModelVO.setChatInfo(wxChatParam);
return userModelVO; return userModelVO;
} }
@Override
public Boolean activateAccount(String token) {
Integer userId = SaTempUtil.parseToken(token, Integer.class);
UserModel userModel = userDao.selectById(userId);
if (userModel == null) {
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
}
userModel.setStatus(0);
if (userDao.updateById(userModel) == 1){
return true;
}else {
throw new BusinessException(ErrorCode.UPDATE_FAILED,"激活失败");
}
}
} }

View File

@@ -15,6 +15,7 @@ public enum ErrorCode {
UPDATE_FAILED(1003, "更新失败"), UPDATE_FAILED(1003, "更新失败"),
CONFIG_NAME_DUPLICATE(1004, "配置名称重复"), CONFIG_NAME_DUPLICATE(1004, "配置名称重复"),
SIGN_IN_FAIL(1004, "当天已签到"), SIGN_IN_FAIL(1004, "当天已签到"),
EMAIL_SEND_FREQUENT(1005,"邮件发送太频繁,请 1 分钟后再试"),
/* =============== 主播相关 =============== */ /* =============== 主播相关 =============== */
ANCHOR_ALREADY_EXISTS(2001, "主播已存在"), ANCHOR_ALREADY_EXISTS(2001, "主播已存在"),

View File

@@ -31,6 +31,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
private String[] getExcludePaths() { private String[] getExcludePaths() {
return new String[]{ return new String[]{
// Swagger & Knife4j 相关 // Swagger & Knife4j 相关
"/error",
"/doc.html", "/doc.html",
"/webjars/**", "/webjars/**",
"/swagger-resources/**", "/swagger-resources/**",
@@ -42,8 +43,9 @@ public class SaTokenConfigure implements WebMvcConfigurer {
"/favicon.ico", "/favicon.ico",
// 你的其他放行路径,例如登录接口 // 你的其他放行路径,例如登录接口
"/user/loginWithPhoneNumber", "/user/loginWithPhoneNumber",
"/user/registerWithMail", "/user/registerWithMail",
"/user/loginWithMail" "/user/loginWithMail",
"/user/activate"
}; };
} }

View File

@@ -1,5 +1,6 @@
package vvpkassistant.mail.service; package vvpkassistant.mail.service;
import vvpkassistant.User.model.DTO.UserModelDTO;
import vvpkassistant.mail.model.MailModel; import vvpkassistant.mail.model.MailModel;
/* /*
@@ -7,5 +8,8 @@ import vvpkassistant.mail.model.MailModel;
* @date: 2025/8/4 15:42 * @date: 2025/8/4 15:42
*/ */
public interface MailService { public interface MailService {
Boolean sendMail(MailModel model);
void sendMail(String emailAddress,Integer userId);
Boolean resendMail(UserModelDTO userModelDTO);
} }

View File

@@ -1,62 +1,208 @@
package vvpkassistant.mail.service; package vvpkassistant.mail.service;
import cn.dev33.satoken.temp.SaTempUtil;
import cn.hutool.extra.mail.MailUtil;
import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.mailgun.api.v3.MailgunMessagesApi; import lombok.extern.slf4j.Slf4j;
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.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import vvpkassistant.mail.model.MailModel; import vvpkassistant.User.model.DTO.UserModelDTO;
import vvpkassistant.common.ErrorCode;
import vvpkassistant.exception.BusinessException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/* /*
* @author: ziin * @author: ziin
* @date: 2025/8/4 15:42 * @date: 2025/8/4 15:42
*/ */
@Slf4j
@Service @Service
public class MailServiceImpl implements MailService { public class MailServiceImpl implements MailService {
@Value("${mailgun}")
private String mailgunKey;
public final Cache<String, String> codeCache = Caffeine.newBuilder() @Value("${activateUrl}")
.expireAfterWrite(10, TimeUnit.MINUTES) // 5 分钟过期 private String activateUrl;
.maximumSize(10_000) // 防止内存暴涨
private final Cache<String, Object> emailSendCache = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.build(); .build();
@Override @Override
public Boolean sendMail(MailModel model) { @Async("taskExecutor")
ExecutorService executor = Executors.newFixedThreadPool(2); public void sendMail(String emailAddress,Integer userId) {
AsyncClient.Default<Object> asyncClient = new AsyncClient.Default<>( log.info("Sending email to {}", emailAddress);
new Client.Default(null, null), executor); String token = SaTempUtil.createToken(userId, 600);
if (emailSendCache.getIfPresent(emailAddress) != null) {
throw new BusinessException(ErrorCode.EMAIL_SEND_FREQUENT);
}
MailUtil.send(emailAddress, "激活你的账号", "<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
" <title>Account Activation</title>\n" +
" <style>\n" +
" * {\n" +
" margin: 0;\n" +
" padding: 0;\n" +
" box-sizing: border-box;\n" +
" }\n" +
"\n" +
" body {\n" +
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n" +
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
" min-height: 100vh;\n" +
" display: flex;\n" +
" align-items: center;\n" +
" justify-content: center;\n" +
" padding: 20px;\n" +
" }\n" +
"\n" +
" .container {\n" +
" background: white;\n" +
" border-radius: 12px;\n" +
" box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);\n" +
" padding: 40px;\n" +
" text-align: center;\n" +
" max-width: 400px;\n" +
" width: 100%;\n" +
" }\n" +
"\n" +
" .icon {\n" +
" width: 60px;\n" +
" height: 60px;\n" +
" background: #4CAF50;\n" +
" border-radius: 50%;\n" +
" display: flex;\n" +
" align-items: center;\n" +
" justify-content: center;\n" +
" margin: 0 auto 20px;\n" +
" color: white;\n" +
" font-size: 24px;\n" +
" }\n" +
"\n" +
" h1 {\n" +
" color: #333;\n" +
" font-size: 24px;\n" +
" margin-bottom: 10px;\n" +
" font-weight: 600;\n" +
" }\n" +
"\n" +
" .subtitle {\n" +
" color: #666;\n" +
" font-size: 16px;\n" +
" margin-bottom: 30px;\n" +
" line-height: 1.5;\n" +
" }\n" +
"\n" +
" .activate-button {\n" +
" display: inline-block;\n" +
" background: #4CAF50;\n" +
" border: none;\n" +
" border-radius: 8px;\n" +
" padding: 15px 30px;\n" +
" margin: 20px 0;\n" +
" font-size: 18px;\n" +
" font-weight: bold;\n" +
" color: white;\n" +
" text-decoration: none;\n" +
" cursor: pointer;\n" +
" transition: all 0.3s ease;\n" +
" box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n" +
" }\n" +
" \n" +
" .activate-button:hover {\n" +
" background: #45a049;\n" +
" transform: translateY(-2px);\n" +
" box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);\n" +
" }\n" +
" \n" +
" .activate-button:active {\n" +
" transform: translateY(0);\n" +
" box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n" +
" }\n" +
"\n" +
" .info {\n" +
" background: #e3f2fd;\n" +
" border-left: 4px solid #2196F3;\n" +
" padding: 15px;\n" +
" margin: 20px 0;\n" +
" text-align: left;\n" +
" border-radius: 4px;\n" +
" }\n" +
"\n" +
" .info-title {\n" +
" font-weight: 600;\n" +
" color: #1976D2;\n" +
" margin-bottom: 5px;\n" +
" }\n" +
"\n" +
" .info-text {\n" +
" color: #424242;\n" +
" font-size: 14px;\n" +
" line-height: 1.4;\n" +
" }\n" +
"\n" +
" .footer {\n" +
" margin-top: 30px;\n" +
" padding-top: 20px;\n" +
" border-top: 1px solid #eee;\n" +
" color: #999;\n" +
" font-size: 12px;\n" +
" }\n" +
"\n" +
" @media (max-width: 480px) {\n" +
" .container {\n" +
" padding: 30px 20px;\n" +
" }\n" +
" \n" +
" .verification-code {\n" +
" font-size: 24px;\n" +
" letter-spacing: 2px;\n" +
" }\n" +
" }\n" +
" </style>\n" +
"</head>\n" +
"<body>\n" +
" <div class=\"container\">\n" +
" <div class=\"icon\">✉</div>\n" +
" \n" +
" <h1>Account Activation</h1>\n" +
" <p class=\"subtitle\">Please click the button below to activate your account</p>\n" +
" \n" +
" <a href=\""+ activateUrl+ token + "\" class=\"activate-button\">\n" +
" Activate Account\n" +
" </a>\n" +
" \n" +
" <div class=\"info\">\n" +
" <div class=\"info-title\">Important Notice:</div>\n" +
" <div class=\"info-text\">\n" +
" • This activation link is valid for 24 hours<br>\n" +
" • Please do not share this link with anyone<br>\n" +
" • If you didn't register an account, please ignore this message\n" +
" </div>\n" +
" </div>\n" +
" \n" +
" <div class=\"footer\">\n" +
" This is an automated message. Please do not reply to this email.\n" +
" </div>\n" +
" </div>\n" +
"</body>\n" +
"</html>\n", true);
emailSendCache.put(emailAddress, userId);
}
MailgunMessagesApi mailgunAsyncMessagesApi = MailgunClient.config(mailgunKey) @Override
.client(asyncClient) public Boolean resendMail(UserModelDTO userModelDTO) {
.createAsyncApi(MailgunMessagesApi.class); try {
sendMail(userModelDTO.getEmail(), userModelDTO.getId());
Message message = Message.builder() return true;
.from("") }catch (Exception e){
.to(model.getMailAddress()) throw new BusinessException(ErrorCode.SYSTEM_ERROR,e.getMessage());
.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;
} }
} }

View File

@@ -4,10 +4,25 @@ server:
spring: spring:
profiles: profiles:
active: local active: local
task:
# Spring 执行器配置,对应 TaskExecutionProperties 配置类。对于 Spring 异步任务,会使用该执行器。
execution:
thread-name-prefix: mail-task # 线程池的线程名的前缀。默认为 task- ,建议根据自己应用来设置
pool: # 线程池相关
core-size: 10 # 核心线程数,线程池创建时候初始化的线程数。默认为 8 。
max-size: 20 # 最大线程数,线程池最大的线程数,只有在缓冲队列满了之后,才会申请超过核心线程数的线程。默认为 Integer.MAX_VALUE
keep-alive: 60s # 允许线程的空闲时间,当超过了核心线程之外的线程,在空闲时间到达之后会被销毁。默认为 60 秒
queue-capacity: 200 # 缓冲队列大小,用来缓冲执行任务的队列的大小。默认为 Integer.MAX_VALUE 。
allow-core-thread-timeout: true # 是否允许核心线程超时,即开启线程池的动态增长和缩小。默认为 true 。
shutdown:
await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置
mybatis-plus:
mailgun: b4888f65c7fd452213f3a8aea9d88269-812b35f5-006d7fd6 global-config:
db-config:
id-type: auto
############## Sa-Token 配置 (文档: https://sa-token.cc) ############## ############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
@@ -15,9 +30,9 @@ sa-token:
# token 名称(同时也是 cookie 名称) # token 名称(同时也是 cookie 名称)
token-name: token token-name: token
# token 有效期(单位:秒) 默认30天-1 代表永久有效 # token 有效期(单位:秒) 默认30天-1 代表永久有效
timeout: 2592000 timeout: -1
# token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
active-timeout: -1 active-timeout: 648000
# 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
is-concurrent: true is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token
@@ -26,3 +41,5 @@ sa-token:
token-style: random-128 token-style: random-128
# 是否输出操作日志 # 是否输出操作日志
is-log: true is-log: true
activateUrl: http://192.168.1.174:8086/user/activate?token=

View File

@@ -0,0 +1,10 @@
# 邮件服务器的SMTP地址可选默认为smtp.<发件人邮箱后缀>
host = smtp.exmail.qq.com
# 邮件服务器的SMTP端口可选默认25
port = 465
# 发件人(必须正确,否则发送失败)
from = chenfu@bilibili.so
# 用户名,默认为发件人邮箱前缀
user = chenfu@bilibili.so
pass = Yt7rWTizdAvE4dc7
sslEnable = true

View File

@@ -4,10 +4,25 @@ server:
spring: spring:
profiles: profiles:
active: local active: local
task:
# Spring 执行器配置,对应 TaskExecutionProperties 配置类。对于 Spring 异步任务,会使用该执行器。
execution:
thread-name-prefix: mail-task # 线程池的线程名的前缀。默认为 task- ,建议根据自己应用来设置
pool: # 线程池相关
core-size: 10 # 核心线程数,线程池创建时候初始化的线程数。默认为 8 。
max-size: 20 # 最大线程数,线程池最大的线程数,只有在缓冲队列满了之后,才会申请超过核心线程数的线程。默认为 Integer.MAX_VALUE
keep-alive: 60s # 允许线程的空闲时间,当超过了核心线程之外的线程,在空闲时间到达之后会被销毁。默认为 60 秒
queue-capacity: 200 # 缓冲队列大小,用来缓冲执行任务的队列的大小。默认为 Integer.MAX_VALUE 。
allow-core-thread-timeout: true # 是否允许核心线程超时,即开启线程池的动态增长和缩小。默认为 true 。
shutdown:
await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置
mybatis-plus:
mailgun: b4888f65c7fd452213f3a8aea9d88269-812b35f5-006d7fd6 global-config:
db-config:
id-type: auto
############## Sa-Token 配置 (文档: https://sa-token.cc) ############## ############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
@@ -26,3 +41,5 @@ sa-token:
token-style: random-128 token-style: random-128
# 是否输出操作日志 # 是否输出操作日志
is-log: true is-log: true
activateUrl: http://192.168.1.174:8086/user/activate?token=