验证码的英文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已本博文无关
<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>
[...] <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>
<action name="register" class="org.tarena.dang.action.RegisterAction" method="register"> <!-- 校验验证码拦截器 --> <interceptor-ref name="jcaptchaDefaultStack" /> <result name="verify">/user/verify_form.jsp</result> </action>
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{ @Override protected 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)); } }
/* * 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:[email protected]">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; } }
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); } @Override public String execute(){ return super.execute(); } }
<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>
效果如下