Servlet中不可不知的Session技术
目录
介绍
Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的Session对象,由于Session为用户浏览器独享,所以用户在访问服务器的Web资源时,可以把各自的数据放在各自的Session中,当用户再去访问服务器中的其它Web资源时,其它Web资源再从用户各自的Session中取出数据为用户服务。
在Web开发中,服务器可以为每个用户浏览器创建一个会话对象(Session对象),注意:一个浏览器独占一个Session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。
Session和Cookie的主要区别
- Cookie是把用户的数据写给用户的浏览器;
- Session技术把用户的数据写到用户独占的session中(即保存在服务器端)。
Session的创建
在一次会话中,服务器首次需要针对该会话操作session时(在Java Web中即request.getSession(),在PHP中即session_start()),服务器才创建session,而不是用户首次访问服务器的某个网站后就立刻创建session的。
参考:
session什么时候被创建 http://blog.sina.com.cn/s/blog_89a6f5b001010gy9.html
session的创建和时间设置 http://blog.csdn.net/w8998036/article/details/51026966
php创建session的方法实例详解 http://www.jb51.net/article/60397.htm
Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。如:
HttpSession session = request.getSession();
使用过程中,没有向getSession方法传递参数,则表示session未创建的情况下先创建session后再返回session对象,如果session已被创建则直接返回session对象。getSession方法存在对象的重载方法,接收一个布尔类型的参数。如:
HttpSession session = request.getSession(false);
getSession(false) 则表示不管session有没有被创建,都不再创建session;getSession(true) 则强制创建session。
Session的销毁
在Java中,默认session在30分钟之内未被使用,服务器就会将session销毁,不管用户浏览器此时有没有关闭。即便用户关闭了浏览器,结束了当前会话,session也不会立即销毁,直到默认时效内session未被使用。
可以通过Web应用的配置文件web.xml,配置session的有效时间,如这里设置为10分钟:
<session-config>
<session-timeout>10</session-timeout>
</session-config>
手动销毁session,则调用session对象的方法,如:
session.invalidate();
Session的实现原理
用户打开浏览器访问服务器的某一应用资源后,如 ServletDemo(用户向服务器的一个Servlet发起了请求)。在该Servlet中服务器调用:
HttpSession session = request.getSession();
则服务器将会判断针对当次会话是否创建了Session,实际上在创建Session的过程中即服务器为该会话生成了一个唯一的标识,我们称之为Session ID,与此同时,请求响应将返回保存了Session ID的Cookie信息。
该Cookie的名称为JSESSIONID
(在PHP中则为PHPSESSID
),默认当浏览器关闭时该Cookie将被销毁。
浏览器端通过获取到该Cookie信息后,用户下次再发起请求时(可以请求与上一次不同的Web资源),则将携带Cookie信息到服务器,服务器通过该Cookie就可以根据Session ID得知当前会话保存的Session。上次请求操作保存在session中的信息,在下次请求操作也同样可以读取到session中保存的信息。
解决浏览器关闭后就立即丢失Session ID的问题
根据Session实现原理,我们可以知道,在默认情况下,当我们关闭浏览器后保存Session ID的Cookie也将被销毁,即我们再次打开浏览器发送相同请求,获得到的Session对象也不再与之前相同。
需要注意的是,关闭浏览器后服务器存储的Session不一定就被销毁了,服务器存储的Session是在一定时间内未被操作,服务器才会将其销毁。这里关闭浏览器之后无法再使用上次Session的原因,在于我们丢失了Session ID(保存Cookie的Session ID默认在浏览器关闭时销毁)。
那么解决这样的问题,我们只需要延长保存Session ID的Cookie的有效期限即可。如:
//=========== 解决浏览器关闭后就立即丢失Session ID的问题(延长保存Session ID的Cookie的有效期,默认没有设置该Cookie的有效期,即浏览器关闭则该Cookie被销毁) ============
String sessionId = session.getId();
Cookie cookie = new Cookie("JSESSIONID", sessionId);
cookie.setPath("/day07/"); // path的值需要与原来的一致才行
cookie.setMaxAge(30 * 60); // 设置为30分钟内有效
response.addCookie(cookie);
//=========== 解决浏览器关闭后就立即丢失Session ID的问题 ============
浏览器禁用Cookie后如何使用Session技术?
从Session的实现原理中,我们可以发现Session的实现需要依赖于Cookie,那么当用户浏览器禁用了Cookie后又该如何使用Session技术呢?
Session的实现原理最基本的是要求用户在每次请求时发送保存有Session ID的信息(如发送保存有Session ID的Cookie)。禁用Cookie后,我们可以为页面中每条请求增加一个参数,用于发送Session ID的值。这样,服务器获取到Session ID后就可以获取到用户独占的Session,为用户服务。
在Java中,通过request对象的getSession方法获取session对象,getSession方法会先判断请求是否发送了含有Session ID的Cookie过来,如果没有,则会判断请求中是否发送了保存Session ID的参数过来。这两种情况下都未能获取到Session ID的话,服务器则判定还未替当前用户创建独占的session,并为用户进行创建。
示例:
WelcomeServlet.java
package com.wm103.session;
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;
/**
* Created by DreamBoy on 2017/5/2.
*/
@WebServlet(name = "WelcomeServlet", urlPatterns = {"/WelcomeServlet"})
public class WelcomeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getSession();
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String url1 = response.encodeURL("/day07/SessionDemo1"); // 通过encodeURL方法为该请求增加Session ID的参数;如前面getSession方法是通过Cookie获取到Session ID的,则这里不会增加Session ID这个参数,因为服务器可以判断用户浏览器未禁用Cookie。如果是首次创建Session同样也会添加Session ID参数。
String url2 = response.encodeURL("/day07/SessionDemo2");
out.print("<a href='" + url1 + "'>购买</a> ");
out.print("<a href='" + url2 + "'>结账</a>");
}
}
注:通过repsonse对象的encodeURL方法为该请求增加Session ID的参数;如前面getSession方法是通过Cookie获取到Session ID的,则这里不会增加Session ID这个参数,因为服务器可以判断用户浏览器未禁用Cookie。如果是首次创建Session同样也会添加Session ID参数。
SessionDemo1.java
package com.wm103.session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
/**
* Created by DreamBoy on 2017/5/1.
*/
@WebServlet(name = "SessionDemo1", urlPatterns = {"/SessionDemo1"})
public class SessionDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.setAttribute("name", "笔记本");
}
}
ServletDemo2.java
package com.wm103.session;
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;
/**
* Created by DreamBoy on 2017/5/1.
*/
@WebServlet(name = "SessionDemo2", urlPatterns = {"/SessionDemo2"})
public class SessionDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
HttpSession session = request.getSession();
response.getWriter().write((String) session.getAttribute("name"));
}
}
示例效果(这里演示的是未禁用Cookie的情况下的使用效果):
- 用户首次访问时,服务器创建Session,此时页面中所有请求的链接均被加上Session ID参数值。
- 用户点击购买后,返回首页,刷新。此时服务器将接收到浏览器端的Cookie,判定用户浏览器未禁用Cookie,则未向页面中的所有请求链接添加Session ID参数值。
- 用户点击结账,查看购买的商品
Session案例
用session实现简单的购物车效果
将购买后的商品保存在session中,显示购物车页面时,从session中取出所有购买后的商品。
显示商品列表 ListBookServlet.java
package com.wm103.shopping;
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.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Created by DreamBoy on 2017/5/2.
*/
@WebServlet(name = "ListBookServlet", urlPatterns = {"/ListBookServlet"})
public class ListBookServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// 输出网站所有商品
out.print("<div style='margin: 20px 50px; padding: 10px 30px; border: 1px solid #eee; box-shadow: 0 2px 2px #ede'>");
out.write("<h3>本网站有如下商品:</h3>");
out.print("<ul>");
Map<String, Book> map = Db.getAll();
for (Map.Entry<String, Book> entry: map.entrySet()) {
Book book = entry.getValue();
out.print("<li style='line-height: 2'>" + book.getName() + " <a href='/day07/BuyServlet?id=" + book.getId() + "' target='_blank'>购买</a></li>");
}
out.print("</ul>");
out.print("</div>");
}
}
class Db {
private static Map<String, Book> map = new LinkedHashMap<>();
static { // 静态代码块
map.put("1", new Book("1", "JavaWeb开发", "007号", "一本关于JavaWeb开发的书"));
map.put("2", new Book("2", "JDBC开发", "008号", "一本关于JDBC开发的书"));
map.put("3", new Book("3", "Spring开发", "009号", "一本关于Spring开发的书"));
map.put("4", new Book("4", "Struts开发", "010号", "一本关于Struts开发的书"));
map.put("5", new Book("5", "Android开发", "011号", "一本关于Android开发的书"));
}
public static Map<String, Book> getAll() {
return map;
}
}
class Book implements Serializable {
private String id;
private String name;
private String author;
private String description;
public Book() {
}
public Book(String id, String name, String author, String description) {
this.id = id;
this.name = name;
this.author = author;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
处理购买请求 BuyServlet.java
package com.wm103.shopping;
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;
import java.util.ArrayList;
import java.util.List;
/**
* Created by DreamBoy on 2017/5/2.
*/
@WebServlet(name = "BuyServlet", urlPatterns = {"/BuyServlet"})
public class BuyServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String id = request.getParameter("id");
Book book = Db.getAll().get(id);
HttpSession session = request.getSession();
// 手工以Cookie形式发SessionId,以解决关闭浏览器后,重新打开浏览器上次购买的东西还在
// 从session中得到用户用于保存所有书的集合(购物车)
List list = (List) session.getAttribute("list");
if(list == null) {
list = new ArrayList<>();
}
list.add(0, book);
session.setAttribute("list", list);
//response.sendRedirect("/day07/ListCartServlet");
response.sendRedirect(request.getContextPath() + "/ListCartServlet");
}
}
显示购物车页面 ListCartServlet.java
package com.wm103.shopping;
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;
import java.io.PrintWriter;
import java.util.List;
/**
* Created by DreamBoy on 2017/5/2.
*/
/**
* 显示用户购买的商品
*/
@WebServlet(name = "ListCartServlet", urlPatterns = {"/ListCartServlet"})
public class ListCartServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession(false);
if(session == null) {
out.write("您还没有购买任何商品!" + "<a href='/day07/ListBookServlet'>前往购买</a>");
return;
}
List<Book> list = (List) session.getAttribute("list");
out.print("<div style='margin: 20px 50px; padding: 10px 30px; border: 1px solid #eee; box-shadow: 0 2px 2px #ede'>");
out.write("<h3>您购买了如下商品:</h3>");
out.print("<ul>");
for (Book book: list) {
out.print("<li style='line-height: 2'>" + book.getName() + "</li>");
}
out.print("</ul>");
out.print("</div>");
}
}
利用session完成用户登录功能
登录页面 login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form action="/day07/LoginServlet" method="post">
<label>用户名:</label><input type="text" name="username"><br/>
<label>密 码:</label><input type="password" name="password"><br/>
<input type="submit" value="登录">
</form>
</body>
</html>
处理登录请求 LoginServlet.java
package com.wm103.login;
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;
import java.io.PrintWriter;
import java.util.List;
/**
* Created by DreamBoy on 2017/5/2.
*/
@WebServlet(name = "LoginServlet", urlPatterns = {"/LoginServlet"})
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
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)) {
HttpSession session = request.getSession();
session.setAttribute("user", user); // 登录成功,向session存入一个登录标记
response.sendRedirect(request.getContextPath() + "/index.jsp");
return;
}
}
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("用户名或密码错误!");
}
}
User.java
package com.wm103.login;
/**
* Created by DreamBoy on 2017/5/2.
*/
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
package com.wm103.login;
import java.util.ArrayList;
import java.util.List;
/**
* Created by DreamBoy on 2017/5/2.
*/
public class DB {
public static List<User> list = new ArrayList<>();
static {
list.add(new User("aaa", "123"));
list.add(new User("bbb", "123"));
list.add(new User("ccc", "123"));
}
public static List getAll() {
return list;
}
}
登录成功后跳转首页 index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
欢迎您,${user.username}! <a href="/day07/LogoutServlet">退出登录</a>
</body>
</html>
退出登录 LogoutServlet.java
package com.wm103.login;
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;
/**
* Created by DreamBoy on 2017/5/2.
*/
/**
* 用户注销
*/
@WebServlet(name = "LogoutServlet", urlPatterns = {"/LogoutServlet"})
public class LogoutServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false);
if(session == null) {
response.sendRedirect(request.getContextPath() + "/index.jsp");
return;
}
session.removeAttribute("user");
response.sendRedirect(request.getContextPath() + "/login.html");
}
}
服务器端session防表单重复提交
- 表单页面由servlet程序生成,servlet为每次产生的表单页面分配一个唯一的随机标识号,并在form表单的一个隐藏字段中设置这个标识号,同时在当前用户的Session域中保存这个标识号。
- 当用户提交form表单时,负责处理表单提交的servlet得到表单提交的标识号,并与session中存储的标识号比较,如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
- 在下列情况下,服务器程序将拒绝用户提交的表单请求:
- 存储Session域中的表单标识号与表单提交的标识号不同
- 当前用户的Session中不存在表单标识号
- 用户提交的表单数据中没有标识号字段
处理生成随机标识号的Servlet FormSerlvet.java
package com.wm103.form;
import sun.misc.BASE64Encoder;
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.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
/**
* Created by DreamBoy on 2017/5/2.
*/
@WebServlet(name = "FormServlet", urlPatterns = {"/FormServlet"})
public class FormServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 产生随机数(表单号)
TokenProcessor tp = TokenProcessor.getInstance();
String token = tp.generateToken();
request.getSession().setAttribute("token", token);
request.getRequestDispatcher("/form.jsp").forward(request, response);
}
}
class TokenProcessor {
/*
* 1. 把构造方法私有
* 2. 自己创建一个
* 3. 对外暴露一个方法:允许获取上面创建的对象
*/
private TokenProcessor() {}
private static final TokenProcessor instance = new TokenProcessor();
public static TokenProcessor getInstance() {
return instance;
}
public String generateToken() {
String token = System.currentTimeMillis() + new Random().nextInt() + "";
try {
MessageDigest md = MessageDigest.getInstance("md5"); // 消息摘要
byte[] md5 = md.digest(token.getBytes()); // 128位,16字节
// base64编码
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
显示form表单的页面 form.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>防止表单重复提交</title>
</head>
<body>
<form action="/day07/DoFormServlet" method="post">
<input type="hidden" name="token" value="${token}">
<label>用户名:</label><input type="text" name="username"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
处理表单请求 DoFormServlet.java
package com.wm103.form;
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;
/**
* Created by DreamBoy on 2017/5/2.
*/
/**
* 处理表单提交请求
*/
@WebServlet(name = "DoFormServlet", urlPatterns = {"/DoFormServlet"})
public class DoFormServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*String username = request.getParameter("username");
// 模拟网络延迟
try {
Thread.sleep(1000*3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("向数据库中注册用户——" + username);*/
boolean b = isTokenValid(request);
if(!b) {
System.out.println("请不要重复提交表单!");
return;
}
request.getSession().removeAttribute("token");
String username = request.getParameter("username");
System.out.println("向数据库中注册用户——" + username);
}
/**
* 判断表单号是否有效
* @param request
* @return
*/
private boolean isTokenValid(HttpServletRequest request) {
String clientToken = request.getParameter("token");
if (clientToken == null || clientToken.equals("")) {
return false;
}
HttpSession session = request.getSession(false);
if (session == null) {
return false;
}
String serverToken = (String) session.getAttribute("token");
return serverToken != null && clientToken.equals(serverToken);
}
}
利用session校验图片验证码
生成验证码图片后,并用session保存验证码的内容用于校验下次用户输入提交的验证码是否正确。
生成图片验证码 ImageServlet.java
package com.wm103.checkcode;
import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/**
* Created by DreamBoy on 2017/4/28.
*/
/**
* 输出一张随机图片(图片验证码)
*/
@WebServlet(name = "ImageServlet", urlPatterns = {"/ImageServlet"})
public class ImageServlet extends HttpServlet {
public static final int WIDTH = 120;
public static final int HEIGHT = 50;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
// 1. 设置背景色
this.setBackground(g);
// 2. 设置边框
this.setBorder(g);
// 3. 画干扰线
this.drawRandomLine(g);
// 4. 写随机数
String random = this.drawRandomNum((Graphics2D) g);
request.getSession().setAttribute("checkcode", random);
// 5. 图片写给浏览器
response.setContentType("image/jpeg");
// 控制浏览器不要缓存图片
response.setDateHeader("expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
ImageIO.write(image, "jpg", response.getOutputStream());
}
private void setBackground(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
private void setBorder(Graphics g) {
g.setColor(Color.BLUE);
g.drawRect(1, 1, WIDTH - 2, HEIGHT - 2);
}
private void drawRandomLine(Graphics g) {
g.setColor(Color.GREEN);
for(int i = 0; i < 5; i++) {
int x1 = new Random().nextInt(WIDTH);
int y1 = new Random().nextInt(HEIGHT);
int x2 = new Random().nextInt(WIDTH);
int y2 = new Random().nextInt(HEIGHT);
g.drawLine(x1, y1, x2, y2);
}
}
private String drawRandomNum(Graphics2D g) {
int fontSize = 20;
g.setColor(Color.RED);
g.setFont(new Font("宋体", Font.BOLD, fontSize));
String base = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789";
int fontNum = 4;
int y = 32;
int x = 18; String ch;
StringBuffer sb = new StringBuffer();
for(int i = 0; i < fontNum; i++) {
int degree = new Random().nextInt() % 30;
double radian = degree * Math.PI / 180; // 弧度
g.rotate(radian, x, y); // 设置旋转的弧度
ch = base.charAt(new Random().nextInt(base.length())) + "";
sb.append(ch);
g.drawString(ch, x, y);
g.rotate(-radian, x, y);
x += 25;
}
return sb.toString();
}
}
使用图片验证码页面 register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
<form action="/day07/RegisterServlet" method="post">
<p><label>用户名:</label><input type="text" name="username"></p>
<p><label>密 码:</label><input type="password" name="password"></p>
<p><label>验证码:</label><input type="text" name="checkcode">
<img style="cursor:pointer;" src="/day07/ImageServlet" alt="换一张" onclick="this.src = '/day07/ImageServlet?' + new Date().getTime()"></p>
<input type="submit" value="注册">
</form>
</body>
</html>
处理注册请求,这里只校验填写的验证码是否正确 RegisterServlet.java
package com.wm103.checkcode;
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;
/**
* Created by DreamBoy on 2017/5/2.
*/
@WebServlet(name = "RegisterServlet", urlPatterns = {"/RegisterServlet"})
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// request.setCharacterEncoding("UTF-8"); // 如果是中文验证码则需要处理中文编码的问题
// 处理注册请求之前,校验验证码是否有效
String c_checkcode = request.getParameter("checkcode");
String s_checkcode = (String) request.getSession().getAttribute("checkcode");
System.out.println(c_checkcode);
System.out.println(s_checkcode);
if(c_checkcode != null && s_checkcode != null && c_checkcode.toLowerCase().equals(s_checkcode.toLowerCase())) {
System.out.println("处理注册请求!");
} else {
System.out.println("验证码验证失败!");
}
}
}