Browse Source

Merge branch 'release/V1.0.0/test' of http://192.168.4.240:3000/LINK/LINK-SERVER into release/V2.0.0/test

 Conflicts:
	src/main/java/com/lqkj/link/config/ThreadPoolConfig.java
	src/main/java/com/lqkj/link/module/authority/service/UserInfoService.java
	src/main/java/com/lqkj/link/util/AliOSSUtils.java
	src/main/resources/db/migration/V3__2.0.0.sql
liaoyitao 4 months ago
parent
commit
78e3b799c5

+ 4 - 1
src/main/java/com/lqkj/link/config/ThreadPoolConfig.java

@@ -14,7 +14,10 @@ public class ThreadPoolConfig {
14 14
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
15 15
         executor.setCorePoolSize(20); // 核心线程池大小
16 16
         executor.setMaxPoolSize(50); // 最大线程池大小
17
-        executor.setQueueCapacity(150); // 队列容量
17
+        executor.setQueueCapacity(500); // 队列容量
18
+        executor.setKeepAliveSeconds(300);
19
+        executor.setWaitForTasksToCompleteOnShutdown(true);
20
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
18 21
         executor.setThreadNamePrefix("Async-"); // 线程名称前缀
19 22
         executor.initialize();
20 23
         return executor;

+ 4 - 3
src/main/java/com/lqkj/link/module/authority/service/UserInfoService.java

@@ -1,11 +1,9 @@
1 1
 package com.lqkj.link.module.authority.service;
2 2
 
3
-import cn.hutool.core.util.RandomUtil;
4
-import com.lqkj.link.module.authority.domain.Captcha;
5 3
 import com.lqkj.link.module.authority.domain.UserInfo;
6
-import com.lqkj.link.module.authority.repository.CaptchaRepository;
7 4
 import com.lqkj.link.module.authority.repository.RoleInfoRepository;
8 5
 import com.lqkj.link.module.authority.repository.UserInfoRepository;
6
+import com.lqkj.link.util.FileUtils;
9 7
 import com.lqkj.link.util.RSAUtils;
10 8
 import com.lqkj.link.util.SendSmsUtils;
11 9
 import jakarta.annotation.PostConstruct;
@@ -20,6 +18,7 @@ import org.springframework.data.domain.Pageable;
20 18
 import org.springframework.security.crypto.password.PasswordEncoder;
21 19
 import org.springframework.stereotype.Service;
22 20
 
21
+import java.io.File;
23 22
 import java.util.*;
24 23
 import java.util.regex.Matcher;
25 24
 import java.util.regex.Pattern;
@@ -320,4 +319,6 @@ public class UserInfoService {
320 319
             throw new RuntimeException(e);
321 320
         }
322 321
     }
322
+
323
+
323 324
 }

+ 14 - 0
src/main/java/com/lqkj/link/module/base/service/BaseService.java

@@ -88,4 +88,18 @@ public class BaseService {
88 88
             throw new RuntimeException(e);
89 89
         }
90 90
     }
91
+
92
+    public String ossAddModel(MultipartFile file, String s) {
93
+        String fileName = file.getOriginalFilename();
94
+        String suffix = fileName == null ? "" : fileName.substring(fileName.lastIndexOf(".") + 1);
95
+        if (!suffix.equals("obj") && !suffix.equals("fbx") && !suffix.equals("FBX"))
96
+            throw new RuntimeException("上传文件类型必须是obj、fbx格式的压缩文件");
97
+        if (aliOSSUtils.ossCheckCapacity(s) + file.getSize() >= 21474836480L)
98
+            throw new RuntimeException("容量已满,无法上传文件");
99
+        try {
100
+            return aliOSSUtils.addModel(file, s);
101
+        } catch (Exception e) {
102
+            throw new RuntimeException(e);
103
+        }
104
+    }
91 105
 }

+ 41 - 0
src/main/java/com/lqkj/link/module/zone/controller/ResourceController.java

