Struts2整合Jcaptcha1.0实现异步验证码

来源:互联网 发布:x连弩升级数据 编辑:程序博客网 时间:2024/04/27 18:12

验证码的英文CAPTCHA 这个词最早是在2000年由卡内基梅隆大学的Luis von Ahn、Manuel Blum、Nicholas J.Hopper以及IBM的John Langford所提出。CAPTCHA 是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机和人的公共全自动程序。这个问题可以由计算机生成并评判,但是必须只有人类才能解答。由于计算机无法解答CAPTCHA的问题,所以回答出问题的用户就可以被认为是人类。

----引自"百度百科"

首先,从sourceforge网站下载 Download jcaptcha-1.0-bin.zip (9.2 MB) 

jCaptcha官方网站是 https://jcaptcha.atlassian.net/wiki/display/general/Home

如果机上装有SVN客户端,还可以下载源代码,SVN地址是: 

https://jcaptcha.svn.sourceforge.net/svnroot/jcaptcha

以上地址从SVN上checkout出整个jcaptcha项目(包括trunk,tags,branch等)100多M,网速慢的比较耗时,建议先浏览仓库,checkout一个tags标签版本即可

当然,如果机上又装mvn,那就可以打包成源代码的jar文件了,方便我们学习,mvn命令是: mvn source:jar


确定环境中包含下列依赖:


其中 jcaptcha依赖于 commons-logging和commons-collections

集成struts2依赖于jcaptcha4struts2

strut2-sitemesh和sitemesh已本博文无关


1,查看jcaptcha4struts2插件配置struts-plugin.xml

<struts><include file="struts-default.xml" /><package name="jcaptcha4struts2-default" extends="struts-default"><result-types><result-type name="captchaImage"class="com.google.code.jcaptcha4struts2.core.actions.support.CaptchaImageResult" /></result-types><interceptors><interceptor name="jcaptchaValidation"class="com.google.code.jcaptcha4struts2.core.interceptors.JCaptchaValidationIntercepter" /><interceptor-stack name="jcaptchaDefaultStack"><interceptor-ref name="defaultStack" /><interceptor-ref name="jcaptchaValidation" /></interceptor-stack></interceptors><action name="jcaptcha_image"class="com.google.code.jcaptcha4struts2.core.actions.JCaptchaImageAction"><result type="captchaImage" /></action></package></struts>


2.单纯使用内置的验证码功能

如果单纯使用jcaptcha4struts2插件提供的验证功能,仅需在页面包含一个<img src=''jcaptcha_image.action" />图片元素就能拿到验证码图片了
而提交表单的时候,要对验证码进行验证,仅需在表单的action中添加jcaptchaValidation拦截器即可

例:index.jsp

[...]<script type="text/javascript">function changeImage() {var jcaptcha_image = document.getElementById("jcaptcha_image");var timestamp = new Date().getTime();jcaptcha_image.src = "ajax_captcha.action?timestamp=" + timestamp;var jcaptcha_input = document.getElementById("txtVerifyCode");jcaptcha_input.value = "";jcaptcha_input.focus();}</script></head><body><div class="form"><form id="register" name="register" method="post"action="user/register">[...]<table width="800px" style="border-collapse:collapse">[...]<tr><td class="label"><label for="verify_code">验证码:</label></td><td class="field"><div class="jcaptcha_image"><!-- 验证码 --><img id="jcaptcha_image"src="jcaptcha_image.action" /></div><!-- 验证码输入框 --> <input name="jCaptchaResponse"type="text" id="txtVerifyCode" class="yzm_input clear-fix" /><div class="text_left"><p class="t1"><span id="vcodeValidMsg">请输入图片中的七个字母。</span><span id="number.info" style="color:red"></span> <a href="javascript:changeImage()">看不清楚?换个图片</a></p></div></td></tr><tr><td> </td><td class="btn-register"><button type="submit"id="btn_register" class="btn-register">同意协议并注册</button></td></tr></table></form></div></body></html>

struts.xml配置文件添加拦截器

<action name="register" class="org.tarena.dang.action.RegisterAction"method="register"><!-- 校验验证码拦截器 --><interceptor-ref name="jcaptchaDefaultStack" /><result name="verify">/user/verify_form.jsp</result></action>



效果如下:

3.自定义验证码

