批量导出二维码并生成压缩文件

生成二维码

第一步:导依赖包(使用的是Qrcode的方法)


 <!--生成二维码,这个jar包可能不容易下载,需要手动将jar包放入maven仓库里-->
   <dependency>
         <groupId>Qrcode_swetake</groupId>
         <artifactId>Qrcode_swetake</artifactId>
         <version>1.0</version>
   </dependency>
 <!--base64流,应用将二维码转为base64流-->
  <dependency>
        <groupId>org.apache.axis</groupId>
        <artifactId>axis</artifactId>
        <version>1.4</version>
    </dependency>

第二步:工具类

public class QRCodeUtil {

    // 生成二维码 content:二维码里面的内容 qrcodeVersion:决定着大小
    public static BufferedImage encoderQRCoder(String content, int qrcodeVersion) {
        try {  
            Qrcode handler = new Qrcode(); 
			 /*表示的字符串长度: 容错率(ECC) 显示编码模式(EncodeMode)及版本(Version)有关*/
			 /*二维码的纠错级别(排错率),共有四级:可选L(7%)、M(15%)、Q(25%)、H(30%)(最高H)。
			 	纠错信息同样存储在二维码中,纠错级别越高,纠错信息占用的空间越多,那么能存储的有用信息就越少,对二维码清晰度的要求越小  */
            handler.setQrcodeErrorCorrect('M');  
			//编码模式:Numeric 数字, Alphanumeric 英文字母,Binary 二进制,Kanji 汉字(第一个大写字母表示)
            handler.setQrcodeEncodeMode('B');  
            handler.setQrcodeVersion(qrcodeVersion);
              
            byte[] contentBytes = content.getBytes("UTF-8");
            
            // 67 + 12 * (v - 1);
            int size = 67 + 12 * (qrcodeVersion -1);
            
            BufferedImage bufImg = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);  
              
            Graphics2D gs = bufImg.createGraphics();  
            gs.setBackground(Color.WHITE);
            gs.clearRect(0, 0, size, size);  
            //设定图像颜色:BLACK  
            gs.setColor(Color.BLACK);  
            //设置偏移量  不设置肯能导致解析出错  
            int pixoff = 2;  
            //输出内容:二维码  
            if(contentBytes.length > 0 && contentBytes.length < 1024) {  
                boolean[][] codeOut = handler.calQrcode(contentBytes);  
                for(int i = 0; i < codeOut.length; i++) {  
                    for(int j = 0; j < codeOut.length; j++) {  
                        if(codeOut[j][i]) {  
                            gs.fillRect(j * 3 + pixoff, i * 3 + pixoff,3, 3);  
                        }  
                    }  
                }  
            } else {  
                System.err.println("QRCode content bytes length = " + contentBytes.length + " not in [ 0,120 ]. ");  
            }  
            gs.dispose();  
            bufImg.flush();

            //生成二维码QRCode图片
            return bufImg;

        } catch (Exception e) {  
            e.printStackTrace();  
        }

        return null;
    }
}

第三步,应用,根据我的业务来,是需要在添加机具的方法里,调用生成二维码的方法,

       //添加后
       this.save(machine);
       //移动端扫描需要的格式是这样的,所以就将这样的格式作为content放进二维码里
       //{"type":1,“params”:{"machineId":111,"projcetId":222,"bidSectionId":333}}
        Map<String,Object> map=new HashMap<>();
        map.put("machineId", machine.getMachineId());//新添加的机具id
        map.put("projectId",machine.getProjectId());//新添加的机具所在项目
        map.put("bidSectionId",machine.getBidSectionId());//新添加的机具所在标段
         //
        JSONObject machineJson=new JSONObject();
        machineJson.put("type",1); //考虑到后面有很多模块需要做二维码功能,所以拿type做区分,机具就是type为1
        machineJson.put("params",map);
        String machineString = machineJson.toJSONString();
        // 生成二维码图片
        BufferedImage bufferedImage = QRCodeUtil.encoderQRCoder(machineString,20);
       String base64 = null;
        try {
            //输出流
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "png", stream);
            base64 = Base64.encode(stream.toByteArray());
           //机具表里存的有二维码字段,因为在添加前没有机具id,所以在save方法执行后拿到机具id再进行修改操作,
           //此时只修二维码,之前为空字符串,所以此时的修改相当于添加了。之后将这个字段返回给前端,剩下的就是前端拿这个流去进行解析了
            Machine m=new Machine();
               m.setQrCode(String.format("%1$s%2$s","data:image/png;base64,",base64));
            m.setMachineId(machine.getMachineId());
            this.updateById(m);

	        } catch (Exception e) {
	            e.printStackTrace();
	        }
          return true;

