【springboot+vue】文件上传的本地存储和阿里云OSS对象存储

本地存储

       文件上传时在服务端会产生一个临时文件,请求响应完成之后,这个临时文件被自动删除,并没有进行保存。此时我们就需要完成将上传的文件保存在服务器的本地磁盘上。

前端

<template>
        <el-upload class="avatar-uploader"
                   :show-file-list="false"
                   :action="uploadUrl"
                   :headers="tokenInfo"
                   ref="upload"
                   :on-success="handleAvatarSuccess">
          <img v-if="dataForm.imgUrl"
               :src="dataForm.imgUrl"
               class="avatar">
          <i v-else
             class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
</template>
<script>
export default {
  data () {
    return {
      visible: false,
      file: null,
    }
  }
}
  methods: {
    handleAvatarSuccess (raw,file) {
      this.dataForm.imgUrl = URL.createObjectURL(file.raw)
    }
}
</script>

上传图片后通过URL.createObjectURL()方法生成一个图片URL,并将img标签的src属性指向这个URL

后端

配置类

首先建立配置类继承WebMvcConfigurer并重写addResourceHandlers方法:

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
 
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String filePath = System.getProperty("user.dir") + "/src/main/resources/static/img/";
        System.out.println(filePath);
        registry.addResourceHandler("/static/**")
                .addResourceLocations("file:" + filePath);
        //addResourceHandler()里的是虚拟路径,addResourceLocations()里加的是真实路径
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }
}

addResourceHandler()里的是虚拟路径,addResourceLocations()里加的是真实路径

controller层

    @PostMapping("/upload")
    public R upload(@RequestParam("file") MultipartFile file) throws IOException {
 
        String fileName = file.getOriginalFilename();
        String hToken = UUID.randomUUID().toString();
        String HeadName = hToken + fileName;
        String filePath = System.getProperty("user.dir") + "/src/main/resources/static/img/";
        String fileAddress = filePath + HeadName;  //文件真实路径
        try {
            file.transferTo(new File(fileAddress));
 
        } catch (Exception e) {
        }
        return R.ok().put("url", "http://localhost:8080/static/" + HeadName);
        //文件映射路径
    }

保存文件到静态目录下,并返回该文件映射路径;

前端页面展示

下载图片

export default {
  data () {
    return {
      uploadUrl: this.$http.adornUrl('/tb/img/upload'),
        }
    }
}
methods: {
    handleAvatarSuccess (res, file) {
      this.dataForm.imgUrl = URL.createObjectURL(file.raw)
      this.dataForm.img = res.url
    }
}

这里的imgUrl就是上面返回的url

前端js代码:

