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
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
14
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
15
         executor.setCorePoolSize(20); // 核心线程池大小
15
         executor.setCorePoolSize(20); // 核心线程池大小
16
         executor.setMaxPoolSize(50); // 最大线程池大小
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
         executor.setThreadNamePrefix("Async-"); // 线程名称前缀
21
         executor.setThreadNamePrefix("Async-"); // 线程名称前缀
19
         executor.initialize();
22
         executor.initialize();
20
         return executor;
23
         return executor;

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

@@ -1,11 +1,9 @@
1
 package com.lqkj.link.module.authority.service;
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
 import com.lqkj.link.module.authority.domain.UserInfo;
3
 import com.lqkj.link.module.authority.domain.UserInfo;
6
-import com.lqkj.link.module.authority.repository.CaptchaRepository;
7
 import com.lqkj.link.module.authority.repository.RoleInfoRepository;
4
 import com.lqkj.link.module.authority.repository.RoleInfoRepository;
8
 import com.lqkj.link.module.authority.repository.UserInfoRepository;
5
 import com.lqkj.link.module.authority.repository.UserInfoRepository;
6
+import com.lqkj.link.util.FileUtils;
9
 import com.lqkj.link.util.RSAUtils;
7
 import com.lqkj.link.util.RSAUtils;
10
 import com.lqkj.link.util.SendSmsUtils;
8
 import com.lqkj.link.util.SendSmsUtils;
11
 import jakarta.annotation.PostConstruct;
9
 import jakarta.annotation.PostConstruct;
@@ -20,6 +18,7 @@ import org.springframework.data.domain.Pageable;
20
 import org.springframework.security.crypto.password.PasswordEncoder;
18
 import org.springframework.security.crypto.password.PasswordEncoder;
21
 import org.springframework.stereotype.Service;
19
 import org.springframework.stereotype.Service;
22
 
20
 
21
+import java.io.File;
23
 import java.util.*;
22
 import java.util.*;
24
 import java.util.regex.Matcher;
23
 import java.util.regex.Matcher;
25
 import java.util.regex.Pattern;
24
 import java.util.regex.Pattern;
@@ -320,4 +319,6 @@ public class UserInfoService {
320
             throw new RuntimeException(e);
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
             throw new RuntimeException(e);
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
     public MessageBean<String> ossUpload(MultipartFile file) {
250
     public MessageBean<String> ossUpload(MultipartFile file) {
251
         return MessageBean.ok(baseService.ossUpload(file), "oss上传");
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
     void deleteAllByTemplateIds(@Param("templateIds") List<Integer> templateIds);
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
 import com.lqkj.link.module.zone.repository.ModelCategoryRepository;
7
 import com.lqkj.link.module.zone.repository.ModelCategoryRepository;
8
 import com.lqkj.link.module.zone.repository.ModelInfoRepository;
8
 import com.lqkj.link.module.zone.repository.ModelInfoRepository;
9
 import com.lqkj.link.util.AliOSSUtils;
9
 import com.lqkj.link.util.AliOSSUtils;
10
+import com.lqkj.link.util.FileUtils;
10
 import com.lqkj.link.util.Unzipper;
11
 import com.lqkj.link.util.Unzipper;
11
 import org.apache.commons.compress.archivers.ArchiveException;
12
 import org.apache.commons.compress.archivers.ArchiveException;
12
 import org.springframework.beans.factory.annotation.Autowired;
13
 import org.springframework.beans.factory.annotation.Autowired;
@@ -121,16 +122,28 @@ public class ResourceService {
121
     }
122
     }
122
 
123
 
123
     public void deleteModel(Integer modelId) {
124
     public void deleteModel(Integer modelId) {
125
+        ModelInfo modelInfo = infoRepository.findById(modelId).get();
124
         infoRepository.deleteById(modelId);
126
         infoRepository.deleteById(modelId);
127
+        aliOSSUtils.deleteModel(modelInfo.getOriginalPath());
125
     }
128
     }
126
 
129
 
127
     @Transactional
130
     @Transactional
128
     public void deleteCategory(List<Integer> categoryId) {
131
     public void deleteCategory(List<Integer> categoryId) {
132
+        deleteOssFiles(categoryId);
129
         categoryRepository.deleteAllByIdInBatch(categoryId);
133
         categoryRepository.deleteAllByIdInBatch(categoryId);
130
         // 更新用户资源刷新状态
134
         // 更新用户资源刷新状态
131
         userInfoRepository.updateRefreshStatus();
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
     public List<Map<String, Object>> resourceCategory(String userCode) {
147
     public List<Map<String, Object>> resourceCategory(String userCode) {
135
         return categoryRepository.queryWithUserCode(userCode);
148
         return categoryRepository.queryWithUserCode(userCode);
136
     }
149
     }
@@ -164,4 +177,28 @@ public class ResourceService {
164
         UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
177
         UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
165
         return userInfo.getRefreshResource() != null && userInfo.getRefreshResource();
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
 import com.aliyun.oss.OSS;
3
 import com.aliyun.oss.OSS;
4
 import com.aliyun.oss.OSSClientBuilder;
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
 import org.springframework.beans.factory.annotation.Autowired;
8
 import org.springframework.beans.factory.annotation.Autowired;
6
 import org.springframework.stereotype.Component;
9
 import org.springframework.stereotype.Component;
7
 import org.springframework.web.multipart.MultipartFile;
10
 import org.springframework.web.multipart.MultipartFile;
@@ -13,6 +16,8 @@ import java.io.InputStream;
13
 import java.time.LocalDate;
16
 import java.time.LocalDate;
14
 import java.time.LocalDateTime;
17
 import java.time.LocalDateTime;
15
 import java.time.LocalTime;
18
 import java.time.LocalTime;
19
+import java.time.LocalDate;
20
+import java.util.List;
16
 import java.util.UUID;
21
 import java.util.UUID;
17
 import java.util.concurrent.Callable;
22
 import java.util.concurrent.Callable;
18
 
23
 
@@ -38,6 +43,11 @@ public class AliOSSUtils {
38
         String originalFilename = file.getName();
43
         String originalFilename = file.getName();
39
         String fileName = "file/" + LocalDate.now() + "/" + UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
44
         String fileName = "file/" + LocalDate.now() + "/" + UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
40
         //上传文件到 OSS
45
         //上传文件到 OSS
46
+        try {
47
+            Thread.sleep(200);
48
+        } catch (InterruptedException e) {
49
+            throw new RuntimeException(e);
50
+        }
41
         OSS ossClient = new OSSClientBuilder().build(aliProperties.getEndpoint(), aliProperties.getAccessKeyId(), aliProperties.getAccessKeySecret());
51
         OSS ossClient = new OSSClientBuilder().build(aliProperties.getEndpoint(), aliProperties.getAccessKeyId(), aliProperties.getAccessKeySecret());
42
         threadPoolUtil.getTaskExecutor().execute(() -> {
52
         threadPoolUtil.getTaskExecutor().execute(() -> {
43
             ossClient.putObject(aliProperties.getBucketName(), fileName, file);
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
         return result;
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
 alter table zone_info add column like_count INT4 default 0;
2
 alter table zone_info add column like_count INT4 default 0;
2
 comment on column zone_info.like_count is
3
 comment on column zone_info.like_count is
3
 '点赞数: like_count';
4
 '点赞数: like_count';
@@ -17,4 +18,24 @@ comment on column Likes.user_id is
17
 comment on column Likes.zone_id is
18
 comment on column Likes.zone_id is
18
 '点赞的作品id: zone_id';
19
 '点赞的作品id: zone_id';
19
 comment on column Likes.create_time is
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