Javaweb基础之cookie&session

来源:互联网 发布:linux 删除tomcat日志 编辑:程序博客网 时间:2024/05/17 22:26

一、会话跟踪技术概述

1.什么叫会话

会话可以理解为客户端和服务器之间的一次对话,在一次对话中可能会有多个请求和响应。
例如:用户通过浏览器登录访问qq空间,登录,查看某人的主页,查看某人详细说说,日志,相册等等,然后关闭浏览器。整个过程称之为一次会话。
在Javaweb中,客户向某一服务器发出第一个请求开始,会话就开始了,直到客户端浏览器被关闭,会话结束。
在一个会话中的多个请求中共享数据,这个就是会话跟踪技术。例如在银行系统操作中:
* 请求银行主页
* 请求登录(请求参数:用户名和密码)
* 请求转账 (具体的用户名)
* 请求信用卡还款(具体的用户)
在以上会话中,当前登录的用户信息必须在整个会话中共享,因为登录是张三,在转账和还款时一定是相对张三的账户(总不能转账完成,突然发现,我转的钱是谁的?),所以,就需要借助Cookie和Session来完成在一个会话过程中共享数据的能力。

二、Cookie

HTTP协议是无状态协议,也就是说每个请求都是独立的,无法记录前一次请求的状态,但Http协议中可以使用Cookie来完成会话跟踪,在Javaweb中,使用Session来完成会话跟踪,而session底层依赖于Cookie技术。

1.Cookie概述

在HTTP中,Cookie由一个键和一个值构成的。随着服务器的响应发送给客户端。当客户端再次访问服务器时会把Cookie再发送给服务器。
cookie原理
如果服务器发送重复的cookie,就会覆盖浏览器原有的cookie。

2.cookie示例1

需求:客户端访问AServlet,AServlet在响应中添加cookie,浏览器自动保存cookie,然后客户端再次访问BServlet,在BServlet获取请求中cookie。
* AServlet
(1)创建cookie对象
(2)将cookie响应给浏览器

public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        //UUID,全局唯一标识符,在一台机器上生成的数字不会重复        //创建cookie        //UUID.randomUUID()获取值,将该值转为字符串toString();        String val=UUID.randomUUID().toString();        //创建cookie对象        Cookie cookie=new Cookie("id",val);        //将cookie响应给浏览器        response.addCookie(cookie);    }
  • BSservlet:获取cookie,
    (1) 从request获取cookie数组,
    (2) 判断该数组是否为空,遍历并根据cookie的name获取值
public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        //获取了cookie        Cookie[] cookie=request.getCookies();        if(cookie!=null){//如果cookie不为空            for(Cookie c:cookie){                if(c.getName().equals("id")){                    response.getWriter().print(c.getValue());                }            }        }    }

3.cookie的生命周期

Cookie不只有name和value,Cookie还有生命,即cookie在客户端浏览器的有效时间,可以通过setMaxAge(int) 来设置Cookie的有效时间
cookie.setMaxAge(-1):cookie的maxAge的默认值就是-1,表示在浏览器内存中存活,一旦关闭浏览器,那cookie就会消失。
cookie.setMaxAge(60*60): 表示cookie对象可以存活一个小时。当生命值大于0时,浏览器会把cookie保存到硬盘上,就算关闭浏览器,或者重启电脑,cookie在生命值时间内也是存活的。
cookie.setMaxAge(0): 表示cookie被作废,也就是说,如果原来浏览器已经保存了cookie,那么可以通过设置生命值为0来删除该cookie。

4.cookie示例2

显示上次访问时间
* 创建Cookie,名称为lasttime,值为当前访问时间,添加到response中
* 在AServlet中获取请求名为lasttime的Cookie
* 如果不存在就输出“欢迎首次访问本站”,如果存在就输出上次访问时间

public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        response.setContentType("text/html;charset=utf-8");        Cookie[] cookie=request.getCookies();        String str="欢迎首次访问本站";        boolean flag=true;        if(cookie!=null){            for(Cookie c:cookie){                if(c.getName().equals("lasttime")){                    str="您上次访问时间是:"+c.getValue();                    c.setValue(new Date().toString())                    response.addCookie(c);                    flag=false;                }            }        }        if(flag){            Cookie co=new Cookie("lasttime",new Date().toString());            response.addCookie(co);        }        response.getWriter().print(str);    }

