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

一、OSS

1、前期准备

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

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

2、后端准备

2.1引入依赖
java 复制代码
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.10.2</version>
</dependency>
2.2:在application.yml中配置一些必要的属性,并写一个类读取出来(我是这样使用的,将某些特定的数据都写到application.yml文件中,方便更改,当然你也可以直接将他写在类的代码中,只不过找起来可能麻烦点
java 复制代码
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框架的一些特性来实现配置属性的注入和初始化
java 复制代码
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,创建一个接口

java 复制代码
import org.springframework.web.multipart.MultipartFile;

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


}
2.5 OssServiceImpl类是一个服务类,它封装了与阿里云OSS交互的逻辑,其主要作用是处理文件(特别是图片)上传到阿里云对象存储服务(Object Storage Service, OSS)的逻辑。
java 复制代码
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请求的逻辑。
java 复制代码
 /**
     * oss上传文件
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public R uploadFile(MultipartFile file) {
        String url = ossService.uploadFileAvatar(file);
        return R.ok().put("url",url);
    }

3、前端代码

javascript 复制代码
 <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;
      },

图片展示

html 复制代码
 <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都是上传图片存储在第三方,前端代码没什么区别,后端代码不同点就是连接的配置不同。

导入依赖

java 复制代码
<!-- MinIO -->
		<dependency>
			<groupId>io.minio</groupId>
			<artifactId>minio</artifactId>
			<version>8.2.2</version>
		</dependency>

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

java 复制代码
 //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);
    }

三、本地

本地代码如下:

java 复制代码
 /**
     * 本地上传
     * @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。这样就能展示了。

html 复制代码
<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>
相关推荐
一只大侠1 分钟前
计算S=1!+2!+3!+…+N!的值:JAVA
java·开发语言
一只大侠4 分钟前
输入一串字符,以“?”结束。统计其中字母个数,数字个数,其它符号个数。:JAVA
java·开发语言·算法
以后不吃煲仔饭4 分钟前
面试小札:线程池
java·后端·面试
Oneforlove_twoforjob5 分钟前
【Java基础面试题011】什么是Java中的自动装箱和拆箱?
java·开发语言
优雅的落幕21 分钟前
多线程---线程安全(synchronized)
java·开发语言·jvm
Charlie__ZS22 分钟前
帝可得-设备管理
java·maven·intellij-idea·idea
爱上语文28 分钟前
请求响应:常见参数接收及封装(数组集合参数及日期参数)
java·开发语言·spring boot·后端
孙同学_31 分钟前
【Linux篇】权限管理 - 用户与组权限详解
java·linux·服务器
CQU_JIAKE40 分钟前
926[study]Docker,DHCP
java·开发语言
浪 子43 分钟前
SpringBoot mq快速上手
java·spring boot·spring