项目通用代码笔记

这是一个关于JWT(JSON Web Token)的使用示例,包括生成、验证和处理过期策略。同时展示了文件压缩工具类,能够对文件夹进行zip压缩并提供下载。此外,还涵盖了Excel的导入导出功能,以及Swagger3的配置和使用。文件下载部分包含了下载文件名乱码问题的解决和文件删除操作。
摘要由CSDN通过智能技术生成

项目通用代码笔记

一、JwtUtils

public class JwtUtils {
    public static void main(String[] args) {
//        String token = getJwtToken("10008", "0");
//        System.out.println("token" + "====================" + token);
//
//        System.out.println(checkCookie(token) + "================");

//        String token = "";
//        System.out.println(checkCookie("token") + "================");

//        String checkToken = getJwtCheckToken("1000045689");
//        System.out.println("checkToken" + "====================" + checkToken);
//
        得到token中的验证码
//        String code = getMemberCheckCodeByJwtToken(checkToken);
//        System.out.println("code" + "====================" + code);
//
//        String idByJwtToken = getMemberIdByJwtToken(token);
//        System.out.println("id" + "====================" + idByJwtToken);
//
//        String type = getMemberUserTypeByJwtToken(token);
//        System.out.println("type" + "====================" + type);

    }

    public static final long EXPIRE = 1000 * 60; //身份认证token过期时间
    //    public static final long EXPIRE = 1000 * 60 * 60 * 24; //身份认证token过期时间
    public static final long CHECKIDEXPIRE = 1000 * 60 * 5; //Ctoken过期时间
    public static final String APP_SECRET = "tyh8BDbRigUDaY6pZJfWus1jZWLTJC"; //秘钥

    //暂时用于数据交换
/*    public static String Id = "123456";
    public static String UserType = "student";*/

    //生成身份认证认证token字符串的方法
    public static String getJwtToken(String id, String userType) {
        //因为还没有与前端交互,所以不能将token放到请求头中,我们在这里设置一个假token
  /*      id = Id;
        userType = UserType;*/
        String JwtToken = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                .claim("id", id)  //设置token主体部分 ,存储用户信息
                .claim("userType", userType)
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();
        return JwtToken;
    }

    //生成验证码Id的token字符串的方法
    public static String getJwtCheckToken(String checkCode) {
        String JwtToken = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))//前端联调阶段验证码有效期暂为一天
                .claim("checkCode", checkCode)  //设置token主体部分 ,存储用户信息
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();
        return JwtToken;
    }


    public static boolean checkCookie(String token) {
        if (StringUtils.hasLength(token)) {
            try {
                Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token);
                return true;
            } catch (Exception e) {
//                e.printStackTrace();
                System.out.println("验证信息已过期");
            }
        }
        return false;
    }

    /**
     * 得到token中的验证码
     *
     * @param token
     * @return
     */
    public static String getMemberCheckCodeByJwtToken(String token) {
        if (token == null || token.equals("")) {
            return "";
        }
        Claims claims = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token).getBody();
        return (String) claims.get("checkCode");
    }

    public static String getMemberIdByJwtToken(String token) {
//        token = getJwtToken(Id,UserType);
        if (token == null || token.equals("")) {
            return "";
        }
        Claims claims = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token).getBody();
        return (String) claims.get("id");
    }


    public static String getMemberUserTypeByJwtToken(String token) {
//        token = getJwtToken(Id,UserType);
        if (token == null || token.equals("")) {
            return "";
        }
        Claims claims = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token).getBody();
        return (String) claims.get("userType");
    }

    /**
     * 得到请求头中的token
     *
     * @param request
     * @return
     */
    public static String getToken(HttpServletRequest request) {
        return request.getHeader("Authorization");
    }

    /**
     * 直接通过这个方法得到存储在token中的UserId
     *
     * @param request
     * @return
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
//        token = getJwtToken(Id,UserType);
        if (token == null || token.equals("")) {
            return "";
        }
        Claims claims = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token).getBody();
        return (String) claims.get("id");
    }

    /**
     * 直接通过这个方法得到存储在token中的UserType
     *
     * @param request
     * @return
     */
    public static String getMemberUserTypeByJwtToken(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
//        token = getJwtToken(Id,UserType);
        if (token == null || token.equals("")) {
            return "";
        }
        Claims claims = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token).getBody();
        return (String) claims.get("userType");
    }
}

