诺依文件上传支持阿里云oss

news2024/10/1 23:46:15

文章目录

  • 描述
  • 后端
    • 引入依赖
    • application.yml 添加访问oss需要的参数
    • 编写oss工具类
    • 编写controller
  • 前端
    • 更改调用接口![在这里插入图片描述](https://img-blog.csdnimg.cn/efc28eb8244e4da482d46327ab29a999.png)
    • 去掉baseUrl
    • 回调成功后url改成真实url
    • main.js中挂在该组件
    • 具体调用代码
    • OssImageUpload具体代码

描述

后端的实现相对简单,网上一大堆参考案例。前端主要是拿ImageUpload改造一下。

后端

后端的实现相对简单,网上一大堆参考案例

引入依赖

<dependency>
     <groupId>com.aliyun.oss</groupId>
     <artifactId>aliyun-sdk-oss</artifactId>
     <version>3.15.2</version>
 </dependency>

application.yml 添加访问oss需要的参数

#操作oss需要的一些参数
aliyun:
  accessKeyId: 你的accessKeyId       # 阿里云的accessKeyId
  secretAccessKey: 你的accessKey密码   # accessKey 密码
  oss:
    endPoint: 你的endpoint     # Endpoint:在阿里云oss控制台查看自己使用的endpoint
    bucketName: 你的bucketName   # bucket 名称

编写oss工具类

@Component
public class OssUtils {

    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;

    @Value("${aliyun.secretAccessKey}")
    private String secretAccessKey;

    @Value("${aliyun.oss.endPoint}")
    private String endPoint;

    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    public String uploadOneFile(MultipartFile file) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, secretAccessKey);
        //设置文件名
        String fileName = new DateTime().toString("yyyy/MM/dd")
                + UUID.randomUUID().toString().replace("-", "")
                + file.getOriginalFilename();

        try {
            // 创建PutObject请求。
            ossClient.putObject(bucketName, fileName, file.getInputStream());

            String url = "http://" + bucketName + "." + endPoint + "/" + fileName;
            return url;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    public List<String> uploadArrayFile(MultipartFile[] files) {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, secretAccessKey);
        List<String> list = new ArrayList<>();

        try {
            //设置文件名
            for (MultipartFile file : files) {
                String fileName = new DateTime().toString("yyyy/MM/dd")
                        + UUID.randomUUID().toString().replace("-", "")
                        + file.getOriginalFilename();
                // 创建PutObject请求。
                ossClient.putObject(bucketName, fileName, file.getInputStream());

                String url = "http://" + bucketName + "." + endPoint + "/" + fileName;
//                System.out.println(url);
                list.add(url);
            }

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return list;

    }

    public boolean deleteFile(String fileUrl) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, secretAccessKey);
        /** oss删除文件是根据文件完成路径删除的,但文件完整路径中不能包含Bucket名称。
         * 比如文件路径为:http://edu-czf.oss-cn-guangzhou.aliyuncs.com/2022/08/abc.jpg",
         * 则完整路径就是:2022/08/abc.jpg
         */
        int begin = ("http://" + bucketName + "." + endPoint + "/").length(); //找到文件路径的开始下标
        String deleteUrl = fileUrl.substring(begin);

        try {
            // 删除文件请求
            ossClient.deleteObject(bucketName, deleteUrl);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

}

编写controller

@RestController
@Api(tags = "OSS对象存储Controller")
@RequestMapping("/oss")
public class OssController {
    @Autowired
    OssUtils ossUtils;

    @PostMapping("upload")
    public AjaxResult uploadFile(MultipartFile file) {
        //返回上传oss的url
        String url = ossUtils.uploadOneFile(file);
        AjaxResult ajax = AjaxResult.success();
        ajax.put("fileName", file.getOriginalFilename());
        ajax.put("url", url);
        return ajax;
    }

    @PostMapping("uploadArrayFile")
    public List<String> uploadArrayFile(MultipartFile[] files) {
        //返回上传oss的url
        return ossUtils.uploadArrayFile(files);
    }

    @PostMapping("deleteFile")
    public boolean deleteFile(@RequestBody String fileUrl) {
        //返回是否删除成功
        return ossUtils.deleteFile(fileUrl);
    }
}

前端

前端主要是拿ImageUpload改造一下,具体改造点如下:

更改调用接口在这里插入图片描述

去掉baseUrl

在这里插入图片描述

回调成功后url改成真实url

在这里插入图片描述

main.js中挂在该组件

import OssImageUpload from "@/components/OssImageUpload"
Vue.component('OssImageUpload', OssImageUpload)

具体调用代码

<oss-image-upload v-model="form.logo" :limit="1" />

OssImageUpload具体代码

<template>
  <div class="component-upload-image">
    <el-upload
      multiple
      :action="uploadImgUrl"
      list-type="picture-card"
      :on-success="handleUploadSuccess"
      :before-upload="handleBeforeUpload"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      name="file"
      :on-remove="handleRemove"
      :show-file-list="true"
      :headers="headers"
      :file-list="fileList"
      :on-preview="handlePictureCardPreview"
      :class="{hide: this.fileList.length >= this.limit}"
    >
      <i class="el-icon-plus"></i>
    </el-upload>
    
    <!-- 上传提示 -->
    <div class="el-upload__tip" slot="tip" v-if="showTip">
      请上传
      <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
      <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
      的文件
    </div>

    <el-dialog
      :visible.sync="dialogVisible"
      title="预览"
      width="800"
      append-to-body
    >
      <img
        :src="dialogImageUrl"
        style="display: block; max-width: 100%; margin: 0 auto"
      />
    </el-dialog>
  </div>
</template>

<script>
import { getToken } from "@/utils/auth";

export default {
  props: {
    value: [String, Object, Array],
    // 图片数量限制
    limit: {
      type: Number,
      default: 5,
    },
    // 大小限制(MB)
    fileSize: {
       type: Number,
      default: 5,
    },
    // 文件类型, 例如['png', 'jpg', 'jpeg']
    fileType: {
      type: Array,
      default: () => ["png", "jpg", "jpeg"],
    },
    // 是否显示提示
    isShowTip: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      number: 0,
      uploadList: [],
      dialogImageUrl: "",
      dialogVisible: false,
      hideUpload: false,
      baseUrl: process.env.VUE_APP_BASE_API,
      uploadImgUrl: process.env.VUE_APP_BASE_API + "/oss/upload", // 上传的图片服务器地址
      headers: {
        Authorization: "Bearer " + getToken(),
      },
      fileList: []
    };
  },
  watch: {
    value: {
      handler(val) {
        if (val) {
          // 首先将值转为数组
          const list = Array.isArray(val) ? val : this.value.split(',');
          // 然后将数组转为对象数组
          this.fileList = list.map(item => {
            if (typeof item === "string") {
              item = { name: item, url: item };
            }
            return item;
          });
        } else {
          this.fileList = [];
          return [];
        }
      },
      deep: true,
      immediate: true
    }
  },
  computed: {
    // 是否显示提示
    showTip() {
      return this.isShowTip && (this.fileType || this.fileSize);
    },
  },
  methods: {
    // 删除图片
    handleRemove(file, fileList) {
      const findex = this.fileList.map(f => f.name).indexOf(file.name);
      if(findex > -1) {
        this.fileList.splice(findex, 1);
        this.$emit("input", this.listToString(this.fileList));
      }
    },
    // 上传成功回调
    handleUploadSuccess(res) {
      this.uploadList.push({ name: res.fileName, url: res.url });
      if (this.uploadList.length === this.number) {
        this.fileList = this.fileList.concat(this.uploadList);
        this.uploadList = [];
        this.number = 0;
        this.$emit("input", this.listToString(this.fileList));
        this.$modal.closeLoading();
      }
    },
    // 上传前loading加载
    handleBeforeUpload(file) {
      let isImg = false;
      if (this.fileType.length) {
        let fileExtension = "";
        if (file.name.lastIndexOf(".") > -1) {
          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
        }
        isImg = this.fileType.some(type => {
          if (file.type.indexOf(type) > -1) return true;
          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
          return false;
        });
      } else {
        isImg = file.type.indexOf("image") > -1;
      }

      if (!isImg) {
        this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`);
        return false;
      }
      if (this.fileSize) {
        const isLt = file.size / 1024 / 1024 < this.fileSize;
        if (!isLt) {
          this.$modal.msgError(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
          return false;
        }
      }
      this.$modal.loading("正在上传图片,请稍候...");
      this.number++;
    },
    // 文件个数超出
    handleExceed() {
      this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
    },
    // 上传失败
    handleUploadError() {
      this.$modal.msgError("上传图片失败,请重试");
      this.$modal.closeLoading();
    },
    // 预览
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    },
    // 对象转成指定字符串分隔
    listToString(list, separator) {
      let strs = "";
      separator = separator || ",";
      for (let i in list) {
        strs += list[i].url.replace(this.baseUrl, "") + separator;
      }
      return strs != '' ? strs.substr(0, strs.length - 1) : '';
    }
  }
};
</script>
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
::v-deep.hide .el-upload--picture-card {
    display: none;
}
// 去掉动画效果
::v-deep .el-list-enter-active,
::v-deep .el-list-leave-active {
    transition: all 0s;
}

::v-deep .el-list-enter, .el-list-leave-active {
    opacity: 0;
    transform: translateY(0);
}
</style>


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/128060.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为手表开发:GT3(1)配置调试设备

华为手表开发&#xff1a;GT3&#xff08;1&#xff09;配置调试设备初环境与设备获取手表UUID登录 AppGallery Connect 点击用户与访问初 希望能写一些简单的教程和案例分享给需要的人 环境与设备 系统&#xff1a;window 设备&#xff1a;HUAWEI WATCH 3 Pro 开发工具&…

自动化测试到底该怎么学?

从功能测试到自动化测试 &#xff0c;待遇翻倍&#xff0c;我整理的超全学习指南&#xff01; 首选你需要拥有一个全网最牛最全面的软件测试全职业生涯进阶从零基础到测试开发学习路线图。 其次跟着大纲的内容慢慢学习&#xff0c;当然配套的【教学视频配套的学习资料】肯定是…

代码随想录二刷day4 24.两两交换链表中的结点 19.删除链表的倒数第n个结点 链表相交(环形链表)

二刷复习 文章目录二刷复习24.两两交换链表中的结点19.删除链表的倒数第n个结点链表相交环形链表224.两两交换链表中的结点 思路还是挺简单的&#xff0c;在纸上画一个图就行了 思考的过程&#xff1a; 1.我会思考需要用一个指针curr还是两个指针prev和curr&#xff0c;思考的…

利用 Nacos 实现了一个动态化线程池,非常实用

在后台开发中&#xff0c;会经常用到线程池技术&#xff0c;对于线程池核心参数的配置很大程度上依靠经验。然而&#xff0c;由于系统运行过程中存在的不确定性&#xff0c;我们很难一劳永逸地规划一个合理的线程池参数。在对线程池配置参数进行调整时&#xff0c;一般需要对服…

SegeX Automation:VC调用Golden Surfer自动化失败(VC调用Automation失败)原因详解

----哆啦刘小洋 原创&#xff0c;转载需说明出处 2022-12-29 SegeX Automation:Surfer自动化&#xff08;Automation&#xff09;失败原因1 简介2 初始化Surfer对象不成功2.1 一般代码2.1 改进代码3 Windows系统原因4 Surfer原因5 其他问题1 简介 在工程领域&#xff0c;Golde…

国产无线耳机什么牌子好?国产真无线蓝牙耳机排行

随着近几年蓝牙耳机市场的快速发展&#xff0c;蓝牙耳机依旧占据着半个行业的份额&#xff0c;在人们的日常生活中出现的频率也越来越高。叫得上名的国产蓝牙耳机牌子也越来越多&#xff0c;那么&#xff0c;国产无线耳机什么牌子好&#xff1f;下面&#xff0c;我来给大家推荐…

无代码资讯 | Gartner 预测明年低代码市场规模;微软推出低代码学习平台;AWS 推出开发无服务器应用的低代码平台

栏目导读&#xff1a;无代码资讯栏目从全球视角出发&#xff0c;带您了解无代码相关最新资讯。 TOP3 大事件 1、Gartner 预测到 2023 年&#xff0c;全球低代码市场预计达到269亿美元 根据 Gartner 的最新预测&#xff0c;到 2023 年全球低代码开发技术市场规模预计将达到 269…

hnu计网实验三-应用层和传输层协议分析(PacketTracer)

前言&#xff1a;难度适中的一个实验 一、实验目的 通过本实验&#xff0c;熟悉PacketTracer的使用&#xff0c;学习在PacketTracer中仿真分析应用层和传输层协议&#xff0c;进一步加深对协议工作过程的理解。 二、实验内容 研究应用层和传输层协议 从 PC 使用 URL 捕获 W…

多道程序与分时多任务--rCore[3]

概念 协作式操作系统 计算机硬件在快速发展&#xff0c;内存容量在逐渐增大&#xff0c;处理器的速度也在增加&#xff0c;外设 I/O 性能方面的进展不大。于是就想到&#xff0c;让应用在执行 I/O 操作或空闲时&#xff0c;可以主动 释放处理器 &#xff0c;让其他应用继续执行…

Linux- 系统随你玩之--grep查找文件内容

1、前言 我们在使用过程中经常需要对当前获取的文件进行过滤、提取和分析&#xff0c;以便快速查找到含有指定内容的文件或指定信息的那些行。本章我们继续深入了解有关文本检索的内容。 2、grep 查找文件内容 Linux系统中grep命令是一种强大的文本搜索工具&#xff0c;它能…

使用Loki收集网络设备日志

新钛云服已累计为您分享716篇技术干货前言Loki是Grafana Labs团队的开源项目&#xff0c;是一个水平可扩展&#xff0c;高可用性&#xff0c;多租户的日志聚合系统&#xff0c;它的设计非常简洁易于操作。受Prometheus启发的&#xff0c;可以水平扩展、高可用以及支持多租户的日…

S-HUB如何实现数据库对接WEBSERVICE API

近几年SAAS被大家逐步认可&#xff0c;越来越多的企业购买SAAS服务&#xff0c;但是仍然有很多自建各种业务系统&#xff0c;这些系统建设时一般都只考虑自身业务&#xff0c;而不是特别注重与别的系统之间的互联互通。而企业为了提升效率&#xff0c;又需要将这些业务与别的系…

Java开发 - 双向链表不可怕

前言 说起链表&#xff0c;那还是当初上学的时候学习的&#xff0c;印象里就觉得像锁链一样一环扣一环&#xff0c;后来工作后就几乎没实际接触过链表&#xff0c;每当遇到链表&#xff0c;总是不知道该怎么讲&#xff0c;因为对链表的本质一无所知。也是在学习了Java后&#…

剑指offer----C语言版----第三天

目录 1. 替换空格 1.1 题目描述 1.2 题目背景 1.3 必要的思考 1.4 思路一 1.5 思路二 1.6 思路三&#xff08;学方法&#xff09; 1.7 小试牛刀 1. 替换空格 原题链接&#xff1a;剑指 Offer 05. 替换空格 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/p…

回首2022,展望2023(年度总结)

回首2022&#xff0c;展望2023 热爱技术的伙计们&#xff1a; 哈喽&#xff0c;这篇文章经过一周左右的写写改改&#xff0c;在2022最后的工作日与大家见面&#xff0c;有人说总结是为了更好的开始。是的&#xff0c;一年的时间真的很快&#xff0c;马上就是2023了&#xff0…

k-mean聚类的python实现

文章目录介绍KMeans()函数介绍实例导入相关包整理数据手肘法确定分类个数创建模型绘制结果分为3类的结果作者&#xff1a;张双双介绍 sklearn.cluster模块提供了常用的非监督聚类算法。 该模块中每一个聚类算法都有两个变体: 一个是类(class)另一个是函数(function)。 类实现了…

day06 Debug基础练习

1.Debug模式 1.1 什么是Debug模式 是供程序员使用的程序调试工具&#xff0c;它可以用于查看程序的执行流程&#xff0c;也可以用于追踪程序执行过程来调试程序。 1.2 Debug介绍与操作流程 如何加断点 选择要设置断点的代码行&#xff0c;在行号的区域后面单击鼠标左键即可 …

刷题记录:牛客NC24858Job Hunt [最长路+两种不同判环详解]

传送门:牛客 题目描述: 奶牛们正在找工作。农场主约翰知道后&#xff0c;鼓励奶牛们四处碰碰运气。而且他还加了一条要求&#xff1a;一头牛在一个城市 最多只能赚D&#xff08;1≤D≤1000&#xff09;美元&#xff0c;然后它必须到另一座城市工作。当然&#xff0c;它可以在…

2自由度陀螺仪滑模控制和PID控制跟踪目标轨迹

目录 前言 1.陀螺仪模型 2.滑模跟踪控制 3.PID控制 4.总结 前言 不为别的&#xff0c;这篇小文章只为内涵某人&#xff0c;问候一下他&#xff1a;不是有手就行&#xff0c;哈哈~ 1.陀螺仪模型 2.滑模跟踪控制 对于2自由度陀螺仪有两个方向x、y跟踪&#xff0c;所以需要…

对于软件测试认识的几大误区,看看你有没有?

对于软件开发来说&#xff0c;软件测试可能还不被大众了解&#xff0c;很多开发人员&#xff0c;包括很多软件高层管理人员&#xff0c;由于缺乏软件测试的知识和实践经验&#xff0c;对软件测试的认识还有很多的误区&#xff1a; 误区一&#xff1a;如果软件发布后有质量问题…