图片服务搭建

发布时间 2024-01-02 17:33:41作者: 青喺半掩眉砂

【图片服务配置方法总结】---2024-01-02 16:21:33 星期二
一、使用各大云平台对象存储服务:阿里云oss、腾讯云cos、华为云obs等
二、使用nginx搭建图片服务器
三、使用minio中间件搭建图片服务器(docker搭建,特别快)后端配置下相关依赖包以及代码,即可使用,配置以后还可以作为typora的图床使用
四、使用代码搭建图片服务

一、使用各大云平台对象存储服务:阿里云oss、腾讯云cos、华为云obs等

1.这里暂时不写内容,感兴趣的自行百度

二、使用nginx搭建图片服务器

后续用到再编辑~

三、使用minio中间件搭建图片服务器

使用minio中间件搭建图片服务器(docker搭建,特别快)后端配置下相关依赖包以及代码,即可使用,配置以后还可以作为typora的图床使用

1.minio介绍

MinIO是一个开源的对象存储服务器,设计用于实现高性能、可扩展的云存储。它兼容Amazon S3云存储服务的API,因此可以与现有的S3兼容应用程序进行集成。
MinIO可以部署在本地服务器、私有云环境或公共云上,如AWS、Azure、Google Cloud等。它通过将数据分散在多个独立节点上实现高可用性和容错性,同时提供强大的分布式对象存储能力。
使用MinIO,你可以通过简单的RESTful API/API对象将数据上传、存储和检索到MinIO服务器。MinIO还提供了许多功能,如数据加密、存储桶生命周期管理、事件通知、访问控制等,以满足各种存储需求。
由于MinIO的可扩展性和高性能,它被广泛用于构建各种应用程序,如数据湖、备份和恢复、文档存储、图像和视频存储等。它还是云原生生态系统中的一部分,可以与Kubernetes、Docker等常用工具无缝集成。
总而言之,MinIO是一个快速、可扩展和开源的对象存储服务器,为开发人员和组织提供了灵活、可靠的数据存储解决方案


2.环境说明

1.系统:linux系统(centos7.x)
2.搭建方式:docker(快速、方便)
3.中间件:minio

3.安装docker版minio

3.1.拉取镜像

sudo docker pull minio/minio

image
image

3.2.创建映射文件

mkdir -p /docker/app/minio/data
mkdir -p /docker/app/minio/config

3.服务器开放端口

=在你使用的服务器上,把需要的端口进行开放,一般是在安全组中添加端口

3.4.启动

docker run -p 9000:9000 -p 9090:9090 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=minioadmin"  -e "MINIO_SECRET_KEY=minioadmin" -v /docker/app/minio/data:/data -v /docker/app/minio/config:/root/.minio minio/minio server /data --console-address ":9090" -address ":9000"

参数说明:

这个命令是用来在 Docker 中运行 MinIO 容器的。下面是各个参数的说明:
● -p 9000:9000 -p 9090:9090 :将容器的 9000 端口映射到主机的 9000 端口,将容器的 9090 端口映射到主机的 9090 端口。
● --name minio:给容器取一个名称为 “minio”。
● -d:以后台模式运行容器。
● --restart=always:当容器退出时,总是重启容器。
● -e "MINIO_ACCESS_KEY=minioadmin" -e "MINIO_SECRET_KEY=minioadmin":设置环境变量,指定 MinIO 的访问密钥和密钥。
● -v /docker/app/minio/data:/data:将主机上 /docker/app/minio/data 目录挂载到容器的 /data 目录,用于持久化存储 MinIO 数据。
● -v /docker/app/minio/config:/root/.minio:将主机上 /docker/app/minio/config 目录挂载到容器的 /root/.minio 目录,用于持久化存储 MinIO 配置文件。
● minio/minio:使用 MinIO 官方提供的镜像。
● server /data:运行容器时执行的命令,启动 MinIO 服务器并指定数据目录为 /data。
● --console-address ":9090":设置 MinIO 控制台的地址为 :9090,即容器的 9090 端口。
● -address ":9000":设置 MinIO 服务器的监听地址为 :9000,即容器的 9000 端口。

PS:这个命令会创建一个名为 “minio” 的容器,该容器运行 MinIO 对象存储服务器,并将数据存储在本地的指定目录中。你可以使用 http://localhost:9000 访问 MinIO 服务器,并使用指定的访问密钥和密钥进行身份验证、使用代码上传文件、typora搭建图床、使用该端口
另外,你也可以使用 http://localhost:9090 访问 MinIO 控制台进行管理操作。

