• Spring Boot 之开发注册功能


    1. 功能描述

    ① 实现访问注册页面的请求,即点击顶部的注册链接时,打开注册页面。
    ② 实现提交注册的请求,在服务端对提交的数据进行验证,通过后发送激活邮件。
    ③ 实现激活账号的请求,在服务端验证激活码的有效性,若有效则修改账号的状态。

    2. 邮件客户端

    util 包下:MailClient.java

    package com.nowcoder.community.util;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.mail.javamail.JavaMailSender;
    import org.springframework.mail.javamail.MimeMessageHelper;
    import org.springframework.stereotype.Component;
    
    import javax.mail.MessagingException;
    import javax.mail.internet.MimeMessage;
    
    
    @Component
    public class MailClient {
    
        private static final Logger logger = LoggerFactory.getLogger(MailClient.class);
    
        @Autowired
        private JavaMailSender mailSender;
    
        @Value("${spring.mail.username}")
        private String from;
    
        public void sendMail(String to, String subject, String content) {
            try {
                MimeMessage message = mailSender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(message);
                helper.setFrom(from);
                helper.setTo(to);
                helper.setSubject(subject);
                helper.setText(content, true);
                mailSender.send(helper.getMimeMessage());
            } catch (MessagingException e) {
                logger.error("Fail to send E-mail!" + e.getMessage());
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    Logger 用于记录发送邮件过程的日志
    JavaMailSender 用于完成注册邮件的发送

    3. 定义注册激活用到的常量

    util 包下的CommunityConstant.java

    package com.nowcoder.community.util;
    
    public interface CommunityConstant {
    
        /**
         * 激活成功
         */
        int ACTIVATION_SUCCESS = 0;
    
        /**
         * 重复激活
         */
        int ACTIVATION_REPEAT = 1;
    
        /**
         * 激活失败
         */
        int ACTIVATION_FAILURE = 2;
    
        /**
         * 默认状态的登录凭证的超时时间
         */
        int DEFAULT_EXPIRED_SECONDS = 3600 * 12;
    
        /**
         * 记住状态的登录凭证超时时间
         */
        int REMEMBER_EXPIRED_SECONDS = 3600 * 24 * 100;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    4. 随机字符串加密

    util 包下的CommunityUtil.java

    package com.nowcoder.community.util;
    
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.util.DigestUtils;
    
    import java.util.UUID;
    
    public class CommunityUtil {
    
        // 生成随机字符串
        public static String generateUUID() {
            return UUID.randomUUID().toString().replaceAll("-", "");
        }
    
        // MD5加密
        // hello -> abc123def456
        // hello + 3e4a8 -> abc123def456abc
        public static String md5(String key) {
            if (StringUtils.isBlank(key)) {
                return null;
            }
            return DigestUtils.md5DigestAsHex(key.getBytes());
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    5. Controller层

    controller 包下的LoginController.java

    package com.nowcoder.community.controller;
    
    import com.nowcoder.community.entity.User;
    import com.nowcoder.community.service.UserService;
    import com.nowcoder.community.util.CommunityConstant;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    
    import java.util.Map;
    
    @Controller
    public class LoginController implements CommunityConstant {
    
        @Autowired
        private UserService userService;
    
        @GetMapping("/register")
        public String getRegisterPage() {
            return "/site/register";
        }
    
        @GetMapping("/login")
        public String getLoginPage() {
            return "/site/login";
        }
    
        @PostMapping("/register")
        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";
            }
    
        }
    
        // http://localhost:8080/community/activation/101/code
        @GetMapping("/activation/{userId}/{code}")
        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";
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    ① 注入 UserService
    ② Get 请求:返回 register 页面
    ③ Get 请求: 返回 login 页面
    ④ Post 请求:返回 register / operate-result 界面,实现用户注册功能,需要验证当前用户是否存在
    ⑤ Get 请求:返回 operate-result 页面,url 路径为 activation/{userId}/{code},需要验证激活码的三种状态

    6. 模板文件

    templates / mail / activation.html

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="utf-8" xmlns:th="http://www.thymeleaf.com">
        <link rel="icon" href="https://static.nowcoder.com/images/logo_87_87.png"/>
        <title>牛客网-激活账号</title>
    </head>
    <body>
    	<div>
    		<p>
    			<b th:text="${email}">xxx@xxx.com</b>, 您好!
    		</p>
    		<p>
    			您正在注册牛客网, 这是一封激活邮件, 请点击 
    			<a th:href="${url}">此链接</a>,
    			激活您的牛客账号!
    		</p>
    	</div>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    templates / site / operate-result.html
    账号激活部分:

    <!-- 内容 -->
    <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">8</span> 秒后自动跳转,
    		您也可以点此 <a id="target" th:href="@{${target}}" class="text-primary">链接</a>, 手动跳转!
    	</p>
    </div>
    </div>
    </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    templates / site / register.html
    注册验证部分:

    <!-- 内容 -->
    <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">&nbsp;&nbsp;</h3>
    		<form class="mt-5" method="post" th:action="@{/register}">
    			<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':''}|"
    						   th:value="${user!=null?user.username:''}"
    						   id="username" name="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':''}|"
    						   th:value="${user!=null?user.password:''}"
    						   id="password" name="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':''}|"
    						   th:value="${user!=null?user.email:''}"
    						   id="email" name="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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
  • 相关阅读:
    ASPICE标准快速掌握「5.2. ASPICE与V模型」
    History库源码分析-Action 动作类型
    【CTA系列】Kelly公式在最优f问题上的应用
    EL 表达式
    用于演示文稿的新 Dapr 幻灯片
    “我有一个大胆的想法”?Meta AI 新技术让你的思维图像一览无余!
    VBA Regex 正则表达式应用介绍
    uniapp和小程序设置tabBar和显示与隐藏tabBar
    Android 10 如何在SurfaceFlinger中解决开机动画显示不全问题
    ubuntu 多版本cmake共存的终极方法
  • 原文地址:https://blog.csdn.net/hutianle/article/details/126095448