本项目是基于ant-design开发的一个前端项目,项目的上线地址:http://user-front.66bond.com/

本项目的开发软件:

  • webstorm2021:关注公众号”青椒工具”,发送”webstorm”获取安装包下载链接;

之前已经将登录跑通,但是今天还余下一个小尾巴,前端登录页时,出现如下的问题:

图4.1currentUser问题

图1 currentUser问题

全局搜索,定位到api.ts中的currentUser方法,其中的代码如下:

1
2
3
4
5
6
7
8
9
** 获取当前的用户 GET /api/currentUser */
export async function currentUser(options?: { [key: string]: any }) {
return request<{
data: API.CurrentUser;
}>('/api/currentUser', {
method: 'GET',
...(options || {}),
});
}

由于我们后端的currentUser路径为:/user/current/,所以我们要对应的修改上述代码中涉及的url路劲;

1
2
3
4
5
6
7
8
9
** 获取当前的用户 GET /api/user/current */
export async function currentUser(options?: { [key: string]: any }) {
return request<{
data: API.CurrentUser;
}>('/api/user/current', {
method: 'GET',
...(options || {}),
});
}

修改成上述后,图1中的问题解决。

1、注册页面:

注册页面与登录页面类似,所以我们直接复制登录页面,然后在登录页面上修改。

操作:鼠标选中”Login”目录,然后右键复制,再鼠标选中”user/“目录,鼠标右键粘贴,然后重命名目录为”Register”。

1.1 修改方法与接口

然后将index.tsx中的Login组件名,重命名为Register,具体修改的地方如下:

