How to Set Up MinIO with Docker and Integrate It into a Spring Boot Application

This tutorial explains how to deploy a MinIO object‑storage service using Docker on Linux/macOS and Windows, configure a Spring Boot backend with MinIO client libraries, and build a Vue + Element‑UI front‑end for various file‑upload methods, providing complete code examples and deployment steps.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
How to Set Up MinIO with Docker and Integrate It into a Spring Boot Application

MinIO is a high‑performance, S3‑compatible object storage released under the AGPL‑v3 license, suitable for machine‑learning, analytics, and application data workloads.

1. Deploy MinIO with Docker

Linux/macOS:

docker run -p 9000:9000 \
  --name minio1 \
  -v /mnt/data:/data \
  -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \
  -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
  minio/minio server /data

Windows:

docker run -p 9000:9000 \
  --name minio1 \
  -v D:\data:/data \
  -e "MINIO_ROOT_USER=AKIAIOSFODNN7EXAMPLE" \
  -e "MINIO_ROOT_PASSWORD=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
  minio/minio server /data

The environment variables MINIO_ROOT_USER and MINIO_ROOT_PASSWORD set the access key and secret key. The commands start a single‑node instance; refer to the official documentation for distributed setups.

After the container starts, the MinIO web console is reachable at http://localhost:9000.

2. Spring Boot Integration

Add the following Maven dependencies:

<!-- Thymeleaf template engine -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!-- MinIO Java client -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.2.1</version>
</dependency>

<!-- Lombok (optional) -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

Configure MinIO properties in application.yml (or application.properties):

spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
  # MinIO configuration
  minio:
    access-key: AKIAIOSFODNN7EXAMPLE
    secret-key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
    url: http://localhost:9000
    bucket-name: wdhcr
  thymeleaf:
    cache: false

Create a configuration class to bind these properties and expose a MinioClient bean:

@Configuration
@ConfigurationProperties(prefix = "spring.minio")
@Data
public class MinioConfiguration {
    private String accessKey;
    private String secretKey;
    private String url;
    private String bucketName;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
                .endpoint(url)
                .credentials(accessKey, secretKey)
                .build();
    }
}

Implement a component MinioComp that provides helper methods for generating presigned policies, uploading files, and obtaining temporary URLs:

@Component
public class MinioComp {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfiguration configuration;

    /** Get presigned POST policy */
    public Map getPolicy(String fileName, ZonedDateTime time) {
        PostPolicy postPolicy = new PostPolicy(configuration.getBucketName(), time);
        postPolicy.addEqualsCondition("key", fileName);
        try {
            Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
            HashMap<String, String> map1 = new HashMap<>();
            map.forEach((k, v) -> map1.put(k.replaceAll("-", ""), v));
            map1.put("host", configuration.getUrl() + "/" + configuration.getBucketName());
            return map1;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /** Get presigned object URL */
    public String getPolicyUrl(String objectName, Method method, int time, TimeUnit timeUnit) {
        try {
            return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(method)
                    .bucket(configuration.getBucketName())
                    .object(objectName)
                    .expiry(time, timeUnit)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /** Upload a file */
    public void upload(MultipartFile file, String fileName) {
        try {
            InputStream inputStream = file.getInputStream();
            minioClient.putObject(PutObjectArgs.builder()
                .bucket(configuration.getBucketName())
                .object(fileName)
                .stream(inputStream, file.getSize(), -1)
                .contentType(file.getContentType())
                .build());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /** Get temporary access URL for a file */
    public String getUrl(String objectName, int time, TimeUnit timeUnit) {
        try {
            return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(configuration.getBucketName())
                    .object(objectName)
                    .expiry(time, timeUnit)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

Key points:

Use MultipartFile to receive file streams from the front‑end and upload them to MinIO.

Generate a signed formData policy for direct browser uploads.

Generate a temporary presigned URL for direct uploads via HTTP PUT.

Obtain a temporary download URL (default up to 7 days).

3. Front‑End Vue + Element‑UI Demo

The page demonstrates three upload approaches: traditional server‑side upload, direct form‑data upload using the signed policy, and direct URL upload using a presigned PUT URL. The Vue instance defines methods to request policies, upload files, and retrieve URLs via Axios.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <title>Upload Image</title>
</head>
<body>
<div id="app">
    <el-row :gutter="2">
        <!-- Traditional upload -->
        <el-col :span="8">
            <el-upload class="upload-demo" action="#" drag
                       :http-request="uploadHandle">
                <i class="el-icon-upload"></i>
                <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
                <div class="el-upload__tip" slot="tip">只能上传 jpg/png,且不超过 500kb</div>
            </el-upload>
            <div v-if="imgUrl"><img :src="imgUrl" style="width:40px;height:40px"></img></div>
        </el-col>
        <!-- Form‑data direct upload -->
        <el-col :span="8">
            <el-upload class="upload-demo" action="#" drag
                       :http-request="httpRequestHandle">
                ...
            </el-upload>
            <div v-if="directUrl"><img :src="directUrl" style="width:40px;height:40px"></img></div>
        </el-col>
        <!-- URL direct upload -->
        <el-col :span="8">
            <el-upload class="upload-demo" action="#" drag
                       :http-request="UrlUploadHandle">
                ...
            </el-upload>
            <div v-if="uploadUrl"><img :src="uploadUrl" style="width:40px;height:40px"></img></div>
        </el-col>
    </el-row>
</div>

<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
new Vue({
    el: '#app',
    data() { return { imgUrl: '', directUrl: '', uploadUrl: '' } },
    methods: {
        uploadHandle({file}) { this.traditionPost(file); },
        traditionPost(file) { /* send file to /upload */ },
        getpolicy(file) { /* request signed policy then upload */ },
        httpRequestHandle({file}) { this.getpolicy(file); },
        getUploadUrl(file) { /* request presigned PUT URL then upload */ },
        UrlUploadHandle({file}) { this.getUploadUrl(file); },
        axiosPost(method, url, data, config) {
            return axios({method, url, data, headers: config})
                .then(resp => resp)
                .catch(err => "exception=" + err);
        }
    }
});
</script>
<style>
.div-center-class { padding:28% 0; text-align:center; background:beige; }
</style>
</body>
</html>

The article concludes with a link to the full source code repository: https://gitee.com/jack_whh/minio-upload .

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DockerSpring BootMinioobject storage
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.