maven小项目注册服务(二)--captcha模块
验证码生成模块,配置信息基本和前面的模块一样。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模块的更多相关文章
- maven小项目注册服务(三)--web模块
java的web应用打包方式一般为war它和jar的区别就是包含了更多的资源和文件,如JSP文件,静态资源文件,servlet等等.war包的核心就WEB-INF文件夹下必须有一个web.xml 的配 ...
- maven小项目注册服务(一)--email和persist模块
跟着书里的讲解,跟着做了一遍该项目: 首先明白注册账户的需求: 账号的lD和Email地址都可以用来唯一地标识某个用户,而显示名称则用来显示在页面下,方便浏览.注册的时候用户还需要输入两次密码,以确保 ...
- Android小项目之十二 设置中心的界面
------- 源自梦想.永远是你IT事业的好友.只是勇敢地说出我学到! ---------- 按惯例,写在前面的:可能在学习Android的过程中,大家会和我一样,学习过大量的基础知识,很多的知识点 ...
- idea结合maven小项目
整体构造 (修改 POM 文件 )parent <?xml version="1.0" encoding="UTF-8"?> <project ...
- spring+springmvc+hibernate架构、maven分模块开发样例小项目案例
maven分模块开发样例小项目案例 spring+springmvc+hibernate架构 以用户管理做測试,分dao,sevices,web层,分模块开发測试!因时间关系.仅仅測查询成功.其它的准 ...
- 基于dubbo构建分布式项目与服务模块
关于分布式服务架构的背景和需求可查阅http://dubbo.io/.不同于传统的单工程项目,本文主要学习如何通过maven和dubbo将构建分布项目以及服务模块,下面直接开始. 创建项目以及模块 ...
- Nacos笔记01——使用Nacos作为SpringCloud项目的服务注册中心
前言 刚学SpringCloud时使用eureka作为服务注册中心,随着网飞公司eureka2.x不再更新,以及最近在公司实习接触到的SpringCloud项目是使用Nacos来做服务注册中心的,所以 ...
- .net core grpc consul 实现服务注册 服务发现 负载均衡(二)
在上一篇 .net core grpc 实现通信(一) 中,我们实现的grpc通信在.net core中的可行性,但要在微服务中真正使用,还缺少 服务注册,服务发现及负载均衡等,本篇我们将在 .net ...
- Dubbo+Zookeeper+SpringMVC+Maven整合实现微服务项目
互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,Dubbo是一个分布式服务框架,在这种情况下诞生的.现在核心业务抽取出来,作为独立的服务,使 ...
随机推荐
- 菜鸟学习Struts——简易计算器
这是学习Struts的一个简单的例子文件结构如下: 1.配置Struts环境 2.新建input.jsp,success.jsp,error.jsp input.jsp代码如下: <%@ pag ...
- C# 反射学习总结
C#中的反射可以使得程序集和类型(类.结构.委托.接口和枚举)以及类型中的成员(方法.字段.属性.事件.参数.构造函数等)都成为变量在编程中动态调用.
- MySQL 5.7.9的多源复制
什么是多源复制? 首先,我们需要清楚 multi-master 与multi-source 复制不是一样的. Multi-Master 复制通常是环形复制,你可以在任意主机上将数据复制给其他主机. M ...
- MySQL 多实例给root用户创建密码
DB:5.5.14 OS:CentOS 6.3 安装多实例MySQL数据库,安装完成后默认无密码,一次性给所有实例的root账户创建密码: #!/bin/bash for i in {3361..3 ...
- nginx error_page 404 用 php header 无法跳转
nginx error_page 404 用 php header 无法跳转 之前用Apache的时候,只需要设置 ErrorDocument 404 /404.php 就可以在 404.php 中根 ...
- 原生js实现仿window10系统日历效果
舞动的灵魂版js日历,完全采用js实现,故而实现了与语言无关,jsp.asp.net php asp均可使用.无论你是开发软件,还是网站,均是不可或缺的实用代码. 该日历主要实现了获取当前时间时分秒, ...
- js异步加载 defer和async 比较
网上说法很多,很少一句话能总结清楚的,终于找到两句一针见血的描述,很到位: 相同点:都不阻塞DOM解析 defer :顺序:保证先后顺序.解析:HTML 解析器遇到它们时,不阻塞(脚本将被异步下载) ...
- 【BZOJ】【1101】【POI2007】Zap
莫比乌斯反演 PoPoQQQ的讲义例一的一半……好吧这题是那题的基础部分= =很水…… WA了一次:因为没强制类型转换LL /************************************* ...
- 有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面m个数。
#include<stdio.h> #include<stdlib.h> int main() { setvbuf(stdout,NULL,_IONBF,); //使用Ecli ...
- PHP杂记
SOAP: 感觉是类似于Java中的HttpClient的东西,和curl也有点像. PHPStorm中查看所有的函数结构(Structure):Alt+7 查找方法或类(Symbol Name 函数 ...