前端
登录页面就是一个让用户输入账号和密码的表单
使用acro组件
先写布局
<a-form-item field="userAccount" label="账号">
<a-input v-model="form.userAccount" placeholder="请输入账号" />
</a-form-item>
<a-form-item field="userPassword" tooltip="密码不少于 8 位" label="密码">
<a-input-password
v-model="form.userPassword"
placeholder="请输入密码"
/>
</a-form-item>
这边调用
之前生成的代码
我们在js里面写代码
这边是把表单提交到这个请求上去
我们实际上在这边是进行表单的填写
再统一发给后端这个接口
但是我们还是要执行一下全局状态管理
把未登录替换成多多
我们这边还是未登录
我们要从前端的请求出发开始排查
可以看到
我们这边还是未登录的状态
原因是前端和后端根本就没有任何关联
我们要去修改openapi里面的配置
然后就能获取
<template>
<div id="userLoginView" class="Login">
<h2 style="margin-bottom: 16px">用户登录</h2>
<a-form
style="max-width: 480px; margin: 0 auto"
label-align="left"
auto-label-width
:model="form"
@submit="handleSubmit"
>
<a-form-item field="userAccount" label="账号">
<a-input v-model="form.userAccount" placeholder="请输入账号" />
</a-form-item>
<a-form-item field="userPassword" tooltip="密码不少于 8 位" label="密码">
<a-input-password
v-model="form.userPassword"
placeholder="请输入密码"
/>
</a-form-item>
<a-form-item>
<div style="display: flex; justify-content: center" class="register">
<a-space class="wrapper" direction="vertical">
<a-button type="primary" html-type="submit" style="width: 120px">
登录
</a-button>
</a-space>
</div>
</a-form-item>
</a-form>
</div>
</template>
<style>
.wrapper {
width: 360px;
/*padding: 20px;*/
border-radius: 4px;
}
.Login {
background: linear-gradient(to bottom, #f0f2f5, #ffffff); /* 示例渐变背景 */
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
</style>
<script setup lang="ts">
import { reactive } from "vue";
import { UserControllerService, UserLoginRequest } from "../../../generated";
import message from "@arco-design/web-vue/es/message";
import { useRouter } from "vue-router";
import { useStore } from "vuex";
/**
* 表单信息
*/
const form = reactive({
userAccount: "",
userPassword: "",
} as UserLoginRequest);
const router = useRouter();
const store = useStore();
/**
* 提交表单
* @param data
*/
const handleSubmit = async () => {
const res = await UserControllerService.userLoginUsingPost(form);
// 登录成功,跳转到主页
if (res.code === 0) {
await store.dispatch("user/getLoginUser");
message.success("登陆成功 欢迎你!");
router.push({
path: "/questions",
replace: true,
});
} else {
message.error("登陆失败," + res.message);
}
};
</script>
改了一晚上的前端布局
后端
我们来看一下这个接口的具体实现
Controller层
我们传入的参数有两个
UserLoginRequest
是包含用户登录信息的请求体,通常包括账号和密码等字段;HttpServletRequest
是代表HTTP请求的对象,提供有关请求的各种信息,如请求头、参数和会话等。这两个参数共同支持用户的登录过程。
可以,只使用 UserLoginRequest
参数也是可行的。你可以在 UserLoginRequest
中添加必要的上下文信息,比如会话ID或其他请求信息。不过,通常使用 HttpServletRequest
可以提供更多的灵活性和功能。
核心逻辑判断了一些是否为空的内容
已经控制台输出
我们看一下service层的核心代码逻辑
接口
实现类
-
校验输入 :检查
userAccount
和userPassword
是否为空,确保账号长度不小于4,密码长度不小于8。如果不符合条件,抛出BusinessException
。 -
加密密码 :使用MD5加密算法对用户输入的密码进行加密,结合一个盐值
SALT
,以增强安全性。 -
查询用户 :构造数据库查询条件,通过
userAccount
和加密后的userPassword
查找用户。如果找不到匹配的用户,记录失败信息并抛出异常。 -
记录登录状态:如果用户存在,将用户信息存储在HTTP会话中,以维护用户的登录状态。
-
返回用户信息 :调用
getLoginUserVO
方法,将用户信息转换为LoginUserVO
对象并返回。@Override public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) { // 1. 校验 if (StringUtils.isAnyBlank(userAccount, userPassword)) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空"); } if (userAccount.length() < 4) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误"); } if (userPassword.length() < 8) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误"); } // 2. 加密 String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes()); // 查询用户是否存在 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("userAccount", userAccount); queryWrapper.eq("userPassword", encryptPassword); User user = this.baseMapper.selectOne(queryWrapper); // 用户不存在 if (user == null) { log.info("user login failed, userAccount cannot match userPassword"); throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误"); } // 3. 记录用户的登录态 request.getSession().setAttribute(USER_LOGIN_STATE, user); return this.getLoginUserVO(user); }
LoginUserVO
是一个数据传输对象(DTO),通常用于封装用户登录后的信息,比如用户ID、用户名、角色、权限等。它的主要目的是在用户成功登录后,向客户端返回必要的用户信息,以便于后续操作。
注意
使用 LoginUserVO
而不是直接封装 User
主要是为了提高安全性和灵活性。LoginUserVO
可以只包含必要的字段,避免泄露敏感信息(如密码)。
此外,它允许在不同场景中定制返回的数据结构,以满足前端需求或简化数据传输。