提示:图片压缩下载

SpringBoot+Vue批量下载图片压缩包


前言

项目中遇到上传的图片需要下载下来,并且是以压缩包的格式。因此记录下来,给自己以及小伙伴们。


提示:以下是本篇文章正文内容,下面案例可供参考

后台正文

controller

/**
 * 教师信息Controller
 *
 * @author milletsoft
 * @date 2022-08-30
 */
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@RestController
@RequestMapping("/jsgl/jsxxb")
public class JsJsxxbController extends BaseController {
	/**
	* 导出照片
	*/
	@PostMapping("/downloadJSImg")
	public void downJSImg(@RequestBody JsJsxxb jsJsxxb){
	   jsJsxxbService.downloadJSImg(jsJsxxb);
	}
}

impl

/**
     * 教师照片导出
     *
     * @param jsJsxxb  导出教师照片
     */
    @Override
    public void downloadJSImg(JsJsxxb jsJsxxb) {
        String namingFormat = jsJsxxb.getDcmmgs();
        //根据条件先查询符合条件的数据
        List<JsJsxxb> list = jsJsxxbMapper.selectDownLoadImg(jsJsxxb);
        //声明一个存储路径的List
        List<Map<String, String>> paths = new ArrayList<Map<String, String>>();
        list.forEach(JsJsxxb -> {
            String imagePrefix = getImagePrefix(JsJsxxb,namingFormat);
            paths.add(GenerateImageUtil.GenerateImage(GenerateImageUtil.ByteStreamToBase64(JsJsxxb.getTxs()),imagePrefix));
        });
        try {
            DownloadZipUtil.download(paths,"教师照片_"+System.currentTimeMillis(),response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

提示:生成图片的格式也可以控制 png jpg 1.我的代码中 namingFormat 是导出的命名格式,前端选择是身份证那就获取用户身份证号作为生成的图片的名称。例如: 12345678901234567.png
2.list.forEach 去遍历查询回来的数据 。getImagePrefix方法中会判断namingFormat ,为空就获取当前时间戳作为生成图片的名称。例如: 1294890876859.png 代码如下:

/**
     * 得到图像前缀
     *
     *  JsJsxxb jsJsxxb
     */
    public String getImagePrefix(JsJsxxb jsJsxxb, String namingFormat) {
        String prefix = new String();
        if (StringUtils.isNotBlank(namingFormat)){
            switch (namingFormat) {
                case "zgh": {
                    prefix = jsJsxxb.getZgh();
                    break;
                }
                case "sfzh": {
                    prefix = jsJsxxb.getSfzh();
                    break;
                }
                default: {
                    prefix = String.valueOf(System.currentTimeMillis());
                }
            }
        }else{
            prefix = String.valueOf(System.currentTimeMillis());
        }
        return prefix;
    }

生成图片。代码如下:

paths.add(GenerateImageUtil.GenerateImage(GenerateImageUtil.ByteStreamToBase64(JsJsxxb.getTxs()),imagePrefix));

生成的图片也先要转为Base64字符串

//就是这串代码
GenerateImageUtil.ByteStreamToBase64(JsJsxxb.getTxs())

生成图片

//就是这串代码 需要两个参数,一个是图片的Base64字符串,一个是生成图片的名称
GenerateImageUtil.GenerateImage()

工具类代码:

import com.ruoyi.common.utils.StringUtils;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
/**
 * 生成图片工具类
 * Created by gs01 on 2022-09-07.
 */
public class GenerateImageUtil {

    /**
     * Base64字符串进行解码并生成图片
     *
     */
    public static HashMap<String, String> GenerateImage(String imgStr, String namingFormat) {
        if (imgStr == null) // 图像数据为空
            return null;
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            // Base64解码
            byte[] b = decoder.decodeBuffer(imgStr);
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {// 调整异常数据
                    b[i] += 256;
                }
            }
            //生成图片名称
            String imgFilePath;
            if (StringUtils.isNotBlank(namingFormat)){
                imgFilePath = "d://"+namingFormat+".jpg";
            }else{
                imgFilePath = "d://"+System.currentTimeMillis()+".jpg";
            }
            //将生成的图片的路径存到Map集合
            HashMap<String, String> map = new HashMap<>();
            map.put("filePath",imgFilePath);
            OutputStream out = new FileOutputStream(imgFilePath);
            out.write(b);
            out.flush();
            out.close();
//            return true;
            return map;
        } catch (Exception e) {
            return null;
        }
    }
    /**
     * 字节流转Base64
     *
     */
    public static String ByteStreamToBase64(byte[] array){
        String imgBase64 = "";
        byte[] zpBlob = array;
        if (zpBlob != null) {
            byte[] encodeBase64 = Base64.encodeBase64(zpBlob);
            //Base64图片
            imgBase64 = new String((encodeBase64));
        }
        return imgBase64;
    }
}

到这里图片就生成了,在你的D盘下。下面这段代码就是生成的路径:

//生成图片名称
String imgFilePath;
if (StringUtils.isNotBlank(namingFormat)){
	//后面的 .jpg就是生成的图片的格式
    imgFilePath = "d://"+namingFormat+".jpg";
}else{
	//后面的 .jpg就是生成的图片的格式
    imgFilePath = "d://"+System.currentTimeMillis()+".jpg";
}

然后就是去调用压缩工具类压缩图片

try {
    DownloadZipUtil.download(paths,"教师照片_"+System.currentTimeMillis(),response);
} catch (Exception e) {
    e.printStackTrace();
}

“教师照片_”+System.currentTimeMillis() 是压缩包文件名称

下面是压缩包工具类 代码如下:

import com.ruoyi.framework.config.RuoYiConfig;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
 * @Author: autumn
 * @Date: 2022/4/2
 */
public class DownloadZipUtil {
    public static void download(List<Map<String, String>> paths,String zipName,HttpServletResponse response) throws Exception{
        if (paths.size() != 0) {
            // 创建临时路径,存放压缩文件
            String zipFilePath = RuoYiConfig.getProfile()+"/temp.zip";
            // 压缩输出流,包装流,将临时文件输出流包装成压缩流,将所有文件输出到这里,打成zip包
            ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFilePath));
            // 循环调用压缩文件方法,将一个一个需要下载的文件打入压缩文件包
            for (Map<String, String> path : paths) {
                // 该方法在下面定义
                try {
                    fileToZip(path, zipOut);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 压缩完成后,关闭压缩流
            zipOut.close();
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-Disposition","filename=" + percentEncode(zipName));
            response.setHeader(" Content-Type","application/octet-stream;charset=UTF-8");
            //该流不可以手动关闭,手动关闭下载会出问题,下载完成后会自动关闭
            ServletOutputStream outputStream = response.getOutputStream();
            FileInputStream inputStream = new FileInputStream(zipFilePath);
            // 如果是SpringBoot框架,在这个路径
            // org.apache.tomcat.util.http.fileupload.IOUtils产品
            // 否则需要自主引入apache的 commons-io依赖
            // copy方法为文件复制,在这里直接实现了下载效果
            IOUtils.copy(inputStream, outputStream);
            // 关闭输入流
            inputStream.close();
            //下载完成之后,删掉这个zip包
            File fileTempZip = new File(zipFilePath);
            fileTempZip.delete();
        }
    }
    public static String percentEncode(String s) throws UnsupportedEncodingException{
        String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
        return encode.replaceAll("\\+", "%20");
    }

    public static void fileToZip(Map<String, String> filePath,ZipOutputStream zipOut) throws IOException {
        // 需要压缩的文件
        File file = new File(filePath.get("filePath"));
        // 获取文件名称,如果有特殊命名需求,可以将参数列表拓展,传fileName
        String fileName = file.getName();
        FileInputStream fileInput = new FileInputStream(filePath.get("filePath"));
        // 缓冲
        byte[] bufferArea = new byte[1024 * 10];
        BufferedInputStream bufferStream = new BufferedInputStream(fileInput, 1024 * 10);
        // 将当前文件作为一个zip实体写入压缩流,fileName代表压缩文件中的文件名称
        String[] split = fileName.split("\\.");
        //压缩的图片的名称
//        String newFileName = fileName+"."+split[1];
//        String ss = fileName.substring(0,fileName.lastIndexOf("."));
        zipOut.putNextEntry(new ZipEntry(fileName));
        int length = 0;
        // 最常规IO操作,不必紧张
        while ((length = bufferStream.read(bufferArea, 0, 1024 * 10)) != -1) {
            zipOut.write(bufferArea, 0, length);
        }
        //关闭流
        fileInput.close();
        // 需要注意的是缓冲流必须要关闭流,否则输出无效
        bufferStream.close();
        // 压缩流不必关闭,使用完后再关
        File f = new File (String.valueOf(file));
		
		//压缩文件生成后把磁盘生成的图片删除
        //图片存在,可执行删除操作
        if (f.exists()==true){
            Boolean flag = false;
            flag = file.delete();
            //成功删除图片
            if (flag){
                //删除失败
            }else {
            }
            //图片不存在,终止操作
        }else{
        }
    }
}

到这里图片压缩包就生成了

前端正文

代码如下(示例):

//导出教师照片
 toDownLoadTeacherPhoto(){
   axios({
     contentType:'application/json;charset=UTF-8',
     method: 'post',
     url: "/dev-api/jsgl/jsxxb/downloadJSImg",//你的下载的接口路径
     data: this.queryParams,//放参数的 图片命名格式啊
     type:'json',
     responseType: 'blob',
     headers: { 'Authorization': 'Bearer ' + getToken() },
   }).then(async (res) => {
     const blob = new Blob([res.data],
       { type: 'application/zip' }
     )
     var downloadElement = document.createElement('a')//创建一个a 虚拟标签
     var href = window.URL.createObjectURL(blob) // 创建下载的链接
     downloadElement.href = href
     downloadElement.download =
       decodeURI(
         res.headers['content-disposition'].split(' ')[0].replace("filename=","")
         // '失败明细.txt'
       ) || '' // 下载后文件名
     document.body.appendChild(downloadElement)
     downloadElement.click() // 点击下载
     document.body.removeChild(downloadElement) // 下载完成移除元素
     window.URL.revokeObjectURL(href);
   })
 },

谷歌下载之后会直接打开,火狐会在左下角显示压缩包
完事。有建议的小伙伴或者有问题的小伙伴可以留言,感谢童鞋的浏览。

总结

1.图片生成也需要先转为Base64字符串
2.生成的图片和压缩包要记得删除
3.response的响应一定要设置。
4.图片,压缩包,生成路径
5.图片名称,图片格式