1. Session簡(jiǎn)單介紹
在WEB開(kāi)發(fā)中,服務(wù)器可以為每個(gè)瀏覽器用戶創(chuàng)建一個(gè)會(huì)話對(duì)象 ( session對(duì)象),注意:一個(gè)瀏覽器用戶獨(dú)占一個(gè)session對(duì)象(默認(rèn)情況下)。 因此,在需要保存用戶數(shù)據(jù)時(shí),服務(wù)器程序可以把用戶數(shù)據(jù)寫到瀏覽器用戶獨(dú)占的session中,當(dāng)用戶使用瀏覽器訪問(wèn)該web應(yīng)用的其它servlet時(shí),其它servlet可以從用戶的session中取出該用戶的數(shù)據(jù),為用戶服務(wù),從而實(shí)現(xiàn)數(shù)據(jù)在多個(gè)頁(yè)面中的共享。
2. Session和Cookie的主要區(qū)別
- Cookie是把用戶的數(shù)據(jù)寫到用戶的瀏覽器。
- Session技術(shù)把用戶的數(shù)據(jù)寫到用戶獨(dú)占的session中,tomcat服務(wù)器內(nèi)存中。
- Session對(duì)象由服務(wù)器(Tomcat)創(chuàng)建,開(kāi)發(fā)人員可以調(diào)用request對(duì)象的getSession()方法得到session對(duì)象
3. session機(jī)制演示圖


服務(wù)器通過(guò)request對(duì)象的getSession方法創(chuàng)建出session對(duì)象后,會(huì)把session的id號(hào),以cookie的形式回寫給客戶機(jī),這樣,只要客戶機(jī)的瀏覽器不關(guān),再去訪問(wèn)服務(wù)器時(shí),都會(huì)帶著session的id號(hào)去,服務(wù)器發(fā)現(xiàn)客戶機(jī)瀏覽器帶session id過(guò)來(lái)了,就會(huì)使用內(nèi)存中與之對(duì)應(yīng)的session為之服務(wù)。
前臺(tái)頁(yè)面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="session.do">第一次訪問(wèn)session.do</a>
<a href="sessiontest.do">第二次訪問(wèn)sessiontest.do</a>
</body>
</html>
第一次訪問(wèn)
package com.lty.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet(name = "SessionServlet" ,urlPatterns = "/session.do")
public class SessionServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 每一個(gè)session對(duì)象都存在著唯一的ID
HttpSession httpSession = request.getSession();
httpSession.setAttribute("user","zhangsan");
System.out.println(httpSession.getId());
// Tomcat服務(wù)器默默做的一件事
// Cookie cookie = new Cookie("JSESSIONID",httpSession.getId());
// response.addCookie(cookie);
}
}
第二次訪問(wèn)
package com.lty.servlet;
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;
import java.io.IOException;
@WebServlet(name = "SessionTestServlet",urlPatterns = "/sessiontest.do")
public class SessionTestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 獲取第一次服務(wù)器創(chuàng)建給用戶的Session
HttpSession httpSession = request.getSession();
String username = (String)httpSession.getAttribute("user");
System.out.println(username);
System.out.println( httpSession.getId());
}
}