@@ -250,4 +250,45 @@ public class ResourceController {
250 250
     public MessageBean<String> ossUpload(MultipartFile file) {
251 251
         return MessageBean.ok(baseService.ossUpload(file), "oss上传");
252 252
     }
253
+
254
+    /**
255
+     * 检查本地容量
256
+     * @param request
257
+     * @return
258
+     */
259
+    @GetMapping("/checkCapacity")
260
+    public MessageBean<String> checkCapacity(HttpServletRequest request){
261
+        String authHeader = request.getHeader("Authorization");
262
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
263
+        return MessageBean.ok(resourceService.checkCapacity(userCode), "检查容量");
264
+    }
265
+
266
+    @Operation(
267
+            summary = "个人库模型上传接口",
268
+            description = "个人库模型上传接口",
269
+            parameters = {
270
+                    @Parameter(name = "file", description = "文件", required = true)
271
+            }
272
+    )
273
+    @PostMapping("/oss/addModel")
274
+    public MessageBean<String> ossAddModel(MultipartFile file,
275
+                                        HttpServletRequest request) {
276
+        String authHeader = request.getHeader("Authorization");
277
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
278
+        Integer userId = userInfoService.detailByUserCode(userCode).getUserId();
279
+        return MessageBean.ok(baseService.ossAddModel(file, "resource/model/" + userId + "/"), "oss上传");
280
+    }
281
+
282
+
283
+    /**
284
+     * 阿里云检查容量
285
+     * @param request
286
+     * @return
287
+     */
288
+    @GetMapping("/oss/checkCapacity")
289
+    public MessageBean<String> ossCheckCapacity(HttpServletRequest request){
290
+        String authHeader = request.getHeader("Authorization");
291
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
292
+        return MessageBean.ok(resourceService.ossCheckCapacity(userCode), "检查容量");
293
+    }
253 294
 }

+ 1 - 0
src/main/java/com/lqkj/link/module/zone/repository/ModelInfoRepository.java

@@ -46,4 +46,5 @@ public interface ModelInfoRepository extends JpaRepository<ModelInfo, Integer> {
46 46
     )
47 47
     void deleteAllByTemplateIds(@Param("templateIds") List<Integer> templateIds);
48 48
 
49
+    List<ModelInfo> findByCategoryIdIn(List<Integer> categoryId);
49 50
 }

+ 37 - 0
src/main/java/com/lqkj/link/module/zone/service/ResourceService.java

@@ -7,6 +7,7 @@ import com.lqkj.link.module.zone.domain.ModelInfo;
7 7
 import com.lqkj.link.module.zone.repository.ModelCategoryRepository;
8 8
 import com.lqkj.link.module.zone.repository.ModelInfoRepository;
9 9
 import com.lqkj.link.util.AliOSSUtils;
10
+import com.lqkj.link.util.FileUtils;
10 11
 import com.lqkj.link.util.Unzipper;
11 12
 import org.apache.commons.compress.archivers.ArchiveException;
12 13
 import org.springframework.beans.factory.annotation.Autowired;
@@ -121,16 +122,28 @@ public class ResourceService {
121 122
     }
122 123
 
123 124
     public void deleteModel(Integer modelId) {
125
+        ModelInfo modelInfo = infoRepository.findById(modelId).get();
124 126
         infoRepository.deleteById(modelId);
127
+        aliOSSUtils.deleteModel(modelInfo.getOriginalPath());
125 128
     }
126 129
 
127 130
     @Transactional
128 131
     public void deleteCategory(List<Integer> categoryId) {
132
+        deleteOssFiles(categoryId);
129 133
         categoryRepository.deleteAllByIdInBatch(categoryId);
130 134
         // 更新用户资源刷新状态
131 135
         userInfoRepository.updateRefreshStatus();
132 136
     }
133 137
 
138
+    /**
139
+     * 删除oss文件
140
+     *
141
+     * @param categoryId
142
+     */
143
+    private void deleteOssFiles(List<Integer> categoryId) {
144
+        infoRepository.findByCategoryIdIn(categoryId).forEach(modelInfo -> aliOSSUtils.deleteModel(modelInfo.getOriginalPath()));
145
+    }
146
+
134 147
     public List<Map<String, Object>> resourceCategory(String userCode) {
135 148
         return categoryRepository.queryWithUserCode(userCode);
136 149
     }
@@ -164,4 +177,28 @@ public class ResourceService {
164 177
         UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
165 178
         return userInfo.getRefreshResource() != null && userInfo.getRefreshResource();
166 179
     }
180
+
181
+    /**
182
+     * 检查本地个人库容量
183
+     * @param userCode
184
+     * @return
185
+     */
186
+    public String checkCapacity(String userCode) {
187
+        UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
188
+        String filePath = "./upload/resource/model/" + userInfo.getUserId();
189
+        File file = new File(filePath);
190
+        if (!file.exists()) return "0";
191
+        return "个人库 已使用" + FileUtils.convertBytes(FileUtils.getFolderSize(new File(filePath))) + "/20G";
192
+    }
193
+
194
+    /**
195
+     * 检查OSS个人库容量
196
+     * @param userCode
197
+     * @return
198
+     */
199
+    public String ossCheckCapacity(String userCode) {
200
+        UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
201
+        Long aLong = aliOSSUtils.ossCheckCapacity("resource/model/" + userInfo.getUserId() + "/");
202
+        return "个人库 已使用" + FileUtils.convertBytes(aLong) + "/20G";
203
+    }
167 204
 }

