1.1 实现的思路

1)用户填写相关信息,点击注册按钮
2)系统先将用户记录保存到数据库中,其中用户状态为未激活
3)系统发送一封邮件并通知用户去验证(code)
4)用户登录邮箱并点击激活链接
5)通过code获取该用户,系统将用户状态更改为已激活并通知用户注册成功

搞清楚了整个流程,实现起来应该就不难了。下图是我建立的包结构:
image.png

1.2 实现步骤

1.2.1 配置POM依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.4.3</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.gmw.boot</groupId>
  12. <artifactId>send_meail</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>send_meail</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-mail</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-web</artifactId>
  31. </dependency>
  32. <dependency>
  33. <groupId>mysql</groupId>
  34. <artifactId>mysql-connector-java</artifactId>
  35. <version>5.1.49</version>
  36. </dependency>
  37. <dependency>
  38. <groupId>com.baomidou</groupId>
  39. <artifactId>mybatis-plus-boot-starter</artifactId>
  40. <version>3.3.1.tmp</version>
  41. </dependency>
  42. <dependency>
  43. <groupId>com.alibaba</groupId>
  44. <artifactId>druid</artifactId>
  45. <version>1.1.20</version>
  46. </dependency>
  47. <dependency>
  48. <groupId>org.springframework.boot</groupId>
  49. <artifactId>spring-boot-devtools</artifactId>
  50. <scope>runtime</scope>
  51. <optional>true</optional>
  52. </dependency>
  53. <dependency>
  54. <groupId>org.projectlombok</groupId>
  55. <artifactId>lombok</artifactId>
  56. <optional>true</optional>
  57. </dependency>
  58. <dependency>
  59. <groupId>org.springframework.boot</groupId>
  60. <artifactId>spring-boot-starter-test</artifactId>
  61. <scope>test</scope>
  62. </dependency>
  63. </dependencies>
  64. <build>
  65. <plugins>
  66. <plugin>
  67. <groupId>org.springframework.boot</groupId>
  68. <artifactId>spring-boot-maven-plugin</artifactId>
  69. <configuration>
  70. <excludes>
  71. <exclude>
  72. <groupId>org.projectlombok</groupId>
  73. <artifactId>lombok</artifactId>
  74. </exclude>
  75. </excludes>
  76. </configuration>
  77. </plugin>
  78. </plugins>
  79. </build>
  80. </project>

1.2.2 配置application.properties文件

#端口号
server.port=8888

#配置thymeleaf模板引擎
spring.thymeleaf.mode=HTML
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=false

#配置邮件设置
#配置QQ邮箱的host的地址
spring.mail.host=smtp.qq.com
#开通QQ邮箱的用户名
spring.mail.username=ganmaowang@qq.com
#设置密码(但要注意,不是设置QQ密码,而是指定发送)
spring.mail.password=vunqpeajrjzmbiac
#设置属性,指定邮件的信息进行加密
spring.mail.properties.mail.smtp.ssl.enable=true

#druid数据源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root

#配置mybatis的xml配置文件的位置
mybatis.mapper-locations=classpath:/com/gmw/boot/send_meail/mapper/*.xml
mybatis.type-aliases-package=com.gmw.boot.send_meail.entity

1.2.3 创建发送邮件的工具类

package com.gmw.boot.send_meail.utils;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

/**
 * 发邮件工具类
 */
public final class MailUtils {
    private static final String USER = "ganmaowang@qq.com"; // 发件人称号,同邮箱地址
    private static final String PASSWORD = "vunqpeajrjzmbiac"; // 如果是qq邮箱可以使户端授权码,或者登录密码

    /**
     *
     * @param to 收件人邮箱
     * @param text 邮件正文
     * @param title 标题
     */
    /* 发送验证信息的邮件 */
    public static boolean sendMail(String to, String text, String title){
        try {
            final Properties props = new Properties();
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.host", "smtp.qq.com");

            // 发件人的账号
            props.put("mail.user", USER);
            //发件人的密码
            props.put("mail.password", PASSWORD);

            // 构建授权信息,用于进行SMTP进行身份验证
            Authenticator authenticator = new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    // 用户名、密码
                    String userName = props.getProperty("mail.user");
                    String password = props.getProperty("mail.password");
                    return new PasswordAuthentication(userName, password);
                }
            };
            // 使用环境属性和授权信息,创建邮件会话
            Session mailSession = Session.getInstance(props, authenticator);
            // 创建邮件消息
            MimeMessage message = new MimeMessage(mailSession);
            // 设置发件人
            String username = props.getProperty("mail.user");
            InternetAddress form = new InternetAddress(username);
            message.setFrom(form);

            // 设置收件人
            InternetAddress toAddress = new InternetAddress(to);
            message.setRecipient(Message.RecipientType.TO, toAddress);

            // 设置邮件标题
            message.setSubject(title);

            // 设置邮件的内容体
            message.setContent(text, "text/html;charset=UTF-8");
            // 发送邮件
            Transport.send(message);
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    public static void main(String[] args) throws Exception { // 做测试用
        MailUtils.sendMail("itcast_xian@163.com","你好,这是一封测试邮件,无需回复。","测试邮件");
        System.out.println("发送成功");
    }

}

1.2.4 创建随机生成UUID的工具类

package com.gmw.boot.send_meail.utils;

import java.util.UUID;

/**
 * 产生UUID随机字符串工具类
 */
public final class UUIDUtils {
    private UUIDUtils(){}
    public static String getUuid(){
        return UUID.randomUUID().toString().replace("-","");
    }
    /**
     * 测试
     */
    public static void main(String[] args) {
        System.out.println(UUIDUtils.getUuid());
        System.out.println(UUIDUtils.getUuid());
        System.out.println(UUIDUtils.getUuid());
        System.out.println(UUIDUtils.getUuid());
    }
}

