CRUD操作指南
📖 前言
本文档基于 yuppie 项目,详细介绍如何在 Spring Boot + MyBatis 框架下实现增删改查(CRUD)操作。
技术栈:
- Java 17
- Spring Boot 4.0.1
- MyBatis 3.0.3
- MySQL 8.0
示例模块:用户管理模块(SysUser)
📚 第一章:CRUD基础概念
1.1 什么是CRUD
CRUD是数据库操作的四种基本功能:
- Create(创建)- 插入数据
- Read(读取)- 查询数据
- Update(更新)- 修改数据
- Delete(删除)- 删除数据
1.2 项目结构
yuppie-system/ # 系统业务模块
├── src/main/java/com/yuppie/system/
│ ├── domain/ # 实体类
│ │ └── SysUser.java # 用户实体 与数据库表user对应
│ ├── mapper/ # 数据访问层
│ │ └── SysUserMapper.java # 用户Mapper接口
│ ├── service/ # 业务逻辑层
│ │ ├── ISysUserService.java # 用户Service接口
│ │ └── impl/
│ │ └── SysUserServiceImpl.java # 用户Service实现
│ └── controller/ # 控制层
│ └── SysUserController.java # 用户控制器
└── src/main/resources/mapper/
└── system/
└── SysUserMapper.xml # MyBatis映射文件
🏗️ 第二章:创建实体类(Domain)
2.1 创建用户实体类
文件路径 :src/main/java/com/yuppie/system/domain/SysUser.java
java
package com.yuppie.system.domain;
import com.yuppie.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
/**
* 用户实体类
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SysUser extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 用户ID */
private Long userId;
/** 部门ID */
private Long deptId;
/** 用户账号 */
@NotBlank(message = "用户账号不能为空")
@Size(min = 0, max = 50, message = "用户账号长度不能超过50个字符")
private String userName;
/** 用户昵称 */
@Size(min = 0, max = 50, message = "用户昵称长度不能超过50个字符")
private String nickName;
/** 用户邮箱 */
@Email(message = "邮箱格式不正确")
@Size(min = 0, max = 100, message = "邮箱长度不能超过100个字符")
private String email;
/** 手机号码 */
@Size(min = 0, max = 20, message = "手机号码长度不能超过20个字符")
private String phonenumber;
/** 用户性别 */
private String sex;
/** 头像地址 */
private String avatar;
/** 密码 */
private String password;
/** 帐号状态 */
private String status;
/** 删除标志 */
private String delFlag;
/** 最后登录IP */
private String loginIp;
/** 最后登录时间 */
private java.util.Date loginDate;
}
2.2 注解说明
| 注解 | 作用 | 示例 |
|---|---|---|
@Data |
自动生成getter/setter/toString等方法 | |
@EqualsAndHashCode(callSuper = true) |
生成equals和hashCode方法,包含父类属性 | |
@NotBlank |
验证字符串非空且长度大于0 | @NotBlank(message = "用户账号不能为空") |
@Size |
验证字符串长度范围 | @Size(min = 0, max = 50) |
@Email |
验证邮箱格式 | @Email(message = "邮箱格式不正确") |
💾 第三章:数据访问层(Mapper)
3.1 创建Mapper接口
文件路径 :src/main/java/com/yuppie/system/mapper/SysUserMapper.java
java
package com.yuppie.system.mapper;
import com.yuppie.system.domain.SysUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 用户Mapper接口
*/
@Mapper
public interface SysUserMapper {
/**
* 查询用户列表
*
* @return 用户列表
*/
List<SysUser> selectUserList();
/**
* 根据用户ID查询用户
*
* @param userId 用户ID
* @return 用户信息
*/
SysUser selectUserById(Long userId);
/**
* 根据用户名查询用户
*
* @param userName 用户名
* @return 用户信息
*/
SysUser selectUserByUserName(String userName);
/**
* 新增用户
*
* @param user 用户信息
* @return 结果
*/
int insertUser(SysUser user);
/**
* 修改用户
*
* @param user 用户信息
* @return 结果
*/
int updateUser(SysUser user);
/**
* 删除用户
*
* @param userId 用户ID
* @return 结果
*/
int deleteUserById(Long userId);
/**
* 批量删除用户
*
* @param userIds 需要删除的用户ID数组
* @return 结果
*/
int deleteUserByIds(Long[] userIds);
/**
* 检查用户名是否唯一
*
* @param userName 用户名
* @return 结果
*/
int checkUserNameUnique(String userName);
/**
* 检查邮箱是否唯一
*
* @param email 邮箱
* @return 用户信息
*/
SysUser checkEmailUnique(String email);
/**
* 检查手机号是否唯一
*
* @param phonenumber 手机号
* @return 用户信息
*/
SysUser checkPhoneUnique(String phonenumber);
}
3.2 创建MyBatis映射文件
文件路径 :src/main/resources/mapper/system/SysUserMapper.xml
xml
<?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="com.yuppie.system.mapper.SysUserMapper">
<!-- 结果映射 -->
<resultMap type="SysUser" id="SysUserResult">
<id property="userId" column="user_id" />
<result property="userName" column="user_name" />
<result property="nickName" column="nick_name" />
<result property="email" column="email" />
<result property="phonenumber" column="phonenumber" />
<result property="sex" column="sex" />
<result property="avatar" column="avatar" />
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="loginIp" column="login_ip" />
<result property="loginDate" column="login_date" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap>
<!-- 通用查询列 -->
<sql id="selectUserVo">
SELECT user_id, user_name, nick_name, email, phonenumber, sex, avatar, status, del_flag, login_ip, login_date, create_by, create_time, update_by, update_time, remark
FROM sys_user
</sql>
<!-- ========== 查询操作(Read) ========== -->
<!-- 查询用户列表 -->
<select id="selectUserList" resultMap="SysUserResult">
<include refid="selectUserVo" />
WHERE del_flag = '0'
</select>
<!-- 根据用户ID查询用户 -->
<select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
<include refid="selectUserVo" />
WHERE user_id = #{userId} AND del_flag = '0'
</select>
<!-- 根据用户名查询用户 -->
<select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
<include refid="selectUserVo" />
WHERE user_name = #{userName} AND del_flag = '0'
</select>
<!-- 检查用户名是否唯一 -->
<select id="checkUserNameUnique" parameterType="String" resultType="int">
SELECT COUNT(*) FROM sys_user WHERE user_name = #{userName}
</select>
<!-- 检查邮箱是否唯一 -->
<select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
<include refid="selectUserVo" />
WHERE email = #{email} AND del_flag = '0'
</select>
<!-- 检查手机号是否唯一 -->
<select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult">
<include refid="selectUserVo" />
WHERE phonenumber = #{phonenumber} AND del_flag = '0'
</select>
<!-- ========== 新增操作(Create) ========== -->
<!-- 新增用户 -->
<insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
INSERT INTO sys_user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="userName != null and userName != ''">user_name,</if>
<if test="nickName != null and nickName != ''">nick_name,</if>
<if test="email != null and email != ''">email,</if>
<if test="phonenumber != null and phonenumber != ''">phonenumber,</if>
<if test="sex != null and sex != ''">sex,</if>
<if test="avatar != null and avatar != ''">avatar,</if>
<if test="password != null and password != ''">password,</if>
<if test="status != null and status != ''">status,</if>
<if test="loginIp != null and loginIp != ''">login_ip,</if>
<if test="loginDate != null">login_date,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="remark != null and remark != ''">remark,</if>
</trim>
<trim prefix="VALUES (" suffix=")" suffixOverrides=",">
<if test="userName != null and userName != ''">#{userName},</if>
<if test="nickName != null and nickName != ''">#{nickName},</if>
<if test="email != null and email != ''">#{email},</if>
<if test="phonenumber != null and phonenumber != ''">#{phonenumber},</if>
<if test="sex != null and sex != ''">#{sex},</if>
<if test="avatar != null and avatar != ''">#{avatar},</if>
<if test="password != null and password != ''">#{password},</if>
<if test="status != null and status != ''">#{status},</if>
<if test="loginIp != null and loginIp != ''">#{loginIp},</if>
<if test="loginDate != null">#{loginDate},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="remark != null and remark != ''">#{remark},</if>
</trim>
</insert>
<!-- ========== 修改操作(Update) ========== -->
<!-- 修改用户 -->
<update id="updateUser" parameterType="SysUser">
UPDATE sys_user
<set>
<if test="userName != null and userName != ''">user_name = #{userName},</if>
<if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
<if test="email != null and email != ''">email = #{email},</if>
<if test="phonenumber != null and phonenumber != ''">phonenumber = #{phonenumber},</if>
<if test="sex != null and sex != ''">sex = #{sex},</if>
<if test="avatar != null and avatar != ''">avatar = #{avatar},</if>
<if test="password != null and password != ''">password = #{password},</if>
<if test="status != null and status != ''">status = #{status},</if>
<if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if>
<if test="loginDate != null">login_date = #{loginDate},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
update_time = NOW()
</set>
WHERE user_id = #{userId}
</update>
<!-- ========== 删除操作(Delete) ========== -->
<!-- 删除用户 -->
<delete id="deleteUserById" parameterType="Long">
DELETE FROM sys_user WHERE user_id = #{userId}
</delete>
<!-- 批量删除用户 -->
<delete id="deleteUserByIds" parameterType="Long">
DELETE FROM sys_user WHERE user_id IN
<foreach item="userId" collection="array" open="(" separator="," close=")">
#{userId}
</foreach>
</delete>
</mapper>
3.3 XML标签说明
| 标签 | 作用 | 属性 |
|---|---|---|
mapper |
根标签 | namespace:对应Mapper接口的全限定名 |
resultMap |
结果集映射 | id:唯一标识,type:实体类 |
select |
查询语句 | id:对应接口方法名,parameterType:参数类型,resultMap/resultType:返回类型 |
insert |
插入语句 | id:对应接口方法名,parameterType:参数类型,useGeneratedKeys:是否自动生成主键,keyProperty:主键属性名 |
update |
更新语句 | id:对应接口方法名,parameterType:参数类型 |
delete |
删除语句 | id:对应接口方法名,parameterType:参数类型 |
sql |
可重用的SQL片段 | id:唯一标识 |
include |
引用SQL片段 | refid:引用的SQL片段id |
trim |
去除多余的逗号或关键字 | prefix:前缀,suffix:后缀,suffixOverrides:去除后缀 |
set |
用于UPDATE语句,自动去除多余逗号 | |
foreach |
循环遍历集合 | item:集合元素,collection:集合类型,open:开始符号,separator:分隔符,close:结束符号 |
if |
条件判断 | test:判断条件 |
🧠 第四章:业务逻辑层(Service)
4.1 创建Service接口
文件路径 :src/main/java/com/yuppie/system/service/ISysUserService.java
java
package com.yuppie.system.service;
import com.yuppie.system.domain.SysUser;
import java.util.List;
/**
* 用户服务接口
*/
public interface ISysUserService {
/**
* 查询用户列表
*
* @return 用户列表
*/
List<SysUser> selectUserList();
/**
* 根据用户ID查询用户
*
* @param userId 用户ID
* @return 用户信息
*/
SysUser selectUserById(Long userId);
/**
* 根据用户名查询用户
*
* @param userName 用户名
* @return 用户信息
*/
SysUser selectUserByUserName(String userName);
/**
* 新增用户
*
* @param user 用户信息
* @return 结果
*/
int insertUser(SysUser user);
/**
* 修改用户
*
* @param user 用户信息
* @return 结果
*/
int updateUser(SysUser user);
/**
* 删除用户
*
* @param userId 用户ID
* @return 结果
*/
int deleteUserById(Long userId);
/**
* 批量删除用户
*
* @param userIds 需要删除的用户ID数组
* @return 结果
*/
int deleteUserByIds(Long[] userIds);
/**
* 检查用户名是否唯一
*
* @param user 用户信息
* @return 结果
*/
boolean checkUserNameUnique(SysUser user);
/**
* 检查邮箱是否唯一
*
* @param user 用户信息
* @return 结果
*/
boolean checkEmailUnique(SysUser user);
/**
* 检查手机号是否唯一
*
* @param user 用户信息
* @return 结果
*/
boolean checkPhoneUnique(SysUser user);
}
4.2 创建Service实现类
文件路径 :src/main/java/com/yuppie/system/service/impl/SysUserServiceImpl.java
java
package com.yuppie.system.service.impl;
import com.yuppie.system.domain.SysUser;
import com.yuppie.system.mapper.SysUserMapper;
import com.yuppie.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
/**
* 用户服务实现类
*/
@Service
public class SysUserServiceImpl implements ISysUserService {
@Autowired
private SysUserMapper userMapper;
/**
* 查询用户列表
*/
@Override
public List<SysUser> selectUserList() {
return userMapper.selectUserList();
}
/**
* 根据用户ID查询用户
*/
@Override
public SysUser selectUserById(Long userId) {
return userMapper.selectUserById(userId);
}
/**
* 根据用户名查询用户
*/
@Override
public SysUser selectUserByUserName(String userName) {
return userMapper.selectUserByUserName(userName);
}
/**
* 新增用户
*/
@Override
public int insertUser(SysUser user) {
// 设置默认值
if (user.getStatus() == null) {
user.setStatus("0"); // 0-正常,1-停用
}
if (user.getDelFlag() == null) {
user.setDelFlag("0"); // 0-存在,2-删除
}
if (user.getCreateTime() == null) {
user.setCreateTime(new Date());
}
return userMapper.insertUser(user);
}
/**
* 修改用户
*/
@Override
public int updateUser(SysUser user) {
return userMapper.updateUser(user);
}
/**
* 删除用户
*/
@Override
public int deleteUserById(Long userId) {
return userMapper.deleteUserById(userId);
}
/**
* 批量删除用户
*/
@Override
public int deleteUserByIds(Long[] userIds) {
return userMapper.deleteUserByIds(userIds);
}
/**
* 检查用户名是否唯一
*/
@Override
public boolean checkUserNameUnique(SysUser user) {
Long userId = user.getUserId() == null ? -1L : user.getUserId();
SysUser info = userMapper.selectUserByUserName(user.getUserName());
if (info != null && !info.getUserId().equals(userId)) {
return false; // 用户名已存在
}
return true; // 用户名唯一
}
/**
* 检查邮箱是否唯一
*/
@Override
public boolean checkEmailUnique(SysUser user) {
Long userId = user.getUserId() == null ? -1L : user.getUserId();
SysUser info = userMapper.checkEmailUnique(user.getEmail());
if (info != null && !info.getUserId().equals(userId)) {
return false; // 邮箱已存在
}
return true; // 邮箱唯一
}
/**
* 检查手机号是否唯一
*/
@Override
public boolean checkPhoneUnique(SysUser user) {
Long userId = user.getUserId() == null ? -1L : user.getUserId();
SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber());
if (info != null && !info.getUserId().equals(userId)) {
return false; // 手机号已存在
}
return true; // 手机号唯一
}
}
🎮 第五章:控制层(Controller)
5.1 创建Controller
文件路径 :src/main/java/com/yuppie/system/controller/SysUserController.java
java
package com.yuppie.system.controller;
import com.yuppie.common.core.domain.AjaxResult;
import com.yuppie.system.domain.SysUser;
import com.yuppie.system.service.ISysUserService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 用户控制器
*/
@RestController
@RequestMapping("/system/user")
public class SysUserController {
@Autowired
private ISysUserService userService;
/**
* 获取用户列表
*/
@GetMapping("/list")
public AjaxResult list() {
List<SysUser> list = userService.selectUserList();
return AjaxResult.success(list);
}
/**
* 根据用户ID获取详细信息
*/
@GetMapping("/{userId}")
public AjaxResult getInfo(@PathVariable Long userId) {
return AjaxResult.success(userService.selectUserById(userId));
}
/**
* 根据用户名获取详细信息
*/
@GetMapping("/name/{userName}")
public AjaxResult getByUserName(@PathVariable String userName) {
return AjaxResult.success(userService.selectUserByUserName(userName));
}
/**
* 新增用户
*/
@PostMapping
public AjaxResult add(@Valid @RequestBody SysUser user) {
// 检查用户名是否唯一
if (!userService.checkUserNameUnique(user)) {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,用户名已存在");
}
// 检查邮箱是否唯一
if (!userService.checkEmailUnique(user)) {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,邮箱已存在");
}
// 检查手机号是否唯一
if (!userService.checkPhoneUnique(user)) {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,手机号已存在");
}
int rows = userService.insertUser(user);
if (rows > 0) {
return AjaxResult.success("新增用户成功");
}
return AjaxResult.error("新增用户失败");
}
/**
* 修改用户
*/
@PutMapping
public AjaxResult edit(@Valid @RequestBody SysUser user) {
// 检查邮箱是否唯一
if (!userService.checkEmailUnique(user)) {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱已存在");
}
// 检查手机号是否唯一
if (!userService.checkPhoneUnique(user)) {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号已存在");
}
int rows = userService.updateUser(user);
if (rows > 0) {
return AjaxResult.success("修改用户成功");
}
return AjaxResult.error("修改用户失败");
}
/**
* 删除用户
*/
@DeleteMapping("/{userIds}")
public AjaxResult remove(@PathVariable Long[] userIds) {
int rows = userService.deleteUserByIds(userIds);
if (rows > 0) {
return AjaxResult.success("删除用户成功");
}
return AjaxResult.error("删除用户失败");
}
}
5.2 注解说明
| 注解 | 作用 | 示例 |
|---|---|---|
@RestController |
组合注解,相当于@Controller + @ResponseBody |
|
@RequestMapping |
映射请求路径 | @RequestMapping("/system/user") |
@GetMapping |
映射GET请求 | @GetMapping("/list") |
@PostMapping |
映射POST请求 | @PostMapping |
@PutMapping |
映射PUT请求 | @PutMapping |
@DeleteMapping |
映射DELETE请求 | @DeleteMapping |
@PathVariable |
获取URL路径参数 | @PathVariable Long userId |
@RequestBody |
获取请求体JSON数据 | @RequestBody SysUser user |
@Valid |
启用参数验证 | @Valid @RequestBody SysUser user |
@Autowired |
自动注入依赖 | @Autowired private ISysUserService userService; |
🚀 第六章:API测试
6.1 启动项目
bash
# 方式1:IDE中启动
# 找到 YuppieAdminApplication.java,右键 Run
# 方式2:Maven命令
cd yuppie-admin
mvn spring-boot:run
6.2 测试接口
基础URL :http://localhost:8085/system/user
6.2.1 查询用户列表
bash
# GET请求
curl http://localhost:8085/system/user/list
响应示例:
json
{
"code": 200,
"msg": "操作成功",
"data": [
{
"userId": 1,
"userName": "admin",
"nickName": "管理员",
"email": "admin@yuppie.com",
"status": "0",
"createTime": "2024-01-01 10:00:00"
},
{
"userId": 2,
"userName": "test",
"nickName": "测试用户",
"email": "test@yuppie.com",
"status": "0",
"createTime": "2024-01-01 10:00:00"
}
]
}
6.2.2 根据ID查询用户
bash
# GET请求
curl http://localhost:8085/system/user/1
响应示例:
json
{
"code": 200,
"msg": "操作成功",
"data": {
"userId": 1,
"userName": "admin",
"nickName": "管理员",
"email": "admin@yuppie.com",
"status": "0",
"createTime": "2024-01-01 10:00:00"
}
}
6.2.3 根据用户名查询用户
bash
# GET请求
curl http://localhost:8085/system/user/name/admin
6.2.4 新增用户
bash
# POST请求
curl -X POST http://localhost:8085/system/user \
-H "Content-Type: application/json" \
-d '{
"userName": "newuser",
"nickName": "新用户",
"email": "newuser@yuppie.com",
"phonenumber": "13900139000",
"password": "123456"
}'
成功响应:
json
{"code": 200, "msg": "新增用户成功", "data": null}
失败响应:
json
{"code": 500, "msg": "新增用户'newuser'失败,用户名已存在", "data": null}
6.2.5 修改用户
bash
# PUT请求
curl -X PUT http://localhost:8085/system/user \
-H "Content-Type: application/json" \
-d '{
"userId": 3,
"nickName": "修改后的昵称",
"email": "updated@yuppie.com"
}'
响应示例:
json
{"code": 200, "msg": "修改用户成功", "data": null}
6.2.6 删除用户
bash
# DELETE请求
curl -X DELETE http://localhost:8085/system/user/3
响应示例:
json
{"code": 200, "msg": "删除用户成功", "data": null}
6.2.7 批量删除用户
bash
# DELETE请求
curl -X DELETE http://localhost:8085/system/user/3,4,5
📝 第七章:高级特性
7.1 分页查询
步骤1:修改Mapper接口
java
// SysUserMapper.java
List<SysUser> selectUserList(SysUser user);
步骤2:修改Mapper XML
xml
<!-- SysUserMapper.xml -->
<select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
<include refid="selectUserVo" />
WHERE del_flag = '0'
<if test="userName != null and userName != ''">
AND user_name LIKE CONCAT('%', #{userName}, '%')
</if>
<if test="status != null and status != ''">
AND status = #{status}
</if>
</select>
步骤3:修改Service
java
// ISysUserService.java
List<SysUser> selectUserList(SysUser user);
// SysUserServiceImpl.java
@Override
public List<SysUser> selectUserList(SysUser user) {
return userMapper.selectUserList(user);
}
步骤4:修改Controller
java
// SysUserController.java
@GetMapping("/list")
public AjaxResult list(SysUser user) {
// 使用PageHelper分页
PageHelper.startPage(1, 10); // 第1页,每页10条
List<SysUser> list = userService.selectUserList(user);
return AjaxResult.success(new PageInfo<>(list));
}
7.2 逻辑删除
推荐使用逻辑删除(标记删除),而不是物理删除:
sql
-- 添加删除标志字段
ALTER TABLE sys_user ADD COLUMN del_flag CHAR(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)';
-- 查询时过滤已删除数据
SELECT * FROM sys_user WHERE del_flag = '0';
-- 逻辑删除
UPDATE sys_user SET del_flag = '2' WHERE user_id = #{userId};
7.3 参数验证
java
// 在实体类中添加验证注解
public class SysUser {
@NotBlank(message = "用户账号不能为空")
@Size(min = 2, max = 50, message = "用户账号长度必须在2-50个字符之间")
private String userName;
@Email(message = "邮箱格式不正确")
private String email;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号码格式不正确")
private String phonenumber;
}
// 在Controller中使用@Valid启用验证
@PostMapping
public AjaxResult add(@Valid @RequestBody SysUser user) {
// ...
}
🎯 第八章:最佳实践
8.1 命名规范
| 层 | 命名规则 | 示例 |
|---|---|---|
| 实体类 | 大驼峰 | SysUser |
| Mapper接口 | 大驼峰 + Mapper | SysUserMapper |
| Service接口 | I + 大驼峰 + Service | ISysUserService |
| Service实现类 | 大驼峰 + ServiceImpl | SysUserServiceImpl |
| Controller | 大驼峰 + Controller | SysUserController |
| 数据库表 | 小写 + 下划线 | sys_user |
| 数据库字段 | 小写 + 下划线 | user_name |
8.2 SQL优化
-
索引优化
sql-- 为经常查询的字段添加索引 CREATE INDEX idx_user_name ON sys_user(user_name); CREATE INDEX idx_email ON sys_user(email); -
**避免SELECT ***
sql-- 不推荐 SELECT * FROM sys_user; -- 推荐 SELECT user_id, user_name, email FROM sys_user; -
使用连接查询
sql-- 避免子查询 SELECT u.*, d.dept_name FROM sys_user u LEFT JOIN sys_dept d ON u.dept_id = d.dept_id;
8.3 异常处理
java
// Service层
@Override
public SysUser selectUserById(Long userId) {
if (userId == null || userId <= 0) {
throw new RuntimeException("用户ID无效");
}
SysUser user = userMapper.selectUserById(userId);
if (user == null) {
throw new RuntimeException("用户不存在");
}
return user;
}
// Controller层
@GetMapping("/{userId}")
public AjaxResult getInfo(@PathVariable Long userId) {
try {
return AjaxResult.success(userService.selectUserById(userId));
} catch (RuntimeException e) {
return AjaxResult.error(e.getMessage());
}
}
8.4 事务管理
java
@Service
public class SysUserServiceImpl implements ISysUserService {
@Autowired
private SysUserMapper userMapper;
@Autowired
private SysUserRoleMapper userRoleMapper;
/**
* 新增用户(带事务)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public int insertUser(SysUser user) {
// 插入用户
int rows = userMapper.insertUser(user);
// 插入用户角色关联
if (user.getRoleIds() != null && user.getRoleIds().length > 0) {
userRoleMapper.insertUserRole(user.getUserId(), user.getRoleIds());
}
return rows;
}
}
❌ 第九章:常见问题
9.1 Mapper接口找不到
问题 :No qualifying bean of type 'SysUserMapper'
解决方案:
-
确保Mapper接口添加了
@Mapper注解 -
确保
@MapperScan扫描包正确java@MapperScan(basePackages = "com.yuppie.*.mapper")
9.2 MyBatis XML文件找不到
问题 :Could not find resource mapper/system/SysUserMapper.xml
解决方案:
-
确保XML文件路径正确:
src/main/resources/mapper/system/SysUserMapper.xml -
确保pom.xml配置了资源过滤:
xml<build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*</include> </includes> </resource> </resources> </build>
9.3 参数绑定失败
问题 :Parameter 'userName' not found
解决方案:
-
确保方法参数名与XML中一致
-
使用
@Param注解指定参数名:javaList<SysUser> selectUserList(@Param("userName") String userName);
9.4 日期格式化问题
问题:日期返回JSON格式不正确
解决方案:
-
使用
@JsonFormat注解:java@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; -
在application.yml中配置全局格式化:
yamlspring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8
📚 附录:常用SQL语句
A.1 创建表
sql
CREATE TABLE `sys_user` (
`user_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`dept_id` BIGINT(20) DEFAULT NULL COMMENT '部门ID',
`user_name` VARCHAR(50) NOT NULL COMMENT '用户账号',
`nick_name` VARCHAR(50) DEFAULT NULL COMMENT '用户昵称',
`email` VARCHAR(100) DEFAULT NULL COMMENT '用户邮箱',
`phonenumber` VARCHAR(20) DEFAULT NULL COMMENT '手机号码',
`sex` CHAR(1) DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',
`avatar` VARCHAR(255) DEFAULT NULL COMMENT '头像地址',
`password` VARCHAR(200) DEFAULT NULL COMMENT '密码',
`status` CHAR(1) DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
`del_flag` CHAR(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
`login_ip` VARCHAR(128) DEFAULT NULL COMMENT '最后登录IP',
`login_date` DATETIME DEFAULT NULL COMMENT '最后登录时间',
`create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
`update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
`remark` VARCHAR(500) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`user_id`),
UNIQUE KEY `uk_user_name` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';
A.2 插入测试数据
sql
INSERT INTO `sys_user`
(`user_name`, `nick_name`, `email`, `phonenumber`, `sex`, `password`, `status`, `create_by`, `create_time`)
VALUES
('admin', '管理员', 'admin@yuppie.com', '13800138000', '0', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', 'admin', NOW()),
('test', '测试用户', 'test@yuppie.com', '13800138001', '0', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', 'admin', NOW());
A.3 常用查询
sql
-- 查询所有用户
SELECT * FROM sys_user WHERE del_flag = '0';
-- 根据用户名查询
SELECT * FROM sys_user WHERE user_name = 'admin' AND del_flag = '0';
-- 模糊查询
SELECT * FROM sys_user WHERE user_name LIKE '%test%' AND del_flag = '0';
-- 统计用户数量
SELECT COUNT(*) FROM sys_user WHERE del_flag = '0';
-- 分页查询
SELECT * FROM sys_user WHERE del_flag = '0' LIMIT 0, 10;
-- 查询最近注册的10个用户
SELECT * FROM sys_user WHERE del_flag = '0' ORDER BY create_time DESC LIMIT 10;
🎉 总结
通过本文档,你已经学会了:
✅ CRUD的完整实现流程
- 创建实体类(Domain)
- 编写Mapper接口和XML映射文件
- 实现Service业务逻辑
- 编写Controller接口
✅ MyBatis的常用标签
select、insert、update、deleteresultMap、sql、includeif、trim、set、foreach
✅ RESTful API设计
- GET:查询
- POST:新增
- PUT:修改
- DELETE:删除
✅ 参数验证和异常处理
- 使用
@Valid进行参数验证 - 统一返回格式(AjaxResult)
下一步:可以尝试实现其他模块(如部门管理、角色管理、菜单管理等),巩固所学知识!
感谢阅读!祝你学习愉快! 🚀
本文档基于 yuppie 项目编写