搭建文件服务器 MinIO
1 下载
minio官方文档
我选择的是docker部署
docker pull minio/minio
docker run \
-p 9000:9000 \
-p 9001:9001 \
--name minio1 \
-v ~/minio/data:/data \
-e "MINIO_ROOT_USER=username" \
-e "MINIO_ROOT_PASSWORD=password" \
-d \
quay.io/minio/minio server /data --console-address ":9001"
访问http://101.42.135.107:9001/
进入控制台界面 ( 如果是云服务器记得打开9001端口)
2 上传文件到minio
创建名为hms的桶
然后上传一个图片
设置访问规则:
添加只读属性,前缀为 “*”,这样就可以浏览器访问了
访问:http://服务器ip:9000/桶名/文件名
2 SpringBoot整合
2.1 依赖,主启动
最开始用的8.3.7, 和我的jar包冲突了,又换成8.2.1
io.minio
minio
8.2.1
2.2 配置文件
server:
port: 9201
spring:
application:
name: file
datasource:
username: root
password: 18170021
url: jdbc:mysql://localhost:3306/db_hms_file?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
server-addr: localhost:8848
# 配置文件大小限制
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
minio:
# minio配置是自定义的配置,注意:一定加http://
endpoint: http://localhost:9000
accessKey: root
secretKey: root18170021
bucketName: hms
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.3 Minio客户端配置类
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioClientConfig {
private String endpoint;
private String accessKey;
private String secretKey;
@Bean
public MinioClient minioClient() {
MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
return minioClient;
}
}
2.4 工具类
不要被吓跑哦,我只用到其中的上传下载删除三个方法,不过以后可能会用到就都copy过来了
@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) {
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;
}
/**
* 获取全部bucket
*/
public List getAllBuckets() {
try {
return minioClient.listBuckets();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 文件上传
* @param file 文件
* @return Boolean
*/
public Boolean upload(String bucketName, String fileName, MultipartFile file, InputStream inputStream) {
try {
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(fileName)
.stream(inputStream,file.getSize(),-1).contentType(file.getContentType()).build();
//文件名称相同会覆盖
minioClient.putObject(objectArgs);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 预览图片
* @param fileName
* @return
*/
public String preview(String fileName,String bucketName){
// 查看文件地址
GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs
.builder().bucket(bucketName)
.object(fileName)
.method(Method.GET).build();
try {
String url = minioClient.getPresignedObjectUrl(build);
return url;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 文件下载
* @param fileName 文件名称
* @param res response
* @return Boolean
*/
public void download(String fileName,String bucketName, HttpServletResponse res) {
GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName)
.object(fileName).build();
try (GetObjectResponse response = minioClient.getObject(objectArgs)){
byte[] buf = new byte[1024];
int len;
try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()){
while ((len=response.read(buf))!=-1){
os.write(buf,0,len);
}
os.flush();
byte[] bytes = os.toByteArray();
res.setCharacterEncoding("utf-8");
//设置强制下载不打开
//res.setContentType("application/force-download");
res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
try (ServletOutputStream stream = res.getOutputStream()){
stream.write(bytes);
stream.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查看文件对象
* @return 存储bucket内文件对象信息
*/
public List- listObjects(String bucketName) {
Iterable
> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).build());
List- items = new ArrayList<>();
try {
for (Result
- result : results) {
items.add(result.get());
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return items;
}
/**
* 删除
* @param fileName
* @return
* @throws Exception
*/
public boolean remove(String fileName,String bucketName){
try {
minioClient.removeObject( RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
}catch (Exception e){
return false;
}
return true;
}
/**
* 批量删除文件对象(没测试)
* @param objects 对象名称集合
*/
public Iterable
> removeObjects(List objects, String bucketName) {
List dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
Iterable> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
return results;
}
}
2.5 Controller
@RestController
@RequestMapping("file")
public class FileController {
private static final Logger log = LogManager.getLogger();
@Autowired
private FileItemServiceImpl fileItemService;
@PostMapping("upload")
public Result upload(@Valid @NotNull @RequestParam(value = "file") MultipartFile file, @Valid @NotNull Integer type) {
Result result;
try {
FileItemVO fileItemVO = fileItemService.uploadFile(file, type);
result = Result.success("文件上传成功!", fileItemVO);
} catch (BcException e) {
result = Result.error(e.getCode(), e.getMessage());
log.error(e.getMessage());
}
return result;
}
@GetMapping("download")
public void download(HttpServletResponse response,
@Valid @RequestParam @NotBlank(message = "fileId不能为空") Integer fileId) {
try {
fileItemService.downloadFile(fileId, response);
} catch (BcException e) {
log.error(e.getMessage());
}
}
@GetMapping("delete")
public Result delete(@Valid @RequestParam @NotBlank(message = "fileId不能为空") Long fileId) {
Result result;
try {
fileItemService.deleteFile(fileId);
result = Result.success("删除附件成功!", fileId);
} catch (BcException e) {
result = Result.error(e.getCode(), e.getMessage());
}
return result;
}
}
2.6 Service
service
public interface FileItemService {
/**
* 上传文件到服务器中
* @param file
* @param type
* @return
*/
FileItemVO uploadFile(MultipartFile file, Integer type);
/**
* 下载文件
* @param fileId
* @param response
*/
void downloadFile(Integer fileId, HttpServletResponse response);
/**
* 删除文件
* @param fileId
*/
void deleteFile(Long fileId);
}
serviceImpl
@Service
public class FileItemServiceImpl implements FileItemService {
@Resource
private MinioUtil minioUtil;
@Value("${minio.bucketName}")
private String bucketName;
@Value("${minio.endpoint}")
private String endpoint;
@Autowired
private FileMapper fileMapper;
private String[] fileFolders = new String[]{"doctorPhotos/", "report", "otherImage/"};
@Override
@Transactional(rollbackFor = Exception.class)
public FileItemVO uploadFile(MultipartFile file, Integer type) {
FileItemVO fileItemVO = null;
try {
String fileName = file.getOriginalFilename();
String ext = fileName.substring(fileName.lastIndexOf("."));
String newFileName = fileFolders[type] + UUID.randomUUID().toString().replaceAll("-", "") + ext;
InputStream inputStream = file.getInputStream();
Boolean flag = minioUtil.upload(bucketName, newFileName,file, inputStream);
if(!flag) {
throw new BcException(ErrorCode.file_upload_fail.getCode(), "文件上传失败");
}
String url = getUrl(newFileName);
fileItemVO = FileItemVO.builder()
.newFileName(newFileName)
.fileName(fileName)
.ext(ext)
.url(url)
.build();
FileEntity fileEntity = new FileEntity();
BeanUtils.copyProperties(fileItemVO, fileEntity);
fileEntity.setType(type);
fileMapper.insert(fileEntity);
fileItemVO.setFileId(fileEntity.getId());
} catch (Exception e) {
throw new BcException(ErrorCode.file_upload_fail.getCode(), "文件上传失败");
}
return fileItemVO;
}
@Transactional(readOnly = true)
@Override
public void downloadFile(Integer fileId, HttpServletResponse response) {
FileEntity fileEntity = fileMapper.selectById(fileId);
if(ObjectUtils.isEmpty(fileEntity)) {
throw new BcException(ErrorCode.file_not_exit.getCode(), "文件不存在");
}
try {
minioUtil.download(fileEntity.getNewFileName(), bucketName, response);
} catch (Exception e) {
throw new BcException(ErrorCode.download_id_exception.getCode(), "文件下载失败");
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public void deleteFile(Long fileId) {
FileEntity fileEntity = fileMapper.selectById(fileId);
if(ObjectUtils.isEmpty(fileEntity)) {
throw new BcException(ErrorCode.file_not_exit.getCode(), "文件不存在");
}
try {
minioUtil.remove(fileEntity.getNewFileName(), bucketName);
fileMapper.deleteById(fileId);
} catch (Exception e) {
throw new BcException(ErrorCode.download_id_exception.getCode(), "文件删除失败");
}
}
private String getUrl(String newFileName) {
return endpoint
+ "/"
+ bucketName
+ "/"
+ newFileName;
}
}
2.7 实体和数据库
FileItemVO (上传文件后响应结果)
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class FileItemVO {
/**
* 文件id
*/
private Long fileId;
/**
* 文件可访问URL
*/
private String url;
/**
* 文件的拓展名
*/
private String ext;
/**
* 上传的源文件的文件名,带有拓展
*/
private String fileName;
/**
* 上传后的文件名
*/
private String newFileName;
}
file表
DROP TABLE IF EXISTS `file`;
CREATE TABLE `file` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
`file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户上传文件的原始名称,带有文件拓展',
`ext` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '文件拓展名',
`type` int(0) NOT NULL COMMENT '文件类型:1医生照片 2其他图片 3体检报告',
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'url',
`new_file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'minio里面的文件名',
`created_time` datetime(0) NOT NULL COMMENT '创建时间',
`modified_time` datetime(0) NOT NULL COMMENT '修改时间',
`state` int(0) NOT NULL DEFAULT 0 COMMENT '状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
2.8 参考链接
参考链接: