本地存储
文件上传时在服务端会产生一个临时文件,请求响应完成之后,这个临时文件被自动删除,并没有进行保存。此时我们就需要完成将上传的文件保存在服务器的本地磁盘上。
前端
<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路径即可。