0为什么需要会话:
传统的客户端服务端交易的数据,可保存在的的的的HttpServletRequest中的和sevletContext对象中。但是当遇到甲发出购买和结账两个不同请求时,HttpServletRequest中的中的中的对象中只保存了结账的请求信息,购买的请求信息将会丢失,因为的的的的HttpServletRequest的的对象只能记录同一次请求的信息(太小了)。使用sevletContext对象保存数据时,由于同一个应用共享的是同一个对象,因此当用户在发送结账请求时,由于无法区分哪些商品是哪些用户所购买的,sevletContext对象会将购物网站中所有用户购买的商品进行计算,这显然是不可行的。为解决这一问题,产生了会话技术。
1.什么是会话:
从打开一个浏览器访问某个站点(会话开始),到关闭这个浏览器(会话结束)的整个过程,称为一次会话
2.什么是会话技术:
会话技术就是记录这次会话中客户端的状态与数据的。
会话技术分为饼干和会话:
饼干:数据存储在客户端本地,减少服务器端的存储的压力,安全性不好,客户端可以清除饼干
会议:将数据存储到服务器端,安全性相对好,增加服务器的压力
3,举个例子:
你(客户端)向我(服务器)借钱(访问服务器),我让你记着(到时还给我就行,但你要忘了,就没办法了 - --------- -----这是饼干
你(客户端)向我(服务器)借钱(访问服务器),我自己拿个(专门记录你我之间交易的)小本本记着(交易数据存放在服务器端),到时还给我就行,(我会根据我这的记录,知道你有没有少还钱,你也无法赖账,钱还完了,我就更新你还钱的状态了)------------- -----------------这是会议
4.实际的饼干案例:显示上次登陆的时间:
当饼干中包含有等号,空格,分号等特殊字符时,可能会导致数据丢失,或者不能解析的错误,一个较好的解决办法就是:在将饼的值写入客户端浏览器之前,首先进行的URLEncode的的的的编码,读取饼干时,进行URLDecode即可。
案例代码如下:
@WebServlet("/hello")
public class ShowLastAccessTime extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获得当前时间Date date = new Date();SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");String currentTime1 = format.format(date);/* 以上可简写为:// String currenttime=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());//字符串currentTime1中包含空格,存入COOKIE时会报错,// 当COOKIE中包含有等号、空格、分号等特殊字符时,可能会导致数据丢失、// 或者不能解析的错误,一个较好的解决办法就是:在将COOKIE值写入客户端浏览器之前,// 首先进行URLEncode编码,读取COOKIE时,进行URLDecode即可*/String currentTime=URLEncoder.encode(currentTime1, "UTF-8");COOKIE COOKIE=new COOKIE("lastAccessTime",currentTime);//COOKIE.setMaxAge(0);// 设为0,就是清空COOKIE的意思,可用于退出系统COOKIE.setMaxAge(10*60); //设置有效期为60分钟resp.addCOOKIE(COOKIE);String lastAccesstime=null;COOKIE[] COOKIEs=req.getCOOKIEs();if (COOKIEs!=null){for(COOKIE coo:COOKIEs){if("lastAccessTime".equals(coo.getName())){lastAccesstime=coo.getValue();}}}req.setCharacterEncoding("utf-8");resp.setContentType("text/html;charset=utf-8");PrintWriter out=resp.getWriter();if (lastAccesstime==null){out.write("第一次访问");} else {String time=URLDecoder.decode(lastAccesstime, "UTF-8");out.write("上次访问时间是:"+time );}}
下面是会话讲解:先看图:
一个网络应用,对应一台服务器,多个客户端,多个会议空间(一台服务器需要为每个客户端开辟一个会话存储空间)
客户端访问的服务程序,网络应用是怎么样将客户端与它的会话一一对应起来的呢,解决的方案就是通过设置会话编号(JSESSIONID)
基本概念:
会话技术是将数据存储在服务器端的技术,会为每个客户端都创建一块内存空间存储客户的数据,但客户端需要每次都携带一个标识ID(存于饼干中,放在请求头里面进行传输)去服务器中寻找属于自己的内存空间。所以说会话的实现是基于COOKIE的,会话需要借助于的COOKIE存储客户的唯一性标识JSESSIONID
- 获得会话对象
HttpSession session = request.getSession();
通过请求对象获得当前会话的会话对象,如果服务器端没有该会话的会话对象(无对应的JSESSIONID),则会创建一个新的会话返回,如果已经有了属于该会话的会话(JSESSIONID,即会的唯一标识,是从请求头的设置COOKIE
里面提取出来的),则直接将已有的会话返回(实质就是根据JSESSIONID判断在我的服务器上有没有与你客户端相对的已经存在了会话,即JSESSIONID是否能匹配的上)。
测试代码:
servlet1类:
@WebServlet("/session1")
public class Servlet1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session1 = req.getSession();session1.setAttribute("name", "jerry");String id = session1.getId();//该session对象的编号idresp.getWriter().write("JSESSIONID:"+id);}}
servlet2类:
@WebServlet("/session2")
public class Servlet2 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession();//从session中获得存储的数据HttpSession session2 = req.getSession();Object attribute = session.getAttribute("name");resp.getWriter().write(attribute+"");}
}
先访问servlet1,在访问servlet2,界面打印出客户名字,但当关闭浏览器,再次访问servlet2时,界面打印为空,因为我们这样的代码有效期是会话级别的。实际上系统默认为我们创建了一个存JSESSIONID的饼干,它的有效期是一次会话的时间(关闭浏览器后,会话结束,保存到本地的存放了JSESSIONID的饼干值也被清空了)
//手动创建一个存储JSESSIONID的COOKIE 为该COOKIE设置持久化时间COOKIE COOKIE = new COOKIE("JSESSIONID",id);COOKIE.setPath("/WEB16/");
//xxx表示一次会话的时间COOKIE.setMaxAge(xxxx);response.addCOOKIE(COOKIE);
我们可以根据需求,手写会议,从而持久化会话
更改后的servlet1代码如下:
@WebServlet("/session1")
public class Servlet1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session1 = req.getSession();session1.setAttribute("name", "jerry");String id = session1.getId();//该session对象的编号id//手动创建一个存储JSESSIONID的COOKIE 为该COOKIE设置持久化时间COOKIE COOKIE = new COOKIE("JSESSIONID",id);/*此处的参数,是相对于应用服务器存放应用的文件夹的根目录而言的(比如tomcat下面的webapp),因此COOKIE.setPath("/");之后,可以在webapp文件夹下的所有应用共享COOKIE,而COOKIE.setPath("/xxx/");是指以在webapp/xxx文件夹下的所有应用共享COOKIE*/COOKIE.setPath("/wego/");COOKIE.setMaxAge(60*10);resp.addCOOKIE(COOKIE);resp.getWriter().write("JSESSIONID:"+id);}}
这样只要在10分内,及时关掉了浏览器,再次打开,访问servlet2,也能打印出名字
可在web.xml文件中配置会话的有效期:
4320