+ 76 - 1
src/main/java/com/lqkj/link/util/AliOSSUtils.java

@@ -2,6 +2,9 @@ package com.lqkj.link.util;
2 2
 
3 3
 import com.aliyun.oss.OSS;
4 4
 import com.aliyun.oss.OSSClientBuilder;
5
+import com.aliyun.oss.model.ListObjectsV2Request;
6
+import com.aliyun.oss.model.ListObjectsV2Result;
7
+import com.aliyun.oss.model.OSSObjectSummary;
5 8
 import org.springframework.beans.factory.annotation.Autowired;
6 9
 import org.springframework.stereotype.Component;
7 10
 import org.springframework.web.multipart.MultipartFile;
@@ -13,6 +16,8 @@ import java.io.InputStream;
13 16
 import java.time.LocalDate;
14 17
 import java.time.LocalDateTime;
15 18
 import java.time.LocalTime;
19
+import java.time.LocalDate;
20
+import java.util.List;
16 21
 import java.util.UUID;
17 22
 import java.util.concurrent.Callable;
18 23
 
@@ -38,6 +43,11 @@ public class AliOSSUtils {
38 43
         String originalFilename = file.getName();
39 44
         String fileName = "file/" + LocalDate.now() + "/" + UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
40 45
         //上传文件到 OSS
46
+        try {
47
+            Thread.sleep(200);
48
+        } catch (InterruptedException e) {
49
+            throw new RuntimeException(e);
50
+        }
41 51
         OSS ossClient = new OSSClientBuilder().build(aliProperties.getEndpoint(), aliProperties.getAccessKeyId(), aliProperties.getAccessKeySecret());
42 52
         threadPoolUtil.getTaskExecutor().execute(() -> {
43 53
             ossClient.putObject(aliProperties.getBucketName(), fileName, file);
@@ -70,5 +80,70 @@ public class AliOSSUtils {
70 80
         }
71 81
     }
72 82
 
73
- 
83
+
84
+    public String addModel(MultipartFile file, String path) {
85
+        // 获取上传的文件的输入流
86
+        try {
87
+            InputStream inputStream = file.getInputStream();
88
+            // 避免文件覆盖
89
+            String originalFilename = file.getOriginalFilename();
90
+            String fileName = path + UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
91
+            //上传文件到 OSS
92
+            OSS ossClient = new OSSClientBuilder().build(aliProperties.getEndpoint(), aliProperties.getAccessKeyId(), aliProperties.getAccessKeySecret());
93
+            threadPoolUtil.getTaskExecutor().execute(() -> {
94
+                ossClient.putObject(aliProperties.getBucketName(), fileName, inputStream);
95
+                ossClient.shutdown();
96
+            });
97
+            //文件访问路径
98
+            return aliProperties.getOsspath().split("//")[0] + "//" + aliProperties.getBucketName() + "." + aliProperties.getOsspath().split("//")[1] + "/" + fileName;
99
+        } catch (IOException e) {
100
+            throw new RuntimeException(e);
101
+        }
102
+    }
103
+
104
+    public Long ossCheckCapacity(String path) {
105
+        OSS ossClient = new OSSClientBuilder().build(aliProperties.getEndpoint(), aliProperties.getAccessKeyId(), aliProperties.getAccessKeySecret());
106
+        return calculateFolderLength(ossClient, aliProperties.getBucketName(), path);
107
+    }
108
+
109
+    private static long calculateFolderLength(OSS ossClient, String bucketName, String folder) {
110
+        long size = 0L;
111
+        ListObjectsV2Result result = null;
112
+        do {
113
+            // MaxKey默认值为100,最大值为1000。
114
+            ListObjectsV2Request request = new ListObjectsV2Request(bucketName).withPrefix(folder).withMaxKeys(1000);
115
+            if (result != null) {
116
+                request.setContinuationToken(result.getNextContinuationToken());
117
+            }
118
+            result = ossClient.listObjectsV2(request);
119
+            List<OSSObjectSummary> sums = result.getObjectSummaries();
120
+            for (OSSObjectSummary s : sums) {
121
+                size += s.getSize();
122
+            }
123
+        } while (result.isTruncated());
124
+        return size;
125
+        try {
126
+            InputStream inputStream = file.getInputStream();
127
+            // 避免文件覆盖
128
+            String originalFilename = file.getOriginalFilename();
129
+            String fileName = "file/" + LocalDate.now() + "/" + UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
130
+            //上传文件到 OSS
131
+            OSS ossClient = new OSSClientBuilder().build(aliProperties.getEndpoint(), aliProperties.getAccessKeyId(), aliProperties.getAccessKeySecret());
132
+            threadPoolUtil.getTaskExecutor().execute(() -> {
133
+                ossClient.putObject(aliProperties.getBucketName(), fileName, inputStream);
134
+                ossClient.shutdown();
135
+            });
136
+            //文件访问路径
137
+            return aliProperties.getOsspath().split("//")[0] + "//" + aliProperties.getBucketName() + "." + aliProperties.getOsspath().split("//")[1] + "/" + fileName;
138
+        } catch (IOException e) {
139
+            throw new RuntimeException(e);
140
+        }
141
+    }
142
+
143
+    public void deleteModel(String path) {
144
+        OSS ossClient = new OSSClientBuilder().build(aliProperties.getEndpoint(), aliProperties.getAccessKeyId(), aliProperties.getAccessKeySecret());
145
+        String prefix = aliProperties.getOsspath().split("//")[0] + "//" + aliProperties.getBucketName() + "." + aliProperties.getOsspath().split("//")[1] + "/";
146
+        ossClient.deleteObject(aliProperties.getBucketName(), path.replace(prefix, ""));
147
+    }
148
+
74 149
 }

+ 45 - 0
src/main/java/com/lqkj/link/util/FileUtils.java

@@ -179,4 +179,49 @@ public class FileUtils {
179 179
         }
180 180
         return result;
181 181
     }