1.2.5 创建前端页面(登录页面,注册页面,首页,点击连接跳转邮箱页面,错误页面)

1)登录页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <form th:action="@{/user/login}" method="post">
        用户名: <input type="text" name="username" placeholder="请输入用户名"/>&nbsp;
        密码 : <input type="password" name="password" placeholder="请输入密码"/>&nbsp;<input type="submit" value="提交"/>
        <a th:href="@{/register}">点击注册</a>
    </form>
</body>
</html>

image.png

2)注册页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>
<span style="text-align: center;font-size: 30px;color: red;" th:text="${exister}"></span>
    <form method="post" th:action="@{/user/register}">
        用户名: <input type="text" name="username" placeholder="请输入用户名"/><br/>
        密码: <input type="password" name="password" placeholder="请输入密码"/><br/>
        邮箱: <input type="email" name="email" placeholder="请输入邮箱"/><br/>
        <input type="submit" value="注册"/>
    </form>
</body>
</html>

image.png

3)点击链接跳转到邮箱激活页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>点击链接跳转到邮箱激活页面</title>
</head>
<body>
<h1 style="text-align: center;color: red;font-size: 60px;"><a th:href="@{https://mail.qq.com/}">你的账号未激活!!请前往邮箱激活您的账号</a></h1>
</body>
</html>

image.png

4)错误页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>错误页面</title>
</head>
<body>
    <h1 th:text="${error}"></h1>
</body>
</html>

5)首页页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页页面</title>
</head>
<body>
<h1>登录成功,欢迎<span th:text="${#session.getAttribute('loginUser')}"></span>用户,上线时间<span th:text="${#session.getAttribute('time')}"></span></h1>
</body>
</html>

1.2.6 创建后端Controller、Service 和 Dao层

1)跳转到登录页面和注册页面的控制层(Controller)

package com.gmw.boot.send_meail.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class IndexController {
    @RequestMapping(value = "/")
    public String index(){
        return "index";
    }

    @RequestMapping(value = "/register")
    public String register(){
        return "register";
    }
}

2)创建UserController类,该类主要做的是登录注册和发邮箱以及激活用户的功能

package com.gmw.boot.send_meail.controller;

import com.gmw.boot.send_meail.entity.User;
import com.gmw.boot.send_meail.service.UserService;
import com.gmw.boot.send_meail.utils.MailUtils;
import com.gmw.boot.send_meail.utils.UUIDUtils;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Controller
@RequestMapping(value = "/user")
public class UserController {
    @Autowired
    public UserService userService;

    //用户的登录
    @PostMapping(value = "/login")
    public String queryByUsernameAndPassword(String username, String password, HttpSession session,Model model){
        //根据用户名和密码查询用户
        User user = userService.queryByUsernameAndPassword(username, password);

        if(!user.getState().equals(1)){
            model.addAttribute("error","该用户还未激活!!,请前往邮箱激活");
            return "error";
        }

        if(user == null && !user.getState().equals(1)){
            System.out.println("用户登录失败");
            return "redirect:/";
        }else{
            //保存登录成功的用户名
            session.setAttribute("loginUser",user.getUsername());
            session.setAttribute("time",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            return "main";
        }
    }

    //用户的注册
    @PostMapping(value = "/register")
    public String register(User user, HttpServletResponse response, Model model){
        System.out.println("user: " + user);

        //根据用户名查询,该用户是否已经存在
        boolean flag = userService.queryByUsername(user.getUsername());

        if(flag){
            model.addAttribute("exister","该用户已经存在,请重新输入");
            return "register";
        }

        if (user == null){
            model.addAttribute("error","用户注册失败,<a href='http://192.168.88.150:8888/register'>请重新注册</a>");
            return "error";
        }else{
            //改变用户的状态
            user.setState(1);
            //设置code
            String code = UUIDUtils.getUuid();
            user.setCode(code);
            //发送邮箱
            //内容
            String content="<a href='http://192.168.88.150:8888/user/activeUserServlet?code="+user.getCode()+"'>点击激活【"+user.getUsername()+"您的账户】</a>";

            MailUtils.sendMail(user.getEmail(),content,"激活邮件");

            //添加到数据库
            userService.register(user);

            System.out.println("邮箱发送成功");
            return "result";

        }
    }

    /**
     * 激活用户
     * @param code
     * @return
     */
    @GetMapping(value = "/activeUserServlet")
    @ResponseBody
    public String activeUserServlet(String code,HttpServletResponse response,Model model) throws IOException {
        //根据code获取用户
        User user = userService.queryByCode(code);

        //根据用户修改用户的状态
        boolean flag = userService.updateState(user);

        if(flag){
            return "<h1>激活成功!!<a href='http://192.168.88.150:8888/'>前往登录</a></h1>";
        }else{
            return "<h1>激活失败!!请联系管理员</h1>";
        }
    }

}

3)剩下的service和数据层都是简单的增删改查,就没必要在这里写了

1.2.7 编写SQL语句

CREATE TABLE `user`(
    id INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '用户id',
    username VARCHAR(255) NOT NULL COMMENT '用户名',
    email VARCHAR(255) NOT NULL COMMENT '用户邮箱',
    PASSWORD VARCHAR(255) NOT NULL COMMENT '用户密码',
    state INT(1) NOT NULL DEFAULT 0 COMMENT '用户激活状态:0表示未激活,1表示激活',
    CODE VARCHAR(255) NOT NULL COMMENT '激活码'
)ENGINE=INNODB DEFAULT CHARSET=utf8;

image.png

1.3 进行代码的测试

image.png
image.png

image.png

1.4 码云地址:https://gitee.com/Program_Monkey/send-email.git

image.png