methods: {
    download (url, fileName) {
      this.$http({
        url: this.$http.adornUrl('/common/download'),
        method: 'post',
        responseType: 'blob',
        params: {
          'url': url,
          'name': fileName,
 
        }
      }).then(res => {
        console.log(res)
        if (res.data.size > 0) {
          var blob = new Blob([res.data]);
          var href = URL.createObjectURL(blob);
          var downloadElement = document.createElement('a');
          downloadElement.href = href;
          downloadElement.download = fileName + "." + 'JPG'; // 下载后文件名
          document.body.appendChild(downloadElement);
          downloadElement.click(); // 点击下载
          document.body.removeChild(downloadElement); // 下载完成移除元素
          window.URL.revokeObjectURL(href); // 释放掉blob对象
        } else {
          this.$message.error('文件或图片失效请重新上传')
        }
      });
    },

运行效果

阿里云OSS对象存储

       由于本地存储是存储在本地服务器,其他人在无法访问到本地所存储的资源,无法实现资源文件共享。这里我们采用阿里云存储的方式来实现文件上传保存,来实现文件的共享。

       阿里云对象存储OSS(Object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件

准备工作

注册一个阿里云账户,在产品一栏中找到对象存储OSS并开通

在页面右上角找到头像,然后点击AccesKey管理

创建AccesKey,创建时需要保存好AccessKey ID和AccesKey Secret,后面的步骤需要配置访问凭证

返回对象存储OSS页面,点击右侧的Bucket列表,然后创建Bucket

填写Bucket名称,选择地域,读写权限设置为公共读,其它选项默认,完成创建

           接下来配置环境变量,官方文档中有提供使用中断命令行来配置环境变量的方式,这里就不做演示,我们直接打开系统属性进行配置,打开环境变量

新建用户变量

变量名为OSS_ACCESS_KEY_ID,变量值为之前保存的AccessKey ID

同理配置OSS_ACCESS_KEY_SECRET环境变量,变量值为AccesKey Secret

后端

引入依赖

        在Maven工程中使用OSS Java SDK,只需在pom.xml中加入相应依赖即可。以3.15.1版本为例,在<dependencies>中加入如下内容:

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

如果使用的是Java 9及以上的版本,则需要添加jaxb相关依赖。添加jaxb相关依赖示例代码如下:

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.3</version>
</dependency>

测试上传

以下是官方文档中的一个上传文件流的测试程序,endpoint , buckName , objectName , filePath变量根据自己实际情况做更改

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.FileInputStream;
import java.io.InputStream;

public class Demo {

    public static void main(String[] args) throws Exception {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
        String objectName = "exampledir/exampleobject.txt";
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
        String filePath= "D:\\localpath\\examplefile.txt";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            InputStream inputStream = new FileInputStream(filePath);
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
            // 创建PutObject请求。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
} 

若上传成功,则可以在阿里云的Bucket中找到对应文件

上传成功以后,写一个图片标签测试是否能访问图片文件

点击详情按钮复制图片的URL

<img src= "https://traveling-light.oss-cn-hangzhou.aliyuncs.com/7a26d086-d37d-4f48-a336-db42ae4e4bfc.jpg">

运行html文件,可以看到图片成功展示

以下是我根据官方文档的改写的一个工具类,endpoint和bucketName在applactipn.yml文件中进行配置,方便管理

#阿里云存储
aliOSS:
  endpoint: https://oss-cn-hangzhou.aliyuncs.com
  bucketName: examplebucket
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyuncs.exceptions.ClientException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

@Component
public class AliOSSUtils {

    /**
     * 阿里云OSS对象存储地址
     */
    @Value("${aliOSS.endpoint}")
    private String endpoint;

    /**
     * OSS存储空间
     */
    @Value("${aliOSS.bucketName}")
    private String bucketName;

    /**
     * 上传到阿里云存储
     * @return url
     */
    public String upload(MultipartFile image) {

        //判断文件是否为空,如果为空则推出方法返回null
        if (image.getOriginalFilename() == null) {
            return null;
        }
        //避免文件覆盖
        //获取文件原始名称
        String originalFilename = image.getOriginalFilename();
        //判断最后一个“.”的位置
        int index = originalFilename.lastIndexOf(".");
        //获取文件扩展名
        String extname = originalFilename.substring(index);
        //组成全新不会重复的文件名
        String newFileName = UUID.randomUUID() + extname;

        //组装文件访问路径
        String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + newFileName;

        //输入流声明
        InputStream inputStream = null;
        //声明OSSClient实例
        OSS ossClient = null;

        try {
            // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
            EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
            // 获取OSSClient实例。
            ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

            //获取输入流
            inputStream = image.getInputStream();

            // 创建PutObjectRequest对象。
            ossClient.putObject(bucketName, newFileName, inputStream);
            
            //返回一个存储路径
            return url;
        } catch (ClientException | IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (ossClient!= null) {
                //关闭OSSClient
                ossClient.shutdown();
            }
            try {
                if (inputStream != null) {
                    //关闭输入流
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }
}

调用此工具类只需传入一个MultipartFile类型的文件,返回值即为存储的URL路径,用法较为简单不再做演示,需要显示图片时直接将访问URL路径即可。

SpringBoot 结合 Vue.js 开发应用时,文件上传通常涉及到前端的 HTML 表单配合 Axios 发送 HTTP 请求到 Spring Boot 后端服务,以及后端处理文件存储并返回文件 URL。当你将文件上传成功后,文件地址并没有保存到数据库中,可能是以下几个步骤出错: 1. **前端上传**: - 在 Vue 中,你需要使用 `axios` 或者其他库来发送 POST 请求,包含文件数据和表单其他字段到 `/api/upload` 这样的指定路径。 ```javascript axios.post('/api/upload', { file: file, // 其他表单字段... }).then(response => { console.log('文件上传成功,服务器返回的地址:', response.data.url); }) ``` 2. **后端处理**: - Spring Boot 接收到请求后,一般会通过 `MultipartFile` 对象获取文件,然后保存到本地文件系统,如 `FileSystemResource` 或第三方云存储如 AWS S3、阿里云 OSS 等。然后返回一个新的 URL 到客户端。 ```java @PostMapping("/upload") public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) { try { // 存储文件并获取URL String url = saveFileToStorage(file); return ResponseEntity.ok(url); // 返回给前端 } catch (Exception e) { return ResponseEntity.badRequest().body(e.getMessage()); } } ``` 3. **数据库操作缺失**: - 如果预期的是将文件 URL 存储到数据库,那么应该在上述处理完成后,调用对应数据库操作方法,例如插入一条记录,字段包括用户 ID、文件名、URL 等。 然而,在这个场景下,由于没有直接提到数据库操作,可能是你漏掉了数据库更新的部分或者是前端未保存上传成功的响应数据。你应该确保前端收到文件 URL 后将其保存到合适的数据库字段,比如用户的文件列表中。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值