目录
一、docker安装minio
1.1拉取镜像
docker pull minio/minio
1.2创建挂载目录
mkdir -p /home/minio/config
mkdir -p /home/minio/data
1.3启动容器
docker run -p 9000:9000 -p 9090:9090 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=minioadmin" -e "MINIO_SECRET_KEY=minioadmin" -v /home/minio/data:/data -v /home/minio/config:/root/.minio minio/minio server /data --console-address ":9090" -address ":9000"
命令 | 描述 |
-d --restart=always | 这是运行容器的其他选项,-d使容器在后台运行,–restart=always表示容器总是会在退出后自动重启 |
-e “MINIO_ACCESS_KEY=minioadmin” | 用户名 |
-e “MINIO_SECRET_KEY=minioadmin” | 密码 |
minio/minio server <br/>/data --console-address ":9090" -address ":9000 | 这是容器内要运行的命令,启动一个名为 “minio” 的服务器,数据存储在 /data 目录下,服务器的控制台地址为 “:9090”,服务地址为 “:9000” |
查看容器
访问操作
http://ip:9090/login 账号:minioadmin 密码:minioadmin
二、springboot整合minio
minio基本概念
- bucket(桶) :类似文件系统的目录(文件夹);
- Object : 类似文件系统的文件;
- Keys :类似文件名;
- MINIO_ACCESS_KEY:访问key,类似账号;
- MINIO_SECRET_KEY:秘钥,类似密码。
2.1minio准备
2.1.1配置 ACCESS KEYS 获取
新建用户
2.1.2新建桶,用来存放文件的位置
2.2 创建minio模块
2.3 引入依赖
pom.xml(minio)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lyj.initMode</groupId>
<artifactId>initMode-function</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>initMode-function-minio</artifactId>
<description>minio功能模块</description>
<dependencies>
<!--文件存储minio-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency>
<dependency>
<groupId>com.lyj.initMode</groupId>
<artifactId>initMode-function-mysql</artifactId>
</dependency>
</dependencies>
</project>
pom.xml(initMode)
<!--minio 文件服务器-->
<minio.version>7.1.0</minio.version>
<dependency>
<groupId>com.lyj.initMode</groupId>
<artifactId>initMode-function-minio</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
pom.xml(function)
<module>minio</module>
2.4配置minio
MinioConfig.java
package com.lyj.function.minio.config;
import com.lyj.common.base.enums.ErrorCodeEnum;
import com.lyj.common.base.util.BizExceptionUtil;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* minio配置类
* @author faminefree
*/
@Slf4j
@Configuration
@EnableConfigurationProperties({com.lyj.function.minio.config.MinioProperties.class})
public class MinioConfig {
@Bean
public MinioClient minioClient(MinioProperties properties) {
// 创建一个Minio的客户端对象
MinioClient client = MinioClient.builder()
.endpoint(properties.getEndpoint())
.credentials(properties.getAccessKey(), properties.getSecretKey())
.build();
//创建一个Minio的存储桶
BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder()
.bucket(properties.getBucketName())
.build();
//判断桶是否存在
try {
if (!client.bucketExists(bucketExistsArgs)) {
// 如果不存在,那么此时就创建一个新的桶
MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder()
.bucket(properties.getBucketName()).build();
client.makeBucket(makeBucketArgs);
}
} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidBucketNameException
| InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException
| ServerException | XmlParserException | RegionConflictException e) {
log.error(ErrorCodeEnum.MINIO_CONNECT_ERROR.getMessage(),e);
BizExceptionUtil.bizException(ErrorCodeEnum.MINIO_CONNECT_ERROR);
}
return client;
}
}
MinioProperties.java
package com.lyj.function.minio.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* minio配置属性类
*/
@Data
@ConfigurationProperties(prefix = "minio")
public class MinioProperties {
/**
* 对象存储服务的URL
* <pre>
* Examples:
* * https://s3.amazonaws.com
* * https://s3.amazonaws.com/
* * https://play.min.io
* * http://play.min.io:9010/
* * localhost
* * localhost.localdomain
* * play.min.io
* * 127.0.0.1
* * 192.168.1.60
* * ::1
* </pre>
*/
private String endpoint;
/**
* Access key 账户ID
*/
private String accessKey;
/**
* Secret key 密码
*/
private String secretKey;
/**
* 默认的存储桶名称
*/
private String bucketName;
/**
* 允许的扩展名文件名,用逗号分隔,如果为空则没有限制
* allowed extension filename,separate by comma,no limits if blank
* <pre>
* Examples:
* txt,doc,docx
* </pre>
*/
private String extension;
/**
* 图片扩展
* jpg,jpeg,png,bmp,gif
*/
private String pictureExtension;
/**
* 图片限制文件大小
* picture limit file size
*/
private Integer pictureVerifySize;
}
创建文件记录表(sys_file)
-- init.sys_file definition
CREATE TABLE `sys_file` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`attachment_suffix` varchar(20) NOT NULL COMMENT '附件后缀:docx/rar/zip/jpg/pdf等',
`attachment_size` bigint NOT NULL COMMENT '文件大小 KB',
`original_name` varchar(1024) NOT NULL COMMENT '原始文件名称',
`file_no` varchar(128) DEFAULT NULL COMMENT '文件编号 每个文件都唯一,对外下载使用',
`file_path` varchar(1024) DEFAULT NULL COMMENT 'minio完整路径',
`create_by` bigint DEFAULT NULL COMMENT '创建人',
`update_by` bigint DEFAULT NULL COMMENT '更新人',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_flag` tinyint DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=97920 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='文件minio';
使用EasyCode生成代码
BeanUtil.java(base)
package com.lyj.common.base.util;
import com.lyj.common.base.enums.ErrorCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
/**
* bean工具类
*/
@Slf4j
public class BeanUtil {
private BeanUtil() {
super();
}
/**
* 按照目标类型创建一个实例并复制相关属性
*
* @param sourceBean 源bean
* @param targetBeanType 目标bean类型
* @param <T> 目标bean类型
* @return 目标bean实例
*/
public static <T> T clone(Object sourceBean, Class<T> targetBeanType) {
try {
T targetBean = targetBeanType.newInstance();
BeanUtils.copyProperties(sourceBean, targetBean);
return targetBean;
} catch (InstantiationException | IllegalAccessException e) {
log.error("BeanUtil|clone|error|sourceBean={},targetBeanType={}", sourceBean, targetBeanType, e);
BizExceptionUtil.bizException(ErrorCodeEnum.BEAN_CLONE_ERROR);
}
return null;
}
/**
* 复制属性
*
* @param source 源bean
* @param target 目标bean
*/
public static void copy(Object source, Object target) {
BeanUtils.copyProperties(source, target);
}
/**
* 将page对象转换为目标对象
*
* @param page page数据
* @param targetBeanType 目标对象类型
* @param <T> 目标对象类型
* @return 目标对象page数据
*/
public static <T> Page<T> convertPage(Page<?> page, Class<T> targetBeanType) {
List<T> content = convertList(page.getContent(), targetBeanType);
if (content == null) {
content = new ArrayList<>();
}
return new PageImpl<>(content, page.getPageable(), page.getTotalElements());
}
/**
* 将list对象转换为目标对象
*
* @param list list数据
* @param targetBeanType 目标对象类型
* @param <T> 目标对象类型
* @return 目标对象list数据
*/
public static <T> List<T> convertList(List<?> list, Class<T> targetBeanType) {
return list.stream().map(t -> BeanUtil.clone(t, targetBeanType)).collect(Collectors.toList());
}
public static void copyPropertiesIgnoreNull(Object source, Object target) throws BeansException {
copyPropertiesIgnoreNull(source, target, null, (String[])null);
}
public static void copyPropertiesIgnoreNull(Object source, Object target, String... ignoreProperties) throws BeansException {
copyPropertiesIgnoreNull(source, target, null, ignoreProperties);
}
private static void copyPropertiesIgnoreNull(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
PropertyDescriptor[] var7 = targetPds;
int var8 = targetPds.length;
for(int var9 = 0; var9 < var8; ++var9) {
PropertyDescriptor targetPd = var7[var9];
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (value != null) {
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
}
} catch (Throwable var15) {
throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);
}
}
}
}
}
}
public static String[] getNullPropertyNames (Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<String>();
for(PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
}
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
}
DeleteFlagEnum.java(base)
package com.lyj.common.base.enums;
import lombok.Getter;
/**
* 删除标记
*/
@Getter
public enum DeleteFlagEnum {
/**
* 删除标记
*/
NO(0, "未删除"),
YES(1, "已删除");
private final Integer code;
private final String message;
DeleteFlagEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
minio服务service
MinioFileService.java
package com.lyj.function.minio.service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.InputStream;
/**
* @author lxr
* @Description minio操作
* @date Created in 2022/3/17
*/
public interface MinioFileService {
/**
* 下载
*/
InputStream download(String filePath);
/**
* 上传
*
* @return 文件id
*/
Boolean upload(MultipartFile file, String filePath);
/**
* 上传
*
* @return 文件id
*/
Boolean upload(File file, String filePath);
/**
* 删除
*
* @return
*/
Boolean delete(String filePath);
String picturePreview(String filePath);
}
MinioServiceImpl.java
package com.lyj.function.minio.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.lyj.common.base.constant.CommonConstant;
import com.lyj.common.base.enums.ErrorCodeEnum;
import com.lyj.common.base.exceptions.BusinessException;
import com.lyj.common.base.util.BizExceptionUtil;
import com.lyj.function.minio.service.MinioFileService;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.lyj.function.minio.config.MinioProperties;
/**
* <p>
* 文件minio 服务实现类
* </p>
*
* @author lxr
* @since 2022-03-16
*/
@Slf4j
@Service
@AllArgsConstructor
public class MinioServiceImpl implements MinioFileService {
private final MinioClient minioClient;
private final MinioProperties properties;
@Override
public InputStream download(String filePath) {
try {
return minioClient.getObject(GetObjectArgs.builder()
.bucket(properties.getBucketName())
.object(filePath)
.build());
} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidBucketNameException
| InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException
| ServerException | XmlParserException e) {
log.error(ErrorCodeEnum.MINIO_READ_ERROR.getMessage() + ":{}", filePath, e);
BizExceptionUtil.bizException(ErrorCodeEnum.MINIO_READ_ERROR);
return null;
}
}
@Override
public Boolean upload(MultipartFile file, String filePath) {
try {
return this.store(file.getOriginalFilename(), file.getSize(), filePath, file.getContentType(), file.getInputStream());
} catch (IOException e) {
log.error("minio upload error:{}", e.getMessage());
return Boolean.FALSE;
}
}
@Override
public Boolean upload(File file, String filePath) {
try {
// return this.store(file.getName(), file.length(), filePath, Files.probeContentType(file.toPath()), new FileInputStream(file));
return this.store(file.getName(), file.length(), filePath,new MimetypesFileTypeMap().getContentType(file), new FileInputStream(file));
} catch (IOException e) {
log.error("minio upload error:{}", e.getMessage());
return Boolean.FALSE;
}
}
@Override
public Boolean delete(String filePath) {
try {
RemoveObjectArgs removeObjectArgs =
RemoveObjectArgs.builder()
.bucket(properties.getBucketName())
.object(filePath)
.build();
minioClient.removeObject(removeObjectArgs);
} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidBucketNameException
| InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException
| ServerException | XmlParserException e) {
log.error(ErrorCodeEnum.MINIO_WRITE_ERROR.getMessage() + ":{}", filePath, e);
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public String picturePreview(String filePath){
try {
minioClient.statObject(StatObjectArgs.builder().bucket(properties.getBucketName()).object(filePath).build());
} catch (Exception e) {
//找不到文件则抛异常
log.error(ErrorCodeEnum.MINIO_READ_ERROR.getMessage() + ":{}", filePath);
return null;
}
GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs.builder()
.bucket(properties.getBucketName())
.object(filePath)
.method(Method.GET)
.build();
String url = null;
try {
url = minioClient.getPresignedObjectUrl(build);
} catch (Exception e) {
log.error("MinioServiceImpl|picturePreview|error, get url error, filePath:{}", filePath);
return null;
}
log.info("MinioServiceImpl|picturePreview|info, filePath:{},url:{}", filePath,url);
return url;
}
private Boolean store(String fileName, Long fileSize, String filePath, String contentType, InputStream input) {
if ((fileName.length() * 2) > 255) {
log.error(ErrorCodeEnum.MINIO_FILE_NAME_TOO_LONG.getMessage());
throw new BusinessException(ErrorCodeEnum.MINIO_FILE_NAME_TOO_LONG.getMessage());
}
if (StringUtils.isNotBlank(properties.getExtension())) {
// 不空时才进行格式校验
List<String> leagueExtension = Arrays.stream(properties.getExtension().split(CommonConstant.COMMA))
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
if (!leagueExtension.isEmpty()) {
// 不空时才进行格式校验
String suffix = fileName.substring(Math.max(fileName.lastIndexOf(CommonConstant.DOT) + 1, 0));
boolean match = false;
for (String s : leagueExtension) {
if (StringUtils.isNotBlank(suffix) && suffix.equalsIgnoreCase(s)) {
match = true;
}
}
//校验图片文件大小
if (StringUtils.isNotBlank(properties.getPictureExtension())) {
List<String> pictureExtension = Arrays.stream(properties.getPictureExtension().split(CommonConstant.COMMA))
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(pictureExtension) && pictureExtension.contains(suffix) && properties.getPictureVerifySize() != null) {
if (BigDecimal.valueOf(fileSize)
.divide(BigDecimal.valueOf(1024 * 1024), 3, RoundingMode.HALF_UP).doubleValue() > properties.getPictureVerifySize()) {
BizExceptionUtil.bizException(ErrorCodeEnum.MINIO_PICTURE_FILE_SIZE_ERROR.getCode(), String.format(ErrorCodeEnum.MINIO_PICTURE_FILE_SIZE_ERROR.getMessage(), properties.getPictureVerifySize()));
}
}
if (!match) {
log.error(ErrorCodeEnum.MINIO_FILE_SUFFIX_ERROR.getMessage());
throw new BusinessException(ErrorCodeEnum.MINIO_FILE_SUFFIX_ERROR.getMessage());
}
}
}
}
PutObjectArgs putObjectArgs;
try {
putObjectArgs = PutObjectArgs.builder()
.bucket(properties.getBucketName())
.object(filePath)
.contentType(contentType)
.stream(input, input.available(), -1)
.build();
minioClient.putObject(putObjectArgs);
} catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidBucketNameException
| InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException
| ServerException | XmlParserException e) {
log.error(ErrorCodeEnum.MINIO_WRITE_ERROR.getMessage() + ":{}", fileName, e);
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}
SysFileService.java
package com.lyj.function.minio.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lyj.common.domain.sysFile.entity.SysFile;
import com.lyj.common.domain.sysFile.vo.SysFileDetailVO;
import com.lyj.common.domain.sysFile.vo.SysFileVO;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
/**
* <p>
* 文件minio 服务类
* </p>
*
* @author lxr
* @since 2022-03-16
*/
public interface SysFileService extends IService<SysFile> {
void downLoad(HttpServletResponse response, Long fileId);
/**
* 带时间戳的下载
* @param response
* @param fileId
*/
void downLoadWithTimestamp(HttpServletResponse response, Long fileId);
byte[] downLoad(Long fileId);
Long upload(MultipartFile file, Long userId);
Long upload(File file, Long userId);
/**
* 文件详情
*
* @param fileIdList
* @return
*/
List<SysFileVO> detail(List<Long> fileIdList);
List<SysFileDetailVO> detailAddUrl(List<Long> fileIdList);
/**
* 图片预览
* @param filePath
* @return url
*/
String picturePreview(String filePath);
}
SysFileServiceImpl.java
package com.lyj.function.minio.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lyj.common.base.enums.DeleteFlagEnum;
import com.lyj.common.base.enums.ErrorCodeEnum;
import com.lyj.common.base.exceptions.BusinessException;
import com.lyj.common.base.util.BeanUtil;
import com.lyj.common.base.util.BizExceptionUtil;
import com.lyj.common.base.util.DateUtil;
import com.lyj.common.domain.sysFile.entity.SysFile;
import com.lyj.common.domain.sysFile.vo.SysFileDetailVO;
import com.lyj.common.domain.sysFile.vo.SysFileVO;
import com.lyj.function.minio.service.MinioFileService;
import com.lyj.function.minio.service.SysFileService;
import com.lyj.function.mysql.dao.sysFile.SysFileMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
/**
* <p>
* 文件minio 服务实现类
* </p>
*
* @author lxr
* @since 2022-03-16
*/
@Slf4j
@Service
@AllArgsConstructor
public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFile> implements SysFileService {
private static final String DOT = ".";
private static final String PATH_SEPARATOR = "/";
private final MinioFileService minioFileService;
@Override
public void downLoad(HttpServletResponse response, Long fileId) {
SysFile byId = getById(fileId);
if (Objects.isNull(byId)) {
BizExceptionUtil.bizException("文件不存在!");
}
String fileName = byId.getOriginalName();
InputStream inputStream = minioFileService.download(byId.getFilePath());
response.setContentType("multipart/form-data");
try {
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20"));
} catch (UnsupportedEncodingException e) {
response.setHeader("Content-Disposition", "attachment;filename="
+ new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
}
try (OutputStream os = response.getOutputStream()) {
IOUtils.copy(inputStream, os);
os.flush();
} catch (IOException e) {
throw new BusinessException(ErrorCodeEnum.DOWNLOAD_ERROR);
}
}
@Override
public void downLoadWithTimestamp(HttpServletResponse response, Long fileId) {
SysFile byId = getById(fileId);
if (Objects.isNull(byId)) {
BizExceptionUtil.bizException("文件不存在!");
return;
}
String fileName = byId.getOriginalName();
if (fileName != null && fileName.contains(".")) {
String[] split = fileName.split("\\.");
fileName = split[0] + DateUtil.getLocalDateTime() + "." + split[1];
}
InputStream inputStream = minioFileService.download(byId.getFilePath());
response.setContentType("multipart/form-data");
try {
response.setHeader("Content-Disposition", "attachment;filename="
+ URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20"));
} catch (UnsupportedEncodingException e) {
response.setHeader("Content-Disposition", "attachment;filename="
+ new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
}
try (OutputStream os = response.getOutputStream()) {
IOUtils.copy(inputStream, os);
os.flush();
} catch (IOException e) {
throw new BusinessException(ErrorCodeEnum.DOWNLOAD_ERROR);
}
}
@Override
public byte[] downLoad(Long fileId) {
SysFile byId = getById(fileId);
InputStream inputStream = minioFileService.download(byId.getFilePath());
try {
return IOUtils.toByteArray(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return new byte[]{};
}
@Override
public Long upload(MultipartFile file, Long userId) {
String originalFilename = file.getOriginalFilename();
String uuid = UUID.randomUUID().toString();
String filePath = uuid + PATH_SEPARATOR + originalFilename;
SysFile sysFile = new SysFile();
sysFile.setAttachmentSuffix(originalFilename.substring(originalFilename.lastIndexOf(DOT)));
sysFile.setAttachmentSize(file.getSize() / 8);
sysFile.setOriginalName(originalFilename);
sysFile.setFileNo(uuid);
sysFile.setFilePath(filePath);
sysFile.setDeleteFlag(DeleteFlagEnum.NO.getCode());
sysFile.setCreateBy(userId);
sysFile.setUpdateBy(userId);
LocalDateTime now = LocalDateTime.now();
sysFile.setCreateTime(now);
sysFile.setUpdateTime(now);
save(sysFile);
minioFileService.upload(file, filePath);
return sysFile.getId();
}
@Override
public Long upload(File file, Long userId) {
String originalFilename = file.getName();
String uuid = UUID.randomUUID().toString();
String filePath = uuid + PATH_SEPARATOR + originalFilename;
SysFile sysFile = new SysFile();
sysFile.setAttachmentSuffix(originalFilename.substring(originalFilename.lastIndexOf(DOT)));
sysFile.setAttachmentSize(file.length() / 8);
sysFile.setOriginalName(originalFilename);
sysFile.setFileNo(uuid);
sysFile.setFilePath(filePath);
sysFile.setDeleteFlag(DeleteFlagEnum.NO.getCode());
sysFile.setCreateBy(userId);
sysFile.setUpdateBy(userId);
LocalDateTime now = LocalDateTime.now();
sysFile.setCreateTime(now);
sysFile.setUpdateTime(now);
save(sysFile);
minioFileService.upload(file, filePath);
return sysFile.getId();
}
@Override
public List<SysFileVO> detail(List<Long> fileIdList) {
List<SysFile> sysFiles = this.list(new LambdaQueryWrapper<SysFile>().in(SysFile::getId, fileIdList));
List<SysFileVO> SysFileVOs = BeanUtil.convertList(sysFiles, SysFileVO.class);
return SysFileVOs;
}
@Override
public List<SysFileDetailVO> detailAddUrl(List<Long> fileIdList) {
List<SysFile> sysFiles = this.list(new LambdaQueryWrapper<SysFile>().in(SysFile::getId, fileIdList));
List<SysFileDetailVO> list = new ArrayList<>();
for (SysFile sysFile : sysFiles) {
SysFileDetailVO SysFileDetailVO = new SysFileDetailVO();
BeanUtil.copy(sysFile,SysFileDetailVO);
SysFileDetailVO.setUrl(picturePreviewBase64(sysFile.getFilePath()));
list.add(SysFileDetailVO);
}
return list;
}
@Override
public String picturePreview(String filePath){
return minioFileService.picturePreview(filePath);
}
public String picturePreviewBase64(String filePath) {
InputStream download = minioFileService.download(filePath);
if (download!=null){
byte[] data = null;
try {
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while ((rc = download.read(buff, 0, 100)) > 0) {
swapStream.write(buff, 0, rc);
}
data = swapStream.toByteArray();
} catch (Exception e) {
log.error("PunchMonthReportQueryServiceImpl|info|error|read picture error e:{}", e);
} finally {
try {
download.close();
} catch (Exception e) {
log.error("PunchMonthReportQueryServiceImpl|info|error|download close error e:{}", e);
}
}
return Base64.getEncoder().encodeToString(data);
}
return null;
}
}
三、管理应用模块(management)集成minio
pom.xml(manegement)
<dependency>
<groupId>com.lyj.initMode</groupId>
<artifactId>initMode-function-minio</artifactId>
</dependency>
application.yml
minio: #minio 参数
accessKey: FjFA028O825BZ47II9fT
secretKey: 5AumALef8wccA1caMamfD3U0DxLAQTK4Z54jQd3y
# 存放文件的桶
bucketName: test
# 访问路径
endpoint: http://192.168.163.158:9000
测试方法
@GetMapping("/uploadFile")
@ApiOperation("测试minio上传")
public R<Long> uploadFile() {
File file = new File("D:下载/7-Zip 64位_23.1.0.0.exe");
return R.ok(sysFileService.upload(file,123L));
}
@GetMapping(value = "/downLoad", produces = "application/octet-stream")
@ApiOperation("测试minio下载")
public void downLoad(HttpServletResponse response, Long fileId) {
sysFileService.downLoad(response, fileId);
}
启动服务测试
四、启动时报错
原因1:
使用的用户权限不足
原因2
minio系统时间与应用服务系统时间相差较大
使用命令同步时间
ntpdate pool.ntp.org