如果jcaptcha4struts2插件内置的验证码无法满足我们的需求,我们需要自己的验证码生成策略

  1. 首先,实现自己的CaptchaEngine
    package com.taobao.utils;import java.awt.Color;import java.awt.Font;import java.awt.image.ImageFilter;import com.jhlabs.image.WaterFilter;import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;import com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator;import com.octo.captcha.component.image.color.RandomListColorGenerator;import com.octo.captcha.component.image.deformation.ImageDeformation;import com.octo.captcha.component.image.deformation.ImageDeformationByFilters;import com.octo.captcha.component.image.fontgenerator.FontGenerator;import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;import com.octo.captcha.component.image.textpaster.MySimpleTextParser;import com.octo.captcha.component.image.textpaster.TextPaster;import com.octo.captcha.component.image.wordtoimage.DeformedComposedWordToImage;import com.octo.captcha.component.image.wordtoimage.WordToImage;import com.octo.captcha.component.word.FileDictionary;import com.octo.captcha.component.word.wordgenerator.ComposeDictionaryWordGenerator;import com.octo.captcha.component.word.wordgenerator.WordGenerator;import com.octo.captcha.engine.image.ListImageCaptchaEngine;import com.octo.captcha.image.gimpy.GimpyFactory;public class MySimpleWaterCaptchaEngine extends ListImageCaptchaEngine{@Overrideprotected void buildInitialFactories() {WaterFilter waterFilter = new WaterFilter();waterFilter.setAmplitude(5d);//振幅waterFilter.setAntialias(true);//锯齿或平滑waterFilter.setPhase(-90);//相位waterFilter.setWavelength(50d);//波长int minWordLength = 4; //最少字符数  int maxWordLength = 5;  //最大字符数int fontSize = 50; //字体大小int imageWidth = 150;  //背景图长度int imageHeight = 50;  //背景图宽度//背景图生成BackgroundGenerator backGround = new UniColorBackgroundGenerator(imageWidth, imageHeight, Color.white);//生成单词WordGenerator dictionnaryWords = new ComposeDictionaryWordGenerator(new FileDictionary("toddlist"));//字体生成FontGenerator font = new RandomFontGenerator(fontSize, fontSize, new Font[] {  new Font("nyala", Font.BOLD, fontSize), new Font("Bell MT", Font.PLAIN, fontSize),  new Font("Credit valley", Font.BOLD, fontSize) });  //单词转化成图片TextPaster randomPaster = new MySimpleTextParser(minWordLength, maxWordLength, new RandomListColorGenerator(new Color[]{Color.black, Color.pink, Color.gray}),true);//backgroundDeformation 背景图变形ImageDeformation backDef = new ImageDeformationByFilters(new ImageFilter[] {});  //textDeformation 字符图层转变形ImageDeformation textDef = new ImageDeformationByFilters(new ImageFilter[] {});  //finalDeformation  最终图片变形ImageDeformation postDef = new ImageDeformationByFilters(new ImageFilter[] {waterFilter});//转化图片WordToImage word2image = new DeformedComposedWordToImage(font, backGround, randomPaster, backDef, textDef,  postDef);  addFactory(new GimpyFactory(dictionnaryWords, word2image));  }}

  2. 由于jcaptcha4struts2插件内置生成的图片文字是从背景的X坐标为background.getHeight()/20 ,  Y轴坐标为background.getWidth()/2开始画图的,所以看上去文字会走动比较大,我们可以自己修改一下,实现自己的验证码文字生成,由于AbstractTextPaster所在包访问权限有所限制,故我这里把实现放在与AbstractTextPaster同一个包内
    /* * JCaptcha, the open source java framework for captcha definition and integration * Copyright (c)  2007 jcaptcha.net. All Rights Reserved. * See the LICENSE.txt file distributed with this package. */package com.octo.captcha.component.image.textpaster;import com.octo.captcha.CaptchaException;import com.octo.captcha.component.image.color.ColorGenerator;import java.awt.*;import java.awt.image.BufferedImage;import java.text.AttributedString;/** * <p/> * Pastes the text at width/20 and height/2 </p> * * @author <a href="mailto:mag@jcaptcha.net">Marc-Antoine Garrigue </a> * @version 1.0 */public class MySimpleTextParser extends AbstractTextPaster {    public MySimpleTextParser(Integer minAcceptedWordLength, Integer maxAcceptedWordLength,                            Color textColor) {        super(minAcceptedWordLength, maxAcceptedWordLength, textColor);    }    public MySimpleTextParser(Integer minAcceptedWordLength, Integer maxAcceptedWordLength,                            ColorGenerator colorGenerator) {        super(minAcceptedWordLength, maxAcceptedWordLength, colorGenerator);    }    public MySimpleTextParser(Integer minAcceptedWordLength, Integer maxAcceptedWordLength,                            ColorGenerator colorGenerator, Boolean manageColorPerGlyph) {        super(minAcceptedWordLength, maxAcceptedWordLength, colorGenerator, manageColorPerGlyph);    }    /**     * Pastes the attributed string on the backround image and return the final image. Implementation must take into     * account the fact that the text must be readable by human and non by programs. Pastes the text at width/20 and     * height/2     *     * @return the final image     *     * @throws com.octo.captcha.CaptchaException     *          if any exception accurs during paste routine.     */    public BufferedImage pasteText(final BufferedImage background,                                   final AttributedString attributedWord) throws CaptchaException {        int x = (background.getWidth()) / 20;        int bgWidth=background.getHeight();        int y = bgWidth-(bgWidth/5);        //创建一个与背景图片同尺寸的图层        BufferedImage out = copyBackground(background);        Graphics2D g2 = pasteBackgroundAndSetTextColor(out, background);        //pie.drawString(attributedWord.getIterator(), x, y);        //pie.dispose();        // convert string into a series of glyphs we can work with        ChangeableAttributedString newAttrString = new ChangeableAttributedString(g2,                attributedWord, 2);        // space out the glyphs with a little kerning        newAttrString.useMinimumSpacing(1);        //newAttrString.useMonospacing(0);        // shift string to a random spot in the output imge        newAttrString.moveTo(x, y);        // now draw each glyph at the appropriate spot on the image.        if (isManageColorPerGlyph())            newAttrString.drawString(g2, getColorGenerator());        else            newAttrString.drawString(g2);        g2.dispose();        return out;    }}

  3. 继承jcaptcha4struts2的JCaptchaImageAction
    package com.taobao.action;import com.google.code.jcaptcha4struts2.core.actions.JCaptchaImageAction;import com.google.code.jcaptcha4struts2.core.beans.JC4S2Config;import com.octo.captcha.service.captchastore.FastHashMapCaptchaStore;import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;import com.taobao.utils.MySimpleWaterCaptchaEngine;public class MyJcaptchaAction extends JCaptchaImageAction {/** *  */private static final long serialVersionUID = 1340725347539598783L;private static MySimpleWaterCaptchaEngine imageCaptchaEngine = null;private static FastHashMapCaptchaStore fastHashMapCaptchaStore = null;private static DefaultManageableImageCaptchaService defaultManageableImageCaptchaService = null;static {imageCaptchaEngine=new MySimpleWaterCaptchaEngine();fastHashMapCaptchaStore = new FastHashMapCaptchaStore();defaultManageableImageCaptchaService=new DefaultManageableImageCaptchaService(fastHashMapCaptchaStore, imageCaptchaEngine, 180, 100000, 75000);JC4S2Config.getInstance().setImageCaptchaService(defaultManageableImageCaptchaService);}@Overridepublic String execute(){return super.execute();}}

  4. 配置页面action
    <package name="ajax-valid" extends="jcaptcha4struts2-default"><action name="ajax_captcha" class="com.taobao.action.MyJcaptchaAction"><interceptor-ref name="jcaptchaDefaultStack" /><result type="captchaImage" /></action></package>

    <tr><td class="label"><label for="verify_code">验证码:</label></td><td class="field"><div class="jcaptcha_image"><!-- 验证吗 --><img id="jcaptcha_image"src="ajax_captcha.action" /></div><!-- 验证码输入框 --> <input name="jCaptchaResponse"type="text" id="txtVerifyCode" class="yzm_input clear-fix" /><div class="text_left"><p class="t1"><span id="vcodeValidMsg">请输入图片中的七个字母。</span><span id="number.info" style="color:red"></span> <a href="javascript:changeImage()">看不清楚?换个图片</a></p></div></td></tr>

效果如下



原创粉丝点击