四、CRUD操作指南

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 测试接口

基础URLhttp://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优化

  1. 索引优化

    sql 复制代码
    -- 为经常查询的字段添加索引
    CREATE INDEX idx_user_name ON sys_user(user_name);
    CREATE INDEX idx_email ON sys_user(email);
  2. **避免SELECT ***

    sql 复制代码
    -- 不推荐
    SELECT * FROM sys_user;
    
    -- 推荐
    SELECT user_id, user_name, email FROM sys_user;
  3. 使用连接查询

    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'

解决方案

  1. 确保Mapper接口添加了@Mapper注解

  2. 确保@MapperScan扫描包正确

    java 复制代码
    @MapperScan(basePackages = "com.yuppie.*.mapper")

9.2 MyBatis XML文件找不到

问题Could not find resource mapper/system/SysUserMapper.xml

解决方案

  1. 确保XML文件路径正确:src/main/resources/mapper/system/SysUserMapper.xml

  2. 确保pom.xml配置了资源过滤:

    xml 复制代码
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*</include>
                </includes>
            </resource>
        </resources>
    </build>

9.3 参数绑定失败

问题Parameter 'userName' not found

解决方案

  1. 确保方法参数名与XML中一致

  2. 使用@Param注解指定参数名:

    java 复制代码
    List<SysUser> selectUserList(@Param("userName") String userName);

9.4 日期格式化问题

问题:日期返回JSON格式不正确

解决方案

  1. 使用@JsonFormat注解:

    java 复制代码
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
  2. 在application.yml中配置全局格式化:

    yaml 复制代码
    spring:
      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的常用标签

  • selectinsertupdatedelete
  • resultMapsqlinclude
  • iftrimsetforeach

RESTful API设计

  • GET:查询
  • POST:新增
  • PUT:修改
  • DELETE:删除

参数验证和异常处理

  • 使用@Valid进行参数验证
  • 统一返回格式(AjaxResult)

下一步:可以尝试实现其他模块(如部门管理、角色管理、菜单管理等),巩固所学知识!


感谢阅读!祝你学习愉快! 🚀


本文档基于 yuppie 项目编写

相关推荐
2301_780669862 小时前
文件字节流输出、文件复制、关闭流的方法
java
剑锋所指,所向披靡!3 小时前
C++之类模版
java·jvm·c++
Coder_Boy_4 小时前
基于SpringAI的在线考试系统-0到1全流程研发:DDD、TDD与CICD协同实践
java·人工智能·spring boot·架构·ddd·tdd
sheji34164 小时前
【开题答辩全过程】以 面向高校校园的物物交换系统设计与实现为例,包含答辩的问题和答案
java·eclipse
卓怡学长4 小时前
m115乐购游戏商城系统
java·前端·数据库·spring boot·spring·游戏
2501_944526424 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 蜘蛛纸牌游戏实现
android·java·python·flutter·游戏
打工的小王5 小时前
java并发编程(三)CAS
java·开发语言
尤老师FPGA5 小时前
使用ZYNQ芯片和LVGL框架实现用户高刷新UI设计系列教程(第四十五讲)
android·java·ui
星火开发设计5 小时前
C++ 函数定义与调用:程序模块化的第一步
java·开发语言·c++·学习·函数·知识