发布于2026-05-31 阅读(0)
扫一扫,手机访问
如果想给 MyBatis-Plus 的增删改查做一套通用的封装,思路其实很直接:利用泛型加继承,把 Mapper、Service、Controller 三层的通用逻辑一次性写好,后续的业务模块直接继承这些通用类,再也不用一遍遍地写那些雷同的 CRUD 代码了。

下面给出完整的实现方案,环境基于 Spring Boot,上手即用。
先把通用响应类准备好,保证所有接口返回的格式一致,后边写 CRUD 时能省不少事。
package com.example.mpdemo.common; import lombok.Data; /** * 通用响应结果类 * @param响应数据类型 */ @Data public class Result { // 响应码(200成功,500失败) private Integer code; // 响应消息 private String msg; // 响应数据 private T data; // 成功响应(无数据) public static Result success() { return new Result<>(200, "操作成功", null); } // 成功响应(有数据) public static Result success(T data) { return new Result<>(200, "操作成功", data); } // 失败响应 public static Result fail(String msg) { return new Result<>(500, msg, null); } }
MyBatis-Plus 自带的 BaseMapper 已经提供了基本的 CRUD 方法,我们只需要定义一个通用接口,让所有业务 Mapper 去继承它就行。
package com.example.mpdemo.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; /** * 通用 Mapper 接口 * @param实体类类型 */ @Mapper public interface BaseGenericMapper extends BaseMapper { // 无需额外方法,继承 BaseMapper 的 17 个基础 CRUD 方法即可 }
Service 层也走同样的路子——先定义通用接口,再写一个通用的实现类,把 IService 的高级能力复用起来。
(1)通用 Service 接口
package com.example.mpdemo.service; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; import ja va.io.Serializable; import ja va.util.List; /** * 通用 Service 接口 * @param实体类类型 */ public interface BaseGenericService extends IService { // 可扩展通用方法,比如自定义分页、批量操作等 List list(Wrapper queryWrapper); // 条件查询列表 IPage page(IPage page, Wrapper queryWrapper); // 条件分页查询 T getById(Serializable id); // 根据 ID 查询 boolean sa veEntity(T entity); // 新增 boolean updateEntity(T entity); // 修改 boolean removeById(Serializable id); // 根据 ID 删除 }
(2)通用 Service 实现类
package com.example.mpdemo.service.impl; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.mpdemo.mapper.BaseGenericMapper; import com.example.mpdemo.service.BaseGenericService; import ja va.io.Serializable; import ja va.util.List; /** * 通用 Service 实现类 * @paramMapper 类型 * @param 实体类类型 */ public class BaseGenericServiceImpl , T> extends ServiceImpl implements BaseGenericService { @Override public List list(Wrapper queryWrapper) { return baseMapper.selectList(queryWrapper); } @Override public IPage page(IPage page, Wrapper queryWrapper) { return baseMapper.selectPage(page, queryWrapper); } @Override public T getById(Serializable id) { return baseMapper.selectById(id); } @Override public boolean sa veEntity(T entity) { return sa ve(entity); // 复用 IService 的 sa ve 方法 } @Override public boolean updateEntity(T entity) { return updateById(entity); // 复用 IService 的 updateById 方法 } @Override public boolean removeById(Serializable id) { return baseMapper.deleteById(id); } }
这一层是重头戏——封装好了通用的增删改查接口,业务 Controller 直接继承,连 HTTP 映射都不用自己写。
package com.example.mpdemo.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.mpdemo.common.Result; import com.example.mpdemo.service.BaseGenericService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import ja va.io.Serializable; import ja va.util.List; /** * 通用 CRUD Controller * @param实体类类型 * @param 主键类型(如 Long、String) */ public class BaseGenericController { // 注入通用 Service(由子类指定具体实现) @Autowired protected BaseGenericService baseService; /** * 1. 新增 */ @PostMapping public Result add(@RequestBody T entity) { boolean success = baseService.sa veEntity(entity); return success ? Result.success(entity) : Result.fail("新增失败"); } /** * 2. 根据 ID 删除 */ @DeleteMapping("/{id}") public Result delete(@PathVariable K id) { boolean success = baseService.removeById(id); return success ? Result.success() : Result.fail("删除失败"); } /** * 3. 修改 */ @PutMapping public Result update(@RequestBody T entity) { boolean success = baseService.updateEntity(entity); return success ? Result.success(entity) : Result.fail("修改失败"); } /** * 4. 根据 ID 查询 */ @GetMapping("/{id}") public Result getById(@PathVariable K id) { T entity = baseService.getById(id); return entity != null ? Result.success(entity) : Result.fail("数据不存在"); } /** * 5. 查询所有(无条件) */ @GetMapping("/list") public Result > list() { List
list = baseService.list(Wrappers.emptyWrapper()); return Result.success(list); } /** * 6. 分页查询(默认第1页,每页10条,可传参数自定义) */ @GetMapping("/page") public Result > page( @RequestParam(defaultValue = "1") Long current, @RequestParam(defaultValue = "10") Long size) { IPage page = baseService.page(new Page<>(current, size), Wrappers.emptyWrapper()); return Result.success(page); } }
有了上面的通用层,写一个 User 的 CRUD 有多轻松?看下面几步就知道。
实体类保持不变,直接用之前的定义:
package com.example.mpdemo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import ja va.time.LocalDateTime;
@Data
@TableName("user")
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String username;
private Integer age;
private String email;
private LocalDateTime createTime;
}
直接继承通用 Mapper 接口,一行额外代码都不需要:
package com.example.mpdemo.mapper; import com.example.mpdemo.entity.User; import org.springframework.stereotype.Repository; @Repository public interface UserMapper extends BaseGenericMapper{ // 无需编写任何代码,自动拥有所有基础 CRUD 能力 }
(1)Service 接口
package com.example.mpdemo.service; import com.example.mpdemo.entity.User; public interface UserService extends BaseGenericService{ // 可扩展自定义业务方法 }
(2)Service 实现类
package com.example.mpdemo.service.impl; import com.example.mpdemo.entity.User; import com.example.mpdemo.mapper.UserMapper; import com.example.mpdemo.service.UserService; import org.springframework.stereotype.Service; @Service public class UserServiceImpl extends BaseGenericServiceImplimplements UserService { // 无需编写任何代码,自动继承通用 Service 的所有方法 }
继承通用 Controller,指定实体和主键类型,所有接口自动生效:
package com.example.mpdemo.controller;
import com.example.mpdemo.entity.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户控制器,继承通用 Controller 后自动拥有所有 CRUD 接口
*/
@RestController
@RequestMapping("/user")
public class UserController extends BaseGenericController {
// 无需编写任何接口代码,自动拥有:
// POST /user → 新增
// DELETE /user/{id} → 删除
// PUT /user → 修改
// GET /user/{id} → 根据ID查询
// GET /user/list → 查询所有
// GET /user/page → 分页查询
}
| 接口 | 请求方式 | 说明 | 示例请求参数 |
|---|---|---|---|
| /user | POST | 新增用户 | {"username":"张三","age":20,"email":"zhangsan@example.com","createTime":"2026-03-13 10:00:00"} |
| /user/1 | DELETE | 删除用户 | 路径参数 id=1 |
| /user | PUT | 修改用户 | {"id":1,"username":"张三","age":21} |
| /user/1 | GET | 查询单个用户 | 路径参数 id=1 |
| /user/list | GET | 查询所有用户 | 无参数 |
| /user/page?current=1&size=2 | GET | 分页查询 | 参数 current=1(页码)、size=2(每页条数) |
// UserController 中新增条件查询接口
@GetMapping("/listByAge")
public Result> listByAge(@RequestParam Integer age) {
LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(User.class)
.gt(User::getAge, age);
List list = baseService.list(wrapper);
return Result.success(list);
}
@RestControllerAdvice 写一个全局异常处理器,统一捕获 CRUD 过程中可能出现的异常(比如主键不存在、参数不合法等);@PreAuthorize 等注解即可;@NotNull、@NotBlank 之类的校验注解,然后在 Controller 参数前加 @Valid,让校验自动生效。这种封装方式能极大减少重复劳动,符合开闭原则,在企业级项目里算是 MyBatis-Plus 的常用最佳实践。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8