用户中心前端-3
# 10.用户中心前端-3
用户管理功能➕登录态管理(currrent)
# 登录态管理(currrent)
# 后端
在UserController添加接口以获取当前登陆状态、信息
@GetMapping("/current")
public User getCurrentUser(HttpServletRequest request) {
Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
User currentUser = (User) userObj;//(User)表示强制转换
if (currentUser == null) {
return null;
}
long userId = currentUser.getId();
//todo校验用户是否合法
User user = userService.getById(userId);
return userService.getSafetyUser(user);
}
2
3
4
5
6
7
8
9
10
11
12
在UserServiceImpl中的getSafetyUser加一个判断,用户是否为空
@Override
public User getSafetyUser(User originUser) {
if (originUser == null){
return null;
}
....
}
2
3
4
5
6
7
# 前端
app.tsx
中点击queryCurrentUser
进入api.ts
,修改代码,点击CurrentUser
查看其返回的数据,结合数据库字段设计代码
api.ts
/** 获取当前的用户 GET /api/currentUser */
export async function currentUser(options?: { [key: string]: any }) {
return request<API.CurrentUser>('/api/user/currentUser', {
method: 'GET',
...(options || {}),
});
}
typings.d.ts
declare namespace API {
type CurrentUser = {
id: number;
username: string;
userAccount: string;
avatarUrl?: string;
gender: number;
phone: string;
email: string;
userStatus: number;
userRole: number;
createTime: Data;
};
address?: string;
phone?: string;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- 将
app.tsx
中之前定义的白名单的代码提到前面,修改变量名,修改引用的变量名
const isDev = process.env.NODE_ENV === 'development';
const loginPath = '/user/login';
/**
* 无需用户登录态的页面
*/
const NO_NEED_LOGIN_WHITE_LIST = ['/user/register',loginPath];
......
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
return {
.....
if (NO_NEED_LOGIN_WHITE_LIST.includes(location.pathname)){
return;
}
....
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 修改
app.tsx
的下面代码
/**
* @see https://umijs.org/zh-CN/plugins/plugin-initial-state
* */
.....
const fetchUserInfo = async () => {
try {
return await queryCurrentUser();
} catch (error) {
history.push(loginPath);
}
return undefined;
};
// 如果不需要登录页面,bu执行
if (NO_NEED_LOGIN_WHITE_LIST.includes(history.location.pathname)) {
return {
//@ts-ignore
fetchUserInfo,
settings: defaultSettings,
};
}
const currentUser = await fetchUserInfo();
return {
//@ts-ignore
fetchUserInfo,
currentUser,
settings: defaultSettings,
};
}
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
return {
rightContentRender: () => <RightContent />,
disableContentMargin: false,
waterMarkProps: {
content: initialState?.currentUser?.username,
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
- 登陆测试,发现一直有一个问题,登陆后会显示登陆成功,但是有一个空白的错误

今天知道了可以用开发者工具查看前端的控制台

有很多错误,一个一个来
第一个就是前端的api.ts文件里,接口名字和后端的不匹配
/** 获取当前的用户 GET /api/currentUser */
改成
/** 获取当前的用户 GET /api/current */
2
3
改好后,请求成功了,发现登陆状态没有被记录

一步步排查 首先是UserController中
/**
* 用户态登录键
*/
//private static final String USER_LOGIN_STATE = "userLoginState"; 注释掉,改成
String USER_LOGIN_STATE = "userLoginState";
2
3
4
5
UserConstant.java补充代码
/**
* 默认权限
*/
int DEFAULT_ROLE = 0;
/**
* 管理员权限
*/
int ADMIN_ROLE = 1;
}
2
3
4
5
6
7
8
9
10
用户态登录键是一个键名,safetyUser是键值
判断是/current请求没有任何信息,因为cookie值不一样了,表示在不同会话,并且后台发现/current的值是空
先不管了 直接做下面的
在论坛里找到了别人遇到同样问题的解决办法用户管理项目关于两次请求sessioni - 编程导航 - 程序员编程学习交流社区 (opens new window)
在request里设置credentials=='include'就行 app.tsx:

export const request: RequestConfig = {
prefix: 'http://localhost:8080',
timeout: 10000,
credentials:'include',
};
2
3
4
5
根据这篇:credentials: 'include'跨域问题解决方案-CSDN博客 (opens new window)
问题在于前端设置: credentials: ‘include’,( 允许 cookie 共享,跨域问题,传Cookie是必须配置)
不传递Cookie时,不允许配置credentials
# 设置头像
src/components/RightContent/AvatarDropdown.tsx
# 用户管理功能
# 前端开发(一)
文件夹
src/pages
下新建Admin
文件夹,复制同级目录user
文件夹下的Register
文件夹粘贴到Admin
文件夹,更名为UserManage
到
config/routes.ts
文件中添加路由访问这个地址,显示没有权限
原因在于routes.ts文件中有一个属性是设置判断权限的
路由组件是如何判断账号的权限呢?从某个地方可以全局获取
- 首次访问页面(刷新页面),会进入
app.tsx
,执行getInitialState (opens new window)方法,其返回值会作为全局共享的数据 services/access.tx
文件中判断用户的访问权限,canAdmin
的值为true
时会被认为是具有管理员权限- 进入文件中修改判断代码
- 首次访问页面(刷新页面),会进入
修改好后,进入管理页面进行测试,显示的是预期的注册功能(因为pages是从注册文件夹复制过来的)
在路由配置中修改补充代码
# 前端开发(二)
使用ProComponents高级表单
- u
- 是
- 是
- 是
删除
src/pages/user/Register/index.tsx
的代码,只保留初始化的部分
补充代码
import React from "react"; const Register: React.FC = () => { return ( <div id="userManage"> </div> ); }; export default Register;
1
2
3
4
5
6
7
8
9到ProTable - 高级表格 - ProComponents (opens new window)找到合适的表格复制代码(这里复制第一个)
删除不需要用到的组件代码,修改我们需要的属性
import { EllipsisOutlined, PlusOutlined } from '@ant-design/icons'; import type { ActionType, ProColumns } from '@ant-design/pro-components'; import { ProTable, TableDropdown } from '@ant-design/pro-components'; import {Button, Dropdown, Image, Space, Tag} from 'antd'; import { useRef } from 'react'; import request from 'umi-request'; import CurrentUser = API.CurrentUser; export const waitTimePromise = async (time: number = 100) => { return new Promise((resolve) => { setTimeout(() => { resolve(true); }, time); }); }; export const waitTime = async (time: number = 100) => { await waitTimePromise(time); }; const columns: ProColumns<API.CurrentUser>[] = [ { dataIndex: 'id', valueType: 'indexBorder', width: 48, }, { title: '用户名', dataIndex: 'username', copyable: true, }, { title: '用户账户', dataIndex: 'userAccount', copyable: true, }, { title: '头像', dataIndex: 'avatarUrl', render: (_,record) => ( <div> <Image src={record.avatarUrl} width={50} height={50}/> //高度限制规格 </div> ), }, { title: '性别', dataIndex: 'gender', }, { title: '电话', dataIndex: 'phone', copyable: true, }, { title: '邮件', dataIndex: 'email', copyable: true, }, { title: '状态', dataIndex: 'userStatus', }, { title: '角色', dataIndex: 'userRole', valueType: 'select', valueEnum: { 0: { text: '普通用户', status:'Default', }, 1: { text: '管理员', status: 'Success', }, }, }, { title: '创建时间', key: 'createTime', valueType: 'dateTime', }, { title: '操作', valueType: 'option', key: 'option', render: (text, record, _, action) => [ <a key="editable" onClick={() => { action?.startEditable?.(record.id); }} > 编辑 </a>, <a href={record.url} target="_blank" rel="noopener noreferrer" key="view"> 查看 </a>, <TableDropdown key="actionGroup" onSelect={() => action?.reload()} menus={[ { key: 'copy', name: '复制' }, { key: 'delete', name: '删除' }, ]} />, ], }, ]; export default () => { const actionRef = useRef<ActionType>(); return ( <ProTable<API.CurrentUser> columns={columns} actionRef={actionRef} cardBordered request={async (params, sort, filter) => { console.log(sort, filter); await waitTime(2000); return request<{ data: CurrentUser[]; }>('https://proapi.azurewebsites.net/github/issues', { params, }); }} editable={{ type: 'multiple', }} columnsState={{ persistenceKey: 'pro-table-singe-demos', persistenceType: 'localStorage', defaultValue: { option: { fixed: 'right', disable: true }, }, onChange(value) { console.log('value: ', value); }, }} rowKey="id" search={{ labelWidth: 'auto', }} options={{ setting: { listsHeight: 400, }, }} form={{ // 由于配置了 transform,提交的参数与定义的不同这里需要转化一下 syncToUrl: (values, type) => { if (type === 'get') { return { ...values, created_at: [values.startTime, values.endTime], }; } return values; }, }} pagination={{ pageSize: 5, onChange: (page) => console.log(page), }} dateFormatter="string" headerTitle="高级表格" toolBarRender={() => [ /* 新建与选择菜单组件 */ <Button key="button" icon={<PlusOutlined />} onClick={() => { actionRef.current?.reload(); }} type="primary" > 新建 </Button>, <Dropdown key="menu" menu={{ items: [ { label: '1st item', key: '1', }, { label: '2nd item', key: '2', }, { label: '3rd item', key: '3', }, ], }} > <Button> <EllipsisOutlined /> </Button> </Dropdown>, ]} /> ); };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204此时前端页面显示如下
修改
src/pages/Admin.tsx
文件import { PageHeaderWrapper } from '@ant-design/pro-components'; import React from 'react'; const Admin: React.FC = (props) => { const {children} = props; return ( <PageHeaderWrapper> {children} </PageHeaderWrapper> ); }; export default Admin;
1
2
3
4
5
6
7
8
9
10
11
12显示效果如下
api.ts
文件里定义一个searchUsers接口(复制notices接口,进行修改)
/** 搜索用户 GET /api/search */
export async function searchUsers(options?: { [key: string]: any }) {
return request<API.NoticeIconList>('/api/user/search', {
method: 'GET',
...(options || {}),
});
}
2
3
4
5
6
7
发现函数没有被使用
原因就在于这里,要改成自己的api,原地址是一个测试文件
}>('http://localhost:8080/api/user/search', {
改完发现还是有问题的,因为没有传递管理页相关的参数,后端始终报错

在编程导航网站里找到了其他朋友写好的代码跟着鱼皮直播(终)做到用户管理的时候,引 - 编程导航 - 程序员编程学习交流社区 (opens new window)
这一段的代码应该改成下面的
request={async (params, sort, filter) => {
console.log(sort, filter);
await waitTime(2000);
const userList = await searchUsers();
return {
data: userListt
}
}}
2
3
4
5
6
7
8
这样就显示出来了
但还可以发现,创建时间是错误的,更新时间加上去之后也是错误的
对比数据库里的数据

对比前端发送请求得到响应的数据

后端在把数据发送给前端时,数据被转化成了 ISO 8601 格式(2025-03-28T10:56:52.000+00:00
)
Protable支持的属性:通用配置 - ProComponents (opens new window)
无语了(ˉ▽ˉ;)... 原因在于 key应该改为dataIndex
{
title: '创建时间',
key: 'createTime',
valueType: 'dateTime',
},
2
3
4
5
文字写于:广东