这两天在帮同学做个项目,项目中需要做个验证码,说实话那么多年竟然没注意过这东西,原理很简单,贴出来给大家做个参考。

1、简单介绍

一般稍微有些经验的程序员都不会再自己写原生验证码生成了,因为各种强大的开源组件,足以解决我们大部分的需求。但是,比较也是刚接触这东西,还需要从原理入手的。

下面我就简单介绍下原生和使用开源项目kaptcha生成验证码的两种形式。

2、jdk原生生成验证码

效果:

2.1 验证码生成的流程

1、定义BufferedImage(图像数据缓冲区)对象

2、获得Graphics对象

3、随机生成验证码字母或者数字

4、使用Graphics绘制图片

5、记录验证码信息到session或数据库,以便校验

5、ImageIO输出图片到客户端

2.2 代码讲解

这里我就不整合框架了,简单用servlet讲下步骤,框架中也是这样做

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{
        //定义BufferedImage(图像数据缓冲区)对象
        BufferedImage bi = new BufferedImage(68,22,BufferedImage.TYPE_INT_RGB);
        //绘制图片
        Graphics g = bi.getGraphics();
        //背景色
        Color c = new Color(200,150,255);
        g.setColor(c);
        //图片坐标
        g.fillRect(0, 0, 68, 22);
        //验证码选取
        char[] ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
        Random r = new Random();
        int len=ch.length,index;
        StringBuffer sb = new StringBuffer();
        for(int i=0; i<4; i++){
            index = r.nextInt(len);
            g.setColor(new Color(r.nextInt(88),r.nextInt(188),r.nextInt(255)));
            Font ft = new Font(Font.SANS_SERIF, Font.BOLD, 16);
            g.setFont(ft);
            g.drawString(ch[index]+"", (i*15)+3, 18);
            sb.append(ch[index]);
        }
//打印验证码,项目中用日志 System.out.println(sb.toString());
     //验证码写到session request.getSession().setAttribute("checkCode", sb.toString()); //ImageIO写出图片 ImageIO.write(bi, "JPG", response.getOutputStream()); }

jsp:

 <form action="XX" method="get">
    验证码:<input type="text" name="checkcode"/>
    <img alt="点击更换验证码" id="imagecode" onclick="this.src='/servlet/ImageServlet?random='+Math.random();" src="/servlet/ImageServlet"/>
    <input type="submit" value="提交">
  </form>

相信稍微有些经验的同学看过上面的代码都能理解其中的原理吧。至于后面的校验相信大家都会的。

下面我重点讲下使用kaptcha开源组件生成验证码的流程,这里我会用servlet和springboot+springmvc的方式分别进行下介绍。

3、使用kaptcha组件生成验证码

既然说到开源组件,必然功能是强大的,还是先看效果图!

数字字母组合

数字字母汉字组合

算数计算

3.1 kaptcha的参数详解

Constant 描述 默认值
kaptcha.border 图片边框,合法值:yes , no yes
kaptcha.border.color 边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue. black
kaptcha.border.thickness 边框厚度,合法值:>0 1
kaptcha.image.width 图片宽 200
kaptcha.image.height 图片高 50
kaptcha.producer.impl 图片实现类 com.google.code.kaptcha.impl.DefaultKaptcha
kaptcha.textproducer.impl 文本实现类 com.google.code.kaptcha.text.impl.DefaultTextCreator
kaptcha.textproducer.char.string 文本集合,验证码值从此集合中获取 abcde2345678gfynmnpwx
kaptcha.textproducer.char.length 验证码长度 5
kaptcha.textproducer.font.names 字体 Arial, Courier
kaptcha.textproducer.font.size 字体大小 40px
kaptcha.textproducer.font.color 字体颜色,合法值: r,g,b  或者 white,black,blue. black
kaptcha.textproducer.char.space 文字间隔 2
kaptcha.noise.impl 干扰实现类 com.google.code.kaptcha.impl.DefaultNoise
kaptcha.noise.color 干扰颜色,合法值: r,g,b 或者 white,black,blue. black
kaptcha.obscurificator.impl 图片样式:
水纹com.google.code.kaptcha.impl.WaterRipple
鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
阴影com.google.code.kaptcha.impl.ShadowGimpy
com.google.code.kaptcha.impl.WaterRipple
kaptcha.background.impl 背景实现类 com.google.code.kaptcha.impl.DefaultBackground
kaptcha.background.clear.from 背景颜色渐变,开始颜色 light grey
kaptcha.background.clear.to 背景颜色渐变,结束颜色 white
kaptcha.word.impl 文字渲染器 com.google.code.kaptcha.text.impl.DefaultWordRenderer
kaptcha.session.key session key KAPTCHA_SESSION_KEY
kaptcha.session.date session date KAPTCHA_SESSION_DATE
 
 

3.2 代码讲解

1、servlet方式

上图可以看到,kaptcha处理验证码的类是KaptchaServlet。这里我们就可以像原生的方式一样直接请求这个servlet,这里主要讲下使用servlet和使用框架的时候参数配置是不用的,servlet的是配置在web.xml中的,形式如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <!-- 登陆验证码Kaptcha 2-->
    <servlet>
        <servlet-name>Kaptcha</servlet-name>
        <servlet-class>
            com.google.code.kaptcha.servlet.KaptchaServlet
        </servlet-class>
        <init-param>
            <description>图片边框,合法值:yes , no</description>
            <param-name>kaptcha.border</param-name>
            <param-value>yes</param-value>
        </init-param>
        <init-param>
            <description>
                边框颜色,合法值: r,g,b (and optional alpha) 或者
                white,black,blue.
            </description>
            <param-name>kaptcha.border.color</param-name>
            <param-value>black</param-value>
        </init-param>
        <init-param>
            <description>边框厚度,合法值:>0</description>
            <param-name>kaptcha.border.thickness</param-name>
            <param-value>1</param-value>
        </init-param>
        <init-param>
            <description>图片宽 200</description>
            <param-name>kaptcha.image.width</param-name>
            <param-value>200</param-value>
        </init-param>
        <init-param>
            <description>图片高 50</description>
            <param-name>kaptcha.image.height</param-name>
            <param-value>50</param-value>
        </init-param>
        <init-param>
            <description>图片实现类</description>
            <param-name>kaptcha.producer.impl</param-name>
            <param-value>
                com.google.code.kaptcha.impl.DefaultKaptcha
            </param-value>
        </init-param>
        <init-param>
            <description>文本实现类</description>
            <param-name>kaptcha.textproducer.impl</param-name>
            <param-value>
                com.google.code.kaptcha.text.impl.DefaultTextCreator
            </param-value>
        </init-param>
        <init-param>
            <description>验证码长度 5</description>
            <param-name>kaptcha.textproducer.char.length</param-name>
            <param-value>5</param-value>
        </init-param>
        <init-param>
            <description>字体 Arial, Courier</description>
            <param-name>kaptcha.textproducer.font.names</param-name>
            <param-value>Arial, Courier</param-value>
        </init-param>
        <init-param>
            <description>字体大小 40px.</description>
            <param-name>kaptcha.textproducer.font.size</param-name>
            <param-value>40</param-value>
        </init-param>
        <init-param>
            <description>
                字体颜色,合法值: r,g,b 或者 white,black,blue.
            </description>
            <param-name>kaptcha.textproducer.font.color</param-name>
            <param-value>black</param-value>
        </init-param>
        <init-param>
            <description>文字间隔 2</description>
            <param-name>kaptcha.textproducer.char.space</param-name>
            <param-value>2</param-value>
        </init-param>
        <init-param>
            <description>干扰实现类</description>
            <param-name>kaptcha.noise.impl</param-name>
            <param-value>
                com.google.code.kaptcha.impl.DefaultNoise
            </param-value>
        </init-param>
        <init-param>
            <description>
                干扰颜色,合法值: r,g,b 或者 white,black,blue.
            </description>
            <param-name>kaptcha.noise.color</param-name>
            <param-value>black</param-value>
        </init-param>
        <init-param>
            <description>
                图片样式: 水纹com.google.code.kaptcha.impl.WaterRipple
                鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
                阴影com.google.code.kaptcha.impl.ShadowGimpy
            </description>
            <param-name>kaptcha.obscurificator.impl</param-name>
            <param-value>
                com.google.code.kaptcha.impl.WaterRipple
            </param-value>
        </init-param>
        <init-param>
            <description>背景实现类</description>
            <param-name>kaptcha.background.impl</param-name>
            <param-value>
                com.google.code.kaptcha.impl.DefaultBackground
            </param-value>
        </init-param>
        <init-param>
            <description>背景颜色渐变,开始颜色</description>
            <param-name>kaptcha.background.clear.from</param-name>
            <param-value>green</param-value>
        </init-param>
        <init-param>
            <description>背景颜色渐变,结束颜色</description>
            <param-name>kaptcha.background.clear.to</param-name>
            <param-value>white</param-value>
        </init-param>
        <init-param>
            <description>文字渲染器</description>
            <param-name>kaptcha.word.impl</param-name>
            <param-value>
                com.google.code.kaptcha.text.impl.DefaultWordRenderer
            </param-value>
        </init-param>
        <init-param>
            <description>
                session中存放验证码的key键
            </description>
            <param-name>kaptcha.session.key</param-name>
            <param-value>KAPTCHA_SESSION_KEY</param-value>
        </init-param>
        <init-param>
            <description>
                The date the kaptcha is generated is put into the
                HttpSession. This is the key value for that item in the
                session.
            </description>
            <param-name>kaptcha.session.date</param-name>
            <param-value>KAPTCHA_SESSION_DATE</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Kaptcha</servlet-name>
        <url-pattern>/randomcode.jpg</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

2、使用springboot+springmvc框架

这里新建一个maven项目,添加依赖

<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>  

controller:

@Controller
public class UserController {
    @Autowired
    private Producer captchaProducer;

    @RequestMapping("/ran/random")
    public void checkCode(HttpServletRequest request,HttpServletResponse response) throws IOException{
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            //生产验证码字符串并保存到session中
            String createText = captchaProducer.createText();
            request.getSession().setAttribute("checkCode", createText);
            //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
            BufferedImage challenge = captchaProducer.createImage(createText);
            ImageIO.write(challenge, "jpg", jpegOutputStream);
        } catch (IllegalArgumentException e) {
            response.sendError(response.SC_NOT_FOUND);
            return;
        }   

        //定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream =
                response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
}

配置类CaptchaConfig:

这里@value是为了将相关属性写进application.properties,避免硬编码,为了方便测试我先注掉

package com.allan.base;

import java.util.Properties;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
/**
 * 验证码配置类
 * @author zhangzhuo
 *
 */
@Configuration
public class CaptchaConfig {
    @Value("${kaptcha.border}")
    private  String  border;
    @Value("${kaptcha.border.color}")
    private  String  borderColor;
    @Value("${kaptcha.textproducer.font.color}")
    private  String  fontColor;
    @Value("${kaptcha.image.width}")
    private  String  imageWidth;
    @Value("${kaptcha.image.height}")
    private  String  imageHeight;
    @Value("${kaptcha.session.key}")
    private  String  sessionKey;
    @Value("${kaptcha.textproducer.char.length}")
    private  String  charLength;
    @Value("${kaptcha.textproducer.font.names}")
    private  String  fontNames;

    @Bean(name="captchaProducer")
    public DefaultKaptcha getKaptchaBean(){
        DefaultKaptcha defaultKaptcha=new DefaultKaptcha();
        Properties properties=new Properties();
      /*  properties.setProperty("kaptcha.border", border);
        properties.setProperty("kaptcha.border.color", borderColor);
        properties.setProperty("kaptcha.textproducer.font.color", fontColor);
        properties.setProperty("kaptcha.image.width", imageWidth);
        properties.setProperty("kaptcha.image.height", imageHeight);
        properties.setProperty("kaptcha.session.key", sessionKey);
        properties.setProperty("kaptcha.textproducer.char.length", charLength);
        properties.setProperty("kaptcha.textproducer.font.names", fontNames);
        properties.setProperty("kaptcha.textproducer.font.size", "30"); */
        properties.setProperty("kaptcha.border", "yes");
        properties.setProperty("kaptcha.border.color", "105,179,90");
        properties.setProperty("kaptcha.textproducer.font.color", "blue");
        properties.setProperty("kaptcha.image.width", "90");
        properties.setProperty("kaptcha.image.height", "28");
        properties.setProperty("kaptcha.textproducer.font.size", "28");
        properties.setProperty("kaptcha.session.key", "code");
        properties.setProperty("kaptcha.textproducer.char.length", "4");
        properties.setProperty("kaptcha.textproducer.char.space", "2");
        properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy");
        properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
        properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
        Config config=new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

启动类:

package com.allan.server;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
@EnableAutoConfiguration
@ComponentScan(basePackages = {"com.allan.controller","com.allan.service","com.allan.base"})
@MapperScan(basePackages = "com.allan.mapper")
public class StartApp {
    public static void main(String[] args) {
        SpringApplication.run(StartApp.class, args);
    }
}

jsp:

<p class="main">
      <label>验证码: </label> <input name="randomCode"
               onkeyup="enterSubmit(event)" placeholder="验证码"
                style="width: 105px;" maxlength="4" /> <span class="yzm-pic">
      <img src="/ran/random" alt="验证码,点击图片更换"
                            onclick="this.src='/ran/random?random='+Math.random();" />
                        </span>
</p>

最终的效果图:

最后说下springboot除了上面写代码的形式还可以写成下面的配置文件:

可以定义applicationcontext-check.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.xsd">
    <bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
        <property name="config">
            <bean class="com.google.code.kaptcha.util.Config">
                <constructor-arg type="java.util.Properties">
                    <props>
                        <prop key = "kaptcha.border ">yes</prop>
                            <prop key="kaptcha.border.color">105,179,90</prop>
                            <prop key="kaptcha.textproducer.font.color">blue</prop>
                            <prop key="kaptcha.image.width">100</prop>
                            <prop key="kaptcha.image.height">50</prop>
                            <prop key="kaptcha.textproducer.font.size">27</prop>
                            <prop key="kaptcha.session.key">code</prop>
                            <prop key="kaptcha.textproducer.char.length">4</prop>
                            <prop key="kaptcha.textproducer.font.names">宋体,楷体,微软雅黑</prop>
                            <prop key="kaptcha.textproducer.char.string">0123456789ABCEFGHIJKLMNOPQRSTUVWXYZ</prop>
                            <prop key="kaptcha.obscurificator.impl">com.google.code.kaptcha.impl.WaterRipple</prop>
                            <prop key="kaptcha.noise.color">black</prop>
                            <prop key="kaptcha.noise.impl">com.google.code.kaptcha.impl.DefaultNoise</prop>
                            <prop key="kaptcha.background.clear.from">185,56,213</prop>
                            <prop key="kaptcha.background.clear.to">white</prop>
                            <prop key="kaptcha.textproducer.char.space">3</prop>
                    </props>
                </constructor-arg>
            </bean>
        </property>
    </bean>  

</beans>  

如果写配置文件,这边在启动的时候需要引入配置文件

@ImportResource(locations={"classpath:applicationcontext-check.xml"})  

基本上就是这些,至于汉字组合或者计算形式的验证码,这边我们只要实现kaptcha.textproducer.impl和com.google.code.kaptcha.servlet.KaptchaServlet这两个类就行了,大家可以看下源码,很简单的。

相关的源码我会近期上传的。

浅谈JAVA验证码~的更多相关文章

  1. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

  2. 浅谈Java中的equals和==(转)

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...

  3. 浅谈Java中的对象和引用

    浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...

  4. 浅谈Java中的equals和==

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...

  5. 浅谈JAVA集合框架

    浅谈JAVA集合框架 Java提供了数种持有对象的方式,包括语言内置的Array,还有就是utilities中提供的容器类(container classes),又称群集类(collection cl ...

  6. 浅谈java性能分析

    浅谈java性能分析,效能分析 在老师强烈的要求下做了效能分析,对上次写过的词频统计的程序进行分析以及改进. 对于效能分析:我个人很浅显的认为就是程序的运行效率,代码的执行效率等等. java做性能测 ...

  7. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

  8. !! 浅谈Java学习方法和后期面试技巧

    浅谈Java学习方法和后期面试技巧 昨天查看3303回复33 部落用户大酋长 下面简单列举一下大家学习java的一个系统知识点的一些介绍 一.java基础部分:java基础的时候,有些知识点是非常重要 ...

  9. 浅谈Java中的深拷贝和浅拷贝

    转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...

随机推荐

  1. 2017华为机试题--Floyd算法

    小K是X区域的销售经理,他平常常驻"5"城市,并且经常要到"1"."2"."3"."4"." ...

  2. webx request注入单例增强实现

    由于在spring中request对象的scope限制导致了request对象无法直接注入到单例bean中,所以webx对其进行了增强实现,达到单例注入的目的. 实现原理大致如下: 1 启动时注册全局 ...

  3. 快速排序算法回顾 --冒泡排序Bubble Sort和快速排序Quick Sort(Python实现)

    冒泡排序的过程是首先将第一个记录的关键字和第二个记录的关键字进行比较,若为逆序,则将两个记录交换,然后比较第二个记录和第三个记录的关键字.以此类推,直至第n-1个记录和第n个记录的关键字进行过比较为止 ...

  4. 初学grunt压缩

    初学grunt 压缩,做个记录.备忘. [JS压缩] 先比较yui compressor 与 uglify  代码压缩, yui compressor,使用起来很简单.需要jdk. https://g ...

  5. python3和python2的区别部分

    字典没有iteritems(),只有items() py2items()返回的是列表,iteritems()返回的是迭代器 py3items()返回的是迭代器

  6. SourceTree 无法查看组织仓库

    error log: Pushing to remote: Repository not found. 在使用SourceTree进行版本控制,代替git命令行,而且作为免费 跨平台 功能完备的git ...

  7. Java Tomcat 启动失败的解决思路

    好久没写新博文了,离自己要求的每年几篇的目标也是渐行渐远. 最近在学习Java,也是从基础学习,因为我是一个.net开发人员,所以学习的成本相对低些.Java JDK,JRE,Tomact 的安装及配 ...

  8. javascript——数据类型

    在内存中,分为栈.堆.代码段.静态区,为了快速处理复杂的代码,在不同的区间储存不同的数据类型. 数据类型分为初始类型与引用类型,初始类型在栈中存储,变量赋值传值不传址,引用类型在堆中存储,传址不传值. ...

  9. Oracle空间查询 ORA-28595

    可使用数据库管理系统 (DBMS) 的结构化查询语言 (SQL).数据类型和表格式来处理地理数据库或安装了 ST_Geometry 类型的数据库中所存储的信息. 例如,在ArcMap中我们使用&quo ...

  10. Andriod中自定义Dialog样式的Activity点击空白处隐藏软件盘(Dialog不消失)

    一.需求触发场景: 项目中需要出发带有EditText的Dialog显示,要求在编辑完EditText时,点击Dilog的空白处隐藏软键盘.但是Dialog不会消失.示例如下: 二.实现方法: 发布需 ...