SpringBoot integration MinIO practice

Posted by johncox on Sun, 27 Feb 2022 05:34:17 +0100

background

MinIO is the world's leading object storage pioneer, with read / write speeds of 183 GB / s and 171 GB / s on standard hardware. MinIO is used as the main storage of cloud native applications. Compared with traditional object storage, cloud native applications need higher throughput and lower latency. By adding more clusters, you can expand the namespace and more racks until you achieve your goal. At the same time, it conforms to the architecture and construction process of all native cloud computing, and includes the latest new technologies and concepts of cloud computing.

As for object storage, it is nothing more than file upload, download and deletion, plus bucket operation. Here we use SpringBoot to integrate MinIO single instance combat. For the high availability and scalability test of MinIO distributed cluster, please refer to the article: High availability test of MinIO distributed file storage cluster developed by full stack

  1. Barrel management;
  2. Object management (upload, download, delete);
  3. Object pre signature;
  4. Bucket strategy management;

rely on

Note: I use 7 X version for experiment and demonstration, the latest version of 8 The MinIO background management interface of X is different, but after our actual production test, the interfaces are compatible.

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>7.1.4</version>
</dependency>

MinIO runs under a single instance of Docker

docker run -p 9000:9000 \
  --name minio1 \
  -v /opt/minio/data-single \
  -e "MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE" \
  -e "MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
  minio/minio server /data

Interface test

Based on MinIO client, it mainly realizes service interfaces such as bucket management, object management and object pre signature.

Provide external operation interfaces for file upload, download and deletion with RESTful API;

Upload, download and delete test files using PostMan interface: header information: content type: multipart / form data

# upload
curl --location --request POST 'localhost:8090/minio/uploadFile' \
--header 'Content-Type: multipart/form-data' \
--form 'file=@"/C:/Users/nxq01/Downloads/springboot-minio-master.zip"'

# download
curl --location --request POST 'localhost:8090/minio/downloadFile' \
--form 'bucketName="heartsuit"' \
--form 'originalName="springboot-minio-master.zip"' \
--form 'filePath="2021-11-23/92cf3f69-501b-41de-83ae-f67e5a57f35f.zip"'

# delete
curl --location --request POST 'localhost:8090/minio/deleteFile' \
--header 'Content-Type: multipart/form-data' \
--form 'bucketName="heartsuit"' \
--form 'filePath="2021-11-23/92cf3f69-501b-41de-83ae-f67e5a57f35f.zip"'

Core interface

  • Controller
@RequestMapping("/minio")
@RestController
@Slf4j
public class MinIOController {
    @Autowired
    private MinIOService minIOService;

    @Autowired
    private MinIOConfig minioConfig;

    @PostMapping("/uploadFile")
    public Result<String> uploadFile(MultipartFile file, String bucketName) {
        try {
            bucketName = !StringUtils.isEmpty(bucketName) ? bucketName : minioConfig.getBucketName();
            if (!minIOService.bucketExists(bucketName)) {
                minIOService.makeBucket(bucketName);
            }
            String fileName = file.getOriginalFilename();
            assert fileName != null;

            // According to the business design, set the storage path: create a directory by day
            String objectName = new SimpleDateFormat("yyyy-MM-dd/").format(new Date())
                    + UUID.randomUUID().toString()
                    + fileName.substring(fileName.lastIndexOf("."));

            minIOService.putObject(bucketName, file, objectName);
            log.info("The file format is:{}", file.getContentType());
            log.info("The original name of the file is:{}", fileName);
            log.info("The bucket of file storage is:{}", bucketName);
            log.info("File object path is:{}", objectName);
            return Result.success(minIOService.getObjectUrl(bucketName, objectName));
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("Upload failed");
        }
    }

