http://akiraly.github.io/cage/index.html


Cage小巧,好用。这里在官方基础例子基础上做了扩展:


package com.lavasoft.ntv.web.common;
import com.github.cage.IGenerator;
import java.util.Random;
/**
 * 验证码生成器
 *
 * @author leizhimin 14-5-5 下午2:42
 */
public class MyTokenGenerator implements IGenerator<String> {
    private int length = 4;
    private String charsetdir = "23456789abcdefghigkmnpqrstuvwxyzABCDEFGHIGKLMNPQRSTUVWXYZ";
    private static final Random r = new Random();
    public MyTokenGenerator() {
    }
    public MyTokenGenerator(int length, String charsetdir) {
        this.length = length;
        this.charsetdir = charsetdir;
    }
    @Override
    public String next() {
        StringBuffer sb = new StringBuffer();
        int len = charsetdir.length();
        for (int i = 0; i < length; i++) {
            sb.append(charsetdir.charAt(r.nextInt(len - 1)));
        }
        return sb.toString();
    }
    public static void main(String[] args) {
        MyTokenGenerator t = new MyTokenGenerator();
        for (int i = 0; i < 100; i++) {
            System.out.println(t.next());
        }
    }
}


package com.lavasoft.ntv.web.servlet;
import com.github.cage.Cage;
import com.lavasoft.ntv.web.common.MyTokenGenerator;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class CaptchaServlet extends HttpServlet {
    private static final long serialVersionUID = 1490947492185481844L;
    private static final Cage cage = new Cage(null,null,null,null,null, new MyTokenGenerator(),null);
    /**
     * Generates a captcha token and stores it in the session.
     *
     * @param session where to store the captcha.
     */
    public static void generateToken(HttpSession session) {
        String token = cage.getTokenGenerator().next();
        session.setAttribute("captchaToken", token);
        markTokenUsed(session, false);
    }
    /**
     * Used to retrieve previously stored captcha token from session.
     *
     * @param session where the token is possibly stored.
     * @return token or null if there was none
     */
    public static String getToken(HttpSession session) {
        Object val = session.getAttribute("captchaToken");
        return val != null ? val.toString() : null;
    }
    /**
     * Marks token as used/unused for p_w_picpath generation.
     *
     * @param session where the token usage flag is possibly stored.
     * @param used    false if the token is not yet used for p_w_picpath generation
     */
    protected static void markTokenUsed(HttpSession session, boolean used) {
        session.setAttribute("captchaTokenUsed", used);
    }
    /**
     * Checks if the token was used/unused for p_w_picpath generation.
     *
     * @param session where the token usage flag is possibly stored.
     * @return true if the token was marked as unused in the session
     */
    protected static boolean isTokenUsed(HttpSession session) {
        return !Boolean.FALSE.equals(session.getAttribute("captchaTokenUsed"));
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        HttpSession session = req.getSession(false);
        String token = session != null ? getToken(session) : null;
        if (token == null || isTokenUsed(session)) {
            resp.sendError(HttpServletResponse.SC_NOT_FOUND,"Captcha not found.");
            return;
        }
        setResponseHeaders(resp);
        markTokenUsed(session, true);
        cage.draw(token, resp.getOutputStream());
    }
    /**
     * Helper method, disables HTTP caching.
     *
     * @param resp response object to be modified
     */
    protected void setResponseHeaders(HttpServletResponse resp) {
        resp.setContentType("p_w_picpath/" + cage.getFormat());
        resp.setHeader("Cache-Control", "no-cache, no-store");
        resp.setHeader("Pragma", "no-cache");
        long time = System.currentTimeMillis();
        resp.setDateHeader("Last-Modified", time);
        resp.setDateHeader("Date", time);
        resp.setDateHeader("Expires", time);
    }
}
<%--
  Created by IntelliJ IDEA.
  User: leizhimin 14-5-5 下午12:18
--%>
<%@page import="com.lavasoft.ntv.web.servlet.CaptchaServlet"%><%@
        page contentType="text/html" pageEncoding="UTF-8"%><%
    boolean showGoodResult;
    boolean showBadResult;
    if ("POST".equals(request.getMethod())) {
        String sessionToken = CaptchaServlet.getToken(session);
        String requestToken = request.getParameter("captcha");
        showGoodResult = sessionToken != null && sessionToken.equals(requestToken);
        showBadResult = !showGoodResult;
    } else {
        showGoodResult = showBadResult = false;
    }
    CaptchaServlet.generateToken(session);
%><!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8" />
    <title>Captcha Reader</title>
</head>
<body>
<%  if (showGoodResult) {%>
<h1 style="color: green;">Your kung fu is good!</h1>
<%  } else if (showBadResult) {%>
<h1 style="color: red;">This is not right. Try again!</h1>
<%  } %>
<p>Type in the word seen on the picture</p>
<form action="" method="post">
    <input name="captcha" type="text" autocomplete="off" />
    <input type="submit" />
</form>
<img alt="captcha p_w_picpath" src="/ntv/captcha" width="120px" height="30px"/>
</body>
</html>


<servlet>
    <servlet-name>captcha</servlet-name>
    <servlet-class>com.lavasoft.ntv.web.servlet.CaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>captcha</servlet-name>
    <url-pattern>/captcha</url-pattern>
</servlet-mapping>


访问页面:


wKioL1NnS2_T5q1RAADnNYpJ3h4765.jpg