会话——验证码注册与记住密码登录

1、需求分析

需求说明:

  1. 完成用户登录功能,如果用户勾选“记住用户” ,则下次访问登录页面自动填充用户名密码
  2. 完成注册功能,并实现验证码功能

image-20220211110320583

2、用户登录功能

  • 用户登录成功后,跳转到列表页面,并在页面上展示当前登录的用户名称
  • 用户登录失败后,跳转回登录页面,并在页面上展示对应的错误信息

image-20220211110333638

2.1、流程分析

  1. 前端通过表单发送请求和数据给Web层的LoginServlet
  2. 在LoginServlet中接收请求和数据[用户名和密码]
  3. LoginServlet接收到请求和数据后,调用Service层完成根据用户名和密码查询用户对象
  4. 在Service层需要编写UserService类,在类中实现login方法,方法中调用Dao层的UserMapper
  5. 在UserMapper接口中,声明一个根据用户名和密码查询用户信息的方法
  6. Dao层把数据查询出来以后,将返回数据封装到User对象,将对象交给Service层
  7. Service层将数据返回给Web层
  8. Web层获取到User对象后,判断User对象,如果为Null,则将错误信息响应给登录页面,如果不为Null,则跳转到主界面,并把当前登录用户的信息存入Session携带到主界面中。

image-20220211110813439

2.2、代码实现

登录核心流程

  1. 创建Web项目,这里是不使用骨架进行创建,具体步骤参考往期博客JavaWeb-IDEA利用Tomcat发布网站中的“不使用骨架搭建Web项目

image-20220211111914462

  1. 编写pom.xml文件,导入对应的依赖。其中共需要导入的依赖如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>session-test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <!-- 防止maven打包时出现乱码 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!--jsp-->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>

        <!--jstl-->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <!-- 添加slf4j日志api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.20</version>
        </dependency>
        <!-- 添加logback-classic依赖 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- 添加logback-core依赖 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- tomcat -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
            </plugin>
        </plugins>
    </build>

</project>
  1. 创建数据库,并新建mybatis-config.xml配置文件

    • 数据库创建
    CREATE DATABASE db1 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
    
    USE db1;
    
    CREATE TABLE tb_user (
    	id INT PRIMARY KEY AUTO_INCREMENT,
    	username VARCHAR(20) UNIQUE,
    	`password` VARCHAR(20)
    );
    
    INSERT tb_user(username, `password`)
    VALUES('张三', '123');
    
    INSERT tb_user(username, `password`)
    VALUES('李四', '456');
    
    SELECT * FROM tb_user;
    
    • xml文件编写
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <!-- 起别名 -->
        <typeAliases>
            <package name="com.xbaozi.pojo"/>
        </typeAliases>
    
        <!-- 配置数据库环境 -->
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql:///db1?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
    
        <!--扫描mapper-->
        <mappers>
            <package name="com.xbaozi.mapper"/>
        </mappers>
    </configuration>
    
  2. 创建SQL映射文件

  • 编写接口中的方法
package com.xbaozi.mapper;

import com.xbaozi.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

/**
 * @author xBaozi
 * @version 1.0
 * @interfacename UserMapper
 * @description 创建UserMapper
 * @date 2022/2/10 14:03
 */
public interface UserMapper {
    /**
     * @description 根据用户名和密码查询用户对象
     * @author xBaozi
     * @date 14:08 2022/2/10
     * @param username 用户名
     * @param password 密码
     * @return 返回一个对应的用户对象,否则为空
     **/
    @Select("select * from tb_user where username = #{username} and password = #{password}")
    User select(@Param("username") String username, @Param("password")  String password);
}
  • 编写mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xbaozi.mapper.UserMapper">

</mapper>
  1. 对工具类SqlSessionFactoryUtil进行编写
package com.xbaozi.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author xBaozi
 * @version 1.0
 * @description 对获取SqlSessionFactory对象的语句进行封装
 * @className SqlSessionFactoryUtil
 * @date 2022/2/10 16:09
 */
public class SqlSessionFactoryUtil {
    private static SqlSessionFactory sqlSessionFactory = null;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }
}

  1. 对Service层中的UserService和LoginService进行编写
  • com.xbaozi.service包下,创建UserService类