    @PostMapping("/deleteFile")
    public Result<String> deleteFile(String bucketName, String filePath) throws Exception {
        if (!minIOService.bucketExists(bucketName)) {
            throw new Exception("The bucket does not exist");
        }
        boolean status = minIOService.removeObject(bucketName, filePath);
        return status ? Result.success("Deleted successfully") : Result.success("Delete failed");
    }

    @PostMapping("/downloadFile")
    public Result<String> downloadFile(String bucketName, String filePath, String originalName, HttpServletResponse response) throws Exception {
        if (!minIOService.bucketExists(bucketName)) {
            throw new Exception("The bucket does not exist");
        }
        boolean status = minIOService.downloadFile(bucketName, filePath, originalName, response);
        return status ? Result.success("Download successful") : Result.success("Download failed");
    }
}
  • Service
@Service
public class MinIOServiceImpl  implements MinIOService {
    @Autowired
    private MinIOUtils minIOUtils;

    /**
     * Determine whether the bucket exists
     *
     * @param bucketName
     * @return
     */
    @Override
    public boolean bucketExists(String bucketName) {
        return minIOUtils.bucketExists(bucketName);
    }

    /**
     * Create bucket
     *
     * @param bucketName
     */
    @Override
    public void makeBucket(String bucketName) {
        minIOUtils.makeBucket(bucketName);
    }

    /**
     * File upload
     *
     * @param bucketName
     * @param objectName
     * @param filename
     */
    @Override
    public void putObject(String bucketName, String objectName, String filename) {
        minIOUtils.putObject(bucketName, objectName, filename);
    }

    @Override
    public void putObject(String bucketName, String objectName, InputStream stream, String contentType) {
        minIOUtils.putObject(bucketName, objectName, stream, contentType);
    }

    /**
     * File upload
     *
     * @param bucketName
     * @param multipartFile
     */
    @Override
    public void putObject(String bucketName, MultipartFile multipartFile, String filename) {
        minIOUtils.putObject(bucketName, multipartFile, filename);
    }

    /**
     * Delete file
     * @param bucketName
     * @param filePath
     */
    @Override
    public boolean removeObject(String bucketName,String filePath) {
        return minIOUtils.removeObject(bucketName,filePath);
    }

    /**
     * Download File
     * @param bucketName
     * @param filePath
     * @param originalName
     * @param response
     * @return
     */
    @Override
    public boolean downloadFile(String bucketName, String filePath, String originalName, HttpServletResponse response) {
        return minIOUtils.downloadFile(bucketName,filePath, originalName, response);
    }

    /**
     * Get file path
     * @param bucketName
     * @param objectName
     * @return
     */
    @Override
    public String getObjectUrl(String bucketName,String objectName) {
        return minIOUtils.getObjectUrl(bucketName,objectName);
    }
}

The miniutils tool class is omitted. Please refer to the project source code at the end of the article.

Possible problems

  • SpringBoot upload file error: org springframework. web. multipart. MaxUploadSizeExceededException: Maximum upload size exceeded; nested exception is java. lang. IllegalStateException: org. apache. tomcat. util. http. fileupload. impl. FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.

This is because the SpringBoot project limits the size of uploaded files, which is 1M by default. When a user uploads a file with a size of more than 1M, the above error will be thrown, which can be modified through the following configuration.

spring:
  servlet:
    multipart:
      maxFileSize: 10MB
      maxRequestSize: 30MB
  • Unable to enter the container through docker exec -it cd34c345960c /bin/bash, with an error: OCI runtime exec failed: exec failed: container_linux.go:349: starting container process caused “exec: “/”: permission denied”: unknown

Solution: change docker exec -it cd34c345960c /bin/bash to: docker exec -it cd34c345960c sh or: docker exec -it cd34c345960c /bin/sh

Source Code

See GitHub for complete source code: https://github.com/heartsuit/demo-spring-boot/tree/master/springboot-minio

Reference

If you have any questions or any bugs are found, please feel free to contact me.

Your comments and suggestions are welcome!

Topics: Java Docker Spring Boot MinIO