SpringBoot+Vue实现个人信息以及头像数据联动
我们在进行功能实现的时候,个人信息是极其重要的一部分。不仅能展示用户的信息给用户,还能让我们的项目更多元化,让用户的体验感得到提升。我们后端利用SpringBoot整合Mybaties-plus获取数据库里面的user表数据,前端利用Vue调用后端接口进行数据渲染。
·
一、功能展示
二、前言
我们在进行功能实现的时候,个人信息是极其重要的一部分。不仅能展示用户的信息给用户,还能让我们的项目更多元化,让用户的体验感得到提升。
我们后端利用SpringBoot整合Mybaties-plus获取数据库里面的user表数据,前端利用Vue调用后端接口进行数据渲染。
三、技术支持
1.首先是我们的头像上传,我们可以使用到element-ui的组件
2.个人信息展示的区域,我使用的是card组件
四、项目配置
五、核心代码
1.个人信息界面
重点!!!
this.$emit('refreshUser')
<template>
<div>
<el-card style="width: 800px; margin-top: 20px; margin-left: 20px;" shadow="hover">
<el-form label-width="80px" size="small">
<el-upload
class="avatar-uploader"
:action="'http://localhost:9090/file/upload'"
:show-file-list="false"
:on-success="handleAvatarSuccess">
<img v-if="form.avatarUrl" :src="form.avatarUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<el-form-item label="用户名" style="margin-left: 200px; margin-top: -150px">
<el-input v-model="form.username" disabled autocomplete="off" style="width: 400px"></el-input>
</el-form-item>
<el-form-item label="昵称" style="margin-left: 200px">
<el-input v-model="form.nickname" autocomplete="off" style="width: 400px"></el-input>
</el-form-item>
<el-form-item label="性别" style="margin-left: 200px">
<el-select v-model="form.sex" placeholder="请选择您的性别" style="width: 400px">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="邮箱" style="margin-left: 200px">
<el-input v-model="form.email" autocomplete="off" style="width: 400px"></el-input>
</el-form-item>
<el-form-item label="电话" style="margin-left: 200px">
<el-input v-model="form.phone" autocomplete="off" style="width: 400px"></el-input>
</el-form-item>
<el-form-item label="地址" style="margin-left: 200px" >
<el-input type="textarea" v-model="form.address" autocomplete="off" style="width: 400px"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="save">保 存</el-button>
<!-- <el-button type="primary" @click="sign"><i class="el-icon-location" />定位</el-button>-->
<el-button type="primary" @click="return1">返回主页</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
export default {
name: "Person",
data() {
//电话号码校验
const checkPhone = (rule, value, callback) => {
if(!this.validatePhone.test(value)) {
return callback(new Error('手机号格式不合法'));
}
callback()
}
return {
form: {
phone: '',
},
user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {},
options: [{
value: '男',
label: '男'
}, {
value: '女',
label: '女'
}],
value: '',
rules: {
phone: [
{required: true, message: '请输入手机号', trigger: 'blur'}
],
},
rulesPhone: {
phone: [
{ validator: checkPhone, trigger: 'blur' }
],
},
interval: null,
validatePhone: /^1[3,4,5,6,7,8,9][0-9]{9}$/
}
},
mounted() {
// 获取地理位置
var geolocation = new BMapGL.Geolocation();
geolocation.getCurrentPosition(function(r){
if(this.getStatus() == BMAP_STATUS_SUCCESS){
const province = r.address.province
const city = r.address.city
localStorage.setItem("location", province + city)
}
});
},
created() {
this.load()
},
methods: {
load() {
const username = this.user.username
if (!username) {
this.$message.error("当前无法获取用户信息!")
return
}
this.request.get("/user/username/" + username).then(res => {
// console.log(res)
this.form = res.data
})
},
sign() {
const location = localStorage.getItem("location")
const username = this.user.username
this.request.post("/sign", { user: username, location: location }).then(res => {
if (res.code === '200') {
this.$message.success("打卡成功")
} else {
this.$message.error(res.msg)
}
})
},
save() {
this.request.post("/user", this.form).then(res => {
if (res.data) {
this.$message.success("保存成功")
this.load()
this.$emit('refreshUser')
} else {
this.$message.error("保存失败")
}
})
},
// 头像上传
handleAvatarSuccess(res) {
// res就是头像文件路径
this.form.avatarUrl = res
},
return1() {
this.$router.push("/")
}
}
}
</script>
<style>
.avatar-uploader {
text-align: left;
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: 160px;
height: 160px;
display: block;
}
</style>
2.头部Header
<template>
<div style="line-height: 60px; display: flex; background-color: whitesmoke">
<div style="flex: 1">
<span :class="collapseBtnClass" style="cursor: pointer; font-size: 18px"></span>
<el-breadcrumb separator="/" style="display: inline-block; margin-left: 10px">
<img src="../assets/images/宿舍管理.png" alt=""
style="width: 30px; position: relative; top: 20px; right: 5px">
<h3 style="margin-left: 30px; color: lightskyblue">宿舍后台管理</h3>
<!-- <el-breadcrumb-item>{{ currentPathName }}</el-breadcrumb-item>-->
</el-breadcrumb>
</div>
<el-dropdown style="width: 130px; cursor: pointer">
<div style="display: inline-block; float: right; margin-right: 10px">
<img :src="user.avatarUrl" alt=""
style="width: 30px; border-radius: 50%; position: relative; top: 10px; right: 5px">
<span>{{user.nickname}}</span><i class="el-icon-arrow-down" style="margin-left: 5px"></i>
</div>
<el-dropdown-menu slot="dropdown" style="width: 100px; text-align: center">
<el-dropdown-item style="font-size: 14px; padding: 5px 0">
<span style="text-decoration: none" @click="person">个人信息</span>
</el-dropdown-item>
<el-dropdown-item style="font-size: 14px; padding: 5px 0">
<span style="text-decoration: none" @click="logout">退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
export default {
name: "Header",
props: {
collapseBtnClass: String,
user: Object
},
computed: {
currentPathName() {
return this.$store.state.currentPathName;
}
},
data() {
return {
user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}
}
},
methods: {
login() {
this.$router.push("/login")
this.$message.success("欢迎使用在线商城")
},
logout() {
this.$router.push("/login")
this.$message.success("退出成功")
},
person(){
this.$router.push("/mall/person")
}
}
}
</script>
<style scoped>
</style>
进行数据联动,一旦上传我们的头像并保存,我们的Header上面就会进行实时更新数据,即刻展现新的头像。
3.图片上传
(1)文件上传SQL
CREATE TABLE `file` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件名称',
`type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件类型',
`size` bigint DEFAULT NULL COMMENT '文件大小(kb)',
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '下载链接',
`md5` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件md5',
`creat_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '时间',
`is_delete` tinyint(1) DEFAULT '0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=114 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
(2)上传接口
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.Constants;
import com.example.demo.common.Result;
import com.example.demo.entity.Files;
import com.example.demo.mapper.FileMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
@RestController
@RequestMapping("/file")
public class FileController {
@Value("${files.upload.path}")
private String fileUploadPath;
@Value("${server.ip}")
private String serverIp;
@Resource
private FileMapper fileMapper;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@PostMapping("/upload")
public String upload(@RequestParam MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
String type = FileUtil.extName(originalFilename);
long size = file.getSize();
// 定义一个文件唯一的标识码
String fileUUID = IdUtil.fastSimpleUUID() + StrUtil.DOT + type;
File uploadFile = new File(fileUploadPath + fileUUID);
// 判断配置的文件目录是否存在,若不存在则创建一个新的文件目录
File parentFile = uploadFile.getParentFile();
//判断目录是否存在,不存在就新建
if (!parentFile.exists()) {
parentFile.mkdirs();
}
String url;
// 获取文件的md5
String md5 = SecureUtil.md5(file.getInputStream());
// 从数据库查询是否存在相同的记录
Files dbFiles = getFileByMd5(md5);
if (dbFiles != null) {
url = dbFiles.getUrl();
} else {
// 上传文件到磁盘
file.transferTo(uploadFile);
// 数据库若不存在重复文件,则不删除刚才上传的文件
url = "http://" + serverIp + ":9090/file/" + fileUUID;
}
//存储到数据库
Files saveFile = new Files();
saveFile.setName(originalFilename);
saveFile.setType(type);
saveFile.setSize(size/1024);
saveFile.setUrl(url);
saveFile.setMd5(md5);
fileMapper.insert(saveFile);
return url;
// String md5 = SecureUtil.md5(file.getInputStream());
// Files files = getFileByMd5(md5);
//
// String url;
// if (files != null) {
// url = files.getUrl();
// } else {
// file.transferTo(uploadFile);
// url = "http://localhost:9090/file/" + fileUUID;
// }
// //存储到数据库
// Files saveFile = new Files();
// saveFile.setName(originalFilename);
// saveFile.setType(type);
// saveFile.setSize(size/1024);
// saveFile.setUrl(url);
// saveFile.setMd5(md5);
// fileMapper.insert(saveFile);
// return url;
}
@GetMapping("/{fileUUID}")
public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {
// 根据文件的唯一标识码获取文件
File uploadFile = new File(fileUploadPath + fileUUID);
// 设置输出流的格式
ServletOutputStream os = response.getOutputStream();
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8"));
response.setContentType("application/octet-stream");
// 读取文件的字节流
os.write(FileUtil.readBytes(uploadFile));
os.flush();
os.close();
}
/**
* 通过文件的md5查询文件
* @param md5
* @return
*/
private Files getFileByMd5(String md5) {
// 查询文件的md5是否存在
QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("md5", md5);
List<Files> filesList = fileMapper.selectList(queryWrapper);
return filesList.size() == 0 ? null : filesList.get(0);
}
// @CachePut(value = "files", key = "'frontAll'")
@PostMapping("/update")
public Result update(@RequestBody Files files) {
fileMapper.updateById(files);
flushRedis(Constants.FILES_KEY);
return Result.success();
}
@GetMapping("/detail/{id}")
public Result getById(@PathVariable Integer id) {
return Result.success(fileMapper.selectById(id));
}
//清除一条缓存,key为要清空的数据
// @CacheEvict(value="files",key="'frontAll'")
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
Files files = fileMapper.selectById(id);
files.setIsDelete(true);
fileMapper.updateById(files);
flushRedis(Constants.FILES_KEY);
return Result.success();
}
@PostMapping("/del/batch")
public Result deleteBatch(@RequestBody List<Integer> ids) {
// select * from sys_file where id in (id,id,id...)
QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
queryWrapper.in("id", ids);
List<Files> files = fileMapper.selectList(queryWrapper);
for (Files file : files) {
file.setIsDelete(true);
fileMapper.updateById(file);
}
return Result.success();
}
/**
* 分页查询接口
* @param pageNum
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public Result findPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
@RequestParam(defaultValue = "") String name) {
QueryWrapper<Files> queryWrapper = new QueryWrapper<>();
// 查询未删除的记录
queryWrapper.eq("is_delete", false);
queryWrapper.orderByDesc("id");
if (!"".equals(name)) {
queryWrapper.like("name", name);
}
return Result.success(fileMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper));
}
// 删除缓存
private void flushRedis(String key) {
stringRedisTemplate.delete(key);
}
}
4.用户数据获取
(1)UserController
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.Constants;
import com.example.demo.common.Result;
import com.example.demo.controller.dto.UserDTO;
import com.example.demo.entity.Build;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import com.example.demo.utils.TokenUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private IUserService userService;
@PostMapping("/login")
public Result login(@RequestBody UserDTO userDTO) {
String username = userDTO.getUsername();
String password = userDTO.getPassword();
if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
return Result.error(Constants.CODE_400,"参数错误");
}
UserDTO dto = userService.login(userDTO);
return Result.success(dto);
}
@PostMapping("/register")
public Result register(@RequestBody UserDTO userDTO) {
String username = userDTO.getUsername();
String password = userDTO.getPassword();
if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
return Result.error(Constants.CODE_400,"参数错误");
}
return Result.success(userService.register(userDTO));
}
//新增或者更新
@PostMapping
public Result save(@RequestBody User user) {
String username = user.getUsername();
if (StrUtil.isBlank(username)) {
return Result.error(Constants.CODE_400, "参数错误");
}
if (user.getId() != null) {
user.setPassword(null);
} else {
user.setNickname(user.getUsername());
if (user.getPassword() == null) {
user.setPassword("123456");
}
}
return Result.success(userService.saveOrUpdate(user));
}
//删除
// @DeleteMapping("/{id}")
// public Result delete(@PathVariable Integer id) {
// return Result.success(userService.removeById(id));
// }
@PostMapping("/del/batch")
public Result deleteBatch(@RequestBody List<Integer> ids) {//批量删除
return Result.success(userService.removeByIds(ids));
}
//查询所有数据
@GetMapping
public Result findAll() {
return Result.success(userService.list());
}
@GetMapping("/role/{role}")
public Result findNames(@PathVariable String role) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("role", role);
List<User> list = userService.list(queryWrapper);
return Result.success(list);
}
@GetMapping("/{id}")
public Result findOne(@PathVariable Integer id) {
return Result.success(userService.getById(id));
}
@GetMapping("/username/{username}")
public Result findByUsername(@PathVariable String username) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
return Result.success(userService.getOne(queryWrapper));
}
@GetMapping("/page")
public Result findPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
@RequestParam(defaultValue = "") String username) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("id");
if (!"".equals(username)) {
queryWrapper.like("username", username);
}
return Result.success(userService.page(new Page<>(pageNum, pageSize), queryWrapper));
}
/**
* 导出接口
*/
@GetMapping("/export")
public void export(HttpServletResponse response) throws Exception {
//从数据库查询出所有的数据
List<User> list = userService.list();
//通过工具类创建writer 写出到磁盘路径
//ExcelWriter writer = ExcelUtil.getWriter(filesUploadPath + "/用户信息.xlsx");
//在内存操作,写出到浏览器
ExcelWriter writer = ExcelUtil.getWriter(true);
//自定义标题别名
writer.addHeaderAlias("username", "用户名");
writer.addHeaderAlias("password", "密码");
writer.addHeaderAlias("nickname", "昵称");
writer.addHeaderAlias("sex", "性别");
writer.addHeaderAlias("phone", "联系方式");
writer.addHeaderAlias("address", "地址");
writer.addHeaderAlias("email", "邮箱");
writer.addHeaderAlias("createTime", "创建时间");
writer.addHeaderAlias("avatarUrl", "头像");
writer.addHeaderAlias("role", "身份");
//一次性写出list类的对象到excel,使用默认样式,强制输出标题
writer.write(list, true);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
String fileName = URLEncoder.encode("用户详情","UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName +".xlsx");
ServletOutputStream out = response.getOutputStream();
writer.flush(out, true);
out.close();
writer.close();
}
/**
* excel导入
* @param
* @throws Exception
*/
@PostMapping("/import")
public Result imp(MultipartFile file) throws Exception {
InputStream inputStream = file.getInputStream();
ExcelReader reader = ExcelUtil.getReader(inputStream);
//通过JavaBean的方式读取Excel内的对象,但要求表头必须是英文,跟JavaBean的属性要对应
List<User> list = reader.readAll(User.class);
userService.saveBatch(list);
return Result.success(true);
}
}
(2)TokenUtils
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
@Component
public class TokenUtils {
private static IUserService staticUserService;
@Resource
private IUserService userService;
@PostConstruct
public void setUserService() {
staticUserService = userService;
}
/**
* 生成token
*
* @return
*/
public static String genToken(String userId, String sign) {
return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷
.withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期
.sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥
}
/**
* 获取当前登录的用户信息
*
* @return user对象
*/
public static User getCurrentUser() {
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("token");
if (StrUtil.isNotBlank(token)) {
String userId = JWT.decode(token).getAudience().get(0);
return staticUserService.getById(Integer.valueOf(userId));
}
} catch (Exception e) {
return null;
}
return null;
}
}
⛵小结
以上就是对Vue实现个人信息简单的概述,当然,该组件还有很多需要完善的地方,各位看官可以根据自己的喜好以及审美进行改动。最后希望各位小伙伴多多点赞,感谢你们的支持💝💝!!
更多推荐
已为社区贡献11条内容
所有评论(0)