zoukankan      html  css  js  c++  java
  • 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目录下看到生成的验证码图片。

  • 相关阅读:
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-print
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-bookmark
    吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-book
    ListView与RadioButton组合——自定义单选列表
    谷歌邮箱上不了的情况下怎么登录谷歌邮箱
    Valid page threshold based garbage collection for solid state drive
    Win10 owerShell Get命令大全
    程序员每天应该思考的5个问题,你有思考过吗?
    程序员每天应该思考的5个问题,你有思考过吗?
    程序员每天应该思考的5个问题,你有思考过吗?
  • 原文地址:https://www.cnblogs.com/silence-hust/p/4217784.html
Copyright © 2011-2022 走看看