package com.xbaozi.service;

import com.xbaozi.mapper.UserMapper;
import com.xbaozi.pojo.User;
import com.xbaozi.util.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

/**
 * @author xBaozi
 * @version 1.0
 * @className UserService
 * @description 封装用户服务类
 * @date 2022/2/10 16:14
 */
public class UserService {
    /** 获取SqlSessionFactory对象 */
    SqlSessionFactory factory = SqlSessionFactoryUtil.getSqlSessionFactory();

    /**
     * @description 用户登录
     * @author xBaozi
     * @date 16:21 2022/2/10
     * @param username  所登陆的用户名
     * @param password  对应的登录密码
     * @return  返回对应的用户对象,否则为空
     **/
    public User login(String username, String password) {
        // 获取SqlSession
        SqlSession sqlSession = factory.openSession();

        // 获取UserMapper
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        // 调用方法
        User user = userMapper.select(username, password);

        // 释放资源
        sqlSession.close();

        return user;
    }

}
  • com.xbaozi.web包下,创建LoginServlet类
package com.xbaozi.web;

import com.xbaozi.pojo.User;
import com.xbaozi.service.UserService;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * @author xBaozi
 * @version 1.0
 * @className LoginServlet
 * @description 实现用户登录功能
 * @date 2022/2/10 16:27
 */
@WebServlet(urlPatterns = "/loginServlet")
public class LoginServlet extends HttpServlet {
    private UserService service = new UserService();

    @Override
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        // 1. 获取用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // 避免用户名存在中文导致乱码
        username = new String(username.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

        System.out.println("Username: " + username);
        System.out.println("password: " + password);

        // 2. 调用UserService的login方法进行查询
        User user = service.login(username, password);

        // 3. 对user对象进行判空
        if (user != null) {
            //将登陆成功后的user对象,存储到session
            HttpSession session = request.getSession();
            session.setAttribute("user", user);

            // 通过request转发
            request.getRequestDispatcher("/index.jsp").forward(request, response);
        } else {
            // 登录失败,存储错误信息到request
            request.setAttribute("login_msg","用户名或密码错误");
            // 跳转到login.jsp
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }

    @Override
    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        this.doPost(request, response);
    }
}
  1. 在webapp下编写前端界面验证后端代码

    • 编写login.jsp,这里值得注意的是表单需要提交到登录对应的Servlet,即loginServlet
    <%--
      Created by IntelliJ IDEA.
      User: Baozi
      Date: 2022/2/10
      Time: 13:54
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>login</title>
            <link href="css/login.css" rel="stylesheet">
        </head>
        <body>
            <div id="loginDiv" style="height: 350px">
                <form action="/session-test/loginServlet" method="post" id="form">
                    <h1 id="loginMsg">LOGIN IN</h1>
                    <div id="errorMsg">${login_msg}</div>
                    <p>Username:<input id="username" name="username" type="text"></p>
    
                    <p>Password:<input id="password" name="password" type="password"></p>
                    <p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p>
                    <div id="subDiv">
                        <input type="submit" class="button" value="login up">
                        <input type="reset" class="button" value="reset">&nbsp;&nbsp;&nbsp;
                        <a href="register.jsp">没有账号?</a>
                    </div>
                </form>
            </div>
        </body>
    </html>
    
    • 编写login.css
    * {
        margin: 0;
        padding: 0;
    }
    
    html {
        height: 100%;
        width: 100%;
        overflow: hidden;
        margin: 0;
        padding: 0;
        background: url(../imgs/Desert1.jpg) no-repeat 0px 0px;
        background-repeat: no-repeat;
        background-size: 100% 100%;
        -moz-background-size: 100% 100%;
    }
    
    body {
        display: flex;
        align-items: center;
        justify-content: center;
        height: 100%;
    }
    
    #loginDiv {
        width: 37%;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 380px;
        background-color: rgba(75, 81, 95, 0.3);
        box-shadow: 7px 7px 17px rgba(52, 56, 66, 0.5);
        border-radius: 5px;
    }
    
    #name_trip {
        margin-left: 50px;
        color: red;
    }
    
    p {
        margin-top: 30px;
        margin-left: 20px;
        color: azure;
    }
    
    
    #remember{
        margin-left: 15px;
        border-radius: 5px;
        border-style: hidden;
        background-color: rgba(216, 191, 216, 0.5);
        outline: none;
        padding-left: 10px;
        height: 20px;
        width: 20px;
    }
    #username{
        width: 200px;
        margin-left: 15px;
        border-radius: 5px;
        border-style: hidden;
        height: 30px;
        background-color: rgba(216, 191, 216, 0.5);
        outline: none;
        color: #f0edf3;
        padding-left: 10px;
    }
    #password{
        width: 202px;
        margin-left: 15px;
        border-radius: 5px;
        border-style: hidden;
        height: 30px;
        background-color: rgba(216, 191, 216, 0.5);
        outline: none;
        color: #f0edf3;
        padding-left: 10px;
    }
    .button {
        border-color: cornsilk;
        background-color: rgba(100, 149, 237, .7);
        color: aliceblue;
        border-style: hidden;
        border-radius: 5px;
        width: 100px;
        height: 31px;
        font-size: 16px;
    }
    
    #subDiv {
        text-align: center;
        margin-top: 30px;
    }
    #loginMsg{
        text-align: center;
        color: aliceblue;
    }
    #errorMsg{
        text-align: center;
        color:red;
    }
    
    • 编写index.jsp
    <%--
      Created by IntelliJ IDEA.
      User: Baozi
      Date: 2022/2/10
      Time: 16:42
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
        <head>
            <title>index</title>
        </head>
        <body>
            <h1>Welcome! Dear ${user.username}</h1>
        </body>
    </html>
    
    

