WpsController.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. package com.yingpaipay.business.controller;
  2. import com.yingpaipay.business.domain.Document;
  3. import com.yingpaipay.business.domain.dto.WpsGetVersionsDTO;
  4. import com.yingpaipay.business.domain.dto.WpsR;
  5. import com.yingpaipay.business.domain.dto.WpsVersionControlDTO;
  6. import com.yingpaipay.business.domain.dto.WpsVersionDTO;
  7. import com.yingpaipay.business.service.common.CommonDocumentService;
  8. import jakarta.servlet.http.HttpServletRequest;
  9. import lombok.RequiredArgsConstructor;
  10. import lombok.extern.slf4j.Slf4j;
  11. import org.dromara.common.core.domain.R;
  12. import org.dromara.common.core.exception.BusinessException;
  13. import org.dromara.common.core.utils.StringUtils;
  14. import org.dromara.common.json.utils.JsonUtils;
  15. import org.dromara.common.oss.core.OssClient;
  16. import org.dromara.common.oss.entity.UploadResult;
  17. import org.dromara.common.oss.factory.OssFactory;
  18. import org.dromara.common.web.core.BaseController;
  19. import org.dromara.system.domain.SysOssExt;
  20. import org.dromara.system.domain.SysUser;
  21. import org.dromara.system.domain.vo.SysOssVo;
  22. import org.dromara.system.service.ISysOssService;
  23. import org.dromara.system.service.ISysUserService;
  24. import org.springframework.http.MediaType;
  25. import org.springframework.web.bind.annotation.*;
  26. import java.io.File;
  27. import java.io.FileOutputStream;
  28. import java.io.IOException;
  29. import java.io.InputStream;
  30. import java.util.*;
  31. import java.util.concurrent.ConcurrentHashMap;
  32. /**
  33. * @Author: Huanyi
  34. * @Description: 由于 WPS 服务对于版本管理非常的麻烦,版本回退一直没有很好的解决方案,因此直接由我们自己负责管理版本。
  35. */
  36. @Deprecated
  37. @RestController
  38. @RequestMapping("/wps/callback/v3/3rd")
  39. @RequiredArgsConstructor
  40. @Slf4j
  41. public class WpsController extends BaseController {
  42. /**
  43. * 这里为版本控制缓存
  44. */
  45. private static final Map<Long, WpsVersionControlDTO> DOCUMENT_MAP = new ConcurrentHashMap<>();
  46. private final ISysOssService ossService;
  47. private final CommonDocumentService documentService;
  48. private final ISysUserService userService;
  49. @PutMapping(value = "/upload/file/{documentId}", consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
  50. public void upload(@PathVariable String documentId, HttpServletRequest request) {
  51. String[] ids = documentId.split("_");
  52. WpsVersionControlDTO dto = DOCUMENT_MAP.get(Long.valueOf(ids[0]));
  53. File tempFile = null;
  54. try {
  55. tempFile = File.createTempFile(dto.getFileName() + "_", dto.getSuffix());
  56. try (InputStream in = request.getInputStream();
  57. FileOutputStream out = new FileOutputStream(tempFile)) {
  58. byte[] buffer = new byte[8192];
  59. int bytesRead;
  60. while ((bytesRead = in.read(buffer)) != -1) {
  61. out.write(buffer, 0, bytesRead);
  62. }
  63. }
  64. // 防止自增ID过早炸掉,这里采用更新操作,不使用自带的图片上传
  65. String originalfileName = tempFile.getName();
  66. String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."));
  67. OssClient storage = OssFactory.instance();
  68. UploadResult uploadResult = storage.uploadSuffix(tempFile, suffix, originalfileName);
  69. dto.setCurrentVersion(Long.parseLong(ids[1]));
  70. List<WpsVersionDTO> versions = dto.getVersions();
  71. for (WpsVersionDTO version : versions) {
  72. if (Objects.equals(version.getVersion(), Long.valueOf(ids[1]))) {
  73. // FIXME 由于原始版本不能被删除,暂时先不实现: 每新增一个版本,就将原始版本上传一个全新的版本
  74. // 旧的版本可以不需要了,只需要新的版本
  75. // storage.delete(version.getUrl());
  76. version.setFileName(uploadResult.getFilename());
  77. version.setUrl(uploadResult.getUrl());
  78. version.setUpdateTime(new Date());
  79. }
  80. }
  81. } catch (IOException e) {
  82. log.error("文件写入失败, documentId={}", documentId, e);
  83. } finally {
  84. if (tempFile != null && tempFile.exists()) {
  85. boolean deleted = tempFile.delete();
  86. if (!deleted) {
  87. log.warn("临时文件删除失败: {}", tempFile.getAbsolutePath());
  88. }
  89. }
  90. }
  91. }
  92. private record WpsFilesCompleteRequestDto(
  93. String file_id, Object request, String name, Integer size, Map<String, String> digest, Boolean is_manual, Object response, Integer status_code
  94. ) {}
  95. private record WpsFilesCompleteResponseDto(
  96. String id, String name, Integer version, Integer size, Integer create_time, Integer modify_time, String creator_id, String modifier_id
  97. ) {}
  98. @PostMapping("/files/{documentId}/upload/complete")
  99. public WpsR complete(@PathVariable String documentId, @RequestBody WpsFilesCompleteRequestDto dto) {
  100. Map<String, Object> request = (LinkedHashMap<String, Object>) dto.request;
  101. return WpsR.ok(
  102. new WpsFilesCompleteResponseDto(
  103. String.valueOf(request.get("file_id")), String.valueOf(request.get("name")), 1, Integer.valueOf(String.valueOf(request.get("size"))), Math.toIntExact(System.currentTimeMillis() / 1000L), Math.toIntExact(System.currentTimeMillis() / 1000L), "1", "1"
  104. )
  105. );
  106. }
  107. private record WpsUplaodPrepareDto(String[] digest_types) {}
  108. @GetMapping("/files/{documentId}/upload/prepare")
  109. public WpsR<WpsUplaodPrepareDto> uploadPrepare(@PathVariable String documentId) {
  110. String[] types = {"md5"};
  111. return WpsR.ok(new WpsUplaodPrepareDto(types));
  112. }
  113. private record WpsUploadAddressRequestDto(
  114. String file_id, String name, Integer size, Map<String, String> digest, Boolean is_manual, Integer attachment_size, String content_type
  115. ) {}
  116. private record WpsUploadAddressResponseDto(String method, String url) {}
  117. @PostMapping("/files/{documentId}/upload/address")
  118. public WpsR uploadAddress(@PathVariable String documentId, @RequestBody WpsUploadAddressRequestDto dto) {
  119. return WpsR.ok(new WpsUploadAddressResponseDto("PUT", "http://yp1.yingpaipay.com:9029/wps/callback/v3/3rd/upload/file/" + documentId));
  120. }
  121. private record WpsGetFileInfoDto(
  122. String id, String name, Integer version, Integer size, Integer create_time, Integer modify_time, String creator_id, String modifier_id
  123. ) {}
  124. @GetMapping("/files/{documentId}")
  125. public WpsR<WpsGetFileInfoDto> getFileInfo(@PathVariable String documentId) {
  126. String[] ids = documentId.split("_");
  127. long id = Long.parseLong(ids[0]);
  128. long version = Long.parseLong(ids[1]);
  129. if (DOCUMENT_MAP.containsKey(id)) {
  130. WpsVersionControlDTO dto = DOCUMENT_MAP.get(id);
  131. return WpsR.ok(new WpsGetFileInfoDto(
  132. documentId, dto.getFileName(), 1, dto.getSize(), Math.toIntExact(new Date().getTime() / 1000L), Math.toIntExact(new Date().getTime() / 1000L), dto.getCreator(), dto.getUpdator()
  133. ));
  134. }
  135. WpsVersionControlDTO dto = initDocument(id);
  136. return WpsR.ok(new WpsGetFileInfoDto(
  137. documentId, dto.getFileName(), 1, dto.getSize(), Math.toIntExact(new Date().getTime() / 1000L), Math.toIntExact(new Date().getTime() / 1000L), dto.getCreator(), dto.getUpdator()
  138. ));
  139. }
  140. private record WpsFilesPermissionDto(
  141. String user_id, Integer read, Integer update, Integer download, Integer rename, Integer history, Integer copy, Integer print, Integer saves, Integer comment
  142. ) {}
  143. /**
  144. * 随便写的,没必要划分的这么细致
  145. */
  146. @GetMapping("/files/{documentId}/permission")
  147. public WpsR permission(@PathVariable String documentId) {
  148. return WpsR.ok(
  149. new WpsFilesPermissionDto(
  150. "1", 1, 1, 1, 1, 1, 1, 1, 1, 1
  151. )
  152. );
  153. }
  154. private record WpsGetUrlDto(String url) {}
  155. @GetMapping("/files/{documentId}/download")
  156. public WpsR getUrl(@PathVariable String documentId) {
  157. String[] ids = documentId.split("_");
  158. long id = Long.parseLong(ids[0]);
  159. long version = Long.parseLong(ids[1]);
  160. if (DOCUMENT_MAP.containsKey(id)) {
  161. WpsVersionControlDTO dto = DOCUMENT_MAP.get(id);
  162. List<WpsVersionDTO> versions = dto.getVersions();
  163. for (WpsVersionDTO versionDto : versions) {
  164. if (versionDto.getVersion() == version) {
  165. return WpsR.ok(new WpsGetUrlDto(versionDto.getUrl()));
  166. }
  167. }
  168. return WpsR.ok(new WpsGetUrlDto(dto.getVersions().get(0).getUrl()));
  169. }
  170. WpsVersionControlDTO dto = initDocument(id);
  171. List<WpsVersionDTO> versions = dto.getVersions();
  172. for (WpsVersionDTO versionDto : versions) {
  173. if (Objects.equals(versionDto.getVersion(), dto.getCurrentVersion())) {
  174. return WpsR.ok(new WpsGetUrlDto(versionDto.getUrl()));
  175. }
  176. }
  177. return WpsR.ok(new WpsGetUrlDto(dto.getVersions().get(0).getUrl()));
  178. }
  179. @GetMapping("/files/{documentId}/versions/{version}/download")
  180. public WpsR getUrlByVersion(@PathVariable String documentId, @PathVariable Integer version) {
  181. if (DOCUMENT_MAP.containsKey(Long.valueOf(documentId.split("_")[0]))) {
  182. WpsVersionControlDTO dto = DOCUMENT_MAP.get(Long.valueOf(documentId.split("_")[0]));
  183. return WpsR.ok(new WpsGetUrlDto(dto.getVersions().get(Integer.parseInt(documentId.split("_")[1])).getUrl()));
  184. }
  185. WpsVersionControlDTO dto = initDocument(Long.valueOf(documentId.split("_")[0]));
  186. return WpsR.ok(new WpsGetUrlDto(dto.getVersions().get(0).getUrl()));
  187. }
  188. private record WpsGetUsersDto(String id, String name, String avatar_url) {}
  189. @GetMapping("/users")
  190. public WpsR getUsers(@RequestParam("user_ids") Long[] userIds) {
  191. if (userIds == null || userIds.length == 0) {
  192. return WpsR.ok();
  193. }
  194. List<SysUser> vos = userService.selectUserByIds(Arrays.stream(userIds).toList());
  195. List<Long> ossIds = new ArrayList<>();
  196. vos.forEach(e -> ossIds.add(e.getAvatar()));
  197. List<SysOssVo> ossVos = ossService.queryListByIds(ossIds);
  198. List<WpsGetUsersDto> dtos = new ArrayList<>();
  199. for (SysUser vo : vos) {
  200. String url = "";
  201. for (SysOssVo ossVo : ossVos) {
  202. if (ossVo.getOssId().equals(vo.getAvatar())) {
  203. url = ossVo.getUrl();
  204. }
  205. }
  206. dtos.add(new WpsGetUsersDto(String.valueOf(vo.getUserId()), vo.getNickName(), url));
  207. }
  208. return WpsR.ok(dtos);
  209. }
  210. @PostMapping(value = "/init/{documentId}")
  211. public R init(@PathVariable Long documentId) {
  212. if (DOCUMENT_MAP.containsKey(documentId)) {
  213. throw new BusinessException("已有其他人正在审核该文件");
  214. }
  215. initDocument(documentId);
  216. return R.ok(DOCUMENT_MAP.get(documentId).getCurrentVersion());
  217. }
  218. private WpsVersionControlDTO initDocument(Long ossId) {
  219. SysOssVo ossVo = ossService.getById(ossId);
  220. Document document = documentService.getByOssId(ossId);
  221. if (DOCUMENT_MAP.containsKey(document.getId())) {
  222. throw new BusinessException("已有其他人正在审核该文件");
  223. }
  224. long currentVersion = System.currentTimeMillis();
  225. List<WpsVersionDTO> list = new ArrayList<>();
  226. list.add(new WpsVersionDTO(ossVo.getFileName(), 0L, ossVo.getUrl(), new Date(), new Date(), Math.toIntExact(document.getCreateTime().getTime() / 1000L), Math.toIntExact(document.getUpdateTime().getTime() / 1000L)));
  227. list.add(new WpsVersionDTO(ossVo.getFileName(), currentVersion, ossVo.getUrl(), new Date(), new Date(), Math.toIntExact(document.getCreateTime().getTime() / 1000L), Math.toIntExact(document.getUpdateTime().getTime() / 1000L)));
  228. WpsVersionControlDTO dto = new WpsVersionControlDTO();
  229. dto.setCurrentVersion(currentVersion);
  230. dto.setVersions(list);
  231. dto.setSuffix(ossVo.getFileSuffix());
  232. dto.setCreator(String.valueOf(document.getCreateBy()));
  233. dto.setUpdator(String.valueOf(document.getUpdateBy()));
  234. dto.setFileName(ossVo.getOriginalName());
  235. SysOssExt ext = JsonUtils.parseObject(ossVo.getExt1(), SysOssExt.class);
  236. long size = ext.getFileSize();
  237. dto.setSize((int) size);
  238. DOCUMENT_MAP.put(ossId, dto);
  239. return dto;
  240. }
  241. @PutMapping("/clean/{documentId}")
  242. public R clean(@PathVariable Long documentId) {
  243. WpsVersionControlDTO dto = DOCUMENT_MAP.get(documentId);
  244. long currentVersion = System.currentTimeMillis();
  245. dto.getVersions().add(new WpsVersionDTO(
  246. dto.getVersions().get(0).getFileName(), currentVersion, dto.getVersions().get(0).getUrl(), new Date(), new Date(), Math.toIntExact(new Date().getTime() / 1000L), Math.toIntExact(new Date().getTime() / 1000L)
  247. ));
  248. dto.setCurrentVersion(currentVersion);
  249. log.info("自行进行刷新版本");
  250. dto.getVersions().forEach(e -> log.info("{}", JsonUtils.toJsonString(e)));
  251. return R.ok(currentVersion);
  252. }
  253. /**
  254. * 已废弃
  255. */
  256. @GetMapping("/files/{documentId}/versions")
  257. public WpsR getVersions(@PathVariable Long documentId, @RequestParam(value = "offset", required = false) Integer offset, @RequestParam(value = "limit", required = false) Integer size) {
  258. WpsVersionControlDTO dto = DOCUMENT_MAP.get(documentId);
  259. List<WpsVersionDTO> versions = dto.getVersions();
  260. List<WpsVersionDTO> reversed = new ArrayList<>(versions);
  261. Collections.reverse(reversed);
  262. if (offset == null || size == null) {
  263. return WpsR.ok(reversed);
  264. }
  265. int fromIndex = Math.min(offset, reversed.size());
  266. int toIndex = Math.min(offset + size, reversed.size());
  267. List<WpsVersionDTO> paginated = reversed.subList(fromIndex, toIndex);
  268. List<WpsGetVersionsDTO> list = new ArrayList<>();
  269. paginated.forEach(e -> list.add(new WpsGetVersionsDTO(
  270. String.valueOf(documentId), dto.getFileName(), Math.toIntExact(e.getVersion() / 1000L), dto.getSize(), e.getCreate_time(), e.getUpdate_time(), dto.getCreator(), dto.getUpdator()
  271. )));
  272. WpsR<List<WpsGetVersionsDTO>> r = WpsR.ok(list);
  273. String str = JsonUtils.toJsonString(r);
  274. log.warn(str);
  275. return r;
  276. }
  277. /**
  278. * 已废弃
  279. */
  280. @GetMapping("/files/{documentId}/versions/{version}")
  281. public WpsR getFileByVersion(@PathVariable Long documentId, @PathVariable Integer version) {
  282. WpsVersionControlDTO dto = DOCUMENT_MAP.get(documentId);
  283. WpsVersionDTO current = dto.getVersions().get(version - 1);
  284. return WpsR.ok(new WpsGetVersionsDTO(
  285. String.valueOf(documentId), dto.getFileName(), Math.toIntExact(current.getVersion() / 1000L), dto.getSize(), current.getCreate_time(), current.getUpdate_time(), dto.getCreator(), dto.getUpdator()
  286. ));
  287. }
  288. @GetMapping("/files/list")
  289. public R<List<WpsVersionDTO>> getVersionList(@RequestParam("ossId") Long ossId) {
  290. List<WpsVersionDTO> list = DOCUMENT_MAP.get(ossId).getVersions();
  291. list.forEach(e -> log.info("{}", JsonUtils.toJsonString(e)));
  292. return R.ok(list.stream().filter(e -> e.getVersion() != 0L).sorted((e1, e2) -> Math.toIntExact(e2.getVersion() - e1.getVersion())).toList());
  293. }
  294. @GetMapping("/getFinal")
  295. public R<SysOssVo> getFinal(@RequestParam("id") String id) {
  296. String[] ids = id.split("_");
  297. long documentId = Long.parseLong(ids[0]);
  298. long version = Long.parseLong(ids[1]);
  299. log.info("文档编号为 {}, 版本号为 : {}", documentId, version);
  300. WpsVersionControlDTO dto = DOCUMENT_MAP.get(documentId);
  301. List<WpsVersionDTO> versions = dto.getVersions();
  302. for (WpsVersionDTO versionDto : versions) {
  303. log.info("当前轮询的版本号为 {}", versionDto.getVersion());
  304. if (versionDto.getVersion() == version) {
  305. String url = versionDto.getUrl();
  306. SysOssVo vo = ossService.insertByUrl(versionDto.getFileName(), dto.getFileName(), url);
  307. DOCUMENT_MAP.remove(documentId);
  308. return R.ok(vo);
  309. }
  310. }
  311. throw new BusinessException("审核内容保存失败");
  312. }
  313. @DeleteMapping("/cancel/{documentId}")
  314. public R<Void> cancel(@PathVariable Long documentId) {
  315. DOCUMENT_MAP.remove(documentId);
  316. return R.ok();
  317. }
  318. }