diff --git a/youlai-common/common-core/src/main/java/com/youlai/common/util/ImgUtils.java b/youlai-common/common-core/src/main/java/com/youlai/common/util/ImgUtils.java
new file mode 100644
index 000000000..83a27b08d
--- /dev/null
+++ b/youlai-common/common-core/src/main/java/com/youlai/common/util/ImgUtils.java
@@ -0,0 +1,54 @@
+package com.youlai.common.util;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.StrUtil;
+
+/**
+ * 文件工具类
+ *
+ * @author
+ * @date 2022/7/17
+ */
+public class ImgUtils {
+
+ private static final String[] imgSuffixArr = {"bmp", "dib", "gif", "jfif", "jpe", "jpeg", "jpg", "png", "tif", "tiff", "ico"};
+
+ /**
+ * 是否图片判断
+ *
+ * @param fileName
+ * @return
+ */
+ public static boolean isImg(String fileName) {
+ if (StrUtil.isBlank(fileName)) {
+ return false;
+ }
+
+ String fileSuffix = FileUtil.getSuffix(fileName);
+
+ for (String imgSuffix : imgSuffixArr) {
+ if (fileSuffix.equals(imgSuffix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * 根据图片大小获取压缩比
+ *
+ * @param size 图片大小(单位:Bytes)
+ * @return 压缩比例
+ */
+ public static float getCompressQuality(long size) {
+ if (size <= 0.1 * 1024 * 1024) {
+ return 0.5f;
+ } else if (size > 0.1 * 1024 * 1024 && size <= 1 * 1024 * 1024) {
+ return 0.3f;
+ } else {
+ // 大于1M
+ return 0.1f;
+ }
+ }
+}
diff --git a/youlai-common/common-file/pom.xml b/youlai-common/common-file/pom.xml
index a8ce82efb..5d86fd5f7 100644
--- a/youlai-common/common-file/pom.xml
+++ b/youlai-common/common-file/pom.xml
@@ -28,5 +28,11 @@
io.minio
minio
+
+
+
+ net.coobird
+ thumbnailator
+
\ No newline at end of file
diff --git a/youlai-common/common-file/src/main/java/com/youlai/common/file/controller/FileController.java b/youlai-common/common-file/src/main/java/com/youlai/common/file/controller/FileController.java
index a8234dfee..832611387 100644
--- a/youlai-common/common-file/src/main/java/com/youlai/common/file/controller/FileController.java
+++ b/youlai-common/common-file/src/main/java/com/youlai/common/file/controller/FileController.java
@@ -15,7 +15,6 @@ import org.springframework.web.multipart.MultipartFile;
@RequestMapping("/api/v1/files")
@RequiredArgsConstructor
public class FileController {
-
private final MinioService minioService;
@PostMapping
@@ -23,7 +22,7 @@ public class FileController {
@SneakyThrows
public Result uploadFile(
@ApiParam("文件") @RequestParam(value = "file") MultipartFile file,
- @ApiParam("存储桶名称(非必须,微服务有单独默认存储桶)") @RequestParam(value = "bucketName", required = false) String bucketName
+ @ApiParam("存储桶名称(没值默认存储桶)") @RequestParam(value = "bucketName", required = false) String bucketName
) {
String path = minioService.putObject(file, bucketName);
return Result.success(path);
diff --git a/youlai-common/common-file/src/main/java/com/youlai/common/file/service/MinioService.java b/youlai-common/common-file/src/main/java/com/youlai/common/file/service/MinioService.java
index 5ee0e65ef..874468365 100644
--- a/youlai-common/common-file/src/main/java/com/youlai/common/file/service/MinioService.java
+++ b/youlai-common/common-file/src/main/java/com/youlai/common/file/service/MinioService.java
@@ -1,19 +1,26 @@
package com.youlai.common.file.service;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
+import com.youlai.common.util.ImgUtils;
import io.minio.*;
import io.minio.http.Method;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
+import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
-import java.io.InputStream;
+import java.io.*;
+import java.time.LocalDateTime;
@Component
@@ -51,6 +58,11 @@ public class MinioService implements InitializingBean {
@Setter
private String defaultBucket;
+
+ @Value("${minio.img_compression_enabled:false}")
+ private boolean imgCompressionEnabled;
+
+
private MinioClient minioClient;
@Override
@@ -61,9 +73,7 @@ public class MinioService implements InitializingBean {
Assert.notBlank(secretKey, "MinIO secretKey不能为空");
this.minioClient = MinioClient.builder()
//.endpoint(endpoint, 443, true)
- .endpoint(endpoint)
- .credentials(accessKey, secretKey)
- .build();
+ .endpoint(endpoint).credentials(accessKey, secretKey).build();
}
/**
@@ -73,19 +83,15 @@ public class MinioService implements InitializingBean {
*/
@SneakyThrows
public void createBucketIfAbsent(String bucketName) {
- BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
- .bucket(bucketName)
- .build();
+ BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
if (!minioClient.bucketExists(bucketExistsArgs)) {
- MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
- .bucket(bucketName)
- .build();
+ MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(bucketName).build();
minioClient.makeBucket(makeBucketArgs);
// 设置存储桶访问权限为PUBLIC, 如果不配置,则新建的存储桶默认是PRIVATE,则存储桶文件会拒绝访问 Access Denied
- SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder()
- .bucket(bucketName)
+ SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs
+ .builder().bucket(bucketName)
.config(publicBucketPolicy(bucketName).toString())
.build();
minioClient.setBucketPolicy(setBucketPolicyArgs);
@@ -108,7 +114,7 @@ public class MinioService implements InitializingBean {
*
* @param file MultipartFile文件对象
* @param bucketName 存储桶名称
- * @return
+ * @return 上传文件路径
*/
@SneakyThrows
public String putObject(MultipartFile file, String bucketName) {
@@ -116,43 +122,61 @@ public class MinioService implements InitializingBean {
if (StrUtil.isBlank(bucketName)) {
bucketName = defaultBucket;
}
-
+ // 判断存储桶是否存在
createBucketIfAbsent(bucketName);
- String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
- String fileName = IdUtil.simpleUUID() + "." + suffix;
+ // 获取文件后缀
+ String suffix = FileUtil.getSuffix(file.getOriginalFilename());
+ // 文件名
+ String uuid = IdUtil.simpleUUID();
+ String fileName = DateUtil.format(LocalDateTime.now(), "yyyy/MM/dd") + "/" + uuid + "." + suffix;
- InputStream inputStream = file.getInputStream();
+ InputStream inputStream;
+ // 是否开启压缩
+ if (ImgUtils.isImg(fileName) && imgCompressionEnabled) {
+ long fileSize = file.getSize();
+ log.info("图片({})压缩前大小:{}KB", uuid, fileSize / 1024);
+ float compressQuality = ImgUtils.getCompressQuality(fileSize);
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(Convert.toInt(fileSize));
+ Thumbnails.of(file.getInputStream())
+ .scale(1f) // 图片大小比例
+ .outputQuality(compressQuality) // 图片质量压缩比
+ .toOutputStream(outputStream);
+ inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+ log.info("图片({})压缩后大小:{}KB", uuid, inputStream.available() / 1024);
+ } else {
+ inputStream = file.getInputStream();
+ }
+
+ // 上传参数构建
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.contentType(file.getContentType())
.stream(inputStream, inputStream.available(), -1)
.build();
-
+ // 上传
minioClient.putObject(putObjectArgs);
String fileUrl;
if (StrUtil.isBlank(customDomain)) { // 没有自定义文件路径域名
GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder()
- .bucket(bucketName)
- .object(fileName)
+ .bucket(bucketName).object(fileName)
.method(Method.GET)
.build();
fileUrl = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs);
fileUrl = fileUrl.substring(0, fileUrl.indexOf("?"));
- } else { // 自定义文件路径域名,Nginx配置方向代理转发MinIO
- fileUrl = customDomain +'/'+ bucketName + "/" + fileName;
+ } else {
+ // 自定义文件路径域名,Nginx配置代理转发
+ fileUrl = customDomain + '/' + bucketName + "/" + fileName;
}
return fileUrl;
}
public void removeObject(String bucket, String fileName) throws Exception {
- RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
- .bucket(bucket)
- .object(fileName)
- .build();
+ RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(fileName).build();
minioClient.removeObject(removeObjectArgs);
}
@@ -172,16 +196,17 @@ public class MinioService implements InitializingBean {
* Action: 操作行为
*/
StringBuilder builder = new StringBuilder();
- builder.append("{\"Version\":\"2012-10-17\"," +
- "\"Statement\":[{\"Effect\":\"Allow\"," +
- "\"Principal\":{\"AWS\":[\"*\"]}," +
- "\"Action\":[\"s3:ListBucketMultipartUploads\",\"s3:GetBucketLocation\",\"s3:ListBucket\"]," +
- "\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"]}," +
- "{\"Effect\":\"Allow\"," +
- "\"Principal\":{\"AWS\":[\"*\"]}," +
- "\"Action\":[\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\"]," +
- "\"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]}]}");
+ builder.append("{\"Version\":\"2012-10-17\","
+ + "\"Statement\":[{\"Effect\":\"Allow\","
+ + "\"Principal\":{\"AWS\":[\"*\"]},"
+ + "\"Action\":[\"s3:ListBucketMultipartUploads\",\"s3:GetBucketLocation\",\"s3:ListBucket\"],"
+ + "\"Resource\":[\"arn:aws:s3:::" + bucketName + "\"]},"
+ + "{\"Effect\":\"Allow\"," + "\"Principal\":{\"AWS\":[\"*\"]},"
+ + "\"Action\":[\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\"],"
+ + "\"Resource\":[\"arn:aws:s3:::" + bucketName + "/*\"]}]}");
return builder;
}
+
+
}