引言
本系统允许用户输入用户名和密码,前端通过AJAX请求将数据发送到后端,后端验证并存储用户信息,同时为每个用户创建一个专属图书表。尽管这是一个基础实现,但它展示了前后端分离开发的核心思想。博客还将讨论潜在的优化点,如密码安全和数据库设计。
1. 约定前后端交互接口
前后端分离开发需要明确的接口约定,以确保数据交互顺畅。在本系统中,前端通过HTTP POST请求将用户注册信息发送到后端的/user/register
端点,后端返回JSON格式的响应,指示注册结果。
请求格式
前端发送的请求包含以下字段:
{
"userName": "exampleUser",
"password": "examplePassword"
}
- userName:用户输入的用户名,字符串类型。
- password:用户输入的密码,字符串类型。
响应格式
后端返回的JSON对象包含以下字段:
{
"status": "SUCCESS" | "FAIL",
"errorMessage": "错误信息(如果有)"
}
- status:表示注册结果,
SUCCESS
表示成功,FAIL
表示失败。 - errorMessage:当注册失败时,提供错误原因,如“用户已存在”或“请填写账号密码”。
2. 整体逻辑
用户注册系统的逻辑分为前端和后端两部分。前端负责用户输入验证和数据发送,后端处理数据存储和业务逻辑。后端采用经典的三层架构:Controller、Service和Mapper。
2.1 Controller的逻辑
Controller层是后端的入口,负责接收前端的HTTP请求,调用Service层处理业务逻辑,并返回响应。在本系统中,UserInfoController
类的register
方法处理/user/register
请求:
- 参数验证:检查传入的
UserInfo
对象是否为空。 - 调用Service:将请求委托给
userInfoService.registerUserInfo
方法。 - 响应处理:根据Service层的返回结果,设置响应的状态和错误消息。
2.2 Service层
Service层封装业务逻辑,确保注册过程的完整性和事务性。UserInfoService
类的registerUserInfo
方法执行以下步骤:
- 检查用户是否存在:查询数据库,确认用户名是否已被注册。
- 插入新用户:如果用户名可用,将用户信息插入数据库。
- 创建图书表:为新用户创建一个专属的图书表,存储其图书信息。
- 事务管理:使用
@Transactional
注解确保操作的原子性。
2.3 Mapper层
Mapper层通过MyBatis与数据库交互,执行SQL操作。UserInfoMapper
接口定义了三个关键方法:
- queryUserInfoByUserNameNormal:根据用户名查询用户信息,用于检查用户是否存在。
- insertUserInfo:插入新用户记录。
- createBooktable:为用户创建图书表,表名以用户ID命名。
MyBatis的XML映射文件定义了createBooktable
的SQL语句,使用动态表名创建图书表。
3. 后端代码实现
以下是后端代码的详细实现,分为Controller和Service层。
3.1 Controller层
UserInfoController
类处理用户注册请求:
@Slf4j
@RestController
@RequestMapping("/user")
public class UserInfoController {
@RequestMapping("/register")
public Result register(UserInfo userInfo){
Result result = new Result();
if(userInfo == null){
result.setStatus(ResultStatus.FAIL);
result.setErrorMessage("请填写账号密码");
return result;
}
result = userInfoService.registerUserInfo(userInfo);
if(result == null){
result.setStatus(ResultStatus.FAIL);
result.setErrorMessage("注册失败");
log.info("注册时,Service返回的result为空");
return result;
}
result.setStatus(ResultStatus.SUCCESS);
return result;
}
}
- 注解说明:
@RestController
:标记为REST控制器,返回JSON响应。@RequestMapping("/user")
:设置基础路径,所有请求以/user
开头。@RequestMapping("/register")
:映射/user/register
路径。
- 逻辑流程:
- 检查
userInfo
是否为空,若为空,返回错误。 - 调用Service层的
registerUserInfo
方法。 - 处理Service返回结果,若为空,记录日志并返回错误;否则返回成功。
- 检查
3.2 Service层
UserInfoService
类实现注册的业务逻辑:
@Slf4j
@Service
public class UserInfoService {
@Transactional
public Result registerUserInfo(UserInfo userInfo){
Result result = new Result();
UserInfo getUserInfo = userInfoMapper.queryUserInfoByUserNameNormal(userInfo.getUserName());
if(getUserInfo != null){
result.setErrorMessage("用户已存在,请重新注册");
result.setStatus(ResultStatus.FAIL);
return result;
}
Integer count = userInfoMapper.insertUserInfo(userInfo);
if(count == 1){
result.setStatus(ResultStatus.SUCCESS);
UserInfo u = userInfoMapper.queryUserInfoByUserNameNormal(userInfo.getUserName());
userInfoMapper.createBooktable(u.getId());
return result;
}else{
result.setStatus(ResultStatus.FAIL);
result.setErrorMessage("用户注册失败");
log.info("新用户插入后返回的值不是1");
return result;
}
}
}
- 注解说明:
@Service
:标记为Spring的服务组件。@Transactional
:确保方法内的数据库操作具有事务性。
- 逻辑流程:
- 调用
queryUserInfoByUserNameNormal
检查用户名是否已存在。 - 若不存在,调用
insertUserInfo
插入用户。 - 检查插入结果,若成功(
count == 1
),查询新用户ID并调用createBooktable
创建图书表。 - 若失败,记录日志并返回错误。
- 调用
3.3 Mapper层实现
UserInfoMapper
接口定义了数据库操作:
@Mapper
public interface UserInfoMapper {
@Select("select id,user_name,password,delete_flag,create_time,updata_time from normal_user_info where user_name= #{userName}")
UserInfo queryUserInfoByUserNameNormal(String userName);
@Insert("insert into normal_user_info (user_name,password) values(#{userName},#{password})")
Integer insertUserInfo(UserInfo userInfo);
Integer createBooktable(Integer userId);
}
对应的MyBatis XML映射文件定义了createBooktable
的SQL:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.booksmanagementsystem.mapper.UserInfoMapper">
<update id="createBooktable">
create table #{id}_book_info(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`book_name` VARCHAR(127) NOT NULL,
`author` VARCHAR(127) NOT NULL,
`count` INT(11) NOT NULL,
`price` DECIMAL(7,2) NOT NULL,
`publish` VARCHAR(256) NOT NULL,
`status` TINYINT(4) DEFAULT 1 COMMENT '0-无效, 1-正常, 2-不允许借阅',
`create_time` DATETIME DEFAULT now(),
`update_time` DATETIME DEFAULT now() ON UPDATE now(),
PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
</update>
</mapper>
- 关键点:
queryUserInfoByUserNameNormal
使用@Select
注解执行查询。insertUserInfo
使用@Insert
注解插入数据。createBooktable
在XML中定义,动态创建表,表名以用户ID为前缀。
4. 前端代码
前端代码包括HTML表单和JavaScript逻辑,使用Bootstrap美化界面,jQuery处理AJAX请求。
HTML代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户注册</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/register.css">
</head>
<body>
<div class="container-login">
<div class="container-pic"></div>
<div class="login-dialog">
<h3>新用户注册</h3>
<form id="registerForm">
<div class="row">
<span>账户</span>
<input type="text" name="username" id="username" class="form-control" required>
</div>
<div class="row">
<span>密码</span>
<input type="password" name="password" id="password" class="form-control" required>
</div>
<div class="row">
<span>确认密码</span>
<input type="password" name="confirmPassword" id="confirmPassword" class="form-control" required>
</div>
<div class="row" style="margin-top: 20px;">
<div class="col-md-6">
<button type="button" class="btn btn-success btn-lg btn-block" onclick="submitRegister()">立即注册</button>
</div>
<div class="col-md-6">
<button type="button" class="btn btn-secondary btn-lg btn-block" onclick="history.back()">返回登录</button>
</div>
</div>
</form>
</div>
</div>
- 结构说明:
- 使用Bootstrap的
form-control
类美化输入框。 - 包含用户名、密码和确认密码三个输入字段。
- 提供“立即注册”和“返回登录”两个按钮。
- 使用Bootstrap的
JavaScript代码
function submitRegister() {
// 基础验证
if ($("#password").val() !== $("#confirmPassword").val()) {
alert("两次密码输入不一致!");
return;
}
$.ajax({
url: "/user/register",
type: "post",
data: {
"userName": $("#username").val(),
"password": $("#password").val()
},
success: function(result) {
if(result.status == "SUCCESS") {
alert("注册成功!");
location.href = "login_test.html";
} else {
alert("注册失败,请重试");
}
}
});
}
功能说明:
- 密码验证:先检查密码和确认密码是否一致,不一致则弹出提示并停止。
- AJAX请求:密码一致时,通过POST请求发送到/user/register,携带用户名和密码。
- 响应处理:成功时,若状态为"SUCCESS",弹出成功提示并跳转到登录页;失败时,弹出失败提示。
5 .总结
本博客详细解析了用户注册系统的实现,从前端表单设计到后端业务逻辑,涵盖了HTML、JavaScript、Spring Boot和MyBatis的集成。系统允许用户注册并为每个用户创建专属图书表,体现了前后端分离开发的优势。