Kaptcha is simple and easy to use Java library to produces a captcha image validation. In this tutorial, we show you how to integrate Kaptcha with Wicket framework, via Spring.

Libraries used :

  1. Kaptcha v2.3.2
  2. Wicket v1.4.17
  3. wicket-spring v1.4.17
  4. Spring v3.0.5.RELEASE
Note
This article is mainly describes how to integrate Kaptcha with Wicket framework, for Wicket + Spring, please refer to this “Wicket + Spring integration example“.

1. Get Kaptcha

According to this thread, the owner don’t like Maven, so you have to install the library into your local Maven repository manually.

1. Get Kaptcha library here http://code.google.com/p/kaptcha/
2. Issue below Maven command to install it manually.

mvn install:install-file -Dfile=c:\kaptcha-2.3.2.jar -DgroupId=com.google.code 
	-DartifactId=kaptcha -Dversion=2.3.2 -Dpackaging=jar

3. Later, you can includes kaptcha in your pom.xml file.

File : pom.xml

	<dependency>
		<groupId>com.google.code</groupId>
		<artifactId>kaptcha</artifactId>
		<version>2.3.2</version>
	</dependency>

2. DefaultKaptcha via Spring

Create a Spring bean for “DefaultKaptcha“, named captchaProducer.

File : applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
	<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>
 
</beans>

3. CaptchaImage

Create a CaptchaImage class which extends Wicket’s NonCachingImage and using DynamicImageResource class to generate captcha image dynamically.

File : CaptchaImage.java

package com.mkyong.user;
 
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import javax.servlet.http.HttpServletRequest;
import org.apache.wicket.Request;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.markup.html.image.NonCachingImage;
import org.apache.wicket.markup.html.image.resource.DynamicImageResource;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.spring.injection.annot.SpringBean;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
 
public class CaptchaImage extends NonCachingImage {
 
	private static final String CAPTCHA_PRODUCER = "captchaProducer";
 
	// inject via Spring
	@SpringBean
	private DefaultKaptcha 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();
 
				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;
 
			}
		});
 
	}
}

4. CaptchaValidator

Create a custom validator, named “CaptchaValidator“, use to validate user input and compare with the Kaptcha generated code.

File : CaptchaValidator.java

package com.mkyong.user;
 
import javax.servlet.http.HttpServletRequest;
import org.apache.wicket.Request;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.validation.IValidatable;
import org.apache.wicket.validation.validator.AbstractValidator;
 
public class CaptchaValidator extends AbstractValidator<String> {
 
	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);
		}
 
	}
 
	// validate on numm value as well
	@Override
	public boolean validateOnNullValue() {
 
		return true;
 
	}
 
	@Override
	protected String resourceKey() {
		return INVALID_CODE;
	}
}

File : package.properties

captcha.invalid = Incorrect answer, type words in image again!

5. Wicket Components

Integrate Kaptcha with Wicket components.

package com.mkyong.user;
 
import org.apache.wicket.PageParameters;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxFallbackLink;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.model.PropertyModel;
 
public class KaptchaPage extends WebPage {
 
	private String captchaInput;
 
	public KaptchaPage(final PageParameters parameters) {
 
		final CaptchaImage captchaImage = new CaptchaImage("kaptchaImage");
		captchaImage.setOutputMarkupId(true);
 
		TextField<String> captchaTF = new TextField<String>("captcha",
				new PropertyModel<String>(this, "captchaInput"));
		captchaTF.add(new CaptchaValidator());
 
		Form<?> form = new Form<Void>("form") {
			@Override
			protected void onSubmit() {
 
				info("Image words are correct!!!");
			};
		};
 
		form.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));
 
		form.add(captchaTF);
		add(form);
		add(new FeedbackPanel("feedback"));
	}
 
}
Note
captchaImage.detach(); is enables generate a new captcha image dynamically while user click on the captcha image.
<html>
<head>
<style>
.feedbackPanelINFO {
	color: green;
}
 
.feedbackPanelERROR {
	color: red;
}
</style>
</head>
<body>
 
	<h1>Wicket + Kaptcha integration example</h1>
	<div wicket:id="feedback"></div>
	<form wicket:id="form">
		<a wicket:id="link" title="Refresh image words"> 
		<img wicket:id="kaptchaImage" /></a>
		<br>
		<label>Type the image words :</label>
		<input type="text"wicket:id="captcha">
		<input type="submit" value="Submit" />
	</form>
 
</body>
</html>

6. Demo

Start and visit – http://localhost:8080/WicketExamples/

If imput is incorrect :

wicket kaptcha

If input is correct :

wicket kaptcha

References

  1. Kaptcha official website
  2. Wicket + Spring integration example
  3. Include library into local Maven repository
Any Java questions or problems? please post at this JavaNullPointer.com forum, see you there ~
[ Read More ] You can find more similar articles at Apache Wicket Tutorials