2.3、结果演示

启动Tomcat,打开登录界面进行代码验证

  1. 正确登录情况

image-20220211113329312

image-20220211113454570

  1. 用户名或密码错误情况

image-20220211195614514

image-20220211195757930

3、登录记住密码功能

如果用户勾选“记住用户” ,则下次访问登陆页面自动填充用户名密码。这样可以提升用户的体验。

image-20220212114701169

3.1、流程分析

因为记住我功能要实现的效果是,就算用户把浏览器关闭过几天再来访问也能自动填充,所以需要将登陆信息存入一个可以长久保存,并且能够在浏览器关闭重新启动后依然有效的地方,很容易想到的就是Cookie,所以:

  • 将用户名和密码写入Cookie中,并且持久化存储Cookie,下次访问浏览器会自动携带Cookie
  • 在页面获取Cookie数据后,设置到用户名和密码框中
  • 用户在登陆成功且勾选了记住我的单选框后将用户登录信息写入Cookie
  • 在页面可以使用EL表达式${cookie.key.value}对cookie中数据进行获取,其中的key:指的是存储在cookie中的键名称

image-20220212114829265

3.2、代码实现

  1. login.jsp中的选择框添加值做以判断
<!-- 只单独写出了改变的一条语句 -->
<p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p>
  1. LoginServlet中的登录成功判断中添加是否勾选了选择框的判断并以此添加cookie
/**
 * @author xBaozi
 * @version 1.0
 * @className LoginServlet
 * @description 实现用户登录功能
 * @date 2022/2/10 16:27
 */
@WebServlet(urlPatterns = "/loginServlet")
public class LoginServlet extends HttpServlet {
    private UserService service = new UserService();
    private String REMEMBER_KEY = "1";

    @Override
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        // 1. 获取用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // 获取单选框中的值
        String remember = request.getParameter("remember");

