web开发学习资源Java

JavaWeb基础之Cookie与Session

2017-06-06  本文已影响56人  Acamy丶

Cookie:
Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
Session:
Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。

本文内容

1.javax.servlet.http.Cookie

Java提供操作Cookie的API

1.1 演示Cookie的创建与使用

public class CookieDemo1 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1.创建Cookie对象
        Cookie cookie1 = new Cookie("name","eric");
        
        
        /**
         * 1)设置cookie的有效路径。默认情况:有效路径在当前web应用下。 /demo
               *有效路径指的是cookie的有效路径保存在哪里,那么浏览器在有效路径下
              *访问服务器时就会带着cookie信息,否则不带cookie信息。
         */
        //cookie1.setPath("/demo");
        
        /**
         * 2)设置cookie的有效时间
         * 正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。
            负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!!
            零:表示删除同名的cookie数据

         */
        //cookie1.setMaxAge(20); //20秒,从最后不调用cookie开始计算
        cookie1.setMaxAge(-1); //cookie保存在浏览器内存(会话cookie)
        //cookie1.setMaxAge(0);
        
        
        //2.把cookie数据发送到浏览器(通过响应头发送: set-cookie名称)
        //response.setHeader("set-cookie", cookie.getName()+"="+cookie.getValue()+",email=eric@qq.com");
        //推荐使用这种方法,避免手动发送cookie信息
        response.addCookie(cookie1);
        

        
        //3.接收浏览器发送的cookie信息
        /*String name = request.getHeader("cookie");
        System.out.println(name);*/
        Cookie[] cookies = request.getCookies();
        //注意:判断null,否则空指针
        if(cookies!=null){
            //遍历
            for(Cookie c:cookies){
                String name = c.getName();
                String value = c.getValue();
                System.out.println(name+"="+value);
            }
        }else{
            System.out.println("没有接收cookie数据");
        }
        
    }

}

1.2. Cookie的使用实例,用户上次访问时间

public class HistServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");

        // 获取当前时间
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String curTime = format.format(new Date());

        // 取得cookie
        Cookie[] cookies = request.getCookies();
        String lastTime = null;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("lastTime")) {
                    // 有lastTime的cookie,已经是第n次访问
                    lastTime = cookie.getValue();// 上次访问的时间
                    // 第n次访问
                    // 1.把上次显示时间显示到浏览器
                    response.getWriter().write(
                            "欢迎回来,你上次访问的时间为:" + lastTime + ",当前时间为:" + curTime);
                    // 2.更新cookie
                    cookie.setValue(curTime);
                    cookie.setMaxAge(1 * 30 * 24 * 60 * 60);
                    // 3.把更新后的cookie发送到浏览器
                    response.addCookie(cookie);
                    break;
                }
            }
        }

        /**
         * 第一次访问(没有cookie 或 有cookie,但没有名为lastTime的cookie)
         */
        if (cookies == null || lastTime == null) {
            // 1.显示当前时间到浏览器
            response.getWriter().write("你是首次访问本网站,当前时间为:" + curTime);
            // 2.创建Cookie对象
            Cookie cookie = new Cookie("lastTime", curTime);
            cookie.setPath("/CookieDemo");
            cookie.setMaxAge(-1);// 设置浏览器关闭cookie就丢失
            // cookie.setMaxAge(1*30*24*60*60);//保存一个月
            // 3.把cookie发送到浏览器保存
            response.addCookie(cookie);
        }
    }

}

效果如下:


**第一次访问时效果如下,可以看到请求头里没有带任何Cookie信息,而响应头里面设置了Cookie的信息** **当第二次及后面的访问时,请求头里面都会带有保存上次访问的Cookie信息,响应头里面会对这个信息进行更新。** **同时我们也可以在浏览器里看到该Cookie的详细信息**

注意:浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。

2. javax.servlet.http.HttpSession

Java提供操作Session的API,服务器在浏览器第一次访问时如果创建了一个Session对象就会给该对象分配一个id并以Cookie的形式保存在浏览器中,以后在有效期内浏览器访问服务器时就会带着该id,服务器通过该id就能匹配到存储在服务器中对应的信息。

2.1 Sesision的存储原理

Demo:

