├── .gitignore ├── README.md ├── minio-swarm.yml ├── miniosample ├── pom.xml └── src │ └── main │ ├── java │ └── me │ │ └── aboullaite │ │ └── minio │ │ └── MinioSampleApplication.java │ └── resources │ └── application.yml ├── miniospringbootautoconfigure ├── pom.xml └── src │ └── main │ ├── java │ └── me │ │ └── aboullaite │ │ └── minio │ │ ├── MinioAutoConfiguration.java │ │ ├── MinioProperties.java │ │ ├── exception │ │ ├── MinioEntityExceptionHandler.java │ │ └── MinioError.java │ │ ├── http │ │ └── MinioEndpoint.java │ │ ├── service │ │ └── MinioTemplate.java │ │ └── vo │ │ ├── MinioItem.java │ │ └── MinioObject.java │ └── resources │ ├── META-INF │ ├── spring-configuration-metadata.json │ └── spring.factories │ └── application.properties ├── miniospringbootstarter └── pom.xml └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | /src/main/resources/** 4 | !.src/main/resources/application.properties 5 | CSV_Files 6 | CSV_Files/** 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | 16 | 17 | ### IntelliJ IDEA ### 18 | .idea 19 | *.iws 20 | *.iml 21 | *.ipr 22 | 23 | ### NetBeans ### 24 | nbproject/private/ 25 | build/ 26 | nbbuild/ 27 | dist/ 28 | nbdist/ 29 | .nb-gradle/ 30 | 31 | 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Minio spring boot starter 2 | Spring boot starter project that autoconfigure a Minio client. 3 | [Minio](https://www.minio.io/) is a high performance distributed object storage server, designed for large-scale private cloud infrastructure. 4 | 5 | #### Usage 6 | ##### Start minio stack: 7 | 1. Add Docker swarm secrets 8 | ``` 9 | echo "AKIAIOSFODNN7EXAMPLE" | docker secret create access_key - 10 | echo "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" | docker secret create secret_key - 11 | ``` 12 | See []Minio Docker Quickstart Guide](https://docs.minio.io/docs/minio-docker-quickstart-guide) 13 | 14 | 2. Deploy stack 15 | ``` 16 | docker stack deploy --compose-file=minio-swarm.yml minio_stack 17 | ``` 18 | 3. Test proxy 19 | We configured Træfɪk with Host:minioproxy. So we need to have a dns record for `minioproxy` pointing to a ip address of any Docker swarm node or just add it to `/etc/hosts` for a quick test. 20 | 21 | #### Configuration 22 | You need to add `minio-springboot-starter` dependency to your pom. Till now, you need to build the starter and it to your repo. 23 | You can either use the rest API to interact with minio, by setting `minio.endpoint.enable = true` (default value is false), or using the `MinioTemplate` class service directly on your code. you need also to setup minion credentials. 24 | 25 | Below a configuration example 26 | 27 | ``` 28 | minio: 29 | url: http://minioproxy 30 | access-key: changeme 31 | secret-key: changeme 32 | endpoint: 33 | enable: true 34 | name: miniotest 35 | ``` -------------------------------------------------------------------------------- /minio-swarm.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | services: 4 | minio1: 5 | image: minio/minio 6 | volumes: 7 | - minio1-data:/export 8 | networks: 9 | - minio_distributed 10 | deploy: 11 | restart_policy: 12 | delay: 10s 13 | max_attempts: 10 14 | window: 60s 15 | labels: 16 | traefik.frontend.rule: "Host:minioproxy" 17 | traefik.port: "9000" 18 | command: server http://minio1/export http://minio2/export http://minio3/export http://minio4/export 19 | secrets: 20 | - secret_key 21 | - access_key 22 | 23 | minio2: 24 | image: minio/minio 25 | volumes: 26 | - minio2-data:/export 27 | networks: 28 | - minio_distributed 29 | deploy: 30 | restart_policy: 31 | delay: 10s 32 | max_attempts: 10 33 | window: 60s 34 | labels: 35 | traefik.frontend.rule: "Host:minioproxy" 36 | traefik.port: "9000" 37 | command: server http://minio1/export http://minio2/export http://minio3/export http://minio4/export 38 | secrets: 39 | - secret_key 40 | - access_key 41 | 42 | minio3: 43 | image: minio/minio 44 | volumes: 45 | - minio3-data:/export 46 | networks: 47 | - minio_distributed 48 | deploy: 49 | restart_policy: 50 | delay: 10s 51 | max_attempts: 10 52 | window: 60s 53 | labels: 54 | traefik.frontend.rule: "Host:minioproxy" 55 | traefik.port: "9000" 56 | command: server http://minio1/export http://minio2/export http://minio3/export http://minio4/export 57 | secrets: 58 | - secret_key 59 | - access_key 60 | 61 | minio4: 62 | image: minio/minio 63 | volumes: 64 | - minio4-data:/export 65 | networks: 66 | - minio_distributed 67 | deploy: 68 | restart_policy: 69 | delay: 10s 70 | max_attempts: 10 71 | window: 60s 72 | labels: 73 | traefik.frontend.rule: "Host:minioproxy" 74 | traefik.port: "9000" 75 | command: server http://minio1/export http://minio2/export http://minio3/export http://minio4/export 76 | secrets: 77 | - secret_key 78 | - access_key 79 | 80 | minioproxy: 81 | image: traefik 82 | volumes: 83 | - /var/run/docker.sock:/var/run/docker.sock 84 | networks: 85 | - minio_distributed 86 | ports: 87 | - 80:80 88 | - 8081:8080 89 | deploy: 90 | placement: 91 | constraints: [node.role == manager] 92 | command: --docker --docker.swarmmode --docker.domain=minio --docker.watch --web 93 | 94 | volumes: 95 | minio1-data: 96 | 97 | minio2-data: 98 | 99 | minio3-data: 100 | 101 | minio4-data: 102 | 103 | networks: 104 | minio_distributed: 105 | driver: overlay 106 | 107 | secrets: 108 | secret_key: 109 | external: true 110 | access_key: 111 | external: true -------------------------------------------------------------------------------- /miniosample/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.aboullaite 8 | 0.0.1-SNAPSHOT 9 | minio-sample 10 | 11 | Spring Boot AutoConfiguration :: Minio Sample 12 | Spring Boot sample Minio app 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.5.6.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-web 30 | 31 | 32 | me.aboullaite 33 | minio-springboot-starter 34 | 0.0.1-SNAPSHOT 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-test 39 | test 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-maven-plugin 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /miniosample/src/main/java/me/aboullaite/minio/MinioSampleApplication.java: -------------------------------------------------------------------------------- 1 | package me.aboullaite.minio; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MinioSampleApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MinioSampleApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /miniosample/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | minio: 2 | url: http://minioproxy 3 | access-key: changeme 4 | secret-key: changeme 5 | endpoint: 6 | enable: true 7 | name: miniotest 8 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.aboullaite 8 | 0.0.1-SNAPSHOT 9 | minio-springboot-autoconfigure 10 | jar 11 | 12 | Spring Boot AutoConfiguration :: MINIO 13 | Spring Boot auto-configuration Minio 14 | 15 | 16 | UTF-8 17 | 1.8 18 | 1.8 19 | 1.8 20 | 3.0.12 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-autoconfigure 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-configuration-processor 31 | true 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-web 36 | 37 | 38 | io.minio 39 | minio 40 | ${minio.version} 41 | 42 | 43 | junit 44 | junit 45 | test 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-dependencies 58 | 1.5.9.RELEASE 59 | pom 60 | import 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/java/me/aboullaite/minio/MinioAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package me.aboullaite.minio; 2 | 3 | import me.aboullaite.minio.service.MinioTemplate; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.autoconfigure.condition.*; 6 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | @EnableConfigurationProperties({ MinioProperties.class }) 12 | public class MinioAutoConfiguration { 13 | 14 | @Autowired 15 | private MinioProperties properties; 16 | 17 | @Bean 18 | @ConditionalOnMissingBean(MinioTemplate.class) 19 | @ConditionalOnProperty(name = "minio.url") 20 | MinioTemplate template(){ 21 | return new MinioTemplate( 22 | properties.getUrl(), 23 | properties.getAccessKey(), 24 | properties.getSecretKey() 25 | ); 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/java/me/aboullaite/minio/MinioProperties.java: -------------------------------------------------------------------------------- 1 | package me.aboullaite.minio; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @ConfigurationProperties(prefix = "minio") 8 | public class MinioProperties { 9 | 10 | private String url, accessKey, secretKey; 11 | 12 | public String getUrl() { 13 | return url; 14 | } 15 | 16 | public void setUrl(String url) { 17 | this.url = url; 18 | } 19 | 20 | public String getAccessKey() { 21 | return accessKey; 22 | } 23 | 24 | public void setAccessKey(String accessKey) { 25 | this.accessKey = accessKey; 26 | } 27 | 28 | public String getSecretKey() { 29 | return secretKey; 30 | } 31 | 32 | public void setSecretKey(String secretKey) { 33 | this.secretKey = secretKey; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "MinioProperties{" + 39 | "url='" + url + '\'' + 40 | ", accessKey='" + accessKey + '\'' + 41 | ", secretKey='" + secretKey + '\'' + 42 | '}'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/java/me/aboullaite/minio/exception/MinioEntityExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package me.aboullaite.minio.exception; 2 | 3 | import io.minio.errors.*; 4 | import org.springframework.http.HttpHeaders; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.context.request.WebRequest; 10 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; 11 | 12 | @ControllerAdvice 13 | public class MinioEntityExceptionHandler extends ResponseEntityExceptionHandler{ 14 | 15 | @ExceptionHandler(value = {InvalidPortException.class}) 16 | protected ResponseEntity handlePortError(RuntimeException ex, WebRequest request) { 17 | MinioError error = new MinioError(HttpStatus.BAD_REQUEST, "The given port number is not valid."); 18 | return handleExceptionInternal(ex, error, 19 | new HttpHeaders(), HttpStatus.BAD_REQUEST, request); 20 | } 21 | 22 | @ExceptionHandler(value = {InvalidEndpointException.class}) 23 | protected ResponseEntity handleEndpointError(RuntimeException ex, WebRequest request) { 24 | MinioError error = new MinioError(HttpStatus.BAD_REQUEST, "The given endpoint number is not valid."); 25 | return handleExceptionInternal(ex, error, 26 | new HttpHeaders(), HttpStatus.BAD_REQUEST, request); 27 | } 28 | 29 | @ExceptionHandler(value = {RegionConflictException.class}) 30 | protected ResponseEntity handleRegionConflictError(RuntimeException ex, WebRequest request) { 31 | MinioError error = new MinioError(HttpStatus.CONFLICT, "The passed region conflicts with the one previously specified."); 32 | return handleExceptionInternal(ex, error, 33 | new HttpHeaders(), HttpStatus.CONFLICT, request); 34 | } 35 | 36 | @ExceptionHandler(value = {NoResponseException.class}) 37 | protected ResponseEntity handleNoResponseError(RuntimeException ex, WebRequest request) { 38 | String bodyOfResponse = "No response is received!"; 39 | MinioError error = new MinioError(HttpStatus.BAD_REQUEST, "No response is received!"); 40 | return handleExceptionInternal(ex, bodyOfResponse, 41 | new HttpHeaders(), HttpStatus.SERVICE_UNAVAILABLE, request); 42 | } 43 | 44 | @ExceptionHandler(value = {ErrorResponseException.class}) 45 | protected ResponseEntity handleResponseError(RuntimeException ex, WebRequest request) { 46 | String bodyOfResponse = "Received an error response while executing the requested operation!"; 47 | MinioError error = new MinioError(HttpStatus.SERVICE_UNAVAILABLE, "The given endpoint number is not valid."); 48 | return handleExceptionInternal(ex, bodyOfResponse, 49 | new HttpHeaders(), HttpStatus.SERVICE_UNAVAILABLE, request); 50 | } 51 | 52 | @ExceptionHandler(value = {InsufficientDataException.class}) 53 | protected ResponseEntity handleInsufficientDataError(RuntimeException ex, WebRequest request) { 54 | MinioError error = new MinioError(HttpStatus.SERVICE_UNAVAILABLE, "Reading given InputStream gets EOFException before reading given length."); 55 | return handleExceptionInternal(ex, error, 56 | new HttpHeaders(), HttpStatus.SERVICE_UNAVAILABLE, request); 57 | } 58 | 59 | @ExceptionHandler(value = {InvalidBucketNameException.class}) 60 | protected ResponseEntity handleBucketNameError(RuntimeException ex, WebRequest request) { 61 | MinioError error = new MinioError(HttpStatus.BAD_REQUEST, "The given bucket name is not valid!"); 62 | return handleExceptionInternal(ex, error, 63 | new HttpHeaders(), HttpStatus.BAD_REQUEST, request); 64 | } 65 | 66 | @ExceptionHandler(value = {InvalidExpiresRangeException.class}) 67 | protected ResponseEntity handleExpiresRangeError(RuntimeException ex, WebRequest request) { 68 | MinioError error = new MinioError(HttpStatus.BAD_REQUEST, "The given expires value is out of range."); 69 | return handleExceptionInternal(ex, error, 70 | new HttpHeaders(), HttpStatus.BAD_REQUEST, request); 71 | } 72 | 73 | @ExceptionHandler(value = {InvalidObjectPrefixException.class}) 74 | protected ResponseEntity handleObjectPrefixError(RuntimeException ex, WebRequest request) { 75 | MinioError error = new MinioError(HttpStatus.BAD_REQUEST, "The given object prefix is not valid"); 76 | return handleExceptionInternal(ex, error, 77 | new HttpHeaders(), HttpStatus.BAD_REQUEST, request); 78 | } 79 | 80 | @ExceptionHandler(value = {IllegalArgumentException.class}) 81 | protected ResponseEntity handleIllegalArgumentError(RuntimeException ex, WebRequest request) { 82 | MinioError error = new MinioError(HttpStatus.BAD_REQUEST, ex.getMessage()); 83 | return handleExceptionInternal(ex, error, 84 | new HttpHeaders(), HttpStatus.NOT_FOUND, request); 85 | } 86 | 87 | @ExceptionHandler(value = {Exception.class}) 88 | protected ResponseEntity handleError(RuntimeException ex, WebRequest request) { 89 | MinioError error = new MinioError(HttpStatus.BAD_REQUEST, "An unexpected internal error occured while processing the request"); 90 | ex.printStackTrace(); 91 | return handleExceptionInternal(ex, error, 92 | new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/java/me/aboullaite/minio/exception/MinioError.java: -------------------------------------------------------------------------------- 1 | package me.aboullaite.minio.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | 5 | public class MinioError { 6 | 7 | private HttpStatus status; 8 | private String message; 9 | 10 | public MinioError(HttpStatus status, String message) { 11 | this.status = status; 12 | this.message = message; 13 | } 14 | 15 | public HttpStatus getStatus() { 16 | return status; 17 | } 18 | 19 | public void setStatus(HttpStatus status) { 20 | this.status = status; 21 | } 22 | 23 | public String getMessage() { 24 | return message; 25 | } 26 | 27 | public void setMessage(String message) { 28 | this.message = message; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/java/me/aboullaite/minio/http/MinioEndpoint.java: -------------------------------------------------------------------------------- 1 | package me.aboullaite.minio.http; 2 | 3 | import io.minio.errors.*; 4 | import io.minio.messages.Bucket; 5 | import me.aboullaite.minio.service.MinioTemplate; 6 | import me.aboullaite.minio.vo.MinioItem; 7 | import me.aboullaite.minio.vo.MinioObject; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.web.bind.annotation.*; 12 | import org.springframework.web.multipart.MultipartFile; 13 | import org.xmlpull.v1.XmlPullParserException; 14 | 15 | import java.io.IOException; 16 | import java.security.InvalidKeyException; 17 | import java.security.NoSuchAlgorithmException; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | @ConditionalOnProperty(name = "minio.endpoint.enable", havingValue = "true") 23 | @RestController 24 | @RequestMapping("${minio.endpoint.name:/minio}") 25 | public class MinioEndpoint { 26 | 27 | @Autowired 28 | private MinioTemplate template; 29 | private static final Integer ONE_DAY = 60 * 60 * 24; 30 | 31 | /** 32 | * 33 | * Bucket Endpoints 34 | */ 35 | @PostMapping("/bucket/{bucketName}") 36 | public Bucket createBucker(@PathVariable String bucketName) throws IOException, InvalidKeyException, NoSuchAlgorithmException, XmlPullParserException, InvalidPortException, ErrorResponseException, InternalException, NoResponseException, InvalidBucketNameException, InsufficientDataException, InvalidEndpointException, RegionConflictException { 37 | 38 | template.createBucket(bucketName); 39 | return template.getBucket(bucketName).get(); 40 | 41 | } 42 | 43 | @GetMapping("/bucket") 44 | public List getBuckets() throws IOException, XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, InvalidPortException, ErrorResponseException, NoResponseException, InvalidBucketNameException, InsufficientDataException, InvalidEndpointException, InternalException { 45 | return template.getAllBuckets(); 46 | } 47 | 48 | @GetMapping("/bucket/{bucketName}") 49 | public Bucket getBucket(@PathVariable String bucketName) throws IOException, XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, InvalidPortException, ErrorResponseException, NoResponseException, InvalidBucketNameException, InsufficientDataException, InvalidEndpointException, InternalException { 50 | return template.getBucket(bucketName).orElseThrow(() -> new IllegalArgumentException("Bucket Name not found!")); 51 | } 52 | 53 | @DeleteMapping("/bucket/{bucketName}") 54 | @ResponseStatus(HttpStatus.ACCEPTED) 55 | public void deleteBucket(@PathVariable String bucketName) throws IOException, XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, InvalidPortException, ErrorResponseException, NoResponseException, InvalidBucketNameException, InsufficientDataException, InvalidEndpointException, InternalException { 56 | 57 | template.removeBucket(bucketName); 58 | } 59 | 60 | /** 61 | * 62 | * Object Endpoints 63 | */ 64 | 65 | @PostMapping("/object/{bucketName}") 66 | public MinioObject createObject(@RequestBody MultipartFile object, @PathVariable String bucketName) throws IOException, InvalidKeyException, NoSuchAlgorithmException, XmlPullParserException, InvalidPortException, ErrorResponseException, InternalException, NoResponseException, InvalidBucketNameException, InsufficientDataException, InvalidEndpointException, RegionConflictException, InvalidArgumentException { 67 | String name = object.getOriginalFilename(); 68 | template.saveObject(bucketName, name, object.getInputStream(), object.getSize(), object.getContentType()); 69 | return new MinioObject(template.getObjectInfo(bucketName, name)); 70 | 71 | } 72 | 73 | @PostMapping("/object/{bucketName}/{objectName}") 74 | public MinioObject createObject(@RequestBody MultipartFile object, @PathVariable String bucketName, @PathVariable String objectName) throws IOException, InvalidKeyException, NoSuchAlgorithmException, XmlPullParserException, InvalidPortException, ErrorResponseException, InternalException, NoResponseException, InvalidBucketNameException, InsufficientDataException, InvalidEndpointException, RegionConflictException, InvalidArgumentException { 75 | template.saveObject(bucketName, objectName, object.getInputStream(), object.getSize(), object.getContentType()); 76 | return new MinioObject(template.getObjectInfo(bucketName, objectName)); 77 | 78 | } 79 | 80 | 81 | @GetMapping("/object/{bucketName}/{objectName}") 82 | public List filterObject(@PathVariable String bucketName, @PathVariable String objectName) throws InvalidPortException, InvalidEndpointException { 83 | 84 | return template.getAllObjectsByPrefix(bucketName, objectName, true); 85 | 86 | } 87 | 88 | @GetMapping("/object/{bucketName}/{objectName}/{expires}") 89 | public Map getObject( @PathVariable String bucketName, @PathVariable String objectName, @PathVariable Integer expires) throws IOException, XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, InvalidPortException, ErrorResponseException, NoResponseException, InvalidBucketNameException, InsufficientDataException, InvalidEndpointException, InternalException, InvalidExpiresRangeException { 90 | Map responseBody = new HashMap<>(); 91 | // Put Object info 92 | responseBody.put("bucket" , bucketName); 93 | responseBody.put("object" , objectName); 94 | responseBody.put("url" , template.getObjectURL(bucketName, objectName, expires)); 95 | responseBody.put("expires" , expires); 96 | return responseBody; 97 | } 98 | 99 | @DeleteMapping("/object/{bucketName}/{objectName}/") 100 | @ResponseStatus(HttpStatus.ACCEPTED) 101 | public void deleteObject(@PathVariable String bucketName, @PathVariable String objectName) throws IOException, XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, InvalidPortException, ErrorResponseException, NoResponseException, InvalidBucketNameException, InsufficientDataException, InvalidEndpointException, InternalException, InvalidArgumentException { 102 | 103 | template.removeObject(bucketName, objectName); 104 | } 105 | 106 | 107 | } 108 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/java/me/aboullaite/minio/service/MinioTemplate.java: -------------------------------------------------------------------------------- 1 | package me.aboullaite.minio.service; 2 | 3 | import io.minio.MinioClient; 4 | import io.minio.ObjectStat; 5 | import io.minio.Result; 6 | import io.minio.errors.*; 7 | import io.minio.messages.Bucket; 8 | import io.minio.messages.Item; 9 | import me.aboullaite.minio.vo.MinioItem; 10 | import org.xmlpull.v1.XmlPullParserException; 11 | 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.security.InvalidKeyException; 15 | import java.security.NoSuchAlgorithmException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import java.util.Optional; 19 | 20 | 21 | public class MinioTemplate { 22 | 23 | private String endpoint, accessKey, secretKey; 24 | 25 | public MinioTemplate() { 26 | } 27 | 28 | /** 29 | * Create new instance of the {@link MinioTemplate} with the access key and secret key. 30 | * @param endpoint minio URL, it should be a URL, domain name, IPv4 address or IPv6 address 31 | * @param accessKey uniquely identifies a minio account. 32 | * @param secretKey the password to a minio account. 33 | */ 34 | public MinioTemplate(String endpoint, String accessKey, String secretKey) { 35 | this.endpoint = endpoint; 36 | this.accessKey = accessKey; 37 | this.secretKey = secretKey; 38 | } 39 | 40 | /** 41 | * Bucket Operations 42 | */ 43 | 44 | public void createBucket(String bucketName) throws XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, IOException, InvalidPortException, InvalidEndpointException, RegionConflictException, NoResponseException, InternalException, ErrorResponseException, InsufficientDataException, InvalidBucketNameException { 45 | MinioClient client = getMinioClient(); 46 | if(!client.bucketExists(bucketName)){ 47 | client.makeBucket(bucketName); 48 | } 49 | } 50 | 51 | public List getAllBuckets() throws InvalidPortException, InvalidEndpointException, IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InternalException, NoResponseException, InvalidBucketNameException, XmlPullParserException, ErrorResponseException { 52 | return getMinioClient().listBuckets(); 53 | } 54 | 55 | public Optional getBucket(String bucketName) throws InvalidPortException, InvalidEndpointException, IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InternalException, NoResponseException, InvalidBucketNameException, XmlPullParserException, ErrorResponseException { 56 | return getMinioClient().listBuckets().stream().filter( b -> b.name().equals(bucketName)).findFirst(); 57 | } 58 | 59 | public void removeBucket(String bucketName) throws InvalidPortException, InvalidEndpointException, IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InternalException, NoResponseException, InvalidBucketNameException, XmlPullParserException, ErrorResponseException { 60 | getMinioClient().removeBucket(bucketName); 61 | } 62 | 63 | public List getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) throws InvalidPortException, InvalidEndpointException{ 64 | List objectList = new ArrayList(); 65 | Iterable> objectsIterator = getMinioClient().listObjects(bucketName, prefix, recursive); 66 | objectsIterator.forEach(i -> { 67 | try { 68 | objectList.add(new MinioItem(i.get())); 69 | } catch (Exception e) { 70 | new Exception(e); 71 | } 72 | }); 73 | return objectList; 74 | } 75 | 76 | /** 77 | * Object operations 78 | */ 79 | 80 | public String getObjectURL(String bucketName, String objectName, Integer expires) throws InvalidPortException, InvalidEndpointException, IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InvalidExpiresRangeException, InternalException, NoResponseException, InvalidBucketNameException, XmlPullParserException, ErrorResponseException { 81 | return getMinioClient().presignedGetObject(bucketName, objectName, expires); 82 | } 83 | 84 | public void saveObject(String bucketName, String objectName, InputStream stream, long size, String contentType) throws InvalidPortException, InvalidEndpointException, IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InvalidArgumentException, InternalException, NoResponseException, InvalidBucketNameException, XmlPullParserException, ErrorResponseException { 85 | getMinioClient().putObject(bucketName, objectName, stream, size, contentType); 86 | } 87 | 88 | public ObjectStat getObjectInfo(String bucketName, String objectName) throws InvalidPortException, InvalidEndpointException, IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InternalException, NoResponseException, InvalidBucketNameException, XmlPullParserException, ErrorResponseException { 89 | return getMinioClient().statObject(bucketName, objectName); 90 | } 91 | 92 | public void removeObject(String bucketName, String objectName ) throws InvalidPortException, InvalidEndpointException, IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InternalException, NoResponseException, InvalidBucketNameException, XmlPullParserException, ErrorResponseException, InvalidArgumentException { 93 | getMinioClient().removeObject(bucketName, objectName); 94 | } 95 | 96 | 97 | /** 98 | * Gets a Minio client 99 | * 100 | * @return an authenticated Amazon S3 client 101 | */ 102 | public MinioClient getMinioClient() throws InvalidPortException, InvalidEndpointException { 103 | return new MinioClient(endpoint, accessKey, secretKey); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/java/me/aboullaite/minio/vo/MinioItem.java: -------------------------------------------------------------------------------- 1 | package me.aboullaite.minio.vo; 2 | import io.minio.messages.Item; 3 | import io.minio.messages.Owner; 4 | 5 | import java.util.Date; 6 | 7 | public class MinioItem { 8 | 9 | private String objectName; 10 | private Date lastModified; 11 | private String etag; 12 | private long size; 13 | private String storageClass; 14 | private Owner owner; 15 | private String type; 16 | 17 | public MinioItem(String objectName, Date lastModified, String etag, long size, String storageClass, Owner owner, String type) { 18 | this.objectName = objectName; 19 | this.lastModified = lastModified; 20 | this.etag = etag; 21 | this.size = size; 22 | this.storageClass = storageClass; 23 | this.owner = owner; 24 | this.type = type; 25 | } 26 | 27 | 28 | public MinioItem(Item item) { 29 | this.objectName = item.objectName(); 30 | this.lastModified = item.lastModified(); 31 | this.etag = item.etag(); 32 | this.size = item.size(); 33 | this.storageClass = item.storageClass(); 34 | this.owner = item.owner(); 35 | this.type = item.isDir() ? "directory" : "file"; 36 | } 37 | 38 | public String getObjectName() { 39 | return objectName; 40 | } 41 | 42 | public void setObjectName(String objectName) { 43 | this.objectName = objectName; 44 | } 45 | 46 | public Date getLastModified() { 47 | return lastModified; 48 | } 49 | 50 | public void setLastModified(Date lastModified) { 51 | this.lastModified = lastModified; 52 | } 53 | 54 | public String getEtag() { 55 | return etag; 56 | } 57 | 58 | public void setEtag(String etag) { 59 | this.etag = etag; 60 | } 61 | 62 | public long getSize() { 63 | return size; 64 | } 65 | 66 | public void setSize(long size) { 67 | this.size = size; 68 | } 69 | 70 | public String getStorageClass() { 71 | return storageClass; 72 | } 73 | 74 | public void setStorageClass(String storageClass) { 75 | this.storageClass = storageClass; 76 | } 77 | 78 | public Owner getOwner() { 79 | return owner; 80 | } 81 | 82 | public void setOwner(Owner owner) { 83 | this.owner = owner; 84 | } 85 | 86 | public String getType() { 87 | return type; 88 | } 89 | 90 | public void setType(String type) { 91 | this.type = type; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/java/me/aboullaite/minio/vo/MinioObject.java: -------------------------------------------------------------------------------- 1 | package me.aboullaite.minio.vo; 2 | 3 | import io.minio.ObjectStat; 4 | 5 | import java.util.Date; 6 | 7 | public class MinioObject { 8 | 9 | private String bucketName; 10 | private String name; 11 | private Date createdTime; 12 | private long length; 13 | private String etag; 14 | private String contentType; 15 | private String matDesc; 16 | 17 | public MinioObject(String bucketName, String name, Date createdTime, long length, String etag, String contentType, String matDesc) { 18 | this.bucketName = bucketName; 19 | this.name = name; 20 | this.createdTime = createdTime; 21 | this.length = length; 22 | this.etag = etag; 23 | this.contentType = contentType; 24 | this.matDesc = matDesc; 25 | } 26 | 27 | public MinioObject(ObjectStat os) { 28 | this.bucketName = os.bucketName(); 29 | this.name = os.name(); 30 | this.createdTime = os.createdTime(); 31 | this.length = os.length(); 32 | this.etag = os.etag(); 33 | this.contentType = os.contentType(); 34 | this.matDesc = os.matDesc(); 35 | } 36 | 37 | public String getBucketName() { 38 | return bucketName; 39 | } 40 | 41 | public String getName() { 42 | return name; 43 | } 44 | 45 | public Date getCreatedTime() { 46 | return createdTime; 47 | } 48 | 49 | public long getLength() { 50 | return length; 51 | } 52 | 53 | public String getEtag() { 54 | return etag; 55 | } 56 | 57 | public String getContentType() { 58 | return contentType; 59 | } 60 | 61 | public String getMatDesc() { 62 | return matDesc; 63 | } 64 | 65 | public void setBucketName(String bucketName) { 66 | this.bucketName = bucketName; 67 | } 68 | 69 | public void setName(String name) { 70 | this.name = name; 71 | } 72 | 73 | public void setCreatedTime(Date createdTime) { 74 | this.createdTime = createdTime; 75 | } 76 | 77 | public void setLength(long length) { 78 | this.length = length; 79 | } 80 | 81 | public void setEtag(String etag) { 82 | this.etag = etag; 83 | } 84 | 85 | public void setContentType(String contentType) { 86 | this.contentType = contentType; 87 | } 88 | 89 | public void setMatDesc(String matDesc) { 90 | this.matDesc = matDesc; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/resources/META-INF/spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "groups": [ 3 | { 4 | "name": "minio", 5 | "type": "me.aboullaite.minio.MinioProperties", 6 | "sourceType": "me.aboullaite.minio.MinioProperties" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=me.aboullaite.minio.MinioAutoConfiguration -------------------------------------------------------------------------------- /miniospringbootautoconfigure/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #minio.endpoint=http://localhost:9000 2 | #minio.access-key= 3 | #minio.secret-key= -------------------------------------------------------------------------------- /miniospringbootstarter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.aboullaite 8 | 0.0.1-SNAPSHOT 9 | minio-springboot-starter 10 | jar 11 | Spring Boot AutoConfiguration :: Minio Starter 12 | 13 | 14 | UTF-8 15 | UTF-8 16 | 17 | 18 | 19 | 20 | me.aboullaite 21 | minio-springboot-autoconfigure 22 | 0.0.1-SNAPSHOT 23 | 24 | 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-dependencies 31 | 1.5.9.RELEASE 32 | pom 33 | import 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.aboullaite 8 | minio-springboot-starter-parent 9 | pom 10 | 0.0.1-SNAPSHOT 11 | 12 | 13 | 1.8 14 | 1.8 15 | 16 | 17 | Spring Boot Minio AutoConfiguration 18 | 19 | 20 | miniospringbootstarter 21 | miniospringbootautoconfigure 22 | miniosample 23 | 24 | 25 | 26 | --------------------------------------------------------------------------------