Java EE入门教程系列第四章Servlet(三)——会话跟踪 秒速五厘米 2022-04-13 05:25 123阅读 0赞 ## 4.3 会话跟踪 ## ### 4.3.1 Cookie ### HTTP协议是一个无状态的协议,无状态也就是说,如果此时的状态是连接的,下一刻状态就可能是断开的,状态是不稳定的。 Cookie是在HTTP协议下,服务器或脚本可以维护客户工作站信息的一种方式。Cookie是由web服务器保存在用户浏览器(客户端)上的小文本文件,可以包含有关用户的信息。无论何时用户链接到服务器,web站点都可以访问Cookie信息。 目前Cookie有些是临时的,有些是持续的。临时的只在浏览器上保存一段时间,一旦超过规定时间就会被系统清除。持续的Cookie保存在用户的Cookie文件中,下一次用户返回时,仍然可以对它进行调用。有些用户会担心这样会造成信息泄露,其实网站以外的用户无法跨过网站来获得Cookie信息,Cookie的存在还是大有作用的。 Cookie类的方法列表: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70][] 举例:Cookie.java判断本地是否存在一个指定名称的cookie,没有则创建这个cookie并显示出来 package cy.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class Cookie */ @WebServlet("/Cookie") public class Cookie extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public Cookie() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=UTF-8"); javax.servlet.http.Cookie cookie=null; javax.servlet.http.Cookie[] cookies=request.getCookies(); boolean newCookie=false; if(cookies!=null) { for(int i=0;i<cookies.length;i++) { if(cookies[i].getName().equals("cyCookie")) { cookie=cookies[i]; } } } if(cookie==null) { newCookie=true; int maxAge=5; cookie=new javax.servlet.http.Cookie("cyCookie","first"); //设置Cookie路径 cookie.setPath(request.getContextPath()); cookie.setMaxAge(maxAge); response.addCookie(cookie); } response.setContentType("text/html;charset=UTF-8"); java.io.PrintWriter out=response.getWriter(); out.println("<html>"); out.println("<head>"); out.println("<title></title>"); out.println("</head>"); out.println("<body>"); out.println("Cookie的值为:"+cookie.getValue()+"<br>"); if(newCookie) { out.println("<br>这里的信息只有第一次运行可以看到!<br>"); out.println("Cookie的生命周期为:"+cookie.getMaxAge()+"<br>"); out.println("Cookie的名字为:"+cookie.getName()+"<br>"); out.println("Cookie的路径为:"+cookie.getPath()+"<br>"); } out.println("</body>"); out.println("</html>"); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } 其中setMaxAge()方法是设置Cookie的有效期,这里的单位是秒。在上面的例子中,浏览器运行结果为: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 1][] 如果在5秒内刷新页面就会发现界面内容少了一些: ![20181127175014308.png][] 5秒后再刷新,页面又变成初次运行的结果。 ### 4.3.2 URL参数传递与重写 ### 我们可以随便在浏览器上搜索某个事物,会发现很多情况下浏览器地址栏除了显示正常的网页地址外,总会在后面跟一个?或!。这里就使用了URL参数传递的技术。 这个技术和前面介绍的cookie都是一种保持状态传递信息的技术。由于cookie技术是把上网信息保存在客户端的硬盘中,有一定安全隐患,URL传递参数就成为一种很好地替代。 不同开发平台,写法有所差异,在Java EE平台的语法形式为: http://www.npumd.edu.cn/file.htm?id=12345&pw=6669 ?代表要在URL后面加入的参数,如果是多个参数,则用&连接。这些参数传递到相关文件后,可通过request.getParameter()方法获取。 举例:传参文件 SetParam.java package cy.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class SetParam */ @WebServlet("/SetParam") public class SetParam extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public SetParam() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=UTF-8"); PrintWriter out=response.getWriter(); try { String uname="Hedy"; String uage="19"; String encodedUrl=response.encodeURL(((HttpServletRequest) request).getContextPath()+ "/PlayerInfo?name="+uname+"&age="+uage); out.println("<html"); out.println("<head>"); out.println("<title></title>"); out.println("</head>"); out.println("<body>"); out.println("查看信息请点击<a href=\""+encodedUrl+"\">这里</a>"); out.println("</body>"); out.println("</html"); }finally { out.close(); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } 接收文件PlayerInfo.java package cy.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class PlayerInfo */ @WebServlet("/PlayerInfo") public class PlayerInfo extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public PlayerInfo() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("UTF-8"); PrintWriter out=response.getWriter(); try { out.println("<html"); out.println("<head>"); out.println("<title></title>"); out.println("</head>"); out.println("<body>"); out.println("名字:"+request.getParameter("name")); out.println("年龄:"+request.getParameter("age")); out.println("</body>"); out.println("</html"); }finally { out.close(); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } 截图: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 2][] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 3][] ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 4][] 虽然我们在实际上网过程中看到了?,但是后面的内容似乎都看不太懂,这是因为Java EE给出了一种名为URL重写的技术。这个技术不是传递参数,而是获得一个进入的URL请求,然后把它重新写成网站可以处理的另一个URL。例如将/PlayerInfo.java?id=100111重写为/PlayerInfo.html。 URL重写的好处: 1)方便用户访问,同时屏蔽了一些重要信息 2)可以把动态的页面变成静态的,有利于搜索引擎的识别抓取 3)提高重用性。例如,系统更改了后端控制程序访问的方法,而通过URL重写定义的前端地址可以不用改,这样就提高了网站的移植性。 ### 4.3.3 Session ### Session是一个高级接口,是建立在上面两个技术之上的。它针对会话跟踪的底层实现机制,对用户是透明的。Session可以连续跨越多个用户的连接,通过HttpServletRequest的getSession()方法可以获取HttpSession对象: HttpSession session=request.getSession(); ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 5][] 使用Session来存储会话信息的步骤如下: 1)获取一个HttpSession的对象资源 2)判断是否存在指定的Session属性,如果存在则获取这个属性的值,不存在则创建这个属性 3)使用这个session对象的属性 4)如果不再需要这个对象,手动停止他或者什么都不做,等待系统自动回收 举例:Session.java package cy.servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class SetParam */ @WebServlet("/SetParam") public class Session extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public Session() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=UTF-8"); PrintWriter out=response.getWriter(); HttpSession session=request.getSession(); Date crtTime=new Date(session.getCreationTime());//创建对象的时间 Date lastAccessTime=new Date(session.getLastAccessedTime());//上次访问session的时间 Integer visitCount=new Integer(0);//统计访问次数 String visitCountKey=new String("visitCount"); String userIDKey=new String("userID"); String userID=new String("ABCD"); if(session.isNew()) { //为空会自动创建一个session对象 session.setAttribute(userIDKey, userID); } else { visitCount=(Integer)session.getAttribute(visitCountKey); if(visitCount!=null) { visitCount+=1; } if(session.getAttribute(userIDKey)!=null) { userID=(String)session.getAttribute(userIDKey); } } session.setAttribute(visitCountKey, visitCount); response.setContentType("text/html;charset=UTF-8"); try { out.println("<html"); out.println("<head>"); out.println("<title></title>"); out.println("</head>"); out.println("<body>"); out.println("<table border='1' align='center'>"); out.println("<tr><th>session</th><th>value</th></tr>"); out.println("<tr><td>id</td><td>"+session.getId()+"</td></tr>"); out.println("<tr><td>creation time</td><td>"+crtTime+"</td></tr>"); out.println("<tr><td>last access time</td><td>"+lastAccessTime+"</td></tr>"); out.println("<tr><td>User ID</td><td>"+userID+"</td></tr>"); out.println("<tr><td>number of visit</td><td>"+visitCount+"</td></tr>"); out.println("</body>"); out.println("</html"); }finally { out.close(); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } 第一次访问时访问次数为0,再访问几次结果为: ![watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 6][] 其他文件获取session的方式都是通过getAttribute()方法,但是在此之前一定要先申请获取session对象资源HttpSession session=request.getSession()才可以。 ### 4.3.4 Servlet的上下文 ### 运行在Servlet服务器中的web应用都会有一个全局的、储存信息的对象,这个对象就是Servlet的上下文,可以使同一个web应用中不同资源之间进行信息共享。Javax.Servlet.ServletContext接口就是对上下文对象进行相关操作的,通过它的getServletContext()方法,可以获得当前运行的Servlet的上下文对象。 Servlet可以通过名称将对象属性绑定到上下文,任何绑定到上下文的属性都可以被同一个web应用的其他Servlet使用。获取上下文实例及添加信息的主要方法为: 1)getServletContext():通过ServletConfig接口获得上下文实例,这里的上下文实例对象不是创建一个新的对象,而是去获取每个web应用都唯一对应的上下文对象 2)getInitParameter()、getInitParameterNames():访问web应用的初始化参数和属性 3)setAttribute()、getAttribute():添加并获取上下文对象的信息 4)getAttributeNames()、removeAttribute():获取上下文信息的名称,并移除上下文中保存的信息 举例:GetMessage.java获取上下文信息并在里面保存一个信息 package cy.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class PlayerInfo */ @WebServlet("/PlayerInfo") public class GetMessage extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public GetMessage() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("UTF-8"); PrintWriter out=response.getWriter(); try { String info="Hedy冲鸭"; getServletConfig().getServletContext().setAttribute("Message", info); out.println("<html"); out.println("<head>"); out.println("<title></title>"); out.println("</head>"); out.println("<body>"); out.println("信息:"+info); out.println("</body>"); out.println("</html"); }finally { out.close(); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } 运行结果: ![20181127215748568.png][] ShowMessage.java读取上一个文件的信息 package cy.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class PlayerInfo */ @WebServlet("/PlayerInfo") public class ShowMessage extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public ShowMessage() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub response.setContentType("text/html;charset=UTF-8"); request.setCharacterEncoding("UTF-8"); PrintWriter out=response.getWriter(); try { String getInfo=(String) getServletContext().getAttribute("Message"); out.println("<html"); out.println("<head>"); out.println("<title></title>"); out.println("</head>"); out.println("<body>"); out.println("读到的信息:"+getInfo); out.println("</body>"); out.println("</html"); }finally { out.close(); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } } 运行可以发现读到的信息和之前保存的信息是一样的: ![20181127223803100.png][] 通过上面的例子,可以发现上下文对象和session的方式非常相似,但是它们是有区别的,最根本的是它们具有不同的生命周期。 当web服务器开始运行后,这个应用就具备了唯一一个上下文对象,只要这个应用没有停止,这个上下文对象就一直存在。而session,每个用户都可以拥有一个。从适用范围来看,session应该是局部的,与用户有关的信息,上下文对象则是全局的,相对公共、更加安全的信息。 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70]: /images/20220413/761527e8b43546d39ab0bb7d6c17b8ef.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 1]: /images/20220413/5be79743232243f6b7f50c787b0a8a3e.png [20181127175014308.png]: /images/20220413/a539ac25675642e4afbb06f27d83454f.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 2]: /images/20220413/85210d2eab5644fba47586b2e4da51d0.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 3]: /images/20220413/79c93676b1194589aea6a4b17dd3e4f9.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 4]: /images/20220413/10ea7b62a1ab4514a1c47443bf800b39.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 5]: /images/20220413/c780efecd65c416cb0b3e7a04c12222a.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwOTk2MDQx_size_16_color_FFFFFF_t_70 6]: /images/20220413/da431df9f0e84eada40ee02c8db7b6dc.png [20181127215748568.png]: /images/20220413/01357c1c786e46d9851640ed477c0b3d.png [20181127223803100.png]: /images/20220413/8b33d1550191457ab75caf1b52773bc4.png
还没有评论,来说两句吧...