使用springboot与vue开发头像功能
1.建立数据库表
CREATE TABLE `file` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`size` bigint DEFAULT NULL,
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`md5` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`is_delete` tinyint(1) DEFAULT '0',
`is_enable` tinyint(1) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.后端接口实现
实体类服务类
直接用mybatisplus代码生成,注意实体类名字是Files避免与java中的File重复
控制器
md5保证文件的唯一性,节省磁盘空间
@PostMapping("/upload")
public String upload(@RequestParam MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
String type = FileUtil.extName(originalFilename);
long size = file.getSize();
File uploadParentFile = new File(fileUploadPath);
// 判断目录是否存在
if (!uploadParentFile.exists()) {
uploadParentFile.mkdirs(); // 使用mkdirs()确保所有父目录都被创建
}
// 定义md5
String md5 = SecureUtil.md5(file.getInputStream());
Files queryFiles = queryByMd5(md5);
String url;
if (queryFiles == null) {
// 定义唯一的文件标识码
String uuid = IdUtil.fastSimpleUUID();
String UUID = uuid + StrUtil.DOT + type;
File uploadFile = new File(fileUploadPath + UUID); // 路径名字
file.transferTo(uploadFile); // 文件写入指定对象
// 存储磁盘
url = "http://" + serverIp + ":9090/file/" + UUID;
// 存储数据库
Files saveFile = new Files();
saveFile.setType(type);
saveFile.setSize(size / 1024);
saveFile.setName(originalFilename);
saveFile.setUrl(url);
saveFile.setMd5(md5);
fileMapper.insert(saveFile);
} else {
url = queryFiles.getUrl();
}
return url;
}
/**
* 根据文件UUID下载文件
*
* @param fileUUID 文件的唯一标识符,用于定位存储的文件
* @param response HTTP响应对象,用于输出文件流和设置响应头
* @throws IOException 如果文件读取或输出流操作失败
*/
@GetMapping("/{fileUUID}")
public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {
// 根据文件UUID创建File对象,用于后续的文件读取操作
File downloadFile = new File(fileUploadPath + fileUUID);
// 获取响应的输出流,用于向客户端发送文件数据
ServletOutputStream outputStream = response.getOutputStream();
// 设置响应头,指示浏览器以附件形式下载文件,并指定文件名
response.addHeader("Content-Disposition","attachment;filenmae="+ URLEncoder.encode(fileUUID,"UTF-8"));
// 设置响应的内容类型,表示以二进制流的形式传输文件
response.setContentType("application/octet-stram");
// 读取文件字节流
outputStream.write(FileUtil.readBytes(downloadFile));
// 刷新输出流,确保所有数据都被写入响应
outputStream.flush();
// 关闭输出流,释放资源
outputStream.close();
}
前端
//页面结构
<el-upload
class="avatar-uploader"
:action="'http://'+'localhost' +':9090/file/upload'"
:show-file-list="true"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="user.avatar" :src="user.avatar" class="avatar" style="">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
submitUser(){
console.log(this.user)
this.request.post("/user/save", this.user).then(res => {
if (res.code==200) {
this.$message.success("修改成功")
localStorage.setItem("userInfo", JSON.stringify(this.user))
this.$emit("refreshUser")//让header的头像信息更新
} else {
this.$message.error(res.msg)
}
})
},
handleAvatarSuccess(res){
this.$message.success("上传成功")
console.log(res)
this.user.avatar = res
},
beforeAvatarUpload(file) {
const isJPG = file.type === 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 1;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 1MB!');
}
return isJPG && isLt2M;
}
.avatar-uploader{
text-align:center;
padding-bottom: 10px;
}
.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: 138px;
height: 138px;
line-height: 138px;
text-align: center;
}
.avatar {
width: 138px;
height: 138px;
display: block;
}