后端开发CRUD实现

目录

[一、环境依赖(pom.xml 核心依赖)](#一、环境依赖(pom.xml 核心依赖))

二、数据库表设计(以sys_user为例)

三、核心代码实现

[1. 实体类(Entity)](#1. 实体类(Entity))

[2. DTO 类(数据传输对象)](#2. DTO 类(数据传输对象))

[(1)新增 / 修改请求 DTO](#(1)新增 / 修改请求 DTO)

[(2)条件查询相关 DTO: 涵盖单条件精确查询、多条件组合查询、模糊查询、范围查询等常见场景](#(2)条件查询相关 DTO: 涵盖单条件精确查询、多条件组合查询、模糊查询、范围查询等常见场景)

[(3)响应 DTO](#(3)响应 DTO)

[3. MapStruct 映射接口](#3. MapStruct 映射接口)

[4. Mapper 接口(MyBatis-Plus)](#4. Mapper 接口(MyBatis-Plus))

[5. Service 层(业务逻辑)](#5. Service 层(业务逻辑))

[(1)Service 接口](#(1)Service 接口)

[(2)Service 实现类](#(2)Service 实现类)

[6. Controller 层(接口暴露)](#6. Controller 层(接口暴露))

四、关键配置

[1. MyBatis-Plus 配置](#1. MyBatis-Plus 配置)

[2. application.yml 配置](#2. application.yml 配置)


基于 Spring Boot + MyBatis-Plus + MapStruct 的完整 CRUD 实现,包含实体、DTO、映射、Service、Controller 全流程。

一、环境依赖(pom.xml 核心依赖)

复制代码
<!-- Spring Boot Web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- MyBatis-Plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>

<!-- MapStruct(DTO与Entity映射) -->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.5.Final</version>
    <scope>provided</scope>
</dependency>

<!-- 数据库驱动(以MySQL为例) -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- Lombok(简化实体类) -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

二、数据库表设计(以sys_user为例)

复制代码
CREATE TABLE `sys_user` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(100) NOT NULL COMMENT '密码',
  `email` varchar(100) DEFAULT NULL COMMENT '邮箱',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

三、核心代码实现

1. 实体类(Entity)

与数据库表字段一一对应,用于 MyBatis-Plus 操作数据库

复制代码
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;

@Data
@TableName("sys_user")
public class UserEntity {
    @TableId(type = IdType.AUTO)
    private Long id;                // 主键ID
    private String username;        // 用户名
    private String password;        // 密码
    private String email;           // 邮箱
    private LocalDateTime createTime; // 创建时间
    private LocalDateTime updateTime; // 更新时间
}

2. DTO 类(数据传输对象)

用于接收前端请求参数和返回响应数据,避免直接暴露 Entity。

(1)新增 / 修改请求 DTO
复制代码
// 新增用户请求DTO
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;

@Data
public class UserAddDTO {
    @NotBlank(message = "用户名不能为空")
    @Size(max = 50, message = "用户名长度不能超过50字符")
    private String username;        // 用户名

    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度需在6-20字符之间")
    private String password;        // 密码

    @Email(message = "邮箱格式不正确")
    private String email;           // 邮箱
}

// 修改用户请求DTO
@Data
public class UserUpdateDTO {
    @NotBlank(message = "用户ID不能为空")
    private Long id;                // 主键ID(修改需传)

    @Size(max = 50, message = "用户名长度不能超过50字符")
    private String username;        // 用户名(可选修改)

    @Size(min = 6, max = 20, message = "密码长度需在6-20字符之间")
    private String password;        // 密码(可选修改)

    @Email(message = "邮箱格式不正确")
    private String email;           // 邮箱(可选修改)
}
(2)条件查询相关 DTO: 涵盖单条件精确查询、多条件组合查询、模糊查询、范围查询等常见场景
复制代码
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Pattern;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 用户表条件查询DTO
 * 支持:分页参数、模糊查询、精确查询、范围查询、多值查询、排序参数
 * 说明:所有参数均为可选,不传则不参与筛选
 */
@Data
public class UserQueryDTO {

    // ======================== 分页参数(用于分页查询,非分页查询可忽略) ========================
    /**
     * 页码(默认1,最小1)
     */
    @Min(value = 1, message = "页码不能小于1")
    private Integer pageNum = 1;

    /**
     * 每页条数(默认10,最小1,最大100)
     */
    @Min(value = 1, message = "每页条数不能小于1")
    @Max(value = 100, message = "每页条数不能大于100")
    private Integer pageSize = 10;


    // ======================== 模糊查询条件 ========================
    /**
     * 用户名(模糊匹配,例如输入"张"可查询所有姓张的用户)
     */
    private String username;

    /**
     * 邮箱(模糊匹配,例如输入"example.com"可查询所有该域名的邮箱)
     * 格式要求:为空或符合邮箱格式(如xxx@xxx.com)
     */
    @Pattern(regexp = "^$|^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$", message = "邮箱格式不正确(可为空)")
    private String email;


    // ======================== 精确查询条件 ========================
    /**
     * 用户状态(精确匹配:1-正常,2-禁用,不传则不筛选)
     */
    private Integer status;


    // ======================== 范围查询条件 ========================
    /**
     * 创建时间起始(>=,格式:yyyy-MM-dd HH:mm:ss,例如"2023-01-01 00:00:00")
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTimeStart;

    /**
     * 创建时间结束(<,格式:yyyy-MM-dd HH:mm:ss,例如"2023-12-31 23:59:59")
     */
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTimeEnd;

    /**
     * 用户ID范围起始(>=,例如100表示查询ID>=100的用户)
     */
    private Long idStart;

    /**
     * 用户ID范围结束(<=,例如200表示查询ID<=200的用户)
     */
    private Long idEnd;


    // ======================== 多值查询条件 ========================
    /**
     * 用户ID列表(精确匹配列表中的ID,例如[1,2,3]表示查询ID为1、2、3的用户)
     */
    private List<Long> idList;

    /**
     * 排除的用户ID列表(排除列表中的ID,例如[4,5,6]表示查询ID不是4、5、6的用户)
     */
    private List<Long> excludeIdList;


    // ======================== 排序参数 ========================
    /**
     * 排序字段(默认createTime,可选值:id、username、createTime)
     */
    @Pattern(regexp = "^$|id|username|createTime", message = "排序字段只能是id、username、createTime")
    private String sortField = "createTime";

    /**
     * 排序方式(asc-升序,desc-降序,默认desc)
     */
    @Pattern(regexp = "^(asc|desc)$", message = "排序方式只能是asc或desc")
    private String sortOrder = "desc";
}
(3)响应 DTO
复制代码
// 用户响应DTO(前端展示用,隐藏敏感字段如密码)
import lombok.Data;
import java.time.LocalDateTime;

@Data
public class UserRespDTO {
    private Long id;                // 主键ID
    private String username;        // 用户名
    private String email;           // 邮箱
    private LocalDateTime createTime; // 创建时间
}

3. MapStruct 映射接口

用于 DTO 与 Entity 之间的自动转换,替代手动BeanUtils.copyProperties

复制代码
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;

// 映射接口,componentModel = "spring"表示交给Spring管理
@Mapper(componentModel = "spring")
public interface UserMapper {
    // 单例实例(也可通过Spring注入)
    UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

    // UserAddDTO -> UserEntity(新增时转换)
    UserEntity addDtoToEntity(UserAddDTO dto);

    // UserUpdateDTO -> UserEntity(更新时转换,覆盖已有字段)
    void updateDtoToEntity(UserUpdateDTO dto, @MappingTarget UserEntity entity);

    // UserEntity -> UserRespDTO(查询响应时转换)
    UserRespDTO entityToRespDto(UserEntity entity);
}

4. Mapper 接口(MyBatis-Plus)

继承BaseMapper,无需手动写 SQL(简单 CRUD)。

复制代码
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;

@Repository
public interface UserMapper extends BaseMapper<UserEntity> {
    // 复杂查询可在此添加注解SQL或XML映射
}

5. Service 层(业务逻辑)

(1)Service 接口
复制代码
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;

public interface UserService extends IService<UserEntity> {
    // 新增用户
    boolean addUser(UserAddDTO dto);

    // 修改用户
    boolean updateUser(UserUpdateDTO dto);

    // 根据ID删除用户
    boolean removeUserById(Long id);

    // 根据ID查询用户
    UserRespDTO getUserById(Long id);

    // 查询所有用户
    List<UserRespDTO> listAllUsers();
}
(2)Service 实现类
复制代码
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {

    @Autowired
    private UserMapper userMapper; // MapStruct映射接口

    @Override
    public boolean addUser(UserAddDTO dto) {
        // DTO转Entity
        UserEntity entity = userMapper.addDtoToEntity(dto);
        // 保存到数据库
        return save(entity);
    }

    @Override
    public boolean updateUser(UserUpdateDTO dto) {
        // 先查询原实体
        UserEntity entity = getById(dto.getId());
        if (entity == null) {
            return false; // 用户不存在
        }
        // DTO数据更新到Entity
        userMapper.updateDtoToEntity(dto, entity);
        // 保存更新
        return updateById(entity);
    }

    @Override
    public boolean removeUserById(Long id) {
        return removeById(id);
    }

    @Override
    public UserRespDTO getUserById(Long id) {
        UserEntity entity = getById(id);
        return entity != null ? userMapper.entityToRespDto(entity) : null;
    }

    @Override
    public List<UserRespDTO> listAllUsers() {
        List<UserEntity> entityList = list();
        // 批量Entity转DTO
        return entityList.stream()
                .map(userMapper::entityToRespDto)
                .collect(Collectors.toList());
    }
}

6. Controller 层(接口暴露)

接收前端请求,调用 Service 处理,返回响应结果。

复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    // 新增用户
    @PostMapping
    public ResponseEntity<Boolean> addUser(@Validated @RequestBody UserAddDTO dto) {
        boolean success = userService.addUser(dto);
        return new ResponseEntity<>(success, HttpStatus.CREATED);
    }

    // 修改用户
    @PutMapping
    public ResponseEntity<Boolean> updateUser(@Validated @RequestBody UserUpdateDTO dto) {
        boolean success = userService.updateUser(dto);
        return ResponseEntity.ok(success);
    }

    // 删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Boolean> removeUser(@PathVariable Long id) {
        boolean success = userService.removeUserById(id);
        return ResponseEntity.ok(success);
    }

    // 根据ID查询用户
    @GetMapping("/{id}")
    public ResponseEntity<UserRespDTO> getUserById(@PathVariable Long id) {
        UserRespDTO dto = userService.getUserById(id);
        return dto != null ? ResponseEntity.ok(dto) : ResponseEntity.notFound().build();
    }

    // 查询所有用户
    @GetMapping
    public ResponseEntity<List<UserRespDTO>> listAllUsers() {
        List<UserRespDTO> dtoList = userService.listAllUsers();
        return ResponseEntity.ok(dtoList);
    }
}
@Validated 分组校验

新增用户时无需校验 id ,修改时必须校验 id ,可通过分组实现:

7. 全局异常处理(捕获校验失败信息)

添加全局异常处理器,统一返回校验失败的提示,避免直接返回 400 原始错误:

复制代码
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

/**
 * 全局异常处理器:处理参数校验失败异常
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 捕获 @Validated 分组校验失败的异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        // 获取所有校验失败的字段信息
        BindingResult bindingResult = ex.getBindingResult();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            // 字段名 -> 错误提示
            errors.put(fieldError.getField(), fieldError.getDefaultMessage());
        }
        return errors;
    }
}

校验失败示例响应:

复制代码
{
  "username": "用户名不能为空",
  "password": "密码长度需在6-20字符之间"
}

四、关键配置

1. MyBatis-Plus 配置

复制代码
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.example.demo.mapper") // Mapper接口所在包
public class MyBatisPlusConfig {

    // 分页插件(可选,用于复杂查询分页)
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

2. application.yml 配置

复制代码
spring:
  # 数据库配置
  datasource:
    url: jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  # 实体类包名(用于自动扫描)
  type-aliases-package: com.example.demo.entity
  #  mapper.xml文件路径(若有自定义SQL)
  mapper-locations: classpath:mapper/*.xml
  # 日志配置(打印SQL,开发环境用)
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
相关推荐
晓13135 小时前
第七章 【C语言篇:文件】 文件全面解析
linux·c语言·开发语言
愚者游世5 小时前
Delegating Constructor(委托构造函数)各版本异同
开发语言·c++·程序人生·面试·改行学it
一 乐5 小时前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
KIKIiiiiiiii5 小时前
微信个人号API二次开发中的解决经验
java·人工智能·python·微信
梵刹古音5 小时前
【C语言】 指针基础与定义
c语言·开发语言·算法
80530单词突击赢5 小时前
SpringBoot整合SpringMVC全解析
java·spring boot·后端
Ekehlaft5 小时前
这款国产 AI,让 Python 小白也能玩转编程
开发语言·人工智能·python·ai·aipy
rit84324995 小时前
MATLAB中Teager能量算子提取与解调信号的实现
开发语言·matlab
开源技术5 小时前
Python GeoPandas基础知识:地图、投影和空间连接
开发语言·ide·python
vx1_Biye_Design5 小时前
基于Spring Boot+Vue的学生管理系统设计与实现-计算机毕业设计源码46223
java·vue.js·spring boot·spring·eclipse·tomcat·maven