preface

1) Why not FastDFS, one must ask? As we all know, FastDFS native installation is very complex, people who have installation experience generally understand, although you can use others to do a good job of docker installation directly, but the real use of the process may also appear many puzzling problems; 2) why not use OSS or other existing cloud products? Reason is very simple, you can’t guarantee their cloud project must be owned by a company meeting, according to my personal understanding, most companies use Intranet server either on party a, or is the company’s own internal structures, such as my company is relying on the own server in hospital, all the deployment headed by safe, can only build internal file server; 3), Minio is developed by GO language, with good performance, easy installation, distributed storage of massive images, audio, video and other files, and has its own management background interface, very friendly. 4), I have a habit, every year will see what will the new technology of large flow training institutions to remove what technology, though Minio out for some time, but these two years in succession lecturer Minio begin to introduce the well-known institutions, means that the acceptance of the product is higher, as the training institutions to cultivate personnel spread to every IT company, Acceptance is only going to get better. IO /docs/minio-… Minio Chinese Address: docs.minio.org.cn/docs/ special note: most of the content can be directly read The Chinese website, but when downloading minio, the best look at the official website, because minio version updates very quickly, often appear resource files change directory, at the same time, the Chinese address may be invalid, resulting in download failure.




Build Minio

It is divided into several steps, such as download, installation, startup, access, custom startup script and permanent access link.

1. Download the minio

IO /docs/minio-…

Go to this location and download the version you want. I use Linux here, so just download the first one.


2) Remote pull

Create your own minio directory

Remote pull:wget http://dl.minio.org.cn/server/minio/release/darwin-amd64/minio


2. Install the minio

Chmod +x minio 2) run the./minio command in the directory where the binary file is located.


3. Start the minio

1) Create a data directory in the miniO installation directory to store miniO data: mkdir data;


/minio server /data/minio/data > /data/minio/minio.log 2>&1 & Run the tail -f minio.log command to check the background run log

Special note: The console port is 33587, and the last line of WARNING indicates that the console port is dynamically generated. Please use the command to select a static port. If you restart the console, the port will change again. You need to set a fixed static port. The specific setting method can be set according to the command prompt. During the restart, run the kill -9 [process NUMBER] command to kill the minio that was started by the background process.

# specify background port as9999
./minio server --console-address 0.0. 0. 0:9999 /data/minio/data > /data/minio/minio.log 2> &1 &
Copy the code


4. Visit the minio

After setting a fixed static port, the log indicates that the access address is http://127.0.0.1:9999. Here, we can replace it with the IP address of our server. I use Tencent cloud server here. Effect of access address: http://42.193.14.144:9999 as follows, and interface are not the same as the original: the default password is: minioadmin minioadmin


5. Customize the script to start minio

1) Create a shell script and put in the commands that need to be set at startup. The command for setting the account password is added instead of using the default account password minioadmin. Create a new shell script: vim minio-start.sh

Set the account passwordexport MINIO_ACCESS_KEY=root
export MINIO_SECRET_KEY=123456Start minio./minio server --console-address 0.0. 0. 0:9999 /data/minio/data > /data/minio/minio.log 2> &1 &
Copy the code

Chmod +x minio-start.sh: chmod +x minio-start.sh: chmod +x minio-start.sh

6. Use minio

Once in the background, you can use Minio to upload files, preview, share urls and more to try out the beauty of Minio. The only thing to understand is the concept of Bucket, because it is often used when calling minio’s API. It can be understood simply as a basket of eggs (directory for files).

PS: Students who just started using the file may be used to click the share button on the right side of the file to copy the file link generated in the background and paste it into the browser to open it. Basically, they will encounter the situation that they cannot open it, because when you look at the link carefully, you will find that the IP port of the link address is wrong, which is a mistake. We usually use minio to execute commands through the MC client for configuration, to achieve permanent access to files and directly download files.


7. Set permanent access links

1) Install the MC client

Can refer to the official website, write very detailed:Docs. Min. IO/docs/minio -…