5.cookie中包含中文

Cookie的name和value都不能使用中文,如果希望在Cookie中使用中文,那么需要先对中文进行URL编码,然后把编码后的字符放到Cookie中。
(1)对含有中文内容的cookie进行编码并保存

public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {            response.setContentType("text/html;charset=utf-8");            String name = URLEncoder.encode("姓名","utf-8");            String value = URLEncoder.encode("张三","utf-8");            Cookie cookie = new Cookie(name,value);            response.addCookie(cookie);            response.getWriter().print("添加成功");            }

(2)获取cookie并解码

public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {            response.setContentType("text/html;charset=utf-8");            Cookie[] cookie = request.getCookies();            if(cookie!=null) {                for(Cookie c:cookie) {                        String name = URLDecoder.decode(c.getName(),"utf-8");                        String value = URLDecoder.decode(c.getValue(),"utf-8");                        response.getWriter().print(name+":"+value);                }            }    }

6.Cookie的路径

6.1什么是Cookie的路径

假设WEB应用A,向客户端发送了100个Cookie,则客户端无论访问应用A的哪个Servlet都会把这100个Cookie包含在请求中!但是也许只有AServlet需要读取请求中的Cookie,而其他Servlet根本就不会获取请求中的Cookie。这说明客户端浏览器有时发送这些Cookie是多余的!
可以通过设置Cookie的path来指定浏览器在访问什么样的路径时,包含什么样的Cookie。

6.2Cookie路径与请求路径的关系

可以使用cookie.setPath(路劲) 来设置cookie的路径。
下面来看看Cookie路径的作用:
如下所示是客户端浏览器保存的3个Cookie的路径(path):
a: /cookietest;
b: /cookietest/servlet;
c: /cookietest/jsp;

下面是浏览器请求的URL:
A: http://localhost:8080/cookietest/AServlet;
B: http://localhost:8080/cookietest/servlet/BServlet;
C: http://localhost:8080/cookietest/jsp/CServlet;

  • 请求A时,会在请求中包含a;
  • 请求B时,会在请求中包含a、b;
  • 请求C时,会在请求中包含a、c;

也就是说,请求路径如果包含了Cookie路径,那么会在请求中包含这个Cookie,否则不会请求中不会包含这个Cookie。
* A请求的URL包含了“/cookietest”,所以会在请求中包含路径为“/cookietest”的Cookie;
* B请求的URL包含了“/cookietest”,以及“/cookietest/servlet”,所以请求中包含路径为“/cookietest”和“/cookietest/servlet”两个Cookie;
* C请求的URL包含了“/cookietest”,以及“/cookietest/jsp”,所以请求中包含路径为“/cookietest”和“/cookietest/jsp”两个Cookie;

6.3设置Cookie的路径

设置Cookie的路径需要使用setPath()方法,例如:
cookie.setPath(“/cookietest/servlet”);
当访问http://localhost:8080/cookietest/servlet/BServlet;浏览器会发送该cookie
如果访问http://localhost:8080/cookietest/jsp/CServlet; 浏览器不会发送该cookie

如果没有设置Cookie的路径,那么Cookie路径的默认值当前访问资源所在路径,例如:
* 访问http://localhost:8080/cookietest/AServlet时添加的Cookie默认路径为/cookietest;
* 访问http://localhost:8080/cookietest/servlet/BServlet时添加的Cookie默认路径为/cookietest/servlet;
* 访问http://localhost:8080/cookietest/jsp/BServlet时添加的Cookie默认路径为/cookietest/jsp;

三、HttpSession

1.HttpSession概述

1.1 什么是HttpSession

javax.servlet.http.HttpSession接口表示一个会话,一般会把一个会话内需要共享的数据保存到HttpSession对象中。

1.2 如何获取HttpSession对象

  • HttpSession request.getSession();
    如果当前会话已经有了session对象那么直接返回,如果当前对象还不存在session,那么创建一个session对象并返回;
  • HttpSession request.getSession(boolean);
    当参数为true时,与HttpSession request.getSession()相同;
    当参数为false时,如果当前Session没有就不创建session,并返回null,如果有就返回当前session。

1.3 HttpSession是域对象