182
+
183
+    public static long getFolderSize(File folder) {
184
+        long totalSize = 0;
185
+
186
+        // 检查路径是否存在且为目录
187
+        if (folder.exists() && folder.isDirectory()) {
188
+            File[] files = folder.listFiles();
189
+            if (files != null) { // 处理可能为 null 的情况
190
+                for (File file : files) {
191
+                    if (file.isFile()) {
192
+                        // 累加文件大小
193
+                        totalSize += file.length();
194
+                    } else if (file.isDirectory()) {
195
+                        // 递归计算子目录大小
196
+                        totalSize += getFolderSize(file);
197
+                    }
198
+                }
199
+            }
200
+        } else {
201
+            System.out.println("The specified path does not exist or is not a directory.");
202
+        }
203
+
204
+        return totalSize;
205
+    }
206
+
207
+    public static String convertBytes(long bytes) {
208
+        if (bytes < 0) {
209
+            return "Invalid size";
210
+        }
211
+
212
+        // 定义单位
213
+        String[] units = {"B", "KB", "MB", "GB"};
214
+        int unitIndex = 0;
215
+
216
+        // 逐步转换为更大的单位
217
+        double size = (double) bytes;
218
+
219
+        while (unitIndex < units.length - 1) {
220
+            size /= 1024;
221
+            unitIndex++;
222
+        }
223
+
224
+        // 使用 String.format 格式化输出
225
+        return String.format("%.2f%s", size, units[unitIndex]);
226
+    }
182 227
 }

+ 22 - 1
src/main/resources/db/migration/V3__2.0.0.sql

@@ -1,3 +1,4 @@
1
+<<<<<<< HEAD
1 2
 alter table zone_info add column like_count INT4 default 0;
2 3
 comment on column zone_info.like_count is
3 4
 '点赞数: like_count';
@@ -17,4 +18,24 @@ comment on column Likes.user_id is
17 18
 comment on column Likes.zone_id is
18 19
 '点赞的作品id: zone_id';
19 20
 comment on column Likes.create_time is
20
-'点赞时间: create_time'
21
+'点赞时间: create_time'
22
+=======
23
+alter table geom_info
24
+    add column if not exists pics varchar(1024),
25
+    add column if not exists video_url varchar(1024),
26
+    add column if not exists audio_url varchar(1024),
27
+    add column if not exists brief text,
28
+    add column if not exists navigation bool default false,
29
+    add column if not exists navigation_end varchar(100);
30
+
31
+comment on column geom_info.pics is '图片地址:pics';
32
+comment on column geom_info.video_url is '视频文件地址:video_url';
33
+comment on column geom_info.audio_url is '音频文件地址:audio_url';
34
+comment on column geom_info.brief is '简介:brief';
35
+comment on column geom_info.navigation is '是否导航:navigation';
36
+comment on column geom_info.navigation_end is '导航终点:navigation_end';
37
+
38
+
39
+ALTER TABLE model_info
40
+ALTER COLUMN texture_path TYPE VARCHAR(5000);
41
+>>>>>>> 2ea1012e32fc18bb55a79461c9862f040d41294a