业务更改,不是添加的时候生成二维码,而是在查询的时候,前端传我一个机具id,点击查看二维码的时候调这个接口,将二维码和一些基本信息返回给他。

@ResponseBody
@RequestMapping(value = {"/createQrCode"}, method = RequestMethod.GET)
public JSONObject createQrCode(@RequestParam(value = "machineId")String machineId){

    Machine machine = machineService.getById(machineId);
    String format="";

    if (machine.getEnterDate()!=null){
        Timestamp enterDate = machine.getEnterDate();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
        format = dateFormat.format(enterDate);

    }else{
       format ="/";
    }
    // 返回的信息
    JSONObject jsonObject=new JSONObject();

    jsonObject.put("machineName",machine.getMachineName());
    jsonObject.put("machineNo",machine.getMachineNo());
    jsonObject.put("specificationType",machine.getSpecificationType());
    jsonObject.put("enterDate",format);
     //二维码的内容
    JSONObject qrCodeJson=new JSONObject();

    qrCodeJson.put("type",1);
    qrCodeJson.put("mId",machine.getMachineId());
    qrCodeJson.put("pId",machine.getProjectId());
    qrCodeJson.put("bId",machine.getBidSectionId());
    String qrCodeString = qrCodeJson.toJSONString();

    //二维码流
    String base64Image = createImage(qrCodeString);
    jsonObject.put("qrCode",String.format("%1$s%2$s","data:image/png;base64,",base64Image));

    return  ReturnUtil.success(jsonObject);


}


