三种方式(oss、本地、minio)图片的上传下载

一、OSS

1、前期准备

1.1 注册阿里云账号,开启对象存储oss功能,创建一个bucket(百度教程多的是,跟着创建一个就行,创建时注意存储类型是标准存储,读写权限是公共读)

有的在创建桶时读写属性是私有,不能设置为公共,先设置为私有,后面再改就可以。

 2、后端准备

2.1引入依赖 
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.10.2</version>
</dependency>
2.2:在application.yml中配置一些必要的属性,并写一个类读取出来(我是这样使用的,将某些特定的数据都写到application.yml文件中,方便更改,当然你也可以直接将他写在类的代码中,只不过找起来可能麻烦点 
bookstore:
  alioss:
    endpoint: xxxxx #外网访问的地域节点
    access-key-id: xxxxxx #访问阿里云api的秘钥
    access-key-secret: xxxxxxx #访问阿里云api的秘钥
    bucket-name: xxxxxxxx #bucket-name
 
//写在application.yml文件中,这些数据在阿里云中可以找到,秘钥在自己的账号主页里创建生成,地域节点和bucket-name都在创建好bucket后查看
2.3 OssUtil是一个用于处理阿里云对象存储服务(Object Storage Service, OSS)的工具类,它利用了Spring框架的一些特性来实现配置属性的注入和初始化
import lombok.Data;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

    @Data
    @Component
    public class OssUtil implements InitializingBean {
        @Value("${aliyun.oss.file.endpoint}")
        private String endpoint;

        @Value("${aliyun.oss.file.keyid}")
        private String keyId;

        @Value("${aliyun.oss.file.keysecret}")
        private String keySecret;

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


        public static String END_POINT;

        public static String ACCESS_KEY_ID;

        public static String ACCESS_KEY_SECRET;

        public static String BUCKET_NAME;


        @Override
        public void afterPropertiesSet() throws Exception {
            END_POINT = endpoint;
            ACCESS_KEY_ID = keyId;
            ACCESS_KEY_SECRET = keySecret;
            BUCKET_NAME = bucketName;
        }

    }

 2.4,创建一个接口

import org.springframework.web.multipart.MultipartFile;

public interface OssService {
    /*
      上传图片到Oss
   */
    String uploadFileAvatar(MultipartFile file);


}
 2.5 OssServiceImpl类是一个服务类,它封装了与阿里云OSS交互的逻辑,其主要作用是处理文件(特别是图片)上传到阿里云对象存储服务(Object Storage Service, OSS)的逻辑。
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.wedu.common.utils.OssUtil;
import com.wedu.modules.dev.service.OssService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;

@Service
public class OssServiceImpl implements OssService {


    @Override
    public String uploadFileAvatar(MultipartFile file) {
        /**
         * 上传图片到oss
         *
         * @param file 文件对象
         * @return
         */
        if (file == null || file.isEmpty()) {
            return "文件为空,请选择文件后再上传。";
        }
        // yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
        String endpoint = OssUtil.END_POINT;
        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        String accessKeyId = OssUtil.ACCESS_KEY_ID;
        String accessKeySecret = OssUtil.ACCESS_KEY_SECRET;
        String bucketName = OssUtil.BUCKET_NAME;

        try {

            // 获取文件名称
            String realName = file.getOriginalFilename();
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            // 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
            InputStream inputStream = file.getInputStream();
            // 依次填写Bucket名称(例如examplebucket)和Object完整路径(例如exampledir/exampleobject.txt)。Object完整路径中不能包含Bucket名称。
            ossClient.putObject(bucketName, realName, inputStream);

            // 关闭OSSClient。
            ossClient.shutdown();


            String url = "https://" + bucketName + "." + endpoint + "/" + realName;
            return url;


        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }


}
 2.6 Spring MVC的控制器方法,它定义了一个处理文件上传的HTTP POST请求的逻辑。
 /**
     * oss上传文件
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public R uploadFile(MultipartFile file) {
        String url = ossService.uploadFileAvatar(file);
        return R.ok().put("url",url);
    }

3、前端代码 

 <el-form-item label="设备图片">
        <!-- action 必选参数,上传的地址  headers设置上传的请求头部  show-file-list	是否显示已上传文件列表
         on-success	文件上传成功时的钩子  before-upload	上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。-->
        <el-upload
          class="avatar-uploader"
          :action= "uploadUrl"
          :headers= "tokenInfo"
          :show-file-list="false"
          :on-success="handleAvatarSuccess"
          :before-upload="beforeAvatarUpload">
          <img v-if="imageUrl" :src="imageUrl" class="avatar">
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
      </el-form-item>


  data () {
      return {
    
          imageUrl:'',
          //oss
          // uploadUrl: this.$http.adornUrl('/dev/fileoss/upload'),
          //本地上传接口
        // uploadUrl: this.$http.adornUrl('/dev/fileoss/uploadLocal'),
          //minio
          uploadUrl: this.$http.adornUrl('/dev/fileoss/minIOUpload'),
          tokenInfo: {
          'token': this.$cookie.get('token')
        },



 //上传成功后的钩子
      handleAvatarSuccess(res, file) {
        //将上传成功后的url
        this.dataForm.image = res.url;
        this.imageUrl = URL.createObjectURL(file.raw);
        
              
      },
      beforeAvatarUpload(file) {
        const isJPG = file.type === 'image/jpeg';
        const isLt2M = file.size / 1024 / 1024 < 2;

        if (!isJPG) {
          this.$message.error('上传头像图片只能是 JPG 格式!');
        }
        if (!isLt2M) {
          this.$message.error('上传头像图片大小不能超过 2MB!');
        }
        return isJPG && isLt2M;
      },

 图片展示

 <el-table-column prop="image" header-align="center" align="center" label="设备图片">
        <template slot-scope="scope">
          <img v-if="scope.row.image"
                 :src=" scope.row.image"
                 style="width: 50px; height: 50px;" 
                 class="avatar">
        </template>
      </el-table-column>

二、Minio

前期的安装准备参考这位博主的MinIO安装与启动【windows】_minio启动-CSDN博客, minio跟oss都是上传图片存储在第三方,前端代码没什么区别,后端代码不同点就是连接的配置不同。

导入依赖

<!-- MinIO -->
		<dependency>
			<groupId>io.minio</groupId>
			<artifactId>minio</artifactId>
			<version>8.2.2</version>
		</dependency>

 没有像oss一样将连接信息写在yml里,直接所以普代码都写在控制层。

 //minIO 文件上传  直接返回图片路径
    @PostMapping("/minIOUpload")
    public R upload(MultipartFile file) throws IOException {
        // 设置 MinIO 连接信息 这里使用API端口 9000 而不是9001
        String endpoint = "http://192.168.255.1:9000";
        String accessKey = "你自己的账户名";
        String secretKey = "密码";
        String bucketName = "桶的名称";
        String bucketUrl = "http://192.168.255.1:9000/" + bucketName; // MinIO bucket URL

        // 获取当前时间戳
        String flag = System.currentTimeMillis() + " ";
        // 获取原始文件名(就是你上传的文件本身的名字)
        String originalFilename = file.getOriginalFilename();
        // 生成新的文件名(时间戳+原始文件名) 避免文件名相同被覆盖
        String fileName = flag + originalFilename;
        // 拼接完整的图片访问路径 URL
        String url = bucketUrl + "/" + fileName;

        try {
            // 创建 MinioClient 实例
            MinioClient minioClient = new MinioClient.Builder()
                    .endpoint(endpoint)
                    .credentials(accessKey, secretKey)
                    .build();

            // 构建文件上传相关信息
            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    //application/octet-stream 告诉浏览器这是一个附件,浏览器会直接进行下载,而不是预览
                    .contentType(("application/octet-stream"))
                    .build();
            // 将文件上传到 MinIO 服务器
            minioClient.putObject(args);

        }catch (Exception e) {
            throw new ServerException("文件上传异常: " + e.getMessage(), e);
        }
        return R.ok().put("url", url);
    }

三、本地

本地代码如下:

 /**
     * 本地上传
     * @param file
     * @return
     */
    @PostMapping("/uploadLocal")
    public R uploadFileLocal(MultipartFile file) {

        //获取当前时间戳
        String flag = System.currentTimeMillis() + " ";
        //获取原始文件名(就是你上传的文件本身的名字)
        String fileName = file.getOriginalFilename();
        try {
            //如果没有file文件夹,在项目根目录创建一个file文件夹
            if (!FileUtil.isDirectory(filePath)) {
                FileUtil.mkdir(filePath);
            }
            //文件存储形式:时间戳+文件名
            String destFileName =filePath + flag + fileName;
           // FileUtil.writeBytes(file.getBytes(), filePath + flag + fileName);
            File destFile = new File(destFileName);
            destFile.getParentFile();
            file.transferTo(destFile);
            Thread.sleep((1L));
        } catch (Exception e) {
            System.err.println(fileName + "--文件上传失败");
        }
        return R.ok().put("url", flag);
    }


    //本地下载
    @GetMapping("/{flag}")
    public void picturePath(@PathVariable String flag, HttpServletResponse response) {
        //用于向客户端写入数据的输出流
        OutputStream os;
        //存储文件名的列表。
        List<String> fileNames = FileUtil.listFileNames(filePath);
        //存储匹配标志的文件名。
        //使用Java 8的Stream API,从fileNames列表中筛选出包含flag的文件名。如果找到匹配项,则使用findAny().orElse("")获取匹配的文件名,否则返回空字符串。
        String picture = fileNames.stream().filter(name -> name.contains(flag)).findAny().orElse("");

        try {
            //如果picture不为空(即找到了匹配的文件名)
            if (StrUtil.isNotEmpty(picture)) {
                response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(picture, "UTF-8"));
                //响应的内容类型为application/octet-stream,确保浏览器不会尝试打开文件
                response.setContentType(("application/octet-stream"));
                //声明了一个字节数组bytes,用于存储文件的二进制内容
                byte[] bytes = FileUtil.readBytes(filePath + picture);
                os = response.getOutputStream();
                //将字节数组写入输出流,发送给客户端
                os.write(bytes);
                os.flush();
                os.close();
            }
        } catch (Exception e) {
            System.out.println("文件下载失败");
        }
    }

注意:前端代码需要改变一下,不然上传的图片是看不了的,回显的方法通过之前的前端代码是不会调用这和方法。需要在前端拼接一下url。这样就能展示了。

<el-table-column prop="image" header-align="center" align="center" label="设备图片">
        <template slot-scope="scope">
          <img v-if="scope.row.image"
                 :src="'http://localhost:8080/wedu/dev/fileoss/'+ scope.row.image"
                 style="width: 50px; height: 50px;" 
                 class="avatar"> 
        </template>
      </el-table-column>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关于Nginx前后端分离部署spring boot和vue工程以及反向代理的配置说明

最近项目中用到关于Nginx前后端分离部署spring boot和vue工程以及反向代理的配置&#xff0c;总结了一下说明&#xff1a; 1、后端是spring boot工程&#xff0c;端口8000&#xff0c;通过 jar命令启动 nohup java -jar xxx-jsonflow-biz.jar > /usr/local/nohup.out 2>…

debian 11 虚拟机环境搭建过坑记录

目录 安装过程系统配置修改 sudoers 文件网络配置换源安装桌面mount nfs 挂载安装复制功能tab 无法补全其他安装 软件配置eclipse 配置git 配置老虚拟机硬盘挂载 参考 原来去 debian 官网下载了一个最新的 debian 12&#xff0c;安装后出现包依赖问题&#xff0c;搞了半天&…

Android:生成Excel表格并保存到本地

提醒 本文实例是使用Kotlin进行开发演示的。 一、技术方案 org.apache.poi:poiorg.apache.poi:poi-ooxml 二、添加依赖 [versions]poi "5.2.3" log4j "2.24.2"[libraries]#https://mvnrepository.com/artifact/org.apache.poi/poi apache-poi { module…

RK3576技术笔记之一 RK3576单板介绍

第二篇嘛&#xff0c;亮亮我们做出来的板子&#xff0c;3576这个片子的基本功能接口单板都做了&#xff0c;接口数量肯定是比不上3588&#xff08;PS&#xff1a;这个我们也在做&#xff0c;后续都完成后会发文章&#xff09;&#xff0c;但是比起3568来说还是升级了&#xff0…

SQL进阶技巧:如何寻找同一批用户 | 断点分组应用【最新面试题】

目录 0 问题描述 1 数据准备 2 问题分析 ​编辑 3 小结 0 问题描述 用户登录时间不超过10分钟的视为同一批用户,找出以下用户哪些属于同一批用户(SQL实现) 例如: user_name time a 2024-10-01 09:55 b 2024-10-01 09:57 c 2024-10-01…

数字图像处理(11):RGB转YUV

&#xff08;1&#xff09;RGB颜色空间 RGB颜色空间&#xff0c;是一种基于红色、绿色、蓝色三种基本颜色进行混合的颜色空间&#xff0c;通过这三种颜色的叠加&#xff0c;可以产生丰富而广泛的颜色。RGB颜色空间在计算机图像处理、显示器显示、摄影和影视制作等领域具有广泛应…

利用Ubuntu批量下载modis图像(New)

由于最近modis原来批量下载的代码不再直接给出&#xff0c;因此&#xff0c;再次梳理如何利用Ubuntu下载modis数据。 之前的下载代码为十分长&#xff0c;现在只给出一部分&#xff0c;需要自己再补充另一部分。之前的为&#xff1a; 感谢郭师兄的指导&#xff08;https://blo…

HTTP 长连接(HTTP Persistent Connection)简介

HTTP长连接怎么看&#xff1f; HTTP 长连接&#xff08;HTTP Persistent Connection&#xff09;简介 HTTP 长连接&#xff08;Persistent Connection&#xff09;是 HTTP/1.1 的一个重要特性&#xff0c;它允许在一个 TCP 连接上发送多个 HTTP 请求和响应&#xff0c;而无需为…

淘宝商品详情主图SKU图价格|品牌监控|电商API接口

淘宝/天猫获得淘宝商品详情 API 返回值说明 item_get-获得淘宝商品详情 taobao.item_get 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&a…

单片机学习笔记 17. 串口通信-发送汉字

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…

五层网络协议(封装和分用)

目录 七层网络协议五层网络协议封装1.应用层2.传输层3.网络层4.数据链路层5.物理层 分用1. 物理层2.数据链路层3.网络层 IP 协议4.传输层 UDP 协议5.应用层 七层网络协议 网络通信过程中&#xff0c;需要涉及到的细节&#xff0c;其实是非常非常多的&#xff0c;如果要有一个协…

阿里云人工智能平台(PAI)免费使用教程

文章目录 注册新建实例交互式建模(DSW)注册 注册阿里云账号进行支付宝验证 新建实例 选择资源信息和环境信息,填写实例名称 资源类型需要选择公共资源,才能使用资源包进行抵扣。目前每月送250计算时。1 * NVIDIA A10 8 vCPU 30 GiB 1 * 24 GiB1 * NVIDIA V100 8 vCPU 32 Gi…

【实战】Oracle基础之控制文件内容的5种查询方法

关于Jady&#xff1a; ★工作经验&#xff1a;近20年IT技术服务经验&#xff0c;熟悉业务又深耕技术&#xff0c;为业务加持左能进行IT技术规划&#xff0c;右能处理综合性故障与疑难杂症&#xff1b; ★成长历程&#xff1a;网络运维、主机/存储运维、程序/数据库开发、大数…

蓝桥杯第 23 场 小白入门赛

一、前言 好久没打蓝桥杯官网上的比赛了&#xff0c;回来感受一下&#xff0c;这难度区分度还是挺大的 二、题目总览 三、具体题目 3.1 1. 三体时间【算法赛】 思路 额...签到题 我的代码 // Problem: 1. 三体时间【算法赛】 // Contest: Lanqiao - 第 23 场 小白入门赛 …

使用 Pytorch 构建 Vanilla GAN

文章目录 一、说明二、什么是 GAN&#xff1f;三、使用 PyTorch 的简单 GAN&#xff08;完整解释的代码示例&#xff09;3.1 配置变量3.2 、PyTorch 加速3.3 构建生成器3.4 构建鉴别器 四、准备数据集五、初始化函数六、前向和后向传递七、执行训练步骤八、结果 一、说明 使用…

【Windows 11专业版】使用问题集合

博文将不断学习补充 I、设置WIN R打开应用默认使用管理员启动 1、WIN R输入 secpol.msc 进入“本地安全策略”。 2、按照如下路径&#xff0c;找到条目&#xff1a; “安全设置”—“本地策略”—“安全选项”—“用户账户控制&#xff1a;以管理员批准模式运行所有管理员” …

合规性要求对漏洞管理策略的影响

讨论漏洞管理中持续面临的挑战&#xff0c;包括确定漏洞的优先级和解决修补延迟问题。 介绍合规性要求以及自动化如何简化漏洞管理流程。 您认为为什么尽管技术不断进步&#xff0c;但优先考虑漏洞和修补延迟等挑战仍然存在&#xff1f; 企业基础设施日益复杂&#xff0c;攻…

IDEA全局设置-解决maven加载过慢的问题

一、IDEA全局设置 注意&#xff1a;如果不是全局设置&#xff0c;仅仅针对某个项目有效&#xff1b;例在利用网上教程解决maven加载过慢的问题时&#xff0c;按步骤设置却得不到解决&#xff0c;原因就是没有在全局设置。 1.如何进行全局设置 a.在项目页面&#xff0c;点击f…

Java - JSR223规范解读_在JVM上实现多语言支持

文章目录 1. 概述2. 核心目标3. 支持的脚本语言4. 主要接口5. 脚本引擎的使用执行JavaScript脚本执行groovy脚本1. Groovy简介2. Groovy脚本示例3. 如何在Java中集成 Groovy4. 集成注意事项 6. 与Java集成7. 常见应用场景8. 优缺点9. 总结 1. 概述 JSR223&#xff08;Java Spe…

oracle数据库的启动与关闭

一.oracle数据库的启动过程 启动实例&#xff08;Start the Instance&#xff09; 启动实例&#xff1a;一个Oracle数据库实例由内存结构和后台进程组成&#xff0c;启动实例时会加载这些内存结构和启动进程。实例是数据库的一个运行时环境&#xff0c;它包含了数据库的控制文…