
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"; //秘钥
//暂时用于数据交换
//生成身份认证认证token字符串的方法
public static String getJwtToken(String id, String userType) {
//因为还没有与前端交互,所以不能将token放到请求头中,我们在这里设置一个假token
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;
}
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");
}
public static String getToken(HttpServletRequest request) {
return request.getHeader("Authorization");
}
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");
}
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;
@Slf4j
public class CompressFileUtils {
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();
}
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();
}
}
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();
}
}
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;
}
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 readDto = ExcelUtils.readExcel(file, FamousTreesExcelReadRecordDTO.class, startRowNum, startCellNum);
if (CollectionUtils.isNotEmpty(readDto.getMessages())) {
return RestResultDTO.newFail(readDto.getMessages().toString() + "导入失败");
}
List 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 importExcel(String tenantId, ExcelReadDTO readDto) {
List readDtoList = readDto.getDatas();
List saveList = new ArrayList<>();
List 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 managementDtoList = umsService.loadDepartments(tenantId);
Map 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 errMsgList = validatorUtils.validateEntity(dto);
if (CollectionUtils.isNotEmpty(errMsgList)) {
excelMessageDto.getMessages().add(errMsgList.toString());
flag = false;
}
//2-唯一性验证 编号
QueryWrapper 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 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 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 list(String tenantId, Sort sort, FamousTreesQueryDTO queryDto, Set ids) {
QueryWrapper queryWrapper = this.buildQueryWrapper(tenantId, queryDto, ids);
PageUtils.transferSort(queryWrapper, sort);
return this.transformToVoList(tenantId, famousTreesMapper.selectList(queryWrapper));
}
//####################################################################################################
//buildQueryWrapper查询条件
private QueryWrapper buildQueryWrapper(String tenantId, FamousTreesQueryDTO queryDto, Set ids) {
QueryWrapper 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 baseMapperxml文件{ Integer getExaminationTimesByYear(@Param("tenantId") String tenantId, @Param("treeId") String treeId, @Param("examinationYear") String examinationYear); }
六、二维码 生成二维码
@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 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文档缓存,
# 禁用后每次访问${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:
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条)