3.5.验证

如图:
image

输入用户名、密码进行登录

image

3.6.创建用户并设置密钥

image

操作如图:

image

3.7.创建桶

image

操作如图:

image

3.8.创建好桶后:点击设置

image

设置桶的规则:读+写规则

image
image

3.9.设置公共桶:

image
image

4.minio 配置并启动完成!

5.springboot配置minio服务

5.1.所需maven依赖:

 <!--图片服务minio-->
        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>8.3.5</version>
        </dependency>
        <!--OK Http-->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.9.1</version>
        </dependency>

5.2.application.yml配置文件,配置minio相关信息

#minio图片服务测试
minio:
  endpoint: http://【填写ip】:9000
  accesskey: minioadmin             #用户名
  secretKey: minioadmin             #密码
  bucketName: xiaoguo               #桶名称

5.3.MinioConfig 核心配置类

package com.pasture.pastureService.modules.third.minio;

import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Classname minioconfig
 * @Description:
 * @Date: 2024-01-02 15:55
 * @AUTHOR: 无泪之城
 * @Version 1.0
 */
@Configuration
@EnableConfigurationProperties(MinioProp.class)
public class minioConfig {
    private MinioProp minioProp;

    @Autowired
    public void setMinioProp(MinioProp minioProp) {
        this.minioProp = minioProp;
    }

    @Bean
    public MinioClient minioClient(){
        MinioClient minioClient = MinioClient.builder().endpoint(minioProp.getEndpoint()).
                credentials(minioProp.getAccesskey(), minioProp.getSecretKey()).region("china").build();
        return minioClient;
    }
}

5.4.配置创建实体类

package com.pasture.pastureService.modules.third.minio;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @Classname MinioProp
 * @Description:
 * @Date: 2024-01-02 15:54
 * @AUTHOR: 无泪之城
 * @Version 1.0
 */
@Data
@Component
@ConfigurationProperties(prefix = "minio")
public class MinioProp {

    /**
     * 连接url
     */
    private String endpoint;
    /**
     * 用户名
     */
    private String accesskey;
    /**
     * 密码
     */
    private String secretKey;

    /**
     * 桶名称
     */
    private String bucketName;
}

5.5.编写minioUtil类

package com.pasture.pastureService.modules.third.minio;

import com.alibaba.fastjson.JSONObject;
import io.minio.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

/**
 * @Classname minioUtil
 * @Description:
 * @Date: 2024-01-02 15:55
 * @AUTHOR: 无泪之城
 * @Version 1.0
 */

@Slf4j
@Component
public class MinioUtil {

    @Autowired
    private MinioClient minioClient;
    @Autowired
    private MinioProp minioProp;

