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目录下看到生成的验证码图片。

时间: 2024-11-08 02:22:31

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

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

java的web应用打包方式一般为war它和jar的区别就是包含了更多的资源和文件,如JSP文件,静态资源文件,servlet等等.war包的核心就WEB-INF文件夹下必须有一个web.xml 的配置文件,子目录classes包含所有该项目的类,子目录lib包含所有的依赖,这两个目录都会在运行的时候添加到classpath下. maven对于web项目有统一的格式.项目代码和资源还是放在src/main/java和src/main/resources下,web资源目录在src/main/web

web day24 小项目练习图书商城, 用户,模块(注册,激活,登陆,退出),分类/图书模块

图书商城 模块 用户模块 分类模块 图书模块 购物车模块 订单模块 功能分析 前台 用户模块:注册/激活/登陆/退出 分类模块:查看所有分类 图书模块:查询所有图书/按分类查询图书/查询图书详细(id) 购物车模块:添加/清空/删除购物车条目 /我的购物车(按用户查询) 订单模块:生成订单/我的订单(按用户查询)/按id查询订单/确认收货/ /付款功能(只跳转到银行页面)/付款回调功能 后台 管理员:登陆 分类管理:增/删/改/查 图书管理(我的):增(上传图片)/删/改/查 订单模块:查询所有

web day25 web day24 小项目练习图书商城, 购物车模块,订单模块,支付(易宝支付)

购物车模块 购物车存储: 保存在session中(本次使用的) 保存在cookie中 保存在数据库中 购物车相关类 购物车结构 CartItem:包含图书和数量,小计 Cart:包含一个Map<String,CartItem>和部分购物车操作方法 修改登录方法,在用户登录成功后,马上在session中添加一辆车 页面负责遍历存在session域中的购物车属性 添加购物车条目 清空购物车条目 指定删除购物车条目 图 我的购物车 top.jsp中存在一个链接:我的购物车 我的购物车直接访问/jsp

bbs小项目整理(二)(编码前的一些准备工作)

1 首先是我们的数据库,我们的所有数据的保存在了数据库中,实现项目的过程就是对我们的数据库的数据进行(提取数据库中的数据——>传递——>展现) 当然了也有界面反馈回来的数据信息要存入数据库了( 页面反馈的数据——>传递——>存储到数据库) 来看看我们的数据库吧 CREATE TABLE `tb_message` ( `messageID` int(11) NOT NULL AUTO_INCREMENT, /*消息主键id,自增 */ `messageTitle` varchar(5

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

maven分模块开发例子小项目案例 spring+springmvc+hibernate架构 以用户管理做测试,分dao,sevices,web层,分模块开发测试!因时间关系,只测查询成功,其他的准备在ext上做个完整的案例来的,可惜最近时间很紧, 高级部分也没做测试,比如建私服,其他常用插件测试之类的,等用时间了我做个完整ext前端和maven 完整的例子出来,在分享吧! 不过目前这些撑握了,在项目中做开发是没有问题的,其他高级部分是架构师所做的. 之前我有的资源都加上了积分,有些博友向我要,

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

maven分模块开发样例小项目案例 spring+springmvc+hibernate架构 以用户管理做測试,分dao,sevices,web层,分模块开发測试!因时间关系.仅仅測查询成功.其它的准备在ext上做个完整的案例来的,可惜近期时间非常紧. 高级部分也没做測试,比方建私服,其它经常使用插件測试之类的,等用时间了我做个完整ext前端和maven 完整的样例出来,在分享吧. 只是眼下这些撑握了.在项目中做开发是没有问题的,其它高级部分是架构师所做的. 之前我有的资源都加上了积分,有些博友

微服务中基于Spring Boot的maven分布式项目框架的搭建

项目介绍 这里搭建的是基于 maven 的分布式工程,因为在一个项目中,多个微服务是属于同一个工程,只不过是提供不同的服务而已,再加上 IDEA 是默认一个窗口打开一个项目工程(这点和 eclipse 不同),如果项目大,不用 maven 聚合工程的话,那估计会打开十几个窗口--会崩溃--而且在架构上,也应该使用 maven 分布式工程来搭建微服务架构.这里手把手教大家在 IDEA 中搭建基于 maven 分布式的 Spring Cloud 微服务工程架构. maven分布式工程架构首先来看一下

超实用python小项目--基于python的手机通讯录二维码生成网站--1、项目介绍和开发环境

这个项目是我做完整的第一个python web项目,对于新手来说,这个项目绝对是一个特别好的练手项目. 起名还是困难,但是自己确实比较烦输入这么长的名字(手机通讯录二维码生成网站)去定义这个网站,所以还是给这个项目起个名字吧,叫什么呢?就叫 "鹅日通讯录"吧(Earth address list). --------------------------------------------------------------------------------------------我是

Android的SQLiteDataBase小项目,实现user类登陆注册以及student类增删改查

关于SQLiteDataBase这块,大体有两种主要的实现方式,一种是不使用Helper类的方式,此种方式存在一个弊端,即不能oncreate两次,如果重复使用oncreate的button,则会报错,所以为了避免这种错误,在此项目中使用类继承SQLiteOpenHelper的方式进行SQLite3小型数据库的小项目开发,简单的实现登陆注册,以及对特定vo类的增删改查,中间还夹杂了ListView,ArrayAdapter,以及Intent的散知识点. 以下为正文:首先介绍以下我写的项目的框架,