        // 避免用户名存在中文导致乱码
         username = new String(username.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

        System.out.println("Username: " + username);
        System.out.println("password: " + password);

        // 2. 调用UserService的login方法进行查询
        User user = service.login(username, password);

        // 3. 对user对象进行判空
        if (user != null) {
            // 判断用户是否勾选记住我,字符串写前面是为了避免出现空指针异常
            if (REMEMBER_KEY.equals(remember)) {
                // 创建Cookie对象
                Cookie cUsername = new Cookie("username", URLEncoder.encode(username, "UTF-8"));
                Cookie cPassword = new Cookie("password", password);

                // 设置Cookie存活时间为7天
                cUsername.setMaxAge(60 * 60 * 24 * 7);
                cPassword.setMaxAge(60 * 60 * 24 * 7);

                // 添加Cookie对象
                response.addCookie(cUsername);
                response.addCookie(cPassword);
            }
            //将登陆成功后的user对象,存储到session
            HttpSession session = request.getSession();
            session.setAttribute("user", user);

            // 通过request转发
            request.getRequestDispatcher("/index.jsp").forward(request, response);
        } else {
            // 登录失败,存储错误信息到request
            request.setAttribute("login_msg","用户名或密码错误");
            // // 通过request转发,跳转到login.jsp
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }

    @Override
    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        this.doPost(request, response);
    }
}
  1. 再次对login.jsp进行修改从而获取cookie,并通过EL表达式将对应的账号密码分别设置为账号和密码输入框中的值
<%@ page import="java.net.URLDecoder" %><%--
  Created by IntelliJ IDEA.
  User: Baozi
  Date: 2022/2/10
  Time: 13:54
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String username = "";
    Cookie[] cookies = request.getCookies();
    for (Cookie cookie : cookies) {
        if ("username".equals(cookie.getName())) {
            username = URLDecoder.decode(cookie.getValue(), "utf-8");
            request.setAttribute("username", username);
            break;
        }
    }
%>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>login</title>
        <link href="css/login.css" rel="stylesheet">
    </head>
    <body>
        <div id="loginDiv" style="height: 350px">
            <form action="/session-test/loginServlet" method="post" id="form">
                <h1 id="loginMsg">LOGIN IN</h1>
                <div id="errorMsg">${login_msg}</div>
                <p>Username:<input id="username" name="username" value="${username}" type="text"></p>

                <p>Password:<input id="password" name="password" value="${cookie.password.value}" type="password"></p>
                <p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p>
                <div id="subDiv">
                    <input type="submit" class="button" value="login up">
                    <input type="reset" class="button" value="reset">&nbsp;&nbsp;&nbsp;
                    <a href="register.jsp">没有账号?</a>
                </div>
            </form>
        </div>
    </body>
</html>

3.3、结果演示

启动Tomcat,对该功能进行演示。

  1. 没有勾选记住我选项的情况,刷新再次进入登录界面会发现没有保存账号密码

image-20220211113329312

image-20220212120345078

  1. 勾选了记住我选项的情况,刷新再次进入登录界面会发现默认输入了上次登录时的账号密码

image-20220212120729193

4、用户注册功能

  • 注册功能:保存用户信息到数据库

  • 验证码功能

    • 展示验证码:展示验证码图片,并可以点击切换
    • 校验验证码:验证码填写不正确,则注册失败

    image-20220212121913115

4.1、流程分析

  1. 前端通过表单发送请求和数据给Web层的RegisterServlet
  2. 在RegisterServlet中接收请求和数据[用户名和密码]
  3. RegisterServlet接收到请求和数据后,调用Service层完成用户信息的保存
  4. 在Service层需要编写UserService类,在类中实现register方法,需要判断用户是否已经存在,如果不存在,则完成用户数据的保存
  5. 在UserMapper接口中,声明两个方法,一个是根据用户名查询用户信息方法,另一个是保存用户信息方法
  6. 在UserService类中保存成功则返回true,失败则返回false,将数据返回给Web层
  7. Web层获取到结果后,如果返回的是true,则提示注册成功,并转发到登录页面,如果返回false则提示用户名已存在并转发到注册页面

image-20220212122104331

4.2、代码实现

  1. 完成Dao层中的接口编写
package com.xbaozi.mapper;

import com.xbaozi.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

/**
 * @author xBaozi
 * @version 1.0
 * @interfacename UserMapper
 * @description 创建UserMapper
 * @date 2022/2/10 14:03
 */
public interface UserMapper {
    /**
     * @description 根据用户名和密码查询用户对象
     * @author xBaozi
     * @date 14:08 2022/2/10
     * @param username 用户名
     * @param password 密码
     * @return 返回一个对应的用户对象,否则为空
     **/
    @Select("select * from tb_user where username = #{username} and password = #{password}")
    User select(@Param("username") String username, @Param("password")  String password);

