四、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 项目编写

相关推荐
小怪吴吴20 小时前
idea 开发Android
android·java·intellij-idea
嘻嘻哈哈樱桃20 小时前
牛客经典101题题解集--动态规划
java·数据结构·python·算法·职场和发展·动态规划
一次旅行20 小时前
IDEA安装CC GUI新手指南
java·ide·intellij-idea
超梦dasgg21 小时前
Spring AI 智能航空助手项目实战
java·人工智能·后端·spring·ai编程
counting money21 小时前
Spring框架基础(配置篇)
java·后端·spring
秋91 天前
OceanBase与GreatSQL在Java应用中的性能调优方法有哪些?
java·开发语言·oceanbase
今天又在写代码1 天前
并发问题解决
java·开发语言·数据库
老王以为1 天前
前端视角下的 Java
java·javascript·程序员
看腻了那片水1 天前
开源一个对业务代码零侵入的透明数据治理框架 —— 【sangsang】
java·mybatis