专栏首页Java 技术分享Session、Cookie 学习笔记

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>

  这些是我前面因为一些事耽搁没写的内容,这次补上,有错误或者歧义的地方还望大家指出,谢谢!

  本周的内容将会尽快补上,还望谅解!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JSP 学习笔记

    bgZyy
  • Ajax 学习总结

    bgZyy
  • JavaWeb 学习之 JSTL

    bgZyy
  • thinkphp常用配置config

    下载解压 ThinkPHP 3.2.3,在默认的应用 Application(./Application) 中,包含一个默认的模块 Home(./Applica...

    公众号php_pachong
  • jquery横向滚动条

    deepcc
  • 结合ES6谈一下JS里面的find()方法的使用及注意事项

    首先简单的介绍一下ES6是什么,可能很多人还是第一次听说,我们都知道H5是html的新一代的标准,同样,ES6是javascript的新一代标准,全称是ECMA...

    何处锦绣不灰堆
  • 日常开发技巧:在远程机器上直接使用adb

    嵌入式开发中,开发工作是在远程服务器上进行的。当需要adb推送一个文件到开发板时,则需要重新在本地机器中找到该文件,再执行命令。这样的操作比较麻烦。

    zqb_all
  • ajaxFileUpload文件

    从网上下了个ajaxfileupload的文件,结果不支持ie,又出现各种问题,上网查了,修改了可以支持各种浏览器。

    Dylan Liu
  • 结构型模式:桥接模式

    姓名 :桥接模式 英文名 :Bridge Pattern 价值观 :解耦靠我 个人介绍 : Decouple an abstraction from its i...

    LieBrother
  • WPF下可编辑Header的Tab控件实现

    介绍 有这样一个需求,当用户双击Tab控件Header区域时, 希望可以直接编辑。对于WPF控件,提供一个ControlTemplate在加上一些Trigger...

    葡萄城控件

扫码关注云+社区

领取腾讯云代金券