JAVA自绘验证码

这篇博客介绍了作者完成一个自绘验证码的作业过程,涉及到BufferedImage、Graphics和ImageIO类的使用。验证码要求包括数字和字母,字体颜色和大小随机,背景有干扰元素。难点在于将验证码写入浏览器,通过Servlet代码实现。
摘要由CSDN通过智能技术生成

前言

近期有个作业是需要自己绘制一个验证码,并布置到网页前端上。其中需要用到的类主要是BufferedImage、Graphics以及ImageIO,因为之前对于这3个类接触的并不多,所以就打算写一篇博客复习。

要求

  1. 验证码的字体一致
  2. 验证码的值包括[0-9a-zA-Z]
  3. 验证码的字体颜色、大小应该不一样
  4. 给验证码背部添加干扰元素
  5. 将验证码的值设置在session中,以便于验证

分析

  1. 通过BufferedImage类我们可以创建一个存在于内存的矩形框,方便我们对其自定义,选择具有8位像素的RGB颜色
BufferedImage image = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);
  1. 创建了BufferedImage实例后,可以通过实例获取其对应的画笔,即Graphics类
 Graphics graphics = image.getGraphics();
  1. 此后每次对画笔的操作,效果都会呈现在我们创建的矩形框中
	//           为画笔设置新的颜色
            graphics.setColor(new Color(bgr, bgg, bgb));
//            画笔绘画填充的整个范围
            graphics.fillRect(0,0, Width,Height);
//            给验证码添加背景干扰
            for (int i=0;i<20;i++){
                int line_x = random.nextInt(400);
                int line_y = random.nextInt(200);
                int line_x1 = line_x + 100;
                int line_y1 = line_y + 100;
                graphics.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
                graphics.drawOval(line_x,line_y, random.nextInt(100),random.nextInt(100));
                //                graphics.drawLine(line_x,line_y, line_x1, line_y1);
            }

//            生成验证码的值,并将每个值的颜色大小设置成随机
            for (int i=0;i<4;i++){
                int font_r = random.nextInt(127)+128;
                int font_g = random.nextInt(127)+128;
                int font_b = random.nextInt(127)+128;
                // 设置字体颜色
                graphics.setColor(new Color(font_r, font_g, font_b));
                int index = random.nextInt(61);
                code.append(chars.charAt(index));
                // 设置字体大小,样式
                Font font = new Font("HGKY_CNKI",Font.PLAIN,random.nextInt(100)+50);
                graphics.setFont(font);
                graphics.drawString(String.valueOf(chars.charAt(index)), i*100,150);
            }
  1. 最后通过ImageIO流,将绘制好的图片写出。
  2. 获取验证码的值,并设置在session中

VerifyImg类 完整代码

	public class VerifyImg {
//        验证码大小
        final int Width = 400;
        final int Height = 200;
        final String chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

//        验证码的值
        private StringBuffer code = null;
        // 存放字节图片
        private ByteArrayInputStream imgInputStream = null;

        private VerifyImg(){

        }

        public static VerifyImg getInstance(){
            return new VerifyImg();
        }

        public void Create(){
            Random random = new Random();
            code = new StringBuffer();
//            背景颜色的rgb,通过随机数决定颜色变化,实现每次刷新背景色都不一样
            int bgr = random.nextInt(127);
            int bgg = random.nextInt(127);
            int bgb = random.nextInt(127);
            BufferedImage image = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);
            Graphics graphics = image.getGraphics();
//            给验证码添加背景色
            graphics.setColor(new Color(bgr, bgg, bgb));
//            填充背景色的范围
            graphics.fillRect(0,0, Width,Height);
//            给验证码添加背景干扰
            for (int i=0;i<20;i++){
                int line_x = random.nextInt(400);
                int line_y = random.nextInt(200);
                int line_x1 = line_x + 100;
                int line_y1 = line_y + 100;
                graphics.setColor(new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
                graphics.drawOval(line_x,line_y, random.nextInt(100),random.nextInt(100));
                //                graphics.drawLine(line_x,line_y, line_x1, line_y1);
            }

//            生成验证码的值,并将每个值的颜色大小设置成随机
            for (int i=0;i<4;i++){
                int font_r = random.nextInt(127)+128;
                int font_g = random.nextInt(127)+128;
                int font_b = random.nextInt(127)+128;
                graphics.setColor(new Color(font_r, font_g, font_b));
                int index = random.nextInt(61);
                code.append(chars.charAt(index));
                Font font = new Font("HGKY_CNKI",Font.PLAIN,random.nextInt(100)+50);
                graphics.setFont(font);
                graphics.drawString(String.valueOf(chars.charAt(index)), i*100,150);
            }
            graphics.dispose();
            ByteArrayInputStream input = null;
//            字节数组输出流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            try {
                //创建image输出流
                ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(out);
                //将image写到
                ImageIO.write(image,"JPEG",imageOutputStream);
                imageOutputStream.close();
                input = new ByteArrayInputStream(out.toByteArray());
                this.imgInputStream = input;
            }catch (Exception e){
                System.out.println("输出失败");
            }
        }

        public StringBuffer getCode(){
            return this.code;
    }

        public ByteArrayInputStream getImgInputStream(){
            return this.imgInputStream;
    }
}

难点

在实现过程中遇到的主要问题就是对于ImageIO的操作,在ImageIO中有一个write方法可以帮助我们将操作的bufferedimage类写出到指定位置

 	ImageIO.write(image,"JPEG",new File(path:)) // 表示将内存中的image写到本地磁盘的某个位置

可实现效果如下:
在这里插入图片描述

但是题目要求的是将生成的验证码写到浏览器上,显然我们还要换一种方式来实现,这里就需要了解一下ByteArrayInputStream,ByteArrayOutputStream。

  • ByteArrayOutputStream是一个可以存放字节数组的输出流,缓冲区会随着数据的增长自动扩大,可以使用toByteArray和toString方法获取字节数组的值。
  • ByteArrayInputStream包含一个内部缓冲区,该缓冲区包含可以从流中读取的字节。 内部计数器跟踪由read方法提供的下一个字节。
	ByteArrayOutputStream out = new ByteArrayOutputStream();
 	ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(out);
 //在这里我把out的上面再次封装了一层image流,当我们用ImageIO.write()
 //方法时,指定流向为imageOutputStream,然后因为out具有存放字节数组的属性,
 //所以图片就可以成功写进了字节数组中。
	input = new ByteArrayInputStream(out.toByteArray());
	//这时候将字节数组的值取出,并创建input对象,就可以方便我们从流中读取字节。
	//最后就能成功在浏览器上了
	

Servlet代码

@WebServlet(name = "VerifyCode", value = "/verify-code")
public class Verifycode extends HttpServlet {
    public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        VerifyImg verifyImg = VerifyImg.getInstance();
        verifyImg.Create();
        ByteArrayInputStream imgInputStream = verifyImg.getImgInputStream();
        StringBuffer verify_code = verifyImg.getCode();
        req.getSession().setAttribute("Verify-Code",verify_code);
        ServletOutputStream respOutputStream = resp.getOutputStream();
        resp.setContentType("image/jpeg");
        byte bytes[] = new byte[1024];
        while (imgInputStream.read(bytes)!=-1){
            respOutputStream.write(bytes);
        }
    }
}

后记

有理解错误的地方欢迎大家来指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值