我们已经学了HttpServletRequest,ServletContext两个域对象,而HttpSession也是域对象。作为域对象可以存储数据。
* setAttribute(String name,Object value);
* getAttribute(String name);
* void removeAttribute(String name);
* Enumeration getAttributeNames();

1.4 HttpSession的生命周期

在第一次调用 request.getSession() 方法时,服务器会检查是否已经有对应的session,如果没有就在服务器内存 中创建一个session并返回。
当一段时间内session没有被使用(默认为30分钟),则服务器会销毁该session。
如果服务器非正常关闭(强行关闭),没有到期的session也会跟着销毁。
如果调用session提供的invalidate( ) ,可以立即销毁session。
注意:服务器正常关闭,再启动,Session对象会进行钝化和活化操作。同时如果服务器钝化的时间在session 默认销毁时间之内,则活化后session还是存在的。否则Session不存在。 如果JavaBean 数据(例如:Person类)在session钝化时,没有实现Serializable 则当Session活化时,会消失。
2、作用范围:一次会话。
Session说明:
对于一个浏览器,一次会话而言,只要session未过期,服务器中只会为本次会话提供一个session对象。
当关闭浏览器(会话结束),再重新打开浏览器器后访问应用后,服务器会再次为该浏览器的本次会话重新创建session对象
即:多个浏览器会有不同的session对象。

2.登陆案例

需要的页面:
* login.jsp:登录页面,提供登录表单;
* success.jsp:主页,登录成功后跳转到该页面;
* fail.jsp:主页,如果没有登录,显示未登陆成功;

Servlet:
LoginServlet:在login.jsp页面提交表单时,请求本Servlet。在本Servlet中获取用户名、密码进行校验,如果用户名、密码错误,显示“用户名或密码错误”,如果正确保存用户名session中,然后重定向到success.jsp;
当用户没有登录时访问success.jsp或fail.jsp,显示“您还没有登录”。如果用户在login.jsp登录成功后到达success.jsp页面会显示当前用户名,而且不用再次登录去访问fail.jsp也会显示用户名。因为多次请求在一个会话范围,success.jsp和fail.jsp都会到session中获取用户名,session对象在一个会话中是相同的,所以都可以获取到用户名!
* Login.jsp

<html>  <head>    <base href="<%=basePath%>">    <title>登录界面</title>  </head>  <body>        <form name="f1" id="f1" action="/myapp/lServlet" method="post">          <table>            <tr>              <td>Login:</td>              <td><input type="text" name="userName"></td>            </tr>            <tr>              <td>Password:</td>              <td><input type="password" name="password"></td>            </tr>             <tr>              <td colspan="2"><input type="submit"></td>            </tr>          </table>        </form>  </body></html>
  • success.jsp
<html>  <head>    <base href="<%=basePath%>">    <title>登录成功页面</title>  </head>  <body>    <%        String userName=(String)session.getAttribute("userName");        out.print("当前用户:"+userName);    %>  </body></html>
  • fail.jsp
  <body>    <%        out.print("用户登录失败,5s后将跳转到登录页面");        response.setHeader("Refresh","5,URL=http://localhost:8080/day08_31/session/login.jsp");    %>  </body>
  • LoginServlet.java
    public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        //设置接收数据的解码格式        request.setCharacterEncoding("utf-8");        //获取参数        String userName=request.getParameter("userName");        String password=request.getParameter("password");        System.out.println("userName="+userName);        //判断用户名和密码是否匹配(张三,123456)        if((userName!=null&&userName.equals("张三"))&&(password!=null&&password.equals("123456"))){            //如果登录成功,将用户名存放在session中            HttpSession session=request.getSession();            session.setAttribute("userName", userName);            response.sendRedirect("/myapp/session/success.jsp");        }else{            //如果登录失败            response.sendRedirect("/myapp/session/fail.jsp");        }    }

3.HttpSession的实现原理

获取session对象后,是保存在服务器内存中的。服务器在响应时会给客户端传送一个sessionId的值(一个cookie中保存了sessionId)。客户端带走的是sessionId,而数据是保存在session中。
当客户端再次访问服务器时,在请求中会带上sessionId,而服务器会通过sessionId找到session。而不需要重新在创建session。
session原理
这个sessionId对应就是浏览器cookie中的JsessionId。服务在首次创建session,会将sessionId封装到cookie中,服务器响应给客户端时返回了该cookie。当客户端再次访问服务器时,会将该cookie封装到request。

