• 保存会话数据——session学习


    Session:
    Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据为用户服务。

    session的实现是基于cookie。 

    Session的生命周期:

      创建: 是在 request.getSession(); 执行时,创建, 它会首先检查客户端带来的cookie中是否存在jsessionid , 如果不存在或者jsessionid所对对应的session已经无效就创建,然后将 jsessionid以cookie的形式发送给客户端(该cookie使用的浏览器进程缓存)。  如果客户端带来的cookie中存在jsessionid并且其所对应的session还是有效的,那么就直接取出来。

      销毁: session在默认情况下是半小时无访问的话,就会失效。 我们可以在web.xml中配置:  

    <session-config>
      	<session-timeout>默认时间</session-timeout>
      </session-config>
    

      

    明白了原理之后我们可以解决多个浏览器访问同一个session的例子了。(也即关闭浏览器之后再次访问,还会获得我们的session(保证在session有效期内访问)):

    	
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		HttpSession session = request.getSession();
    		//收到想客户端发送cookie, 实现关闭浏览器之后还能访问session中的值
    		String jsessionid = session.getId();
    		Cookie cookie = new Cookie("JSESSIONID", jsessionid);  //request.getSession();默认发送的cookie的名字为JSESSIONID
    		cookie.setMaxAge(1*60);
    		cookie.setPath("/Test");
    		response.addCookie(cookie);
    		
    		session.setAttribute("pro", "电视");
    	}
    

      

    解决用户禁用cookie的问题:

    如果用户浏览器禁用cookie之后,我们传统的session就无法实现数据的保存了。  必须进行对所有的连接跟上jsessionid

    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		
    		response.setCharacterEncoding("UTF-8");
    		response.setContentType("text/html; charset=UTF-8");
    		PrintWriter pw = response.getWriter();
    		
    		request.getSession();
    		//自动检查是否禁用cookie, 如果禁用,会将jsessionid加入url
    		
    		String url1 = response.encodeURL("/Test/sessionDemo1");
    		String url2 = response.encodeURL("/Test/sessionDemo2");
    		
    		pw.print("<a href='" + url1 +"'>购买</a>");
    		pw.print("<a href='"+ url2 +"'>已买</a>   ");
    	}
    

      

     1:session实现购物车功能: (实际开发的时候为了解决服务器压力,一般用cookie实现,与现实浏览过的商品类似)

      我们将我们定义的购物车可以放入session, 然后点击购买时,就将我们购买的东西放入购物车。

      1: 如果我们要实现我们关闭浏览器购物车中的东西还存在,就要手动发送jsessionid。

      2 :如果解决客户端浏览器禁止cookie的问题的话,就要对所有涉及到url的地址进行重写

      3:当我们购买完跳到购物车显示页面时,一定要使用重定向。如果使用转发的发,我们每刷新一次就会购买一次

    :2:还可以实现用户登录:

    当用登录提交表单, 然后servlet处理完之后,经用户对象保存在session中, 然后我们处理每次对话就能够得到用户了。

    3:session实现防止表单重复提交:

      首先我们可以在前端利用js实现防止表单重复提交:

      

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'index.jsp' starting page</title>
        
    	<meta http-equiv="pragma" content="no-cache">
    	<meta http-equiv="cache-control" content="no-cache">
    	<meta http-equiv="expires" content="0">    
    	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    	<meta http-equiv="description" content="This is my page">
    	<!--
    	<link rel="stylesheet" type="text/css" href="styles.css">
    	-->
    
    	<script type="text/javascript">
    		
    		//利用程序结构控制
    		/*var isSubmit = false; 
    		function dosubmit(){
    			//alert("hhh");
    			if (!isSubmit) {
    				isSubmit = true;
    				return true;
    			} else {
    				return false;
    			}
    		}*/
    		
    		// 将提交按钮,设为disable
    		function dosubmit(){
    			var input = document.getElementById("submit");
    			input.disabled = "disabled";
    			return true;
    		}
    	</script>
      </head>
      
      <body>
          <form action="/Test/DoFormServlet" method="post" onsubmit="return dosubmit()">
          	 用户名:<input type="text" name="username">  <br/>
          	 <input id="submit" type="submit"  value="提交" > <br/>
          </form>
      </body>
    </html>
    

      

     前端js存在缺陷, 我可以修改你的js代码,然后实现重复提交

    实际开发中我们利用前端js + 后台servlet来实现:

    后台为了实现防止表单提交,我们可以为每一个表单设置一个唯一的编号, 每当我们提交表单时, 我们就从session中去这个Id如果存在,说明该表单还未提交,则允许提交,否则表明该表单已经提交,则防止提交。 

    这样在显示表单提交这个页面的时候, 就必须利用一个servlet来产生唯一编号,给表单。

    产生唯一标号的servlet

    package com.from;
    
    import java.io.IOException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Random;
    
    import javax.management.RuntimeErrorException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import sun.misc.BASE64Encoder;
    
    
    
    
    public class FormServlet extends HttpServlet {
    
    	
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		TokenProcessor tokenPro = TokenProcessor.getInstance();
    		String token = tokenPro.generateToken();
    		request.getSession().setAttribute("token", token);
    		request.getRequestDispatcher("/session/login.jsp").forward(request, response);
    	}
    
    	
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		doGet(request, response);
    	}
    
    }
    
    //单例用来产生唯一标示表单的令牌
    class TokenProcessor{
    	private TokenProcessor(){}
    	private static final TokenProcessor instance = new TokenProcessor();
    	public static TokenProcessor getInstance(){
    		return instance;
    	}
    	public String generateToken(){
    		String token = System.currentTimeMillis() + new Random().nextInt() + "";
    		//利用MD5算法,得到数据的摘要
    		try {
    			MessageDigest md = MessageDigest.getInstance("md5");
    			byte[] buff = md.digest(token.getBytes());  //将任意长度的数据,转化成128位的数据 即16个字节
    			
    			//base64编码  返回键盘上可见的字符组成的字符串  将六位0|1 转化成一个字节。  则其取值范围为[0,63]业绩64个字符 
    			//可用于数据的传输, base64编码之后,我们的消息 开石头, 结束为 用不是base64里面的字符即可
    			BASE64Encoder encoder = new BASE64Encoder();
    			return encoder.encode(buff);
    		} catch (NoSuchAlgorithmException e) {
    			throw new RuntimeException(e);
    		}
    	}
    }
    

      
    处理表单提交的servlet

    package com.from;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    public class DoFormServlet extends HttpServlet {
    
    	
    	public void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		
    		String username = request.getParameter("username");
    		try {
    			Thread.sleep(3*1000);
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		HttpSession session = request.getSession();
    		String t_token = request.getParameter("token");
    		
    		if (t_token != null && session != null && t_token.equals(session.getAttribute("token"))){
    			System.out.println("写入数据库..." + username);
    			session.removeAttribute("token");
    		} else {
    			System.out.println("重复提交");
    		}
    	}
    	public void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		doGet(request, response);
    	}
    
    }
    

      

    表单提交

     <body>
          <form action="/Test/DoFormServlet" method="post" >
          	<input type="hidden" name="token" value="${token}">
          	 用户名:<input type="text" name="username">  <br/>
          	 <input id="submit" type="submit"  value="提交" > <br/>
          </form>
      </body>
    

      

    这里我们可以结合js一起实现更佳

    4:session实现验证码的校验;

    我在response向客户端输出验证码的时候写过http://www.cnblogs.com/E-star/p/3504320.html

  • 相关阅读:
    elasticsearch 不能通过9200端口访问
    elasticsearch 2.0+ 安装 Marvel
    修改es最大返回结果数
    ElasticSearch的Marvel更新license
    python-execjs(调用js)
    爬取豆瓣电影排名的代码以及思路
    docker的安装
    mysql主从同步
    Docker配置yapi接口
    第24课
  • 原文地址:https://www.cnblogs.com/E-star/p/3510322.html
Copyright © 2020-2023  润新知