小博老师解析Java核心技术点-验证码制作

筅森魡賤 提交于 2019-12-04 08:55:02

[理论知识]

java程序开发中,要显示一张图片,主要有两种方式。第一种是基于现成图片,这种方式比较常见也比较简单。第二种是使用java中java.awt包和com.sun.image包中的绘图技术,使用代码绘制出一张图片,这种技术一般适用于图片并非固定、重复使用率较低的场景,比如验证码、图片加水印、生成缩略图、绘制各种数据分析图(柱状图、饼图、线性图等),这些图片并不是固定的,而是根据数据的改变而随时变化的。

[步骤解读一]绘制验证码

本文中,小博老师就为大家解析一下,如何使用java绘图技术来制作验证码,由于验证码的功能比较常用,代码又比较繁琐,因此小博老师先为大家封装一个Identifying类,以后要使用验证码就可以直接调用它了,核心代码如下:

package com.bwf.framework.javaee.imageutils;

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics2D;

import java.awt.image.BufferedImage;

import java.io.IOException;

import java.util.ArrayList;

import java.util.Collections;

import java.util.Random;

import javax.servlet.ServletException;

import javax.servlet.ServletOutputStream;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import com.sun.image.codec.jpeg.JPEGCodec;

import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**

 * 验证码图片生成Servlet类,直接调用该Servlet即可使用 取值的时候调用session.getAttribute("code")得到生成的值

 * @author 博为峰-小博老师

 * @time 2016-11-1 下午14:26:00

 */

public class Identifying extends HttpServlet {

       public Identifying(HttpServletRequest request, HttpServletResponse response){

              this.setRequest(request);

              this.setResponse(response);

       }

 

       private static final long serialVersionUID = 1L; // 对象序列号

       private int width = 120; // 画布宽度(px)

       private int height = 30; // 画布高度(px)

       private int lineNum = 150; // 干扰线数量

       private int pointNum = 100; // 干扰点数量

       private int wordNum = 4; // 验证码字符个数

       private HttpServletRequest request; // 当前请求对象

       private HttpServletResponse response; // 当前响应对象

       private String sessionName = "code"; // 正确验证码存放在Session对象中的key名称

 

       /**

        * 获取范围内的随机颜色

        * @param fc  颜色范围的最大值(0~255)

        * @param bc 颜色范围的最小值(0~255)

        * @return 随机颜色值

        */

       private Color getRandColor(int fc, int bc) {

              Random random = new Random();

              if (fc > 255)

                     fc = 255;

              if (fc < 0)

                     fc = 0;

              if (bc > 255)

                     bc = 255;

              if (bc < 0)

                     bc = 0;

              int r = fc + random.nextInt(bc - fc);

              int g = fc + random.nextInt(bc - fc);

              int b = fc + random.nextInt(bc - fc);

              return new Color(r, g, b);

       }

 

       /**

        * 绘制验证码图片

        */

       public void create() throws IOException, ServletException {

              // 设置输出类型为图片

              response.setContentType("image/jpeg");

              // 获取画布宽度和高度

              int width = this.width;

              int height = this.height;

              // 产生随机数

              Random r = new Random();

              // 产生缓冲画布

              BufferedImage imgbuf = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

              // 取得缓冲的绘制环境

              Graphics2D g = imgbuf.createGraphics();

              // 设置笔触颜色 用来填充画布的颜色

              g.setColor(getRandColor(200, 250));

              // 填充画布

              g.fillRect(0, 0, width, height);

 

              // 设计笔触颜色 用来绘制干扰线

              g.setColor(getRandColor(160, 200));

              // 随机产生lineNum条干扰线,使图象中的认证码不易被其它程序探测到

              for (int i = 0; i < this.lineNum; i++) {

                     int x = r.nextInt(width); // 干扰线起始点x轴坐标

                     int y = r.nextInt(height); // 干扰线起始点y轴坐标

                     int xl = r.nextInt(12); // 干扰线结束点x轴坐标

                     int yl = r.nextInt(12); // 干扰线结束点y轴坐标

                     g.drawLine(x, y, x + xl, y + yl); // 绘制干扰线

              }

 

              // 设置笔触颜色 用来绘制干扰点

              g.setColor(getRandColor(120, 240));

              // 随机产生pointNum个干扰点,使图像中的验证码不易被其他分析程序探测到

              for (int i = 0; i < this.pointNum; i++) {

                     int x = r.nextInt(width); // 设置干扰点中心点x轴坐标

                     int y = r.nextInt(height); // 设置干扰点中心点y轴坐标

                     g.drawOval(x, y, 0, 0); // 绘制干扰点,半径0,起始角度0

              }

 

              // 设置文字样式 用来绘制验证码字符

              g.setFont(new Font("Times New Roman", Font.PLAIN, 18));

              // 准备一个ArrayList 用于存放验证码字符库

              ArrayList libs = new ArrayList();

              // 准备一个char[] 列出验证码字符库

              char[] arr = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',

                            'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',

                            'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6','7', '8', '9' };

