【机房报修管理系统】 后端篇(二十二)Controller层开发——二维码相关接口、Zip压缩以及定时任务

一、前情提要


    上一次我们完成了历史工单管理接口的开发,由于实训楼和实训室管理的开发也是比较简单的服务调用而已,所以在这里就不再赘述了,这一次我们来做二维码的相关开发,实现二维码生成,Zip压缩,制作定时任务。


二、接口功能设想


    这个项目需要二维码的原因是这样的,我当初的设想是在每台电脑前都有一个相应的二维码,只需要扫一扫二维码,然后会出现对应的电脑位置信息,如在哪栋实训楼,实训室,电脑编号是什么,从而不需要用户来手动输入电脑位置信息。用户只需要编写电脑出现的问题,必要时上传图片,然后写上自己的信息提交即可。而管理员也可以按照报修信息准确找到相应的电脑。



三、接口设计及实现

1.导入相应的第三方工具

pom.xml中编写以下代码,导入第三方工具

  • 二维码生成插件,二维码插件的GitHub地址
    这个插件不仅仅可以生成二维码,它还能提供图片 + 音频 + 视频处理,如果需要其他功能请查看该项目的ReadMe。
  • 压缩文件,zip4j官网
    压缩文件用于应对生成图像时可能会不止一张,如果让管理员一张张地下载会很麻烦,所以需要将生成的图片进行压缩打包后提供给管理员下载。
<!--生成二维码的外部项目源-->
<!--请务必先写好外部项目源,然后再导入相应插件,不然会找不到包报错-->
    <repositories>
        <repository>
            <id>yihui-maven-repo</id>
            <url>https://raw.githubusercontent.com/liuyueyi/maven-repository/master/repository</url>
        </repository>
    </repositories>

		<!--二维码生成器插件-->
        <dependency>
            <groupId>com.github.hui.media</groupId>
            <artifactId>qrcode-plugin</artifactId>
            <version>1.0</version>
        </dependency>

        <!--压缩文件上传工具-->
        <dependency>
            <groupId>net.lingala.zip4j</groupId>
            <artifactId>zip4j</artifactId>
            <version>1.3.2</version>
        </dependency>

2.定义好二维码生成地址的常量

com.repairsystem.utils.ConstantUtils定义好生成二维码的位置

class Path {

		//虚拟目录地址
        public static final String DIRPATH = "/opt/Image";
        
        public static final String QRCODEPATH = "/QRCODE";
     
    }

3.创建二维码生成工具QRCodeUtils

由于二维码生成器插件只会生成一个二维码,并不会在二维码隔壁再写一些内容,如实训楼、实训室、电脑编号。所以我们需要对于生成的二维码进行再次加工。

实现步骤:
1.判断生成的图片是一张还是多张。
2.使用插件生成二维码,二维码内容为报修表单地址,带有实训楼ID和名称、实训室ID和名称、电脑编号参数。
3.使用BufferedImage创建一张700*300的画布,填充为白色。
4.把二维码的图像流放入画布中。
5.把需要的信息定位到画布中。
6.把图像流导出到一个文件夹中,如果没有该文件夹则生成文件夹,如果是多张二维码生成则不断循环步骤2~6。
7.最后返回生成二维码文件夹位置。

com.repairsystem.utils创建二维码生成工具QRCodeUtils

package com.repairsystem.utils;

import com.github.hui.quick.plugin.qrcode.wrapper.QrCodeGenWrapper;
import com.google.zxing.WriterException;
import com.repairsystem.entity.Class;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * @author CheungChingYin
 * @date 2018/11/18
 * @time 21:37
 */
public class QRCodeUtils {

