Vue+SpringBoot 实现用户头像上传(附前后端源码)
文章目录一、背景二、vue-image-crop-upload组件三、编写前端上传头像功能四、编写后台上传用户头像接口4.1 实现前端组件上传过来的头像文件保存到服务器上4.2 将保存在服务器上的用户头像路径存放到用户信息表中4.3 编写用户更新头像信息API五、前后端联调六、源码一、背景后台系统一般会有用户个人信息的模块(见下图),为了增强用户的体验度,系统会开放自定义头像的功能,让用户可以上传
·
文章目录
一、背景
- 后台系统一般会有用户个人信息的模块(见下图),为了增强用户的体验度,系统会开放自定义头像的功能,让用户可以上传自定义图片替代默认的系统头像。本文将通过Vue+SpringBoot来具体实现。
二、vue-image-crop-upload组件
- 首先我们会用到vue-image-crop-upload组件
- 一些重要的参数与事件
三、编写前端上传头像功能
- 了解了vue-image-crop-upload组件的功能后,编写自定义头像前台上传功能就相当容易了,我们只需要把这个组件嵌入到个人信息页面中,并编写相应事件即可。
<template>
<div class="app-container">
...
<div slot="header" class="clearfix">
<span>个人信息</span>
</div>
<div>
<div style="text-align: center">
<div class="el-upload">
<myUpload
v-model="showDialog"
:headers="headers"
:url="baseApi+'/api/user/updateAvatar'"
@crop-upload-success="cropUploadSuccess"
/>
<img
:src="
user.avatarUrl
? baseApi + '/file/' + user.avatarUrl
: Avatar
"
title="点击上传头像"
class="avatar"
@click="toggleShow"
>
...
</div>
</div>
</div>
..
</div>
</template>
<script>
// 使用头像上传组件
import myUpload from 'vue-image-crop-upload'
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
import store from '@/store'
import Avatar from '@/assets/images/avatar.png'
export default {
name: 'Center',
components: { myUpload },
data() {
return {
showDialog: false,
Avatar: Avatar,
headers: {
'Authorization': getToken()
},
...
}
},
computed: {
...mapGetters([
'user',
'baseApi'
])
},
methods: {
// 点击头像打开上传窗口
toggleShow() {
this.showDialog = !this.showDialog
},
// 上传成功后重新载入信息
cropUploadSuccess(jsonData, field) {
store.dispatch('getInfo').then(() => { })
},
...
}
}
</script>
...
- 页面效果如下:
四、编写后台上传用户头像接口
- 有了前端页面,就需要后台实现对应的接口,想一想,该接口需要有哪些功能呢?
- 需要将前端组件上传过来的头像文件保存到服务器上;
- 需要将保存在服务器上的用户头像路径存放到用户信息表中。
4.1 实现前端组件上传过来的头像文件保存到服务器上
- 我们需要建立一个上传文件信息表,及建立上传文件的操作服务类来实现文件的保存。
- 上传文件信息表
/**
* 文件信息表
*
* @author zhuhuix
* @date 2020-04-20
*/
@ApiModel(value = "用户信息")
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("upload_file")
public class UploadFile implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 文件实际名称
*/
private String realName;
/**
* 文件名
*/
private String fileName;
/**
* 文件主名称
*/
private String primaryName;
/**
* 文件扩展名
*/
private String extension;
/**
* 存放路径
*/
private String path;
/**
* 文件类型
*/
private String type;
/**
* 文件大小
*/
private Long size;
/**
* 上传人
*/
private String uploader;
private Timestamp createTime;
@Override
public String toString() {
return "UploadFile{" +
"fileName='" + fileName + '\'' +
", uploader='" + uploader + '\'' +
", createTime=" + createTime +
'}';
}
}
- 上传文件DAO
/**
* 文件上传DAO接口
*
* @author zhuhuix
* @date 2021-07-19
*/
@Mapper
public interface UploadFileMapper extends BaseMapper<UploadFile> {
}
- 上传文件工具具体实现类
/**
* 文件上传接口定义
*
* @author zhuhuix
* @date 2020-04-20
*/
public interface UploadFileTool {
/**
* 文件上传
*
* @param uploader 上传人
* @param realName 文件实际名称
* @param multipartFile 文件
* @return 上传信息
*/
UploadFile upload(String uploader, String realName, MultipartFile multipartFile);
}
/**
* 文件上传实现类
*
* @author zhuhuix
* @date 2020-04-20
*/
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class UploadFileToolImpl implements UploadFileTool {
private final UploadFileMapper uploadFileMapper;
@Value("${uploadFile.path}")
private String path;
@Value("${uploadFile.maxSize}")
private long maxSize;
@Override
@Transactional(rollbackFor = Exception.class)
public UploadFile upload(String uploader, String realName, MultipartFile multipartFile) {
//检查文件大小
if (multipartFile.getSize() > maxSize * Constant.MB) {
throw new RuntimeException("超出文件上传大小限制" + maxSize + "MB");
}
//获取上传文件的主文件名与扩展名
String primaryName = FileUtil.mainName(multipartFile.getOriginalFilename());
String extension = FileUtil.extName(multipartFile.getOriginalFilename());
//根据文件扩展名得到文件类型
String type = getFileType(extension);
//给上传的文件加上时间戳
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMddhhmmssS");
String nowStr = "-" + date.format(format);
String fileName = primaryName + nowStr + "." + extension;
try {
String filePath = path + type + File.separator + fileName;
File dest = new File(filePath).getCanonicalFile();
if (!dest.getParentFile().exists()) {
if (ObjectUtil.isNull(dest.getParentFile().mkdirs())) {
throw new RuntimeException("上传文件失败:建立目录错误");
}
}
multipartFile.transferTo(dest);
if (ObjectUtil.isNull(dest)) {
throw new RuntimeException("上传文件失败");
}
UploadFile uploadFile = new UploadFile(null, realName, fileName, primaryName,
extension, dest.getPath(), type, multipartFile.getSize(),
uploader, Timestamp.valueOf(LocalDateTime.now()));
if (uploadFileMapper.insert(uploadFile) > 0) {
return uploadFile;
}
throw new RuntimeException("上传文件失败");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
/**
* 根据文件扩展名给文件类型
*
* @param extension 文件扩展名
* @return 文件类型
*/
private static String getFileType(String extension) {
String document = "txt doc pdf ppt pps xlsx xls docx csv";
String music = "mp3 wav wma mpa ram ra aac aif m4a";
String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
if (image.contains(extension)) {
return "image";
} else if (document.contains(extension)) {
return "document";
} else if (music.contains(extension)) {
return "music";
} else if (video.contains(extension)) {
return "video";
} else {
return "other";
}
}
}
4.2 将保存在服务器上的用户头像路径存放到用户信息表中
- 在用户信息服务中增加保存头像信息的功能
/**
* 用户信息
*
* @author zhuhuix
* @date 2020-04-03
*/
public interface SysUserService {
....
/**
* 修改用户头像
* @param file 文件
* @return json
*/
Map<String,String> updateAvatar(MultipartFile file);
}
/**
* 用户信息实现
*
* @author zhuhuix
* @date 2020-04-03
*/
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class SysUserServiceImpl implements SysUserService {
private final SysUserMapper sysUserMapper;
private final UploadFileTool uploadFileTool;
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, String> updateAvatar(MultipartFile file) {
SysUser sysUser = findByUserName(getCurrentLoginUserName());
// 调用上传文件服务保存头像
UploadFile uploadFile = uploadFileTool.upload(sysUser.getUserName(), file.getOriginalFilename(), file);
// 将头像路径保存到个人信息中
sysUser.setAvatarUrl(uploadFile.getType() + File.separator + uploadFile.getFileName());
update(sysUser);
return new HashMap<String, String>(1) {{
put("avatar", uploadFile.getFileName());
}};
}
@Override
@Transactional(rollbackFor = Exception.class)
public SysUser update(SysUser user) {
if (sysUserMapper.updateById(user) > 0) {
return user;
}
throw new RuntimeException("更新用户信息失败");
}
@Override
public SysUser findByUserName(String userName) {
return sysUserMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getUserName, userName));
}
private String getCurrentLoginUserName() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new RuntimeException("登录状态已过期");
}
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
return (userDetails.getUsername());
}
throw new RuntimeException("找不到当前登录的信息");
}
}
4.3 编写用户更新头像信息API
- 最后只需要在Controller层增加用户更新头像信息API接口供前端调用即可
@ApiOperation("修改用户头像")
@PostMapping(value = "/updateAvatar")
public ResponseEntity<Object> updateAvatar(@RequestParam MultipartFile avatar) {
return ResponseEntity.ok(sysUserService.updateAvatar(avatar));
}
五、前后端联调
六、源码
更多推荐
已为社区贡献6条内容
所有评论(0)