    /**
     * @description 根据用户名查询用户对象
     * @author xBaozi
     * @date 14:15 2022/2/10
     * @param username 用户名
     * @return  返回一个对应的用户对象,否则为空
     **/
    @Select("select * from tb_user where username = #{username}")
    User selectByName(@Param("username") String username);

    /**
     * @description 添加用户
     * @author xBaozi
     * @date 14:18 2022/2/10
     * @param user  需要添加的用户对象
     **/
    @Insert("insert into tb_user values(null, #{username}, #{password})")
    void addUser(User user);
}
  1. 编写Service层中UserService的注册方法
/**
 * @description 用户注册
 * @author xBaozi
 * @date 11:35 2022/2/13
 * @param user  需要注册的用户对象
 * @return      返回是否注册成功
 **/
public boolean register(User user) {
    // 获取SqlSession
    SqlSession sqlSession = factory.openSession();
    // 获取UserMapper
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 调用方法
    User u = userMapper.selectByName(user.getUsername());
    // 对用户是否存在判定
    if (u == null) {
        // 用户不存在进行注册操作
        userMapper.addUser(user);
        sqlSession.commit();
    }
    // 关闭资源
    sqlSession.close();
    return u == null;
}
  1. 编写RegisterServlet实现注册功能
/**
 * @author xBaozi
 * @version 1.0
 * @className RegisterServlet
 * @description 实现用户注册功能
 * @date 2022/2/15 14:17
 */
@WebServlet(urlPatterns = "/registerServlet")
public class RegisterServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 获取用户名和密码数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // 避免用户名存在中文导致乱码
        username = new String(username.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

        // 2. 封装成User对象
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);

        // 3. 调用service中的注册方法
        boolean isRegister = new UserService().register(user);

        // 4. 判断是否注册成功
        if (isRegister) {
            // 注册成功
            request.setAttribute("register_msg", "新用户注册成功");
            request.getRequestDispatcher("login.jsp").forward(request, response);
        } else {
            // 注册失败
            request.setAttribute("register_msg", "该用户名已存在");
            request.getRequestDispatcher("register.jsp").forward(request, response);
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
  1. 完成register.jsp的编写进行测试
<%--
  Created by IntelliJ IDEA.
  User: Baozi
  Date: 2022/2/15
  Time: 14:39
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>欢迎注册</title>
        <link href="css/register.css" rel="stylesheet">
    </head>
    <body>
        <div class="form-div">
            <div class="reg-content">
                <h1>欢迎注册</h1>
                <span>已有帐号?</span> <a href="login.html">登录</a>
            </div>
            <form id="reg-form" action="/session-test/registerServlet" method="post">
                <table>
                    <tr>
                        <td>用户名</td>
                        <td class="inputs">
                            <input name="username" type="text" id="username">
                            <br>
                            <span id="username_err" class="err_msg">${register_msg}</span>
                        </td>
                    </tr>
                    <tr>
                        <td>密码</td>
                        <td class="inputs">
                            <input name="password" type="password" id="password">
                            <br>
                            <span id="password_err" class="err_msg" style="display: none">密码格式有误</span>
                        </td>
                    </tr>
                    <tr>
                        <td>验证码</td>
                        <td class="inputs">
                            <input name="checkCode" type="text" id="checkCode">
                            <img src="imgs/a.jpg">
                            <a href="#" id="changeImg" >看不清?</a>
                        </td>
                    </tr>
                </table>
                <div class="buttons">
                    <input value="注 册" type="submit" id="reg_btn">
                </div>
                <br class="clear">
            </form>
        </div>
    </body>
</html>

--------------------css---------------------

* {
    margin: 0;
    padding: 0;
    list-style-type: none;
}
.reg-content{
    padding: 30px;
    margin: 3px;
}
a, img {
    border: 0;
}

body {
    background-image: url("../imgs/reg_bg_min.jpg") ;
    text-align: center;
}

table {
    border-collapse: collapse;
    border-spacing: 0;
}

td, th {
    padding: 0;
    height: 90px;

}
.inputs{
    vertical-align: top;
}

.clear {
    clear: both;
}

.clear:before, .clear:after {
    content: "";
    display: table;
}

.clear:after {
    clear: both;
}

.form-div {
    background-color: rgba(255, 255, 255, 0.27);
    border-radius: 10px;
    border: 1px solid #aaa;
    width: 424px;
    margin-top: 150px;
    margin-left:1050px;
    padding: 30px 0 20px 0px;
    font-size: 16px;
    box-shadow: inset 0px 0px 10px rgba(255, 255, 255, 0.5), 0px 0px 15px rgba(75, 75, 75, 0.3);
    text-align: left;
}

.form-div input[type="text"], .form-div input[type="password"], .form-div input[type="email"] {
    width: 268px;
    margin: 10px;
    line-height: 20px;
    font-size: 16px;
}

.form-div input[type="checkbox"] {
    margin: 20px 0 20px 10px;
}

.form-div input[type="button"], .form-div input[type="submit"] {
    margin: 10px 20px 0 0;
}

.form-div table {
    margin: 0 auto;
    text-align: right;
    color: rgba(64, 64, 64, 1.00);
}

.form-div table img {
    vertical-align: middle;
    margin: 0 0 5px 0;
}

.footer {
    color: rgba(64, 64, 64, 1.00);
    font-size: 12px;
    margin-top: 30px;
}

.form-div .buttons {
    float: right;
}

input[type="text"], input[type="password"], input[type="email"] {
    border-radius: 8px;
    box-shadow: inset 0 2px 5px #eee;
    padding: 10px;
    border: 1px solid #D4D4D4;
    color: #333333;
    margin-top: 5px;
}

input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus {
    border: 1px solid #50afeb;
    outline: none;
}

input[type="button"], input[type="submit"] {
    padding: 7px 15px;
    background-color: #3c6db0;
    text-align: center;
    border-radius: 5px;
    overflow: hidden;
    min-width: 80px;
    border: none;
    color: #FFF;
    box-shadow: 1px 1px 1px rgba(75, 75, 75, 0.3);
}

input[type="button"]:hover, input[type="submit"]:hover {
    background-color: #5a88c8;
}

input[type="button"]:active, input[type="submit"]:active {
    background-color: #5a88c8;
}
.err_msg{
    color: red;
    padding-right: 170px;
}
#password_err,#tel_err{
    padding-right: 195px;
}

#reg_btn{
    margin-right:50px; width: 285px; height: 45px; margin-top:20px;
}

#checkCode{
    width: 100px;
}

#changeImg{
    color: aqua;
}
  1. 如果注册成功,需要把成功信息展示在登录页面,所以也需要修改login.jsp
修改前:<div id="errorMsg">${login_msg}</div>
修改后:<div id="errorMsg">${login_msg} ${register_msg}</div>

4.3、结果演示

  1. 用户名已存在情况

image-20220215152136429

  1. 注册成功情况

image-20220215152221877

5、注册验证码功能

展示验证码:展示验证码图片,并可以点击切换。

  • 验证码就是使用Java代码生成的一张图片

  • 验证码的作用:防止机器自动注册,攻击服务器

  • 生成验证码和校验验证码是两次请求,此处就需要在一个会话的两次请求之间共享数据

  • 验证码属于安全数据类的,所以我们选中Session来存储验证码数据。

5.1、流程分析

  1. 前端发送请求给CheckCodeServlet
  2. CheckCodeServlet接收到请求后,生成验证码图片,将图片用Reponse对象的输出流写回到前端
  3. 在CheckCodeServlet中生成验证码的时候,将验证码数据存入Session对象
  4. 前端将验证码和注册数据提交到后台,交给RegisterServlet类
  5. RegisterServlet类接收到请求和数据后,其中就有验证码,和Session中的验证码进行对比
  6. 如果一致,则完成注册,如果不一致,则提示错误信息

image-20220215152912357

5.2、代码实现

  1. 编写CheckCodeServlet类,用来接收请求生成验证码与接收
