diff --git a/src/main/java/com/example/catchTheLetters/config/MinioConfig.java b/src/main/java/com/example/catchTheLetters/config/MinioConfig.java deleted file mode 100644 index 2ccff41..0000000 --- a/src/main/java/com/example/catchTheLetters/config/MinioConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.example.catchTheLetters.config; - -import io.minio.MinioClient; -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties(prefix = "minio") -public class MinioConfig { - private String endpoint; - private String bucket; - private String accessKey; - private String secretKey; - - @Bean - public MinioClient minioClient(){ - return MinioClient.builder() - .endpoint(endpoint) - .credentials(accessKey, secretKey) - .build(); - } - -} diff --git a/src/main/java/com/example/catchTheLetters/controller/AuthController.java b/src/main/java/com/example/catchTheLetters/controller/AuthController.java index d032d3d..c7dbb22 100644 --- a/src/main/java/com/example/catchTheLetters/controller/AuthController.java +++ b/src/main/java/com/example/catchTheLetters/controller/AuthController.java @@ -14,6 +14,7 @@ import jakarta.annotation.Resource; import jakarta.validation.constraints.Email; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; /** * 认证控制器 @@ -85,4 +86,10 @@ public class AuthController { public R emailVerify(String email, String code) { return emailService.verifyEmail(email, code); } + + @ApiOperation(value = "上传头像文件") + @PostMapping("/upload-avatar") + public R uploadAvatar(@RequestHeader("token") String token, @RequestParam("file") MultipartFile file) { + return authService.uploadAvatar(token, file); + } } diff --git a/src/main/java/com/example/catchTheLetters/controller/LevelController.java b/src/main/java/com/example/catchTheLetters/controller/LevelController.java index 31c14cc..eeddf40 100644 --- a/src/main/java/com/example/catchTheLetters/controller/LevelController.java +++ b/src/main/java/com/example/catchTheLetters/controller/LevelController.java @@ -13,7 +13,6 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import java.io.IOException; import java.util.List; /** @@ -112,9 +111,4 @@ public class LevelController { public R> getNewVersion(){ return versionService.getNewDownloads(); } - - @PostMapping("/test") - public R testMinio(MultipartFile file) throws Exception { - return R.ok(versionService.testMinIO(file)); - } -} \ No newline at end of file +} diff --git a/src/main/java/com/example/catchTheLetters/service/AuthService.java b/src/main/java/com/example/catchTheLetters/service/AuthService.java index 6fa3801..0a48d2f 100644 --- a/src/main/java/com/example/catchTheLetters/service/AuthService.java +++ b/src/main/java/com/example/catchTheLetters/service/AuthService.java @@ -5,6 +5,7 @@ import com.example.catchTheLetters.model.dto.RegisterDto; import com.example.catchTheLetters.entity.User; import com.example.catchTheLetters.model.vo.UserVo; import com.example.catchTheLetters.utils.R; +import org.springframework.web.multipart.MultipartFile; /** * 认证服务接口 @@ -68,4 +69,13 @@ public interface AuthService { * @return 新的用户信息 */ R update(User user, String token); + + /** + * 上传头像 + * + * @param token token + * @param file 头像文件 + * @return 头像地址 + */ + R uploadAvatar(String token, MultipartFile file); } diff --git a/src/main/java/com/example/catchTheLetters/service/VersionService.java b/src/main/java/com/example/catchTheLetters/service/VersionService.java index 37cb539..a4da1f2 100644 --- a/src/main/java/com/example/catchTheLetters/service/VersionService.java +++ b/src/main/java/com/example/catchTheLetters/service/VersionService.java @@ -42,6 +42,4 @@ public interface VersionService { * @return 版本集合 */ R> getNewDownloads(); - - String testMinIO(MultipartFile file) throws Exception; } diff --git a/src/main/java/com/example/catchTheLetters/service/impl/AuthServiceImpl.java b/src/main/java/com/example/catchTheLetters/service/impl/AuthServiceImpl.java index 1a5e9ad..6ea74d7 100644 --- a/src/main/java/com/example/catchTheLetters/service/impl/AuthServiceImpl.java +++ b/src/main/java/com/example/catchTheLetters/service/impl/AuthServiceImpl.java @@ -10,12 +10,14 @@ import com.example.catchTheLetters.service.AuthService; import com.example.catchTheLetters.service.RedisService; import com.example.catchTheLetters.utils.DESUtil; import com.example.catchTheLetters.utils.JwtUtil; +import com.example.catchTheLetters.utils.MinioUtil; import com.example.catchTheLetters.utils.R; import jakarta.annotation.Resource; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; import java.util.HashMap; import java.util.Map; @@ -34,6 +36,9 @@ public class AuthServiceImpl implements AuthService { @Resource private DESUtil desUtil; + @Resource + private MinioUtil minioUtil; + @Override public R login(LoginDto loginDto) { // 根据用户名查询用户信息 @@ -209,4 +214,20 @@ public class AuthServiceImpl implements AuthService { return R.ok(mongoTemplate.save(verify).toVo()); } + + @Override + public R uploadAvatar(String token, MultipartFile file) { + var user = verify(token); + if (user == null) { + return R.fail(HttpStatus.TOKEN_EXCEPTION.getCode(), HttpStatus.TOKEN_EXCEPTION.getDesc()); + } + + // 随机生成文件名 + var fileName = System.currentTimeMillis() + file.getOriginalFilename(); + + // 上传头像到minio + var success = minioUtil.uploadFile(file, "avatar/" + fileName); + + return success ? R.ok("http://1.14.105.160:9001/catchtheletters/avatar/" + fileName) : R.fail("上传失败"); + } } diff --git a/src/main/java/com/example/catchTheLetters/service/impl/VersionServiceImpl.java b/src/main/java/com/example/catchTheLetters/service/impl/VersionServiceImpl.java index bde81f5..7905a70 100644 --- a/src/main/java/com/example/catchTheLetters/service/impl/VersionServiceImpl.java +++ b/src/main/java/com/example/catchTheLetters/service/impl/VersionServiceImpl.java @@ -1,15 +1,10 @@ package com.example.catchTheLetters.service.impl; -import com.example.catchTheLetters.config.MinioConfig; -import com.example.catchTheLetters.constant.CommonConstant; import com.example.catchTheLetters.entity.Version; import com.example.catchTheLetters.entity.VersionDownload; import com.example.catchTheLetters.service.VersionService; import com.example.catchTheLetters.utils.R; -import io.minio.*; -import io.minio.errors.*; import jakarta.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; @@ -17,11 +12,6 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; import java.util.List; @Service @@ -30,11 +20,6 @@ public class VersionServiceImpl implements VersionService { @Resource private MongoTemplate mongoTemplate; - @Resource - private MinioClient minioClient; - @Autowired - private MinioConfig minioConfig; - @Override public Long getVersion(String tableName) { var res = mongoTemplate.findOne(new Query(Criteria.where("table").is(tableName)), Version.class); @@ -75,12 +60,4 @@ public class VersionServiceImpl implements VersionService { List list = mongoTemplate.find(query, VersionDownload.class); return R.ok(list); } - - @Override - public String testMinIO(MultipartFile file) throws Exception { - System.out.println(minioConfig.getBucket()); - minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioConfig.getBucket()).build()); -// boolean bucketFound = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioConfig.getBucket()).build()); - return "未找到"; - } } diff --git a/src/main/java/com/example/catchTheLetters/utils/MinioUtil.java b/src/main/java/com/example/catchTheLetters/utils/MinioUtil.java new file mode 100644 index 0000000..2d84bcc --- /dev/null +++ b/src/main/java/com/example/catchTheLetters/utils/MinioUtil.java @@ -0,0 +1,264 @@ +package com.example.catchTheLetters.utils; + +import io.minio.*; +import io.minio.messages.Item; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * @description minio工具类 + * @className MinioUtil + * @auther spyn + */ + +@Slf4j +@Data +@Configuration +@ConfigurationProperties(prefix = "minio") +public class MinioUtil { + + private String url; + + private String accessKey; + + private String secretKey; + + private String bucketName; + + private MinioClient minioClient; + + @Bean + public MinioClient getMinioClient() { + try { + minioClient = MinioClient.builder() + .endpoint(url) + .credentials(accessKey, secretKey) + .build(); + // 如果没有,创建默认桶 + boolean isExist = checkBucketExist(bucketName); + if (!isExist) { + boolean isTrue = createBucket(bucketName); + if (isTrue) { + log.info("默认桶创建成功"); + } else { + log.error("默认桶创建失败"); + throw new RuntimeException("默认桶创建失败"); + } + } + } catch (Exception e) { + log.error("初始化minioClient失败", e); + } + return minioClient; + } + + /** + * 创建桶 + * @param bucketName 桶名 + * @return 是否创建成功 + */ + public Boolean createBucket(String bucketName) { + if (!StringUtils.hasLength(bucketName)) { + log.error("桶名不能为空"); + return false; + } + try { + boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); + if (!isExist) { + minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + log.info("桶创建成功"); + return true; + } else { + log.info("桶已存在"); + return false; + } + } catch (Exception e) { + log.error("创建bucket失败", e); + return false; + } + } + + /** + * 检测桶是否存在 + * @param bucketName 桶名 + * @return 是否存在 + */ + public Boolean checkBucketExist(String bucketName) { + if (!StringUtils.hasLength(bucketName)) { + log.error("桶名不能为空"); + return false; + } + + try { + return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); + } catch (Exception e) { + log.error("检测bucket失败", e); + return false; + } + } + + /** + * 检测是否存在某个文件 + * @param bucketName 桶名 + * @param path 文件路径 + * @return 是否存在 + */ + public Boolean checkFileExist(String bucketName, String path) { + if (!StringUtils.hasLength(bucketName) || !StringUtils.hasLength(path)) { + log.error("桶名和文件路径不能为空"); + return false; + } + + try { + return (checkBucketExist(bucketName) && + minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(path).build()) != null); + } catch (Exception e) { + return false; + } + } + + /** + * 删除文件 + * @param bucketName 桶名 + * @param path 文件路径 + * @param isDeep 是否深度删除 + * @return 是否删除成功 + */ + public Boolean deleteFile(String bucketName, String path, Boolean isDeep) { + if (!StringUtils.hasLength(bucketName) || !StringUtils.hasLength(path)) { + log.error("桶名和文件路径不能为空"); + return false; + } + + try { + ListObjectsArgs args = ListObjectsArgs.builder().bucket(bucketName).prefix(path).recursive(isDeep).build(); + Iterable> listObjects = minioClient.listObjects(args); + listObjects.forEach(objectResult -> { + try { + Item item = objectResult.get(); + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(item.objectName()).build()); + } catch (Exception e) { + log.info("删除文件夹中的文件异常", e); + throw new RuntimeException("删除文件夹中的文件异常"); + } + }); + return true; + } catch (Exception e) { + log.info("删除失败", e); + return false; + } + } + + /** + * 删除文件 + * @param path 文件路径 + * @return 是否删除成功 + */ + public Boolean deleteFile(String path) { + return deleteFile(bucketName, path, true); + } + + /** + * 上传文件 + * @param bucketName 桶名 + * @param file 文件 + * @param path 路径 + * @return 是否上传成功 + */ + public Boolean uploadFile(String bucketName, MultipartFile file, String path) { + if (!StringUtils.hasLength(bucketName) || file == null || !StringUtils.hasLength(path)) { + log.error("桶名、文件和路径不能为空"); + return false; + } + + try { + // 检查是否有同名文件 + if (checkFileExist(bucketName, path)) { + log.error("已存在同名文件"); + return false; + } + // 资源的媒体类型 + String contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;//默认未知二进制流 + InputStream inputStream = file.getInputStream(); + // 将文件上传到MinIO服务器 + minioClient.putObject( + PutObjectArgs.builder() + .bucket(bucketName) + .object(path) + .stream(inputStream, file.getSize(), -1) + .contentType(contentType) + .build() + ); + inputStream.close(); + return true; + } catch (Exception e) { + log.error("上传文件失败", e); + return false; + } + } + + /** + * 上传文件 + * @param file 文件 + * @param path 路径 + * @return 是否上传成功 + */ + public Boolean uploadFile(MultipartFile file, String path) { + return uploadFile(bucketName, file, path); + } + + /** + * 上传文件 + * @param file 文件 + * @return 是否上传成功 + */ + public Boolean uploadFile(MultipartFile file) { + return uploadFile(bucketName, file, file.getOriginalFilename()); + } + + /** + * 查看桶内目录树 + * @param bucketName 桶名 + * @return 目录树 + */ + public List fileList(String bucketName) { + if (!StringUtils.hasLength(bucketName)) { + log.error("桶名不能为空"); + return null; + } + + try { + List list = new ArrayList<>(); + Iterable> results = minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).recursive(true).build()); + results.forEach(itemResult -> { + try { + Item item = itemResult.get(); + list.add(item.objectName()); + } catch (Exception e) { + log.error("获取文件列表失败", e); + } + }); + return list; + } catch (Exception e) { + log.error("获取文件列表失败", e); + return null; + } + } + + /** + * 查看桶内目录树 + * @return 目录树 + */ + public List fileList() { + return fileList(bucketName); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6c4ee50..d97f029 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -25,7 +25,7 @@ spring: server: port: 3536 minio: - endpoint: http://1.14.105.160:9000 - bucket: catchtheletters - accessKey: spyn - secretKey: pengjunda1 + url: http://1.14.105.160:9001 + accessKey: lOz0abIfahyfs70aCCX6 + secretKey: ffxkRxt2TLjZcKQqfEAmv5SfcqxvsUnY0bIIitaH + bucket-name: catchtheletters