文章目录
1、需求分析
需求说明:
- 完成用户登录功能,如果用户勾选“记住用户” ,则下次访问登录页面自动填充用户名密码
- 完成注册功能,并实现验证码功能
2、用户登录功能
- 用户登录成功后,跳转到列表页面,并在页面上展示当前登录的用户名称
- 用户登录失败后,跳转回登录页面,并在页面上展示对应的错误信息
2.1、流程分析
- 前端通过表单发送请求和数据给Web层的LoginServlet
- 在LoginServlet中接收请求和数据[用户名和密码]
- LoginServlet接收到请求和数据后,调用Service层完成根据用户名和密码查询用户对象
- 在Service层需要编写UserService类,在类中实现login方法,方法中调用Dao层的UserMapper
- 在UserMapper接口中,声明一个根据用户名和密码查询用户信息的方法
- Dao层把数据查询出来以后,将返回数据封装到User对象,将对象交给Service层
- Service层将数据返回给Web层
- Web层获取到User对象后,判断User对象,如果为Null,则将错误信息响应给登录页面,如果不为Null,则跳转到主界面,并把当前登录用户的信息存入Session携带到主界面中。
2.2、代码实现
- 创建Web项目,这里是不使用骨架进行创建,具体步骤参考往期博客JavaWeb-IDEA利用Tomcat发布网站中的“不使用骨架搭建Web项目”
- 编写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>
-
创建数据库,并新建
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&useUnicode=true&characterEncoding=utf8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!--扫描mapper--> <mappers> <package name="com.xbaozi.mapper"/> </mappers> </configuration>
-
创建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>
- 对工具类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;
}
}
- 对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);
}
}
-
在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"> <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>
- 编写login.jsp,这里值得注意的是表单需要提交到登录对应的Servlet,即
2.3、结果演示
启动Tomcat,打开登录界面进行代码验证
- 正确登录情况
- 用户名或密码错误情况
3、登录记住密码功能
如果用户勾选“记住用户” ,则下次访问登陆页面自动填充用户名密码。这样可以提升用户的体验。
3.1、流程分析
因为记住我
功能要实现的效果是,就算用户把浏览器关闭过几天再来访问也能自动填充,所以需要将登陆信息存入一个可以长久保存,并且能够在浏览器关闭重新启动后依然有效的地方,很容易想到的就是Cookie,所以:
- 将用户名和密码写入Cookie中,并且持久化存储Cookie,下次访问浏览器会自动携带Cookie
- 在页面获取Cookie数据后,设置到用户名和密码框中
- 用户在登陆成功且勾选了
记住我
的单选框后将用户登录信息写入Cookie - 在页面可以使用EL表达式
${cookie.key.value}
对cookie中数据进行获取,其中的key:指的是存储在cookie中的键名称
3.2、代码实现
- 为
login.jsp
中的选择框添加值做以判断
<!-- 只单独写出了改变的一条语句 -->
<p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p>
- 在
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);
}
}
- 再次对
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">
<a href="register.jsp">没有账号?</a>
</div>
</form>
</div>
</body>
</html>
3.3、结果演示
启动Tomcat,对该功能进行演示。
- 没有勾选记住我选项的情况,刷新再次进入登录界面会发现没有保存账号密码
- 勾选了记住我选项的情况,刷新再次进入登录界面会发现默认输入了上次登录时的账号密码
4、用户注册功能
-
注册功能:保存用户信息到数据库
-
验证码功能
- 展示验证码:展示验证码图片,并可以点击切换
- 校验验证码:验证码填写不正确,则注册失败
4.1、流程分析
- 前端通过表单发送请求和数据给Web层的RegisterServlet
- 在RegisterServlet中接收请求和数据[用户名和密码]
- RegisterServlet接收到请求和数据后,调用Service层完成用户信息的保存
- 在Service层需要编写UserService类,在类中实现register方法,需要判断用户是否已经存在,如果不存在,则完成用户数据的保存
- 在UserMapper接口中,声明两个方法,一个是根据用户名查询用户信息方法,另一个是保存用户信息方法
- 在UserService类中保存成功则返回true,失败则返回false,将数据返回给Web层
- Web层获取到结果后,如果返回的是true,则提示
注册成功
,并转发到登录页面,如果返回false则提示用户名已存在
并转发到注册页面
4.2、代码实现
- 完成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);
}
- 编写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;
}
- 编写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);
}
}
- 完成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;
}
- 如果注册成功,需要把成功信息展示在登录页面,所以也需要修改login.jsp
修改前:<div id="errorMsg">${login_msg}</div>
修改后:<div id="errorMsg">${login_msg} ${register_msg}</div>
4.3、结果演示
- 用户名已存在情况
- 注册成功情况
5、注册验证码功能
展示验证码:展示验证码图片,并可以点击切换。
-
验证码就是使用Java代码生成的一张图片
-
验证码的作用:防止机器自动注册,攻击服务器
-
生成验证码和校验验证码是两次请求,此处就需要在一个会话的两次请求之间共享数据
-
验证码属于安全数据类的,所以我们选中Session来存储验证码数据。
5.1、流程分析
- 前端发送请求给CheckCodeServlet
- CheckCodeServlet接收到请求后,生成验证码图片,将图片用Reponse对象的输出流写回到前端
- 在CheckCodeServlet中生成验证码的时候,将验证码数据存入Session对象
- 前端将验证码和注册数据提交到后台,交给RegisterServlet类
- RegisterServlet类接收到请求和数据后,其中就有验证码,和Session中的验证码进行对比
- 如果一致,则完成注册,如果不一致,则提示错误信息
5.2、代码实现
- 编写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);
}
}
- 在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);
}
}
- 修改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、结果演示
- 验证码缺省或错误
- 验证码正确且注册用户合法
完结走人