Commit ad797d81 authored by licancan's avatar licancan

minio测试demo

parents
# springboot-minio
MinIO 是一个基于Apache License v2.0开源协议的对象存储服务。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。 本项目集成Minio的java客户端SDK,对Minio文件服务器进行读写,将操作封装为MinioUtil工具,直接在项目中可以复用。其操作主要包括:
- 上传文件
- 下载文件
- 读取桶列表
- 读取桶中的文件列表
- 删除桶
- 删除文件
\ No newline at end of file
This diff is collapsed.
<?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>
<groupId>com.yifu</groupId>
<artifactId>springboot-minio</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.6.RELEASE</version>
<exclusions><!-- 去掉springboot默认配置 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.6.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
<exclusions><!-- 去掉springboot默认配置 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.3.7</version>
</dependency>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
<version>2.1.6.RELEASE</version>
</dependency>
</dependencies>
<build>
<finalName>springboot-minio</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.6.RELEASE</version>
<configuration>
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- 指定maven编译方式为jdk1.8版本 -->
<profiles>
<profile>
<id>jdk-1.8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
</project>
\ No newline at end of file
package com.yifu.minio;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author licancan
* @description 启动类
* @date 2022-04-07 16:03:05
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package com.yifu.minio;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author licancan
* @description Swagger2配置
* @date 2022-04-07 16:09:02
*/
@Configuration
@EnableSwagger2
public class Swagger2 {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.yifu.minio.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("springboot利用swagger构建api文档")
.description("简单优雅的restful风格")
.termsOfServiceUrl("https://gitee.com/canexplorer")
.version("1.0")
.build();
}
}
package com.yifu.minio.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author licancan
* @description 跨域配置
* @date 2022-04-07 16:05:31
*/
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
//重写父类提供的跨域请求处理的接口
public void addCorsMappings(CorsRegistry registry) {
//添加映射路径
registry.addMapping("/**")
//放行哪些原始域
.allowedOrigins("*")
//是否发送Cookie信息
.allowCredentials(true)
//放行哪些原始域(请求方式)
.allowedMethods("GET", "POST", "PUT", "DELETE")
//放行哪些原始域(头部信息)
.allowedHeaders("*")
//暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
.exposedHeaders("token");
}
};
}
}
package com.yifu.minio.config;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author licancan
* @description minio配置
* @date 2022-04-07 16:06:44
*/
@Configuration
public class MinioConfig {
@Value("${minio.url}")
private String url;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
@Bean
public MinioClient getMinioClient() {
MinioClient minioClient = MinioClient.builder().endpoint(url)
.credentials(accessKey, secretKey).build();
return minioClient;
}
}
package com.yifu.minio.controller;
import com.yifu.minio.domain.AjaxResult;
import com.yifu.minio.util.MinioUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
/**
* @author licancan
* @description TODO
* @date 2022-04-07 16:24:06
*/
@Api(tags = "文件操作接口")
@Controller
public class FileController {
@Resource
private MinioUtil minioUtil;
@ApiOperation("上传一个文件")
@RequestMapping(value = "/uploadfile", method = RequestMethod.POST)
@ResponseBody
public AjaxResult fileupload(@RequestParam MultipartFile uploadfile, @RequestParam String bucket,
@RequestParam(required=false) String objectName) throws Exception {
minioUtil.createBucket(bucket);
if (objectName != null) {
minioUtil.uploadFile(uploadfile.getInputStream(), bucket, objectName+"/"+uploadfile.getOriginalFilename());
} else {
minioUtil.uploadFile(uploadfile.getInputStream(), bucket, uploadfile.getOriginalFilename());
}
return AjaxResult.success();
}
@ApiOperation("列出所有的桶")
@RequestMapping(value = "/listBuckets", method = RequestMethod.GET)
@ResponseBody
public AjaxResult listBuckets() throws Exception {
return AjaxResult.success(minioUtil.listBuckets());
}
@ApiOperation("递归列出一个桶中的所有文件和目录")
@RequestMapping(value = "/listFiles", method = RequestMethod.GET)
@ResponseBody
public AjaxResult listFiles(@RequestParam String bucket) throws Exception {
return AjaxResult.success("200", minioUtil.listFiles(bucket));
}
@ApiOperation("下载一个文件")
@RequestMapping(value = "/downloadFile", method = RequestMethod.GET)
@ResponseBody
public void downloadFile(@RequestParam String bucket, @RequestParam String objectName,
HttpServletResponse response) throws Exception {
InputStream stream = minioUtil.download(bucket, objectName);
ServletOutputStream output = response.getOutputStream();
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName.substring(objectName.lastIndexOf("/") + 1), "UTF-8"));
response.setContentType("application/octet-stream");
response.setCharacterEncoding("UTF-8");
IOUtils.copy(stream, output);
}
@ApiOperation("删除一个文件")
@RequestMapping(value = "/deleteFile", method = RequestMethod.GET)
@ResponseBody
public AjaxResult deleteFile(@RequestParam String bucket, @RequestParam String objectName) throws Exception {
minioUtil.deleteObject(bucket, objectName);
return AjaxResult.success();
}
@ApiOperation("删除一个桶")
@RequestMapping(value = "/deleteBucket", method = RequestMethod.GET)
@ResponseBody
public AjaxResult deleteBucket(@RequestParam String bucket) throws Exception {
minioUtil.deleteBucket(bucket);
return AjaxResult.success();
}
}
package com.yifu.minio.domain;
import java.util.HashMap;
/**
* @author licancan
* @description 响应结果类
* @date 2022-04-07 16:15:35
*/
public class AjaxResult extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
/** 状态码 */
public static final String CODE_TAG = "code";
/** 返回内容 */
public static final String MSG_TAG = "msg";
/** 数据对象 */
public static final String DATA_TAG = "data";
/**
* 状态类型
*/
public enum Type {
/** 成功 */
SUCCESS(0),
/** 警告 */
WARN(301),
/** 错误 */
ERROR(500);
private final int value;
Type(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult() {
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param type 状态类型
* @param msg 返回内容
*/
public AjaxResult(Type type, String msg) {
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param type 状态类型
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(Type type, String msg, Object data) {
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
if (data != null)
{
super.put(DATA_TAG, data);
}
}
/**
* 方便链式调用
*
* @param key 键
* @param value 值
* @return 数据对象
*/
@Override
public AjaxResult put(String key, Object value) {
super.put(key, value);
return this;
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success() {
return AjaxResult.success("操作成功");
}
/**
* 返回成功数据
*
* @return 成功消息
*/
public static AjaxResult success(Object data) {
return AjaxResult.success("操作成功", data);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult success(String msg) {
return AjaxResult.success(msg, null);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data) {
return new AjaxResult(Type.SUCCESS, msg, data);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult warn(String msg) {
return AjaxResult.warn(msg, null);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult warn(String msg, Object data) {
return new AjaxResult(Type.WARN, msg, data);
}
/**
* 返回错误消息
*
* @return
*/
public static AjaxResult error() {
return AjaxResult.error("操作失败");
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult error(String msg) {
return AjaxResult.error(msg, null);
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult error(String msg, Object data) {
return new AjaxResult(Type.ERROR, msg, data);
}
}
package com.yifu.minio.domain;
/**
* @author licancan
* @description 文件类
* @date 2022-04-07 16:13:47
*/
public class FileInfo {
String filename;
Boolean directory;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public Boolean getDirectory() {
return directory;
}
public void setDirectory(Boolean directory) {
this.directory = directory;
}
}
package com.yifu.minio.util;
import com.yifu.minio.domain.FileInfo;
import io.minio.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* @author licancan
* @description minio工具类
* @date 2022-04-07 16:11:11
*/
@Component
public class MinioUtil {
@Resource
private MinioClient minioClient;
/**
* 创建一个桶
*/
public void createBucket(String bucket) throws Exception {
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
if (!found) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
}
}
/**
* 上传一个文件
*/
public void uploadFile(InputStream stream, String bucket, String objectName) throws Exception {
minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName)
.stream(stream, -1, 10485760).build());
}
/**
* 列出所有的桶
*/
public List<String> listBuckets() throws Exception {
List<Bucket> list = minioClient.listBuckets();
List<String> names = new ArrayList<>();
list.forEach(b -> {
names.add(b.name());
});
return names;
}
/**
* 列出一个桶中的所有文件和目录
*/
public List<FileInfo> listFiles(String bucket) throws Exception {
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucket).recursive(true).build());
List<FileInfo> infos = new ArrayList<>();
results.forEach(r->{
FileInfo info = new FileInfo();
try {
Item item = r.get();
info.setFilename(item.objectName());
info.setDirectory(item.isDir());
infos.add(info);
} catch (Exception e) {
e.printStackTrace();
}
});
return infos;
}
/**
* 下载一个文件
*/
public InputStream download(String bucket, String objectName) throws Exception {
InputStream stream = minioClient.getObject(
GetObjectArgs.builder().bucket(bucket).object(objectName).build());
return stream;
}
/**
* 删除一个桶
*/
public void deleteBucket(String bucket) throws Exception {
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucket).build());
}
/**
* 删除一个对象
*/
public void deleteObject(String bucket, String objectName) throws Exception {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build());
}
}
server:
port: 8080
logging:
config: classpath:log4j2.xml
spring:
servlet:
multipart:
max-file-size: 100MB
max-request-size: 1000MB
#minio配置
minio:
url: http://192.168.1.65:16000/ #对象存储服务的URL
accessKey: minio #Access key账户
secretKey: 12345678 #Secret key密码
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="off">
<Properties>
<!-- 日志存储路径 -->
<Property name="baseDir">./logs</Property>
</Properties>
<CustomLevels>
<CustomLevel name="AUDIT" intLevel="50" />
</CustomLevels>
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout charset="UTF-8" pattern="[%-5p] [%d{HH:mm:ss}] %c - %m%n" />
</Console>
<!-- 自定义 -->
<RollingFile name="RollingFileAUDIT"
fileName="${baseDir}/logservice-web/audit-log/audit-log.log" filePattern="${baseDir}/logservice-web/audit-log/audit-log-%i.log">
<ThresholdFilter level="AUDIT" onMatch="ACCEPT" onMismatch="DENY" />
<PatternLayout pattern="[%d{yyyy/MM/dd HH:mm:ssS}][%p][LOGSERVICE][日志系统]%m%n" />
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<!-- 保存最大文件个数 -->
<DefaultRolloverStrategy max="50" />
</RollingFile>
<!--Trace级别日志输出-->
<RollingFile name="system-trace"
fileName="${baseDir}/logservice-web/trace.log" filePattern="${baseDir}/logservice-web/trace-%i.log">
<Filters>
<ThresholdFilter level="debug" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY" />
</Filters>
<PatternLayout charset="UTF-8" pattern="[%d{yyyy/MM/dd HH:mm:ssSSS}][%p][LOGSERVICE][日志系统][%l]%n%m%n" />
<Policies>
<!-- 日志文件大小 -->
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<!-- 保存最大文件个数 -->
<DefaultRolloverStrategy max="50" />
</RollingFile>
<!--Info级别日志输出-->
<RollingFile name="system-info"
fileName="${baseDir}/logservice-web/info.log"
filePattern="${baseDir}/logservice-web/info-%i.log">
<Filters>
<ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
</Filters>
<PatternLayout charset="UTF-8" pattern="[%d{yyyy/MM/dd HH:mm:ssSSS}][%p][LOGSERVICE][日志系统][%l]%n%m%n" />
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="50" />
</RollingFile>
<!--Debug级别日志输出-->
<RollingFile name="system-debug"
fileName="${baseDir}/logservice-web/debug.log" filePattern="${baseDir}/logservice-web/debug-%i.log">
<Filters>
<ThresholdFilter level="info" onMatch="DENY" onMismatch="NEUTRAL"/>
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
</Filters>
<PatternLayout charset="UTF-8" pattern="[%d{yyyy/MM/dd HH:mm:ssSSS}][%p][LOGSERVICE][日志系统][%l]%n%m%n" />
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="50" />
</RollingFile>
<!--Error级别日志输出-->
<RollingFile name="system-error"
fileName="${baseDir}/logservice-web/error.log" filePattern="${baseDir}/logservice-web/error-%i.log">
<Filters>
<ThresholdFilter level="AUDIT" onMatch="DENY" onMismatch="NEUTRAL" />
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY" />
</Filters>
<PatternLayout charset="UTF-8" pattern="[%d{yyyy/MM/dd HH:mm:ssSSS}][%p][LOGSERVICE][日志系统][%l]%n%m%n" />
<Policies>
<SizeBasedTriggeringPolicy size="10 MB" />
</Policies>
<DefaultRolloverStrategy max="50" />
</RollingFile>
</Appenders>
<Loggers>
<logger name="io.netty" level="INFO"></logger>
<logger name="org.springframework" level="INFO"></logger>
<logger name="org.elasticsearch" level="INFO"></logger>
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="system-info" />
<appender-ref ref="system-trace" />
<appender-ref ref="system-debug" />
<appender-ref ref="system-error" />
<appender-ref ref="RollingFileAUDIT" />
</root>
</Loggers>
</configuration>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment