0001-3d.patch 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. From 30c5e5f1f7b70d18d7006266640f6e24b1a000b9 Mon Sep 17 00:00:00 2001
  2. From: xiongzhu <692949348@qq.com>
  3. Date: Wed, 29 Dec 2021 18:15:08 +0800
  4. Subject: [PATCH] 3d
  5. ---
  6. .../com/izouma/nineth/domain/Collection.java | 4 ++
  7. .../izouma/nineth/service/AssetService.java | 2 +-
  8. .../com/izouma/nineth/utils/FileUtils.java | 66 +++++++++++++++++++
  9. .../nineth/web/FileUploadController.java | 33 ++++++++--
  10. src/main/vue/src/components/FileUpload.vue | 7 +-
  11. src/main/vue/src/views/BlindBoxEdit.vue | 4 +-
  12. src/main/vue/src/views/CollectionEdit.vue | 13 +++-
  13. 7 files changed, 119 insertions(+), 10 deletions(-)
  14. diff --git a/src/main/java/com/izouma/nineth/domain/Collection.java b/src/main/java/com/izouma/nineth/domain/Collection.java
  15. index f3ee2ed..75c7949 100644
  16. --- a/src/main/java/com/izouma/nineth/domain/Collection.java
  17. +++ b/src/main/java/com/izouma/nineth/domain/Collection.java
  18. @@ -37,6 +37,10 @@ public class Collection extends BaseEntity {
  19. @Convert(converter = FileObjectListConverter.class)
  20. private List<FileObject> pic;
  21. + @Column(columnDefinition = "TEXT")
  22. + @Convert(converter = FileObjectListConverter.class)
  23. + private FileObject model3d;
  24. +
  25. @ApiModelProperty("铸造者")
  26. @Searchable
  27. private String minter;
  28. diff --git a/src/main/java/com/izouma/nineth/service/AssetService.java b/src/main/java/com/izouma/nineth/service/AssetService.java
  29. index 134a056..01e1b01 100644
  30. --- a/src/main/java/com/izouma/nineth/service/AssetService.java
  31. +++ b/src/main/java/com/izouma/nineth/service/AssetService.java
  32. @@ -289,7 +289,7 @@ public class AssetService {
  33. .toUserId(toUser.getId())
  34. .toAvatar(toUser.getAvatar())
  35. .operation(reason)
  36. - .price("转赠".equals(reason) ? price : null)
  37. + .price("转赠".equals(reason) ? null : price)
  38. .build());
  39. asset.setPublicShow(false);
  40. diff --git a/src/main/java/com/izouma/nineth/utils/FileUtils.java b/src/main/java/com/izouma/nineth/utils/FileUtils.java
  41. index 3545e2c..d4454d9 100644
  42. --- a/src/main/java/com/izouma/nineth/utils/FileUtils.java
  43. +++ b/src/main/java/com/izouma/nineth/utils/FileUtils.java
  44. @@ -3,13 +3,18 @@ package com.izouma.nineth.utils;
  45. import org.apache.commons.lang3.StringUtils;
  46. import java.io.*;
  47. +import java.nio.charset.Charset;
  48. +import java.nio.charset.StandardCharsets;
  49. import java.nio.file.Files;
  50. import java.nio.file.Path;
  51. import java.nio.file.attribute.PosixFileAttributeView;
  52. import java.nio.file.attribute.PosixFileAttributes;
  53. import java.nio.file.attribute.PosixFilePermission;
  54. import java.nio.file.attribute.PosixFilePermissions;
  55. +import java.util.Optional;
  56. import java.util.Set;
  57. +import java.util.zip.ZipEntry;
  58. +import java.util.zip.ZipInputStream;
  59. public class FileUtils {
  60. @@ -200,5 +205,66 @@ public class FileUtils {
  61. }
  62. + public static void unzip(InputStream in, File destDir) throws IOException {
  63. + try {
  64. + unzip(in, destDir, StandardCharsets.UTF_8);
  65. + } catch (Exception e) {
  66. + unzip(in, destDir, Charset.forName("GB2312"));
  67. + }
  68. + }
  69. +
  70. + public static void unzip(InputStream in, File destDir, Charset charset) throws IOException {
  71. + byte[] buffer = new byte[1024];
  72. + ZipInputStream zis = new ZipInputStream(in);
  73. + ZipEntry zipEntry = zis.getNextEntry();
  74. + while (zipEntry != null) {
  75. + File newFile = newFile(destDir, zipEntry);
  76. + if (zipEntry.isDirectory()) {
  77. + if (!newFile.isDirectory() && !newFile.mkdirs()) {
  78. + throw new IOException("Failed to create directory " + newFile);
  79. + }
  80. + } else {
  81. + // fix for Windows-created archives
  82. + File parent = newFile.getParentFile();
  83. + if (!parent.isDirectory() && !parent.mkdirs()) {
  84. + throw new IOException("Failed to create directory " + parent);
  85. + }
  86. + // write file content
  87. + FileOutputStream fos = new FileOutputStream(newFile);
  88. + int len;
  89. + while ((len = zis.read(buffer)) > 0) {
  90. + fos.write(buffer, 0, len);
  91. + }
  92. + fos.close();
  93. + }
  94. + zipEntry = zis.getNextEntry();
  95. + }
  96. + zis.closeEntry();
  97. + zis.close();
  98. + }
  99. +
  100. + public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
  101. + File destFile = new File(destinationDir, zipEntry.getName());
  102. +
  103. + String destDirPath = destinationDir.getCanonicalPath();
  104. + String destFilePath = destFile.getCanonicalPath();
  105. +
  106. + if (!destFilePath.startsWith(destDirPath + File.separator)) {
  107. + throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
  108. + }
  109. +
  110. + return destFile;
  111. + }
  112. +
  113. + public static File findInDir(File dir, String ext) {
  114. + if (!(dir.exists() && dir.isDirectory())) return null;
  115. + for (File file : Optional.ofNullable(dir.listFiles()).orElse(new File[0])) {
  116. + String name = file.getName().toLowerCase();
  117. + if (name.endsWith(ext.toLowerCase()) && !file.isHidden()) {
  118. + return file;
  119. + }
  120. + }
  121. + return null;
  122. + }
  123. }
  124. diff --git a/src/main/java/com/izouma/nineth/web/FileUploadController.java b/src/main/java/com/izouma/nineth/web/FileUploadController.java
  125. index 47580f3..114788e 100644
  126. --- a/src/main/java/com/izouma/nineth/web/FileUploadController.java
  127. +++ b/src/main/java/com/izouma/nineth/web/FileUploadController.java
  128. @@ -10,10 +10,10 @@ import org.apache.commons.io.FilenameUtils;
  129. import org.apache.commons.lang3.ArrayUtils;
  130. import org.apache.commons.lang3.RandomStringUtils;
  131. import org.apache.commons.lang3.StringUtils;
  132. +import org.apache.poi.util.TempFile;
  133. import org.bytedeco.javacv.FFmpegFrameGrabber;
  134. import org.bytedeco.javacv.Frame;
  135. import org.bytedeco.javacv.Java2DFrameConverter;
  136. -import org.pngquant.PngQuant;
  137. import org.springframework.beans.factory.annotation.Autowired;
  138. import org.springframework.web.bind.annotation.PostMapping;
  139. import org.springframework.web.bind.annotation.RequestMapping;
  140. @@ -26,10 +26,7 @@ import java.awt.image.BufferedImage;
  141. import java.io.*;
  142. import java.net.URLConnection;
  143. import java.text.SimpleDateFormat;
  144. -import java.util.Base64;
  145. -import java.util.Date;
  146. -import java.util.Objects;
  147. -import java.util.Optional;
  148. +import java.util.*;
  149. import java.util.regex.Pattern;
  150. @@ -182,4 +179,30 @@ public class FileUploadController {
  151. return new FileObject(file.getOriginalFilename(), url, thumbUrl, file.getContentType());
  152. }
  153. +
  154. + @PostMapping("/3dModel")
  155. + public FileObject upload3dModel(@RequestParam("file") MultipartFile file) throws IOException {
  156. + if (!"zip".equalsIgnoreCase(FilenameUtils.getExtension(file.getOriginalFilename()))) {
  157. + throw new BusinessException("只能上传zip");
  158. + }
  159. + File destDir = TempFile.createTempDirectory(RandomStringUtils.randomAlphabetic(20));
  160. + com.izouma.nineth.utils.FileUtils.unzip(file.getInputStream(), destDir);
  161. + File fbxFile = com.izouma.nineth.utils.FileUtils.findInDir(destDir, ".fbx");
  162. + if (fbxFile == null) {
  163. + throw new BusinessException("找不到fbx文件");
  164. + }
  165. + File fbxDir = fbxFile.getParentFile();
  166. + String basePath = "fbx/"
  167. + + new SimpleDateFormat("yyyy-MM_dd-HH").format(new Date()) + "/"
  168. + + RandomStringUtils.randomAlphabetic(16);
  169. + List<String> urls = new ArrayList<>();
  170. + for (File listFile : fbxDir.listFiles()) {
  171. + if (!listFile.isHidden() && !listFile.isDirectory()) {
  172. + urls.add(storageService.uploadFromInputStream(new FileInputStream(listFile), basePath + "/" + listFile.getName()));
  173. + }
  174. + }
  175. + String fbxUrl = urls.stream().filter(s -> s.toLowerCase().endsWith(".fbx")).findAny()
  176. + .orElseThrow(new BusinessException("找不到fbx文件"));
  177. + return new FileObject(fbxFile.getName(), fbxUrl, null, "fbx");
  178. + }
  179. }
  180. diff --git a/src/main/vue/src/components/FileUpload.vue b/src/main/vue/src/components/FileUpload.vue
  181. index beed236..e5257e1 100644
  182. --- a/src/main/vue/src/components/FileUpload.vue
  183. +++ b/src/main/vue/src/components/FileUpload.vue
  184. @@ -1,13 +1,14 @@
  185. <template>
  186. <el-upload
  187. class="file-upload"
  188. - :action="uploadUrl"
  189. + :action="customUrl || uploadUrl"
  190. :on-success="onSuccess"
  191. :headers="headers"
  192. :file-list="fileList"
  193. :limit="filesLimit"
  194. :on-exceed="onExceed"
  195. :on-preview="onPreview"
  196. + :accept="accept || '*/*'"
  197. ref="upload"
  198. >
  199. <el-button type="primary" size="mini" slot="trigger"> 点击上传 </el-button>
  200. @@ -62,7 +63,9 @@ export default {
  201. format: {
  202. type: String,
  203. default: 'string'
  204. - }
  205. + },
  206. + customUrl: {},
  207. + accept: {}
  208. },
  209. data() {
  210. return {
  211. diff --git a/src/main/vue/src/views/BlindBoxEdit.vue b/src/main/vue/src/views/BlindBoxEdit.vue
  212. index 773a3aa..2459522 100644
  213. --- a/src/main/vue/src/views/BlindBoxEdit.vue
  214. +++ b/src/main/vue/src/views/BlindBoxEdit.vue
  215. @@ -189,6 +189,7 @@
  216. </div>
  217. </template>
  218. <script>
  219. +import resolveUrl from 'resolve-url';
  220. export default {
  221. name: 'BlindBoxEdit',
  222. created() {
  223. @@ -428,7 +429,8 @@ export default {
  224. id: [{ required: true, message: '请选择作品' }],
  225. total: [{ required: true, message: '请输入数量' }]
  226. },
  227. - cateogories: ['勋章', '收藏品', '数字艺术', '门票', '游戏', '音乐', '使用', '其他']
  228. + cateogories: ['勋章', '收藏品', '数字艺术', '门票', '游戏', '音乐', '使用', '其他'],
  229. + customUrl: resolveUrl(this.$baseUrl, 'upload/3dModel')
  230. };
  231. },
  232. methods: {
  233. diff --git a/src/main/vue/src/views/CollectionEdit.vue b/src/main/vue/src/views/CollectionEdit.vue
  234. index d794f0d..5574fc7 100644
  235. --- a/src/main/vue/src/views/CollectionEdit.vue
  236. +++ b/src/main/vue/src/views/CollectionEdit.vue
  237. @@ -29,6 +29,15 @@
  238. ></object-upload>
  239. <div class="tip">支持JPG、PNG、GIF、MP4,推荐长宽比1:1</div>
  240. </el-form-item>
  241. + <el-form-item prop="model3d" label="3D模型">
  242. + <file-upload
  243. + :limit="1"
  244. + v-model="formData.model3d"
  245. + :customUrl="customUrl"
  246. + accept="application/zip"
  247. + ></file-upload>
  248. + <div class="tip">请将FBX文件与贴图打包成zip压缩包上传</div>
  249. + </el-form-item>
  250. <el-form-item prop="minterId" label="铸造者">
  251. <minter-select
  252. v-model="formData.minterId"
  253. @@ -221,6 +230,7 @@
  254. </div>
  255. </template>
  256. <script>
  257. +import resolveUrl from 'resolve-url';
  258. export default {
  259. name: 'CollectionEdit',
  260. created() {
  261. @@ -418,7 +428,8 @@ export default {
  262. privelegeRules: {
  263. detail: [{ required: true, message: '请填写内容' }],
  264. remark: [{ required: true, message: '请填写说明' }]
  265. - }
  266. + },
  267. + customUrl: resolveUrl(this.$baseUrl, 'upload/3dModel')
  268. };
  269. },
  270. methods: {
  271. --
  272. 2.30.1 (Apple Git-130)