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