Servlet之图形验证码工具类封装

    通常,在网站开发时,在登录、注册以及一些敏感操作的时候,为了防止服务器被暴力请求,或爬虫爬取,可以使用验证码进行过滤,减轻服务器的压力。
    现在常见的验证码技术有:短信验证码、邮箱验证码、图形验证码等,例如:要求输入随机字符序列、数字计算结果、图片选择验证、拼图互动验证等等。
    图像验证码是通过绘图技术实现的,严格意义上来说:是在服务器端通过调用画笔对象,将一系列“字符串+干扰图形”绘制到某个Image图像实例上,并将该图像通过IO流通道返还给前端页面显示实现的。当然也可以完全基于前端的canvas绘图实现。

Java图像验证码的相关实现类

    对于Java编程语言来说,图形验证码图片资源的创建需要主要借助Image类(图像)、Font字体、Color颜色类、Graphics类()、IO流类实现。

Image抽象类与图像坐标系

    Image抽象类是所有表示图形图像的父类,并且图像的底层创建是与系统平台相关的。Image抽象类的继承结构如下图所示。
    Image图像坐标系的原点在左上角,这一点可参见:图像像素值处理

The abstract class Image is the superclass of all classes that represent graphical 
images. The image must be obtained in a platform-specific manner.

请添加图片描述

BufferedImage类

    BufferedImage类表示一个带有可访问图像数据缓冲区的图像,该对象由ColorModel和图像数据Raster两个组件组成。

ColorModel组件

    ①ColorModel组件:用于存储图像的像素数据,该类封装了将像素值转换为颜色分量(例如:R、G、B)和alpha透明度分量的方法。为了将一个Image图像渲染到屏幕、打印机等显示设备,像素值必须被转换为颜色和透明度值,而ColorModel作为这些方法的参数或返回值。

The ColorModel abstract class encapsulates the methods for translating a pixel value to color components (for example, red, green, and blue) and an alpha component.

Raster组件

    ②Raster是表示矩形像素数组的类,用于存储图像的颜色值数据。该类封装了一个用于存储颜色样本的DataBuffer、一个描述在DataBuffer中定位给定样本值的SampleModel对象。
    那么,如何理解这个矩形像素数组呢?
    由于像素点的位置是通过坐标值唯一标识的,所示这个矩形像素数组可以理解为一个包含全部像素点的平面区域(或者最小外接矩形),它是由minX、minY、、宽度、高度所定义的Rectangle矩形类对象,可以通过调用getBounds()方法获得,其中:minX、minY对应对应坐标系的原点(左上角的(0,0)位置),也就是接下来我们要通过BufferedImage定义的图像原点和宽高值。

BufferedImage类的基本操作

    该类的基本操作,可以参考另一位博主的文章:《BufferedImage 学习》,写的很详细。

Graphics抽象类

    Graphics类是所有图形上下文的抽象基类,允许应用程序绘制到各种设备上实现的组件上,也可以绘制到屏外图像上。此次要实现的图形验证码就属于后者。
    由于Graphics是一个抽象类,无法直接创建对象,但是可以通过Image对象的getGraphics()方法获取一个对象。
    通过Graphics对象,可以绘制2D或者3D对象,到输出设备/图片上。这些可绘制的对象包括:拥有特定字体(通过Font类定义)、特定颜色(通过Color类定义)的文字、图形图形等。

Java图像验证码工具类

    这部分就不解释了,直接上代码,对于某些方法可以直接查看jdk文档理解。

package com.xwd.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

/**
 * @ClassName VerifyCodeUtil---[生成验证码工具]
 * @Description: com.xwd.util
 * @Auther: xiwd
 * @Date: 2022/2/11 - 02 - 11 - 16:47
 * @version: 1.0
 */
public class VerifyCodeUtil {
    //methods
    private static final String originCode="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";//验证码原始字符序列
    private static final Random random=new Random();//随机数对象
    private static final Color[] colors=new Color[]{Color.WHITE,Color.ORANGE,Color.RED,Color.GREEN};//定制颜色
    public static final int type_verifyImage=0;//不带干扰线的验证码图像
    public static final int type_verifyImage_withLine = 1;//带干扰线的验证码图像

    /**
     * 随机生成四位数验证码
     * @return 验证码字符序列
     */
    public static String generateVerifyCode(){
        StringBuilder verifyCode=new StringBuilder();
        for (int i = 0; i < 4; i++) {
            verifyCode.append(originCode.charAt(random.nextInt(originCode.length())));
        }
        return verifyCode.toString();
    }

