一个Maven实现的验证码模块
2015-07-24 23:08
316 查看
下面是Maven构建的实现账户注册服务的account-captcha模块,该模块负责处理账户注册时key生成、图片生成以及验证等。
POM部分配置
//account-captcha的pom.xml
这里的kaptcha依赖通过 默认repo没有找到,所以只有通过手动添加。jar下载包地址:https://code.google.com/p/kaptcha/downloads/list
另外手动jar包到本地仓库的教程地址:http://www.cnblogs.com/jerome-rong/archive/2012/12/08/2808947.html
简单来说这里的kaptcha包下载jar包之后执行命令:mvn install:install-file -Dfile=${下载路径}\kaptcha-2.3.2.jar -DgroupId=com.google.code.kaptcha -DartifactId=kaptcha -Dversion=2.3.2 -Dpackaging=jar 即可添加到本地仓库。
这段POM配置中首先是父模块声明,之后是项目本身的artifactId和name,groupId和version继承自父模块。然后声明了一个Maven属性kaptcha.version,用于依赖声明。依赖除了SpringFramework和junit之外,还包含一个com.google.code.kaptcha:kaptcha。kaptcha是一个用来生成验证码的开源类库。
注意不要忘记把account-captcha加入到聚合模块中,即修改account-parent的POM文件:
主代码部分
account-captcha需要提供的服务是生成随机的验证码主键,然后用户可以使用这个主键要求服务生成一个验证码图片,这个图片对应的值应该是随机的,最后用户读取图片值并交给服务验证。这一服务的接口定义如下:
//AccountCaptchaService.java
这里引入了一个异常类,定义如下:
另外为了能够生成随机的验证码主键,引入一个RandomGenerator类
//RandomGenerator.java
//account-captcha.xml
测试代码
首先是测试随机数生成:
//RandomGeneratorTest.java
//AccountCaptchaServiceTest.java
测试结果
执行mvn test,构建成功,结果如下:
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.555 s
[INFO] Finished at: 2015-07-24T23:06:14+08:00
[INFO] Final Memory: 12M/127M
[INFO] ------------------------------------------------------------------------
参考书籍:《Maven实战》第10章——徐晓斌著
POM部分配置
//account-captcha的pom.xml
<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> <parent> <groupId>com.juvenxu.mvnbook.account</groupId> <artifactId>account-parent</artifactId> <version>1.0.0-SNAPSHOT</version> </parent> <artifactId>account-captcha</artifactId> <name>Account Captcha</name> <properties> <kaptcha.version>2.3.2</kaptcha.version> </properties> <dependencies> <dependency> <groupId>com.google.code.kaptcha</groupId> <artifactId>kaptcha</artifactId> <version>${kaptcha.version}</version> </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> </dependencies> <build/> </project>
这里的kaptcha依赖通过 默认repo没有找到,所以只有通过手动添加。jar下载包地址:https://code.google.com/p/kaptcha/downloads/list
另外手动jar包到本地仓库的教程地址:http://www.cnblogs.com/jerome-rong/archive/2012/12/08/2808947.html
简单来说这里的kaptcha包下载jar包之后执行命令:mvn install:install-file -Dfile=${下载路径}\kaptcha-2.3.2.jar -DgroupId=com.google.code.kaptcha -DartifactId=kaptcha -Dversion=2.3.2 -Dpackaging=jar 即可添加到本地仓库。
这段POM配置中首先是父模块声明,之后是项目本身的artifactId和name,groupId和version继承自父模块。然后声明了一个Maven属性kaptcha.version,用于依赖声明。依赖除了SpringFramework和junit之外,还包含一个com.google.code.kaptcha:kaptcha。kaptcha是一个用来生成验证码的开源类库。
注意不要忘记把account-captcha加入到聚合模块中,即修改account-parent的POM文件:
<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.juvenxu.mvnbook.account</groupId> <artifactId>account-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <name>Account Parent</name> <modules> <module>../account-email</module> <module>../account-persist</module> <module>../account-captcha</module> </modules> <properties> <springframework.version>4.1.7.RELEASE</springframework.version> <junit.version>4.12</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-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>
主代码部分
account-captcha需要提供的服务是生成随机的验证码主键,然后用户可以使用这个主键要求服务生成一个验证码图片,这个图片对应的值应该是随机的,最后用户读取图片值并交给服务验证。这一服务的接口定义如下:
//AccountCaptchaService.java
package com.juvenxu.mvnbook.account.captcha; import java.util.List; public interface AccountCaptchaService { /** * 生成随机的验证码主键 * * @return 验证码主键 * @throws AccountCaptchaException */ String generateCaptchaKey() throws AccountCaptchaException; /** * 生成验证码图片 * * @param 验证码主键 * @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 验证码 */ void setPreDefinedTexts(List<String> preDefinedTexts); }
这里引入了一个异常类,定义如下:
package com.juvenxu.mvnbook.account.captcha; @SuppressWarnings("serial") public class AccountCaptchaException extends Exception { /** * 带一个参数的构造函数 * * @param message * 错误信息 */ public AccountCaptchaException(String message) { super(message); } /** * 带两个参数的构造参数 * * @param message * 错误信息 * @param throwable * 是否可抛出 */ public AccountCaptchaException(String message, Throwable throwable) { super(message, throwable); } }这里的服务接口之所以要定义额外的getPreDefinedTexts()和setPreDefinedTexts()方法,主要是为了提高可测试性,方便获取验证码及设置方便测试。
另外为了能够生成随机的验证码主键,引入一个RandomGenerator类
//RandomGenerator.java
package com.juvenxu.mvnbook.accoun 4000 t.captcha; import java.util.Random; public class RandomGenerator { // 验证码字符范围 private static String range = "0123456789abcdefghijklmnopqrstuvwxyz"; /** * 静态且安全地获取一个长度为8的随机字符串 * * @return 随机字符串 */ 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.juvenxu.mvnbook.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())); // 为producer提供默认配置 } public String generateCaptchaKey() { String key = RandomGenerator.getRandomString(); // 生成随机的验证码主键 String value = getCaptchaText(); captchaMap.put(key, value); // 存储主键到captchaMap 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!"); } // 通过producer生成一个BufferImage BufferedImage image = producer.createImage(text); // 将图片对象转换为jpg格式的字节数组并返回 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; } } }另外还需要SpringFramework的配置文件,放在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-4.1.xsd"> <bean id="accountCaptchaService" class="com.juvenxu.mvnbook.account.captcha.AccountCaptchaServiceImpl"> </bean> </beans>
测试代码
首先是测试随机数生成:
//RandomGeneratorTest.java
package com.juvenxu.mvnbook.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); //创建初始容量为100的集合 for (int i = 0; i < 100; i++) { String random = RandomGenerator.getRandomString(); assertFalse(randoms.contains(random)); //检查新生成的随机数是否包含在集合中 randoms.add(random); } } }然后是服务模块的测试:
//AccountCaptchaServiceTest.java
package com.juvenxu.mvnbook.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 /** * 运行在测试方法前,初始化AccountCaptchaService的bean * @throws Exception */ public void prepare() throws Exception { @SuppressWarnings("resource") ApplicationContext ctx = new ClassPathXmlApplicationContext( "account-captcha.xml"); service = (AccountCaptchaService) ctx.getBean("accountCaptchaService"); } @Test /** * 测试验证码图片生成 * @throws Exception */ public void testGenerateCaptcha() throws Exception { String captchaKey = service.generateCaptchaKey(); assertNotNull(captchaKey); byte[] captchaImage = service.generateCaptchaImage(captchaKey); assertTrue(captchaImage.length > 0); //在项目的target目录下创建一个名为主键的jpg格式文件 File image = new File("target/" + captchaKey + ".jpg"); OutputStream output = null; try { //将验证码图片字节数组内容写入到jpg文件中 output = new FileOutputStream(image); output.write(captchaImage); } finally { if (output != null) { output.close(); } } //检查文件存在且包含实际内容 assertTrue(image.exists() && image.length() > 0); } @Test /** * 测试验证流程正确性 * @throws Exception */ 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 /** * 测试用户反馈Captcha错误时发生情况 * @throws Exception */ 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")); } }
测试结果
执行mvn test,构建成功,结果如下:
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.555 s
[INFO] Finished at: 2015-07-24T23:06:14+08:00
[INFO] Final Memory: 12M/127M
[INFO] ------------------------------------------------------------------------
参考书籍:《Maven实战》第10章——徐晓斌著
相关文章推荐
- java自动生成验证码插件-kaptcha
- 加载flash9.ocx出现错误的解决方法
- 如何识别高级的验证码的技术总结第1/4页
- jquery实现的代替传统checkbox样式插件
- 10款新鲜出炉的 jQuery 插件(Ajax 插件,有幻灯片、图片画廊、菜单等)
- 推荐40个非常优秀的jQuery插件和教程【系列三】
- Node.js插件的正确编写方式
- PHP 验证码不显示只有一个小红叉的解决方法
- 推荐十款免费 WordPress 插件
- asp汉字中文图片验证码
- php 验证码制作(网树注释思想)
- 使用JavaScript开发IE浏览器本地插件实例
- C#验证码识别基础方法实例分析
- 推荐25个超炫的jQuery网格插件
- 纯JavaScript实现的分页插件实例
- JQuery插件jcarousellite的参数中文说明
- javascript点击才出现验证码
- node.js WEB开发中图片验证码的实现方法
- jQuery插件kinMaxShow扩展效果用法实例