4. session与浏览器

sessionId是通过Cookie发送给客户端的,但这个cookie的默认生命值是-1,只在浏览器内存中存在,也就是说如果用户关闭立刻浏览器,那么这个Cookie就丢失了。
当用户再次打开浏览器访问服务器,就不会再有sessionId(在浏览器中是JsessionId)发送给服务器。那么服务器会认为没有session,所有服务器会创建一个新session对象,并在响应时将新的sessionId以cookie的形式发送给浏览器。
而原先的session对象因为长时间没被调用,所以服务器会在一定时间后把该session删除。该时间长在Tomcat中默认配置为30分钟,可以在tomcat配置文件中还找到,tomcat文件夹中的conf文件中的web.xml可以找到。
也可以单独为应用设置session,即在项目的web.xml中配置session的过期时间(单位分钟)

<session-config>    <session-timeout>30</session-timeout></session-config>

session失效时间也说明一个问题,如果打开一个浏览器页面长时间不去操作,超出30分钟后,再去点击链接或者表单,原先的session已经丢失。

5.session其他常用api

  • String getId():获取sessionId;
  • int getMaxInactiveInterval():获取session可以的最大不活动时间(秒),默认为30分钟。当session在30分钟内没有使用,那么Tomcat会在session池中移除这个session;
  • void setMaxInactiveInterval(int interval):设置session允许的最大不活动时间(秒),如果设置为1秒,那么只要session在1秒内不被使用,那么session就会被移除;
  • long getCreationTime():返回session的创建时间,返回值为当前时间的毫秒值;
  • long getLastAccessedTime():返回session的最后活动时间,返回值为当前时间的毫秒值;
  • void invalidate():让session失效!调用这个方法会让session失效,当session失效后,客户端再次请求,服务器会给客户端创建一个新的session,并在响应中给客户端新session的sessionId;
  • boolean isNew():查看session是否为新。当客户端第一次请求时,服务器为客户端创建session,但这时服务器还没有响应客户端,也就是还没有把sessionId响应给客户端时,这时session的状态为新。
public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        //设置编码格式        request.setCharacterEncoding("utf-8");        response.setContentType("text/html;charset=utf-8");        //创建或者获取session        HttpSession session=request.getSession();        //获取sessionId        String sessionId=session.getId();        //获取session可以的最大不活动时间(秒),默认为30分钟。        int time=session.getMaxInactiveInterval();        System.out.println("session有效期="+time);        //设置session可以的最大不活动时间(秒)        session.setMaxInactiveInterval(20);        int time2=session.getMaxInactiveInterval();        System.out.println("新的session有效期="+time2);        //获取session域参数        String val=(String)session.getAttribute("name");        response.getWriter().print("session中的值为:"+val+"</br>sessionId="+sessionId);    }

6.URL重写

session依赖Cookie,那么如果客户端浏览器禁用了Cookie,即浏览器不用再接收cookie,那么sessionId也将不会被再次接收。此时可以通过URL重写来解决这种问题。这种方法让服务器收到的每个请求中都带有sessioinId。在每个页面中的每个链接和表单中都添加名为jSessionId的参数,值为当前sessionid。当用户点击链接或提交表单时服务器可以通过获取jSessionId这个参数来得到客户端的sessionId,找到sessoin对象。
index.jsp

  <body><h1>URL重写</h1><a href='/myapp/index.jsp;jsessionid=<%=session.getId() %>' >主页</a><form action='/myapp/index.jsp;jsessionid=<%=session.getId() %>' method="post">    <input type="submit" value="提交"/></form>  </body>

也可以使用response.encodeURL()对每个请求的URL处理,这个方法会自动追加jsessionid参数,与上面手动添加是一样的效果。

<a href='<%=response.encodeURL("/day06_5/index.jsp") %>' >主页</a><form action='<%=response.encodeURL("/day06_5/index.jsp") %>' method="post">    <input type="submit" value="提交"/></form>

使用response.encodeURL()更加“智能”,它会判断客户端浏览器是否禁用了Cookie,如果禁用了,那么这个方法在URL后面追加jsessionid,否则不会追加。

原创粉丝点击