    /**
     * 根据Image尺寸,生成验证码Image对象
     * @param width 宽度
     * @param height 高度
     * @param verifyCode 验证码
     */
    public static Image generateVerifyImage(int width, int height, String verifyCode){
        Image image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);//创建图像
        Graphics graphics = image.getGraphics();//获取画笔对象
        //根据Image图像宽高计算必要参数
        int fontSize = width/5;//计算字体大小
        int codeStartPos_x = fontSize/2;
        int codeStartPos_y = height/2+fontSize/2;
        //设置背景填充颜色
        graphics.setColor(Color.pink);
        graphics.fillRect(0,0,width,height);
        //设置字体样式
        Font font =new Font("gothic",Font.PLAIN,fontSize);
        graphics.setFont(font);
        //设置字体颜色
        graphics.setColor(Color.blue);
        //将验证码写入图像
        for (int i = 0; i < 4; i++) {
            graphics.drawString(verifyCode.charAt(i)+"",codeStartPos_x+fontSize*i,codeStartPos_y);//填充验证码
        }
        return image;
    }

    /**
     * 根据Image尺寸,生成带有干扰线的验证码Image对象
     * @param width Image宽度
     * @param height Image高度
     * @param verifyCode 验证码
     * @return Image对象
     */
    public static Image generateVerifyImageWithLines(int width,int height, String verifyCode){
        Image image = generateVerifyImage(width, height,verifyCode);
        Graphics graphics = image.getGraphics();//获取画笔对象
        //定义坐标变量
        int x1,x2,y1,y2;
        //添加干扰线
        for (int i = 0; i < 30; i++) {
             x1 = random.nextInt(width);
             x2 = random.nextInt(width);
             y1 = random.nextInt(height);
             y2 = random.nextInt(height);
            graphics.setColor(colors[random.nextInt(colors.length)]);//设置一定范围的随机色
            graphics.drawLine(x1,y1,x2,y2);//绘制干扰线
        }
        //返回Image对象
        return image;
    }

    /**
     * 根据参数获取指定类型的验证码Image对象
     * 可选值:
     *      type_verifyImage
     *      type_verifyImage_withLine
     * @param width Image宽度
     * @param height Image高度
     * @param verifyCode 验证码
     * @param type_image Image类型
     * @return RenderedImage对象
     */
    public static RenderedImage getVerifyImage(int width,int height,String verifyCode,int type_image){
        switch (type_image){
            case type_verifyImage:{
                return (RenderedImage) generateVerifyImage(width, height,verifyCode);
            }
            case type_verifyImage_withLine:{
                return (RenderedImage) generateVerifyImageWithLines(width, height,verifyCode);
            }
            default:
                return null;
        }
    }

    /**
     * 输出指定类型的Image验证码图像到指定流中
     * @param width Image宽度
     * @param height Image高度
     * @param verifyCode 验证码
     * @param outputStream 输出流对象
     * @return 是否执行成功-true-success;false-failed
     * @throws IOException
     */
    public static boolean genereteVerifyCodeImage(int width, int height,String verifyCode,int type_image, OutputStream outputStream) throws IOException {
        //输出图片
        return ImageIO.write(getVerifyImage(width, height, verifyCode, type_image),"jpg",outputStream);
    }


    /**
     * 输出指定类型的Image验证码图像到指定流中——图像尺寸:100*50
     * @param outputStream 输出流对象
     * @return 是否执行成功-true-success;false-failed
     * @throws IOException
     */
    public static boolean genereteVerifyCodeImage(String verifyCode,int type_image, OutputStream outputStream) throws IOException {
        //输出图片
        return ImageIO.write(getVerifyImage(100, 50,verifyCode, type_image),"jpg",outputStream);
    }
}

验证码工具类&Servlet配置使用

定义Servlet类

package com.xwd.servlet;

import com.xwd.util.VerifyCodeUtil;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @ClassName VerifyCodeServlet
 * @Description: com.xwd.servlet
 * @Auther: xiwd
 * @Date: 2022/2/11 - 02 - 11 - 16:07
 * @version: 1.0
 */
@WebServlet(
        name = "verifycode",
        value = {
                "/verifycode"
        }
)
public class VerifyCodeServlet extends HttpServlet {
    //methods

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //super.doGet(req, resp);
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //super.doPost(req, resp);
        req.setCharacterEncoding("UTF-8");
        resp.setContentType("image/jpeg;charset=UTF-8");
        boolean flag=false;
        //获取验证码
        String verifyCode = VerifyCodeUtil.generateVerifyCode();
        //获取输出流对象
        ServletOutputStream outputStream = resp.getOutputStream();
        try{
            //获取请求参数
            int width = Integer.valueOf(req.getParameter("width"));
            int height = Integer.valueOf(req.getParameter("height"));
            //返回验证码Image对象
            flag = VerifyCodeUtil.genereteVerifyCodeImage(width, height, verifyCode,VerifyCodeUtil.type_verifyImage_withLine, outputStream);
        }catch (Exception e){
            //自动输出宽100,高50的图像
            flag = VerifyCodeUtil.genereteVerifyCodeImage(verifyCode,VerifyCodeUtil.type_verifyImage_withLine, outputStream);
        }
        if (flag){
            System.out.println("SUCCESS!");
        }else
            System.out.println("FAILED!");
    }
}

测试

    (1)返回默认宽高100*50的图像验证码图像,

在这里插入图片描述
    (2)返回指定宽高120*60的图像验证码图像,
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是席木木啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值