/**
 * @author xBaozi
 * @version 1.0
 * @className CheckCodeServlet
 * @description 用于验证码的生成和验证
 * @date 2022/2/15 15:33
 */
@WebServlet(urlPatterns = "/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 生成验证码
        ServletOutputStream os = response.getOutputStream();
        String checkCode = CheckCodeUtil.outputVerifyImage(100, 50, os, 4);
        System.out.println(checkCode);

        // 将数据存入session
        HttpSession session = request.getSession();
        session.setAttribute("CheckCodeGen", checkCode);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
  1. 在RegisterServlet中,获取页面的和session对象中的验证码,进行对比
/**
 * @author xBaozi
 * @version 1.0
 * @className RegisterServlet
 * @description 实现用户注册功能
 * @date 2022/2/15 14:17
 */
@WebServlet(urlPatterns = "/registerServlet")
public class RegisterServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 获取用户名和密码数据
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // 避免用户名存在中文导致乱码
        username = new String(username.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);

        // 2. 封装成User对象
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);

        // 获取用户输入的验证码
        String checkCode = request.getParameter("checkCode");

        // 程序生成的验证码,从Session获取
        HttpSession session = request.getSession();
        String checkCodeGen = (String) session.getAttribute("CheckCodeGen");

        // 比对
        if(!checkCodeGen.equalsIgnoreCase(checkCode)){

            request.setAttribute("register_msg","验证码错误");
            request.getRequestDispatcher("/register.jsp").forward(request,response);

            // 不允许注册
            return;
        }

        // 3. 调用service中的注册方法
        boolean isRegister = new UserService().register(user);

        // 4. 判断是否注册成功
        if (isRegister) {
            // 注册成功
            request.setAttribute("register_msg", "新用户注册成功");
            request.getRequestDispatcher("login.jsp").forward(request, response);
        } else {
            // 注册失败
            request.setAttribute("register_msg", "该用户名已存在");
            request.getRequestDispatcher("register.jsp").forward(request, response);
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
  1. 修改register.jsp界面代码,并添加点击事件
<%--
  Created by IntelliJ IDEA.
  User: Baozi
  Date: 2022/2/15
  Time: 14:39
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>欢迎注册</title>
        <link href="css/register.css" rel="stylesheet">
    </head>
    <body>
        <div class="form-div">
            <div class="reg-content">
                <h1>欢迎注册</h1>
                <span>已有帐号?</span> <a href="login.html">登录</a>
            </div>
            <form id="reg-form" action="/session-test/registerServlet" method="post">
                <table>
                    <tr>
                        <td>用户名</td>
                        <td class="inputs">
                            <input name="username" type="text" id="username">
                            <br>
                            <span id="username_err" class="err_msg">${register_msg}</span>
                        </td>
                    </tr>
                    <tr>
                        <td>密码</td>
                        <td class="inputs">
                            <input name="password" type="password" id="password">
                            <br>
                            <span id="password_err" class="err_msg" style="display: none">密码格式有误</span>
                        </td>
                    </tr>
                    <tr>
                        <td>验证码</td>
                        <td class="inputs">
                            <input name="checkCode" type="text" id="checkCode">
                            <img id="checkCodeImg" src="/session-test/checkCodeServlet">
                            <a href="#" id="changeImg" >看不清?</a>
                        </td>
                    </tr>
                </table>
                <div class="buttons">
                    <input value="注 册" type="submit" id="reg_btn">
                </div>
                <br class="clear">
            </form>
        </div>
        <script>
            <%-- a标签点击事件 --%>
            document.getElementById("changeImg").onclick = function () {
                document.getElementById("checkCodeImg").src = "/session-test/checkCodeServlet?"+new Date().getMilliseconds();
            }
            <%-- 图片点击事件 --%>
            document.getElementById("checkCodeImg").onclick = function () {
                document.getElementById("checkCodeImg").src = "/session-test/checkCodeServlet?"+new Date().getMilliseconds();
            }
        </script>
    </body>
</html>

5.3、结果演示

  1. 验证码缺省或错误

image-20220215160118233

  1. 验证码正确且注册用户合法

image-20220215160323771

完结走人

在这里插入图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈宝子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值