site/register
;@Controller
public class LoginController {
@RequestMapping(value = "/register",method = RequestMethod.GET)
public String getRegisterPage(){
return "site/register";
}
}
;th:replace="index::header"
<a class="nav-link" th:href="@{/index}">首页a>
<a class="nav-link" th:href="@{/register}">注册a>
th:fragment="header"
,其他的文件复用这段代码:th:replace="index::header"
http://localhost:8080/community/register
,可以使用;从首页访问,可以跳转;commons long
,这个包是判断字符串,是否存在空值等等,注册会用到:
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.12.0version>
dependency>
community.path.domain=http://localhost:8080
public class CommunityUtil {
// 生成随机字符串
public static String generateUUID() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
/**
* @param key ,用户输入的密码
* @return 返回 MD5 加密的密码
*
* MD5加密:hello -> abc123def456
* 一般情况下我们会先加盐,再加密:hello + 3e4a8 -> abc123def456abc
*/
public static String md5(String key) {
if (StringUtils.isBlank(key)) {
return null;
}
return DigestUtils.md5DigestAsHex(key.getBytes());//加密成16进制的字符串返回
}
}
@Autowired
private MailClient mailClient;
@Autowired
private TemplateEngine templateEngine;
@Value("${server.servlet.context-path}")
private String contextPath;
@Value("${community.path.domain}")
private String domain;
register
方法:Map
来接收,并在形参中传入 User 对象:http://images.nowcoder.com/head/%dt.png
,其中 %d 填充位 0-1000 随机数;http://localhost:8080/community/activation/用户id/激活码
(这里的用户id为什么不为空呢?因为我们 mybatis 配置中打开了自增主键配置,在向数据库插入数据之后自动将得到的自增 id 填充给了User类)@Override
public Map<String, Object> register(User user) {
Map<String, Object> map = new HashMap<>();
//空值处理
if (user == null) {
throw new IllegalArgumentException("参数不能为空!");
}
if (StringUtils.isBlank(user.getUsername())) {
map.put("usernameMsg", "用户名不能为空!");
return map;
}
if (StringUtils.isBlank(user.getPassword())) {
map.put("passwordMsg", "密码不能为空!");
return map;
}
if (StringUtils.isBlank(user.getEmail())) {
map.put("emailMsg", "邮箱不能为空!");
return map;
}
//验证账号没有被注册过
User uTemp = userMapper.selectByName(user.getUsername());
if (uTemp != null) {
map.put("usernameMsg", "用户名已经被注册过!");
return map;
}
//验证邮箱没有被注册过
uTemp = userMapper.selectByEmail(user.getEmail());
if (uTemp != null) {
map.put("emailMsg", "该邮箱已经被注册过!");
return map;
}
//注册用户
user.setSalt(CommunityUtil.generateUUID().substring(0, 5));
user.setPassword(CommunityUtil.md5(user.getPassword() + user.getSalt()));
user.setType(0);
user.setStatus(0);
user.setActivationCode(CommunityUtil.generateUUID());
//设置头像路径为:http://images.nowcoder.com/head/%dt.png,其中%d填充位0-1000随机数
user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png", (int) (Math.random() * 1000)));
user.setCreateTime(new Date());
userMapper.insertUser(user);
//发送激活邮件
Context context = new Context();
//这些是要替换html模板文件中的,设置邮箱
context.setVariable("email", user.getEmail());
//设置激活链接:http://localhost:8080/community/activation/用户id/激活码
String activationUrl = "http://localhost:8080/community/activation/" + user.getId() + "/" + user.getActivationCode();
context.setVariable("activationUrl", activationUrl);
//调用模板引擎生成动态网页
String content = templateEngine.process("mail/activation",context);
mailClient.sendMail(user.getEmail(),"激活账号",content);
return map;
}
注意:
StringUtils.isBlank()
这个方法,并且存在错误直接返回 map,结束当前方法;xmlns:th="http://www.thymeleaf.org"
th:text="${email}"
th:href="${activationUrl}"
doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link rel="icon" href="https://static.nowcoder.com/images/logo_87_87.png"/>
<title>牛客网-激活账号title>
head>
<body>
<div>
<p>
<b th:text="${email}">[email protected]b>, 您好!
p>
<p>
您正在注册牛客网, 这是一封激活邮件, 请点击
<a th:href="${activationUrl}">http://www.nowcoder.com/activation/abcdefg.htmla>,
激活您的牛客账号!
p>
div>
body>
html>
register(User user)
方法,返回一个map容器operate-result
页面,告诉用户请尽快激活;@RequestMapping(value = "/register", method = RequestMethod.POST)
public String register(Model model, User user) {
Map<String, Object> map = userService.register(user);
if (map == null || map.isEmpty()) {
model.addAttribute("msg", "注册成功,我们已经向您的邮箱发送了一封激活邮件,请尽快激活!");
model.addAttribute("target", "/index");
return "site/operate-result";
}else{
model.addAttribute("usernameMsg",map.get("usernameMsg"));
model.addAttribute("passwordMsg",map.get("passwordMsg"));
model.addAttribute("emailMsg",map.get("emailMsg"));
return "/site/register";
}
}
th:href="@{/css/global.css}"
th:replace="index::header"
<div class="main">
<div class="container mt-5">
<div class="jumbotron">
<p class="lead" th:text="${msg}">您的账号已经激活成功,可以正常使用了!p>
<hr class="my-4">
<p>
系统会在 <span id="seconds" class="text-danger">8span> 秒后自动跳转,
您也可以点此 <a id="target" th:href="@{${target}}" class="text-primary">链接a>, 手动跳转!
p>
div>
div>
div>
注意:
th:href="@{${target}}"
,注意这里里面代表一个链接,所以要从绝对路径开始;th:action="@{/register}" method="post"
name="username"
th:value="${user!=null?user.username:''}"
th:text="${usernameMsg}"
th:class="|form-control ${usernameMsg!=null?'is-invalid':''}|"
<div class="main">
<div class="container pl-5 pr-5 pt-3 pb-3 mt-3 mb-3">
<h3 class="text-center text-info border-bottom pb-3">注 册h3>
<form class="mt-5" th:action="@{/register}" method="post">
<div class="form-group row">
<label for="username" class="col-sm-2 col-form-label text-right">账号:label>
<div class="col-sm-10">
<input type="text" th:class="|form-control ${usernameMsg!=null?'is-invalid':''}|"
name="username" th:value="${user!=null?user.username:''}"
id="username" placeholder="请输入您的账号!" required>
<div class="invalid-feedback" th:text="${usernameMsg}">
该账号已存在!
div>
div>
div>
<div class="form-group row mt-4">
<label for="password" class="col-sm-2 col-form-label text-right">密码:label>
<div class="col-sm-10">
<input type="password" th:class="|form-control ${passwordMsg!=null?'is-invalid':''}|"
name="password" th:value="${user!=null?user.password:''}"
id="password" placeholder="请输入您的密码!" required>
<div class="invalid-feedback" th:text="${passwordMsg}">
密码长度不能小于8位!
div>
div>
div>
<div class="form-group row mt-4">
<label for="confirm-password" class="col-sm-2 col-form-label text-right">确认密码:label>
<div class="col-sm-10">
<input type="password" class="form-control"
th:value="${user!=null?user.password:''}"
id="confirm-password" placeholder="请再次输入密码!" required>
<div class="invalid-feedback">
两次输入的密码不一致!
div>
div>
div>
<div class="form-group row">
<label for="email" class="col-sm-2 col-form-label text-right">邮箱:label>
<div class="col-sm-10">
<input type="email" th:class="|form-control ${emailMsg!=null?'is-invalid':''}|"
name="email" th:value="${user!=null?user.email:''}"
id="email" placeholder="请输入您的邮箱!" required>
<div class="invalid-feedback" th:text="${emailMsg}">
该邮箱已注册!
div>
div>
div>
<div class="form-group row mt-4">
<div class="col-sm-2">div>
<div class="col-sm-10 text-center">
<button type="submit" class="btn btn-info text-white form-control">立即注册button>
div>
div>
form>
div>
div>
①成功没问题 ②重复激活 ③激活码伪造
创建一个接口表示上述三种状态
public interface CommunityConstant {
/**
* 激活成功
*/
int ACTIVATION_SUCCESS = 0;
/**
* 重复激活
*/
int ACTIVATION_REPEAT = 1;
/**
* 激活失败
*/
int ACTIVATION_FAILURE = 2;
/**
* 默认状态的登录凭证的超时时间,12h
*/
int DEFAULT_EXPIRED_SECONDS = 3600 * 12;
/**
* 记住状态的登录凭证超时时间,100天
*/
int REMEMBER_EXPIRED_SECONDS = 3600 * 24 * 100;
}
CommunityConstant
接口,因为要用到其中定义的常量;//①成功没问题 ②重复激活 ③激活码伪造
@Override
public int activation(int userId, String code) {
int status = userMapper.selectById(userId).getStatus();
String activationCode = userMapper.selectById(userId).getActivationCode();
if (status == 0 && activationCode.equals(code)){
return ACTIVATION_SUCCESS;
}else if (status == 1){
return ACTIVATION_REPEAT;
}else {
return ACTIVATION_FAILURE;
}
}
CommunityConstant
接口;activation
方法,设置映射的跳转路径为我们之前规定好的激活超链接http://localhost:8080/community/activation/用户id/激活码
;@PathVariable
注解将请求路径中的信息与形参信息对应起来),调用 UserService 层判断激活状态码;operate-result
页面;即根据不同的激活状态码向 model 中放置不同的 msg 和 target 信息;//超链接http://localhost:8080/community/activation/用户id/激活码
@RequestMapping(path = "/activation/{userId}/{code}",method = RequestMethod.GET)
public String activation(Model model,
@PathVariable("userId") int userId,@PathVariable("code") String code){
int result = userService.activation(userId, code);
if (result == ACTIVATION_SUCCESS) {
model.addAttribute("msg", "激活成功,您的账号已经可以正常使用了!");
model.addAttribute("target", "/login");
} else if (result == ACTIVATION_REPEAT) {
model.addAttribute("msg", "无效操作,该账号已经激活过了!");
model.addAttribute("target", "/index");
} else {
model.addAttribute("msg", "激活失败,您提供的激活码不正确!");
model.addAttribute("target", "/index");
}
return "/site/operate-result";
}
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String getLoginPage(){
return "site/login";
}
xmlns:th="http://www.thymeleaf.org"
th:href="@{/css/global.css}"
th:replace="index::header"
th:src="@{/img/captcha.png}"
th:href="@{/login}"