4. Session cookie
session通過(guò)SessionID來(lái)區(qū)分不同的客戶,session是以cookie為基礎(chǔ)的,系統(tǒng)會(huì)創(chuàng)造一個(gè)名為JSESSIONID的輸出cookie ,這稱之為session cookie,以區(qū)別persistent cookies(也就是我們通常所說(shuō)cookie),session cookie是存儲(chǔ)于瀏覽器內(nèi)存中的,并不是寫到硬盤上的, session cookie針對(duì)某一次會(huì)話而言,會(huì)話結(jié)束session cookie也就隨著消失了,而persistent cookie只是存在于客戶端硬盤上的一段文本。
關(guān)閉瀏覽器,只會(huì)使瀏覽器端內(nèi)存里的session cookie消失,但不會(huì)使保存在服務(wù)器端的session對(duì)象消失,同樣也不會(huì)使已經(jīng)保存到硬盤上的持久化cookie消失。
持久化Session cookie
關(guān)閉瀏覽器,一小時(shí)之內(nèi)打開(kāi)瀏覽器,session仍然有效(通過(guò)使用cookie類的setMaxAge(秒)方法設(shè)置持久化的時(shí)效)
package com.lty.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@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("JSESSIONID",httpSession.getId());
cookie.setMaxAge(60*60);// 關(guān)閉瀏覽器,一小時(shí)之內(nèi)打開(kāi)瀏覽器,session仍然有效
}
}
5. HttpSession的生命周期
問(wèn)題:用戶開(kāi)一個(gè)瀏覽器訪問(wèn)一個(gè)網(wǎng)站,服務(wù)器是不是針對(duì)這次會(huì)話創(chuàng)建一個(gè)session?
答:不是的。session的創(chuàng)建時(shí)機(jī)是在程序中第一次去執(zhí)行request.getSession();這個(gè)代碼,服務(wù)器才會(huì)為你創(chuàng)建session。
問(wèn)題:關(guān)閉瀏覽器,會(huì)話結(jié)束,session是不是就銷毀了呢?
答:不是的。session是30分鐘(默認(rèn)30分鐘)沒(méi)人用了才會(huì)死,服務(wù)器會(huì)自動(dòng)摧毀session。
session何時(shí)會(huì)銷毀
(1)調(diào)用invalidate()方法,該方法使HttpSession立即失效
package com.lty.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@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();
}
}
(2)服務(wù)器卸載了當(dāng)前WEB應(yīng)用
(3)超出session過(guò)期時(shí)間
package com.lty.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@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(10);// 單位: 秒
}
}
web.xml文件中也可以修改session的過(guò)期時(shí)間(全局的,所有的session的過(guò)期時(shí)間,若想單獨(dú)設(shè)置還是需要像上面那樣進(jìn)行單獨(dú)session設(shè)置),單位:分鐘
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
6. session小練習(xí)(利用session完成用戶登錄)
java實(shí)體類對(duì)象 User.java
package com.lty.bean;
public class User {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
DB java類(利用list集合來(lái)模擬向數(shù)據(jù)庫(kù)中查詢用戶信息的操作過(guò)程)
package com.lty.bean;
import java.util.ArrayList;
import java.util.List;
public class DB {
public static List<User> list = new ArrayList<User>();
static{
list.add(new User("aaa","123"));
list.add(new User("bbb","123"));
list.add(new User("ccc","123"));
}
public static List<User> getAll(){
return list;
}
}
主頁(yè)面index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
歡迎你:${user.username}
<a href="login.jsp">登錄</a>
<a href="LogoutServlet">退出登錄</a>
<br>
<a href="SessionDemo1">購(gòu)買</a>
<br>
</body>
</html>
登錄頁(yè)面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="LoginServlet" method="post">
用戶名:<input type="text" name="username">
密碼:<input type="password" name="password">
<input type="submit" value="登錄">
</form>
</body>
</html>
購(gòu)買頁(yè)面 SessionDemo1.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
歡迎你:${user.username}
</body>
</html>
后臺(tái)servlet
package com.lty.servlet;
import com.lty.bean.DB;
import com.lty.bean.User;
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 java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
@WebServlet(name = "LoginServlet" , urlPatterns = "/LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String username = request.getParameter("username");
String password = request.getParameter("password");
List<User> list = DB.getAll();
for(User user : list){
// 用戶登錄成功
if(user.getUsername().equals(username) && user.getPassword().equals(password)){
request.getSession().setAttribute("user",user);
response.sendRedirect("index.jsp");
return;
}
}
out.print("用戶名或密碼不正確?。?!");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
package com.lty.servlet;
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 java.io.IOException;
@WebServlet(name = "LogoutServlet" , urlPatterns = "/LogoutServlet")
public class LogoutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 立即徹底銷毀當(dāng)前session對(duì)象
request.getSession().invalidate();
response.sendRedirect("index.jsp");
}
}
package com.lty.servlet;
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 java.io.IOException;
@WebServlet(name = "SessionDemo1" , urlPatterns = "/SessionDemo1")
public class SessionDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("SessionDemo1.jsp").forward(request,response);
}
}
7. 使用Session實(shí)現(xiàn)驗(yàn)證碼
Session的典型案例:一次性驗(yàn)證碼
java工具類 GenerateCode.java(將隨機(jī)生成的由四個(gè)字符組成的字符串用圖片進(jìn)行渲染)
package com.lty.util;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
public class GenerateCode {
// 設(shè)置驗(yàn)證碼圖片的寬度,高度,驗(yàn)證碼的個(gè)數(shù)
private int width = 152;
private int height = 40;
// 驗(yàn)證碼字體的高度
private int fontHeight = 38;
// 驗(yàn)證碼中的單個(gè)字符基線。即:驗(yàn)證碼中的單個(gè)字符位于驗(yàn)證碼圖形左上角的(codeX,codeY)位置處
private int codeX = 25;
private int codeY = 36;
public BufferedImage Generate(String code){
// 定義一個(gè)類型為 BufferedImage.TYPE_INT_BGR 類型的圖像緩存
BufferedImage buffImg = null;
buffImg = new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR);
// 在 buffImg 中創(chuàng)建一個(gè) Graphics2D 圖像
Graphics2D graphics = null;
graphics = buffImg.createGraphics();
// 設(shè)置一個(gè)顏色,使 Graphics2D 對(duì)象的后續(xù)圖形使用這個(gè)顏色
graphics.setColor(Color.WHITE);
// 填充一個(gè)指定的矩形:x - 要填充矩形的 x 坐標(biāo); y - 要填充矩形的 y 坐標(biāo); width - 要填充矩形的寬度; height - 要填充矩形的高度
graphics.fillRect(0,0,width,height);
// 創(chuàng)建一個(gè) Font 對(duì)象:name - 字體名稱; style - Font 的樣式常量; size - Font 的點(diǎn)大小
Font font = null;
font = new Font("",Font.BOLD,fontHeight);
// 使 Graphics2D 對(duì)象的后續(xù)圖形使用此字體
graphics.setFont(font);
graphics.setColor(Color.BLACK);
// 繪制指定矩形的邊框,繪制出的矩形將比構(gòu)件寬一個(gè)也高一個(gè)像素
graphics.drawRect(0,0,width - 1,height - 1);
// 隨機(jī)產(chǎn)生 15 條干擾線,使圖像中的驗(yàn)證碼不易被其它程序探測(cè)到
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++){
// 用隨機(jī)產(chǎn)生的顏色將驗(yàn)證碼繪制到圖像中
graphics.drawString(String.valueOf(code.charAt(i)),(i + 1)* codeX,codeY);
}
return buffImg;
}
}
測(cè)試生成驗(yàn)證碼圖片的java類(將生成的驗(yàn)證碼圖片保存到電腦磁盤中)
package com.lty.util;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
GenerateCode generateCode = new GenerateCode();
BufferedImage bufferedImage = generateCode.Generate("lisi");
// 把圖片保存到磁盤
FileOutputStream fileOutputStream = new FileOutputStream("d:/abc.jpg");
ImageIO.write(bufferedImage,"jpeg",fileOutputStream);
System.out.println("成功");
}
}
登錄頁(yè)面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script>
window.onload = function () {
var img = document.getElementById('code');
img.onclick = function () {
var d = new Date();
// alert(d.getTime());
// 為了讓瀏覽器感覺(jué)到每一次請(qǐng)求的地址不一樣(不會(huì)使用之前緩存的圖片),每一次都會(huì)發(fā)出新的請(qǐng)求,使服務(wù)器生成新的驗(yàn)證碼
img.src = "ValidateColorServlet?time=" + d.getTime();
}
}
</script>
</head>
<body>
<form action="LoginServlet" method="post">
username:<input type="text" name="username">
驗(yàn)證碼:<input type="text" name="check">
<img src="ValidateColorServlet" id="code">
<input type="submit" value="登錄">
</form>
</body>
</html>
后臺(tái)servlet 隨機(jī)生成四位驗(yàn)證碼
package com.lty.servlet;
import com.lty.util.GenerateCode;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@WebServlet(name = "ValidateColorServlet" , urlPatterns = "/ValidateColorServlet")
public class ValidateColorServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// System.out.println("ValidateColorServlet");
//回應(yīng)一張圖片的全部字節(jié) --- 圖片由一堆字節(jié)構(gòu)成 瀏覽器進(jìn)行解析 顯示成圖片
//這張圖片是一個(gè)驗(yàn)證碼圖片
//1.在內(nèi)存中生成這張圖片
//1.1圖片上的文字如何生成?
//隨機(jī)生成一個(gè)4個(gè)字符的字符串(a-z,0-9組成)
char [] codeSequence = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789".toCharArray();
String code = "";
for(int i = 0; i < 4; i++){
Random random = new Random();
int index = random.nextInt(codeSequence.length);
char c = codeSequence[index];
code += c;
}
System.out.println(code);
request.getSession().setAttribute("code",code);
GenerateCode generateCode = new GenerateCode();
BufferedImage bufferedImage = generateCode.Generate(code);
// 向客戶端瀏覽器進(jìn)行輸出
ServletOutputStream outputStream = response.getOutputStream();
ImageIO.write(bufferedImage,"jpeg",outputStream);
}
}
校驗(yàn)用戶輸入的驗(yàn)證碼與隨機(jī)生成的驗(yàn)證碼的一致性
package com.lty.servlet;
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 java.io.IOException;
@WebServlet(name = "LoginServlet" , urlPatterns = "/LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
String checkcode = request.getParameter("check");// 用戶輸入的驗(yàn)證碼
String genCode = (String) request.getSession().getAttribute("code");// 當(dāng)時(shí)隨機(jī)生成的驗(yàn)證碼
if(checkcode.equalsIgnoreCase(genCode)){
response.getWriter().println("驗(yàn)證碼正確");
}else{
response.getWriter().println("驗(yàn)證碼不正確");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}