diff --git a/bonus-modules/bonus-file/src/main/java/com/bonus/file/controller/SysFileController.java b/bonus-modules/bonus-file/src/main/java/com/bonus/file/controller/SysFileController.java index 6799348..677f2b0 100644 --- a/bonus-modules/bonus-file/src/main/java/com/bonus/file/controller/SysFileController.java +++ b/bonus-modules/bonus-file/src/main/java/com/bonus/file/controller/SysFileController.java @@ -3,7 +3,10 @@ package com.bonus.file.controller; import cn.hutool.core.util.ObjectUtil; import com.bonus.common.core.constant.HttpStatus; import com.bonus.common.core.utils.Base64Utils; +import com.bonus.common.core.utils.StringUtils; import com.bonus.common.core.web.domain.AjaxResult; +import com.bonus.file.entity.Base64File; +import com.bonus.file.entity.Base64ToMultipartFile; import com.bonus.file.service.ISysFileService; import com.bonus.system.api.domain.SysFile; import io.swagger.annotations.Api; @@ -11,16 +14,15 @@ import io.swagger.annotations.ApiOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.net.URLDecoder; +import java.util.Base64; +import java.util.UUID; /** * 文件请求处理 @@ -29,8 +31,7 @@ import java.net.URLDecoder; */ @RestController @Api("服务文件存储") -public class SysFileController -{ +public class SysFileController { private static final Logger log = LoggerFactory.getLogger(SysFileController.class); private final ISysFileService sysFileService; @@ -42,22 +43,91 @@ public class SysFileController /** * 单文件上传 + * * @param file 单个文件 * @return 文件信息,包括文件名和文件路径 */ @PostMapping("upload") @ApiOperation("上传本地文件到服务器") - public AjaxResult upload(MultipartFile file) - { - try - { + public AjaxResult upload(MultipartFile file) { + try { // 上传并返回访问地址 - if (ObjectUtil.isEmpty(file)) { return AjaxResult.error("上传文件不能为空");} + if (ObjectUtil.isEmpty(file)) { + return AjaxResult.error("上传文件不能为空"); + } SysFile sysFile = sysFileService.uploadFile(file); return AjaxResult.success(sysFile); + } catch (Exception e) { + log.error("上传文件失败", e); + return AjaxResult.error(e.getMessage()); } - catch (Exception e) - { + } + + + /** + * 单文件上传(支持Base64格式) + * + * @param base64File Base64编码的文件内容 + * @param fileName 文件名(可选) + * @param fileType 文件类型(如image/png,可选) + * @return 文件信息,包括文件名和文件路径 + */ + @PostMapping("uploadBase64") + @ApiOperation("上传Base64文件到服务器") + public AjaxResult uploadBase64(@RequestBody Base64File entity) { + try { + // 验证Base64数据是否为空 + if (StringUtils.isEmpty(entity.getBase64File())) { + return AjaxResult.error("上传文件内容不能为空"); + } + + // 处理可能包含的data URI前缀(如"data:image/png;base64,") + String base64Data; + if (entity.getBase64File().startsWith("data:")) { + // 提取真正的base64内容 + String[] parts = entity.getBase64File().split(","); + if (parts.length < 2) { + return AjaxResult.error("Base64格式不正确"); + } + base64Data = parts[1]; + + // 如果没传fileType,尝试从data URI中提取 + if (entity.getFileType() == null && parts[0].contains(":")) { + entity.setFileType(parts[0].split(":")[1].split(";")[0]); + } + } else { + base64Data = entity.getBase64File(); + } + + // 解码Base64 + byte[] fileBytes = Base64.getDecoder().decode(base64Data); + + // 如果没传文件名,生成一个随机文件名 + if (StringUtils.isEmpty(entity.getFileName())) { + entity.setFileName(UUID.randomUUID().toString()); + // 如果知道文件类型,添加合适的扩展名 + if (entity.getFileType() != null) { + String extension = ""; + if (entity.getFileType().equals("image/png")) { + extension = ".png"; + } else if (entity.getFileType().equals("image/jpeg")) { + extension = ".jpg"; + } else if (entity.getFileType().equals("application/pdf")) { + extension = ".pdf"; + } + entity.setFileName(entity.getFileName() + extension); + } + } + + // 创建临时MultipartFile对象 + MultipartFile multipartFile = new Base64ToMultipartFile(fileBytes, entity.getFileName(), entity.getFileType()); + // 调用原有的上传逻辑 + SysFile sysFile = sysFileService.uploadFile(multipartFile); + return AjaxResult.success(sysFile); + } catch (IllegalArgumentException e) { + log.error("Base64解码失败", e); + return AjaxResult.error("Base64格式不正确"); + } catch (Exception e) { log.error("上传文件失败", e); return AjaxResult.error(e.getMessage()); } @@ -65,30 +135,33 @@ public class SysFileController /** * 多文件上传 + * * @param files 多个文件流 * @return 文件信息 */ @PostMapping("/uploadFiles") public AjaxResult uploadFile(MultipartFile[] files) { try { - if (ObjectUtil.isEmpty(files)) { return AjaxResult.error("上传文件不能为空");} + if (ObjectUtil.isEmpty(files)) { + return AjaxResult.error("上传文件不能为空"); + } return AjaxResult.success(sysFileService.uploadFiles(files)); - } catch (Exception e) - { + } catch (Exception e) { return AjaxResult.error(e.getMessage()); } } /** * 文件下载 - * @param response 请求响应 + * + * @param response 请求响应 * @param objectKey,除mongodb 存fileid之外,其他均存上传文件的网络路径 */ @GetMapping("/download") public void downloadFile(HttpServletResponse response, @RequestParam String objectKey) throws IOException { try { - String fileUrl = Base64Utils.decodeUrl(URLDecoder.decode(objectKey)); - sysFileService.downloadFile(response, fileUrl); + String fileUrl = Base64Utils.decodeUrl(URLDecoder.decode(objectKey)); + sysFileService.downloadFile(response, fileUrl); } catch (Exception e) { log.error("downloadFile error:{}", e.getMessage()); response.setStatus(HttpStatus.ERROR); @@ -105,10 +178,11 @@ public class SysFileController /** * 文件删除 * 从各个存储平台删除文件 + * * @param objectKey * @param objectKey,除mongodb 存fileid之外,其他均存上传文件的网络路径 */ @PostMapping("/deleteFile") - public AjaxResult deleteFile(@RequestParam("objectKey") String objectKey) { + public AjaxResult deleteFile(@RequestParam("objectKey") String objectKey) { try { String fileUrl = Base64Utils.decodeUrl(URLDecoder.decode(objectKey)); sysFileService.deleteFile(fileUrl); @@ -120,37 +194,38 @@ public class SysFileController /** * 单文件上传到指定文件夹 + * * @param file 单个文件 * @return 文件信息,包括文件名和文件路径 */ @PostMapping("uploadToFolder") @ApiOperation("上传本地文件到服务器") - public AjaxResult upload(MultipartFile file, String folderName) - { + public AjaxResult upload(MultipartFile file, String folderName) { return AjaxResult.success("单文件上传成功"); } /** * 创建文件夹 + * * @param folderPath 文件夹路径(例如 "folder1/subfolder/") * @return 文件夹网络路径 */ @PostMapping("/createFolder") @ApiOperation("创建文件夹") - public AjaxResult createFolder(@RequestParam("folderName") String folderPath) - { + public AjaxResult createFolder(@RequestParam("folderName") String folderPath) { sysFileService.createFolder(folderPath); return AjaxResult.success("创建文件夹"); } /** * list 指定目录下所有文件信息(文件名,文件大小,上传时间,是否目录),包括子文件夹 + * * @param folderPath 要获取文件夹和文件的父文件夹路径(例如 "folder1/") * @return 文件夹网络路径 */ @GetMapping("/listFiles") - public AjaxResult listFiles(@RequestParam("folderName") String folderPath) { + public AjaxResult listFiles(@RequestParam("folderName") String folderPath) { return AjaxResult.success(sysFileService.getFilesAndSubfolders(folderPath)); } @@ -158,13 +233,27 @@ public class SysFileController /** * 文件夹删除 * 从各个存储平台删除文件 + * * @param folderPath 文件夹路径(例如 "folder1/subfolder/") * @return 文件夹网络路径 */ @PostMapping("/deleteFolder") - public AjaxResult deleteFolder(@RequestParam("folderName") String folderPath) { + public AjaxResult deleteFolder(@RequestParam("folderName") String folderPath) { sysFileService.deleteFolder(folderPath); return AjaxResult.success("文件夹删除成功"); } + + @PostMapping("/uploadResume") + public AjaxResult uploadResume(@RequestParam("md5") String md5, @RequestParam("chunkIndex") Integer chunkIndex, @RequestParam("file") MultipartFile file, @RequestParam("totalChunks") Integer totalChunks, @RequestParam("filename") String filename) { + try { + if (ObjectUtil.isEmpty(file)) { + return AjaxResult.error("上传文件不能为空"); + } + return AjaxResult.success(sysFileService.uploadResume(md5, chunkIndex, file, totalChunks, filename)); + } catch (Exception e) { + return AjaxResult.error(e.getMessage()); + } + } + } \ No newline at end of file diff --git a/bonus-modules/bonus-file/src/main/java/com/bonus/file/entity/Base64File.java b/bonus-modules/bonus-file/src/main/java/com/bonus/file/entity/Base64File.java new file mode 100644 index 0000000..1e8ac54 --- /dev/null +++ b/bonus-modules/bonus-file/src/main/java/com/bonus/file/entity/Base64File.java @@ -0,0 +1,17 @@ +package com.bonus.file.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Base64File { + + private String fileName; + + private String base64File; + + private String fileType; +} diff --git a/bonus-modules/bonus-file/src/main/java/com/bonus/file/entity/Base64ToMultipartFile.java b/bonus-modules/bonus-file/src/main/java/com/bonus/file/entity/Base64ToMultipartFile.java new file mode 100644 index 0000000..345f6dc --- /dev/null +++ b/bonus-modules/bonus-file/src/main/java/com/bonus/file/entity/Base64ToMultipartFile.java @@ -0,0 +1,62 @@ +package com.bonus.file.entity; + +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; + +/** + * 自定义MultipartFile实现,用于包装Base64解码后的数据 + */ +public class Base64ToMultipartFile implements MultipartFile { + private final byte[] content; + private final String name; + private final String contentType; + + public Base64ToMultipartFile(byte[] content, String name, String contentType) { + this.content = content; + this.name = name; + this.contentType = contentType; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getOriginalFilename() { + return name; + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public boolean isEmpty() { + return content == null || content.length == 0; + } + + @Override + public long getSize() { + return content.length; + } + + @Override + public byte[] getBytes() throws IOException { + return content; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(content); + } + + @Override + public void transferTo(File dest) throws IOException, IllegalStateException { + try (FileOutputStream fos = new FileOutputStream(dest)) { + fos.write(content); + } + } +} \ No newline at end of file