验证码生成模块,配置信息基本和前面的模块一样。account-captcha需要提供的服务是生成随机的验证码主键,然后用户可以使用这个主键要求服务生成一个验证码图片,这个图片对应的值应该是随机的,最后用户用肉眼读取图片的值,并将验证码的主键与这个值交给服务进行验证。这一服务对应的接口可以定义如下:

具体代码:

public interface AccountCaptchaService {
//生成主见
String generateCaptchaKey() throws AccountCaptchaException;
byte[] generateCaptchaImage(String captchaKey) throws AccountCaptchaException;
//验证主键和值
boolean validateCaptcha(String captchaKey, String captchaValue)throws AccountCaptchaException;
List<String> getPreDefinedTexts();
void setPreDefinedTexts(List<String> preDefinedTexts);
}

  额外定义的getPreDefinedText和set方法可以预定义验证码图片的值,提高程序的可预测性。

为你了能够生成随机的验证码主键,定义一个类RandomGenerator如下:

public class RandomGenerator {

private static String rangeString = "0123456789qwertyuiopasdfghjklzxcvbnm";
public static synchronized String getRandomString(){
Random random = new Random();
StringBuffer result = new StringBuffer();
for (int i = 0; i < 8; i++) {
result.append(rangeString.charAt(random.nextInt(rangeString.length())));
}
return result.toString();
}
}

  该方法提供了一个线程安全且静态的方法,nextInt()会放回一个大于等于0且小于n的整数。

接口实现:

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() throws AccountCaptchaException {
String key = RandomGenerator.getRandomString();
String value = getCaptchaText();
captchaMap.put(key, value);
return key;
} 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("captaha key"+captchaKey+"not found");
}
BufferedImage image = producer.createImage(text);
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
ImageIO.write(image,"jpg" , out);
} catch (Exception e) {
throw new AccountCaptchaException("failed to write image");
}
return out.toByteArray();
} public boolean validateCaptcha(String captchaKey, String captchaValue)
throws AccountCaptchaException {
String text = captchaMap.get(captchaKey);
if (text == null) {
throw new AccountCaptchaException("captaha key"+captchaKey+"not found");
}
if (text.equals(captchaValue)) {
captchaMap.remove(captchaKey);
return true;
}else {
return false;
} } public List<String> getPreDefinedTexts() { return preDefinedTexts;
} public void setPreDefinedTexts(List<String> preDefinedTexts) {
this.preDefinedTexts = preDefinedTexts; } }

 afterPropertiesSet会在framework初始化的时候调用,这个方法初始化验证码生成器,并提供默认配置。

generateCaptchaKey()首先生成一个随机的验证码主键,每个主键将和一个验证码字符串相关联,然后这组关联会被存储到中captchaMap以备将来验证。主键的目的仅仅是标识验证码图片,其本身没有实际的意义。getCaptchaText()用来生成验证码字符串,当preDefinedTexts存在或者为空的时候,就是用验证码图片生成器producer创建一个随机的字符串。当preDefinedTexts,不为空的时候,就顺序地循环该字符串列表读取值。preDefinedTexts有其对应的一组get和stet方法,这样就能让用户预定义验证码字符串的值。generateCaptchaImage方法就能通过producer来生成一个Bufferedlmage ,随后的代码将这个图片对象转换成jpg格式的字节数组并返回。有了该字节数组,用户就能随意地将其保存成文件,或者在网页上显示。

用户得到了验证码图片以及主键后。就会识别图片中所包含的字符串信息,然后将此验证码的值与主键一起反馈给 validateCaptcha方法以进行验证。

测试代码:

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, "67809"));
}
}

  

public class RandomGeneratorTest {
@Test
public void testGetRandomTest() 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);
} } }

  这个测试代码比较容易看懂。运行测试后可以在项目的target目录下看到生成的验证码图片。

