SpringBoot+Vue2实现图片的上传和回显
1、环境准备:
- 搭建好的SpringBoot项目,需要引入Hutool包。
- 搭建好的Vue2项目,在本次实验中将结合ElementUI来实现前端图片的上传和回显功能。
2、引入ElementUI组件
-
<template> <div> <el-upload class="avatar-uploader" action="https://jsonplaceholder.typicode.com/posts/" :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> </div> </template> <script> export default { name: "Upload", data() { return { imageUrl: '', }; }, methods: { handleAvatarSuccess(res, file) { this.imageUrl = URL.createObjectURL(file.raw); }, beforeAvatarUpload(file) { const isJPG = file.type === 'image/jpeg'; const isLt2M = file.size / 1024 / 1024 < 6; if (!isJPG) { this.$message.error('上传头像图片只能是 JPG 格式!'); } if (!isLt2M) { this.$message.error('上传头像图片大小不能超过 6MB!'); } return isJPG && isLt2M; } } } </script> <style scoped> .avatar-uploader .el-upload { border: 1px dashed #d9d9d9; border-radius: 6px; cursor: pointer; position: relative; overflow: hidden; } .avatar-uploader .el-upload:hover { border-color: #409EFF; } .avatar-uploader-icon { font-size: 28px; color: #8c939d; width: 178px; height: 178px; line-height: 178px; text-align: center; background-color: aqua; } .avatar { width: 178px; height: 178px; display: block; } </style>
-
主要属性解释:
-
<el-upload class="avatar-uploader" action="https://jsonplaceholder.typicode.com/posts/" :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>
-
action="https://jsonplaceholder.typicode.com/posts/"
action是文件上传的后端接口,我们在前端上传图片之后,需要将文件保存在指定的路径。
-
:show-file-list="false"
是否显示已上传的文件列表
-
:before-upload="beforeAvatarUpload"
是指在图像上传前的校验规则,需要对上传的文件进行一些校验,比如:上传图片时判断是否是图片,文件大小是否超过6MB等,若返回 false 或者返回 Promise 且被 reject,则停止上传。对应的校验规则如下所示(仅供参考):
beforeAvatarUpload(file) { const isJPG = file.type === 'image/jpeg'; const isLt2M = file.size / 1024 / 1024 < 6; if (!isJPG) { this.$message.error('上传头像图片只能是 JPG 格式!'); } if (!isLt2M) { this.$message.error('上传头像图片大小不能超过 6MB!'); } return isJPG && isLt2M; }
-
:on-success="handleAvatarSuccess"
上传成功之后的响应事件,比如可以进行文件回显等。此处进行文件回显的方法如下:
handleAvatarSuccess(res, file) { this.imageUrl = URL.createObjectURL(file.raw); },
-
其他属性请参考官方网站:https://element.eleme.cn/#/zh-CN/component/upload
-
-
<img v-if="imageUrl" :src="imageUrl" class="avatar">
图片回显,在此处可能出现的问题就是出现(即:文件上传之后不会回显图片,解决方法见下文):
Not allowed to load local resource:file:///D:/files/1716169296.jpg
-
3、后端代码的编写
3.1文件上传:
-
// 文件上传路径 private String ROOT_PATH = "D:\files"; /** * 文件上传 * @param file * @return * @throws IOException */ @PostMapping("/upload") public String upload(MultipartFile file) throws IOException { // 获取文件的原始名称:aaa.jpg String originalFilename = file.getOriginalFilename(); // 获取文件名:aaa 此处的FileUtil是Hutool包提供的 String mainName = FileUtil.mainName(originalFilename); // 获取文件的后缀:jpg String extName = FileUtil.extName(originalFilename); // 判断文件上传的路径是否存在,不存在就需要主动创建一个 if (!FileUtil.exist(ROOT_PATH)) { // 如果文件的父级目录不存在,则创建一个文件夹 FileUtil.mkdir(ROOT_PATH); } // 对上传的文件进行重命名,命名规则:当前时间戳.文件后缀 originalFilename = System.currentTimeMillis() + "." + extName; // 创建一个File对象,将上传的文件保存到指定文件上传地址 其中:File.separator表示 \ File saveFile = new File(ROOT_PATH + File.separator + originalFilename); // 将文件保存到本地磁盘中:D:\files\1716169296.jpg file.transferTo(saveFile); // 文件上传成功之后需要返回一个文件的链接,这个链接就是文件的下载地址,是后台提供的 String url = "http://localhost:8080/file/download/" + originalFilename; return url; }
3.2、文件下载:
-
/** * 文件下载: 此处需要将我们之前上传保存的文件加入到客户端(浏览器)中,才能进行文件的正常回显,否则就会出现上述报错。 * @param fileName * @param response * @throws IOException */ @AuthAccess @GetMapping("/download/{fileName}") public void download(@PathVariable String fileName, HttpServletResponse response) throws IOException { // 根据前端传回的文件名进行拼接本地文件的路径:D:\files\1716169296.jpg String filePath = ROOT_PATH + File.separator + fileName; // 如果文件不存在就直接返回,即文件无法回显。 if (!FileUtil.exist(filePath)) { return; } // 读取图片的字节信息,保存到字节数组中 byte[] bytes = FileUtil.readBytes(filePath); // 获取响应对象的输出流对象,需要将字节数组信息写回浏览器中 ServletOutputStream outputStream = response.getOutputStream(); // 将图片的字节数组信息写入到响应对象之中,实现文件的下载 outputStream.write(bytes); // 刷新输出流对象 outputStream.flush(); // 关闭资源 outputStream.close(); }
4、修改前端代码:
-
图片上传路径修改(此处对应的是后端接口中的文件上传接口):
action="http://localhost:8080/file/upload"
-
图片回显路径修改(此处对应的是后端接口中的文件下载接口):
handleAvatarSuccess(res, file) { // 根据文件上传接口传回的数据是一个文件下载的链接:http://localhost:8080/file/download/1716169296.jpg,所以在此处只需要接收到这个参数即可,如果是返回一个上传后的文件名,则需要去拼接Url路径即可 this.imageUrl = res },
5、为什么无法通过本地路径直接回显图片:
- 原因:在前后端分离项目中,浏览器会出于安全考虑,不允许用户通过网页去访问本地的文件。
- 解决方法之一:通过读取本地的文件,将文件保存到浏览器中,既可以正常进行图片的回显。