1.新建Maven模块项目,父项目为account,建好后account的POM文件内容为:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.iteye.xujava</groupId> <artifactId>account</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <name>Account</name> <modules> <module>account-email</module> <module>account-persist</module> <!-- 自动加入的部分 --> <module>account-captcha</module> </modules> <properties> <springframework.version>2.5.6</springframework.version> <junit.version>4.9</junit.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>
2.account captcha中的POM文件内容如下:
<?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.iteye.xujava</groupId> <artifactId>account</artifactId> <version>1.0.0</version> </parent> <artifactId>account-captcha</artifactId> <name>Account Captcha</name> <properties> <kaptcha.version>2.3</kaptcha.version> </properties> <dependencies> <dependency> <groupId>com.google.code.kaptcha</groupId> <artifactId>kaptcha</artifactId> <version>${kaptcha.version}</version> <classifier>jdk15</classifier> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies> <repositories> <repository> <id>sonatype-forge</id> <name>Sonatype Forge</name> <url>http://repository.sonatype.org/content/groups/forge/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> </project>
3.account captcha模块中src/main/java目录com.iteye.xujava.account.captcha包下创建以下4个文件:
package com.iteye.xujava.account.captcha;
public class AccountCaptchaException extends Exception {
private static final long serialVersionUID = 1339439433313285858L;
public AccountCaptchaException(String message) {
super(message);
}
public AccountCaptchaException(String message, Throwable throwable) {
super(message, throwable);
}
}
package com.iteye.xujava.account.captcha;
import java.util.Random;
public class RandomGenerator {
private static String range = "0123456789abcdefghijklmnopqrstuvwxyz";
public static synchronized String getRandomString() {
Random random = new Random();
StringBuffer result = new StringBuffer();
for (int i = 0; i < 8; i++) {
result.append(range.charAt(random.nextInt(range.length())));
}
return result.toString();
}
}
package com.iteye.xujava.account.captcha;
import java.util.List;
public interface AccountCaptchaService {
/**
* 生成随机验证码
*
* @return
* @throws AccountCaptchaException
*/
String generateCaptchaKey() throws AccountCaptchaException;
/**
* 生成验证码图片
*
* @param captchaKey
* @return
* @throws AccountCaptchaException
*/
byte[] generateCaptchaImage(String captchaKey) throws AccountCaptchaException;
/**
* 验证用户反馈的主键和值
*
* @param captchaKey
* @param captchaValue
* @return
* @throws AccountCaptchaException
*/
boolean validateCaptcha(String captchaKey, String captchaValue) throws AccountCaptchaException;
/**
* 获得自定义验证码
*
* @return
*/
List<String> getPreDefinedTexts();
/**
* 设置自定义验证码
*
* @param preDefinedTexts
*/
void setPreDefinedTexts(List<String> preDefinedTexts);
}
package com.iteye.xujava.account.captcha;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.imageio.ImageIO;
import org.springframework.beans.factory.InitializingBean;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
public class AccountCaptchaServiceImpl implements AccountCaptchaService, InitializingBean {
private DefaultKaptcha producer;
private Map<String, String> captchaMap = new HashMap<String, String>();
private List<String> preDefinedTexts;
private int textCount = 0;
public void afterPropertiesSet() throws Exception {
producer = new DefaultKaptcha();
producer.setConfig(new Config(new Properties()));
}
public String generateCaptchaKey() {
String key = RandomGenerator.getRandomString();
String value = getCaptchaText();
captchaMap.put(key, value);
return key;
}
public List<String> getPreDefinedTexts() {
return preDefinedTexts;
}
public void setPreDefinedTexts(List<String> preDefinedTexts) {
this.preDefinedTexts = preDefinedTexts;
}
private String getCaptchaText() {
if (preDefinedTexts != null && !preDefinedTexts.isEmpty()) {
String text = preDefinedTexts.get(textCount);
textCount = (textCount + 1) % preDefinedTexts.size();
return text;
} else {
return producer.createText();
}
}
public byte[] generateCaptchaImage(String captchaKey) throws AccountCaptchaException {
String text = captchaMap.get(captchaKey);
if (text == null) {
throw new AccountCaptchaException("Captch key '" + captchaKey + "' not found!");
}
BufferedImage image = producer.createImage(text);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
ImageIO.write(image, "jpg", out);
} catch (IOException e) {
throw new AccountCaptchaException("Failed to write captcha stream!", e);
}
return out.toByteArray();
}
public boolean validateCaptcha(String captchaKey, String captchaValue) throws AccountCaptchaException {
String text = captchaMap.get(captchaKey);
if (text == null) {
throw new AccountCaptchaException("Captch key '" + captchaKey + "' not found!");
}
if (text.equals(captchaValue)) {
captchaMap.remove(captchaKey);
return true;
} else {
return false;
}
}
}
4. 在src/main/resources目录下创建配置文件account-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-2.5.xsd"> <bean id="accountCaptchaService" class="com.iteye.xujava.account.captcha.AccountCaptchaServiceImpl"> </bean> </beans>
5.在src/test/main目录com.iteye.xujava.account.captcha下创建测试文件
package com.iteye.xujava.account.captcha;
import static org.junit.Assert.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AccountCaptchaServiceTest {
private AccountCaptchaService service;
@Before
public void prepare() throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("account-captcha.xml");
service = (AccountCaptchaService) ctx.getBean("accountCaptchaService");
}
@Test
public void testGenerateCaptcha() throws Exception {
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"));
}
@Test
public void testValidateCaptchaIncorrect() throws Exception {
List<String> preDefinedTexts = new ArrayList<String>();
preDefinedTexts.add("12345");
service.setPreDefinedTexts(preDefinedTexts);
String captchaKey = service.generateCaptchaKey();
service.generateCaptchaImage(captchaKey);
assertFalse(service.validateCaptcha(captchaKey, "67890"));
}
}
package com.iteye.xujava.account.captcha;
import static org.junit.Assert.assertFalse;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
public class RandomGeneratorTest {
@Test
public void testGetRandomString() throws Exception {
Set<String> randoms = new HashSet<String>(100);
for (int i = 0; i < 100; i++) {
String random = RandomGenerator.getRandomString();
assertFalse(randoms.contains(random));
randoms.add(random);
}
}
}
6.运行mvn clean test
mvn clean install