20 changed files with 507 additions and 29 deletions
@ -0,0 +1,39 @@ |
|||||
|
package com.lx.common.enums; |
||||
|
|
||||
|
public enum FileTypeEnum { |
||||
|
|
||||
|
FILE(0,"文件"), |
||||
|
IMAGE(1,"图片"), |
||||
|
VIDEO(2,"视频"); |
||||
|
|
||||
|
|
||||
|
private Integer code; |
||||
|
|
||||
|
private String desc; |
||||
|
|
||||
|
FileTypeEnum(Integer index, String desc) { |
||||
|
this.code =index; |
||||
|
this.desc=desc; |
||||
|
} |
||||
|
|
||||
|
public static FileTypeEnum fromCode(Integer code){ |
||||
|
for (FileTypeEnum typeEnum:values()) { |
||||
|
if (typeEnum.code.equals(code)) { |
||||
|
return typeEnum; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public String getDesc() { |
||||
|
return desc; |
||||
|
} |
||||
|
|
||||
|
public Integer getCode(){ |
||||
|
return this.code; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
@ -0,0 +1,31 @@ |
|||||
|
package com.lx.implatform.config; |
||||
|
|
||||
|
import io.minio.MinioClient; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
|
||||
|
|
||||
|
@Configuration |
||||
|
public class MinIoClientConfig { |
||||
|
@Value("${minio.endpoint}") |
||||
|
private String endpoint; |
||||
|
@Value("${minio.accessKey}") |
||||
|
private String accessKey; |
||||
|
@Value("${minio.secretKey}") |
||||
|
private String secretKey; |
||||
|
|
||||
|
/** |
||||
|
* 注入minio 客户端 |
||||
|
* @return |
||||
|
*/ |
||||
|
@Bean |
||||
|
public MinioClient minioClient(){ |
||||
|
|
||||
|
MinioClient client = MinioClient.builder() |
||||
|
.endpoint(endpoint) |
||||
|
.credentials(accessKey, secretKey) |
||||
|
.build(); |
||||
|
return client; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
package com.lx.implatform.controller; |
||||
|
|
||||
|
import com.lx.common.result.Result; |
||||
|
import com.lx.common.result.ResultUtils; |
||||
|
import com.lx.implatform.service.thirdparty.FileService; |
||||
|
import io.swagger.annotations.Api; |
||||
|
import io.swagger.annotations.ApiOperation; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
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.RestController; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
/* |
||||
|
* 文件上传 |
||||
|
* @Author Blue |
||||
|
* @Date 2022/10/28 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@RestController |
||||
|
@Api(tags = "文件上传") |
||||
|
public class FileController { |
||||
|
|
||||
|
|
||||
|
@Autowired |
||||
|
private FileService fileService; |
||||
|
|
||||
|
@ApiOperation(value = "上传图片",notes="上传图片") |
||||
|
@PostMapping("/image/upload") |
||||
|
public Result upload(MultipartFile file) { |
||||
|
return ResultUtils.success(fileService.uploadImage(file)); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@GetMapping("/online") |
||||
|
@ApiOperation(value = "查找用户",notes="根据昵称查找用户") |
||||
|
public Result checkOnline(){ |
||||
|
|
||||
|
return ResultUtils.success(""); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,83 @@ |
|||||
|
package com.lx.implatform.service.thirdparty; |
||||
|
|
||||
|
import com.lx.common.enums.FileTypeEnum; |
||||
|
import com.lx.common.enums.ResultCode; |
||||
|
import com.lx.implatform.exception.GlobalException; |
||||
|
import com.lx.implatform.util.ImageUtil; |
||||
|
import com.lx.implatform.util.MinioUtil; |
||||
|
import com.lx.implatform.vo.UploadImageVO; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import javax.annotation.PostConstruct; |
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/* |
||||
|
* 文件上传服务 |
||||
|
* @Author Blue |
||||
|
* @Date 2022/10/28 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class FileService { |
||||
|
|
||||
|
@Autowired |
||||
|
private MinioUtil minioUtil; |
||||
|
|
||||
|
@Value("${minio.public}") |
||||
|
private String minIOServer; |
||||
|
@Value("${minio.bucketName}") |
||||
|
private String bucketName; |
||||
|
|
||||
|
@Value("${minio.imagePath}") |
||||
|
private String imagePath; |
||||
|
|
||||
|
@Value("${minio.filePath}") |
||||
|
private String filePath; |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init(){ |
||||
|
if(!minioUtil.bucketExists(bucketName)){ |
||||
|
minioUtil.makeBucket(bucketName); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public UploadImageVO uploadImage(MultipartFile file){ |
||||
|
try { |
||||
|
UploadImageVO vo = new UploadImageVO(); |
||||
|
|
||||
|
String fileName = minioUtil.upload(bucketName,imagePath,file); |
||||
|
vo.setOriginUrl(generUrl(FileTypeEnum.IMAGE,fileName)); |
||||
|
// 上传缩略图
|
||||
|
byte[] imageByte = ImageUtil.compressForScale(file.getBytes(),100); |
||||
|
fileName = minioUtil.upload(bucketName,imagePath,file.getOriginalFilename(),imageByte,file.getContentType()); |
||||
|
vo.setCompressUrl(generUrl(FileTypeEnum.IMAGE,fileName)); |
||||
|
return vo; |
||||
|
} catch (IOException e) { |
||||
|
log.error("上传图片失败,{}",e.getMessage(),e); |
||||
|
throw new GlobalException(ResultCode.PROGRAM_ERROR,"图片上传失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public String generUrl(FileTypeEnum fileTypeEnum, String fileName){ |
||||
|
String url = minIOServer+"/"+bucketName; |
||||
|
switch (fileTypeEnum){ |
||||
|
case FILE: |
||||
|
url += "/file/"; |
||||
|
break; |
||||
|
case IMAGE: |
||||
|
url += "/image/"; |
||||
|
break; |
||||
|
case VIDEO: |
||||
|
url += "/video/"; |
||||
|
break; |
||||
|
} |
||||
|
url += fileName; |
||||
|
return url; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
package com.lx.implatform.util; |
||||
|
|
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import net.coobird.thumbnailator.Thumbnails; |
||||
|
|
||||
|
import java.io.ByteArrayInputStream; |
||||
|
import java.io.ByteArrayOutputStream; |
||||
|
|
||||
|
@Slf4j |
||||
|
public class ImageUtil { |
||||
|
|
||||
|
//以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
|
||||
|
private static final Integer ZERO = 0; |
||||
|
private static final Integer ONE_ZERO_TWO_FOUR = 1024; |
||||
|
private static final Integer NINE_ZERO_ZERO = 900; |
||||
|
private static final Integer THREE_TWO_SEVEN_FIVE = 3275; |
||||
|
private static final Integer TWO_ZERO_FOUR_SEVEN = 2047; |
||||
|
private static final Double ZERO_EIGHT_FIVE = 0.85; |
||||
|
private static final Double ZERO_SIX = 0.6; |
||||
|
private static final Double ZERO_FOUR_FOUR = 0.44; |
||||
|
private static final Double ZERO_FOUR = 0.4; |
||||
|
|
||||
|
/** |
||||
|
* 根据指定大小压缩图片 |
||||
|
* |
||||
|
* @param imageBytes 源图片字节数组 |
||||
|
* @param desFileSize 指定图片大小,单位kb |
||||
|
* @return 压缩质量后的图片字节数组 |
||||
|
*/ |
||||
|
public static byte[] compressForScale(byte[] imageBytes, long desFileSize) { |
||||
|
if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) { |
||||
|
return imageBytes; |
||||
|
} |
||||
|
long srcSize = imageBytes.length; |
||||
|
double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR); |
||||
|
try { |
||||
|
while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) { |
||||
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes); |
||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length); |
||||
|
Thumbnails.of(inputStream) |
||||
|
.scale(accuracy) |
||||
|
.outputQuality(accuracy) |
||||
|
.toOutputStream(outputStream); |
||||
|
imageBytes = outputStream.toByteArray(); |
||||
|
} |
||||
|
log.info("图片原大小={}kb | 压缩后大小={}kb", |
||||
|
srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR); |
||||
|
} catch (Exception e) { |
||||
|
log.error("【图片压缩】msg=图片压缩失败!", e); |
||||
|
} |
||||
|
return imageBytes; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 自动调节精度(经验数值) |
||||
|
* |
||||
|
* @param size 源图片大小 |
||||
|
* @return 图片压缩质量比 |
||||
|
*/ |
||||
|
private static double getAccuracy(long size) { |
||||
|
double accuracy; |
||||
|
if (size < NINE_ZERO_ZERO) { |
||||
|
accuracy = ZERO_EIGHT_FIVE; |
||||
|
} else if (size < TWO_ZERO_FOUR_SEVEN) { |
||||
|
accuracy = ZERO_SIX; |
||||
|
} else if (size < THREE_TWO_SEVEN_FIVE) { |
||||
|
accuracy = ZERO_FOUR_FOUR; |
||||
|
} else { |
||||
|
accuracy = ZERO_FOUR; |
||||
|
} |
||||
|
return accuracy; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
@ -0,0 +1,139 @@ |
|||||
|
package com.lx.implatform.util; |
||||
|
|
||||
|
|
||||
|
import com.lx.common.util.DateTimeUtils; |
||||
|
import io.minio.*; |
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import java.io.ByteArrayInputStream; |
||||
|
import java.io.InputStream; |
||||
|
import java.util.Date; |
||||
|
|
||||
|
@Component |
||||
|
public class MinioUtil { |
||||
|
|
||||
|
|
||||
|
@Autowired |
||||
|
private MinioClient minioClient; |
||||
|
|
||||
|
/** |
||||
|
* 查看存储bucket是否存在 |
||||
|
* @return boolean |
||||
|
*/ |
||||
|
public Boolean bucketExists(String bucketName) { |
||||
|
Boolean found; |
||||
|
try { |
||||
|
found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return false; |
||||
|
} |
||||
|
return found; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建存储bucket |
||||
|
* @return Boolean |
||||
|
*/ |
||||
|
public Boolean makeBucket(String bucketName) { |
||||
|
try { |
||||
|
minioClient.makeBucket(MakeBucketArgs.builder() |
||||
|
.bucket(bucketName) |
||||
|
.build()); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 删除存储bucket |
||||
|
* @return Boolean |
||||
|
*/ |
||||
|
public Boolean removeBucket(String bucketName) { |
||||
|
try { |
||||
|
minioClient.removeBucket(RemoveBucketArgs.builder() |
||||
|
.bucket(bucketName) |
||||
|
.build()); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 文件上传 |
||||
|
* @bucketName bucket名称 |
||||
|
* @path 路径 |
||||
|
* @param file 文件 |
||||
|
* @return Boolean |
||||
|
*/ |
||||
|
public String upload(String bucketName,String path,MultipartFile file) { |
||||
|
String originalFilename = file.getOriginalFilename(); |
||||
|
if (StringUtils.isBlank(originalFilename)){ |
||||
|
throw new RuntimeException(); |
||||
|
} |
||||
|
String fileName = System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf(".")); |
||||
|
String objectName = DateTimeUtils.getFormatDate(new Date(),DateTimeUtils.PARTDATEFORMAT)+ "/" + fileName; |
||||
|
try { |
||||
|
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(path+"/" +objectName) |
||||
|
.stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build(); |
||||
|
//文件名称相同会覆盖
|
||||
|
minioClient.putObject(objectArgs); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return null; |
||||
|
} |
||||
|
return objectName; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 文件上传 |
||||
|
* @param bucketName bucket名称 |
||||
|
* @param path 路径 |
||||
|
* @param name 文件名 |
||||
|
* @param fileByte 文件内容 |
||||
|
* @param contentType |
||||
|
* @return Boolean |
||||
|
*/ |
||||
|
public String upload(String bucketName,String path,String name,byte[] fileByte,String contentType) { |
||||
|
|
||||
|
String fileName = System.currentTimeMillis() + name.substring(name.lastIndexOf(".")); |
||||
|
String objectName = DateTimeUtils.getFormatDate(new Date(),DateTimeUtils.PARTDATEFORMAT)+ "/" + fileName; |
||||
|
try { |
||||
|
InputStream stream = new ByteArrayInputStream(fileByte); |
||||
|
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(path+"/" +objectName) |
||||
|
.stream(stream, fileByte.length, -1).contentType(contentType).build(); |
||||
|
//文件名称相同会覆盖
|
||||
|
minioClient.putObject(objectArgs); |
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
return null; |
||||
|
} |
||||
|
return objectName; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 删除 |
||||
|
* @param bucketName bucket名称 |
||||
|
* @path path |
||||
|
* @param fileName |
||||
|
* @return |
||||
|
* @throws Exception |
||||
|
*/ |
||||
|
public boolean remove(String bucketName,String path,String fileName){ |
||||
|
try { |
||||
|
minioClient.removeObject( RemoveObjectArgs.builder().bucket(bucketName).object(path+fileName).build()); |
||||
|
}catch (Exception e){ |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
package com.lx.implatform.vo; |
||||
|
|
||||
|
import io.swagger.annotations.ApiModel; |
||||
|
import io.swagger.annotations.ApiModelProperty; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
@ApiModel("图片上传VO") |
||||
|
public class UploadImageVO { |
||||
|
|
||||
|
@ApiModelProperty(value = "原图") |
||||
|
private String originUrl; |
||||
|
|
||||
|
@ApiModelProperty(value = "缩略图") |
||||
|
private String compressUrl; |
||||
|
} |
||||
@ -0,0 +1,4 @@ |
|||||
|
|
||||
|
set MINIO_ACCESS_KEY=admin |
||||
|
set MINIO_SECRET_KEY=12345678 |
||||
|
.\minio.exe server C:\data\minio --address ":9001" --console-address ":9002" |
||||
Loading…
Reference in new issue