使用google的kaptcha包实现,可预定义验证码内容。
pom.xml:
<dependency>
<groupId>com.google.code.kaptcha</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3</version>
<!--Kaptcha针对1.5和1.4提供了不同的分发包,这里使用classifier来区分-->
<classifier>jdk15</classifier>
</dependency>
CaptchaService:
package net.deniro.captcha;
import java.util.List;
/**
* 验证码
*
* @author deniro
* 15-2-24上午10:49
*/
public interface CaptchaService {
/**
* 生成随机验证码主键
*
* @return
* @throws CaptchaException
*/
String generateCaptchaKey() throws CaptchaException;
/**
* 生成验证码图片
*
* @param captchaKey
* @return
* @throws CaptchaException
*/
byte[] generateCaptchaImage(String captchaKey) throws CaptchaException;
/**
* 验证用户返回的主键和值
*
* @param captchaKey
* @param captchaValue
* @return
* @throws CaptchaException
*/
boolean validateCaptcha(String captchaKey, String captchaValue) throws CaptchaException;
/**
* 获取 预定义验证码图片的内容
*
* @return
*/
List<String> getPreDefinedTexts();
/**
* 设置 预定义验证码图片的内容
*
* 提高可测试性
*
* @param preDefinedTexts
*/
void setPreDefinedTexts(List<String> preDefinedTexts);
}
CaptchaServiceImpl:
package net.deniro.captcha;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.beans.factory.InitializingBean;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* 验证码实现
*
* @author deniro
* 15-2-24上午11:05
*/
public class CaptchaServiceImpl implements CaptchaService, InitializingBean {
/**
* 验证码生成器
*/
private DefaultKaptcha producer;
private Map<String, String> captchaMap = new HashMap<String, String>();
/**
* 预定义验证码内容列表
*/
private List<String> preDefinedTexts;
/**
* 预定义验证码内容列表索引
*/
private int textCount = 0;
/**
* 生成随机验证码
*
* @return
* @throws CaptchaException
*/
@Override
public String generateCaptchaKey() throws CaptchaException {
String key = RandomGenerator.getRandomString();//主键的目的仅是标识验证码图片,本身没有实际意义
String value = getCaptchaText();
captchaMap.put(key, value);
return key;
}
/**
* 生成验证码字符串
*
* @return
*/
private String getCaptchaText() {
if (preDefinedTexts != null && !preDefinedTexts.isEmpty()) {//顺序循环字符串列表读取值
String text = preDefinedTexts.get(textCount);
textCount = (textCount + 1) % preDefinedTexts.size();
return text;
} else {//创建随机字符串
return producer.createText();
}
}
/**
* 生成验证码图片
*
* @param captchaKey
* @return
* @throws CaptchaException
*/
@Override
public byte[] generateCaptchaImage(String captchaKey) throws CaptchaException {
String text = captchaMap.get(captchaKey);
if (text == null) {
throw new CaptchaException("验证码' " + captchaKey + " ' 未找到。");
}
BufferedImage image = producer.createImage(text);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
ImageIO.write(image, "jpg", out);
} catch (Exception e) {
throw new CaptchaException("无法生成验证码流。");
}
return out.toByteArray();
}
/**
* 验证
*
* @param captchaKey
* @param captchaValue
* @return
* @throws CaptchaException
*/
@Override
public boolean validateCaptcha(String captchaKey, String captchaValue) throws CaptchaException {
String text = captchaMap.get(captchaKey);
if (text == null) {
throw new CaptchaException("验证码主键' " + captchaKey + " '不存在!");
}
if (text.equals(captchaValue)) {
captchaMap.remove(captchaKey);
return true;
} else {
return false;
}
}
@Override
public List<String> getPreDefinedTexts() {
return preDefinedTexts;
}
@Override
public void setPreDefinedTexts(List<String> preDefinedTexts) {
this.preDefinedTexts = preDefinedTexts;
}
/**
* 初始化验证码生成器,并提供默认配置
* <p/>
* Spring初始化对象时调用
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
producer = new DefaultKaptcha();
producer.setConfig(new Config(new Properties()));
}
}
RandomGenerator:
package net.deniro.captcha;
import java.util.Random;
/**
* 随机码生成器
*
* @author deniro
* 15-2-24上午10:59
*/
public class RandomGenerator {
/**
* 字符范围
*/
private static String range="0123456789abcdefghijklmnopqrstuvwxyz";
/**
* 获取随机字符串
*
* 静态、线程安全
* @return
*/
public static synchronized String getRandomString(){
Random random=new Random();
StringBuilder result=new StringBuilder();
for (int i = 0; i < 8; i++) {
result.append(range.charAt(random.nextInt(range.length())));
}
return result.toString();
}
}
CaptchaException:
package net.deniro.captcha;
/**
* 验证码异常
*
* @author deniro
* 15-2-24上午10:51
*/
public class CaptchaException extends Exception {
public CaptchaException(String message) {
super(message);
}
public CaptchaException(String message, Throwable throwable) {
super(message, throwable);
}
}
captcha.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
<bean id="CaptchaService" class="net.deniro.captcha.CaptchaServiceImpl"></bean>
</beans>
CaptchaServiceTest:
package captcha;
import net.deniro.captcha.CaptchaService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* @author deniro
* 15-2-24下午11:24
*/
public class CaptchaServiceTest {
private CaptchaService service;
@Before
public void prepare() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("captcha.xml");
service = (CaptchaService) ctx.getBean("CaptchaService");
}
@Test
public void testGenerateCaptcha() throws Exception {
List<String> preDefinedTexts = new ArrayList<String>();
preDefinedTexts.add("12345");
preDefinedTexts.add("abcde");
service.setPreDefinedTexts(preDefinedTexts);
for (int i = 0; i < preDefinedTexts.size(); i++) {
String captchaKey = service.generateCaptchaKey();
assertNotNull(captchaKey);
byte[] captchaImage = service.generateCaptchaImage(captchaKey);
assertTrue(captchaImage.length > 0);
File image = new File("target/" + captchaKey + ".jpg");
OutputStream output = null;
try {
output = new FileOutputStream(image);
output.write(captchaImage);
} finally {
if (output != null) {
output.close();
}
}
assertTrue(image.exists() && image.length() > 0);
}
}
@Test
public void testValidateCaptchaCorrect() throws Exception {
List<String> preDefinedTexts = new ArrayList<String>();
preDefinedTexts.add("12345");
preDefinedTexts.add("abcde");
service.setPreDefinedTexts(preDefinedTexts);
String captchaKey = service.generateCaptchaKey();
service.generateCaptchaImage(captchaKey);
assertTrue(service.validateCaptcha(captchaKey, "12345"));
captchaKey = service.generateCaptchaKey();
service.generateCaptchaImage(captchaKey);
assertTrue(service.validateCaptcha(captchaKey, "abcde"));
}
}
生成的验证码图片: