技术栈目录结构数据库源码
pomapplicationcontrollermapperpojoserviceSpringbootLoginRegistryApplicationtemplates 可能遇到的问题
技术栈 目录结构 数据库SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for user -- ---------------------------- DROp TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱', `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码', `salt` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '盐', `/confirm/i_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '确认码', `activation_time` datetime(0) NULL DEFAULT NULL COMMENT '激活失效时间', `is_valid` tinyint(1) NULL DEFAULT NULL COMMENT '是否可用,0不可用,1可用', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;源码 pom
可单独添加依赖
cn.hutool hutool-all 5.6.3 org.springframework.boot spring-boot-starter-mail
完整依赖
application4.0.0 com.example springboot-login-registry 0.0.1-SNAPSHOT springboot-login-registry Demo project for Spring Boot 1.8 UTF-8 UTF-8 2.3.7.RELEASE org.springframework.boot spring-boot-starter-mail org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-starter-web org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.4 cn.hutool hutool-all 5.6.3 mysql mysql-connector-java runtime org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import org.apache.maven.plugins maven-compiler-plugin 3.8.1 1.8 1.8 UTF-8 org.springframework.boot spring-boot-maven-plugin 2.3.7.RELEASE com.example.SpringbootLoginRegistryApplication repackage repackage
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/xiaomu?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
mail:
protocol: smtps # 邮件协议
host: smtp.qq.com # QQ邮箱 smtp 服务器地址
port: 465 # 端口
username: # 邮箱用户名
password: # 授权码
default-encoding: utf-8 # 编码字符集
properties:
mail:
debug: ture # 开启debug模式以后会完整打印邮件发送过程的日志
mybatis:
configuration:
map-underscore-to-camel-case: true # 开启驼峰功能
controller
SystemController
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class SystemController {
@GetMapping("login")
public String login() {
return "login";
}
@GetMapping("registry")
public String registry() {
return "registry";
}
}
UserController
package com.example.controller;
import com.example.pojo.User;
import com.example.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Map;
@RestController
@RequestMapping("user")
public class UserController {
@Resource
private UserService userService;
@PostMapping("create")
public Map createAccount(User user) {
return userService.createAccount(user);
}
@PostMapping("login")
public Map loginAccount(User user) {
return userService.loginAccount(user);
}
@GetMapping("activation")
public Map activationAccount(String /confirm/iCode) {
return userService.activationAccount(/confirm/iCode);
}
}
mapper
UserMapper
package com.example.mapper;
import com.example.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface UserMapper {
@Insert("INSERT INTO user ( email, password, salt, /confirm/i_code, activation_time, is_valid)" +
"VALUES ( #{email}, #{password}, #{salt}, #{/confirm/iCode}, #{activationTime}, #{isValid})")
int insertUser(User user);
@Select("SELECT email, activation_time FROM user WHERe /confirm/i_code = #{/confirm/iCode} AND is_valid = 0")
User selectUserBy/confirm/iCode(@Param("/confirm/iCode") String /confirm/iCode);
@Update("UPDATE user SET is_valid = 1 WHERe /confirm/i_code = #{/confirm/iCode}")
int updateUserBy/confirm/iCode(@Param("/confirm/iCode") String /confirm/iCode);
@Select("SELECT email, password, salt FROM user WHERe email = #{email} AND is_valid = 1")
List selectUserByEmail(@Param("email") String email);
}
pojo
User
package com.example.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Integer id; // 主键
private String email; // 邮箱
private String password; // 密码,使用md5 + 盐 加密
private String salt; // 盐
private String /confirm/iCode; // 确认码
private LocalDateTime activationTime; // 激活失效时间
private Byte isValid; // 是否可用
}
service
package com.example.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Date;
@Service
public class MailService {
@Value("${spring.mail.username}")
private String mailUsername;
@Resource
private TemplateEngine templateEngine;
@Resource
private JavaMailSender javaMailSender;
public void sendMailForActivationAccount(String activationUrl, String email) {
// 创建邮件对象
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try {
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
// 设置邮件主题
messageHelper.setSubject("欢迎加入小沐 -- 个人账号激活");
// 设置邮件发送者
messageHelper.setFrom(mailUsername);
// 设置邮件加接收者,可以多人
messageHelper.setTo(email);
// 邮件发送日期
messageHelper.setSentDate(new Date());
// 创建上下文环境
Context context = new Context();
context.setVariable("activationUrl", activationUrl);
// 邮件模板
String text = templateEngine.process("activation-account.html", context);
// 设置邮件正文
messageHelper.setText(text, true);
} catch (MessagingException e) {
e.printStackTrace();
}
// 邮件发送
javaMailSender.send(mimeMessage);
}
}
UserService
package com.example.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import com.example.mapper.UserMapper;
import com.example.pojo.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class UserService {
@Resource
private UserMapper userMapper;
@Resource
private MailService mailService;
@Transactional
public Map createAccount(User user){
// 雪花算法
String confirmCode = IdUtil.getSnowflake(1, 1).nextIdStr();
// 盐
String salt = RandomUtil.randomString(6);
// 加密密码:原始密码 + 盐
String md5Pwd = SecureUtil.md5(user.getPassword() + salt);
// 激活失效时间: 24 小时
LocalDateTime ldt = LocalDateTime.now().plusDays(1);
// 初始账号信息
user.setSalt(salt);
user.setPassword(md5Pwd);
user.set/confirm/iCode(/confirm/iCode);
user.setActivationTime(ldt);
user.setIsValid((byte) 0);
// 新增账号
int result = userMapper.insertUser(user);
Map resultMap = new HashMap<>();
if (result > 0) {
// 发送邮件
String activationUrl = "http://localhost:8080/user/activation?confirmCode=" + /confirm/iCode;
mailService.sendMailForActivationAccount(activationUrl, user.getEmail());
resultMap.put("code", 200);
resultMap.put("message", "注册成功,请前往邮箱进行账号激活");
} else {
resultMap.put("code", 400);
resultMap.put("message", "注册失败");
}
return resultMap;
}
public Map loginAccount(User user) {
Map resultMap = new HashMap<>();
// 根据邮箱查询用户
List userList = userMapper.selectUserByEmail(user.getEmail());
// 查询不到结果,返回:该账号不存在或者未激活
if (userList == null || userList.isEmpty()) {
resultMap.put("code", 400);
resultMap.put("message", "该账号不存在或者未激活");
return resultMap;
}
// 查询到多个用户,返回: 账号异常,请联系管理员
if (userList.size() > 1) {
resultMap.put("code", 400);
resultMap.put("message", "账号异常,请联系管理员");
return resultMap;
}
// 查询到一个用户,进行密码对比
User u = userList.get(0);
// 用户输入的密码和盐进行加密
String md5Pwd = SecureUtil.md5(user.getPassword() + u.getSalt());
// 密码不一致,返回:用户名或者密码错误
if (!u.getPassword().equals(md5Pwd)) {
resultMap.put("code", 400);
resultMap.put("message", "用户名或者密码错误");
return resultMap;
}
resultMap.put("code", 200);
resultMap.put("message", "登录成功");
return resultMap;
}
@Transactional
public Map activationAccount(String /confirm/iCode) {
Map resultMap = new HashMap<>();
// 根据用户确认码查询用户
User user = userMapper.selectUserBy/confirm/iCode(/confirm/iCode);
// 判断激活时间是否超时
boolean after = LocalDateTime.now().isAfter(user.getActivationTime());
if (after) {
resultMap.put("code", 400);
resultMap.put("message", "链接已失效,请重新注册");
return resultMap;
}
// 根据确认码查询用户并修改状态值为 1 (可用)
int result = userMapper.updateUserBy/confirm/iCode(/confirm/iCode);
if (result > 0) {
resultMap.put("code", 200);
resultMap.put("message", "激活成功");
return resultMap;
} else {
resultMap.put("code", 400);
resultMap.put("message", "激活失败");
}
return resultMap;
}
}
SpringbootLoginRegistryApplication
package com.example;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.example.mapper")
@SpringBootApplication
public class SpringbootLoginRegistryApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootLoginRegistryApplication.class, args);
}
}
templates
activation-acount(简陋模板)
login
Login Example - Semantic
登 录
registry
Login Example - Semantic
注 册
可能遇到的问题
Debug问题
解决方案



