开发者

SpringBoot整合Minio实现图片上传功能

开发者 https://www.devze.com 2024-08-30 10:24 出处:网络 作者: 蜗牛学苑_武汉
目录minio服务器1、MinIo简介2、安装MinIoa、下载安装b、安装minio3、Springboot整合minio4、案例:用户头像上传文件上传注意事项el-upload上传组件常用属性文件上传组件常用属性axIOS.post提交上传请求Controller控
目录
  • minio服务器
  • 1、MinIo简介
  • 2、安装MinIo
    • a、下载安装
    • b、安装minio
  • 3、Springboot整合minio
    • 4、案例:用户头像上传
      • 文件上传注意事项
      • el-upload上传组件常用属性
      • 文件上传组件常用属性
      • axIOS.post提交上传请求
      • Controller控制器后端处理上传请求
      • 处理上传后的响应结果
    • 5、常见问题

      minio服务器

      minio服务器主要功能:保存文件【可以图片、ppt、xsl】

      1、MinIo简介

      Minio 是个基于 golang 编写的开源对象存储套件,虽然轻量,却拥有着不错的性能。

      • 官网地址:MinIO | High Performance, Kubernetes Native Object Storage

      • 中文官网地址:http://www.minio.org.cn

        中文文档对应的是上个版本,新版本中有些内容已发生了变化,所以最好是看英文文档。

      • 何为对象存储?

        对象存储服务( Object Storage Service,OSS )是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。

      对于中小型企业,如果不选择存储上云,那么 Minio 是个不错的选择,麻雀虽小,五脏俱全。

      2、安装MinIo

      a、下载安装

      Windows 版下载地址:windows-amd64 版按惯例,我们将下载的 minio.exe 放在 C:\ProgramFiles\MinIO 下,因此,MINIO_HOME 就是 C:\ProgramFiles\MinIO

      b、安装minio

      1、下载 MinIO

      安装wget:
      	yum -y install wget   #由于需要用到wget命令,所以要先安装wget
      
      创建minio目录:
          mkdir -p /usr/local/minio
          mkdir -p /usr/local/mwww.devze.cominio/bin
          mkdir -p /usr/local/minio/data
          
      进入/usr/local/minio/bin执行如下命令:
      	wget https://dl.minio.org.cn/server/minio/release/linux-amd64/minio
      	
      赋予它可执行权限: 进入到/usr/local/minio/bin中执行如下命令
      	chmod +x minio
      

      在usr/local下创建minio文件夹,并在minio文件里面创建bin和data目录,把下载好的minio文件拷贝到bin目录里面

      2、将 minio 添加成 Linux 的服务

      cat > /etc/systemd/system/minio.service << EOF
      [Unit]
      Description=Minio
      Wants=network-online.target
      After=network-online.target
      AssertFileIsExecutable=/usr/local/minio/bin/minio
      
      [Service]
      WorkingDirectory=/usr/local/minio/
      PermissionsStartOnly=true
      ExecStataPNxnkrt=/usr/local/minio/bin/minio server /usr/local/minio/data
      ExecReload=/bin/kill -s HUP $MAINPID
      ExecStop=/bin/kill -s QUIT $MAINPID
      PrivateTmp=true
      
      [Install]
      WantedBy=multi-user.target
      EOF
      

      这样就可以使用 systemctl 启停 minio

      systemctl start minio   # 启动
      systemctl stop minio    # 停止
      systemctl enable minio  #设置自动开启
      systemctl status minio # 查看服务运行状态
      

      c、启动运行

      输入用户名/密码 minioadmin/minioadmin 可以进入 web 管理系统:

      d、创建桶

      刚打开的时候,是没有bucket桶,可以手动或者通过Java代码来创建一个桶。

      创建的桶默认的权限时private私有的,外部不能访问,你可以修改桶的属性,点击manage,找到Access Policy,修改权限为public即可。
      

      e、上传文件到桶

      f、关停 MinIO

      通过命令行启动 MioIO 后,命令行窗口就被占用了。关闭命令行窗口即关闭 MioIO ,也可以使用 ctrl + c 关闭

      3、Springboot整合minio

      添加minio整合所需的依赖

      com.squareup.okhttp3
      okhttp
      4.8.1
      
      
      io.minio
      minio
      8.3.9

      设置minio服务器信息

      #minio配置
      minio:
      endpoint: http://127.0.0.1:9000
      accesskey: minioadmin
      secretKey: minioadmin

      创建minion配置类

      /**
      * minio配置类
      */
      @Configuration
      @Data
      @ConfigurationProperties(prefix = “minio”)
      public class MinIoConfig {
      private String endpoint;
      private String accesskey;
      private String secretKey;
          /**
           * 创建MinioClient对象
           * @return
           * @throws Exception
           */
          @Bean
          public MinioClient minioClient() throws Exception {
              return MinioClient.builder().endpoint(endpoint)
                      .credentials(accesskey, secretKey).build();
          }
      }
      

      测试整合结果

      4、案例:用户头像上传

      文件上传是日常项目中非常常规且常用的一个功能。主要的功能就是将客户端的文件保存到服务器,以便于资源的“浏览”。怎么实现文件上传呢?SpringMvc中提供了对应的文件上传解析器,按照给定要求,在SpringMvc的环境下,我们可以很方便的实现上传功能。

      文件上传注意事项

      • form 表单的 enctype 取值必须是:multipart/form-data(默认值是:application/x-www-form-urlencoded)

      • method 属性取值必须是 post

      • 提供一个文件选择域,html5原生html中,利用

      不过,元素file标签,外观单一,企业级应用中更多的会选择使用外观更加丰富的一些“组件”,比如在element-ui的el-upload组件

      el-upload上传组件常用属性

      <el-upload
                 class="avatar-uploader" action="#"
                 :show-file-list="false"
                 :before-upload="beforeAvatarUpload"
                 :http-request="doUploadImage">
          <img v-if="imageUrl" :src="imageUrl" class="avatar">
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>
      </el-upload>
      

      文件上传组件常用属性

      1. action:设置文件上传控制器url地址,属于同步请求提交方式。必备属性
      2. http-request:设置实现上传请求发送的自定义函数名,若要实现自定义上传方式,必须使用http-requeset
      3. :before-upload:处理图片上传过程的钩子,该属性处理图片上传之前的功能。其值设置一个函数,参考上述案例代码:可以判断上传文件的格式和大小

      axios.post提交上传请求

      因为文件上传的格式必须是:multipart/formdata格式,所以axios.post处理文件上传时,参数较以前的使用,略有变化,具体代码参考如下:

      doUpload(file){//file 获取用户选择封面图片
          console.log("file",file.file);
          //将用户选择的图片内容封装为formdata类型,才能交给控制器处理
          let formData=new FormData();
          formData.append("face",file.file);
          axios.post("/user/do-upload",formData,{contentType:'multipart/form-data'})
              .then(resp=>{
              if(resp.data.status===200){
                  alert("文件上传成功"+resp.data.msg);
              }else{
                  alert("文件上传失败");
              }
          });
      

      代码解读

      FormData是javascript提供的一个对象类型,作用封装multipart/form-data格式数据。
      formData对象的append()方法,可以以key:value格式存入数据,控制器在后台以key获取对应的值
      
      contentType:'multipart/form-data'设置axios.post提交数据格式。
      因为axios.post默认提交格式是jsonstring,此处需要手动显式设置数据提交格式:contentType:'multipart/form-data'
      

      Controller控制器后端处理上传请求

      Springmvc处理文件上传请求时,因为请求体提交数据的格式不再是传统的jsonstring或querystring格式,所以,控制器在处理上传请求前,需要先配置文件上传解析器。具体流程如下所示:

      pom.XML导入文件解析器依赖

      commons-fileupload commons-fileupload 1.4 commons-io commons-io 2.10.0

      pplication.yml配置文件上传解析器

      Spring:
      servlet:
      multipart:
      max-file-size: 30MB #单个文件的最大上限
      max-request-size: 60MB #单个请求的文件总大小上限

      Controller处理上传请求

      @PostMapping(“/do-upload”)
      public ResponseResult doUploadImage(
      @RequestParam(value = “aa”,required = true,defaultValue = “”) MultipartFile image
      ) {
      log.info(“用户提交的图书:{}”,image);
      //保存文件到minio服务器即可
      String bucketName=“woniu-mall”;
      //1-1 创建桶
      minIoUtil.createBucket(bucketName);
      //1-2 上传文件
      String oldName = image.getOriginalFilename();
      //文件名称
      String firstName = UUID.randomUUID().toString().replace(“-”, “”);
      //文件后缀名
      String lastName = oldName.substring(oldName.lastIndexOf(“.”));
      //新的文件名称
      String fileName=“goods/”+firstName+ lastName;
      minIoUtil.putObject(bucketName,image,fileName,image.getContentType());
      //1-3 获取外链
      String objectUrl = minIoUtil.getObjectUrl(bucketName, fileName);
      return new ResponseResult(200,“上传成功!”,objectUrl);
      }

      处理上传后的响应结果

      Minio操作工具类

      基于Springmvc整合Minio时,我们在MinioConfig中注入过MinioClient对象,而MinioClient对象就是操作minio服务器的核心对象,该对象提供了在minio服务器上创建桶、上传文件,分享外链给用户使用的功能。为了便于日常的开发使用,我们将这些功能封装成MinioUtil工具类,开发人员结合开发需求,调用对应方法完成需求即可。工具类的具体代码如下所示:

      @Slf4j //日志管理工具
      @Component
      public class MinIoUtil {
          @Autowired
          private MinioClient minioClient;
      
          /**
           * 创建桶
           * @param bucketName 桶名
           */
          public void createBucket(String bucketName) {
              BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
              MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(bucketName).build();
      
              try {
                  if (minioClient.bucketExists(bucketExistsArgs)) {
                      return;
                  }
                  minioClient.makeBucket(makeBucketArgs);
              } catch (Exception e) {
                  //跟sout作用一样,在控制台输出程序执行信息
                  log.error("创建桶失败:", e.getMessage());
                  throw new RuntimeException(e);
              }
          }
      
          /**
           * 通过 MultipartFile ,上传文件
           *
           * @param bucketName 存储桶
           * @param file       文件
           * @param objectName 对象名(文件名)存入桶时,文件新命名:唯一不重复
           * @param contentType   文件类型 文件上传时格式
           */
          public ObjectWriteResponse putObject(String bucketName, MultipartFile file, String objectName, String contentType) {
              try {
                  //调用创建桶方法
                  createBucket(bucketName);
                  //获取文件输入流
                  InputStream inputStreamjavascript = file.getInputStream();
                  PutObjectArgs args = PutObjectArgs.builder()
                          .bucket(bucketName)
                          .object(objectName)
                          .contentType(contentType)
                          .stream(inputStream, inputStream.available(), -1)
                          .build();
                  return minioClient.putObject(args);
              } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                      InvalidResponseException | IOException | NoSuchAlgorithmException |
                      ServerException | XmlParserException e) {
                  throw new RuntimeException(e);
              }
          }
      
          /**
           * 获取⽂件外链
           *
           * @param bucketName bucket名称
           * @param objectName ⽂件名称
           * @param expires    过期时间 <=7
           * @param timeUnit 有效期时间单位
           */
          public String getObjectUrl(String bucketName, String objectName, Integer expires, TimeUnit timeUnit) {
              GetPresignedObhttp://www.devze.comjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                      .method(Method.GET)
                      .bucket(bucketName)
        taPNxnk              .object(objectName)
                      .expiry(expires,timeUnit)// 单位:默认是,秒
                      .build();
              try {
                  String url=minioClient.getPresignedObjectUrl(args);
                  return getImgUrl(url);
              } catch (ErrorResponseException | InsufficientDataException | InternalException |
                      InvalidResponseException | InvalidKeyException | NoSuchAlgorithmException |
                      IOException | XmlParserException | ServerException e) {
                  throw new RuntimeException(e);
              }
          }
      
          /**
           * 获取⽂件外链
           *
           * @param bucketName bucket名称
           * @param objectName ⽂件名称
           */
          public String getObjectUrl(String bucketName, String objectName) {
              GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
                      .method(Method.GET)
                      .bucket(bucketName)
                      .object(objectName)// 单位:默认是,秒
                      .build();
              try {
                  String url=minioClient.getPresignedObjectUrl(args);
                  return getImgUrl(url);
              } catch (ErrorResponseException | InsufficientDataException | InternalException |
                      InvalidResponseException | InvalidKeyException | NoSuchAlgorithmException |
                      IOException | XmlParserException | ServerException e) {
                  throw new RuntimeException(e);
              }
          }
      
          /**
           * 处理图片上传后外链地址
           * 只获得url端口号以后的内容
           * @param urlStr
           * @return
           */
          private String getImgUrl(String urlStr){
              if(urlStr.isEmpty()){
                  return "";
              }
      
              Pattern pattern = Pattern.compile("\\?"); //通过正则找字符串中的?
              Matcher matcher = pattern.matcher(urlStr); //正则表达式比对器
              if (matcher.find()){
                  int seartIndex = matcher.end();  //获得?开始的位置
                  if(seartIndex!=-1){
                      urlStr=urlStr.substring(0,seartIndex-1);
                  }
              }
      
              Pattern pattern1 = Pattern.compile(":\\d{1,5}"); //通过正则找字符串中的端口
              Matcher matcher1 = pattern1.matcher(urlStr); //正则表达式比对器
              if (matcher1.find()){
                  int endIndex = matcher1.end();  //获得正则表达式规则结束字符串的位置
                  if(endIndex!=-1){
                      return  urlStr.substring(endIndex);
                  }
              }
              return "";
          }
      }
      

      5、常见问题

      商品列表:表格图片无法正常显示问题

      用户头像显示问题:element组件中el-table默认循环时,没有给每一行指定key,用于标识数据渲染的位置,所以在使用el-avatar显示图片时,会出现图片url地址正确的情况下,图片无法正常显示问题,

      解决方案有以下两种:

      修改商品信息时:设置图片回显

      在商品信息管理时,我们可能会对商品的封面照片进行修改。那么当我们点击“修改”按钮进入到商品修改页面时,一般情况,需要默认显示商品“旧”图片的信息。el-upload组件如何设置默认显示的图片呢?在修改页面初始化数据时,给el-upload组件的imageUrl赋值即可完成

      以上就是SpringBoot整合Minio实现图片上传功能的详细内容,更多关于SpringBoot Minio图片上传的资料请关注编程客栈(www.devze.com)其它相关文章!

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消