Session簡單介紹
在WEB開發中,服務器可以為每個瀏覽器用戶創建一個會話對象(session對象),注意:一個瀏覽器用戶獨占一個session對象(默認情況下)。因此,在需要保存用戶數據時,服務器程序可以把用戶數據寫到瀏覽器用戶獨占的session中,當用戶使用瀏覽器訪問該web應用的其它servlet時,其它servlet可以從用戶的session中取出該用戶的數據,為用戶服務,從而實現數據在多個頁面中的共享。
Session和Cookie的主要區別
- Cookie是把用戶的數據寫到用戶的瀏覽器。
- Session技術把用戶的數據寫到用戶獨占的session中,tomcat服務器內存中。
- Session對象由服務器創建,開發人員可以調用request對象的getSession方法得到session對象
session機制演示圖
服務器通過request對象的getSession方法創建出session對象后,會把session的id號,以cookie的形式回寫給客戶機,這樣,只要客戶機的瀏覽器不關,再去訪問服務器時,都會帶著session的id號去,服務器發現客戶機瀏覽器帶session id過來了,就會使用內存中與之對應的session為之服務。
@WebServlet(name = "TestServlet",urlPatterns = "/test")
public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession httpSession = request.getSession();
httpSession.setAttribute("user","zhangsan");
System.out.println(httpSession.getId());
}
}
在開發者工具中查看,第一發出時請求響應頭當中有Set-Cooie
再次請求時(刷新),響應頭當中將沒有Set-Cookie,而請求頭當中將有Cookie發回給服務器,
兩個Cookie完全一樣,以后的每次請求都會找到那個session對象,完成跟蹤。
Session cookie
session通過SessionID來區分不同的客戶, session是以cookie為基礎的,系統會創造一個名為JSESSIONID的輸出cookie,這稱之為session cookie,以區別persistent cookies(也就是我們通常所說的cookie),session cookie是存儲于瀏覽器內存中的,并不是寫到硬盤上的,session cookie針對某一次會話而言,會話結束session cookie也就隨著消失了,而persistent cookie只是存在于客戶端硬盤上的一段文本。
關閉瀏覽器,只會使瀏覽器端內存里的session cookie消失,但不會使保存在服務器端的session對象消失,同樣也不會使已經保存到硬盤上的持久化cookie消失。
持久化session cookie
@WebServlet(name = "TestServlet",urlPatterns = "/test")
public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession httpSession = request.getSession();
Cookie cookie = new Cookie("JESSIONID",httpSession.getId());
cookie.setMaxAge(300);
}
}
關閉瀏覽器,5分鐘之內打開瀏覽器,session依然有效。
HttpSession的生命周期
問題:用戶開一個瀏覽器訪問一個網站,服務器是不是針對這次會話創建一個session?
答:不是的。session的創建時機是在程序中第一次去執行request.getSession();這個代碼,服務器才會為你創建session。
問題:關閉瀏覽器,會話結束,session是不是就銷毀了呢?
答:不是的。session是30分鐘沒人用了才會死,服務器會自動摧毀session。
session何時會銷毀
A.調用invalidate()方法,該方法使HttpSession立即失效
@WebServlet(name = "TestServlet",urlPatterns = "/test")
public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession httpSession = request.getSession();
httpSession.invalidate();
}
}
B.服務器卸載了當前WEB應用
C.超出session過期時間
@WebServlet(name = "TestServlet",urlPatterns = "/test")
public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession httpSession = request.getSession();
httpSession.setMaxInactiveInterval(30);//單位秒
}
}
web.xml文件中也可以修改session的過期時間(全局的,所有的session的過期時間,若想單獨設置還是像上面那樣單獨設置),單位分鐘。
<session-config>
<session-timeout>30</session-timeout>
</session-config>
Session的典型案例:一次性驗證碼
生成驗證碼圖像的工具類GenerateCode.java 代碼
package util;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* Created by ttc on 2018/3/15.
*/
public class GenerateCode {
//設置驗證圖片的寬度, 高度, 驗證碼的個數
private int width = 152;
private int height = 40;
//驗證碼字體的高度
private int fontHeight = 38;
//驗證碼中的單個字符基線. 即:驗證碼中的單個字符位于驗證碼圖形左上角的 (codeX, codeY) 位置處
private int codeX = 25;//width / (codeCount + 2);
private int codeY = 36;
public BufferedImage Generate(String code)
{
//定義一個類型為 BufferedImage.TYPE_INT_BGR 類型的圖像緩存
BufferedImage buffImg = null;
buffImg = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
//在 buffImg 中創建一個 Graphics2D 圖像
Graphics2D graphics = null;
graphics = buffImg.createGraphics();
//設置一個顏色, 使 Graphics2D 對象的后續圖形使用這個顏色
graphics.setColor(Color.WHITE);
//填充一個指定的矩形: x - 要填充矩形的 x 坐標; y - 要填充矩形的 y 坐標; width - 要填充矩形的寬度; height - 要填充矩形的高度
graphics.fillRect(0, 0, width, height);
//創建一個 Font 對象: name - 字體名稱; style - Font 的樣式常量; size - Font 的點大小
Font font = null;
font = new Font("", Font.BOLD, fontHeight);
//使 Graphics2D 對象的后續圖形使用此字體
graphics.setFont(font);
graphics.setColor(Color.BLACK);
//繪制指定矩形的邊框, 繪制出的矩形將比構件寬一個也高一個像素
graphics.drawRect(0, 0, width - 1, height - 1);
//隨機產生 15 條干擾線, 使圖像中的認證碼不易被其它程序探測到
Random random = null;
random = new Random();
graphics.setColor(Color.GREEN);
for(int i = 0; i < 30; i++){
int x = random.nextInt(width);
int y = random.nextInt(height);
int x1 = random.nextInt(20);
int y1 = random.nextInt(20);
graphics.drawLine(x, y, x + x1, y + y1);
}
graphics.setColor(Color.BLACK);
for(int i = 0; i < code.length(); i++){
//用隨機產生的顏色將驗證碼繪制到圖像中
// graphics.setColor(Color.BLUE);
graphics.drawString(String.valueOf(code.charAt(i)), (i + 1)* codeX, codeY);
}
return buffImg;
}
}
ValidateColorServlet
@WebServlet("/validateColorServlet")
public class ValidateColorServlet extends HttpServlet {
private int codeCount = 4;
//驗證碼由哪些字符組成
char [] codeSequence = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz23456789".toCharArray();
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//創建 randomCode 對象, 用于保存隨機產生的驗證碼, 以便用戶登錄后進行驗證
StringBuffer randomCode = new StringBuffer();
Random random = new Random();
for(int i = 0; i < codeCount; i++){
//得到隨機產生的驗證碼數字
String strRand = null;
strRand = String.valueOf(codeSequence[random.nextInt(36)]);
randomCode.append(strRand);
}
GenerateCode generateCode = new GenerateCode();
BufferedImage buffImg =generateCode.Generate(randomCode.toString());
request.getSession().setAttribute("CHECK_CODE", randomCode.toString());
//禁止圖像緩存
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
//將圖像輸出到輸出流中
ServletOutputStream sos = null;
sos = response.getOutputStream();
ImageIO.write(buffImg, "jpeg", sos);
sos.close();
}
}
check.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="checkCodeServlet" method="post">
username:<input type="text" name="username">
checkCode:<input type="text" name="check">
<img src="${pageContext.request.contextPath }/validateColorServlet">
<input type="submit" value="Submit">
</form>
</body>
</html>
CheckCodeServlet
package com.neusoft.javaweb.checkcode;
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 CheckCodeServlet
*/
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String strCheckCode = request.getParameter("check");
String checkCode = (String)request.getSession().getAttribute("CHECK_CODE");
if(strCheckCode.equalsIgnoreCase(checkCode)) {
response.sendRedirect("hello.jsp");
}else {
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter pr = response.getWriter();
pr.println("驗證碼錯誤");
}
}
}