Boost Your Spring Boot CRUD with MyBatisPlusPro: A Step‑by‑Step Guide
This tutorial shows how to extend MyBatis‑Plus functionality to the controller layer by creating a reusable BaseController, utility methods, pagination configuration, and concrete controllers, enabling full CRUD, list, page, and count operations with minimal code.
When using MyBatisPlus in a Spring Boot project, most developers only implement CRUD operations at the DAO layer. This guide introduces MybatisPlusPro, a set of utilities that let you obtain full CRUD, list, pagination, sorting, and count features simply by extending a BaseController class.
Step 1: Add MyBatisPlus dependency
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>Step 2: Create utility class
/**
* Apprentice system Util
* @author MaSiyi
* @version 1.0.0 2021/11/26
* @since JDK 1.8.0
*/
public class ApprenticeUtil {
private static Pattern humpPattern = Pattern.compile("[A-Z]");
private static Pattern linePattern = Pattern.compile("_(\\w)");
/** Convert camelCase to snake_case */
public static String humpToLine(String str) {
Matcher matcher = humpPattern.matcher(str);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
}
matcher.appendTail(sb);
return sb.toString();
}
/** Convert snake_case to camelCase */
public static String lineToHump(String str) {
str = str.toLowerCase();
Matcher matcher = linePattern.matcher(str);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
}
matcher.appendTail(sb);
return sb.toString();
}
/** Build QueryWrapper from an entity */
public static <E> QueryWrapper<E> getQueryWrapper(E entity) {
Field[] fields = entity.getClass().getDeclaredFields();
QueryWrapper<E> eQueryWrapper = new QueryWrapper<>();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (Modifier.isFinal(field.getModifiers())) {
continue;
}
field.setAccessible(true);
try {
Object obj = field.get(entity);
if (!ObjectUtils.isEmpty(obj)) {
String name = ApprenticeUtil.humpToLine(field.getName());
eQueryWrapper.eq(name, obj);
}
} catch (IllegalAccessException e) {
return null;
}
}
return eQueryWrapper;
}
/** Get field value via reflection */
public static <E> Object getValueForClass(E entity, String value) {
Field id = null;
PropertyDescriptor pd = null;
try {
id = entity.getClass().getDeclaredField(value);
pd = new PropertyDescriptor(id.getName(), entity.getClass());
} catch (NoSuchFieldException | IntrospectionException e) {
e.printStackTrace();
}
Method getMethod = Objects.requireNonNull(pd).getReadMethod();
return ReflectionUtils.invokeMethod(getMethod, entity);
}
}The reflection utilities allow dynamic extraction of field names and values, converting between camelCase and snake_case to match database column naming conventions.
Step 3: Write BaseController class
/** Core public controller */
public class BaseController<S extends IService<E>, E> {
@Autowired
protected S baseService;
@ApiOperation("增")
@PostMapping("/insert")
public ResponseUtils insert(@RequestBody E entity) {
baseService.save(entity);
return ResponseUtils.success("添加成功");
}
@ApiOperation("删")
@PostMapping("/deleteById")
public ResponseUtils delete(@RequestBody List<Integer> ids) {
baseService.removeByIds(ids);
return ResponseUtils.success("添加成功");
}
@ApiOperation("改")
@PostMapping("/updateById")
public ResponseUtils updateById(@RequestBody E entity) {
baseService.updateById(entity);
return ResponseUtils.success("添加成功");
}
@ApiOperation("查")
@GetMapping("/getById")
public ResponseUtils getById(@RequestParam Integer id) {
return ResponseUtils.success(baseService.getById(id));
}
@ApiOperation("存")
@PostMapping("/save")
public ResponseUtils save(@RequestBody E entity) {
baseService.saveOrUpdate(entity);
return ResponseUtils.success("添加成功");
}
@ApiOperation("list查")
@PostMapping("/list")
public ResponseUtils list(@RequestBody E entity) {
QueryWrapper<E> queryWrapper = ApprenticeUtil.getQueryWrapper(entity);
List<E> list = baseService.list(queryWrapper);
return ResponseUtils.success(list);
}
@ApiOperation("page查")
@PostMapping("/page")
public ResponseUtils page(@RequestBody PageParamDto<E> pageParamDto) {
if (pageParamDto.getPage() < 1) {
pageParamDto.setPage(1);
}
if (pageParamDto.getSize() > 100) {
pageParamDto.setSize(100);
}
Page<E> page = new Page<>(pageParamDto.getPage(), pageParamDto.getSize());
QueryWrapper<E> queryWrapper = new QueryWrapper<>();
String asc = pageParamDto.getAsc();
if (!StrUtil.isEmpty(asc) && !"null".equals(asc)) {
queryWrapper.orderByAsc(asc.split(","));
}
String desc = pageParamDto.getDesc();
if (!StrUtil.isEmpty(desc) && !"null".equals(desc)) {
queryWrapper.orderByDesc(desc.split(","));
}
Page<E> ePage = baseService.page(page, queryWrapper);
return ResponseUtils.success(ePage);
}
@ApiOperation("获取数量")
@PostMapping("/count")
public ResponseUtils count(@RequestBody E entity) {
QueryWrapper<E> queryWrapper = ApprenticeUtil.getQueryWrapper(entity);
long count = baseService.count(queryWrapper);
return ResponseUtils.success(count);
}
}The generic BaseController provides five basic HTTP operations (POST, GET) for any entity type, exposing them as RESTful APIs via Spring Boot annotations.
Step 4: Enable pagination support
@Configuration
public class MybatisPlusConfig {
/** Set pagination interceptor */
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}Step 5: Extend BaseController in your own controllers
@RestController
@RequestMapping("/apprentice/dynamic")
@Api("动态管理")
public class DynamicController extends BaseController<IDynamicService, Dynamic> {
}
@RestController
@RequestMapping("/apprentice/blog")
@Api(tags = "博客管理")
public class BlogController extends BaseController<IBlogService, Blog> {
}By inheriting BaseController and specifying the service and entity types, the concrete controllers instantly gain default CRUD endpoints.
Java Interview Crash Guide
Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
