心链 — 伙伴匹配系统
后端用户个人信息修改接口
控制层新增用户信息更新接口
UserController
/**
* 用户信息更新
* @param user
* @param request
* @return
*/
@PostMapping("/update")
public BaseResponse<Integer> updateUser(@RequestBody User user , HttpServletRequest request) {
//验证参数是否为空
if (user == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
//鉴权
User loginUser = userService.getLogininUser(request);
int result = userService.updateUser(user,loginUser);
return ResultUtils.success(result);
}
service层提供用户信息修改方法,并提取了获取当前用户信息和是否为管理员的方法。
UserService
/**
* 用户信息修改
* @param user
* @return
*/
int updateUser(User user,User loginUser);
/**
* 获取当前用户信息
* @param request
* @return
*/
User getLogininUser(HttpServletRequest request);
/**
* 是否为管理员
*
* @param request
* @return
*/
boolean isAdmin(HttpServletRequest request);
/**
* 是否为管理员
*
* @param loginUser
* @return
*/
boolean isAdmin(User loginUser);
serviceImpl层进行实现。
UserSercviceImpl
/**
* 用户信息修改
* @param user
* @return
*/
@Override
public int updateUser(User user,User loginUser) {
long userId = user.getId();
if (userId <= 0){
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
//如果是管理员,允许更新任意用户
//如果不是管理员,只允许更新自己的信息
if (!isAdmin(loginUser) && userId != loginUser.getId()){
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
User userold = userMapper.selectById(userId);
if (userold == null){
throw new BusinessException(ErrorCode.NULL_ERROR);
}
return userMapper.updateById(user);
}
/**
* 是否为管理员
*
* @param request
* @return
*/
public boolean isAdmin(HttpServletRequest request) {
// 仅管理员可查询
Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
User user = (User) userObj;
return user != null && user.getUserRole() == ADMIN_ROLE;
}
/**
* 是否为管理员
*
* @param loginUser
* @return
*/
public boolean isAdmin(User loginUser) {
return loginUser != null && loginUser.getUserRole() == ADMIN_ROLE;
}
/**
* 获取当前用户信息
* @param request
* @return
*/
@Override
public User getLogininUser(HttpServletRequest request) {
if (request == null){
return null;
}
Object userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
if (userObj == null){
throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
}
return (User) userObj;
}
前端对接
登录
我这里不能使用Toast.success() ,进行提示,看文档说使用showSuccessToast、showFailToast进行提示
<template>
<van-form @submit="onSubmit">
<van-cell-group inset>
<van-field
v-model="userAccout"
name="userAccout"
label="账户"
placeholder="账户"
:rules="[{ required: true, message: '请填写账户' }]"
/>
<van-field
v-model="userPassword"
type="password"
name="userPassword"
label="密码"
placeholder="密码"
:rules="[{ required: true, message: '请填写密码' }]"
/>
</van-cell-group>
<div style="margin: 16px;">
<van-button round block type="primary" native-type="submit">
提交
</van-button>
</div>
</van-form>
</template>
<script setup lang="ts">
import {useRouter} from "vue-router";
import {ref} from "vue";
import myAxios from "../plugins/myAxios";
import {Toast} from "vant";
const router = useRouter();
const userAccout = ref('');
const userPassword = ref('');
const onSubmit = async () => {
const res = await myAxios.post('/user/login',{
userAccount: userAccout.value,
userPassword: userPassword.value,
})
console.log(res,'用户登录');
if (res.code == 0 && res.data){
Toast.success('登录成功');
router.replace('/')
} else {
Toast.fail('登录失败')
}
};
</script>
<style scoped>
</style>
在路由里面引入
import UserLoginPage from "../pages/UserLoginPage.vue";
{ path: '/user/login', component: UserLoginPage },
这里需要我们在myAxios.ts里把响应改成data,如下图:
http://localhost:5173/#/user/login
运行 ,输入数据,成功登录并跳转的主页,显示如下:
用户信息获取
在用户个人信息页面上调取后端接口获取用户的信息。
import myAxios from "../plugins/myAxios.ts";
import {showFailToast,showSuccessToast} from "vant/lib/vant.es";
const user = ref();
onMounted(async ()=>{
const res = await myAxios.get('/user/current');
if (res.code === 0){
user.value =res.data;
showSuccessToast('获取用户信息成功');
}else {
showFailToast('获取用户信息成功');
}
})
但是登录不会种下cookie,意味着后端不能获取登录用户信息,就不能动态展示用户信息
种cookie
在myAxios.ts中添加以下代码:(注意要在定义的变量,即myAxios之后粘贴)
myAxios.defaults.withCredentials = true; // 允许携带 cookie
这里遇到了新的坑,给后端接口添加允许携带 cookie 的配置,才能把cookie种下
后端设置 cookie 的作用域
再尝试就ok了
<template>
<template v-if="user">
<van-cell title="昵称" is-link to="/user/edit" :value="user.username" @click="toEdit('username','昵称',user.username)"/>
<van-cell title="账户" :value="user.userAccount"
@click="toEdit('userAccount','账户',user.userAccount)"/>
<van-cell title="头像" is-link to="/user/edit" :value="user.avatarUrl" @click="toEdit('avatarUrl','头像',user.avatarUrl)">
<img style="height: 48px" :src="user.avatarUrl">
</van-cell>
<van-cell title="性别" is-link to="/user/edit" :value="user.gender" @click="toEdit('gender','性别',user.gender)" />
<van-cell title="电话" is-link to="/user/edit" :value="user.phone" @click="toEdit('phone','电话',user.phone)"/>
<van-cell title="邮箱" is-link to="/user/edit" :value="user.email" @click="toEdit('email','邮箱',user.email)"/>
<van-cell title="星球编号" :value="user.planetCode" />
<van-cell title="注册时间" :value="user.createTime" />
</template>
</template>
<script setup lang="ts">
import {useRouter} from "vue-router";
import {onMounted, ref} from "vue";
import myAxios from "../plugins/myAxios.ts";
import {showFailToast, showSuccessToast} from "vant";
const user = ref();
// const user = {
// id: 1,
// username: '阿尼亚',
// userAccount: 'Aniya',
// avatarUrl: 'https://raw.githubusercontent.com/RockIvy/images/master/img/avatar42.jpg',
// gender: '男',
// phone: '12131133313',
// email: '23432444@qq.com',
// planetCode: '2220',
// createTime: new Date(),
// };
const router = useRouter()
const toEdit = (editKey: String, editName: String, currentValue: String) => {
router.push({
path: 'user/edit',
query: {
editKey,
editName,
currentValue,
}
})
}
onMounted(async () => {
const res = await myAxios.get('/user/current');
if (res.code === 0) {
user.value = res.data;
showSuccessToast('获取用户信息成功');
} else {
showFailToast('获取用户信息成功');
}
})
</script>
<style scoped>
</style>
完善修改用户信息
发现每个页面都要获取当前的用户信息,所以我们把这个方法提取出来 在src目录下建立services包,并创建user.ts编写代码
import myAxios from "../plugins/myAxios";
import {getCurrentUserState, setCurrentUserState} from "../states/user";
/**
* 获取用户信息
* @returns {Promise<null|any>}
*/
export const getCurrentUser = async () => {
const user = getCurrentUserState();
if (user) {
return user;
}
//从远程处获取用户信息
const res = await myAxios.get("/user/current");
if (res.code == 0 ) {
// setCurrentUserState(res.data);
return res.data;
}
return null;
}
同时在src目录下建立states包,并创建user.ts编写代码(定义两个方法)
import {UserType} from "../models/user";
let currentUser: UserType;
const setCurrentUserState = (user:UserType) =>{
currentUser =user;
}
const getCurrentUserState = (): UserType =>{
return currentUser;
}
export {
setCurrentUserState,
getCurrentUserState,
}
由于提取了获取用户信息的代码,所以用户页原来编写的代码需要修改为下图
最后就是要编写用户修改页面了,发送修改用户信息请求。 UserEditPage.vue完整代码如下
<template>
<van-form @submit="onSubmit">
<van-field
v-model="editUser.currentValue"
:name="editUser.editKey"
:label="editUser.editName"
:placeholder="`请输入${editUser.editName}`"
/>
<div style="margin: 16px;">
<van-button round block type="primary" native-type="submit">
提交
</van-button>
</div>
</van-form>
</template>
<script setup lang="ts">
import {useRoute, useRouter} from "vue-router";
import {ref} from "vue";
import myAxios from "../plugins/myAxios";
import {showSuccessToast,showFailToast} from "vant/lib/vant.es";
import {getCurrentUser} from "../services/user";
const route = useRoute();
const router =useRouter();
const editUser = ref({
editKey: route.query.editKey,
currentValue: route.query.currentValue,
editName: route.query.editName,
})
// 不可以写在外面,否则页面不显示内容,还没有报错信息,原因未知
// const currentUser = await getCurrentUser();
const onSubmit = async () => {
// 异步方法必须添加 await 才可以拿到数据, 否则拿到的是 promise 对象
const currentUser = await getCurrentUser();
console.log("-------UserEditPage", currentUser);
const res = await myAxios.post("/user/update", {
"id": currentUser.id,
[editUser.value.editKey]: editUser.value.currentValue // 动态取值
})
console.log("修改用户信息", res);
if (res.code === 0 && res.data > 0) {
showSuccessToast('修改成功')
router.back()
}else {
showFailToast('修改失败');
}
};
</script>
<style scoped>
</style>
**注意踩坑处:**语法糖是支持写在外面的,但是这里面运用就不显示页面
关于调用缓存去获取当前用户信息的问题
建议:在小系统(用户少)中尽量不要使用缓存,可以使用路由守卫,从远程获取踩坑处:如果前端在用户页的信息中并未设定editKey的话,就无法修改信息(更新内容为空),这需要我们在后端去控制、筛选前端所传入的参数 后端会有类似以下报错