JavaWeb开发中的会话技术[Cookie/Session]
2016-04-20 14:19
746 查看
会话
会话:用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。会话过程中要解决的一些问题:
每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自回产生一些数据,程序要想办法为每个用户保存这些资源。电商中的保存用户的购买的商品。
保存会话数据的两种技术
Cookie:Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去,这样web资源处理的就是用户自己的数据。Session:Session是服务器技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其他web资源时,其他的web资源再从用户各自德尔session中取出数据为用户服务。
Cookie
Cookie的访问过程:javax.servlet.http.Cookie类用于创建一个Cookie,response接口也定义了一个addCookie方法,它用于在其响应头中增加一个相应的
Set-Cookie头字段。同样在request接口中也定义了一个getCookies方法,它用于获取客户端提交的Cookie。
Cookie类的方法有(最好查看其API):
public Cookie(String name, String value)
setValue 与 getValue
setMaxAge 与 getMaxAge() [秒]
setPath 与 getPath
setDomain 与 getDomain
getName
一个Cookie是一个键值对。
通过Cookie可以保存用户的信息,示例:保存用户的上次的访问的时间并显示出来(通过request获取请求头中带有的Cookie,再通过response的响应头将Cookie值返回给浏览器):
package com.hsx.cookie; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.hsx.constant.MyConstant; /** * 保存用户的上次的访问的时间并显示出来 * @author hsx * */ public class CookieDemo1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("您上次获取的时间是:"); // 从客户端的请求获取指定的cookie Cookie[] cookies = request.getCookies(); System.out.println(cookies); // 第一次访问时cookie的值可能为null for (int i = 0; cookies != null && i < cookies.length; i++) { Cookie cookie = cookies[i]; System.out.println(cookie.getName()); if (MyConstant.LAST_ACCESS_TIME.equals(cookie.getName())) { long value = Long.parseLong(cookie.getValue()); out.println(new Date(value).toLocaleString()); } } // 把当前的时间写给客户端 Cookie cookie1 = new Cookie(MyConstant.LAST_ACCESS_TIME, System.currentTimeMillis() + ""); cookie1.setPath(request.getContextPath()); cookie1.setMaxAge(10 * 24 * 60 * 60); //存活的时间,默认浏览器的进程 response.addCookie(cookie1); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } } -------------------------------------------------------- /** * 常量接口设计模式(这里只是设置了Cookie的name值) * @author hsx * */ public interface MyConstant { String LAST_ACCESS_TIME = "lastAccessTime"; }
Cookie细节:
获取Cookie采用:request.getCookies();
设置Cookie采用:response.addCookie(cookie);
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(name)和设置值(value)。
一个Web站点可以给一个Web浏览器发送多个Cookie,一个Web浏览器也可以存储多个Web站点提供的Cookie。
浏览器一般存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
如果创建了一个Cookie,并将它发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的内存中),用户退出浏览器之后即被删除。若希望浏览器将该Cookie存储在磁盘上,则需要使用maxAge(默认是浏览器的进程),并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该Cookie。
path:默认是产生cookie的应用的访问路径,删除Cookie时,path必须一致,否则不会删除。在应用程序中设置Cookie时[cookie.setPath(“xxx”)]注意:
如果设置了路径,只能被包含的此路径的资源访问。
如果设置的路径是”/servletCS”,该Cookie只能被servletCS这个应用访问。
如果设置的路径是”/servletCS2”,虽然是servletCS应用产生的Cookie,但是该Cookie只能被servletCS2这个应用访问,servletCS是访问不到的。
cookie.setPath(request.getContextPath())这条语句设置的Cookie是本身这个应用的。由此可得:
request.getContextPath()是获取该应用[项目]的路径。
如果设置的路径是
cookie.setPath("http://localhost:8080/")或者
cookie.setPath("/")这条语句设置的Cookie能被”http://localhost:8080/“下的所有的应用访问。
如果设置的路径是
cookie.setPath("http://localhost:8080/ServletCS/servlet/")这条语句设置的Cookie能只能被该Servlet访问;即某个Servlet的
url-pattern配置是servlet2,则该servlet2都不能访问其Cookie。
总结:Cookie是否能被访问到是根据其设置的路径而言的。
//--- 删除指定的cookie cookie.setMaxAge(0);---// // 先获取指定的Cookie Cookie[] cookies = request.getCookies(); for (int i = 0; cookies != null && i < cookies.length; i++) { Cookie cookie = cookies[i]; if (MyConstant.LAST_ACCESS_TIME.equals(cookie.getName())) { //设置其maxAge(0):必须有path一致 cookie.setMaxAge(0); cookie.setPath(request.getContextPath()); //写个客户端 response.addCookie(cookie); } }
Cookie应用
模拟用户名登陆,始终保存用户的用户名[CookieDemo2中输入用户名,提交到CookieDemo3中,CookieDemo3对其用户名的Cookie做永久保存,在以后访问CookieDemo2时,用户名能显示出来]
/*---------------CookieDemo2---------------------*/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = ""; String rem = ""; // 从Cookie中获取用户名 Cookie[] cookies = request.getCookies(); for (int i = 0; cookies != null && i < cookies.length; i++) { Cookie cookie = cookies[i]; if (MyConstant.USER_NAEM.equals(cookie.getName())) { name = cookie.getValue(); rem = "checked='checked'"; } } // 显示出登陆页面 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head><title>用户登陆</title></head>"); out.println("<body>"); out.println("<form action='/servletCS/CookieDemo3' method='post'>"); out.println("<table width='400' border='1'>"); out.println("<tr>"); out.println("<td>用户名</td>"); out.println("<td><input type='text' name='username' value='" + name + "'/></td>"); out.println("</tr>"); out.println("<tr>"); out.println("<td>密码</td>"); out.println("<td><input type='password' name='password'/></td>"); out.println("</tr>"); out.println("<tr>"); out.println("<td colspan='2'><input type='checkbox' name='remember' " + rem + " />记住用户名</td>"); out.println("</tr>"); out.println("<tr>"); out.println("<td colspan='2'><input type='submit' value='go'/></td>"); out.println("</tr>"); out.println("</table>"); out.println("</form>"); out.println("</body>"); out.println("</html>"); } /*------------------CookieDemo3--------------------------*/ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); Cookie cookie = null; String remember = request.getParameter("remember"); System.out.println(remember); if (remember != null) { cookie = new Cookie(MyConstant.USER_NAEM, request.getParameter("username")); cookie.setPath(request.getContextPath()); cookie.setMaxAge(Integer.MAX_VALUE); //永久保存 response.addCookie(cookie); } out.println(cookie.getName() + "<br/>"); out.println(cookie.getValue()); } /*--------------------常量接口设计模式------------------------*/ public interface MyConstant { String USER_NAEM = "username"; }
Seesion
session的访问过程在Web开发中,服务器可以为每一个用户浏览器创建一个会话对象(Session对象),注意:一个浏览器独占一个Session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的Session中,当用户使用浏览器访问其他程序时,其他程序可以从用户的Session中取出该用户的数据,为用户服务。
Session和Cookie的主要区别在于:
Cookie是把用户的数据写给用户的浏览器。
Seesion技术把用户的对象写到用户独占的session中。
Session对象是由服务器创建的,开发人员可以调用request对象的getSession方法得到session对象。
Session技术实际上用的Cookie技术。图解说明:
注意:
IE7及以下版本,新开的窗口都会开启一次新会话。
每一个客户端都有各自的Session对象,以SeesionID标识。
Seesion技术实际上是借助Cookie技术实现的,在创建Session对象时,会将该Session对象的ID以Cookie的JSESSIONID=SessionID的形式写给客户端。
session的原理图:
Session默认何时时效?时间到了,就会失效,默认是30分钟。更改Session的默认时间:
在web.xml文件的根元素中增加,单位为分钟。
<session-config> <session-timeout>1s</session-timeout> </session-config>
注意:
request.getSession(); // 要是没有Session对象,就立马创建Session对象 request.getSession(false); // 设置了false,要是没有Session对象,不会创建session对象。
IE禁用Cookie后的session处理
解决方案:URL重写(以下方法先检查浏览器是否禁用Cookie,若禁用Cookie那么会在地址栏上加上jsesssionid=xxx,若没有禁用Cookie那么不加jsessionid–>很智能。注意:当禁用Cookie后,要对所有的URL进行重写)
response.encodeRedirectURL(java.lang.String url); //用于对sendRedirect方法后的url地址进行重写。
response.encodeURL(java.lang.String url); //用于对表单action和超链接的url地址进行重写。
String url1 = request.getContextPath() + "/PayServlet"; url1 = response.encodeURL(url1); out.println("<br/><a href='" + url1 + "'>结账</a>");
案例:
/*-----IndesServlet-----显示所有的商品,提供购买链接 -- 放入购物车*/
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>商品</title></head>");
out.println("<body>");
// 显示所有的商品
List<String> productList = Product.getAllProduct();
out.println("本站有以下好商品:<br/>");
for (String product : productList) {
out.println(product);
String url = request.getContextPath() + "/BuyServlet?name=" + product;
url = response.encodeURL(url); //禁用浏览器的Cookie时使用的
out.println("<a href='" + url + "'>购买</a><br/>");
}
// 转向结账
String url1 = request.getContextPath() + "/PayServlet"; url1 = response.encodeURL(url1); out.println("<br/><a href='" + url1 + "'>结账</a>");
out.println("</body>");
out.println("</html>");
out.close();
/*-----BuyServlet-----购买的Servlet,将商品加入购物车*/
String productName = request.getParameter("name");
productName = new String(productName.getBytes("ISO-8859-1"), "UTF-8");
// 查看Session中是否有购物车
HttpSession session = request.getSession();
Object object = session.getAttribute(MyConstant.MY_CART);
if (null != object) {// 有:取出来,放商品
List<String> cartList = (List<String>) object;
cartList.add(productName);
}
else {// 没有,先构件购物车
List<String> cartList = new ArrayList<String>();
cartList.add(productName);
session.setAttribute(MyConstant.MY_CART, cartList);
}
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("您已经购买了:" + productName);
String url = request.getContextPath() +"/IndesServlet";
url = response.encodeURL(url);
out.println("<br/><br/><a href='"+ url +"'>继续购买</a>");
/*-----PayServlet-----显示购物车中的商品*/
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession(false); //只是取
if (session == null) {
out.println("您还未购物");
}
else {
List<String> myCartList = (List<String>) session.getAttribute(MyConstant.MY_CART);
out.println("您购买了以下商品:<br/>");
for (Object object : myCartList) {
out.println(object + "<br/>");
}
}
out.close();
Session开发中遇到的问题?
内存中的Session非常多,怎么办?
用户在购物中,服务器停了该web应用(或者重启了),那么用户购物车中的东西怎么办?
解决办法:将内存中的Session持久化。
何时session会被持久化?[具体是根据服务器的实现定的,对用户来说完全是透明的]
当服务器停止当前应用
内存中的session对象太多
session长时间没有活动(并没有被销毁)
何时会被激活?
当前web应用又启动了
用户又开始使用了(鼠标、键盘又开始使用了)
session中的序列与反序列基本图:
相关文章推荐
- Java中的数组基础(一)
- J2SE(十一)Java之内部类
- Spring 整合Mybatis实例
- [改善Java代码]别让null值和空值威胁到变长方法
- 【项目管理和构建】十分钟教程,eclipse配置maven + 创建maven项目(三)
- java学习笔记3
- ios 和 java byte[]的兼容处理
- 【LeetCode-137】Single Number II
- eclipse启动时devices.xml报错 不具有面有效性。它必须是来自枚举的值。
- Java BIO、NIO、AIO、同步、异步
- 关于maven的依赖分析
- java中InputStream转化为byte[]数组
- java学习笔记2
- java从本地向另外一个地址发送请求
- Java抽象类和接口的区别
- 《疯狂Java讲义(第3版)》.(李刚)——前言
- java中的进制
- java web classpath
- MD5加密--Java
- SpringMVC 基于注解的Controller详解