会话跟踪技术
会话: 用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。
- 在一次会话中可以包含多次请求和响应;
- 从浏览器发出请求到服务端响应数据给前端之后,一次会话(在浏览器和服务器之间)就被建立了;
- 会话被建立后,如果浏览器或服务端都没有被关闭,则会话就会持续建立着;
//比如在我们访问京东的时候,当打开浏览器进入京东首页后,浏览器和京东的服务器之间就建立了一次会话,后面的搜索商品,查看商品的详情,加入购物车等都是在这一次会话中完成。
会话跟踪: 一种维护浏览器状态的方法,服务器需要
识别多次请求是否来自于同一浏览器
,以便在同一次会话的多次请求间共享数据
。
- 服务器需要用来识别请求是否来自同一个浏览器
- 服务器用来识别浏览器的过程,这个过程就是会话跟踪
- 服务器识别浏览器后就可以在同一个会话中多次请求之间来共享数据
会话跟踪的实现方式
- 客户端会话跟踪技术:Cookie
- 服务端会话跟踪技术:Session
这两个技术都可以实现会话跟踪,它们之间最大的区别:Cookie是存储在浏览器端而Session是存储在服务器端。
HTTP协议
浏览器使用HTTP协议或HTTPS协议与服务器建立连接。
HTTP(Hypertext Transfer Protocol) 是一种
用于在Web上
进行通信的协议。 它是一种无状态
的、应用层
的协议。
- AIM: 用于在客户端和服务器之间传输超文本(例如HTML、CSS、JavaScript)和其他资源(例如图像、视频)。
HTTP请求的特点:
无状态性 :
HTTP是一种无状态协议
,即服务器不会保留先前请求的状态信息。每个请求都是独立的,服务器仅根据请求和响应之间的交互进行处理。
- 这意味着服务器不能直接识别连续的请求是否来自同一个客户端。每个请求都必须包含足够的信息(如请求头、URL参数、Cookie等)来完整描述客户端的意图和操作;
- 无状态性的优势:使得服务器可以
更容易进行负载均衡和横向扩展
,服务器可以将请求路由到任何可用的服务器,无需考虑之前的状态,更好的应对高并发和大规模请求
;简化服务器设计
,提高服务器可靠性和独立性;可缓存性
:以根据请求的响应头中的缓存相关字段进行缓存控制,代理服务器可以有效地缓存响应,提高性能和减少网络流量。基于请求-响应模型
HTTP使用请求-响应模型。客户端发送HTTP请求到服务器,并等待服务器返回HTTP响应。请求包括请求方法(如GET、POST、PUT、DELETE等)、URL、请求头和请求体。响应包括状态码、响应头和响应体。URL和资源定位
HTTP使用统一资源定位符(URL)来标识和定位网络上的资源。客户端通过指定URL来请求特定的资源加密和安全
HTTP可以通过使用SSL或TLS协议来加密通信,形成HTTPS,以提供安全的数据传输。
概念
Cookie是一种用于在Web浏览器和服务器之间传递数据的机制。
- 是
由服务器发送给客户端浏览器
并存储在本地(客户端)的小型文本文件;- 浏览器在后续请求中会
将该文本文件作为HTTP头信息
的一部分发送回服务器;//注意的是,Cookie是存储在用户本地的文本文件,因此用户可以查看和修改Cookie。为了保护敏感信息,可以使用安全标志(secure)和HttpOnly属性来限制Cookie的访问性
cookie的应用场景
Cookie通常用于以下几个方面:
会话管理:
Cookie最常见的用途之一是管理用户的会话。服务器
可以在用户登录后创建一个包含会话标识符的Cookie
,并将其发送给浏览器
。浏览器
随后会将该Cookie存储
,并在后续的请求中将会话标识符作为Cookie头信息的一部分发送回服务器,以便服务器能够识别和跟踪用户的会话状态。用户识别:
Cookie还可以用于识别和跟踪用户的身份
。服务器可以在用户登录或进行其他身份验证操作后创建一个包含用户标识信息的Cookie,并将其发送给浏览器。浏览器随后会存储该Cookie,并在后续的请求中将用户标识信息作为Cookie头信息的一部分发送回服务器,以便服务器能够识别用户的身份。个性化体验:
Cookie可用于存储用户的偏好设置和个性化信息。服务器可以将用户的偏好设置等数据存储在Cookie
中,并在后续的请求中使用该Cookie提供个性化的体验。例如,保存用户的语言偏好、主题偏好或上次访问的页面等。跟踪和分析:
Cookie可用于跟踪用户在网站上的活动和行为。服务器可以使用Cookie来记录用户的访问时间、页面浏览记录和点击行为
等信息,从而进行用户行为分析和统计。
步骤:
- 创建cookie对象,设置数据
Cookie cookie = new Cookie(“username”, “zs”);- 发送cookie到客户端:使用resp对象
resp.addCookie(cookie);- 获取客户端携带的cookie,使用req对象
Cookie[] cookies = req.getCookies();- 遍历数组,获取每一个cookie对象:for
- 使用cookie对象方法获取数据
//创建喝发送cookie
@WebServlet("/aServlet")
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 创建Cookie对象,写入数据
Cookie cookie = new Cookie("username", "zs");
//2.发送cookie。resp
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
//获取cookie
@WebServlet("/bServlet")
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取cookie数据数组
Cookie[] cookies = req.getCookies();
//2. 遍历数组
for (Cookie cookie:cookies){
//3.获取数据
String name = cookie.getName(); //获取键
String value = cookie.getValue(); //获取值
System.out.println(name+":"+value);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
对于Cookie的实现原理是
基于HTTP协议
的,其中设计到HTTP协议中的两个请求头信息:案例分析
- AServlet给前端
发送
Cookie,BServlet从request中获取
Cookie的功能;- 对于AServlet响应数据的时候,Tomcat服务器都是基于HTTP协议来响应数据;
- 当Tomcat发现后端要返回的是一个Cookie对象之后,Tomcat就会在响应头中添加一行数据SetCookie:username=zs;
- 浏览器获取到响应结果后,从响应头中就可以获取到Set-Cookie对应值username=zs ,并将数据存储在浏览器的内存中;
- 浏览器再次发送请求给BServlet的时候,浏览器会自动在请求头中添加Cookie: username=zs发送给服务端BServlet;
- Request对象会把请求头中cookie对应的值封装成一个个Cookie对象,最终形成一个数组;
- BServlet通过Request对象获取到Cookie[]后,就可以从中获取自己需要的数据;
cookie的存活时间
- 默认情况下,cookie为
会话Cookie
,即仅在浏览器会话期间有效,在关闭浏览器后将被删除。- 设置最大存活时间 ,可以
指定Cookie从当前时间开始的存活时长
(以秒为单位)。
cookie.setMaxAge(int time);
- 正数:将cookie写到浏览器所在电脑的硬盘,持久化存储,到时间自动删除。
- 负数:默认值,还是会话cookie,关闭浏览器,cookie消失。
- 0:删除对应的cookie;
Cookie在存储中文或其他非ASCII字符时,需要进行
编码处理
。
实现思路为:
在AServlet中对中文进行URL编码,采用URLEncoder.encode(),将编码后的值存入Cookie中
在BServlet中获取Cookie中的值,获取的值为URL编码后的值
将获取的值在进行URL解码,采用URLDecoder.decode(),就可以获取到对应的中文值
@WebServlet("/aServlet")
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//发送Cookie
String value = "张三";
//对中文进行URL编码
value = URLEncoder.encode(value, "UTF-8");
System.out.println("存储数据:"+value);
//将编码后的值存入Cookie中
Cookie cookie = new Cookie("username",value);
//设置存活时间 ,1周 7天
cookie.setMaxAge(60*60*24*7);
//2. 发送Cookie,response
response.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
@WebServlet("/bServlet")
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取Cookie
//1. 获取Cookie数组
Cookie[] cookies = request.getCookies();
//2. 遍历数组
for (Cookie cookie : cookies) {
//3. 获取数据
String name = cookie.getName();
if("username".equals(name)){
String value = cookie.getValue();//获取的是URL编码后的值 %E5%BC%A0%E4%B8%89
//URL解码
value = URLDecoder.decode(value,"UTF-8");
System.out.println(name+":"+value);//value解码后为 张三
break;
}
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
概念
Session是指在客户端与服务器之间建立的一个临时交互期间。在Web开发中,会话是一种用于跟踪用户状态和存储用户数据的机制。
- 服务端会话跟踪技术:将
数据保存到服务端
(相比于cookie可以保证数据的一个安全)。
Session的工作流程
相关代码
1. 获取Session对象,使用的是request对象;
HttpSession session = request.getSession();
2. Session对象提供的功能
* 存储数据到 session 域中
```
void setAttribute(String name, Object o)
```
* 根据 key,获取值
```
Object getAttribute(String name)
```
* 根据 key,删除该键值对
```
void removeAttribute(String name)
```
Session快速入门步骤
需求: 在一个Servlet中往Session中存入数据,在另一个Servlet中获取Session中存入的数据
创建名为SessionDemo1的Servlet类
创建名为SessionDemo2的Servlet类
在SessionDemo1的方法中:获取Session对象、存储数据
在SessionDemo2的方法中:获取Session对象、获取数据
启动测试
@WebServlet("/sessionDemo1")
public class SessionDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 创建Session对象
HttpSession session = req.getSession();
//2.存储数据
session.setAttribute("username", "ls");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
package com.itheima.web;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet("/sessionDemo2")
public class SessionDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取数据,从session中
//1. 获取Session对象
HttpSession session = req.getSession();
//2. 获取数据
Object username = session.getAttribute("username");
System.out.println(username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
前提条件
一个浏览器在会话期间,请求的session是同一个
Session是基于Cookie实现的
具体来说,当用户第一次访问网站时,服务器会为该用户创建一个唯一的会话标识符(Session ID)。为了在用户的后续请求中跟踪会话,服务器会将这个会话标识符发送给客户端,并存储在Cookie中。
- 尽管
会话数据存储在服务器端
,但由于会话标识符存储在Cookie
中,因此客户端(浏览器)会在每次请求中将会话标识符发送给服务器,以便进行会话跟踪。这样,服务器就能够将每个请求与正确的会话相关联,实现了会话机制的跨请求和跨页面的状态保持。- 会话数据本身并不存储在Cookie中。Cookie只是用于存储会话标识符,而实际的会话数据存储在服务器端的会话数据存储区域(如内存、数据库等)中。这样做
既保护了会话数据的安全性,又提供了更大的存储空间和灵活性
。
(1)demo1在第一次获取session对象的时候,session对象会有一个唯一的标识,假如是`id:10`
(2)demo1在session中存入其他数据并处理完成所有业务后,需要通过Tomcat服务器响应结果给浏览器
(3)Tomcat服务器发现业务处理中使用了session对象,就会把session的唯一标识`id:10`当做一个cookie,添加`Set-Cookie:JESSIONID=10`到响应头中,并响应给浏览器
(4)浏览器接收到响应结果后,会把响应头中的coookie数据存储到浏览器的内存中
(5)浏览器在同一会话中访问demo2的时候,会把cookie中的数据按照`cookie: JESSIONID=10`的格式添加到请求头中并发送给服务器Tomcat
(6)demo2获取到请求后,从请求头中就读取cookie中的JSESSIONID值为10,然后就会到服务器内存中寻找`id:10`的session对象,如果找到了,就直接返回该对象,如果没有则新创建一个session对象
(7)关闭打开浏览器后,因为浏览器的cookie已被销毁,所以就没有JESSIONID的数据,服务端获取到的session就是一个全新的session对象
Q:服务器重启后,Session中的数据是否还在?
正常重启并不会;
R:Session的钝化和活化
钝化:在服务器正常关闭后,Tomcat会自动将Session数据写入硬盘的文件中
活化:再次启动服务器后,从文件中加载数据到Session中
注意:
session数据存储在服务端,服务器重启后,session数据会被保存
浏览器被关闭启动后,重新建立的连接就已经是一个全新的会话,获取的session数据也是一个新的对象
session的数据要想共享,浏览器不能关闭,所以session数据不能长期保存数据
cookie是存储在客户端,是可以长期保存
session的销毁会有两种方式:
- 默认情况下,无操作,30分钟自动销毁
- 调用Session对象的invalidate()进行销毁
失效时间,可以在web.xml文件里进行配置
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<session-config>
<session-timeout>100session-timeout>
session-config>
web-app>
调用Session对象的invalidate()进行销毁
在SessionDemo2类中添加session销毁的方法
@WebServlet("/demo2")
public class SessionDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取数据,从session中
//1. 获取Session对象
HttpSession session = request.getSession();
System.out.println(session);
// 销毁
session.invalidate();
//2. 获取数据
Object username = session.getAttribute("username");
System.out.println(username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
* 区别:
* 存储位置:Cookie 是将数据存储在客户端,Session 将数据存储在服务端
* 安全性:Cookie不安全,Session安全
* 数据大小:Cookie最大3KB,Session无大小限制
* 存储时间:Cookie可以通过setMaxAge()长期存储,Session默认30分钟
* 服务器性能:Cookie不占服务器资源,Session占用服务器资源
* 应用场景
根据具体的应用需求和安全考虑来选择合适的机制。
Cookie通常用于在客户端存储少量的信息
而Session通常用于在服务器端存储更多的会话数据。
同时,Cookie的存储时间相对较长,而Session的存储时间通常与用户的活动相关。
* 结论
* Cookie是用来保证用户在未登录情况下的身份识别
* Session是用来保存用户登录后的数据
Cookie的应用场景:
用户身份管理:
Cookie常用于管理用户的登录状态
。通过在用户登录时设置包含用户标识信息的Cookie,可以在用户的后续请求中通过Cookie来验证用户的身份,实现用户的持久登录状态
。个性化设置:
网站可以使用Cookie来存储用户的个性化设置
,例如用户的偏好、主题选择等。通过在Cookie中保存这些设置,可以在用户的每次访问中提供一致的用户体验。购物车和电子商务:
Cookie可以用于存储用户的购物车信息
,以便在用户浏览和购买商品时保持持久状态。通过在Cookie中保存购物车的内容,可以在用户访问网站的不同页面时保留购物车的信息。广告跟踪和定向广告:
Cookie可以用于跟踪用户的浏览行为和兴趣,并提供定向广告
。广告服务商可以通过在用户浏览网站时设置Cookie来收集用户数据,以便更好地了解用户的兴趣和行为,从而提供相关的广告。
Session的应用场景:
用户登录和权限管理:
Session通常用于管理用户的登录状态和权限
。通过在用户登录后创建一个唯一的会话标识符(Session ID),可以将用户的身份和权限信息存储在服务器端的会话数据中,从而实现对用户的身份验证和访问控制。表单数据和用户输入:
Session可以用于暂时存储用户提交的表单数据和用户输入
。例如,在多步表单流程中,可以使用Session来存储用户在不同步骤中输入的数据,以便在最后一步提交时进行整体处理。应用程序状态管理:
Session可以用于存储应用程序的状态和上下文信息
。例如,在Web应用程序中,可以使用Session来存储用户的浏览历史、页面访问计数等信息,以便在用户的不同请求中保持应用程序的状态。购物和订单管理:
Session可以用于管理用户的购物和订单信息。通过在Session中存储购物车的内容、订单状态和支付信息,可以实现在用户浏览和结算购物车时的持久状态。
用户登录注册案例:https://blog.csdn.net/meini32/article/details/132305323
新添功能:
- 完成用户登录功能,如果用户勾选“记住用户” ,则下次访问登录页面自动填充用户名密码
- 完成注册功能,并实现验证码功能
UserMapper
package com.mapper;
import com.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper {
//查全部
@Select("SELECT * FROM tb_user")
List<User> selectAll();
//根据用户名查询
@Select("SELECT * FROM tb_user where username=#{username}")
User selectByUserName(String username);
//根据用户名和密码查询
@Select("select * from tb_user where username = #{username} and password = #{password}")
User select(@Param("username") String username, @Param("password") String password);
/**
* 添加用户
* @param user
*/
@Insert("insert into tb_user values(null,#{username},#{password})")
void add(User user);
}
UserService
package com.service;
import com.mapper.UserMapper;
import com.pojo.User;
import com.util.SqlSessionFactoryUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
public class UserService {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtil.getSqlSessionFactory();
public User selectByUserName(String username){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.selectByUserName(username);
sqlSession.close();
return user;
}
public User login(String username,String password){
//2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 获取UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//4. 调用方法
User user = mapper.select(username, password);
//释放资源
sqlSession.close();
return user;
}
}
登录Servlet
package com.web;
import com.pojo.User;
import com.service.UserService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
private UserService service = new UserService();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接受username
// String username = "zhangsan";
String username = req.getParameter("username");
String password = req.getParameter("password");
//2. 调用service查询
User user = service.login(username, password);
//3. 判断
if(user != null){
//登录成功,跳转到查询所有的BrandServlet
//将登陆成功后的user对象,存储到session
HttpSession session = req.getSession();
session.setAttribute("user",user);
// String contextPath = req.getContextPath();
// resp.sendRedirect(contextPath+"/selectAllServlet");
resp.sendRedirect("hello.jsp");
}else {
// 登录失败,
// 存储错误信息到request
req.setAttribute("login_msg","用户名或密码错误");
// 跳转到login.jsp
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
//输出
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
登录和跳转页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page isELIgnored="false" %>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>logintitle>
<link href="css/login.css" rel="stylesheet">
head>
<body>
<div id="loginDiv" style="height: 350px">
<form action="/loginServlet" method="post" id="form">
<h1 id="loginMsg">LOGIN INh1>
<%-- <div id="errorMsg">用户名或密码不正确div>--%>
<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" type="checkbox">p>
<div id="subDiv">
<input type="submit" class="button" value="login up">
<input type="reset" class="button" value="reset">
<a href="register.html">没有账号?a>
div>
form>
div>
body>
html>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page isELIgnored="false" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titletitle>
head>
<body>
<h1>${user.username},欢迎您h1>
body>
html>
如果用户勾选“记住用户” ,则下次访问登陆页面自动填充用户名密码。这样可以提升用户的体验。
(1)在login.jsp为复选框设置值
(2)在LoginServlet获取复选框的值并在登录成功后进行设置Cookie
package com.web;
import com.pojo.User;
import com.service.UserService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
private UserService service = new UserService();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接受username
// String username = "zhangsan";
String username = req.getParameter("username");
String password = req.getParameter("password");
//获取复选框数据
String remember = req.getParameter("remember");
//2. 调用service查询
User user = service.login(username, password);
//3. 判断
if(user != null){
//判断用户是否勾选记住我,字符串写前面是为了避免出现空指针异常
if("1".equals(remember)){
//勾选了,发送Cookie
//1. 创建Cookie对象
Cookie c_username = new Cookie("username",username);
Cookie c_password = new Cookie("password",password);
// 设置Cookie的存活时间
c_username.setMaxAge( 60 * 60 * 24 * 7);
c_password.setMaxAge( 60 * 60 * 24 * 7);
//2. 发送
resp.addCookie(c_username);
resp.addCookie(c_password);
}
//将登陆成功后的user对象,存储到session
HttpSession session = req.getSession();
session.setAttribute("user",user);
resp.sendRedirect("hello.jsp");
}else {
// 登录失败,
// 存储错误信息到request
req.setAttribute("login_msg","用户名或密码错误");
// 跳转到login.jsp
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
//输出
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
(1)在login.jsp用户名的表单输入框使用value值给表单元素添加默认值,value可以使用
${cookie.username.value}
(2)在login.jsp密码的表单输入框使用value值给表单元素添加默认值,value可以使用
${cookie.password.value}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>logintitle>
<link href="css/login.css" rel="stylesheet">
head>
<body>
<div id="loginDiv" style="height: 350px">
<form action="/brand-demo/loginServlet" method="post" id="form">
<h1 id="loginMsg">LOGIN INh1>
<div id="errorMsg">${login_msg}div>
<p>Username:<input id="username" name="username" value="${cookie.username.value}" 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.html">没有账号?a>
div>
form>
div>
body>
html>
- 注册功能:保存用户信息到数据库
- 验证码功能
- 展示验证码:展示验证码图片,并可以点击切换
- 校验验证码:验证码填写不正确,则注册失败
注册页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page isELIgnored="false" %>
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.jsp">登录a>
div>
<form id="reg-form" action="/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" style="display:none">用户名不太受欢迎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>
UserMApper和Service
// 添加用户
@Insert("insert into tb_user values(null,#{username},#{password})")
void add(User user);
public boolean register(User user){
//2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 获取UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//4. 判断用户名是否存在
User u = mapper.selectByUserName(user.getUsername());
if(u == null){
// 用户名不存在,注册
mapper.add(user);
sqlSession.commit();
}
sqlSession.close();
return u == null;
}
注册servlet
package com.web;
import com.pojo.User;
import com.service.UserService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet("/registerServlet")
public class RegisterServlet extends HttpServlet {
private UserService service = new UserService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取用户名和密码数据
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = new User();
user.setUsername(username);
user.setPassword(password);
//2. 调用service 注册
boolean flag = service.register(user);
//3. 判断注册成功与否
if(flag){
//注册功能,跳转登陆页面
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 doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
验证码是什么?
- 验证码就是使用Java代码生成的一张图片
- 验证码的作用:防止机器自动注册,攻击服务器
实现
(1)前端发送请求给CheckCodeServlet
(2)CheckCodeServlet接收到请求后,生成验证码图片,将图片用Reponse对象的输出流写回到前端
步骤:
0. 修改Register.jsp页面,将验证码的图片从后台获取
1. 添加验证码工具类CheckCodeUtil;
2. 编写CheckCodeServlet类,用来接收请求生成验证码
3. 在CheckCodeServlet中生成验证码的时候,将验证码数据存入Session对象
4. 前端将验证码和注册数据提交到后台,交给RegisterServlet类
5. RegisterServlet类接收到请求和数据后,其中就有验证码,和Session中的验证码进行对比
6. 如果一致,则完成注册,如果不一致,则提示错误信息
//2. 编写CheckCodeServlet类,用来接收请求生成验证码
//3. 在CheckCodeServlet中生成验证码的时候,将验证码数据存入Session对象
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 生成验证码
ServletOutputStream os = resp.getOutputStream();
String checkCode = CheckCodeUtil.outputVerifyImage(100, 50, os, 4);
// 存入Session
HttpSession session = req.getSession();
session.setAttribute("checkCodeGen",checkCode);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
//4. 前端将验证码和注册数据提交到后台,交给RegisterServlet类
//5. RegisterServlet类接收到请求和数据后,其中就有验证码,和Session中的验证码进行对比
//6. 如果一致,则完成注册,如果不一致,则提示错误信息
@WebServlet("/registerServlet")
public class RegisterServlet extends HttpServlet {
private UserService service = new UserService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取用户名和密码数据
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = new User();
user.setUsername(username);
user.setPassword(password);
// 获取用户输入的验证码
String checkCode = request.getParameter("checkCode");
System.out.println("获取用户输入的验证码"+checkCode);
// 程序生成的验证码,从Session获取
HttpSession session = request.getSession();
String checkCodeGen = (String) session.getAttribute("checkCodeGen");
System.out.println("程序生成的验证码"+checkCodeGen);
// 比对
if(!checkCodeGen.equalsIgnoreCase(checkCode)){
request.setAttribute("register_msg","验证码错误");
request.getRequestDispatcher("/register.jsp").forward(request,response);
// 不允许注册
return;
}
//2. 调用service 注册
boolean flag = service.register(user);
//3. 判断注册成功与否
if(flag){
//注册功能,跳转登陆页面
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 doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}