项目通用代码笔记
一、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
登录
- 创建时间
- 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简介
配置
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
注解
八、文件下载
文件(生成-压缩-下载)
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();
}
}