Backend Development 11 min read

Automating CRUD Operations with MyBatisPlus: Building a Generic BaseController in Spring Boot

This tutorial demonstrates how to automate CRUD functionality in a Spring Boot application by introducing MyBatisPlus, creating a reusable utility class, configuring pagination, and implementing a generic BaseController that can be extended by concrete controllers for any entity.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Automating CRUD Operations with MyBatisPlus: Building a Generic BaseController in Spring Boot

This article shows how to achieve automatic CRUD operations in a Spring Boot project by leveraging MyBatisPlus and a generic BaseController that can be reused across different entity types.

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 a utility class

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ApprenticeUtil {
    private static Pattern humpPattern = Pattern.compile("[A-Z]");
    private static Pattern linePattern = Pattern.compile("_(\\w)");

    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();
    }

    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();
    }

    public static
QueryWrapper
getQueryWrapper(E entity) {
        Field[] fields = entity.getClass().getDeclaredFields();
        QueryWrapper
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;
    }

    public static
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);
    }
}

Step 3 – Implement the generic BaseController

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wangfugui.apprentice.common.util.ApprenticeUtil;
import com.wangfugui.apprentice.common.util.ResponseUtils;
import com.wangfugui.apprentice.dao.dto.PageParamDto;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

public class BaseController
, 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
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
queryWrapper = ApprenticeUtil.getQueryWrapper(entity);
        List
list = baseService.list(queryWrapper);
        return ResponseUtils.success(list);
    }

    @ApiOperation("page查")
    @PostMapping("/page")
    public ResponseUtils page(@RequestBody PageParamDto
pageParamDto) {
        if (pageParamDto.getPage() < 1) pageParamDto.setPage(1);
        if (pageParamDto.getSize() > 100) pageParamDto.setSize(100);
        Page
page = new Page<>(pageParamDto.getPage(), pageParamDto.getSize());
        QueryWrapper
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
ePage = baseService.page(page, queryWrapper);
        return ResponseUtils.success(ePage);
    }

    @ApiOperation("获取数量")
    @PostMapping("/count")
    public ResponseUtils count(@RequestBody E entity) {
        QueryWrapper
queryWrapper = ApprenticeUtil.getQueryWrapper(entity);
        long count = baseService.count(queryWrapper);
        return ResponseUtils.success(count);
    }
}

Step 4 – Enable pagination support

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

Step 5 – Extend the BaseController in concrete controllers

import com.wangfugui.apprentice.dao.domain.Dynamic;
import com.wangfugui.apprentice.service.IDynamicService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/apprentice/dynamic")
@Api("动态管理")
public class DynamicController extends BaseController
{}

import com.wangfugui.apprentice.dao.domain.Blog;
import com.wangfugui.apprentice.service.IBlogService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/apprentice/blog")
@Api(tags = "博客管理")
public class BlogController extends BaseController
{}

By inheriting BaseController , the DynamicController and BlogController instantly gain standard CRUD endpoints without writing additional code, streamlining development and ensuring consistent API behavior across the project.

JavaSpring BootCRUDRESTful APIGeneric ControllerMyBatisPlus
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

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.