码迷,mamicode.com
首页 > 其他好文 > 详细

JCaptcha生成计算式验证码

时间:2015-04-30 23:22:56      阅读:425      评论:0      收藏:0      [点我收藏+]

标签:

前两天买了张火车票,令人egg碎的验证已经无力吐槽,试了几次都让我开始怀疑我的IQ是不是适合再从事程序猿的这个”神圣的职业“了。今天分享的是一段比较传统而不失实用的验证,验证的意义想必大家都已知晓。

好了,语言总是苍白无力。直入真题来看代码的实现的吧。

操作环境:
jboss eap 6.2
tomcat也可以,比较懒直接用的jboss。大家有兴趣也可以试试,支持的服务更多,性能更加稳定些。
servlet
麻雀虽小,五脏俱全,做了小例子足以。
JCaptcha
jcaptcha是一个开源的验证码生成控件。一般用于生产图片类验证码,但也支持声音的验证。
JCaptcha的官方网站:http://jcaptcha.sourceforge.net/
另外还有对应的开源社区:http://www.oschina.net/p/jcaptcha/
这里使用的是 jcaptcha-1.0-all.jar ,好像有点老,但是自己maven的nexus里面正好有。

主要分为几个步骤
1.BackgroundGenerator生成图片。包括图片的背景色,大小等样式。
2.生成文字、运算符。包括文字的格式,字体的种类,字体的最小最大样式。
3.利用JCaptcha的一个工具类WordToImage生成带文字的图片。
4.最后则是验证的过程

一、生成图片

package com.tgb.cfl;

import com.octo.captcha.service.captchastore.FastHashMapCaptchaStore;
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;

public class BfferImageCss {

    private static DefaultManageableImageCaptchaService instance=null;
    public static int result;

    /**
     * 单例模式的类用于生成图片
     * @return
     */
    public static ImageCaptchaService getInstance() {
        VerifImage vi= new VerifImage();
        result=vi.getResult();
        if(instance==null){
            instance = new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), vi, 180, 100000, 75000);
        }else{
            instance.setCaptchaEngine(vi);
        }
        return instance;
    }
}

二、设置图片样式、字体形式、操作符形式

package com.tgb.cfl;


import java.awt.*;
import java.util.Random;

import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator.FunkyBackgroundGenerator;
import com.octo.captcha.component.image.color.ColorGenerator;
import com.octo.captcha.component.image.color.RandomRangeColorGenerator;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;
import com.octo.captcha.component.image.textpaster.TextPaster;
import com.octo.captcha.component.image.textpaster.RandomTextPaster;
import com.octo.captcha.component.image.wordtoimage.WordToImage;
import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;
import com.octo.captcha.component.word.wordgenerator.DummyWordGenerator;
import com.octo.captcha.component.word.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import com.octo.captcha.image.gimpy.GimpyFactory;

