HgEqbController.java 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package com.malk.huagao.controller;
  2. import org.springframework.core.io.UrlResource;
  3. import org.springframework.core.io.Resource;
  4. import com.alibaba.fastjson.JSON;
  5. import com.malk.huagao.service.EqbService;
  6. import com.malk.server.common.McR;
  7. import com.malk.utils.UtilMap;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.beans.factory.annotation.Value;
  11. import org.springframework.http.HttpHeaders;
  12. import org.springframework.http.MediaType;
  13. import org.springframework.http.ResponseEntity;
  14. import org.springframework.web.bind.annotation.*;
  15. import java.io.IOException;
  16. import java.nio.file.Files;
  17. import java.nio.file.Path;
  18. import java.nio.file.Paths;
  19. import java.util.Map;
  20. import java.util.concurrent.ConcurrentHashMap;
  21. import java.util.concurrent.ConcurrentMap;
  22. import java.util.concurrent.TimeUnit;
  23. @Slf4j
  24. @RestController
  25. @RequestMapping("/eqb")
  26. public class HgEqbController {
  27. @Autowired
  28. private EqbService eqbService;
  29. @Value(value = "${eqb.downloadFilePath}")
  30. private String fileStoragePath;
  31. @PostMapping("/sign")
  32. public McR sign(@RequestBody Map map){
  33. eqbService.sign(map);
  34. return McR.success();
  35. }
  36. // 使用ConcurrentHashMap保证线程安全
  37. private final ConcurrentMap<String, Long> eventList = new ConcurrentHashMap<>();
  38. // 记录最后一次清理时间
  39. private volatile long lastCleanTime = System.currentTimeMillis();
  40. // 清理间隔时间(毫秒)
  41. private static final long CLEAN_INTERVAL = 60_000;
  42. @PostMapping("/callback")
  43. public McR callback(@RequestBody Map map){
  44. System.out.println(map);
  45. log.info("e签宝回调: {}", JSON.toJSONString(map));
  46. //签署回调通知:SIGN_MISSON_COMPLETE 事件订阅-签署流程完成:SIGN_FLOW_FINISH
  47. String action = UtilMap.getString(map, "action");
  48. String signFlowId = UtilMap.getString(map, "signFlowId");//e签宝签署流程id
  49. String info = action + "-" + signFlowId;
  50. // 定期清理过期记录
  51. cleanExpiredEvents();
  52. if (isCallbackProcessed(info)){
  53. log.info("info:{},重复回调,不做处理",info);
  54. }else {
  55. eventList.put(info, System.currentTimeMillis());
  56. //签署回调结束
  57. if ("SIGN_MISSON_COMPLETE".equals(action)) {
  58. int signResult = UtilMap.getInt(map, "signResult");//2 - 签署完成,4 - 拒签
  59. if (2 == signResult) {
  60. String processInstanceId = UtilMap.getString(map, "customBizNum");//宜搭审批实例id
  61. //自动同意审批节点
  62. eqbService.autoAgree(signFlowId,processInstanceId);
  63. }
  64. }
  65. }
  66. return McR.success();
  67. }
  68. @GetMapping("/files/{fileId}")
  69. public ResponseEntity<Resource> getFileResource(
  70. @PathVariable String fileId,
  71. @RequestParam(defaultValue = "download") String option) throws IOException {
  72. // 根据fileId获取实际文件路径,这里简化处理,实际可能需要从数据库查询
  73. Path filePath = Paths.get(fileStoragePath).resolve(fileId).normalize();
  74. // 检查文件是否存在
  75. if (!Files.exists(filePath)) {
  76. return ResponseEntity.notFound().build();
  77. }
  78. // 创建Resource对象
  79. Resource resource = new UrlResource(filePath.toUri());
  80. // 根据选项设置响应头
  81. HttpHeaders headers = new HttpHeaders();
  82. if ("preview".equalsIgnoreCase(option)) {
  83. // 预览模式 - 尝试确定内容类型
  84. String contentType = Files.probeContentType(filePath);
  85. // 强制修正 PDF 的 Content-Type
  86. if (filePath.toString().toLowerCase().endsWith(".pdf")) {
  87. contentType = "application/pdf";
  88. } else if (contentType == null) {
  89. contentType = "application/octet-stream";
  90. }
  91. headers.setContentType(MediaType.parseMediaType(contentType));
  92. headers.add("Content-Disposition", "inline; filename=\"" + resource.getFilename() + "\"");
  93. headers.add("X-Content-Type-Options", "nosniff"); // 防止浏览器忽略 Content-Type
  94. } else {
  95. // 下载模式 - 默认处理
  96. headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
  97. headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
  98. }
  99. return ResponseEntity.ok()
  100. .headers(headers)
  101. .contentLength(resource.contentLength())
  102. .body(resource);
  103. }
  104. /**
  105. * 检查并清理过期事件
  106. */
  107. private void cleanExpiredEvents() {
  108. long currentTime = System.currentTimeMillis();
  109. // 只在达到清理间隔时执行清理
  110. if (currentTime - lastCleanTime > CLEAN_INTERVAL) {
  111. synchronized (this) {
  112. // 双重检查,避免重复清理
  113. if (currentTime - lastCleanTime > CLEAN_INTERVAL) {
  114. long expirationTime = currentTime - TimeUnit.MINUTES.toMillis(1);
  115. eventList.entrySet().removeIf(entry -> entry.getValue() < expirationTime);
  116. lastCleanTime = currentTime;
  117. }
  118. }
  119. }
  120. }
  121. /**
  122. * 检查该回调事件在一分钟内是否处理过
  123. */
  124. private boolean isCallbackProcessed(String detail) {
  125. return eventList.containsKey(detail);
  126. }
  127. }