You can also refer to Chinese website:Docs.minio.org.cn/docs/master…

When you open the document and read it for a while, you’ll find that it’s written well, but you don’t understand it. Never mind, there are many people who have stepped on the hole and cleared the obstacle.

Install the MC client:wget https://dl.min.io/client/mc/release/linux-amd64/mc

Here confirms what I said before, install minio related files best look at the official website, here the Chinese address can not download, so the installation is not successful.

Official MC installation address:

Chinese MC installation address :(this has been invalid when I use)


Similarly, grant permissions to the MC execution file, otherwise insufficient permissions will be displayed. Chmod + x MC

Set a permanent access link, the official website and Chinese website are not clear, I think this is to set an accessible prefix address, convenient after opening the bucket permission can directly access the picture, convenient to understand you can imagine doing proxy for nginx.

Set the configuration name to minio, set the access prefix to http://42.193.14.144, this is my Tencent cloud server address mentioned above, and set the port to 9000, of course, can also be set to other, I set 9000 here because the rules of Tencent cloud security group already exist 9000 port, I don’t need to add rules again. Here root and 123456 is the previous custom startup script set account password, you can change your own. Nothing else needs to be changed.

./mc config host add minio http://42.193.14.144:9000 root 123456 -- API S3v4
Copy the code

Special note: remember, set port here, if you use a local VIRTUAL machine, or close the firewall, or open the port you set; If you are using a cloud server like mine, you need to add rules to open this port in the cloud server background management regardless of whether the firewall is turned on or not, otherwise you still cannot open the file.


Set the permission for files in a bucket (i.e. file directory) to be downloaded directly:./ MC policy set Download minio/ Hospitalimages

Hospitalimages here is the bucket that I built to store Internet hospital files. Remember to add the previous minio, which is the configuration name set in the previous command.

After executing the command, the files under the bucket are directly accessible.

After the command for setting permanent access link and download permission is executed, the final effect is as follows:

throughhttp://server IP address: port/bucket name/file nameDirect access!




Integrate SpringBoot Minio

Special note: Minio introduced different versions rely on, there is a large difference between the use of such as 7 and 8, difference is very big, I also touched many pits, search a lot of data, although 7 version is used, but the current version is new, just use version 8, 8 many pit, then in a website finally found the wind shadow month between the teacher can use to plan, It has been used in the company’s projects, and I share it directly with you here.

1. Introduce dependencies
<! -- MinIO --> <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.21.</version>
</dependency>
Copy the code
2. MinioUtils tool class
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

/** * MinIO tool class **@author guoj
 * @date 2021/12/14 19:30
 */
@Slf4j
public class MinIOUtils {

    private static MinioClient minioClient;

    private static String endpoint;
    private static String bucketName;
    private static String accessKey;
    private static String secretKey;
    private static Integer imgSize;
    private static Integer fileSize;


    private static final String SEPARATOR = "/";

    public MinIOUtils(a) {}public MinIOUtils(String endpoint, String bucketName, String accessKey, String secretKey, Integer imgSize, Integer fileSize) {
        MinIOUtils.endpoint = endpoint;
        MinIOUtils.bucketName = bucketName;
        MinIOUtils.accessKey = accessKey;
        MinIOUtils.secretKey = secretKey;
        MinIOUtils.imgSize = imgSize;
        MinIOUtils.fileSize = fileSize;
        createMinioClient();
    }

    /** * Create java-based MinioClient */
    public void createMinioClient(a) {
        try {
            if (null == minioClient) {
                log.info(Start creating MinioClient...);
                minioClient = MinioClient
                                .builder()
                                .endpoint(endpoint)
                                .credentials(accessKey, secretKey)
                                .build();
                createBucket(bucketName);
                log.info("MinioClient created..."); }}catch (Exception e) {
			log.error("[Minio tool class]>>>> Minio server exception:", e); }}/** * Get the upload file prefix path *@return* /
    public static String getBasisUrl(a) {
        return endpoint + SEPARATOR + bucketName + SEPARATOR;
    }

    /****************************** Operate Bucket Start ******************************/