1
2
3
const Login: React.FC = () => {
const [userLoginState] = useState<API.LoginResult>({});
...

修改为:

1
2
3
const Register: React.FC = () => {
const [userLoginState] = useState<API.LoginResult>({});
...

index.tsx文件尾部的export语句也要修改如下:

1
export default Register;

其他的内容我们暂时不修改,快速地来看看如何让浏览器可以访问到我们新创建的注册页。

1.2 配置路由

所谓路由,就是用户在浏览器中输入什么网址,才能访问到我们的Register模块;参照/config/routes.ts中的源代码;

我们添加关于Register的路由条目,代码如下:

1
2
3
4
5
6
7
routes: [
{ name: '登录', path: '/user/login', component: './user/Login' },
/**
* 新增注册路由
*/
{name: '注册', path:'/user/register', component: './user/Register'},
{ component: './404' },

然后,我们再浏览中输入”localhost:8000/user/register”

让人意外的是,我们并没有登录到新创建的register页面,而是直接重定向到login页面。这是什么原因呢?

采用关键词”重定向”全局上搜索,发现在app.tsx中出现重定向的字眼,具体onPageChange()这个方法中:

1
2
3
4
5
6
7
8
onPageChange: () => {
const { location } = history;

// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== loginPath) {
history.push(loginPath);
}
}

我们首先要确定的一点:上述代码是否在浏览器中输入”localhostL8000/user/register”时被调用。一个方法就是我们在上述代码中插入alter语句:

1
2
3
4
5
6
7
8
9
onPageChange: () => {
const { location } = history;
alert("onPagechange called");

// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== loginPath) {
history.push(loginPath);
}
}

保存刷新后,我们在浏览器中再次访问:localhostL8000/user/register,看到”onPagechange called”字眼的弹窗,如图2所示,

图4.2onpagechange-裁剪

图2 onPageChange()方法执行

当前onPageChange方法的逻辑是如果当前没有登录且不是登录页,那么就重定向到login页。

要使得register页面不跳转,我们可以修改上述并重新实现如下的逻辑:

  • 如果当前的路径属于login或者register,则返回,不进行定向;

修改后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
onPageChange: () => {
const { location } = history;
const whiteList = ['/user/register', loginPath];
if(whiteList.includes(location.pathname)){
return;
}
// alert("onPageChange() called!!!");

// 如果没有登录,重定向到 login
// if (!initialState?.currentUser && location.pathname !== loginPath) {
if (!initialState?.currentUser) {
history.push(loginPath);
}
}

保存刷新,我们在浏览器中再次访问:localhostL8000/user/register,这次可以看到register页面,图3所示:

图4.3register页面裁剪后

图3 直接访问到register页面
1.3 修改注册页的界面;

我们将登录页修改为注册页,主要的改动:

  • 增加确认密码输入框;
  • 删除”自动登录”和”忘记密码”;
  • 将蓝色按钮中的”登录”二字修改为”注册”;

步骤1,增加到/user/register/index.tsx中的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ProFormText.Password
name="checkPassword"
fieldProps={{
size: 'large',
prefix: <LockOutlined className={styles.prefixIcon} />,
}}
placeholder={'请确认密码:'}
rules={[
{
required: true,
message: '密码是必填项!',
},
]}
/>

步骤2,就不多说了,直接删除相关代码即可。

步骤3,/user/register/index.tsx文件中没有”登录”和”button”相关的关键词,另外就关键词”登录”全局搜索,没有找到。

因为LoginForm是ant design的组件,我们看下它的源代码。

知识点:要查看组件代码,可以点击工具栏的圆轮形按钮,“选择打开的文件”,如下图所示;

图4.4LoginForm裁剪后的查看源码

图4 查看LoginForm源代码

点击”index.js”,查找到关于”登录”的源码:

1
2
3
searchConfig: {
submitText: intl.getMessage('loginForm.submitText', '登录')
},

我们参照上述的代码,在/Register/index.tsx修改:

1
2
3
4
5
submitter={{
searchConfig:{
submitText:'注册'
}
}}

重新刷新,可以看到按钮的”登录”字眼修改为”注册”:

图4.5注册页面-裁剪版

图5 注册页面
1.4 修改注册接口名称与参数:

访问后端的接口参数要增加checkPassword,所以要对handleSubmit中的接口和参数作相应修改:

  • 将register的index.tsx中handleSubmit中的login接口名修改为register;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const handleSubmit = async (values: API.RegisterParams) => {
    try {
    // 注册
    // const msg = await login({
    const user = await register({
    ...values,
    type,
    });
    // if (msg.status === 'ok') {
  • 参照login接口,书写register接口代码:

1
2
3
4
5
6
7
8
9
10
11
/** 登录接口 POST /api/user/register */
export async function register(body: API.RegisterParams, options?: { [key: string]: any }) {
return request<API.RegisterResult>('/api/user/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}

上述的API.RegisterParams可以参考API.LoginParams,代码为:

1
2
3
4
5
6
type RegisterParams = {
userAccount?: string;
userPassword?: string;
checkPassword?: string;
type?: string;
};

注册成功返回的是用户的id,所以对应的API.RegisterResult的定义如下:

1
type RegisterResult = number;

将Register/index.tsx中handleSubmit()方法中的参数修改为API.RegisterParams,具体如下:

1
2
3
4
5
6
7
8
9
const handleSubmit = async (values: API.RegisterParams) => {
try {
// 登录
// const msg = await login({
const user = await register({
...
onFinish={async (values) => {
await handleSubmit(values as API.RegisterParams);
}}
1.5 完善注册业务逻辑代码:

在表单提交数据之前,对数据进行简单的校验;

  • 从参数中取出userPassword和checkPassword,判断两者是否相等;
1
2
3
4
5
6
const {userAccount, userPassword, checkPassword} = values;

if(userPassword !== checkPassword){
message.error('两次密码输入不相同!!');
return;
}

因为后端注册成功是返回一个大于零的用户id,Long类型;所以返回的类型判断要修改为如下:

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
const handleSubmit = async (values: API.RegisterParams) => {

const {userAccount, userPassword, checkPassword} = values;
if(userPassword !== checkPassword){
message.error('两次密码输入不相同!!');
return;
}

try {
// 登录
// const msg = await login({
const id = await register({
...values,
type,
});
// if (msg.status === 'ok') {
if(id >= 0){
const defaultLoginSuccessMessage = '注册成功!';
message.success(defaultLoginSuccessMessage);
await fetchUserInfo();
/** 此方法会跳转到 redirect 参数所在的位置 */
if (!history) return;
const { query } = history.location;
const { redirect } = query as {
redirect: string;
};
// history.push(redirect || '/');
/**
* 注册完毕后,跳转到login界面;
*/
history.push('/user/login');
return;
}else throw new Error(`注册页出错 error=${id}`);
// console.log(msg);
// // 如果失败去设置用户错误信息
// setUserLoginState(msg);
}

保存刷新后,浏览器输入”localhost:8000/user/register”,输入用户名和密码,发现注册成功,可以获取返回的id,浏览器访问标头如下:

1
2
3
4
5
6
7
8
9
10
请求 URL:
http://localhost:8000/api/user/register
请求方法:
POST
状态代码:
200 OK
远程地址:
127.0.0.1:8000
引用者策略:
strict-origin-when-cross-origin

响应如下:

1
8

数字为8,表示当前注册的用户id是8。至此我们就完成了注册页的添加。

2、参考资料:

本文参考自如下知识星球中的视频教程,更多的完整的相关视频教程,见如下的收费知识星球,近3万人的学习社区,

编程有人同行,学习不再迷茫

编程导航知识星球