              // 将char[]中的验证码字符 存放到 ArrayList中

              for (int i = 0; i <= arr.length - 1; i++) {

                     libs.add(arr[i] + "");

              }

              // 随机打乱顺序

              Collections.shuffle(libs);

              // 定义字符串 用于拼接正确验证码

              String scode = "";

              // 循环出wordNum个验证码字符

              for (int i = 0; i < this.wordNum; i++) {

                     // 从随机验证码字符库 抽取一个验证码字符

                     String rand = String.valueOf(libs.get(i));

                     // 拼接正确验证码

                     scode += rand;

                     // 设置笔触颜色 用于绘制验证码字符

                     g.setColor(new Color(20 + r.nextInt(110), 20 + r.nextInt(110), 20 + r.nextInt(110)));

                     // 绘制验证码字符

                     g.drawString(rand, (this.width / this.wordNum / 2 + 12) * i + (this.width / this.wordNum / 2),this.height / 2 + 6);

              }

              // 将正确验证码存放到Session对象中

              request.getSession().setAttribute(this.sessionName, scode);

              // 得到HTTP的流

              ServletOutputStream out = response.getOutputStream();

              // 产生JPEG的图像加码器

              JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);

              // 将图像画布内容转码

              encoder.encode(imgbuf);

              // 输出图像

              out.flush();

       }

……省略getter和setter……

}

然后我们在一个Servlet,实例化Identifying对象,调用create()方法,即可显示出一个验证码图片,核心代码如下:

@WebServlet("/BWFIdentifying")

public class BWFIdentifyingServlet extends HttpServlet {

       protected void doGet(HttpServletRequest request, HttpServletResponse response)  throws ServletException, IOException {

              Identifying iden = new Identifying(request, response);

              iden.create();

       }

}

浏览器访问效果如下:

 

 

[步骤解读二]在登录页面中引入验证码

接下来我们制作一个简单的登录页面,引入验证码,我们创建一个jsp,核心代码如下:

<body>

       <form action="BWFCheckLogin" method="post">

              账户名称:<input type="text" name="username"/><br/><br/>

              账户密码:<input type="password" name="password"/><br/><br/>

              验证&nbsp;码:<input type="text" name="iden" style="width:60px;"/>

                     <img src="BWFIdentifying" title="看不清?点击换一张!" style="cursor:pointer;" id="iden" /><br/><br/>

              <input type="submit" value="登  录"/>

       </form>

</body>

访问jsp页面效果如下:

 

 

为了实现验证码图片点击后可以自动更换一张验证码的效果,我们在该jsp页面中增加javascript,核心代码如下:

<script>

window.onload=function(){

       document.getElementById("iden").onclick=function(){

              this.src="BWFIdentifying?a="+Math.random();

       }

}

</script>

其中在URL中传递参数a,使用随机数作为值,是为了让该Servlet认为每次都是新的请求。

这样,我们的验证码效果基本就做完了,当用户点击登录按钮,提交页面后,我们只需要获取表单提交的用户填写的验证码,然后从Session对象(默认key为“Code”)获取正确的验证码,进行比对即可。

[步骤解读三]Identifying类的常用方法

小博老师为大家封装的Identifying类,除了上述默认使用方式,还可以按照自己的需求,设置常用参数,例如:

@WebServlet("/BWFIdentifying")

public class BWFIdentifyingServlet extends HttpServlet {

       protected void doGet(HttpServletRequest request, HttpServletResponse response)  throws ServletException, IOException {

              Identifying iden = new Identifying(request, response);

              iden.setWidth(300);                              // 设置验证码画布宽度

              iden.setHeight(50);                   // 设置验证码画布高度

              iden.setLineNum(30);               // 设置干扰线数量

              iden.setPointNum(50);              // 设置干扰点属相

              iden.setWordNum(6);               // 设置验证码字符数量

// 设置正确验证码存放Session对象的key名称

              iden.setSessionName("iden");           i

den.create();

       }

}

访问后效果:

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!