    /**
     * @param domain
     * @param clazz
     * @param computerStartNum
     * @param computerEndNum
     * @return存储图片的文件夹地址
     */
    public static String generateQRCode(String domain, Class clazz, Integer computerStartNum, Integer computerEndNum) {
        if (computerStartNum.equals(computerEndNum)) {
            BufferedImage bufferedImage = null;
            try {
                bufferedImage = QrCodeGenWrapper.of("http://" + domain + "?buildingId=" + clazz.getBuildingId() + "&buildingName=" + clazz.getBuildingName() + "&classId=" + clazz.getClassId() + "&className=" + clazz.getClassName() + "&computerNum=" + computerStartNum)
                        .setW(300)
                        .setH(300)
                        .asBufferedImage();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (WriterException e) {
                e.printStackTrace();
            }
            BufferedImage picture = new BufferedImage(700, 300, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = (Graphics2D) picture.getGraphics();
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, 700, 300);
            g.drawImage(bufferedImage, 0, 0, null);
            g.setColor(Color.BLACK);
            g.setFont(new Font("宋体", Font.PLAIN, 20));
            g.drawString("所在实训楼:" + clazz.getBuildingName(), 350, 50);
            g.drawString("所在实训室:" + clazz.getClassName(), 350, 100);
            g.drawString("电脑编号:" + computerStartNum, 350, 150);
            g.drawString("若当前电脑出现问题", 350, 200);
            g.drawString("请扫描左侧二维码进行报修", 350, 250);
            g.dispose();

            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String currentDate = simpleDateFormat.format(new Date());
            String realPath = ConstantUtils.Path.DIRPATH + ConstantUtils.Path.QRCODEPATH + "/" + currentDate + "/" + UUID.randomUUID() + "/";
            String fileName = clazz.getBuildingName() + "-" + clazz.getClassName() + "-" + computerStartNum + ".jpg";

            File outPutFileDir = new File(realPath);
            if (!outPutFileDir.exists()) {
                outPutFileDir.mkdirs();
            }

            File outPutFile = new File(realPath + fileName);
            try {
                ImageIO.write(picture, "jpg", outPutFile);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return realPath;

        } else {
            BufferedImage bufferedImage = null;
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String currentDate = simpleDateFormat.format(new Date());
            String realPath = ConstantUtils.Path.DIRPATH + ConstantUtils.Path.QRCODEPATH + "/" + currentDate + "/" + UUID.randomUUID() + "/";

            File outPutFileDir = new File(realPath);
            if (!outPutFileDir.exists()) {
                outPutFileDir.mkdirs();
            }

            for (int i = computerStartNum; i <= computerEndNum; i++) {

                try {
                    bufferedImage = QrCodeGenWrapper.of("http://" + domain + "?buildingId=" + clazz.getBuildingId() + "&buildingName=" + clazz.getBuildingName() + "&classId=" + clazz.getClassId() + "&className=" + clazz.getClassName() + "&computerNum=" + i)
                            .setW(300)
                            .setH(300)
                            .asBufferedImage();
                    BufferedImage picture = new BufferedImage(700, 300, BufferedImage.TYPE_INT_RGB);
                    Graphics2D g = (Graphics2D) picture.getGraphics();
                    g.setColor(Color.WHITE);
                    g.fillRect(0, 0, 700, 300);
                    g.drawImage(bufferedImage, 0, 0, null);
                    g.setColor(Color.BLACK);
                    g.setFont(new Font("微软雅黑", Font.PLAIN, 20));
                    g.drawString("所在实训楼:" + clazz.getBuildingName(), 350, 50);
                    g.drawString("所在实训室:" + clazz.getClassName(), 350, 100);
                    g.drawString("电脑编号:" + i, 350, 150);
                    g.drawString("若当前电脑出现问题", 350, 200);
                    g.drawString("请扫描左侧二维码进行报修", 350, 250);
                    g.dispose();
                    String fileName = clazz.getBuildingName() + "-" + clazz.getClassName() + "-" + i + ".jpg";
                    File outPutFile = new File(realPath + fileName);
                    ImageIO.write(picture, "jpg", outPutFile);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (WriterException e) {
                    e.printStackTrace();
                }

            }
            return realPath;
        }
    }


}

4.创建压缩工具类ZipUtils

com.repairsystem.utils创建压缩工具类ZipUtils

package com.repairsystem.utils;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import org.apache.commons.lang3.StringUtils;

import java.io.File;

/**
 * @author CheungChingYin
 * @date 2018/11/19
 * @time 14:23
 */
public class ZipUtils {

    //声明压缩对象
    private static ZipParameters parameters;

    //解压文件对象
    private static ZipFile zipFile;

    /**
     *
     * @param sourceFilePath    被压缩的文件的路径(单文件,文件夹)
     * @param zipFilePath       压缩文件路径
     * @param password          压缩密码
     * @return                  压缩成功:true ,压缩失败:false
     */
    public static Boolean singleFileCompress(String sourceFilePath,String zipFilePath,String password){
        parameters = new ZipParameters();
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // 压缩方式(默认方式)
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL); // 压缩级别(默认级别)
        //压缩加密设置
        if (!StringUtils.isEmpty(password)) {
            parameters.setEncryptFiles(true);//是否设置文件加密(默认为否)
            parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD); // 加密方式(此处是标准压缩)
            parameters.setPassword(password.toCharArray());
        }
        try {
            ZipFile zipFile = new ZipFile(zipFilePath);
            //如果是文件则直接压缩,若是文件夹,遍历文件全部压缩
            if(new File(sourceFilePath).isFile()) {
                zipFile.setFileNameCharset("GBK");
                zipFile.addFile(new File(sourceFilePath), parameters);
                return true;
            }
            //File ff=new File(sourceFilePath);
            File[] flst=new File(sourceFilePath).listFiles();
            System.out.println("文件个数=>"+flst.length);
            for(File f:flst){
                zipFile.setFileNameCharset("GBK");
                zipFile.addFile(f, parameters);
            }

            return true;
        } catch (ZipException e) {
            e.printStackTrace();
            return false;
        }catch (Exception id){
            id.printStackTrace();
            return false;
        }
    }
    public static Boolean unZip(String zipFile,String unZipDir){
        try {
            ZipUtils.zipFile = new ZipFile(zipFile);
            ZipUtils.zipFile.setFileNameCharset("GBK");//设置编码格式
            //用自带的方法检测一下zip文件是否合法,包括文件是否存在、是否为zip文件、是否被损坏等
            if (!ZipUtils.zipFile.isValidZipFile()) {
                throw new ZipException("文件不合法或不存在");
            }
            // 跟java自带相比,这里文件路径会自动生成,不用判断
            ZipUtils.zipFile.extractAll(unZipDir);
            return true;
        }catch(ZipException e){
            return false;
        }
    }
}

5.创建接口二维码相关接口QRCodeController

com.repairsystem.web.controller创建接口二维码相关接口QRCodeController

提供下载功能需要在响应头上设置application/force-download

package com.repairsystem.web.controller;

import com.repairsystem.entity.Class;
import com.repairsystem.utils.QRCodeUtils;
import com.repairsystem.utils.ZipUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletResponse;
import java.io.*;

/**
 * @author CheungChingYin
 * @date 2018/11/19
 * @time 20:10
 */
@Controller
@Api(value = "二维码相关接口", tags = {"二维码相关接口"})
@RequestMapping("/QRCode")
public class QRCodeController {

