Skip to content

Commit ff2f353

Browse files
authored
fix: modify resource upload (opentiny#262)
* fix: modify resource upload
1 parent 1756a9a commit ff2f353

File tree

3 files changed

+115
-25
lines changed

3 files changed

+115
-25
lines changed

base/src/main/java/com/tinyengine/it/common/utils/ImageThumbnailGenerator.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919
import org.apache.batik.transcoder.image.JPEGTranscoder;
2020
import org.apache.batik.transcoder.image.PNGTranscoder;
2121
import org.apache.batik.util.XMLResourceDescriptor;
22+
import org.springframework.web.multipart.MultipartFile;
2223
import org.w3c.dom.Document;
2324

2425
import javax.imageio.ImageIO;
2526
import java.awt.*;
2627
import java.awt.image.BufferedImage;
2728
import java.io.ByteArrayInputStream;
2829
import java.io.ByteArrayOutputStream;
30+
import java.io.IOException;
31+
import java.nio.charset.StandardCharsets;
2932
import java.util.Base64;
3033
import java.util.HashMap;
3134
import java.util.Map;
@@ -235,6 +238,70 @@ public static String extractContentType(String base64Data) {
235238
throw new IllegalArgumentException("Cannot extract content type from Base64 data");
236239
}
237240

241+
/**
242+
* 图片验证
243+
*/
244+
public static boolean validateByImageIO(MultipartFile file) {
245+
try {
246+
String filename = file.getOriginalFilename();
247+
if (filename == null) {
248+
return false;
249+
}
250+
// 获取文件扩展名
251+
String extension = getFileExtension(filename).toLowerCase();
252+
253+
if ("svg".equals(extension)) {
254+
return isSvgFile(file);
255+
}
256+
257+
BufferedImage image = ImageIO.read(new ByteArrayInputStream(file.getBytes()));
258+
return image != null;
259+
} catch (IOException e) {
260+
return false;
261+
}
262+
}
263+
264+
/**
265+
* SVG文件验证
266+
*/
267+
private static boolean isSvgFile(MultipartFile file) {
268+
try {
269+
byte[] bytes = file.getBytes();
270+
String content = new String(bytes, StandardCharsets.UTF_8);
271+
272+
// 简单检查:包含<svg标签和SVG命名空间
273+
return content.contains("<svg") &&
274+
(content.contains("xmlns=\"http://www.w3.org/2000/svg\"") ||
275+
content.contains("xmlns='http://www.w3.org/2000/svg'"));
276+
277+
} catch (IOException e) {
278+
return false;
279+
}
280+
}
281+
/**
282+
* 获取文件扩展名
283+
*/
284+
private static String getFileExtension(String filename) {
285+
if (filename == null || !filename.contains(".")) {
286+
return "";
287+
}
288+
return filename.substring(filename.lastIndexOf(".") + 1);
289+
}
290+
/**
291+
* 简化版Base64转换
292+
*/
293+
public static String convertToBase64(MultipartFile file) throws IOException {
294+
String mimeType = file.getContentType();
295+
byte[] fileBytes = file.getBytes();
296+
String base64 = Base64.getEncoder().encodeToString(fileBytes);
297+
// 如果是SVG文件,修正MIME类型
298+
String filename = file.getOriginalFilename();
299+
if (filename != null && filename.toLowerCase().endsWith(".svg")) {
300+
mimeType = "image/svg+xml";
301+
}
302+
return "data:" + mimeType + ";base64," + base64;
303+
}
304+
238305
/**
239306
* MIME类型转格式
240307
*/

base/src/main/java/com/tinyengine/it/controller/AiChatController.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ public class AiChatController {
6666
@Parameter(name = "ChatRequest", description = "入参对象")
6767
}, responses = {
6868
@ApiResponse(responseCode = "200", description = "返回信息",
69-
content = @Content(mediaType = "application/json", schema = @Schema())),
69+
content = @Content(mediaType = "application/json", schema = @Schema())),
7070
@ApiResponse(responseCode = "400", description = "请求失败")
7171
})
72-
@SystemControllerLog(description = "AI api")
72+
@SystemControllerLog(description = "AI chat")
7373
@PostMapping("/ai/chat")
7474
public ResponseEntity<?> aiChat(@RequestBody ChatRequest request) {
7575
try {
@@ -99,12 +99,12 @@ public ResponseEntity<?> aiChat(@RequestBody ChatRequest request) {
9999
@Parameter(name = "ChatRequest", description = "入参对象")
100100
}, responses = {
101101
@ApiResponse(responseCode = "200", description = "返回信息",
102-
content = @Content(mediaType = "application/json", schema = @Schema())),
102+
content = @Content(mediaType = "application/json", schema = @Schema())),
103103
@ApiResponse(responseCode = "400", description = "请求失败")
104104
})
105-
@SystemControllerLog(description = "AI api v1")
105+
@SystemControllerLog(description = "AI completions")
106106
@PostMapping("/chat/completions")
107-
public ResponseEntity<?> chat(@RequestBody ChatRequest request,
107+
public ResponseEntity<?> completions(@RequestBody ChatRequest request,
108108
@RequestHeader("Authorization") String authorization) {
109109
if (authorization != null && authorization.startsWith("Bearer ")) {
110110
String token = authorization.replace("Bearer ", "");
@@ -133,11 +133,11 @@ public ResponseEntity<?> chat(@RequestBody ChatRequest request,
133133
* @return ai回答信息 result
134134
*/
135135
@Operation(summary = "搜索知识库", description = "搜索知识库",
136-
parameters = {
137-
@Parameter(name = "content", description = "入参对象")
138-
}, responses = {
136+
parameters = {
137+
@Parameter(name = "content", description = "入参对象")
138+
}, responses = {
139139
@ApiResponse(responseCode = "200", description = "返回信息",
140-
content = @Content(mediaType = "application/json", schema = @Schema())),
140+
content = @Content(mediaType = "application/json", schema = @Schema())),
141141
@ApiResponse(responseCode = "400", description = "请求失败")
142142
})
143143
@SystemControllerLog(description = "AI serarch api")

base/src/main/java/com/tinyengine/it/controller/ResourceController.java

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
package com.tinyengine.it.controller;
1414

1515
import com.tinyengine.it.common.base.Result;
16+
import com.tinyengine.it.common.context.LoginUserContext;
17+
import com.tinyengine.it.common.exception.ExceptionEnum;
1618
import com.tinyengine.it.common.log.SystemControllerLog;
1719
import com.tinyengine.it.common.utils.ImageThumbnailGenerator;
1820
import com.tinyengine.it.common.utils.Utils;
@@ -28,6 +30,7 @@
2830
import jakarta.servlet.http.HttpServletResponse;
2931
import jakarta.validation.Valid;
3032
import org.springframework.beans.factory.annotation.Autowired;
33+
import org.springframework.util.StringUtils;
3134
import org.springframework.validation.annotation.Validated;
3235
import org.springframework.web.bind.annotation.DeleteMapping;
3336
import org.springframework.web.bind.annotation.GetMapping;
@@ -38,6 +41,7 @@
3841
import org.springframework.web.bind.annotation.RequestMapping;
3942
import org.springframework.web.bind.annotation.RequestParam;
4043
import org.springframework.web.bind.annotation.RestController;
44+
import org.springframework.web.multipart.MultipartFile;
4145

4246
import java.io.OutputStream;
4347
import java.net.URLEncoder;
@@ -61,6 +65,9 @@ public class ResourceController {
6165
@Autowired
6266
private ResourceService resourceService;
6367

68+
@Autowired
69+
private LoginUserContext loginUserContext;
70+
6471
/**
6572
* 查询表Resource信息
6673
*
@@ -69,7 +76,7 @@ public class ResourceController {
6976
@Operation(summary = "查询表Resource信息", description = "查询表Resource信息",
7077
responses = {
7178
@ApiResponse(responseCode = "200", description = "返回信息",
72-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
79+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
7380
@ApiResponse(responseCode = "400", description = "请求失败")
7481
})
7582
@SystemControllerLog(description = "查询表Resource信息")
@@ -90,7 +97,7 @@ public Result<List<Resource>> getAllResource() {
9097
@Parameter(name = "id", description = "Resource主键id")
9198
}, responses = {
9299
@ApiResponse(responseCode = "200", description = "返回信息",
93-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
100+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
94101
@ApiResponse(responseCode = "400", description = "请求失败")
95102
})
96103
@SystemControllerLog(description = "根据id查询表Resource信息")
@@ -110,7 +117,7 @@ public Result<Resource> getResourceById(@PathVariable Integer id) {
110117
@Parameter(name = "resourceGroupId", description = "ResourceGroup主键id")
111118
}, responses = {
112119
@ApiResponse(responseCode = "200", description = "返回信息",
113-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
120+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
114121
@ApiResponse(responseCode = "400", description = "请求失败")
115122
})
116123
@SystemControllerLog(description = "根据分组id和创建人查询表t_resource信息")
@@ -132,7 +139,7 @@ public Result<List<Resource>> getResourceByResourceGroupId(@PathVariable Integer
132139
@Parameter(name = "des", description = "描述")
133140
}, responses = {
134141
@ApiResponse(responseCode = "200", description = "返回信息",
135-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
142+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
136143
@ApiResponse(responseCode = "400", description = "请求失败")
137144
})
138145
@SystemControllerLog(description = "模糊查询表Resource信息列表")
@@ -154,7 +161,7 @@ public Result<List<Resource>> getResourceById(@RequestParam String name, @Reques
154161
@Parameter(name = "resource", description = "Resource入参对象")
155162
}, responses = {
156163
@ApiResponse(responseCode = "200", description = "返回信息",
157-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
164+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
158165
@ApiResponse(responseCode = "400", description = "请求失败")
159166
})
160167
@SystemControllerLog(description = "创建resource")
@@ -167,20 +174,36 @@ public Result<Resource> createResource(@Valid @RequestBody Resource resource) th
167174
/**
168175
* 上传图片
169176
*
170-
* @param resource the resource
177+
* @param file the file
171178
* @return Resource信息 result
172179
*/
173180
@Operation(summary = "上传图片", description = "上传图片",
174-
parameters = {
175-
@Parameter(name = "resource", description = "Resource入参对象")
176-
}, responses = {
181+
parameters = {
182+
@Parameter(name = "file", description = "图片")
183+
}, responses = {
177184
@ApiResponse(responseCode = "200", description = "返回信息",
178-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
185+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
179186
@ApiResponse(responseCode = "400", description = "请求失败")
180187
})
181188
@SystemControllerLog(description = "上传图片")
182-
@PostMapping("/resource/uoload")
183-
public Result<Resource> resourceUoload(@Valid @RequestBody Resource resource) throws Exception {
189+
@PostMapping("/resource/upload")
190+
public Result<Resource> resourceUpload(@RequestParam MultipartFile file) throws Exception {
191+
// 获取文件的原始名称
192+
String fileName = StringUtils.cleanPath(java.util.Optional.ofNullable(file.getOriginalFilename()).orElse("image"));
193+
194+
if(!ImageThumbnailGenerator.validateByImageIO(file)){
195+
return Result.failed(ExceptionEnum.CM325);
196+
}
197+
if(fileName.contains("..")) {
198+
return Result.failed(ExceptionEnum.CM325);
199+
}
200+
// 将文件转为 Base64
201+
String base64 = ImageThumbnailGenerator.convertToBase64(file);
202+
Resource resource = new Resource();
203+
resource.setName(fileName);
204+
resource.setResourceData(base64);
205+
resource.setAppId(loginUserContext.getAppId());
206+
resource.setCategory("image");
184207
Resource result = resourceService.resourceUpload(resource);
185208
return Result.success(result);
186209
}
@@ -196,7 +219,7 @@ public Result<Resource> resourceUoload(@Valid @RequestBody Resource resource) th
196219
@Parameter(name = "resources", description = "Resource入参对象")
197220
}, responses = {
198221
@ApiResponse(responseCode = "200", description = "返回信息",
199-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
222+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
200223
@ApiResponse(responseCode = "400", description = "请求失败")
201224
})
202225
@SystemControllerLog(description = "批量创建Resource")
@@ -218,7 +241,7 @@ public Result<List<Resource>> createResource(@Valid @RequestBody List<Resource>
218241
@Parameter(name = "id", description = "id"),
219242
@Parameter(name = "Resource", description = "入参对象")}, responses = {
220243
@ApiResponse(responseCode = "200", description = "返回信息",
221-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
244+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
222245
@ApiResponse(responseCode = "400", description = "请求失败")
223246
})
224247
@SystemControllerLog(description = "修改单个Resource信息")
@@ -258,7 +281,7 @@ public Result<Resource> deleteResource(@PathVariable Integer id) {
258281
parameters = {
259282
@Parameter(name = "id", description = "id")}, responses = {
260283
@ApiResponse(responseCode = "200", description = "返回信息",
261-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
284+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
262285
@ApiResponse(responseCode = "400", description = "请求失败")
263286
})
264287
@SystemControllerLog(description = "获取resource信息详情")
@@ -277,7 +300,7 @@ public Result<Resource> detail(@PathVariable Integer id) {
277300
parameters = {
278301
@Parameter(name = "data", description = "base64编码数据")}, responses = {
279302
@ApiResponse(responseCode = "200", description = "图片流数据",
280-
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
303+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
281304
@ApiResponse(responseCode = "400", description = "请求失败")
282305
})
283306
@SystemControllerLog(description = "获取资源")

0 commit comments

Comments
 (0)