token失效方案

方案一:

在每次修改密码或者退出登录后,修改一下自定义的盐值。当进行下次访问时,会根据自定义盐值验证token,修改了自定义盐值,自然访问不通过。

方案二:

利用数据库,存放一个修改或者登出的时间,在创建token时,标注上创建时间。如果这个创建时间小于修改或登出的时间,就表示它是修改或者登出之前的token,为过期token

登录

  1. 创建时间
  2. token生成时间

token》创建时间

修改:更新时间,

1639662926682

二 、CompressFileUtils

文件下载工具类

package com.vortex.cloud.grzhcg.util;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author wanglin
 * @version 1.0
 * @date 2021-12-25 周六
 * @description 压缩文件夹-格式(zip、rar)
 */
@Slf4j
public class CompressFileUtils {
    /**
     * @param path   要压缩的文件路径
     * @param format 生成的格式(zip、rar)
     *               //     * @param saveZipPath 放压缩文件的文件夹路径
     */
    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();
//        String generateFile = file.getParent() + File.separator + "compressFile";
        File compress = new File(generateFile);
//        File compress = new File(saveZipPath);
        // 如果文件夹不存在,进行创建
        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() + "\n目的压缩文件生成位置:" + 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();
        }
    }

    /**
     * 下载压缩包zip
     *
     * @param downZipName 下载压缩包的文件名
     * @param downZipPath 下载压缩包的路径
     * @param response
     */
    public static void downloadZipFile(String downZipName, String downZipPath, HttpServletResponse response) {
        try {
            //处理-下载文件名乱码
            downZipName = URLEncoder.encode(downZipName, StandardCharsets.UTF_8.name());
            downZipName = new String(downZipName.getBytes(), StandardCharsets.ISO_8859_1.name());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8'zh_cn'" + downZipName);
        try {
            FileInputStream fileInputStream = new FileInputStream(downZipPath);
            byte[] bytes = new byte[1024 * 1024 * 10];
            int len = -1;
            OutputStream outputStream = response.getOutputStream();
            while ((len = fileInputStream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, len);
            }
            outputStream.flush();
            outputStream.close();
            fileInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 清空当前文件夹
     *
     * @param file
     * @return
     */
    public static boolean deleteFile(File file) {
        //判断文件不为null或文件目录存在
        if (file == null || !file.exists()) {
            System.out.println("文件删除失败,请检查文件路径是否正确");
            return false;
        }
        //取得这个目录下的所有子文件对象
        File[] files = file.listFiles();
        //遍历该目录下的文件对象
        for (File f : files) {
            //打印文件名
            String name = file.getName();
            System.out.println("删除:" + name + "成功!");
            //判断子目录是否存在子目录,如果是文件则删除
            if (f.isDirectory()) {
                deleteFile(f);
            } else {
                f.delete();
            }
        }
        //删除空文件夹  for循环已经把上一层节点的目录清空。
//        file.delete();
        return true;
    }

    /**
     * 删除文件夹下的单个文件
     *
     * @param file
     * @return
     */
    public static boolean deleteSingleFile(File file) {
        if (file.isFile() && file.exists()) {
            file.delete();
            return true;
        } else {
            return false;
        }
    }

}

三、Excel导入导出

Excel导入

//####################################################################################################
//controller层
@Operation(summary = "导入Excel")
    @RequestMapping(value = "importExcel", method = {RequestMethod.POST, RequestMethod.GET}, consumes = {"multipart/form-data"})
    public RestResultDTO<?> importExcel(@Parameter(description = "租户ID") @RequestHeader(required = false) String tenantId,
                                        @Parameter(description = "文件") @RequestPart(required = false) MultipartFile file,
                                        @Parameter(description = "开始读取数据的行索引") @RequestParam(required = false, defaultValue = "1") Integer startRowNum,
                                        @Parameter(description = "开始读取数据的列索引") @RequestParam(required = false, defaultValue = "1") Integer startCellNum) {
        ExcelReadDTO<FamousTreesExcelReadRecordDTO> readDto = ExcelUtils.readExcel(file, FamousTreesExcelReadRecordDTO.class, startRowNum, startCellNum);
        if (CollectionUtils.isNotEmpty(readDto.getMessages())) {
            return RestResultDTO.newFail(readDto.getMessages().toString() + "导入失败");
        }
        List<ExcelMessageDTO> excelMessageDtoList = famousTreesService.importExcel(tenantId, readDto);
        if (CollectionUtils.isNotEmpty(excelMessageDtoList)) {
            return RestResultDTO.newFail(excelMessageDtoList + "导入失败");
        }
        return RestResultDTO.newSuccess(null, "导入成功");
    }
//####################################################################################################
//service层
@Transactional(rollbackFor = Exception.class)
@Override
public List<ExcelMessageDTO> importExcel(String tenantId, ExcelReadDTO<FamousTreesExcelReadRecordDTO> readDto) {
    List<FamousTreesExcelReadRecordDTO> readDtoList = readDto.getDatas();
    List<FamousTrees> saveList = new ArrayList<>();
    List<ExcelMessageDTO> messageList = readDto.getMessages();

    int rowNum = 0;
    boolean flag = true;
    for (FamousTreesExcelReadRecordDTO dto : readDtoList) {
        rowNum++;
        ExcelMessageDTO excelMessageDto = new ExcelMessageDTO(rowNum);
        if (Objects.isNull(dto)) {
            excelMessageDto.getMessages().add("空行");
        } else {
            flag = checkValidate(tenantId, flag, dto, excelMessageDto);
        }
        if (CollectionUtils.isEmpty(excelMessageDto.getMessages())) {
            FamousTrees famousTreesEntity = transferToEntity(tenantId, dto, null);
            saveList.add(famousTreesEntity);
        } else {
            messageList.add(excelMessageDto);
        }
    }
    saveList.stream().forEach(entity -> {
        famousTreesMapper.insert(entity);
    });
    return messageList;
}
//####################################################################################################
//excelDTO验证方法
private boolean checkValidate(String tenantId, boolean flag, FamousTreesExcelReadRecordDTO dto, ExcelMessageDTO excelMessageDto) {
        //1- 验证是否存在: 保护级别
        String protectLevelId = verifyLevelByName(tenantId, dto.getProtectLevel(), Constants.PARAM_STANDARD_LEVEL);
        if (!StringUtils.isNotBlank(protectLevelId)) {
            excelMessageDto.getMessages().add("保护级别错误");
            flag = false;
        }
        dto.setProtectLevel(protectLevelId);
        // 2 - 验证是否存在:权属
        String belongToId = FamousTreesBelongToEnum.getKeyByValue(dto.getBelongTo());
        if (!StringUtils.isNotBlank(belongToId)) {
            excelMessageDto.getMessages().add("权属错误");
            flag = false;
        }
        dto.setBelongTo(belongToId);
        // 3 - 验证是否存在:养护单位
        List<DeptOrgDTO> managementDtoList = umsService.loadDepartments(tenantId);
        Map<String, String> managementMap = managementDtoList.stream().collect(Collectors.toMap(DeptOrgDTO::getText, DeptOrgDTO::getId));
        String managementId = managementMap.get(dto.getManagementUnitName());
        if (!StringUtils.isNotBlank(managementId)) {
            excelMessageDto.getMessages().add("养护单位错误");
            flag = false;
        }
        dto.setManagementUnitId(managementId);
        dto.setTenantId(tenantId);
        List<String> errMsgList = validatorUtils.validateEntity(dto);
        if (CollectionUtils.isNotEmpty(errMsgList)) {
            excelMessageDto.getMessages().add(errMsgList.toString());
            flag = false;
        }
        //2-唯一性验证 编号
        QueryWrapper<FamousTrees> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(FamousTrees::getTreeCode, dto.getTreeCode());
        FamousTrees famousTreesEntity = famousTreesMapper.selectOne(queryWrapper);
        if (Objects.nonNull(famousTreesEntity)) {
            excelMessageDto.getMessages().add(famousTreesEntity.getTreeCode() + "该编号已存在");
            flag = false;
        }
        dto.setTenantId(tenantId);
        dto.setId(null);
        return flag;
    }

Excel导出

//####################################################################################################
//controller层
 @Value("vortex.rest.url.file:")
 private String fileServer;

@Operation(summary = "导出Excel")
@RequestMapping(value = "exportExcel", method = {RequestMethod.POST, RequestMethod.GET})
public void exportExcel(@ParameterObject @SortDefault(sort = "createTime", direction = Sort.Direction.DESC) Sort sort,
                        @Parameter(description = "租户ID") @RequestHeader String tenantId,
                        @ParameterObject FamousTreesQueryDTO queryDTO,
                        @Parameter(description = "id集合") @RequestParam(required = false) Set<String> ids,
                        @Parameter(description = "导出列JSON") @RequestParam(defaultValue = ExcelExportParams.FILE_MANAGEMENT_PARAMS) String columnJson,
                        @Parameter(description = "文件扩展名") @RequestParam(required = false, defaultValue = Constants.EXTENSION_XLS) String extension,
                        HttpServletResponse response) {
    List<FamousTreesVO> results = famousTreesService.list(tenantId, sort, queryDTO, ids);
    String downloadUrl = fileServer + "/cloudFile/common/downloadFile?id=";
    ExcelUtils.exportExcel("古树名木档案表", extension, downloadUrl, columnJson, results, response);
}
//####################################################################################################
//service层
@Transactional(readOnly = true)
    @Override
    public List<FamousTreesVO> list(String tenantId, Sort sort, FamousTreesQueryDTO queryDto, Set<String> ids) {
        QueryWrapper<FamousTrees> queryWrapper = this.buildQueryWrapper(tenantId, queryDto, ids);
        PageUtils.transferSort(queryWrapper, sort);
        return this.transformToVoList(tenantId, famousTreesMapper.selectList(queryWrapper));
    }
//####################################################################################################
//buildQueryWrapper查询条件
 private QueryWrapper<FamousTrees> buildQueryWrapper(String tenantId, FamousTreesQueryDTO queryDto, Set<String> ids) {
        QueryWrapper<FamousTrees> queryWrapper = new QueryWrapper<>();
        if (Objects.isNull(queryDto)) {
            return queryWrapper;
        }
        //获取选中的数据
        if (CollectionUtils.isNotEmpty(ids)) {
            queryWrapper.lambda().in(FamousTrees::getId, ids);
        }
        queryWrapper.lambda().like(StringUtils.isNotBlank(queryDto.getTreeName()), FamousTrees::getTreeName, queryDto.getTreeName())
                .eq(StringUtils.isNotBlank(queryDto.getManagementUnitId()), FamousTrees::getManagementUnitId, queryDto.getManagementUnitId())
                .eq(StringUtils.isNotBlank(queryDto.getProtectLevel()), FamousTrees::getProtectLevel, queryDto.getProtectLevel())
                .eq(StringUtils.isNotBlank(queryDto.getBelongTo()), FamousTrees::getBelongTo, queryDto.getBelongTo())
                .ge(Objects.nonNull(queryDto.getAgeStart()), FamousTrees::getAge, queryDto.getAgeStart())
                .le(Objects.nonNull(queryDto.getAgeEnd()), FamousTrees::getAge, queryDto.getAgeEnd())
                .ge(Objects.nonNull(queryDto.getHeightStart()), FamousTrees::getHeight, queryDto.getHeightStart())
                .le(Objects.nonNull(queryDto.getHeightEnd()), FamousTrees::getHeight, queryDto.getHeightEnd())
                .ge(Objects.nonNull(queryDto.getTreeDbhStart()), FamousTrees::getTreeDbh, queryDto.getTreeDbhStart())
                .le(Objects.nonNull(queryDto.getTreeDbhEnd()), FamousTrees::getTreeDbh, queryDto.getTreeDbhEnd())
                .eq(StringUtils.isNotBlank(tenantId), FamousTrees::getTenantId, tenantId);
        return queryWrapper;
    }
//获取体检次数
TreeExaminationRecordTimesDTO examinationTimesDto = treeExaminationRecordMapper.getExaminationTimes(entity.getId());
if (Objects.nonNull(examinationTimesDto)) {
    vo.setExaminationTimes(examinationTimesDto.getTimes());
}

四、Mapper查询

根据年份查询

根据 树木id和体检的年份 获取体检次数

mapper文件
@Mapper
public interface TreeExaminationRecordMapper extends BaseMapper<TreeExaminationRecord> {

   /**
     * 根据树木id和体检的年份,获取体检次数
     *
     * @param tenantId
     * @param treeId
     * @param examinationYear
     * @return
     */
    Integer getExaminationTimesByYear(@Param("tenantId") String tenantId, @Param("treeId") String treeId, @Param("examinationYear") String examinationYear);

}
xml文件
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.vortex.cloud.grzhcg.mapper.TreeExaminationRecordMapper">
    <select id="getExaminationTimesByYear" parameterType="string" resultType="integer">
        select count(*) times from grzhcg_trees_examination
        where deleted = 0
        <if test="tenantId != null and tenantId != ''">
            and tenant_id = #{tenantId}
        </if>
        <if test="treeId != null and treeId != ''">
            and tree_id = #{treeId}
        </if>
        <if test="examinationYear != null and examinationYear != ''">
            and DATE_FORMAT(examination_time,'%Y') = #{examinationYear}
        </if>
    </select>
</mapper>

六、二维码

生成二维码

@Operation(summary = " 生成二维码")
@RequestMapping(value = "exportZip", method = {RequestMethod.POST, RequestMethod.GET})
public void dowanload(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //二维码中包含的信息
    String content = "https://grhwdev.cloudhw.cn:8446/treeh5/#/?coordinateType=bd09&id=1472888540794257409";
    Map<EncodeHintType, Object> hints = new HashMap<>(16);
    // 指定编码格式
    hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
    // 指定纠错级别(L--7%,M--15%,Q--25%,H--30%)
    hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
    // 编码内容,编码类型(这里指定为二维码),生成图片宽度,生成图片高度,设置参数
    BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 200, 200, hints);
    //设置请求头
    response.setHeader("Content-Type", "application/octet-stream");
    response.setHeader("Content-Disposition", "attachment;filename=" + "二维码.png");
    OutputStream outputStream = response.getOutputStream();
    MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream);
    outputStream.flush();
    outputStream.close();
}