public class VerifImage extends ListImageCaptchaEngine {
    static{
        System.setProperty("java.awt.headless", "true");
    }
    //壹 贰 叁 肆 伍 陆 柒 捌 玖
    private final static String[] nods={"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
    //一,二,三,四,五,六,七,八,九
    private final static String[] nohs={"零","一","二","三","四","五","六","七","八","九"};
    //0 1 2 3 4 5 6 7 8 9
    private final static String[] noss={"0","1","2","3","4","5","6","7","8","9"};
    // 存放加减乘运算符
    private final static char[] arr = {‘+‘, ‘-‘, ‘ב};
    //汉字加减乘运算符
    private final static char[] arrh={‘加‘,‘减‘,‘乘‘};
    private StringBuffer sb=null;
    private Random random=null;

    private int result;
    public int getResult(){
        return result;
    }
    @Override
    protected void buildInitialFactories() {
        random = new Random();
        sb=new StringBuffer();
        //获取一个随机boolean
        boolean bool=random.nextBoolean();
        //掉用生成运算模式方法
        this.model(bool);
        int len=sb.toString().length();
        WordGenerator wgen=new DummyWordGenerator(sb.toString());
        //设置字体颜色
        RandomRangeColorGenerator cgen = new RandomRangeColorGenerator(new int[]{0, 60}, new int[]{0, 60}, new int[]{0, 60});
        // 文字显示的个数
        TextPaster textPaster = new RandomTextPaster(len, len, cgen, true);
        //设置图片背景颜色
        ColorGenerator colorGenerator = new RandomRangeColorGenerator(new int[]{200, 200}, new int[]{200, 200}, new int[]{200, 200});
        // 图片的大小
        BackgroundGenerator backgroundGenerator = new FunkyBackgroundGenerator(90, 28,colorGenerator);
        // 字体格式
        Font[] fontsList = new Font[]{new Font("宋体", 0, 10)};
        // 文字的大小
        FontGenerator fontGenerator = new RandomFontGenerator(18, 20, fontsList);
        //将文字写入到图片中
        WordToImage wordToImage = new ComposedWordToImage(fontGenerator, backgroundGenerator, textPaster);
        this.addFactory(new GimpyFactory(wgen, wordToImage));

    }
    private void model(boolean bool){
        // 生成随机整数num1
        int num1 = getRandomNum();
        // 生成随机整数num2
        int num2 = getRandomNum();
        //随机产生运算方式
        int operate = random.nextInt(3);
        switch (operate) {
            case 0:
                this.result = num1 + num2;
                break;
            case 1:
                this.result = num1 - num2;
                break;
            case 2:
                this.result = num1 * num2;
                break;
        }
        try{
            //随机生成运算表达试
            if(bool){
                this.getRes(operate,num1,num2);
            }else{
                int r=random.nextInt(3);
                sb.append(getNos(r,num1)+" ");

                r=random.nextInt(2);
                sb.append(getOperate(r,operate)+" ");

                r=random.nextInt(3);
                sb.append(getNos(r,num2));

                sb.append(" = ?");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    //生成运算表达试
    private void getRes(int operate,int num1,int num2){
        int r=random.nextInt(2);
        switch (r){
            case 0:
                r=random.nextInt(3);
                sb.append(getNos(r,num1)+" ");

                r=random.nextInt(2);
                sb.append(getOperate(r,operate)+" ");
                sb.append("?");

                sb.append(" = "+this.result);
                this.result=num2;
                break;
            case 1:
                sb.append("? ");
                r=random.nextInt(2);
                sb.append(getOperate(r,operate)+" ");

                r=random.nextInt(3);
                sb.append(getNos(r,num2));

                sb.append(" = "+this.result);
                this.result=num1;
                break;
        }
    }
    //获取运算数字
    private String getNos(int random,int num) {
        switch (random){
            case 0:
                return nods[num];
            case 1:
                return nohs[num];
            case 2:
                return noss[num];
        }
        return null;
    }
    //获取运算符
    private String getOperate(int random,int num){
        switch (random){
            case 0:
                return String.valueOf(arr[num]);
            case 1:
                return String.valueOf(arrh[num]);
        }
        return null;
    }
    //获取0~9随机数
    private int getRandomNum(){
        int num = random.nextInt(10);
        while (num == 0) {
            num = random.nextInt(10);
        }
        return num;
    }
}

这里主要是为了形成用于计算结果的文字和图片以及一些样式的设定。

三、测试验证码

servlet

package com.tgb.cfl;

import com.octo.captcha.service.CaptchaServiceException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * 用于生产验证码图片的class
 * @author cfl 
 * @date 2015年4月30日
 *
 */
public class VerificationCode extends HttpServlet {
    private static final long serialVersionUID = -11L;

    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        byte[] b = null;

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            //获取session对象
            HttpSession session=request.getSession();

           //获取本次会话的sessionID
            String captchaId = session.getId();
            //生成图片
            BufferedImage challenge = BfferImageCss.getInstance().getImageChallengeForID(captchaId, request.getLocale());

            //将结果保存到session
            session.setAttribute(captchaId+"_vccode",BfferImageCss.result);

            //加密
            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(baos);           

            jpegEncoder.encode(challenge);

        } catch (IllegalArgumentException e) {

            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;

        } catch (CaptchaServiceException e) {

            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;

        }

        b = baos.toByteArray();

        //设置相应的参数,用于显示图片
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream sos = response.getOutputStream();
        sos.write(b);
        sos.flush();
        sos.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

这里是一个简单的servlet用于,虽然是一个简单的servlet,但是也足够完成所需功能。

好了,最后附上效果图一张

技术分享

JCaptcha生成计算式验证码

标签:

原文地址:http://blog.csdn.net/cfl20121314/article/details/45399603

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!