最近在着手一个前后端分离的项目,前端用的Vue+ElementUI,后端则是使用Springboot+mybatis实现的。由于本人是第一次完全自己一人编写前后端,所以记录下自己遇到的问题。如果说你也在为上传文件
这样一个功能而头疼,那么可以看看我写的这篇文章,希望可以帮到你。废话不多说,咱们直接进入正题。
这里用了ElementUI的upload组件,主要是样式比自己写的好看点,用标记其实也是一样的,主要注意下在提交文件的时候的数据格式!!!
<el-upload
ref="upload"
class="avatar-uploader"
action="#"
accept="image/png,image/jpg,image/jpeg"
:auto-upload="true"
:limit="1"
:show-file-list="false"
:before-upload="beforeAvatarUpload"
:http-request="uploadHead"
:on-success="handleAvatarSuccess"
>
<img v-if="userInfo.headImage" :src="userInfo.headImage" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
文件在上传的时候需要用FormData格式的数据发送请求,这里用到了vue-axios实现请求示例,使用ajax的小伙伴也是一样的哦!只要在ajax的data里传入FormData格式的数据即可。
async uploadHead(f) {
// console.log(f); // 感兴趣的小伙伴可以在控制台输出下这里
let fd = new FormData(); //通过form数据格式来传
fd.append("file", f.file);
// console.log(fd.get('file'));
let res = await this.$http.uploadHead(fd, {
headers: { 'Content-Type': 'multipart/form-data' }
});
console.log(res);
}
这里需要注意的是我们使用fd.append("file",f)
是不行的,为什么呢,改成fd.append(“file”,f)我们发送下请求
可以看到请求头里确实发送了一个FormData的数据,但是后端在处理这样的请求时会出现400错误,我们需要的并不是这样的一个数据,接下来感兴趣的小伙伴可以在控制台输出一下我们在前端选中的文件f
可以看到输出了一个对象,而这个对象里又包含了一个file对象,这才是我们需要传递的数据,所以在发送请求时需要将这个file对象传至后端,使用“对象.属性名”的方式即可获取到相应的值,我们再来发送一次请求
可以看到请求参数变成二进制格式,这就是我们需要的数据
由于本人对java并不熟练,所以对于后端如何处理文件请求实在是一概不知,本着勤奋好学的态度,最终,找到了这样一种方式
@PostMapping("/uploadHead")
@ResponseBody
public ServerResponse uploadHead(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
String path = ResourceUtils.getURL("classpath:").getPath() + "static/headImage/";
String url = request.getContextPath() + "/headImage/";
File filePath = new File(path);
System.out.println("文件的保存路径:" + path);
if (!filePath.exists() && !filePath.isDirectory()) {
System.out.println("目录不存在,创建目录:" + filePath);
filePath.mkdirs(); // mkdir()不会创建目录,找不到相应路径时返回false;而mkdirs()当目录不存在时则会创建相应目录
}
//获取原始文件名称(包含格式)
String originalFileName = file.getOriginalFilename();
//获取文件类型,以最后一个`.`为标识
String type = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
HttpSession session = request.getSession();
String userId = Integer.toString((Integer)session.getAttribute("userId"));
String fileName = userId + "."+ type; // 新文件名,这里可以根据需要改名
//在指定路径下创建一个文件
File targetFile = new File(path, fileName); // 未使用outputStream.write()的时候,是一个File对象,保存在内存中,硬盘中看不到,但是可以使用这个对象
try {
// 使用springmvc的transferTo方法上传文件
file.transferTo(targetFile);
UserInfo userInfo = new UserInfo();
userInfo.setHeadImage(url + fileName);
userInfo.setUserId((Integer)session.getAttribute("userId"));
int i = userService.updateUserInfo(userInfo);
if (i != 0) {
return ServerResponse.createBySuccess("头像上传成功", url + fileName);
}
} catch (IOException e) {
e.printStackTrace();
}
return ServerResponse.createByError("头像上传失败");
}
处理成功后,我们来看数据库是否保存了相应路径,以及文件系统中是否保存了相应文件
这是上面获取到的路径,这个路径是springboot内置的tomcat的临时地址,所以每次启动springboot项目的时候,目录名字都不一样。在此路径下确实保存了相应的文件,数据库也确实保存了相应路径。
但是这样一条路径,前端要如何访问呢?
这里就要在前端设置一下代理了,在vue.config.js
里配置跨域
module.exports = {
devServer: {
open: false,// 自动打开浏览器
host: 'localhost',
port: 8080,
https: false,
hotOnly: false,
disableHostCheck: true,//Invalid Host header
proxy: { // 配置跨域
'/alumni': {
target: 'http://localhost:8081', // 这是后端地址
ws: true,
changOrigin: true,
pathRewrite: {
'^/alumni': '/alumni'
}
}
},
before: app => { }
}
}
第一次写博客,可能有很多表达不清晰的地方,希望大家见谅,也希望能够帮助到大家。