    /** * Initializes the Bucket when the SpringBoot container is started@throws Exception
     */
    private static void createBucket(String bucketName) throws Exception {
        if (!bucketExists(bucketName)) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /** * Check whether the Bucket exists. True: yes, false: no *@return
     * @throws Exception
     */
    public static boolean bucketExists(String bucketName) throws Exception {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }


    /** * Get the Bucket policy *@param bucketName
     * @return
     * @throws Exception
     */
    public static String getBucketPolicy(String bucketName) throws Exception {
		return minioClient
								.getBucketPolicy(
										GetBucketPolicyArgs
												.builder()
												.bucket(bucketName)
												.build()
								);
    }


    /** * Get all Bucket lists *@return
     * @throws Exception
     */
    public static List<Bucket> getAllBuckets(a) throws Exception {
        return minioClient.listBuckets();
    }

    /** * Get bucketName information *@param bucketName
     * @return
     * @throws Exception
     */
    public static Optional<Bucket> getBucket(String bucketName) throws Exception {
        return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    }

    /** * If bucketName is bucketName, the Bucket is deleted successfully. False: Delete failed, or the file does not exist *@param bucketName
     * @throws Exception
     */
    public static void removeBucket(String bucketName) throws Exception {
        minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /****************************** Operate Bucket End ******************************/


    /****************************** Operate Files Start ******************************/

    /** * Check whether the file exists *@paramBucketName Bucket *@paramObjectName File name *@return* /
    public static boolean isObjectExist(String bucketName, String objectName) {
        boolean exist = true;
        try {
            minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (Exception e) {
			log.error("[Minio utility class]>>>> Check whether the file exists, exception:", e);
            exist = false;
        }
        return exist;
    }

    /** * Check whether the folder exists *@paramBucketName Bucket *@paramObjectName Folder name *@return* /
    public static boolean isFolderExist(String bucketName, String objectName) {
        boolean exist = false;
        try {
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
            for (Result<Item> result : results) {
                Item item = result.get();
                if (item.isDir() && objectName.equals(item.objectName())) {
                    exist = true; }}}catch (Exception e) {
        	log.error("[Minio tool class]>>>> Check whether the folder exists, abnormal:", e);
            exist = false;
        }
        return exist;
    }

    /** * query file * from file@paramBucketName Bucket *@paramThe prefix prefix *@paramRecursive whether to use recursive queries *@returnMinioItem list *@throws Exception
     */
    public static List<Item> getAllObjectsByPrefix(String bucketName,
                                                   String prefix,
                                                   boolean recursive) throws Exception {
        List<Item> list = new ArrayList<>();
        Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
        if(objectsIterator ! =null) {
            for(Result<Item> o : objectsIterator) { Item item = o.get(); list.add(item); }}return list;
    }

    /** * get file stream *@paramBucketName Bucket *@paramObjectName File name *@returnBinary stream */
    public static InputStream getObject(String bucketName, String objectName) throws Exception {
        return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    /** * download *@paramBucketName Bucket *@paramObjectName File name *@paramOffset Specifies the start byte position *@paramLength Indicates the length to be read *@returnBinary stream */
    public InputStream getObject(String bucketName, String objectName, long offset, long length)throws Exception {
        return minioClient.getObject(
                GetObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .offset(offset)
                        .length(length)
                        .build());
    }

    /** * Get the file list in the path *@paramBucketName Bucket *@paramPrefix File name *@paramRecursive whether to search recursively, false: emulates folder structure search *@returnBinary stream */
    public static Iterable<Result<Item>> listObjects(String bucketName, String prefix,
                                                     boolean recursive) {
        return minioClient.listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(prefix)
                        .recursive(recursive)
                        .build());
    }

    /** * Upload files using MultipartFile *@paramBucketName Bucket *@paramFile File name *@paramObjectName objectName *@paramContentType type *@return
     * @throws Exception
     */
    public static ObjectWriteResponse uploadFile(String bucketName, MultipartFile file, String objectName, String contentType) throws Exception {
        InputStream inputStream = file.getInputStream();
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .contentType(contentType)
                        .stream(inputStream, inputStream.available(), -1)
                        .build());
    }

    /** * Upload local file *@paramBucketName Bucket *@paramObjectName objectName *@paramFileName Local file path */
    public static ObjectWriteResponse uploadFile(String bucketName, String objectName, String fileName) throws Exception {
        return minioClient.uploadObject(
                UploadObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .filename(fileName)
                        .build());
    }

    /** * Upload files through stream **@paramBucketName Bucket *@paramObjectName File object *@paramInputStream File stream */
    public static ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) throws Exception {
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(inputStream, inputStream.available(), -1)
                        .build());
    }

    /** * Create a folder or directory *@paramBucketName Bucket *@paramObjectName Directory path */
    public static ObjectWriteResponse createDir(String bucketName, String objectName) throws Exception {
        return minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(new ByteArrayInputStream(new byte[] {}),0, -1)
                        .build());
    }

    /** * get file information. If an exception is thrown, the file does not exist@paramBucketName Bucket *@paramObjectName File name */
    public static String getFileStatusInfo(String bucketName, String objectName) throws Exception {
        return minioClient.statObject(
                StatObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build()).toString();
    }

    /** * Copy the file **@paramBucketName Bucket *@paramObjectName File name *@paramSrcBucketName Target bucket *@paramSrcObjectName Indicates the destination file name */
    public static ObjectWriteResponse copyFile(String bucketName, String objectName, String srcBucketName, String srcObjectName) throws Exception {
        return minioClient.copyObject(
                CopyObjectArgs.builder()
                        .source(CopySource.builder().bucket(bucketName).object(objectName).build())
                        .bucket(srcBucketName)
                        .object(srcObjectName)
                        .build());
    }

    /** * delete file *@paramBucketName Bucket *@paramObjectName File name */
    public static void removeFile(String bucketName, String objectName) throws Exception {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .build());
    }

    /** * Delete files in batches *@paramBucketName Bucket *@paramKeys List of files to delete *@return* /
    public static void removeFiles(String bucketName, List<String> keys) {
        List<DeleteObject> objects = new LinkedList<>();
        keys.forEach(s -> {
            objects.add(new DeleteObject(s));
            try {
                removeFile(bucketName, s);
            } catch (Exception e) {
				log.error("[Minio tool class]>>>> Failed to delete files in batches:", e); }}); }/** * get file external chain *@paramBucketName Bucket *@paramObjectName File name *@paramExpires time <=7 seconds (external chain validity time (unit: second)) *@return url
     * @throws Exception
     */
    public static String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();
        return minioClient.getPresignedObjectUrl(args);
    }

    /** * get file external chain *@param bucketName
     * @param objectName
     * @return url
     * @throws Exception
     */
    public static String getPresignedObjectUrl(String bucketName, String objectName) throws Exception {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                                                                    .bucket(bucketName)
                                                                    .object(objectName)
                                                                    .method(Method.GET).build();
        return minioClient.getPresignedObjectUrl(args);
    }

    /** * convert URLDecoder to UTF8 *@param str
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
        String url = str.replaceAll("% (? ! [0-9a-fA-F]{2})"."% 25");
        return URLDecoder.decode(url, "UTF-8");
    }

    /****************************** Operate Files End ******************************/


}
Copy the code




conclusion

This is So Easy to integrate. Kaka, where required by MinioUtils. XXX () method call can, for example I used in the project company is MinioUtils. GetPresignedObjectUrl () the method of access to files outside chain, Most of the time, you do not need to modify or delete the file itself. Normally, you only need to upload and query the file. In terms of design, many product teachers will also avoid this risk. In addition, the endpoint, bucketName, accessKey, ecretKey and other parameters passed in the tool class can be obtained in the background of miniO. If not, you can also set them by yourself.




What also don’t say, pure hand dozen, see in this hard share, everybody see officer point praise to a concern ok? Unfortunately, there is no triple link… (= _ =!