Session、Cookie 學習筆記
在開始今天的博文之前首先為自己慶祝一下自己有了三個粉絲,也有了同僚的評論,說實話因為這個開心了好久!哈哈,好了在開始今天的正題之前,首先大家需要了解以下幾點:
a. HTTP 協議是無狀態的協議,WEB 服務器本身不能識別出哪些請求是同一個瀏覽器發出的,瀏覽器的每一次請求都是孤立的;
b. 作為服務器必須能夠采用一種機制來唯一標識一個用戶,同時記錄該用戶的狀態;
c. WEB 應用中的會話是指一個客戶端瀏覽器與 WEB 服務器之間連續發生的一系列請求和響應過程;
d. WEB 應用的會話狀態是指 WEB 服務器與瀏覽器會話過程中產生的狀態信息,借助會話狀態 WEB 服務器能夠把屬於同一會話中的一系列的請求和響應過程關聯起來;
e. Cookie 機制采用的是在客戶端保持 HTTP 狀態信息的方案,在瀏覽器訪問 WEB 服務器的某個資源時,由 WEB 服務器在 HTTP 響應消息頭中附帶傳送給瀏覽器的一個小文本文件,一旦WEB 瀏覽器保存了某個 Cookie,那麽他在以 後每次訪問該 WEB 服務器時,都會在 HTTP 請求頭中將這個 Cookie 回傳給 WEB 服務器
1. Cookie
1). 實現原理:WEB 服務器通過在 HTTP 響應頭消息中增加 Set-Cookie 響應頭字段將 Cookie 消息發送給瀏覽器,瀏覽器則通過在 HTTP 請求消息中增加 Cookie 請求頭字段將 Cookie 回傳給 WEB 服務器
2). 第一次訪問瀏覽器不存在 Cookie,服務器給瀏覽器響應時給其加上 Cookie,第二次請求的時候便會自動加上 Cookie,服務器便會根據此 cookie 信息辨別用戶狀態,以彌補 HTTP 協議的無狀態缺點
1.1 Cookie 應用實例之用戶的自動登錄
a. 用戶登錄後會跳轉到一個歡迎頁面,一段時間之內我們再次訪問歡迎頁面時可以不用登錄,但是過了 Cookie 的保質期我們訪問歡迎頁面的時候就需要去登錄
b. 首先我們寫一個登錄頁面,然後提交請求到 servlet,在 servlet 中判斷 cookie 中是否有值,若沒有值可能是 cookie 失效,可能是第一次訪問,然後將用戶登錄信息保存到 cookie 中;若有值則去判斷該 cookie 中是否有匹配的 cookie,若有則顯示歡迎頁面,否則回到登錄頁面(登錄頁面中只有用戶名,沒有密碼,在實際中我們對密碼需要進行加密處理),演示如下:
e. 代碼如下(我們在 JSP 中模仿 Servlet,沒有單獨去新建 Servlet):
login.jsp
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>Login</title> 5 </head> 6 <body> 7 <form action="welcom.jsp" method="post"> 8 UserName: <input type="text" name="name"><br> 9 <button type="submit">Submit</button> 10 </form> 11 </body> 12 </html>
welcom.jsp
1 <%-- 2 Created by IntelliJ IDEA. 3 User: yin‘zhao 4 Date: 2017/11/15 5 Time: 9:30 6 To change this template use File | Settings | File Templates. 7 --%> 8 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 <html> 10 <head> 11 <title>Welcom</title> 12 </head> 13 <body> 14 <h3> 15 <% 16 /* 17 * 獲取用戶名和cookie,如果用戶名不為空(從登錄頁面而來)則打印歡迎消息 18 * 如果用戶名為空但cookie 不為空,且cookie 的name 為所要求的同樣打印歡迎消息 19 * 如果都為空則重定向到登錄頁面 20 * */ 21 22 String userName = request.getParameter("name"); 23 if (userName != null) { 24 Cookie cookie1 = new Cookie("name", userName); 25 cookie1.setMaxAge(30); 26 response.addCookie(cookie1); 27 } else { 28 // 獲取所有的 Cookie 29 Cookie[] cookies2 = request.getCookies(); 30 if (cookies2 != null && cookies2.length > 0) { 31 for (Cookie cookie : cookies2) { 32 // 尋找相匹配的 Cookie 33 if (cookie.getName().equals("name")) { 34 // 使得 userName 為所匹配的 Cookie 的值 35 userName = cookie.getValue(); 36 } 37 } 38 } 39 } 40 41 if (userName != "" && userName != null) { 42 // 打印歡迎消息 43 out.print("Hello" + userName); 44 } else { 45 // 如果用戶名為空則重定向到登錄頁面 46 response.sendRedirect("login.jsp"); 47 } 48 %> 49 </h3> 50 </body> 51 </html>
1.2 顯示最近瀏覽記錄(只顯示 5 條)
a. 在顯示頁面顯示出商品清單,點擊商品後轉到詳情頁面,然後再次返回到頁面此商品將會顯示到歷史記錄中
b. 如果所瀏覽的是以前所瀏覽過的那麽就需要將此商品更新到最新的記錄中,即最後一個,演示如下
代碼如下(依舊使用 jsp 模仿 servlet)
1 <%-- 2 Created by IntelliJ IDEA. 3 User: yin‘zhao 4 Date: 2017/11/15 5 Time: 8:59 6 To change this template use File | Settings | File Templates. 7 --%> 8 <%-- 9 從 Cookie 中獲取書的信息並顯示,如果 Cookie 的 name 是以 book 開始的就將其顯示到頁面 10 --%> 11 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 12 <html> 13 <head> 14 <title>Cookie</title> 15 </head> 16 <body> 17 <a href="book.jsp?book=javaWeb">JavaWeb</a><br> 18 <a href="book.jsp?book=Java">Java</a><br> 19 <a href="book.jsp?book=Oracle">Oracle</a><br> 20 <a href="book.jsp?book=Mysql">Mysql</a><br> 21 <a href="book.jsp?book=JDBC">JDBC</a><br> 22 <a href="book.jsp?book=C">C</a><br> 23 <a href="book.jsp?book=R">R</a><br> 24 <a href="book.jsp?book=Hibernate">Hibernate</a><br> 25 <a href="book.jsp?book=Ajax">Ajax</a><br> 26 <a href="book.jsp?book=Spring">Spring</a><br> 27 28 <h2> 29 <% 30 Cookie[] cookies = request.getCookies(); 31 for (Cookie cookie : cookies) { 32 if (cookie.getName().startsWith("book")) { 33 out.print(cookie.getValue() + "<br>"); 34 } 35 } 36 %> 37 </h2> 38 </body> 39 </html>
1 <%@ page import="java.util.ArrayList" %> 2 <%@ page import="java.util.List" %> 3 <%-- 4 把書的信息以 Cookie 傳回瀏覽器,如果以 book 開頭的 cookie name 屬性大於 5, 那麽刪除一個,如果新來的book 5 已經存在,那麽將其放到最後,如果不存在則刪除第一個 6 --%> 7 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 8 <html> 9 <head> 10 <title>Book</title> 11 </head> 12 <body> 13 <h3> 14 <% 15 String bookName = request.getParameter("book"); 16 // 存儲相同的 Cookie 17 Cookie tempCookie = null; 18 // 獲得所有的 Cookie 19 Cookie[] cookies = request.getCookies(); 20 // 存儲Cookie 的 name 屬性以 book 開頭的並存儲在 List 中 21 List<Cookie> cookieList = new ArrayList<Cookie>(); 22 23 // 遍歷所有的 Cookie,將所有以 book 開頭的存儲在 List 中,並為 tempCookie 賦值 24 for (Cookie cookie1 : cookies) { 25 if (cookie1.getName().startsWith("book")) { 26 cookieList.add(cookie1); 27 if (cookie1.getValue().equals(bookName)) { 28 tempCookie = cookie1; 29 } 30 } 31 } 32 33 System.out.println(tempCookie); 34 35 // 如果 List 的 size 大於等於 5,且不存在相同的 Cookie 那麽就刪除第一個 36 // 要知道加入新的一個要麽全部不相同且大於 5 刪除第一個,要麽存在相同的刪除相同的 37 // 心得: 最後就是總刪除一個,所以我們可以把刪除的那個單獨為其賦值 38 if (cookieList.size() > 5 && tempCookie == null) { 39 tempCookie = cookieList.get(0); 40 } 41 if (tempCookie != null) { 42 tempCookie.setMaxAge(0); 43 // 另一個不足為提的錯誤是沒有將設置過的Cookie加入到Response中,因為服務器端設置了Cookie,客戶端, 44 // 也就是瀏覽器是不知道的,所以對Cookie的所有修改都需要調用Response的addCookie方法給客戶端響應,“存”回瀏覽器,這樣,瀏覽器才會更改Cookie 集合 45 response.addCookie(tempCookie); 46 } 47 48 // 獲取調用 Servlet 的 Path, 但 JSP 底層就是一個 Servlet,所以會打印文件名 49 // out.print(request.getServletPath()); 50 // 將新傳入的 cookie 返回 51 Cookie cookie = new Cookie("book" + bookName, bookName); 52 response.addCookie(cookie); 53 %> 54 </h3> 55 <h3><%=bookName%> 56 </h3> 57 <a href="index.jsp">Return...</a> 58 </body> 59 </html>
以上便是我所對 cookie 的理解和自己練習的小應用,接下來我們開始講解 session
2. session
1). Session 在 WEB 開發環境下的語義是指一類用來在客戶端與服務器端之間保持狀態的解決方法,有時候 Session 也用來指這中解決方案的存儲結構
2). 如果瀏覽器發一個 session 並沒有帶任何標識,服務器便會新建一個 session 對象,服務器返回響應的時候會以 cookie的方式返回標識頭(JSessionId),下一次請求 cookie 會把這個標識 id 帶回去,就會找到指定的 session,只要瀏覽器不關就會一直在 cookie存取數據
3). Session 通過 sessionId 來區分不同的客戶,session以cookie 或 URL 重寫為基
4). 礎在程序中可以設置 cookie(JSESSIONID)的持久化,保證重啟瀏覽器的不會重新發送
5). HttpSession 的生命周期之創建 Session
a. 瀏覽器訪問服務端的任何一個 JSP,服務器不一定會立即創建一個 HttpSession 對象
b. 若當前 JSP 是瀏覽器訪問當前 WEB 資源的第一個資源且 JSP 的 page 指令的 session 設為 false,那麽服務器就不會為 JSP 創建一個 HttpSession 對象(Page 指令的 session 屬性為 false 是指 JSP 頁面的隱含變量不可用,但可以通過顯示的方法去創建。)
c. 若當前 JSP 不是客戶端訪問的第一個,且其他頁面已經創建了一個 HttpSession’ 對象,則服務器也不會為當前 JSP 頁面創建一個 HttpSession 對象, 而會把和當前頁面會話關聯的那個 HttpSession 對象返回
d. 對於 Servlet 若是第一個訪問的資源,則只有調用了 request.getSession 或 request。getSession(true) 才會創建一個對象
6). HttpSession 的生命周期之銷毀 session
a. 超出 HttpSession 的過期時間,調用 session.setMaxInactiveInterval(5) 設置失效時間,單位為秒
b. 服務器調用 sesion.invalidate() 方法,
c. 服務器卸載了當前 WEB 應用
7). Servlet 中如何獲取 HttpSession 對象
a. request.getsession(boolean) boolean 為false ,表示若沒有和當前JSP 頁面關聯的 HttpSession則返回 null,若有則返回對象;為 true 表示一定返回,若沒有關聯頁面則服務器創建一個,此時的 true 可省略
8). Session 應用案例之購物車
a. 用戶選擇所要購買的商品,並填寫訂單信息後在購買頁面顯示用戶所要購買的物品信息和用戶信息(由於是多個請求跨頁面,所以我們不能將信息存到 request 中)
b. 代碼如下(以下是我自己所寫的代碼,有點煩瑣,代碼註釋中有自己寫代碼過程中所犯的錯誤和更好的解決方案,我這裏就不貼出留給有興趣的自己去實踐):
index.jsp(由於此案例並不是一個請求所以我們再次利用反射使得所有請求利用一個 Servlet 和之前所用到的一樣)
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>FirstPage</title> 5 </head> 6 <body> 7 <h3>請選擇你要購買的書籍</h3> 8 <table cellpadding="10"> 9 <form action="books.do" method="post"> 10 <tr> 11 <th>書名</th> 12 <th>購買</th> 13 </tr> 14 <tr> 15 <td>Oracle</td> 16 <td><input type="checkbox" name="book" value="Oracle"></td> 17 </tr> 18 <tr> 19 <td>Spring</td> 20 <td><input type="checkbox" name="book" value="Spring"></td> 21 </tr> 22 <tr> 23 <td>Mysql</td> 24 <td><input type="checkbox" name="book" value="Mysql"></td> 25 </tr> 26 <tr> 27 <td>SqlServer</td> 28 <td><input type="checkbox" name="book" value="SqlServer"></td> 29 </tr> 30 <tr><td> 31 <button type="submit">Submit</button> 32 </td></tr> 33 </form> 34 </table> 35 </body> 36 </html>
books 方法
1 protected void books(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 2 HttpSession session = request.getSession(); 3 String[] values = request.getParameterValues("book"); 4 5 for (String value : values) { 6 session.setAttribute("book" + value, value); 7 } 8 response.sendRedirect("buyBook.jsp"); 9 }
buyBook.jsp
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>BuyBooks</title> 5 </head> 6 <body> 7 <h3>請輸入您的基本信息</h3> 8 <table cellpadding="10"> 9 <form action="buyBook.do" method="post"> 10 <tr> 11 <td>基本信息</td> 12 </tr> 13 <tr> 14 <td>UserName: </td> 15 <td><input type="text" name="userName"></td> 16 </tr> 17 <tr> 18 <td>Address: </td> 19 <td><input type="text" name="address"></td> 20 </tr> 21 <tr> 22 <td>CardNum: </td> 23 <td><input type="text" name="cardNum"></td> 24 </tr> 25 <tr> 26 <td><button type="submit">Submit</button></td> 27 </tr> 28 </form> 29 </table> 30 </body> 31 </html>
buyBook 方法
1 protected void buyBook(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 2 HttpSession session = request.getSession(); 3 Enumeration<String> enumeration = request.getParameterNames(); 4 5 while(enumeration.hasMoreElements()) { 6 String name = enumeration.nextElement(); 7 session.setAttribute("buy" + name, request.getParameter(name)); 8 } 9 10 response.sendRedirect("SubmitOrder.jsp"); 11 }
SubmitOrder.jsp
1 <%@ page import="java.util.Enumeration" %> 2 <%@ page import="java.util.List" %> 3 <%@ page import="java.util.ArrayList" %><%-- 4 Created by IntelliJ IDEA. 5 User: yin‘zhao 6 Date: 2017/11/16 7 Time: 18:05 8 To change this template use File | Settings | File Templates. 9 --%> 10 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 11 <html> 12 <head> 13 <title>SubmitOrder</title> 14 </head> 15 <body> 16 <h3>訂單信息確認</h3> 17 <h4><% 18 Enumeration<String> enumeration = session.getAttributeNames(); 19 List<String> bookList = new ArrayList<String>(); 20 String userName = null; 21 String address = null; 22 String cardNum = null; 23 24 while (enumeration.hasMoreElements()) { 25 String atrName = enumeration.nextElement(); 26 if (atrName.startsWith("book")) { 27 String atrVal = (String) session.getAttribute(atrName); 28 bookList.add(atrVal); 29 } 30 31 if (atrName.startsWith("buyuser")) { 32 String atrVal = (String) session.getAttribute(atrName); 33 userName = atrVal; 34 } 35 if (atrName.startsWith("buyadd")) { 36 String atrVal = (String) session.getAttribute(atrName); 37 address = atrVal; 38 } 39 if (atrName.startsWith("buycard")) { 40 String atrVal = (String) session.getAttribute(atrName); 41 cardNum = atrVal; 42 } 43 } 44 %></h4> 45 <table cellpadding="10" border="1" cellspacing="0"> 46 <tr> 47 <td>UserName</td> 48 <td><%= userName%> 49 </td> 50 </tr> 51 <tr> 52 <td>Address</td> 53 <td><%= address%> 54 </td> 55 </tr> 56 <tr> 57 <td>CardNum</td> 58 <td><%= cardNum%> 59 </td> 60 </tr> 61 <tr> 62 <td>購買項目</td> 63 <td> 64 <% 65 for (String bookName : bookList) { 66 %> 67 <%= bookName %> 68 <%= "<br><br>"%> 69 <% 70 } 71 %> 72 </td> 73 </tr> 74 </table> 75 </body> 76 </html>
完整 servlet 代碼以及自己的錯誤和不足
1 package com.java.session.cart.servlet; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.HttpServlet; 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 import javax.servlet.http.HttpSession; 8 import java.io.IOException; 9 import java.lang.reflect.InvocationTargetException; 10 import java.lang.reflect.Method; 11 import java.util.ArrayList; 12 import java.util.Enumeration; 13 import java.util.List; 14 15 16 /** 17 * 小結: 18 * 1. 首先對於多選框他們的 name 屬性應該一致,獲取其值的時候直接 getParameterValues(name) 返回一個數組 19 * 將獲得的值直接加入 session 中,不用分開加; 20 * 2. 對於第二個頁面的多個屬性應該考慮到將其封裝為一個類,比如 Customer,然後為 session 賦值的時候 21 * 直接用 getParameter(name) 獲取到,將他們初始化為 customer 對象,將 customer 對象加入 session 22 * 屬性 23 * 3. 第三個頁面獲取 session 屬性的時候就可以直接獲取 customer 對象和第一步的數組,並將其寫到頁面 24 * 25 * 我的錯誤: 26 * 對於多選框的沒有將其 name 屬性設置為一樣的; 27 * 使用 getParameterNames() 方法,誤導自己後面只知道使用 getParameterNames() 方法,很不好; 28 * 沒有很好的用到面向對象的編程思想; 29 */ 30 public class CartServlet extends HttpServlet { 31 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 32 String servletPath = request.getServletPath(); 33 String methodName = servletPath.substring(1).substring(0, servletPath.length() - 4); 34 35 try { 36 Method method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); 37 method.invoke(this, request, response); 38 } catch (NoSuchMethodException e) { 39 e.printStackTrace(); 40 } catch (IllegalAccessException e) { 41 e.printStackTrace(); 42 } catch (InvocationTargetException e) { 43 e.printStackTrace(); 44 } 45 } 46 47 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 48 doPost(request, response); 49 } 50 protected void books(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 51 HttpSession session = request.getSession(); 52 String[] values = request.getParameterValues("book"); 53 54 for (String value : values) { 55 session.setAttribute("book" + value, value); 56 } 57 response.sendRedirect("buyBook.jsp"); 58 } 59 60 protected void buyBook(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 61 HttpSession session = request.getSession(); 62 Enumeration<String> enumeration = request.getParameterNames(); 63 64 while(enumeration.hasMoreElements()) { 65 String name = enumeration.nextElement(); 66 session.setAttribute("buy" + name, request.getParameter(name)); 67 } 68 69 response.sendRedirect("SubmitOrder.jsp"); 70 } 71 }
9). session 典型案例之解決重復提交問題
a. 什麽是重復提交
1). 在表單提交到一個 servlet,而 servlet 又通過請求轉發的方式響應一個 jsp 頁面,此時地址欄裏面還保留著 servlet 的路徑。在響應頁面點擊 “刷新”
2). 在響應頁面沒有到達時重復點擊 “提交按鈕”
3). 點擊返回再點擊提交,也算是重復提交
b. 如何避免重復提交
1). 在表單中做一個標記,提交到 Servlet 時,檢查標記是否存在且是否和預定義的一致,若一致則受理,並銷毀,若不一致或沒有標記則響應消息重復提交
代碼如下:
index.jsp
1 <%@ page import="java.util.Date" %><%-- 2 Created by IntelliJ IDEA. 3 User: yin‘zhao 4 Date: 2017/11/20 5 Time: 14:51 6 To change this template use File | Settings | File Templates. 7 --%> 8 <%-- 9 在此頁面將 token 值存儲在隱藏域和 session 屬性中,提交到 servlet 並在 servlet 中校驗,且校驗成功,然後 10 成功頁面返回再提交,由於有緩存,java 代碼將不會執行,所以 session 屬性域中就不會有值,所以就會出錯 11 --%> 12 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 13 <html> 14 <head> 15 <title>LoginPage</title> 16 </head> 17 <body> 18 <h4><% 19 /*隨表單一塊提交的標識*/ 20 String tokenValue = String.valueOf(new Date().getTime()); 21 /*將此標識存入 session 中*/ 22 session.setAttribute("token", tokenValue); 23 %></h4> 24 <form action="<%=request.getContextPath()%>/tokenServlet" method="post"> 25 <%--將標識放入隱藏表單中,隨表單一塊提交到 servlet,在 servlet 中和 session 域中的標識進行比較 --%> 26 <input type="hidden" name="token" value=<%=tokenValue%>> 27 name: <input type="text" name="name"><br><br> 28 <button type="submit">Submit</button> 29 </form> 30 </body> 31 </html>
TokenServet.java
1 package com.java.token.servlet; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.HttpServlet; 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 import javax.servlet.http.HttpSession; 8 import java.io.IOException; 9 10 /* 11 * 從登錄頁面到這裏提交,校驗是否為重復提交,若是則給出錯誤頁面,若不是則給出正確的響應頁面。 12 * */ 13 public class TokenServlet extends HttpServlet { 14 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 15 HttpSession session = request.getSession(); 16 String tokenValue = request.getParameter("token"); 17 String attribute = String.valueOf(session.getAttribute("token")); 18 19 if (tokenValue != null && tokenValue.equals(attribute)) { 20 // 如果標識一直將其移除,並轉發到成功頁面 21 session.removeAttribute("token"); 22 } else { 23 // 若不一致或不存在結束當前方法並重定向到錯誤頁面 24 response.sendRedirect(request.getContextPath() + "/token.jsp"); 25 return; 26 } 27 28 request.getRequestDispatcher("/success.jsp").forward(request, response); 29 } 30 31 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 32 doPost(request, response); 33 } 34 }
success.jsp
1 <%-- 2 Created by IntelliJ IDEA. 3 User: yin‘zhao 4 Date: 2017/11/20 5 Time: 16:35 6 To change this template use File | Settings | File Templates. 7 --%> 8 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 <html> 10 <head> 11 <title>Success</title> 12 </head> 13 <body> 14 15 <h3>Hello <%= request.getParameter("name")%></h3> 16 </body> 17 </html>
10). 利用 session 完成驗證碼功能
a. 在原表單頁面,生成一個驗證碼圖片,生成圖片的同時將其字符放入到 session 中;
b. 在原表單頁面,定義一個文本域,用於輸入驗證碼
c. 在目標 servlet 中,獲取 session 和表單域中的驗證碼值
d. 比較兩個值是否一致,若一致則受理請求,並井session 屬性清除
e. 若不一致,則直接通過重定向的方式返回原表單頁面,並提示用戶“驗證碼錯誤”
1). 演示如下
2). 代碼如下
ValidateColorServlet.java(用於生成驗證碼,該 Servlet 算是難點吧,其余代碼邏輯和前面的案例差不多)
1 package com.java.token.servlet; 2 3 import javax.imageio.ImageIO; 4 import javax.servlet.ServletException; 5 import javax.servlet.ServletOutputStream; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import java.awt.*; 10 import java.awt.image.BufferedImage; 11 import java.io.IOException; 12 import java.util.Random; 13 14 /** 15 * 產生隨機驗證碼 16 */ 17 public class ValidateColorServlet extends HttpServlet { 18 19 // 定義驗證圖片的寬和高,以及驗證圖片中字符數 20 private int width = 152; 21 private int height = 40; 22 private int codeCount = 6; 23 24 // 驗證字符的高度 25 private int fontHeight = 0; 26 27 // 驗證碼中單個字符基線,即:驗證碼中的單個字符位於驗證碼圖形左上角的 (codeX, codeY)位置處 28 private int codeX = 0; 29 private int codeY = 0; 30 31 // 驗證碼由哪些字符組成 32 char[] codeSequence = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz23456789".toCharArray(); 33 34 // 初始化驗證碼圖形屬性 35 public void init() { 36 fontHeight = height - 2; 37 codeX = width / (codeCount + 2); 38 codeY = height - 4; 39 } 40 41 public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 42 // 定義一個類型為 BufferedImage.TYPE_INT_BGR 類型的圖像緩存 43 BufferedImage buffImg; 44 buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR); 45 46 // 在 buffImg 中創建一個 Graphics2D 圖像 47 Graphics2D graphics2D = buffImg.createGraphics(); 48 49 // 設置一個顏色,是 graphics2D 後續使用這個顏色 50 graphics2D.setColor(Color.white); 51 // 填充一個指定的矩形,x - 要填充矩形的 x 坐標,y - 要填充矩形的 y 坐標,width 要填充矩形的寬,height - 要填充矩形的高 52 graphics2D.fillRect(0, 0, width, height); 53 // 創建一個 font 對象,name 字體名稱,style font 的樣式常量,size font的點大小 54 Font font = new Font("", 1, fontHeight); 55 // Graphics2D 使用此字體 56 graphics2D.setFont(font); 57 58 graphics2D.setColor(Color.black); 59 60 // 繪制指定矩形矩形的邊框,比構建寬和高大一個像素 61 graphics2D.drawRect(0, 0, width - 1, height - 1); 62 63 // 產生幹擾線 64 Random random = new Random(); 65 graphics2D.setColor(Color.cyan); 66 67 for (int i = 0; i < 55; i++) { 68 int x = random.nextInt(width); 69 int y = random.nextInt(height); 70 int x1 = random.nextInt(20); 71 int y1 = random.nextInt(20); 72 graphics2D.drawLine(x, y, x + x1, y + y1); 73 } 74 // 創建 StringBuffer 對象,保存隨機產生的驗證碼 75 StringBuffer stringBuffer = new StringBuffer(); 76 for (int i = 0; i < codeCount; i++) { 77 String randCode = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]); 78 // 把隨機數放入到 StringBuffer 79 stringBuffer.append(randCode); 80 81 // 將字符繪制到圖像 82 graphics2D.setColor(Color.PINK); 83 graphics2D.drawString(randCode, (i + 1) * codeX, codeY); 84 } 85 86 // 將 StringBuffer 存入 session 中 87 request.getSession().setAttribute("CHECK_CODE_KEY", stringBuffer.toString()); 88 89 // 禁止圖像緩存 90 response.setHeader("Pragma", "no-cache"); 91 response.setHeader("Cache-Control", "no-cache"); 92 response.setDateHeader("Expires", 0); 93 // 將圖像輸出到輸出流中 94 ServletOutputStream sos = response.getOutputStream(); 95 ImageIO.write(buffImg, "jpeg", sos); 96 sos.close(); 97 } 98 }
login.jsp
1 <%-- 2 Created by IntelliJ IDEA. 3 User: yin‘zhao 4 Date: 2017/11/20 5 Time: 18:12 6 To change this template use File | Settings | File Templates. 7 --%> 8 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 <html> 10 <head> 11 <title>Login</title> 12 </head> 13 <body> 14 <h3><% 15 String message = String.valueOf(session.getAttribute("message")); 16 if (message.equals("null")) { 17 message = ""; 18 } 19 out.print(message); 20 %></h3> 21 <form action="<%=request.getContextPath()%>/checkCodeServlet" method="post"> 22 Name: <input type="text" name="name"><br><br> 23 Code: <input type="text" name="CHECK_CODE_KEY"><br><br> 24 <img src="<%=request.getContextPath()%>/validateColorServlet"><br><br> 25 <button type="submit">Submit</button> 26 </form> 27 </body> 28 </html>
CheckCodeServlet.java
1 package com.java.token.servlet; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.HttpServlet; 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 import javax.servlet.http.HttpSession; 8 import java.io.IOException; 9 10 /** 11 * Created by shkstart on 2017/11/20. 12 */ 13 public class CheckCodeServlet extends HttpServlet { 14 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 15 HttpSession session = request.getSession(); 16 String sessionAttr = String.valueOf(session.getAttribute("CHECK_CODE_KEY")); 17 System.out.println(sessionAttr); 18 String nameValue = request.getParameter("CHECK_CODE_KEY"); 19 20 if (nameValue != null && nameValue.equalsIgnoreCase(sessionAttr)) { 21 session.removeAttribute("CHECK_CODE_KEY"); 22 } else { 23 session.setAttribute("message", "驗證碼錯誤"); 24 System.out.println(sessionAttr); 25 response.sendRedirect(request.getContextPath() + "/checkCode/login.jsp"); 26 return; 27 } 28 29 request.getRequestDispatcher("/checkCode/success.jsp").forward(request, response); 30 } 31 32 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 33 doPost(request, response); 34 } 35 }
success.jsp
1 <%-- 2 Created by IntelliJ IDEA. 3 User: yin‘zhao 4 Date: 2017/11/20 5 Time: 18:12 6 To change this template use File | Settings | File Templates. 7 --%> 8 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 <html> 10 <head> 11 <title>Success</title> 12 </head> 13 <body> 14 <h3>Hello <%= request.getParameter("name")%></h3> 15 </body> 16 </html>
這些是我前面因為一些事耽擱沒寫的內容,這次補上,有錯誤或者歧義的地方還望大家指出,謝謝!
本周的內容將會盡快補上,還望諒解!
Session、Cookie 學習筆記