Cookie
Cookie是servlet发送到Web浏览器的少量信息,该信息由浏览器保存,然后发送回服务器。一般情况下,Cookie是以键值对进行表示的(key-value),Cookie的值可以唯一地标识客户端,因此Cookie常用于会话管理。servlet通过使用HttpServletResponse#addCookie方法将cookie发送到浏览器,该方法将字段添加到http响应头,以便一次一次地将cookie发送到浏览器,每个Cookie的大小限定为4kb。
创建Cookie
客户端没有Cookie -> 服务器创建Cookie -> 通知客户端保存Cookie -> 通过响应头Set-Cookie通知客户端保存Cookie(Set-Cookie:key=value) ->客户端收到响应后发现set-cookie响应头,查看有没有Cookie,如果没有就创建如果有就修改。
package com.pero.servlet.cookie_session;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.lang.reflect.Method;
public abstract class BaseServlet extends HttpServlet {
protected void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
String action = request.getParameter("action");
try {
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
method.invoke(this,request,response);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
package com.pero.servlet.cookie_session;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class CookieServlet extends BaseServlet {
protected void createCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建Cookie
Cookie cookie = new Cookie("key","value");
//通知客户端保存
response.addCookie(cookie);
response.getWriter().write("Cookie创建成功");
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<title>Cookie</title>
<base href="http://localhost:8080/cookie_session/">
<style type="text/css">
ul li{
list-style: none;
}
</style>
</head>
<body>
<iframe name="target" width="500" height="500" style="..."></iframe>
<div style="...">
<ul>
<li><a href="cookieServlet?action=createCookie" target="target">Cookie的创建</a></li>
<li><a href="cookieServlet?action=getCookie" target="target">Cookie的获取</a></li>
<li><a href="cookieServlet?action=updateCookie" target="target">Cookie值的修改</a></li>
<li>Cookie的存活周期</li>
<li>
<ul>
<li><a href="cookieServlet?action=defaultLifeCookie" target="target">Cookie的默认存活时间(会话)</a></li>
<li><a href="cookieServlet?action=deleteNowCookie" target="target">Cookie立即删除</a></li>
<li><a href="cookieServlet?action=life5Cookie" target="target">Cookie存活5秒</a></li>
</ul>
</li>
<li><a href="cookieServlet?action=pathCookie" target="target">Cookie的路径设置</a></li>
<li><a href="" target="target">Cookie的用户登录练习</a></li>
</ul>
</div>
</body>
</html>
服务器获取Cookie
客户端有了Cookie的值 -> 通过请求头:Cookie:key=value 把Cookie信息发送给服务器 -> 服务器获取客户端发送过来的Cookie只需要一行代码{request.getCookies():返回Cookie[]数组}
package com.pero.servlet.cookie_session;
import com.pero.servlet.util.CookieUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class CookieServlet extends BaseServlet {
protected void getCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
//getName()获取Cookie的Key值,getValue()方法获取Cookie的value值
response.getWriter().write("Cookie{" + cookie.getName() + ":" + cookie.getValue() + "} <br/>");
}
Cookie iWantCookie = CookieUtil.findCookie("key",cookies);
//如果不等于null意味着找到了Cookie
if (iWantCookie != null){
response.getWriter().write("找到了Cookie");
}
}
...
}
package com.pero.servlet.util;
import jakarta.servlet.http.Cookie;
public class CookieUtil {
/**
* 查找指定名称的Cookie对象
* @param name
* @param cookies
* @return
*/
public static Cookie findCookie(String name,Cookie[] cookies){
if (name == null || cookies == null || cookies.length ==0){
return null;
}
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())){
return cookie;
}
}
return null;
}
}
Cookie值的修改
package com.pero.servlet.cookie_session;
import com.pero.servlet.util.CookieUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class CookieServlet extends BaseServlet {
protected void updateCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//方法一:
//创建需要修改的同名Cookie对象
//在构造器中同时赋予新的Cookie值
// Cookie cookie = new Cookie("key","newValue");
//调用response.addCookie(Cookie)
// response.addCookie(cookie);
// response.getWriter().write("key的Cookie的值已经修改");
//方法二
//查找需要修改的Cookie对象
Cookie cookie = CookieUtil.findCookie("key",request.getCookies());
//调用setValue()方法付于心的Cookie值
if (cookie != null){
cookie.setValue("NewCookie");
}
//调用response.addCookie(cookie)通知客户端保存修改
response.addCookie(cookie);
}
...
}
Cookie的生命控制
Cookie的生命控制指的是如何管理Cookie什么时候被销毁(删除)。setMaxAge();整数表示在指定秒数后过期,负数表示浏览器一关Cookie就会被删除(程序默认),0表示立刻删除Cookie。
package com.pero.servlet.cookie_session;
import com.pero.servlet.util.CookieUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class CookieServlet extends BaseServlet {
protected void life5Cookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie cookie = new Cookie("life5","life5");
cookie.setMaxAge(5); //设置Cookie5秒后删除
response.addCookie(cookie);
response.getWriter().write("创建了5秒钟的Cookie");
}
protected void deleteNowCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//查找需要删除的Cookie
Cookie cookie = CookieUtil.findCookie("key",request.getCookies());
if (cookie != null){
//设置cookie.setMaxAge(0);立刻销毁Cookie
cookie.setMaxAge(0);
//response.addCookie();浏览器保存
response.addCookie(cookie);
response.getWriter().write("key的Cookie已经被删除");
}
}
protected void defaultLifeCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie cookie = new Cookie("defaultLife","defaultLife");
cookie.setMaxAge(-1); //设置存活时间为浏览器退出后Cookie被销毁
response.addCookie(cookie);
}
...
}
Cookie有效路径Path的设置
Cookie的path属性可以有效的过滤那些Cookie可以发送给服务器那些不发送,path属性是通过请求的地址来进行过滤。
package com.pero.servlet.cookie_session;
import com.pero.servlet.util.CookieUtil;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class CookieServlet extends BaseServlet {
protected void pathCookie(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie cookie = new Cookie("path","path");
//getContextPath()得到工程路径
cookie.setPath(request.getContextPath() + "/file");
response.addCookie(cookie);
response.getWriter().write("创建了一个带有Path路径的Cookie");
}
...
}
Cookie练习免用户名登陆
第一次登录时:客户端(浏览器)第一次访问,服务器返回给客户端登陆页面,填写用户名和密码后提交给服务器,服务器获取用户名和密码,判断用户名和密码是否正确,正确允许登录,错误不允许登录,把用户名保存为Cookie发送给客户端,浏览器有了用户名和Cookie信息;
第二次登陆时:客户端(浏览器)第二次访问服务器会把Cookie信息发给服务器,服务器返回给客户端带用户名的登录界面。
package com.pero.servlet.cookie_session;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if ("root".equals(username) && "root".equals(password)){
//登陆成功
Cookie cookie = new Cookie("username", username);
cookie.setMaxAge(60*60*24*7); //cookie一周内有效
response.addCookie(cookie);
System.out.println("登陆成功");
}else {
System.out.println("登陆失败");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/3/16
Time: 18:35
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>
<form action="http://localhost:8080/cookie_session/loginServlet" method="get">
用户名:<input type="text" name="username" value="${cookie.username.value}"><br>
密 码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
Session
Session是一个接口(HttpSession),Session是会话,用来维护一个客户端和服务器之间关联的一种技术,每个客户端都有自己的一个Session会话,Session会话中经常用来保存用户登录之后的信息。
创建Session和获取
request.getSession():第一次调用是创建Session会话,之后都是调用,获取前面创建好的Session会话对象;
isNew():判断是不是新创建出来的Session,true表示新创建,false表示获取之前创建的;
getId():得到Session会话的id值,每一个会话都有一个id值,这个id值是唯一的。
package com.pero.servlet.cookie_session;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class SessionServlet extends BaseServlet {
protected void createOrGetSession(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建和获取Session会话对象
HttpSession session = request.getSession();
//判断当前Session会话是否是新创建出来的
boolean isNew = session.isNew();
//获取Session会话的唯一标识
String id = session.getId();
response.getWriter().write("得到的Session的ID:" + id + " <br/>");
response.getWriter().write("Session是否为新创建的:" + isNew + " <br/>");
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="pragma" content="no-cache"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="Expires" content="0"/>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<title>Session</title>
<base href="http://localhost:8080/cookie_session/">
<style type="text/css">
ul li {
list-style: none;
}
</style>
</head>
<body>
<iframe name="target" width="500" height="500" style="..."></iframe>
<div style="...">
<ul>
<li><a href="sessionServlet?action=createOrGetSession" target="target">Session的创建和获取</a></li>
<li><a href="" target="target">Session域数据的存储</a></li>
<li><a href="" target="target">Session域数据的获取</a></li>
<li>Session的存活周期</li>
<li>
<ul>
<li><a href="" target="target">Session默认超时配置</a></li>
<li><a href="" target="target">Session5秒超时销毁</a></li>
<li><a href="" target="target">Session立刻销毁</a></li>
</ul>
</li>
<li><a href="" target="target">浏览器和Session绑定的原理</a></li>
</ul>
</div>
</body>
</html>
Session域中数据的存取
package com.pero.servlet.cookie_session;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class SessionServlet extends BaseServlet {
protected void getAttributeSession(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
Object attribute = session.getAttribute("key");
response.getWriter().write("从Session中获取key的值为:" + attribute);
}
protected void setAttributeSession(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.setAttribute("key","value");
response.getWriter().write("已经向Session中存储值");
}
...
}
Session生命周期
Session超时是指客户端两次请求的最大间隔时间。
public void setMaxInactiveInterval(int interval):设置Session超时时间(以秒为单位),超过指定时长Session会被销毁,值为正数的时候,设定Session的超市时长,值为负数的时候,Session永不超时;
public void invalidate():让Session会话立刻超时无效;
public int getMaxInactiveInterval():获取Session的超时时间;
Session的默认超时时长为:Session的默认超时时长为1800秒。
package com.pero.servlet.cookie_session;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class SessionServlet extends BaseServlet {
protected void defaultLife(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
int maxInactiveInterval = session.getMaxInactiveInterval();
response.getWriter().write("Session的默认超时时长为" + maxInactiveInterval + "秒");
}
...
}
如果调整web工程的超时时长,可以在web.xml中进行配置。
<!-- 表示当前web工程创建出来的所有Session默认是20分钟超时时长 -->
<session-config>
<session-timeout>10</session-timeout>
</session-config>
也可以通过setMaxInactiveInterval(int interval)设置Session超时时间
package com.pero.servlet.cookie_session;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class SessionServlet extends BaseServlet {
protected void life5Session(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//设置当前Session5秒后超时
session.setMaxInactiveInterval(5);
response.getWriter().write("当前Session已经设置为5秒后超时");
}
...
}
设置Session立刻超时
package com.pero.servlet.cookie_session;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
public class SessionServlet extends BaseServlet {
protected void shutDownSession(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//设置当前Session立刻超时
session.invalidate();
response.getWriter().write("当前Session立刻超时关闭");
}
...
}
浏览器和Session之间关联的技术
Session技术底层是基于Cookie技术实现的。
客户端(浏览器) | 服务器 | ↔ | 服务器内存 | |
没有Cookie信息 | 发送请求 → | request.getSession() 创建会话对象 | Session1 Session2 Session3 Session4 Session5 Session6 Session7 Session8 | |
保存Cookie信息 | 通过响应把新创建的Session的id值返回给客户端 ← JSESSIONID的值 | 服务器每次创建Session会话对象的时候都会创建一个Cookie对象。这个Cookie对象的key是JSESSIONID的值,是新创建出来的SessionID的值。 | ||
有Cookie信息 | 有了Cookie信息之后,每次请求都会把Session的ID以Cookie的形式发送给服务器 → | request.getSession() 通过Cookie中的id值找到创建好的Session对象,并返回 | ||
删除Cookie | ||||
没有Cookie信息 | 发送请求 → | request.getSession() 创建会话对象 | ||
保存Cookie信息 | 通过响应把新创建的Session的id值返回给客户端 ← JSESSIONID的值 | 服务器每次创建Session会话对象的时候都会创建一个Cookie对象。这个Cookie对象的key是JSESSIONID的值,是新创建出来的SessionID的值。 | ||
有Cookie信息 | 有了Cookie信息之后,每次请求都会把Session的ID以Cookie的形式发送给服务器 → | request.getSession() 通过Cookie中的id值找到创建好的Session对象,并返回 |