maven小项目注册服务(二)--captcha模块的更多相关文章

  1. maven小项目注册服务(三)--web模块

    java的web应用打包方式一般为war它和jar的区别就是包含了更多的资源和文件,如JSP文件,静态资源文件,servlet等等.war包的核心就WEB-INF文件夹下必须有一个web.xml 的配 ...

  2. maven小项目注册服务(一)--email和persist模块

    跟着书里的讲解,跟着做了一遍该项目: 首先明白注册账户的需求: 账号的lD和Email地址都可以用来唯一地标识某个用户,而显示名称则用来显示在页面下,方便浏览.注册的时候用户还需要输入两次密码,以确保 ...

  3. Android小项目之十二 设置中心的界面

    ------- 源自梦想.永远是你IT事业的好友.只是勇敢地说出我学到! ---------- 按惯例,写在前面的:可能在学习Android的过程中,大家会和我一样,学习过大量的基础知识,很多的知识点 ...

  4. idea结合maven小项目

    整体构造 (修改 POM 文件 )parent <?xml version="1.0" encoding="UTF-8"?> <project ...

  5. spring+springmvc+hibernate架构、maven分模块开发样例小项目案例

    maven分模块开发样例小项目案例 spring+springmvc+hibernate架构 以用户管理做測试,分dao,sevices,web层,分模块开发測试!因时间关系.仅仅測查询成功.其它的准 ...

  6. 基于dubbo构建分布式项目与服务模块

      关于分布式服务架构的背景和需求可查阅http://dubbo.io/.不同于传统的单工程项目,本文主要学习如何通过maven和dubbo将构建分布项目以及服务模块,下面直接开始. 创建项目以及模块 ...

  7. Nacos笔记01——使用Nacos作为SpringCloud项目的服务注册中心

    前言 刚学SpringCloud时使用eureka作为服务注册中心,随着网飞公司eureka2.x不再更新,以及最近在公司实习接触到的SpringCloud项目是使用Nacos来做服务注册中心的,所以 ...

  8. .net core grpc consul 实现服务注册 服务发现 负载均衡(二)

    在上一篇 .net core grpc 实现通信(一) 中,我们实现的grpc通信在.net core中的可行性,但要在微服务中真正使用,还缺少 服务注册,服务发现及负载均衡等,本篇我们将在 .net ...

  9. Dubbo+Zookeeper+SpringMVC+Maven整合实现微服务项目

    互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...

随机推荐

  1. 轻量级远程调用框架-Hessian学习笔记-Demo实现

    Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能. 相比WebService,Hessian更简单.快捷.采用的是二进制RPC协议,因为采用的是二进制协 ...

  2. adb 选择设备

    在adb中有多个设备时,可以先adb devices列举出设备,然后可以通过adb -s <设备名>  [其他参数] 对某个设备进行操作. 例如: adb -s 0123456789ABC ...

  3. Text selection in div(contenteditable) when double click

    背景: 在最近项目中,碰到一个问题:有一个可编辑的div需要双击时可编辑,blur或者回车时将编辑结果保存.你可能注意到双击时,文字会被选中,可编辑区域不会focus到光标位置.考虑到兼容性问题,写了 ...

  4. SqlBulkCopy批量写入25万条数据只需3s

    Microsoft SQL Server 提供一个称为 bcp 的流行的命令提示符实用工具,用于将数据从一个表移动到另一个表(表既可以在同一个服务器上,也可以在不同服务器上).SqlBulkCopy  ...

  5. 关于sublime text的配置方法

    一个星期没有写博客了, 是时候来一波了 -------------------------------------------------------------------------------- ...

  6. 机器学习中的数学-矩阵奇异值分解(SVD)及其应用

    转自:http://www.cnblogs.com/LeftNotEasy/archive/2011/01/19/svd-and-applications.html 版权声明: 本文由LeftNotE ...

  7. Java---算法---插入排序

    /** * 插入排序(升序) * * @param array */ public static void insertSort(int[] array) { int j = 0; // 下标从1开始 ...

  8. C# 生成MD5编码方法(不同位数)

    /// <summary>          /// </summary>          /// <param name="strSource"& ...

  9. Taxi Trip Time Winners' Interview: 3rd place, BlueTaxi

    Taxi Trip Time Winners' Interview: 3rd place, BlueTaxi This spring, Kaggle hosted two competitions w ...

  10. Unity3D WP8发布解决方案名 DefaultPackageName 修改问题

    原地址:http://blog.csdn.net/w337198302/article/details/16960661 在对Unity3D游戏进行Windows phone 8 发布的时候,首先是需 ...