diff --git a/base/src/main/java/com/tinyengine/it/common/utils/ImageThumbnailGenerator.java b/base/src/main/java/com/tinyengine/it/common/utils/ImageThumbnailGenerator.java index 4b653ef0..5678ce12 100644 --- a/base/src/main/java/com/tinyengine/it/common/utils/ImageThumbnailGenerator.java +++ b/base/src/main/java/com/tinyengine/it/common/utils/ImageThumbnailGenerator.java @@ -19,6 +19,7 @@ import org.apache.batik.transcoder.image.JPEGTranscoder; import org.apache.batik.transcoder.image.PNGTranscoder; import org.apache.batik.util.XMLResourceDescriptor; +import org.springframework.web.multipart.MultipartFile; import org.w3c.dom.Document; import javax.imageio.ImageIO; @@ -26,6 +27,8 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.HashMap; import java.util.Map; @@ -235,6 +238,70 @@ public static String extractContentType(String base64Data) { throw new IllegalArgumentException("Cannot extract content type from Base64 data"); } + /** + * 图片验证 + */ + public static boolean validateByImageIO(MultipartFile file) { + try { + String filename = file.getOriginalFilename(); + if (filename == null) { + return false; + } + // 获取文件扩展名 + String extension = getFileExtension(filename).toLowerCase(); + + if ("svg".equals(extension)) { + return isSvgFile(file); + } + + BufferedImage image = ImageIO.read(new ByteArrayInputStream(file.getBytes())); + return image != null; + } catch (IOException e) { + return false; + } + } + + /** + * SVG文件验证 + */ + private static boolean isSvgFile(MultipartFile file) { + try { + byte[] bytes = file.getBytes(); + String content = new String(bytes, StandardCharsets.UTF_8); + + // 简单检查:包含 aiChat(@RequestBody ChatRequest request) { try { @@ -99,12 +99,12 @@ public ResponseEntity aiChat(@RequestBody ChatRequest request) { @Parameter(name = "ChatRequest", description = "入参对象") }, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema())), + content = @Content(mediaType = "application/json", schema = @Schema())), @ApiResponse(responseCode = "400", description = "请求失败") }) - @SystemControllerLog(description = "AI api v1") + @SystemControllerLog(description = "AI completions") @PostMapping("/chat/completions") - public ResponseEntity chat(@RequestBody ChatRequest request, + public ResponseEntity completions(@RequestBody ChatRequest request, @RequestHeader("Authorization") String authorization) { if (authorization != null && authorization.startsWith("Bearer ")) { String token = authorization.replace("Bearer ", ""); @@ -133,11 +133,11 @@ public ResponseEntity chat(@RequestBody ChatRequest request, * @return ai回答信息 result */ @Operation(summary = "搜索知识库", description = "搜索知识库", - parameters = { - @Parameter(name = "content", description = "入参对象") - }, responses = { + parameters = { + @Parameter(name = "content", description = "入参对象") + }, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema())), + content = @Content(mediaType = "application/json", schema = @Schema())), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "AI serarch api") diff --git a/base/src/main/java/com/tinyengine/it/controller/ResourceController.java b/base/src/main/java/com/tinyengine/it/controller/ResourceController.java index d445f35c..05d13f76 100644 --- a/base/src/main/java/com/tinyengine/it/controller/ResourceController.java +++ b/base/src/main/java/com/tinyengine/it/controller/ResourceController.java @@ -13,6 +13,8 @@ package com.tinyengine.it.controller; import com.tinyengine.it.common.base.Result; +import com.tinyengine.it.common.context.LoginUserContext; +import com.tinyengine.it.common.exception.ExceptionEnum; import com.tinyengine.it.common.log.SystemControllerLog; import com.tinyengine.it.common.utils.ImageThumbnailGenerator; import com.tinyengine.it.common.utils.Utils; @@ -28,6 +30,7 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -38,6 +41,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; import java.io.OutputStream; import java.net.URLEncoder; @@ -61,6 +65,9 @@ public class ResourceController { @Autowired private ResourceService resourceService; + @Autowired + private LoginUserContext loginUserContext; + /** * 查询表Resource信息 * @@ -69,7 +76,7 @@ public class ResourceController { @Operation(summary = "查询表Resource信息", description = "查询表Resource信息", responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "查询表Resource信息") @@ -90,7 +97,7 @@ public Result> getAllResource() { @Parameter(name = "id", description = "Resource主键id") }, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "根据id查询表Resource信息") @@ -110,7 +117,7 @@ public Result getResourceById(@PathVariable Integer id) { @Parameter(name = "resourceGroupId", description = "ResourceGroup主键id") }, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "根据分组id和创建人查询表t_resource信息") @@ -132,7 +139,7 @@ public Result> getResourceByResourceGroupId(@PathVariable Integer @Parameter(name = "des", description = "描述") }, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "模糊查询表Resource信息列表") @@ -154,7 +161,7 @@ public Result> getResourceById(@RequestParam String name, @Reques @Parameter(name = "resource", description = "Resource入参对象") }, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "创建resource") @@ -167,20 +174,36 @@ public Result createResource(@Valid @RequestBody Resource resource) th /** * 上传图片 * - * @param resource the resource + * @param file the file * @return Resource信息 result */ @Operation(summary = "上传图片", description = "上传图片", - parameters = { - @Parameter(name = "resource", description = "Resource入参对象") - }, responses = { + parameters = { + @Parameter(name = "file", description = "图片") + }, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "上传图片") - @PostMapping("/resource/uoload") - public Result resourceUoload(@Valid @RequestBody Resource resource) throws Exception { + @PostMapping("/resource/upload") + public Result resourceUpload(@RequestParam MultipartFile file) throws Exception { + // 获取文件的原始名称 + String fileName = StringUtils.cleanPath(java.util.Optional.ofNullable(file.getOriginalFilename()).orElse("image")); + + if(!ImageThumbnailGenerator.validateByImageIO(file)){ + return Result.failed(ExceptionEnum.CM325); + } + if(fileName.contains("..")) { + return Result.failed(ExceptionEnum.CM325); + } + // 将文件转为 Base64 + String base64 = ImageThumbnailGenerator.convertToBase64(file); + Resource resource = new Resource(); + resource.setName(fileName); + resource.setResourceData(base64); + resource.setAppId(loginUserContext.getAppId()); + resource.setCategory("image"); Resource result = resourceService.resourceUpload(resource); return Result.success(result); } @@ -196,7 +219,7 @@ public Result resourceUoload(@Valid @RequestBody Resource resource) th @Parameter(name = "resources", description = "Resource入参对象") }, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "批量创建Resource") @@ -218,7 +241,7 @@ public Result> createResource(@Valid @RequestBody List @Parameter(name = "id", description = "id"), @Parameter(name = "Resource", description = "入参对象")}, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "修改单个Resource信息") @@ -258,7 +281,7 @@ public Result deleteResource(@PathVariable Integer id) { parameters = { @Parameter(name = "id", description = "id")}, responses = { @ApiResponse(responseCode = "200", description = "返回信息", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "获取resource信息详情") @@ -277,7 +300,7 @@ public Result detail(@PathVariable Integer id) { parameters = { @Parameter(name = "data", description = "base64编码数据")}, responses = { @ApiResponse(responseCode = "200", description = "图片流数据", - content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), + content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))), @ApiResponse(responseCode = "400", description = "请求失败") }) @SystemControllerLog(description = "获取资源")