原创

验证码和图片下载思路分析

温馨提示:
本文最后更新于 2022年06月18日,已超过 8 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

验证码的思路分析

在页面中输出一张验证码

思路分析

  1. 画出一张图片
    1. 使用image对应的流对象来画图BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
    2. image对象中的画笔方法getGraphics()
      1. 设置图片的背景颜色
  2. 在图片上写上随机字符
    1. 利用random对象中的方法,来随机生成字符
    2. 利用graphics方法来设置随机字符
  3. 在图片上画上线条
    1. 利用random对象中的方法,来生成随机坐标
    2. 利用graphics来生成随机线条
  4. 输出存在于内存中的图片到浏览器
    1. 使用流将图片输出到浏览器

java代码实现

package com.rlf;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

/**
 * @author Mr.sun
 */
@WebServlet("/checkcode")
public class CheckCodeServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //创建一个对象,在内存中画图,代表验证码的图片对象
        int width = 100;
        int height = 50;
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        //美化图片
        //填充背景颜色
        Graphics graphics = image.getGraphics();
        //设置画笔的颜色
        graphics.setColor(Color.BLUE);
        graphics.fillRect(0,0,width,height);
        //画边框
        graphics.setColor(Color.RED);
        graphics.drawRect(0,0,width-1,height-1);
        //写验证码
        //输出到屏幕的码值
        String str = "123456789ABCDEFGHIJKLMNOPQWXYZabcdhjloiuytr";
        Random rand = new Random();
        for(int i = 1;i<=4;i++){
            int anInt = rand.nextInt(str.length());
            //获取字符
            char charAt = str.charAt(anInt);
            graphics.drawString(charAt+"",(width/4*i),height/2);
        }
        //画线
        graphics.setColor(Color.BLACK);
        for(int i = 1;i<=5;i++){
            int x1 = rand.nextInt(width);
            int x2 = rand.nextInt(width);
            int y2 = rand.nextInt(height);
            int y1 = rand.nextInt(height);
            graphics.drawLine(x1,y1,x2,y2);
        }
        //将图片输出到页面展示
        ImageIO.write(image,"jpg",resp.getOutputStream());

    }
}

浏览器端实现的功能

  • 点击图片切换验证码
    • 给图片绑定单击事件,单击的时候改变src的请求地址,实际上没有改变,知识重新请求了一边,但是由于浏览器的缓存原因,如果每一次的请求地址一样,浏览器就会默认加载缓存中的信息,所以需要设置一个值来改变请求时的src属性值,这个值需要时刻在变化,不然出现相同的值的时候就会加载浏览器的缓存,这样就达不到切花验证码的效果
  • 点击文字切换验证码
    • 这里和图片的一样,也是绑定单击事件

html代码实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        window.onload = function() {
            var image = document.getElementById("checkcode");
            image.onclick = function () {
                var date = new Date().getTime();
                image.src = "/day26/checkcode?" + date;
                var image2 = document.getElementById("check");
                image2.src = "/day26/checkcode?" + date;
            }
        }
    </script>
</head>
<body>
<img id="checkcode" src="/day26/checkcode" alt="">
<a id="check" href="">看不清,换一张</a>
</body>
</html>

image-20220326161056926

图片资源下载的思路分析

需求:点击图片的时候弹出下载提示框

  • 设置超链接请求对应的class类加载对应的下载方法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>图片下载</title>
</head>
<!--分析:超链接指向的资源,如果能被浏览器解析,在浏览器中展示,否则弹出下载提示框-->
<!--使用响应头设置资源的打开方式:content-disposition:attachment;filename="";-->
<!--1.定义页面,编辑超链接的src属性,传递资源的名称-->
<!--2. 定义servlet,获取文件名称,加载文件进内存-->
<!--3. 指定响应头-->
<!--4. 将数据输出-->
<body>
    <a href="/day26/download?filename=test.jpg">图片</a>
</body>
</html>

java代码实现思路

  1. 获取一张图片的地址
    1. 需要在更改html中代码的时候就自动更改java中对应的代码,来实现对不同资源的下载,因此就需要在html中指定出需要下载的文件名字,并且在java代码中获取对应的文件名字
    2. 在html中使用filename=test.jpg的方式来设置文件的名字
    3. 在java代码中通过获取html代码属性值的方式来获取filename对应的值getParameter("filename");
    4. 获取到了文件对应的文件名,这时就需要获取文件对应的真实路径getRealPath("WEB-INF/classes/img/" + filename);
    5. 获取到了文件真实的路径,这时就需要将文件加载进内存
  2. 将图片加载进内存
    1. 直接使用流对象
    2. 但是由于浏览器对于图片类信息是可以直接解析显示的,所以在浏览器中就不会弹出下载的提示,这是就需要对response的设置,设置响应头的type,这里需要使用filename来获取,设置响应头的disposition为:attachment;filename=,加上获取的文件名字
    3. 因为加载数据进内存和写出数据是在while循环中进行的所以上述步骤要在加载图片进内存的时候完成
  3. 将图片输出
    1. 使用流直接将图片输出到浏览器,这样就可以实现对图片的下载
package com.rlf;

import javax.servlet.ServletContext;
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.FileInputStream;
import java.io.IOException;

import static com.sun.xml.internal.ws.streaming.XMLStreamWriterUtil.getOutputStream;

/**
 * @author Mr.sun
 */
@WebServlet("/download")
public class Download extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求参数
        String filename = req.getParameter("filename");
        //使用字节输入流加载文件进内存
        //找到真实的服务器路径
        ServletContext context = getServletContext();
        String realPath = context.getRealPath("WEB-INF/classes/img/" + filename);
        //字节流关联
        FileInputStream fis = new FileInputStream(realPath);
        //将输入流的数据写出到输出流中
        //设置响应头
        //设置类型
        //获取mime类型
        String mimeType = context.getMimeType(filename);
        resp.setHeader("content-type","mimeType");
        //设置打开方式
        resp.setHeader("content-disposition","attachment;filename="+filename);
        ServletOutputStream outputStream = resp.getOutputStream();
        byte[] bytes = new byte[1024*8];
        int len = 0;
        while((len = fis.read(bytes))!=-1){
            outputStream.write(bytes, 0, len);
        }
        fis.close();
        outputStream.close();
    }
}

image-20220326161216216

正文到此结束