Java_web Session技术

Java_web——Session技术

Session技术

  1. Session当服务器运行到request.getSession()时就会被创建(当此用户Session已存在就不会再创建)
  2. Session默认当30分钟没人使用就会摧毁(或者你调用Session.invalidate()就会被摧毁)
  3. request.getSession(false)只会获取已存在的Session,就算对这个用户的Session不存在也不会创建
  4. Session的多长时间没人使用就摧毁可以定义在web.xml文件中
    1
    2
    3
    4
    //10分钟不使用的Session就摧毁掉
    <session-config>
    <session-timeout>10</session-timeout>
    </session-config>
  5. request.getSession()是怎么样判断这个用户的session是否存在呢?

其实每一个session都有一个id号,服务器把这个id号以cookie的形式写会用户浏览器,但是这个cookie的生存时间是默认的(也就是说当用户的浏览器进程一旦终止,这个cookie也就没有了)

下面我们写一个设置session的id有效期的代码:

购买SessionDemo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package test;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
* Servlet implementation class SessionDemo
*/
@WebServlet("/SessionDemo")
public class SessionDemo extends HttpServlet { //购买
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
HttpSession session = request.getSession();
String sessionid = session.getId(); //获取session的id
Cookie cookie = new Cookie("JSESSIONID",sessionid); //session把id写回浏览器时用的Cookie名为JSESSIONID
cookie.setPath("/day02");
cookie.setMaxAge(30*60); //设置cookie有效期为30分钟
response.addCookie(cookie);
session.setAttribute("name", "洗衣机");
}

/**
* @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);
}
}

结账SessionDemo1.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package test;

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;
import javax.servlet.http.HttpSession;

/**
* Servlet implementation class SessionDemo1
*/
@WebServlet("/SessionDemo1")
public class SessionDemo1 extends HttpServlet { //结账
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();

HttpSession session = request.getSession();
String product = (String) session.getAttribute("name");
out.write("你购买得商品为:"+product);

}

/**
* @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);
}
}

ind.html

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="/day02/SessionDemo">购买</a>
<a href="/day02/SessionDemo1">结账</a>
</body>
</html>
  1. response有一个方法encodeURL(示例:response.encodeURL(“/day02/SessionDemo”)),这个方法你需要提供给它一个链接,它会返回给你一个链接,返回给你的链接后面可能会把session的id追加到后面(为什么说可能,因为如果服务器检测到你带cookie来了,那就说明你的浏览器没有禁用cookie,那么session就可以正常工作,那么就不会把session的id追加到链接后面。但是如果你禁用session了,那么这个函数就会把session的id追加到你提供链接后面)。当第一次访问这个网站,服务器不知道你禁用cookie了没有,那么服务器即会给你以cookie形式返回session的id,还会给你提供的链接后面把session的id追加上去。

  2. 用session解决表单重复提交的问题

表单重复提交:当提交表单之后一旦刷新你之前做的事情就会重新做一次
Session技术

或者是由于网络延迟,导致你点击提交按钮多次,都会让服务器接收到多次提交表单的信息

这个问题可以由JavaScript来解决,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
/* 第一种JavaScript解决表单重复提交
var issub = false;
function dosubmit(){
if(!issub){
issub=true;
return true;
}else {
return false;
}
}*/
//第二种解决表单重复提交
function dosubmit(){
var input = document.getElementById("submit");
input.disable='disable';
return true;
}
</script>
</head>
<body>
<form action="/day02/SessionDemo2" method="post" onsubmit="return dosubmit()">
用户名2:<input name="username" type="text"><br/>
<input id="submit" type="submit" value="提交" ><br/>
</form>
</body>
</html>

但是这种方法是不彻底的,因为JavaScript代码可以在用户浏览器上被用户更改而使得没有彻底解决问题,或者用户提交表单之后刷新,或者用户不断地点击前进和后退按钮。

在这种情况下我们使用session来解决这个问题,我们给予每一个表单一个表单号,存放到session中,如果这个表单被提交过了就把相应的表单号从session中删除,一个表单号只能用于提交一次。

formRandom.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package test;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

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 sun.misc.BASE64Encoder;

/**
* Servlet implementation class formRandom
*/
//产生表单
@WebServlet("/formRandom")
public class formRandom extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//产生表单号
TokenRandom tr = TokenRandom.getRandom();
String token = tr.generateRandom();
request.getSession().setAttribute("token", token);
request.getRequestDispatcher("/form.jsp").forward(request, response);
}

/**
* @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);
}

}
class TokenRandom{
//采用单例模式:在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
/*步骤
* 1、构造方法私有化
* 2、自己创建一个
* 3、对外暴露一个方法,允许获得上面创建的对象
*/
private TokenRandom() {}
private static final TokenRandom random = new TokenRandom();
public static TokenRandom getRandom() {
return random;
}
public String generateRandom() {
String token = System.currentTimeMillis()+new Random().nextInt()+"";
//上面产生的字符串长度不一致,我们需要使用md5得到token字符串的摘要,获得的字符串md5摘要长度为128位
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte[] md5 = md.digest(token.getBytes());
//又因为我们需要获得一个字符串,所以我们采用base64把md5摘要过的byte数组转换为字符串
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
}catch(NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}

给一个Base64算法的内部实现:https://blog.csdn.net/benbenxiongyuan/article/details/7756912

SessionDemo2.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package test;

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 SessionDemo2
*/
@WebServlet("/SessionDemo2")
public class SessionDemo2 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
boolean b = isTokenValid(request);
if(!b) {
out.print("请不要重复提交"+"<br/>");
return;
}
request.getSession().removeAttribute("token");
System.out.println("向数据库注册用户");
}



private boolean isTokenValid(HttpServletRequest request) {
// TODO Auto-generated method stub
String client_token = request.getParameter("token");
if(client_token==null) {
return false;
}
String server_token = (String) request.getSession().getAttribute("token");
if(server_token==null) {
return false;
}
if(!server_token.equals(client_token)) {
return false;
}
return true;
}
/**
* @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);
}

}

form.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/day02/SessionDemo2" method="post">
<input type="hidden" name="token" value="${ token}">
用户名2:<input name="username" type="text"><br/>
<input id="submit" type="submit" value="提交" ><br/>
</form>
</body>
</html>