// 创建二维码并生成流
public static String createImage(String content) {

    // 生成二维码图片
    BufferedImage bufferedImage = QRCodeUtil.encoderQRCoder(content,5);
    String base64 = null;
    try {
        //输出流
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", stream);
        base64 = Base64.encode(stream.toByteArray());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return base64;
}

ps :bufferedImage和base64的互转
https://www.2loveyou.com/articles/2020/01/19/1579401149903.html

批量导出二维码并生成压缩文件

/**
 * 批量导出二维码
 * @param machineIds
 * @param response
 */
@ResponseBody
@RequestMapping(value = {"/importQrCode"}, method = RequestMethod.GET)
public void importQrCode(String machineIds, HttpServletResponse response) {

    String path = "D://";
    String pathName = "images";
    // 先删除
    // 先创建临时文件夹
    File filePath = new File(path + pathName);
    path = path + pathName;// path D://images

    //如果文件夹存在 ,删除文件夹以及下面所有文件
    if(filePath.exists()){
        CompressUtil.deleteDir(path);
    }

    filePath.mkdir();//否则创建文件夹

    // 压缩格式 这个需要在配置文件写
    String format = "zip";

    path = path +  "/" ; // path D://images/
    Map<String,String> map1 = new HashMap<>();
    try {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        String fileName = sdf.format(new Date());
        // 先创建临时文件夹
        File file = new File(path + fileName);

        if(!file.exists()){//如果文件夹不存在
            file.mkdir();//创建文件夹
        }

        // 根据拿到的ids从数据库查出集合

        QueryWrapper<Machine> wrapper = Wrappers.query();
          //前台传来字符串转“,”分隔的数组presentStatus:"1,2"转[1,2]
        if (!StringUtil.isNullOrEmpty(machineIds)) {
            wrapper.in("machineId",machineIds);
        }
        List<Map<String, Object>> machineList = machineService.listMaps(wrapper);

        path = path + fileName; // D://images/2020-10-19

        for (int i = 0; i < machineList.size(); i++) {
            // 在machineList里生成文件
            BASE64Decoder decoder =new BASE64Decoder();
            //解码过程,即将base64字符串转换成二进制流
            byte[] imageByte=decoder.decodeBuffer(machineList.get(i).get("qrCode") + "");
            //生成图片路径和文件名
            String imagePath = path + "/"  + machineList.get(i).get("machineName") + ".jpg";   // D://images/2020-10-19/1.jpg
            map1.put(machineList.get(i).get("machineName") + ".jpg",imagePath);
            OutputStream out =new FileOutputStream(imagePath);
            out.write(imageByte);
            /*
             * 使用流时,都会有一个缓冲区,按一种它认为比较高效的方法来发数据:
             * 把要发的数据先放到缓冲区,缓冲区放满以后再一次性发过去,而不是分开一次一次地发.
             * 而flush()表示强制将缓冲区中的数据发送出去,不必等到缓冲区满.
             * 所以如果在用流的时候,没有用flush()这个方法,很多情况下会出
             * 现流的另一边读不到数据的问题,特别是在数据特别小的情况下.
             */
            out.flush();
            out.close();
        }
        // 压缩且下载
        CompressUtil.MultiFileZipDownload(response,(fileName + "." + format),map1);

    } catch (Exception e) {
        e.printStackTrace();
    }
}

所需工具类:

/**
 * 生成压缩文件 (zip,rar 格式)
 */
public class CompressUtil {

    /**
     * 多文件zip压缩下载 (说明:读取文件流到zip流中,之后下载)
     * @param response
     * @param downloadName  下载后的压缩包名,带后缀
     * @param map  存放文件信息的map ,key为该文件压缩后的目录层级路径如:/xxx/xxx/xxx.jpg,为文件名时则在压缩包的顶层
     *             如:xxx.jpg。 value为下载文件所在的路径
     */
    public static void MultiFileZipDownload(HttpServletResponse response, String downloadName, Map<String,String> map) {
        OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        ZipOutputStream zos=new ZipOutputStream(outputStream);
        try {
            response.setContentType("multipart/form-data");
            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(downloadName, "UTF-8"));
            map.forEach((name,path)->{
                InputStream is = null;
                BufferedInputStream in = null;
                byte[] buffer = new byte[1024];
                int len;
                //创建zip实体(一个文件对应一个ZipEntry)
                //name --->压缩包的层级路径
                ZipEntry entry = new ZipEntry(name);
                try {
                    //获取需要下载的文件流
                    File file=new File(path);
                    is = new FileInputStream(file);
                    in = new BufferedInputStream(is);
                    zos.putNextEntry(entry);
                    //文件流循环写入ZipOutputStream
                    while ((len = in.read(buffer)) != -1 ) {
                        zos.write(buffer, 0, len);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    if(entry != null) {
                        try {
                            zos.closeEntry();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    if(in != null) {
                        try {
                            in.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    if(is != null) {
                        try {
                            is.close();
                        }catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(zos != null) {
                try {
                    zos.close();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
            if(outputStream != null) {
                try {
                    outputStream.close();
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }

        }
    }



    /**
     * @param path   要压缩的文件路径
     * @param format 生成的格式(zip、rar)d
     */
    public static void generateFile(String path, String format) throws Exception {

        File file = new File(path);
        // 压缩文件的路径不存在
        if (!file.exists()) {
            throw new Exception("路径 " + path + " 不存在文件,无法进行压缩...");
        }
        // 用于存放压缩文件的文件夹
        String generateFile = file.getParent();
        File compress = new File(generateFile);
        // 如果文件夹不存在,进行创建
        if( !compress.exists() ){
            compress.mkdirs();
        }

        // 目的压缩文件
        String generateFileName = compress.getAbsolutePath() + File.separator +  file.getName() + "." + format;

        // 输入流 表示从一个源读取数据
        // 输出流 表示向一个目标写入数据

        // 输出流
        FileOutputStream outputStream = new FileOutputStream(generateFileName);

        // 压缩输出流
        ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(outputStream));

        generateFile(zipOutputStream,file,"");

        System.out.println("源文件位置:" + file.getAbsolutePath() + ",目的压缩文件生成位置:" + generateFileName);
        // 关闭 输出流
        zipOutputStream.close();
    }

    /**
     * @param out  输出流
     * @param file 目标文件
     * @param dir  文件夹
     * @throws Exception
     */
    private static void generateFile(ZipOutputStream out, File file, String dir) throws Exception {

        // 当前的是文件夹,则进行一步处理
        if (file.isDirectory()) {
            //得到文件列表信息
            File[] files = file.listFiles();

            //将文件夹添加到下一级打包目录
            out.putNextEntry(new ZipEntry(dir + "/"));

            dir = dir.length() == 0 ? "" : dir + "/";

            //循环将文件夹中的文件打包
            for (int i = 0; i < files.length; i++) {
                generateFile(out, files[i], dir + files[i].getName());
            }

        } else { // 当前是文件

            // 输入流
            FileInputStream inputStream = new FileInputStream(file);
            // 标记要打包的条目
            out.putNextEntry(new ZipEntry(dir));
            // 进行写操作
            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = inputStream.read(bytes)) > 0) {
                out.write(bytes, 0, len);
            }
            // 关闭输入流
            inputStream.close();
        }

    }

    /**
     * 迭代删除文件夹
     * @param dirPath 文件夹路径
     */
    public static void deleteDir(String dirPath)
    {
        File file = new File(dirPath);
        if(file.isFile())
        {
            file.delete();
        }else
        {
            File[] files = file.listFiles();
            if(files == null)
            {
                file.delete();
            }else
            {
                for (int i = 0; i < files.length; i++)
                {
                    deleteDir(files[i].getAbsolutePath());
                }
                file.delete();
            }
        }
    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值