Servlet中不可不知的Session技术

JavaEE 专栏收录该内容
43 篇文章 2 订阅

目录

介绍

  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("验证码验证失败!");
        }
    }
}
  • 3
    点赞
  • 0
    评论
  • 6
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

葡萄干是个程序员

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值