日常生活中:从拨通电话到挂断电话之间的一连串你问我答的过程就是一个会话。
B/S架构中 : 从浏览器第一次给服务器发送请求时,建立会话;直到有一方断开,会话结束。
一次会话:包含多次请求响应。
会话中出现的问题:由于Http是一个无状态协议,不会记录每次请求的状态,这就造成了同一个会话的两请求之间相互独立,彼此没有联系。
此时就需要一种技术在客户端或者服务端,记录会话过程中产生的一些数据,这就是会话管理技术。
两种会话管理技术:
cookie
:在一次会话的多次请求响应之间共享数据,将数据保存到客户端(浏览器)session
:在一次会话的多次请求之间共享数据,它将数据保存到服务器cookie
:利用客户端保存共享信息实现多次请求的数据共享。
使用cookie需要导入javax.servlet.http.Cookie
。
name
cookie的名称value
cookie的值domain
cookie的域名,默认值是访问服务的主机名称path
cookie的路径,默认值是应用的发布URI(发布名称/发布路径)maxAge
cookie的存活时间,0表示立即销毁comment
描述信息 (无关紧要的属性)version
版本号 (无关紧要的属性)方法名 | 作用 |
---|---|
Cookie cookie = new Cookie(name,value) | 创建Cookie对象 |
response.addCookie(Cookie c) | 将cookie写回浏览器 |
cookie.getName() | 获取cookie名 |
cookie.getValue() | 获取cookie的值 |
Cookie [] cookis = request.getCookies() | 获取cookie数组 |
cookie.setMaxAge(秒) | 设置cookie的有效时间 |
cookie.setPath("/path") | 设置cookie再次访问服务器时,自动携带cookie的依据 |
客户端带cookie到服务器机制:
请求资源URI去掉资源的部分之后和Cookie的Path进行比较,请求资源URI去掉资源的部分.startWith(cookiePath)
,结果为true,客户端就会带着cookie访问浏览器;如果为false,客户端访问浏览器就不会带cookie。
coolkiePath /cookieandsession/servlet PathQuestionDemo2 访问URI: /cookieandsession/PathQuestionDemo2 URI去掉资源的部分: /cookieandsession PathQuestionDemo3 访问URI: /cookieandsession/servlet/PathQuestionDemo3 URI去掉资源的部分: /cookieandsession/servlet
在上面的案例中,只有PathQuestionDemo3
访问服务器会带着cookie
。
xml配置:
<servlet> <servlet-name>CartServlet</servlet-name> <servlet-class>com.itcast.cart.CartServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>CartServlet</servlet-name> <url-pattern>/cart</url-pattern> </servlet-mapping>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>购物车</title> </head> <body> <a href="/cookieandsession/cart?action=showProductList">查看商品列表</a> <hr/> <a href="/cookieandsession/cart?action=showCartInfo">查看购物车</a> </body> </html>
public class CartServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置请求正文字符集 req.setCharacterEncoding("UTF-8"); //设置响应正文的MIME类型和字符集 resp.setContentType("text/html;charset=UTF-8"); //获取请求参数 String action = req.getParameter("action"); if ("showProductList".equals(action)){ showProductList(req,resp); }else if ("showCartInfo".equals(action)){ showCartInfo(req,resp); }else { System.out.println("无信息"); } //获取请求参数 String productName = req.getParameter("productName"); if (productName != null){ addCart(req,resp,productName); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } private void showProductList(HttpServletRequest req, HttpServletResponse resp){ PrintWriter out = null; try { //获取输出流 out = resp.getWriter(); } catch (IOException e) { e.printStackTrace(); } //输出商品列表 out.write("01.Xiaomi <a href='"+req.getContextPath()+"/cart?action=showProductList&productName=Xiaomi'>添加购物车</a><br/>"); out.write("02.Huawei <a href='"+req.getContextPath()+"/cart?action=showProductList&productName=Huawei'>添加购物车</a><br/>"); out.write("03.Lianxiang <a href='"+req.getContextPath()+"/cart?action=showProductList&productName=Lianxiang'>添加购物车</a><br/>"); } private void showCartInfo(HttpServletRequest req, HttpServletResponse resp){ PrintWriter out = null; try { //获取输出流 out = resp.getWriter(); } catch (IOException e) { e.printStackTrace(); } out.write("<h1>购物车的详情:</h1>"); //获取Cookie Cookie[] cookies = req.getCookies(); //4.判断 if(cookies == null || cookies.length == 0){ out.write("您还没有添加商品到购物车"); }else { for (Cookie cookie : cookies){ //判断 if("CartInfo".equals(cookie.getName())){ //找到了我们想要的cookie String value = cookie.getValue();//Xiaomi-Xiaomi-Lianxiang //分隔 String[] productNames = value.split("-"); //遍历名称 for(String productName : productNames){ out.write(productName+"<br/>"); } } } } } private void addCart(HttpServletRequest req, HttpServletResponse resp,String productName){ PrintWriter out = null; try { //取出输出流 out = resp.getWriter(); } catch (IOException e) { e.printStackTrace(); } //取出Cookie Cookie[] cookies = req.getCookies(); //定义要写到客户端的Cookie Cookie cookie = null; //判断,如果没有Cookies就是第一次 if(cookies == null || cookies.length == 0){ cookie = new Cookie("CartInfo",productName); }else { //遍历 for(Cookie c : cookies){ //判断名称 if("CartInfo".equals(c.getName())){ cookie = c; break; } } //给cookie拼值,就是在原来的value上,再加上新的value(productName) String value = cookie.getValue()+"-"+productName; cookie.setValue(value); } //设置最大存活时间 cookie.setMaxAge(Integer.MAX_VALUE); //把cookie写到浏览器 resp.addCookie(cookie); //提示 out.write("<hr size='7px' color='orange'>"); out.write("添加成功。<a href='"+req.getContextPath()+"/cart?action=showCartInfo'>查看购物车</a>"); } }
session:在一次会话的多次请求之间共享数据,将数据保存到服务器端
在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。
Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
使用session需要导入javax.servlet.http.HttpSession
。
HttpSession session = request.getSession();
无论之前有还是没有session,都会有返回一个session,若之前的找到了就使用之前的session;若之前的session没有找到,就创建一个sessionHttpSession session = request.getSession(boolean create);
当create为true
时,与request.getSession()
使用情况一致;当create为false
时,若之前的找到了就使用之前的session;若之前的session没有找到,就返回null
HttpSession也是一个域对象,它表示的是会话域,作用范围是一次会话之中(包含多次请求)。
域对象常用api:
getAttribute(String name)
通过属性名获取域对象的属性setAttibute(String name , Object obj)
设置域对象的属性removeAttribtue(String name)
通过属性名移除域对象的属性session生命周期:
1.关闭浏览器,会话结束; 2.超过一定时间没有对网站有任何操作时,会话超时结束,默认时间是30分钟; 3.手动调用 session.invalidate() 销毁session对象; 4.服务器非正常关闭销毁对象(关机 死机 蓝屏等)
正常关闭服务器将session保存到本地:
正常关闭session没有销毁 而是保存到本地 , 再次启动服务器时会加载本地文件到内存中。
HttpSession是利用了Cookie实现的,其本质是一个特殊的Cookie。
Cookie名称是固定的:JSESSIONID
,Cookie的值就是HttpSession的唯一标识。
如果cookie被清除了,session还在,只不过无法直接找到session, 可以通过url重写地址栏可以找回来的。
如果浏览器禁用cookie,session还可以使用,session的底层基于cookie 但不完全依赖cookie 有其他的方式可以替代。
session是一个域对象 , 为什么cookie不是域对象?因为域对象指的是服务器端的技术,而cookie是浏览器端的技术。
通过创建cookie,可以持久化保存session
//创建session对象 HttpSession session = request.getSession(); //自己创建cookie Cookie cookie = new Cookie("JSESSIONID" , session.getId()); cookie.setMaxAge(60*60*7); response.addCookie(cookie); System.out.println("session地址值:" + session); System.out.println("session的id为:" + session.getId()); System.out.println("session是否为新创建的:" + session.isNew());
session的活化与钝化:
前提:
客户端禁用Cookie的会话保持:
3. 文字提示,请不要禁用您的Cookie
4. URL重写,在访问地址后面拼接一个JSESSIONID(不推荐使用)
encodeUrl(url)
:其他的连接使用此方法endcodeRedirectUrl(url)
:重定向的连接就使用此方法//获取session HttpSession session = request.getSession(); session.setAttribute("username","url重写"); String url=request.getContextPath(); System.out.println(response.encodeRedirectURL(url)); response.setContentType("text/html;charset=utf-8"); response.getWriter().print("<a href='"+url+"'>返回首页</a><br>"); String url2 = request.getContextPath()+"/demo2"; url2=response.encodeURL(url2); System.out.println(url2); response.getWriter().print("<a href='"+url2+"'>获取数据</a>");