In this article, i used Spring + Wicket + Kaptcha library to generate captcha image dynamically.
1) Create a Spring xml file to load the Kaptcha class into captchaProducer bean
<bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha"> <property name="config"> <bean class="com.google.code.kaptcha.util.Config"> <constructor-arg type="java.util.Properties" value="null"> </constructor-arg> </bean> </property> </bean>
2) Create a CaptchaImage class which extends Wicket’s NonCachingImage and using DynamicImageResource class to generate the captcha image dynamically.
P.S SpringContextLocator is my custom class to locate the Spring’s bean.
public class CaptchaImage extends NonCachingImage{ private static final String CAPTCHA_PRODUCER = "captchaProducer"; //private DefaultKaptcha captchaProducer; public CaptchaImage (String id){ super(id); setImageResource(new DynamicImageResource(){ public byte[] getImageData(){ ByteArrayOutputStream os = new ByteArrayOutputStream(); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os); try{ BufferedImage bi = getImageCaptchaService(); encoder.encode(bi); return os.toByteArray(); }catch(Exception e){ throw new RuntimeException(e); } }; private BufferedImage getImageCaptchaService(){ Request request = RequestCycle.get().getRequest(); HttpServletRequest httpRequest = ((WebRequest) request).getHttpServletRequest(); DefaultKaptcha captchaProducer = (DefaultKaptcha)SpringContextLocator.getInstance().getSpringContext().getBean(CAPTCHA_PRODUCER); String capText = captchaProducer.createText(); // store the text in the session httpRequest.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, capText); // create the image with the text BufferedImage bi = captchaProducer.createImage(capText); return bi; } }); } }
3) Create a custom CaptchaValidator class which use to validate the Kaptcha generated code.
public class CaptchaValidator extends AbstractValidator { private static final long serialVersionUID = 1L; private String INVALID_CODE = "captcha.invalid"; public void onValidate(IValidatable validatable) { String kaptchaReceived = (String)validatable.getValue(); Request request = RequestCycle.get().getRequest(); HttpServletRequest httpRequest = ((WebRequest) request).getHttpServletRequest(); String kaptchaExpected = (String)httpRequest.getSession().getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY); if (kaptchaReceived == null || !kaptchaReceived.equalsIgnoreCase(kaptchaExpected)) { error(validatable); } } @Override protected String resourceKey(){ return INVALID_CODE; } }
4) Here is the wicket html file
<a wicket:id="link"><img wicket:id="kaptchaImage" /></a> <br> <input type="text" wicket:id="captcha" >
5) Wicket implementation code
TextField<String> captchaTF = new TextField<String>("captcha",
new PropertyModel<String>(null,""));
captchaTF.add(new CaptchaValidator());
add(captchaTF);
CaptchaImage captchaImage = new CaptchaImage("kaptchaImage");
captchaImage.setOutputMarkupId(true);
add(new AjaxFallbackLink("link"){
@Override
public void onClick(final AjaxRequestTarget target) {
captchaImage.detach();
if(target!=null){
target.addComponent(captchaImage);
}else{
//javascript is disable
}
}
}.add(captchaImage));P.S captchaImage.detach(); is required to enable dynamic generate a new captcha image while user click on the image.
I just publish the core Kaptcha and Wicket implementation code, hope this partial code didn’t confuse anyone and make a simple guideline about how do integrate Kaptcha in Wicket framework.


