您的位置:首页 > 编程语言 > Java开发

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

2013-02-06 13:35 323 查看
验证码的英文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插件内置的验证码无法满足我们的需求,我们需要自己的验证码生成策略

首先,实现自己的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{

@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;  //背景图宽度

//背景
4000
图生成
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));
}

}


由于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;
}
}


继承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);
}

@Override
public String execute(){
return super.execute();
}
}


配置页面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>


效果如下

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jcatpcha strut2 验证码