Backend Development 9 min read

Boost Your Spring Boot CRUD with MyBatisPlusPro: A Complete Guide

This article walks you through creating a reusable BaseController using MyBatisPlusPro, including dependency setup, utility methods for reflection, a generic CRUD controller, pagination configuration, and how to extend it in your own Spring Boot applications.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Boost Your Spring Boot CRUD with MyBatisPlusPro: A Complete Guide

MybatisPlusPro provides a ready‑to‑use BaseController that grants CRUD, list, pagination, sorting, and count operations simply by extending a generic class.

Step 1: Add MyBatisPlus dependency

<code>&lt;dependency&gt;
  &lt;groupId&gt;com.baomidou&lt;/groupId&gt;
  &lt;artifactId&gt;mybatis-plus-boot-starter&lt;/artifactId&gt;
  &lt;version&gt;3.4.2&lt;/version&gt;
&lt;/dependency&gt;</code>

Step 2: Write utility class

<code>/** Apprentice system Util */
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 (Field field : fields) {
            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) {
        try {
            Field id = entity.getClass().getDeclaredField(value);
            PropertyDescriptor pd = new PropertyDescriptor(id.getName(), entity.getClass());
            Method getMethod = Objects.requireNonNull(pd).getReadMethod();
            return ReflectionUtils.invokeMethod(getMethod, entity);
        } catch (NoSuchFieldException | IntrospectionException e) {
            e.printStackTrace();
            return null;
        }
    }
}</code>

The above utilities handle camel‑to‑snake conversion, build query conditions, and retrieve field values via reflection.

Step 3: Create generic BaseController

<code>/** Core public controller */
public class BaseController<S extends IService<E>, E> {
    @Autowired
    protected S baseService;

    @ApiOperation("Insert")
    @PostMapping("/insert")
    public ResponseUtils insert(@RequestBody E entity) {
        baseService.save(entity);
        return ResponseUtils.success("Add successful");
    }

    @ApiOperation("Delete")
    @PostMapping("/deleteById")
    public ResponseUtils delete(@RequestBody List<Integer> ids) {
        baseService.removeByIds(ids);
        return ResponseUtils.success("Delete successful");
    }

    @ApiOperation("Update")
    @PostMapping("/updateById")
    public ResponseUtils updateById(@RequestBody E entity) {
        baseService.updateById(entity);
        return ResponseUtils.success("Update successful");
    }

    @ApiOperation("Get by ID")
    @GetMapping("/getById")
    public ResponseUtils getById(@RequestParam Integer id) {
        return ResponseUtils.success(baseService.getById(id));
    }

    @ApiOperation("Save")
    @PostMapping("/save")
    public ResponseUtils save(@RequestBody E entity) {
        baseService.saveOrUpdate(entity);
        return ResponseUtils.success("Save successful");
    }

    @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("Count")
    @PostMapping("/count")
    public ResponseUtils count(@RequestBody E entity) {
        QueryWrapper<E> queryWrapper = ApprenticeUtil.getQueryWrapper(entity);
        long count = baseService.count(queryWrapper);
        return ResponseUtils.success(count);
    }
}</code>

This controller provides default implementations for common CRUD endpoints using generics, making it reusable for any entity type.

Step 4: Enable pagination support

<code>@Configuration
public class MybatisPlusConfig {
    /** Set pagination interceptor */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}</code>

Step 5: Extend BaseController in your own controller

<code>@RestController
@RequestMapping("/apprentice/dynamic")
@Api("Dynamic Management")
public class DynamicController extends BaseController<IDynamicService, Dynamic> {
}

@RestController
@RequestMapping("/apprentice/blog")
@Api(tags = "Blog Management")
public class BlogController extends BaseController<IBlogService, Blog> {
}</code>

By inheriting BaseController , the derived controllers automatically gain all CRUD, list, pagination, and count functionalities without additional code.

Project source code: https://gitee.com/WangFuGui-Ma/mybatis-plus-pro
JavaSpring BootpaginationCRUDRESTful APIMyBatisPlusBaseController
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.