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) { ExcelReadDTOExcel导出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; }
//#################################################################################################### //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) Setids, @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七、swagger3 swagger3简介 配置 application配置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(); }
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条)