七、swagger3

swagger3简介

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A4nJrqEH-1640696483961)(H:\TyporaPictures\image-20211224004627994.png)]

配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MlsCVI4v-1640696483964)(H:\TyporaPictures\image-20211224004204267.png)]

application配置

springdoc:
  # OpenAPI文档相关参数
  api-docs:
    # OpenAPI文档开关, true: 开启OpenAPI文档访问功能, false: 关闭。
    enabled: true       
    # JSON格式的OpenAPI文档的访问路径
    path: /v3/api-docs
  # 扫描哪些包来生成OpenAPI文档, 多个包名用逗号分隔
  packages-to-scan: * 
  # 路径匹配规则, API路径符合这些匹配规则才会包含到OpenAPI文档中, 多个规则用逗号分隔
  paths-to-match: /* 
  # 返回媒体类型匹配规则, 返回媒体类型符合这些匹配规则才会包含到OpenAPI文档中, 多个规则用逗号分隔
  produces-to-match: /* 
  # 请求头匹配规则, 请求头符合这些匹配规则才会包含到OpenAPI文档中, 多个规则用逗号分隔
  headers-to-match: /* 
  # 请求媒体类型匹配规则, 请求媒体类型符合这些匹配规则才会包含到OpenAPI文档中, 多个规则用逗号分隔
  consumes-to-match: /* 
  # 排除路径匹配规则, API路径符合这些匹配规则会排除在OpenAPI文档之外, 多个规则用逗号分隔
  paths-to-exclude: 
  # 排除包匹配规则, 包名符合这些匹配规则会排除在OpenAPI文档之外, 多个规则用逗号分隔
  packages-to-exclude: 
  # 默认请求媒体类型
  default-consumes-media-type: application/json
  # 默认返回的响应媒体类型
  default-produces-media-type: '*/*' 
  # 是否禁用OpenAPI文档缓存, 
  # 禁用后每次访问${springdoc.api-docs.path}都会重新生成(适合开发调试阶段)当响应会比较缓慢。
  cache.disabled: false 
  # 是否显示Spring Actuator的接口
  show-actuator: false 
  # 是否自动将类名生成为Tag
  auto-tag-classes: true 
  # 是否包含返回ModelAndView对象的接口
  model-and-view-allowed: false 
  # 是否从 @ControllerAdvice 注解获取接口的响应信息.
  override-with-generic-response: true 
  # 是否开启接口分组功能, 开启后, 一个App可以生成多个OpenAPI文档, 每个文档显示一部分接口。
  api-docs.groups.enabled: true 
  # 分组配置
  group-configs:
      # 分组名称
    - group: XXX
      # 同`springdoc.packages-to-scan`
      packages-to-scan: *    
      # 同`springdoc.paths-to-match`
      paths-to-match: /*     
      # 同`springdoc.paths-to-exclude`
      paths-to-exclude: ``   
      # 同`springdoc.packages-to-exclude`
      packages-to-exclude:   
      # 同`springdoc.produces-to-match`
      produces-to-match: /*  
      # 同`springdoc.consumes-to-match`
      consumes-to-match: /*  
      # 同`springdoc.headers-to-match`
      headers-to-match: /* 
  # webjar资源的访问路径前缀
  webjars.prefix: /webjars 
  # 是否翻译属性值, true: Schema中的属性的值可以用Spring的表达式来编写, 然后运行时自动转成真实的取值
  api-docs.resolve-schema-properties: false 
  # 删除无效的引用定义
  remove-broken-reference-definitions: true 
  # 是否格式化输出的OpenAPI文档, 方便人类阅读
  writer-with-default-pretty-printer: false 
  # 是否启用 deprecating model converter.
  model-converters.deprecating-converter.enabled: true 
  # 生成的Schema等组件的名称是否使用全名(类似java的Class.getName和getSimpleName的区别)
  use-fqn: false # FQN是指 fully qualified names.
  # 是否显示spring security的登录接口
  show-login-endpoint: false
  # 是否预加载OpenAPI文档, true: 程序启动的时候就生成OpenAPI文档, false: 第一次访问OpenAPI文档的时候生成。
  pre-loading-enabled: false 

注解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wYXCZXsF-1640696483965)(H:\TyporaPictures\image-20211224004109457.png)]

八、文件下载

文件(生成-压缩-下载)

public void generateZip(String tenantId, Sort sort, Set<String> ids, HttpServletResponse response) {
    Assert.notEmpty(ids, "ids不能为空");
    QueryWrapper<FamousTrees> queryWrapper = this.buildQueryWrapper(tenantId, ids);
    PageUtils.transferSort(queryWrapper, sort);
    List<FamousTrees> famousTreesList = famousTreesMapper.selectList(queryWrapper);

    String dateName = DateUtils.format(new Date(), "yyyyMMdd");
    String zipName = Constants.ZIP_NAME + dateName;
    //获取项目相对路径(项目的根路径)
    String path = System.getProperty("user.dir");
    String zipProjectPath = path + Constants.FILE_SEPARATOR + Constants.FILE_CONTENTS_NAME + Constants.FILE_SEPARATOR + zipName + Constants.FILE_SEPARATOR;
    //文件名称-古树名木档案+时间(如古树名木档案20211203)
    File fileRealPath = new File(zipProjectPath);
    try {
        String os = System.getProperty(com.vortex.cloud.grzhcg.support.Constants.OS_NAME);
        if (os.toLowerCase().startsWith(com.vortex.cloud.grzhcg.support.Constants.WIN)) {
        }
        if (!fileRealPath.exists()) {
            fileRealPath.mkdirs();
        }
        famousTreesList.stream().forEach(entity -> {
            String qrCodeUrl = Constants.URL_PREFIX + this.url + Constants.URL_ROUTE + entity.getId();
            //二维码图片名称-古树名木中文名+编码,如银杏yx0001
            String qrCodeFileName = entity.getTreeName() + entity.getTreeCode();
            try {
                File fileRealPath2 = new File(fileRealPath + "/" + qrCodeFileName + Constants.QRCODE_SUFFIX);
                //生成二维码图片
                generateQrCodeImage(qrCodeUrl, 350, 350, fileRealPath2.toPath());
            } catch (WriterException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    } catch (Exception e) {
        log.error("文件写入异常:{}", e.getMessage());
        throw new VortexException(e.getMessage());
    }
    //生成压缩包
    try {
        CompressFileUtils.generateFile(zipProjectPath, Constants.ZIP_SUFFIX_ZIP);
    } catch (Exception e) {
        log.error("生成压缩包异常:{}", e.getMessage());
        throw new VortexException(e.getMessage());
    }

    //下载zip文件
    String downZipName = zipName + Constants.ZIP_SPLIT + Constants.ZIP_SUFFIX_ZIP;
    String downZipPath = path + Constants.FILE_SEPARATOR + Constants.FILE_CONTENTS_NAME + Constants.FILE_SEPARATOR + zipName + Constants.ZIP_SPLIT + Constants.ZIP_SUFFIX_ZIP;
    CompressFileUtils.downloadZipFile(downZipName, downZipPath, response);

    //删除压缩包
    File file = new File(downZipPath);
    boolean deleteSingleFile = CompressFileUtils.deleteSingleFile(file);
    if (deleteSingleFile) {
        log.info("删除压缩包:" + zipName + "成功!");
    } else {
        log.info("删除压缩包:" + zipName + "失败!");
    }

    //删除文件下的所有文件
    boolean delAllFileFlag = CompressFileUtils.deleteFile(fileRealPath);
    if (delAllFileFlag) {
        log.info("清空文件夹:" + zipName + "成功!");
    } else {
        log.info("清空文件夹:" + zipName + "失败!");
    }

}

下载文件名乱码

String name = "H:\\fuTaiPorjects\\guangrao\\version6\\grcg-backend\\compressFile\\古树名木档案20211227.zip";
        String zipName = "古树名木档案压缩包" + ".zip";
        try {
            zipName = URLEncoder.encode(zipName, StandardCharsets.UTF_8.name());
            zipName = new String(zipName.getBytes(), StandardCharsets.ISO_8859_1.name());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

//        response.setContentType("application/x-msdownload");
        response.setCharacterEncoding("utf-8");
//        response.setHeader("Content-disposition", "attachment");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8'zh_cn'" + zipName);
        try {
            FileInputStream fin = new FileInputStream(name);
            byte[] bytes = new byte[1024 * 1024 * 10];
            int len = -1;
            OutputStream os = response.getOutputStream();
            while ((len = fin.read(bytes)) != -1) {
                os.write(bytes, 0, len);
            }
            os.flush();
            os.close();
            fin.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

删除单个文件

//zip压缩包
File file = new File(downZipPath);
if (file.isFile() && file.exists()) {
    file.delete();
    System.out.println("删除压缩包" + zipName + "成功!");
} else {
    System.out.println("删除压缩包" + zipName + "失败!");
}

清空文件

//删除该文件下的所有文件
boolean delAllFileFlag = deleteFile(fileRealPath);
if (delAllFileFlag) {
    System.out.println("清空文件夹:" + zipName + "成功!");
} else {
    System.out.println("清空文件夹:" + zipName + "失败!");
}
//###########################################################################################
public static boolean deleteFile(File file) {
        //判断文件不为null或文件目录存在
        if (file == null || !file.exists()) {
            System.out.println("文件删除失败,请检查文件路径是否正确");
            return false;
        }
        //取得这个目录下的所有子文件对象
        File[] files = file.listFiles();
        //遍历该目录下的文件对象
        for (File f : files) {
            //打印文件名
            String name = file.getName();
            System.out.println("清空:" + name + "成功!");
            //判断子目录是否存在子目录,如果是文件则删除
            if (f.isDirectory()) {
                deleteFile(f);
            } else {
                f.delete();
            }
        }
        //删除空文件夹  for循环已经把上一层节点的目录清空。
//        file.delete();
        return true;
    }

下载压缩包zip

//下载zip文件
        String downZipName = zipName + Constants.ZIP_SPLIT + Constants.ZIP_SUFFIX_ZIP;
        String downZipPath = path + Constants.FILE_SEPARATOR + Constants.FILE_CONTENTS_NAME + Constants.FILE_SEPARATOR + zipName + Constants.ZIP_SPLIT + Constants.ZIP_SUFFIX_ZIP;
        downloadZipFile(downZipName, downZipPath, response);
//###########################################################################################
/**
 * 下载压缩包zip
 *
 * @param downZipName 下载压缩包的文件名
 * @param downZipPath 下载压缩包的路径
 * @param response
 */
private void downloadZipFile(String downZipName, String downZipPath, HttpServletResponse response) {
    try {
        //处理-下载文件名乱码
        downZipName = URLEncoder.encode(downZipName, StandardCharsets.UTF_8.name());
        downZipName = new String(downZipName.getBytes(), StandardCharsets.ISO_8859_1.name());
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    response.setCharacterEncoding("utf-8");
    response.setHeader("Content-disposition", "attachment;filename*=utf-8'zh_cn'" + downZipName);
    try {
        FileInputStream fileInputStream = new FileInputStream(downZipPath);
        byte[] bytes = new byte[1024 * 1024 * 10];
        int len = -1;
        OutputStream outputStream = response.getOutputStream();
        while ((len = fileInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, len);
        }
        outputStream.flush();
        outputStream.close();
        fileInputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值