diff --git a/pom.xml b/pom.xml index f14fffc..771ee66 100644 --- a/pom.xml +++ b/pom.xml @@ -63,8 +63,12 @@ hutool-all 5.8.26 - - + + + io.minio + minio + 8.5.17 + diff --git a/src/main/java/com/huangge1199/picture/config/MinioConfig.java b/src/main/java/com/huangge1199/picture/config/MinioConfig.java new file mode 100644 index 0000000..c462342 --- /dev/null +++ b/src/main/java/com/huangge1199/picture/config/MinioConfig.java @@ -0,0 +1,37 @@ +package com.huangge1199.picture.config; + +import org.springframework.context.annotation.Configuration; +import io.minio.MinioClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; + +/** + * MinioConfig + * + * @author huangge1199 + * @since 2025/7/25 10:38:38 + */ +@Configuration +public class MinioConfig { + + // 从配置文件中获取Minio的endpoint + @Value("${minio.endpoint}") + private String endpoint; + + // 从配置文件中获取Minio的accessKey + @Value("${minio.access-key}") + private String accessKey; + + // 从配置文件中获取Minio的secretKey + @Value("${minio.secret-key}") + private String secretKey; + + // 创建MinioClient的Bean + @Bean + public MinioClient minioClient() { + return MinioClient.builder() + .endpoint(endpoint) + .credentials(accessKey, secretKey) + .build(); + } +} diff --git a/src/main/java/com/huangge1199/picture/controller/FileController.java b/src/main/java/com/huangge1199/picture/controller/FileController.java new file mode 100644 index 0000000..bee5384 --- /dev/null +++ b/src/main/java/com/huangge1199/picture/controller/FileController.java @@ -0,0 +1,54 @@ +package com.huangge1199.picture.controller; + +import com.huangge1199.picture.common.R; +import com.huangge1199.picture.service.FileService; +import org.springframework.web.bind.annotation.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; + +/** + * 文件 + * + * @author huangge1199 + * @since 2025/7/25 10:51:38 + */ +@RestController +@RequestMapping("/file") +public class FileController { + + @Resource + private FileService fileService; + + /** + * 文件上传 + * @param file 文件 + * @return 文件上传地址 + */ + @PostMapping("/upload") + public R uploadFile(@RequestParam("file") MultipartFile file) { + try { + String url = fileService.uploadFile(file); + return R.ok(url); + } catch (Exception e) { + return R.fail("上传失败: " + e.getMessage()); + } + } + + /** + * 文件删除 + * @param fileUrl 文件的URL + * @return 操作结果 + */ + @DeleteMapping + public R deleteFile(@RequestParam String fileUrl) { + try { + fileService.deleteFile(fileUrl); + return R.ok("文件删除成功"); + } catch (Exception e) { + return R.fail("删除失败: " + e.getMessage()); + } + } +} diff --git a/src/main/java/com/huangge1199/picture/service/FileService.java b/src/main/java/com/huangge1199/picture/service/FileService.java new file mode 100644 index 0000000..0af44ec --- /dev/null +++ b/src/main/java/com/huangge1199/picture/service/FileService.java @@ -0,0 +1,15 @@ +package com.huangge1199.picture.service; + +import org.springframework.web.multipart.MultipartFile; + +/** + * FileService + * + * @author huangge1199 + * @since 2025/7/25 10:52:55 + */ +public interface FileService { + String uploadFile(MultipartFile file) throws Exception; + + void deleteFile(String fileUrl) throws Exception; +} diff --git a/src/main/java/com/huangge1199/picture/service/impl/FileServiceImpl.java b/src/main/java/com/huangge1199/picture/service/impl/FileServiceImpl.java new file mode 100644 index 0000000..53def60 --- /dev/null +++ b/src/main/java/com/huangge1199/picture/service/impl/FileServiceImpl.java @@ -0,0 +1,40 @@ +package com.huangge1199.picture.service.impl; + +import com.huangge1199.picture.service.FileService; +import com.huangge1199.picture.utils.MinioUtil; +import org.springframework.stereotype.Service; +import io.minio.MinioClient; +import io.minio.PutObjectArgs; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.util.UUID; + +/** + * FileServiceImpl + * + * @author huangge1199 + * @since 2025/7/25 10:53:09 + */ +@Service +public class FileServiceImpl implements FileService { + + @Resource + private MinioUtil minioUtil; + + @Override + public String uploadFile(MultipartFile file) throws Exception { + + // 生成唯一文件名 + String originalFilename = file.getOriginalFilename(); + String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".")); + + return minioUtil.upload(file.getInputStream(),fileExtension,file.getContentType()); + } + + @Override + public void deleteFile(String fileUrl) throws Exception { + minioUtil.deleteFile(fileUrl); + } +} diff --git a/src/main/java/com/huangge1199/picture/utils/MinioUtil.java b/src/main/java/com/huangge1199/picture/utils/MinioUtil.java new file mode 100644 index 0000000..9262a97 --- /dev/null +++ b/src/main/java/com/huangge1199/picture/utils/MinioUtil.java @@ -0,0 +1,74 @@ +package com.huangge1199.picture.utils; + +import io.minio.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.InputStream; +import java.util.UUID; + +/** + * MinioUtil + * + * @author huangge1199 + * @since 2025/7/25 10:45:58 + */ +@Component +@Slf4j +public class MinioUtil { + + @Resource + private MinioClient minioClient; + + @Value("${minio.bucket}") + private String bucketName; + + @Value("${minio.endpoint}") + private String endpoint; + + /** + * 上传文件到 MinIO 并返回访问地址 + * + * @param inputStream 文件流 + * @param originalFilename 原始文件名 + * @param contentType 文件类型(如 image/jpeg) + * @return 公网访问地址 + */ + public String upload(InputStream inputStream, String originalFilename, String contentType) throws Exception { + // 生成文件名 + String fileName = UUID.randomUUID() + "_" + originalFilename; + + // 上传文件到 MinIO + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketName) + .object(fileName) + .stream(inputStream, inputStream.available(), -1) + .contentType(contentType) + .build()); + + // 拼接访问地址(取决于 MinIO 是否配置了静态资源网关) + return String.format("%s/%s/%s", endpoint, bucketName, fileName); + } + + /** + * 删除 Minio 中的文件 + * + * @param fileUrl 文件的URL(需要从中提取文件名) + */ + public void deleteFile(String fileUrl) throws Exception { + String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1); + try { + minioClient.removeObject( + RemoveObjectArgs.builder() + .bucket(bucketName) + .object(fileName) + .build()); + log.info("文件删除成功: {}", fileName); + } catch (Exception e) { + log.error("文件删除失败: {}", fileName, e); + throw new RuntimeException("文件删除失败: " + e.getMessage()); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5852379..5b11252 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -8,9 +8,11 @@ spring: # 数据库配置 datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://192.168.188.2:3306/long-picture - username: root - password: huangge1199 + url: jdbc:mysql://ip:端口/数据库名 + username: 数据库用户名 + password: 数据库密码 + profiles: + active: local mybatis-plus: configuration: map-underscore-to-camel-case: false