写在最前
最近在折腾 SpringBoot,后端开发最火的当属 MyBatis-Plus 框架了。虽然它简化了很多操作,但手动编写 CRUD 代码依然是一件繁琐又枯燥的事。有没有一种“一键生成、原地起飞”的解决方案呢?当然有!MyBatis-Plus 官方提供了代码生成器 —— MyBatis Generator。不过,原生工具在使用体验上还有些不足。幸运的是,我在 GitHub 上发现了一个基于它开发的图形化代码生成工具,功能强大、界面友好,真正做到了开箱即用,简直不要太香!
1. 前置要求
用 MyBatis 代码生成器之前,记得先把相关依赖加进项目里,尤其是 pom.xml
。不然生成一堆代码也白搭,项目都用不上,岂不是白忙一场?
<!-- MyBatis Plus: 增强的MyBatis框架,简化数据库操作 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
2. 操作流程
在使用代码生成器之前,需要先配置好数据库连接信息。然后通过 IDEA 创建好 SpringBoot 项目,并进入项目的 java
目录,例如:F:\idea_code\demo\src\main\java
。将这个路径复制下来,并作为代码生成器的输出目录。这样生成的代码就会直接写入到你的项目中,无需手动移动,IDEA 也能立即识别使用。
还有一点非常重要,那就是在生成器配置中务必勾选“开启 @Mapper 注解”的选项。这样就可以启用注解驱动的方式,完全舍弃传统的 mapper.xml
配置文件,实现无 XML 的简洁开发模式。
在完成配置后,点击“立即生成”,系统会自动将生成的代码插入到项目中,我们可以在项目中查看生成结果。
顺带一提,因为我们开启了@Mapper了,所以生成的mapper_xml这个目录的内容是可以直接删掉的。
3. 优化配置
虽然系统已生成了所有代码,但我们注意到各个 Controller 类中尚未包含具体实现。为了解决这一问题,我们可以创建一个通用的 BaseController
类,统一实现常用的 RESTful API 接口。然后让这些空的 Controller 类继承 BaseController
,即可自动拥有基础的接口功能,提升代码复用性与开发效率。
package com.tanqidi.survey.common;
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.tanqidi.survey.common.utils.LogContextUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.Serializable;
import java.util.List;
/**
* 通用 RESTful 控制器
* @param <T> 实体类型
* @param <S> Service 类型
*/
@RestController
public abstract class BaseController<T, S extends IService<T>> {
protected final Logger log = LoggerFactory.getLogger(getClass());
@Autowired
protected S service;
/**
* 记录请求开始时间
*/
protected void logRequestStart(String operation, Object... args) {
log.info("开始执行: {} - 参数: {}", operation, args);
}
/**
* 记录请求结束时间和执行时间
*/
protected void logRequestEnd(String operation, long startTime) {
long endTime = System.currentTimeMillis();
log.info("结束执行: {} - 耗时: {}ms", operation, (endTime - startTime));
}
/**
* 记录异常信息
*/
protected void logError(String operation, Exception e) {
log.error("执行出错: {} - 错误信息: {}", operation, e.getMessage(), e);
}
@PostMapping
public R<T> create(@RequestBody T entity) {
String operation = "创建实体";
long startTime = System.currentTimeMillis();
logRequestStart(operation, entity);
try {
boolean success = service.save(entity);
logRequestEnd(operation, startTime);
return success ? R.ok(entity) : R.error("新增失败");
} catch (Exception e) {
logError(operation, e);
return R.error("新增失败: " + e.getMessage());
}
}
@PutMapping
public R<T> update(@RequestBody T entity) {
String operation = "更新实体";
long startTime = System.currentTimeMillis();
logRequestStart(operation, entity);
try {
boolean success = service.updateById(entity);
logRequestEnd(operation, startTime);
return success ? R.ok(entity) : R.error("更新失败");
} catch (Exception e) {
logError(operation, e);
return R.error("更新失败: " + e.getMessage());
}
}
@DeleteMapping("/{id}")
public R<Boolean> delete(@PathVariable Serializable id) {
String operation = "删除实体";
long startTime = System.currentTimeMillis();
logRequestStart(operation, id);
try {
boolean success = service.removeById(id);
logRequestEnd(operation, startTime);
return R.ok(success);
} catch (Exception e) {
logError(operation, e);
return R.error("删除失败: " + e.getMessage());
}
}
@PostMapping("/batch-delete")
public R<Boolean> deleteBatch(@RequestBody List<? extends Serializable> ids) {
String operation = "批量删除实体";
long startTime = System.currentTimeMillis();
logRequestStart(operation, ids);
try {
boolean success = service.removeByIds(ids);
logRequestEnd(operation, startTime);
return R.ok(success);
} catch (Exception e) {
logError(operation, e);
return R.error("批量删除失败: " + e.getMessage());
}
}
@GetMapping("/{id}")
public R<T> getById(@PathVariable Serializable id) {
String operation = "根据ID查询实体";
long startTime = System.currentTimeMillis();
logRequestStart(operation, id);
try {
T result = service.getById(id);
logRequestEnd(operation, startTime);
return result != null ? R.ok(result) : R.error("数据不存在");
} catch (Exception e) {
logError(operation, e);
return R.error("查询失败: " + e.getMessage());
}
}
@GetMapping
public R<List<T>> list() {
String operation = "查询所有实体";
long startTime = System.currentTimeMillis();
logRequestStart(operation);
try {
List<T> list = service.list();
logRequestEnd(operation, startTime);
return R.ok(list);
} catch (Exception e) {
logError(operation, e);
return R.error("查询失败: " + e.getMessage());
}
}
@PostMapping("/page")
public R<Page<T>> page(
@RequestBody(required = false) T query,
@RequestParam(defaultValue = "1") long page,
@RequestParam(defaultValue = "10") long size
) {
String operation = "分页查询实体";
long startTime = System.currentTimeMillis();
logRequestStart(operation, query, page, size);
try {
QueryWrapper<T> wrapper = new QueryWrapper<>();
if (query != null) {
wrapper.setEntity(query);
}
Page<T> resultPage = service.page(new Page<>(page, size), wrapper);
logRequestEnd(operation, startTime);
return R.ok(resultPage);
} catch (Exception e) {
logError(operation, e);
return R.error("分页查询失败: " + e.getMessage());
}
}
@PostMapping("/list-by")
public R<List<T>> listBy(@RequestBody(required = false) T query) {
String operation = "条件查询实体";
long startTime = System.currentTimeMillis();
logRequestStart(operation, query);
try {
QueryWrapper<T> wrapper = new QueryWrapper<>();
if (query != null) {
wrapper.setEntity(query);
}
List<T> resultList = service.list(wrapper);
logRequestEnd(operation, startTime);
return R.ok(resultList);
} catch (Exception e) {
logError(operation, e);
return R.error("条件查询失败: " + e.getMessage());
}
}
}
只需继承 BaseController
,并传入对应的实体类(Entity)和对应的 IXXXService
接口,即可通过 BaseController
自动完成依赖注入(@Autowired)并找到具体的实现类,从而让每个 Controller 拥有完整的基础接口能力,无需重复编写增删改查等通用代码。
package com.tanqidi.survey.controller;
import com.tanqidi.survey.common.BaseController;
import com.tanqidi.survey.common.R;
import com.tanqidi.survey.entity.SysUserEntity;
import com.tanqidi.survey.service.ISysUserService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author
* @since 2025-06-01
*/
@RestController
@RequestMapping("/api/v1/sys-users")
public class SysUserController extends BaseController<SysUserEntity, ISysUserService> {
}
4. 写在最后
值得注意的是,本项目中还有很多细节未一一展示,例如 application.properties
的具体配置。若各位希望深入了解这些内容,欢迎留言探讨,我会视情况补充更多细节文档。