会话技术
概念
会话:一次会话中包含多次请求和响应。
一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
功能:
在一次会话的范围内的多次请求间,共享数据
方式:
- 客户端会话技术:
Cookie
- 服务器端会话技术:
Session
Cookie:
概念:
客户端会话技术,将数据保存到客户端
快速入门
使用步骤:
创建Cookie
对象,绑定数据
1
| new Cookie(String name, String value)
|
发送Cookie
对象
1
| response.addCookie(Cookie cookie)
|
获取Cookie
,拿到数据
1
| Cookie[] request.getCookies()
|
示例:
首先创建CookieDemo1
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @WebServlet("/cookieDemo1") public class CookieDemo1 extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Cookie cookie=new Cookie("msg","hello");
resp.addCookie(cookie); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } }
|
然后创建CookieDemo2
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @WebServlet("/cookieDemo2") public class CookieDemo2 extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Cookie [] cs=req.getCookies(); if(cs!=null){ for(Cookie c:cs){ String name=c.getName(); String value=c.getValue(); System.out.println(name+":"+value); } } }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } }
|
启动服务器,分别访问http://localhost:8080/servlet_cookie/cookieDemo
和http://localhost:8080/servlet_cookie/cookieDemo2
实现原理
基于响应头set-cookie和请求头cookie实现
cookie的细节
1. 一次可不可以发送多个cookie?
可以创建多个Cookie对象,使用response调用多次addCookie方法发送cookie即可
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @WebServlet("/cookieDemo1") public class CookieDemo1 extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Cookie cookie1=new Cookie("msg","hello"); Cookie cookie2=new Cookie("name","zhangsan"); resp.addCookie(cookie1); resp.addCookie(cookie2); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } }
|
2. cookie在浏览器中保存多长时间?
默认情况下,当浏览器关闭后,Cookie数据被销毁
持久化存储:
setMaxAge(int seconds)
正数
:将Cookie
数据写到硬盘的文件中, 持久化存储。并指定cookie
存活时间,时间到后,cookie
文件自动失效
负数
:默认值
零
:删除cookie
信息
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @WebServlet("/cookieDemo1") public class CookieDemo1 extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Cookie cookie1=new Cookie("msg","hello"); cookie1.setMaxAge(30); resp.addCookie(cookie1);
}
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } }
|
3. cookie能不能存中文?
- 在
tomcat 8
之前 cookie
中不能直接存储中文数据。
需要将中文数据转码—一般采用URL
编码(%E3)
- 在
tomcat 8
之后,cookie
支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
4. cookie共享问题?
假设在一个tomcat
服务器中,部署了多个web项目,那么在这些web项目中cookie
能不能共享?
默认情况下cookie不能共享
setPath(String path)
:设置cookie
的获取范围。默认情况下,设置当前的虚拟目录
不同的tomcat
服务器间cookie
共享问题?
setDomain(String path)
:如果设置一级域名相同,那么多个服务器之间cookie可以共享
例如:setDomain(".baidu.com")
那么tieba.baidu.com
和news.baidu.com中cookie
可以共享
5. Cookie的特点和作用
- 特点
cookie
存储数据在客户端浏览器
- 浏览器对于单个cookie 的大小有限制(
4kb
) 以及 对同一个域名下的总cookie
数量也有限制(20
个)
- 作用:
- cookie一般用于存出少量的不太敏感的数据
- 在不登录的情况下,完成服务器对客户端的身份识别
案例:记住上一次访问时间
需求:
- 访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问。
- 如果不是第一次访问,则提示:欢迎回来,您上次访问时间为:显示时间字符串
分析:
1. 可以采用`Cookie`来完成
2. 在服务器中的`Servlet`判断是否有一个名为`lastTime`的`cookie`
- 有:不是第一次访问
- 响应数据:欢迎回来,您上次访问时间为:2018年6月10日11:50:20
- 写回Cookie:lastTime=2018年6月10日11:50:01
- 没有:是第一次访问
- 响应数据:您好,欢迎您首次访问
- 写回Cookie:lastTime=2018年6月10日11:50:01
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| @WebServlet("/cookieTest") public class CookieTest extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8"); Cookie [] cookies=req.getCookies(); boolean flag=false; if(cookies!=null && cookies.length>0){ for(Cookie c:cookies){ String name=c.getName(); if(name.equals("lastTime")){ flag=true;
String value=c.getValue(); value= URLDecoder.decode(value,"utf-8"); resp.getWriter().write("<h1>欢迎回来,您上次访问时间为:"+value+"</h1>");
Date date=new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); String str_date=sdf.format(date); System.out.println("编码前"+str_date); str_date= URLEncoder.encode(str_date,"utf-8"); System.out.println("编码后"+str_date); c.setValue(str_date); c.setMaxAge(50); resp.addCookie(c); break; } } } if(!flag || cookies.length==0 || cookies==null){ Date date=new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); String str_date=sdf.format(date); System.out.println("编码前"+str_date); str_date= URLEncoder.encode(str_date,"utf-8"); System.out.println("编码后"+str_date); Cookie cookie=new Cookie("lastTime",str_date); cookie.setMaxAge(50); resp.addCookie(cookie); resp.getWriter().write("<h1>您好,欢迎您首次访问</h1>"); } }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } }
|
启动服务器
Session
概念:
服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中:HttpSession
快速入门:
获取HttpSession
对象:
1
| HttpSession session = request.getSession();
|
使用HttpSession
对象:
1 2 3
| Object getAttribute(String name) void setAttribute(String name, Object value) void removeAttribute(String name)
|
示例:
首先创建SessionDemo1
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @WebServlet("/sessionDemo1") public class SessionDemo1 extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session=req.getSession(); session.setAttribute("msg","hello session"); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } }
|
然后创建SessionDemo2
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @WebServlet("/sessionDemo2") public class SessionDemo2 extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session=req.getSession(); Object msg=session.getAttribute("msg"); System.out.println(msg); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } }
|
分别访问http://localhost:8080/servlet_session/sessionDemo1
和http://localhost:8080/servlet_session/sessionDemo2
原理
Session的实现是依赖于Cookie的。
细节:
1. 当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
默认情况下: 不是。
如果需要相同,则可以创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。
1 2 3
| Cookie c = new Cookie("JSESSIONID",session.getId()); c.setMaxAge(60*60); response.addCookie(c);
|
2. 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
不是同一个,但是要确保数据不丢失。tomcat自动完成以下工作
3. session什么时候被销毁?
服务器关闭
session对象调用invalidate()
。
session默认失效时间 30分钟
选择性配置修改
1 2 3
| <session-config> <session-timeout>30</session-timeout> </session-config>
|
session的特点
1. session用于存储一次会话的多次请求的数据,存在服务器端
2. session可以存储任意类型,任意大小的数据
session与Cookie的区别:
1. session存储数据在服务器端,Cookie在客户端
2. session没有数据大小限制,Cookie有
3. session数据安全,Cookie相对于不安全
案例:验证码
案例需求:
- 访问带有验证码的登录页面
login.jsp
- 用户输入用户名,密码以及验证码。
- 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
- 如果验证码输入有误,跳转登录页面,提示:验证码错误
- 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
代码实现
首先新建login.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| <%-- Created by IntelliJ IDEA. User: Liu Fei Date: 2020/11/3 Time: 11:48 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>login</title> <script> window.onload=function() { document.getElementById("img").onclick=function(){ this.src="/servlet_test03/checkCodeServlet?time="+new Date().getTime(); } }
</script> <style> div{ color:red; } </style>
</head> <body> <form action="/servlet_test03//loginServlet" method="post"> <table> <tr> <td>用户名</td> <td><input type="text" name="username"></td> </tr>
<tr> <td>密码</td> <td><input type="password" name="password"></td> </tr>
<tr> <td>验证码</td> <td><input type="text" name="checkCode"></td> </tr>
<tr> <td colspan="2"><img id="img" src="/servlet_test03//checkCodeServlet"></td> </tr>
<tr> <td colspan="2"><input type="submit" value="登录"></td> </tr>
</table>
</form>
<div><%=request.getAttribute("cc_error")==null?"":request.getAttribute("cc_error")%></div> <div><%=request.getAttribute("login_error")==null?"":request.getAttribute("login_error")%></div>
</body> </html>
|
创建success.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <%-- Created by IntelliJ IDEA. User: Liu Fei Date: 2020/11/3 Time: 14:42 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1><%=request.getSession().getAttribute("username")%>,欢迎您</h1> </body> </html>
|
然后新建LoginServlet
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| @WebServlet("/loginServlet") public class LoginServlet extends HttpServlet{ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); String username=req.getParameter("username"); String password=req.getParameter("password"); String checkCode=req.getParameter("checkCode"); HttpSession session=req.getSession(); String cheackCode_session=(String)session.getAttribute("checkCode_session"); session.removeAttribute("checkCode_session"); if(cheackCode_session!=null && cheackCode_session.equalsIgnoreCase(checkCode)){ if("liufei".equals(username) && "123456".equals(password)){ session.setAttribute("username",username);
resp.sendRedirect(req.getContextPath()+"/success.jsp"); }else{ req.setAttribute("login_error","用户名或密码错误"); req.getRequestDispatcher("/login.jsp").forward(req,resp); } }else{ req.setAttribute("cc_error","验证码错误"); req.getRequestDispatcher("/login.jsp").forward(req,resp); }
}
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); } }
|
新建CheckCodeServlet
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| @WebServlet("/checkCodeServlet") public class CheckCodeServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int width=100; int height=50; BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); Graphics g=image.getGraphics(); g.setColor(Color.PINK); g.fillRect(0,0,width,height);
g.setColor(Color.BLUE); g.drawRect(0,0,width-1,height-1);
String str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random rd=new Random(); StringBuilder sb=new StringBuilder(); for(int i=0;i<4;i++){ int index=rd.nextInt(str.length()); char ch=str.charAt(index); sb.append(ch); g.drawString(ch+"",(width/5)*(i+1),25); } String checkCode_session=sb.toString(); req.getSession().setAttribute("checkCode_session",checkCode_session); g.setColor(Color.GREEN); for(int i=0;i<5;i++){ int x1=rd.nextInt(width); int y1=rd.nextInt(height);
int x2=rd.nextInt(width); int y2=rd.nextInt(height); g.drawLine(x1,y1,x2,y2); }
ImageIO.write(image,"jpg",resp.getOutputStream()); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req,resp); }
}
|
效果展示:
![image-20201103151228393](C:\Users\Liu Fei\AppData\Roaming\Typora\typora-user-images\image-20201103151228393.png)