    @ApiOperation(value = "下载二维码图片")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "domain", value = "当前域名", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "buildingId", value = "所属实训楼Id", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "buildingName", value = "所属实训楼名称", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "classId", value = "所属实训室ID", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "className", value = "所属实训室名称", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "computerStartNum", value = "电脑开始编号", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "computerEndNum", value = "电脑结束编号", required = true, dataType = "String", paramType = "query"),

    })
    @GetMapping("/QRCodeDownLoad")
    public String downloadQRCode(String domain, Integer buildingId, String buildingName, Integer classId, String className,
                                 Integer computerStartNum, Integer computerEndNum, HttpServletResponse response) {
        Class clazz = new Class();
        clazz.setBuildingId(buildingId);
        clazz.setBuildingName(buildingName);
        clazz.setClassId(classId);
        clazz.setClassName(className);

        String dirPath = QRCodeUtils.generateQRCode(domain, clazz, computerStartNum, computerEndNum);
        String zipFileName = buildingName + "&" + className + ".zip";
        String zipFilePath = dirPath + zipFileName;
        boolean zipResult = ZipUtils.singleFileCompress(dirPath, zipFilePath, null);
        if (zipResult) {
            response.setContentType("application/force-download");// 设置强制下载不打开
            response.addHeader("Content-Disposition", "attachment;fileName=QRCode.zip");// 设置文件名
            File file = new File(zipFilePath);
            if (file.exists()) {

                byte[] buffer = new byte[1024];
                FileInputStream fis = null;
                BufferedInputStream bis = null;
                try {
                    fis = new FileInputStream(file);
                    IOUtils.copy(fis, response.getOutputStream());
                    response.flushBuffer();
                    System.out.println("success");
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (bis != null) {
                        try {
                            bis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }


        }
        return null;
    }

}

6.定时任务:删除生成的二维码图片

在我们生成了二维码后,二维码会存在我们的服务器中,如果不定时删除图片会造成服务器的空间不足,所以在这里我们利用SpringBoot自带的定时器来做一个定时删除图片功能。

定时功能只需要使用@Scheduled注解即可,更多关于@Scheduled的用法请查看此网站:点我跳转

首先在RepairsystemApplication中开启定时器,只需要在类的头上添加@EnableScheduling注解即可

在这里插入图片描述
然后在com.repairsystem.config创建定时任务类SchedulerTask

package com.repairsystem.config;

import com.repairsystem.utils.ConstantUtils;
import org.apache.commons.io.FileUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;

/**
 * @author CheungChingYin
 * @date 2018/11/20
 * @time 10:55
 */
@Component
public class SchedulerTask {

    /**
     * 每天凌晨3点删除生成的QRCode文件
     */
    @Scheduled(cron = "0 0 3 * * ?")
    private void deleteQRCodeFile(){
        File file = new File(ConstantUtils.Path.DIRPATH+ ConstantUtils.Path.QRCODEPATH);
        if (file.exists()){
            try {
                FileUtils.cleanDirectory(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

        到这里,Controller层开发——二维码相关接口以及定时任务已经开发完成了,也就意味着【机房报修管理系统】 后端篇已经结束,接下来我将会更新前端篇,如果各位同学对前端有兴趣可以来看一下。如果您对次篇文章有疑问,可以在文章下方留言,谢谢您的阅读。如对【机房报修管理系统】系列文章有兴趣,可以关注或收藏我的文章,您的支持是我最大的动力,我会尽快推出下一期内容,敬请期待。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值