    /**
     * @Author smallhou
     * @Description //TODO 判断桶存在不存在,不存在创建桶
     * @Date 10:49 2022-08-16
     * @Param [bucketName]
     * @return void
     **/
    @SneakyThrows
    public void createBucket(String bucketName) {
        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }

    }

    @SneakyThrows
    public InputStream getObjectInputStream(String objectName, String bucketName){
        GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                .bucket(bucketName)
                .object(objectName)
                .build();
        return minioClient.getObject(getObjectArgs);
    }


    public JSONObject uploadFile(MultipartFile file) throws Exception {
        JSONObject res = new JSONObject();
        res.put("code", 0);
        // 判断上传文件是否为空
        if (null == file || 0 == file.getSize()) {
            res.put("msg", "上传文件不能为空");
            return res;
        }
        InputStream is=null;
        try {
            // 判断存储桶是否存在
            createBucket(minioProp.getBucketName());
            // 文件名
            String originalFilename = file.getOriginalFilename();
            // 新的文件名 = 存储桶名称_时间戳.后缀名
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            String fileName = minioProp.getBucketName() + "_" +format.format(new Date())
                    + new Random().nextInt(1000) + originalFilename.substring(originalFilename.lastIndexOf("."));
            // 开始上传
            is=file.getInputStream();
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(minioProp.getBucketName())
                    .object(fileName)
                    .contentType(file.getContentType())
                    .stream(is, is.available(), -1)
                    .build();
            minioClient.putObject(putObjectArgs);

            res.put("code", 1);
            res.put("msg",  minioProp.getBucketName() + "/" + fileName);
            res.put("bucket", minioProp.getBucketName());
            res.put("fileName", fileName);
            res.put("fileUrl", minioProp.getEndpoint()+"/"+minioProp.getBucketName()+"/"+fileName);
            return res;
        }  catch (Exception e) {
            e.printStackTrace();
            log.error("上传文件失败:{}", e.getMessage());
        }finally {
            is.close();
        }
        res.put("msg", "上传失败");
        return res;
    }

    public void downLoad(String fileName, String realFileName, HttpServletResponse response, HttpServletRequest request) {
        InputStream is=null;
        OutputStream os =null;
        try {
            is=getObjectInputStream(fileName,minioProp.getBucketName());
            if(is!=null){
                byte buf[] = new byte[1024];
                int length = 0;
                String codedfilename = "";
                String agent = request.getHeader("USER-AGENT");
                System.out.println("agent:" + agent);
                if ((null != agent && -1 != agent.indexOf("MSIE")) || (null != agent && -1 != agent.indexOf("Trident"))) {
                    String name = URLEncoder.encode(realFileName, "UTF8");
                    codedfilename = name;
                } else if (null != agent && -1 != agent.indexOf("Mozilla")) {
                    codedfilename = new String(realFileName.getBytes("UTF-8"), "iso-8859-1");
                } else {
                    codedfilename = new String(realFileName.getBytes("UTF-8"), "iso-8859-1");
                }
                response.reset();
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(realFileName.substring(realFileName.lastIndexOf("/") + 1), "UTF-8"));
                response.setContentType("application/octet-stream");
                response.setCharacterEncoding("UTF-8");
                os = response.getOutputStream();
                // 输出文件
                while ((length = is.read(buf)) > 0) {
                    os.write(buf, 0, length);
                }
                // 关闭输出流
                os.close();

            }else{
                log.error("下载失败");
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("错误:"+e.getMessage());
        }finally {
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void deleteObject(String objectName) {
        try {
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                    .bucket(minioProp.getBucketName())
                    .object(objectName)
                    .build();
            minioClient.removeObject(removeObjectArgs);
        }catch (Exception e){
            log.error("错误:"+e.getMessage());
        }
    }
}

5.6.编写测试接口

 @ApiOperation("【上传文件到minio】-【MINIO服务器】")
    @PostMapping("/uploadFileToMinio")
    public JSONObject uploadFileToMinio(@RequestParam("file") @ApiParam(value = "二进制文件流") MultipartFile file) throws Exception {
        JSONObject jsonObject = minioUtil.uploadFile(file);
        return jsonObject;
    }

如图:

image
image
image

6.搭建typora图床

6.1.下载破解版typora

Typora 永久破解教程 注册码 v1.0.4 激活教程 图文教程 亲测可用(附带下载)

今天分享一个低版本(v1.0.4)的激活教程,以下教程亲测可用,需要使用我提供的Typora安装包,安装低版本的Typora,如果你已经安装了其他版本,建议请先卸载

下载链接:

链接: https://pan.baidu.com/s/1esMBH1fnod2Wltd-BL6fyQ
提取码: 1403

6.2.下载好后,双击执行typora-setup-x64.exe程序,选择为所有用户安装,一直下一步安装即可。

6.3.激活

  • 替换文件

先关闭Typora工具。

打开Typora工具的安装目录,到resources这一层下。将下载的补丁工具app.asar.txt修改下,去掉后缀txt,恢复app.asar,然后复制到resource下,替换掉原来的文件app.asar,也可以将原有的app.asar文件更改后缀名。
image

重启Typora工具

  • 输入序列号
复制一个下面的序列号
DZTX2H-6MCQZT-QL4GCT-5EBWFX
G7LPKN-HP4NLD-FA3BGF-6JDQ5R
3MH4Y8-YJWT37-G5JL9Y-UHNQDJ
85ZPHY-ELQ9FQ-94J3VP-D92YLU
VEZ7NV-USYN3G-8TL2N3-DADUG4

image

之后点击激活,没有问题的话,应该就可以激活成功了。

image

6.4.下载picgo

官网链接--> picgo

6.5.正常安装picgo

安装过程-略

6.6.picgo配置

点击插件设置,如图:

image

搜索minio插件并安装:

image

打开图床设置:

image
image

填写minio服务的相关配置:

image

之后点解确定保存即可

6.7.typora配置picgo

打开typora的偏好设置:

image

设置picgo的安装路径等

6.8.测试使用typora上传图片到minio服务器

如图:

image
image
image

四、使用代码搭建图片服务

后续用到再编辑~