public class SessionDemo1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setCharacterEncoding("UTF=8");
        response.setContentType("text/html;charset=UTF-8");
        // 使用request对象的getSession()获取session,如果session不存在则创建一个
        HttpSession session = request.getSession();
        // 将数据存储到session中
        session.setAttribute("data", "acamy");
        // 获取session的Id
        String sessionId = session.getId();
        // 判断session是不是新创建的
        response.getWriter().println(new Date());
        if (session.isNew()) {
            response.getWriter().print("session创建成功,session的id是:" + sessionId);
        } else {
            response.getWriter().print(
                    "服务器已经存在该session了,session的id是:" + sessionId);
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

效果如下:


可以看到第一次访问时浏览器会创建一个Session对象,给该对象分配一个id,并以JSESSIONID作为键,id作为值以Cookie的形式保存在浏览器中 第二次访问时浏览器发起请求时就会在Cookie里面带着该id信息,服务器就能根据这个id匹配存储在服务器的里面的信息

2.2.浏览器禁用Cookie后的session处理

当我们想实现提供用户浏览过的商品时,利用上面的Cookie和Session思想很容易实现,但是如果浏览器作了上图中的设置,也就是禁用了Cookie,我们又该如何实现呢,这就需要用到URL重写:

用于对sendRedirect方法后的url地址进行重写。
**response.encodeRedirectURL(java.lang.String url) **

//用于对表单action和超链接的url地址进行重写
response.encodeURL(java.lang.String url)

String javax.servlet.http.HttpServletResponse.encodeURL(String url)
Encodes the specified URL by including the session ID in it, or, if encoding is not needed, returns the URL unchanged. The implementation of this method includes the logic to determine whether the session ID needs to be encoded in the URL. For example, if the browser supports cookies, or session tracking is turned off, URL encoding is unnecessary.
看了上面官方对该方法的解释就是对特定的URL添加session ID进行编码,如果不需要的话就不会对URL作任何改变。所有对该方法的实现应该包含判断session ID的信息是否需要添加到URL里面对URL作改变的逻辑。例如,如果浏览器支持cookies,或者session跟踪关了的话,就不对URL作改变。

下面看实例源码:

IndexServlet:首页,列出所有书

public class IndexServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        // 创建Session
        request.getSession();

        out.write("本网站有如下书:<br/>");
        Set<Map.Entry<String, Book>> set = DB.getAll().entrySet();
        for (Map.Entry<String, Book> me : set) {
            Book book = me.getValue();
            String url = request.getContextPath() + "/buyServlet?id="
                    + book.getId();
            // response. encodeURL(java.lang.String
            // url)用于对表单action和超链接的url地址进行重写,通过此方法带上JSESSSIONID
            url = response.encodeURL(url);// 将超链接的url地址进行重写
            out.println(book.getName() + "   <a href='" + url + "'>购买</a><br/>");
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

/**
 * @author gacl 模拟数据库
 */
class DB {
    private static Map<String, Book> map = new LinkedHashMap<String, Book>();
    static {
        map.put("1", new Book("1", "javaweb开发"));
        map.put("2", new Book("2", "spring开发"));
        map.put("3", new Book("3", "hibernate开发"));
        map.put("4", new Book("4", "struts开发"));
        map.put("5", new Book("5", "ajax开发"));
    }

    public static Map<String, Book> getAll() {
        return map;
    }
}

class Book {

    private String id;
    private String name;

    public Book() {
        super();
    }

    public Book(String id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

BuyServlet:点击购买后的逻辑

public class BuyServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String id = request.getParameter("id");
        Book book = DB.getAll().get(id); // 得到用户想买的书
        HttpSession session = request.getSession();

        HashSet<Book> set = (HashSet) session.getAttribute("set"); // 得到用户用于保存所有书的容器
        if (set == null) {
            set = new HashSet<Book>();
            session.setAttribute("set", set);
        }
        set.add(book);
        // response. encodeRedirectURL(java.lang.String
        // url)用于对sendRedirect方法后的url地址进行重写
        String url = request.getContextPath() + "/listCartServlet";
        url = response.encodeRedirectURL(url);//通过此方法带上JSESSSIONID
        System.out.println(url);
        response.sendRedirect(url);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

ListCartServlet:购物车页面

public class ListCartServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        HttpSession session = request.getSession();

        HashSet<Book> set = (HashSet) session.getAttribute("set");
        if (set == null || set.size() == 0) {
            out.write("对不起,您还没有购买任何商品!!");
            return;
        }

        // 显示用户买过的商品
        out.write("您买过如下商品:<br>");
        for (Book book : set) {
            out.write(book.getName() + "<br/>");
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

查看首页源码如下:

每个超链接都被encode加上了JSESSSIONID的信息,所以在访问BuyServlet带着此信息就相当于带着session信息,而BuyServlet在跳转到ListCartServlet也会把url encode一下带上JSESSSIONID,三个Servlet由此实现了session共享。

但当我们刷新列表页时会发现URL里面带的JSESSSIONID已经改变,购物车页面也会清空,所以并不能实现完全没禁用Cookie效果。

当我们开启Cookie时,只有在第一次访问列表页面时会有JSESSSIONID的信息,但我们刷新列表页面时,购物车页面没有清空,页面源码如下所示,没有了JSESSSIONID的信息,证明了encode方法的智能性。

2.3 session对象的销毁时机

session对象默认30分钟没有使用,则服务器会自动销毁session,在web.xml文件中可以手工配置session的失效时间,例如:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name></display-name>
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <!-- 设置Session的有效时间:以分钟为单位-->
    <session-config>
        <session-timeout>15</session-timeout>
    </session-config>

</web-app>

当需要在程序中手动设置Session失效时,可以手工调用session.invalidate方法,摧毁session。

HttpSession session = request.getSession();
//手工调用session.invalidate方法,摧毁session
session.invalidate();
上一篇下一篇

猜你喜欢

热点阅读