SpringBoot后端项目快速搭建基础代码。
1.项目环境搭建
项目地址:https://github.com/Wahoyu/SpringBootBasicCode
创建后端项目

可以创建空的项目,然后在下面pom.xml文件中选择依赖:
导入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency>
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.3.0</version> </dependency>
<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.0</version> </dependency>
<dependency> <groupId>com.spring4all</groupId> <artifactId>spring-boot-starter-swagger</artifactId> <version>1.5.1.RELEASE</version> </dependency>
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency>
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.17</version> </dependency>
<dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl</artifactId> <version>3.3.2.RELEASE</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-extension</artifactId> <version>3.5.2</version> </dependency>
|
连接数据库测试
配置文件配置数据源和MybatisPlus日志
1 2 3 4 5 6 7 8 9
| spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 username: root password: 123456 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|

测试成功!
2.代码生成器
MybatisPlus代码生成器可以根据配置文件生成数据库表对应的从Controller→Entity的文件,相当于搭建了项目的框架,方便我们进行后续开发。
搭建数据库表环境
MyBatis Plus的代码生成器不对数据库表中的字段有任何必须要求。生成器会根据数据库表的结构自动生成相应的实体类、Mapper接口、Service类等代码。
然而,建议数据库表至少包含以下字段,以便使用MyBatis Plus代码生成器更好地生成代码:
- 主键字段:建议表中具有一个主键字段,用于唯一标识每一条记录。最常见的选择是使用递增的整数类型作为主键。
- 创建时间和更新时间字段:为了方便记录信息的创建和更新时间,建议在表中包含创建时间和更新时间字段。常见的选择是使用时间戳字段(如
datetime
或timestamp
类型)。
- update_time 修改时间字段
- create_time 创建时间字段
以上字段是一些常见的最佳实践,但并非强制要求。你可以根据具体的业务需求和设计选择其他字段类型和结构。
另外,我们还可以设置乐观锁和逻辑删除字段。
- version 乐观锁更新版本字段
- deleted 逻辑删除字段
如果我们在配置文件中对这些字段进行了配置,但是数据库表中没有这些字段,问题也不大。

1 2 3 4 5 6 7
| CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, age INT, created_time DATETIME, updated_time DATETIME );
|
编写可执行文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| public class CodeGenerator {
private static final String[] TABLE_NAMES = new String[]{"sys_org"}; public static final String PROJECT_PATH = "/Users/wanghongyu/IdeaProjects/GeneratorTest/src/main/java"; public static final String PROJECT_NAME = "meeting"; public static final String MODULE_NAME ="";
public static void main(String[] args) { AutoGenerator autoGenerator = new AutoGenerator(); DataSourceConfig dataSource = new DataSourceConfig(); dataSource.setDriverName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8"); dataSource.setUsername("root"); dataSource.setPassword("123456"); autoGenerator.setDataSource(dataSource); GlobalConfig globalConfig = new GlobalConfig(); globalConfig.setOutputDir(PROJECT_PATH); globalConfig.setOpen(true); globalConfig.setAuthor("wahoyu"); globalConfig.setFileOverride(false); globalConfig.setMapperName("%sMapper");
autoGenerator.setGlobalConfig(globalConfig); PackageConfig packageConfig = new PackageConfig(); packageConfig.setParent("com.example"); packageConfig.setEntity("entity"); packageConfig.setMapper("mapper"); autoGenerator.setPackageInfo(packageConfig); StrategyConfig strategyConfig = new StrategyConfig(); strategyConfig.setTablePrefix(""); strategyConfig.setRestControllerStyle(true); strategyConfig.setVersionFieldName("version"); strategyConfig.setEntityLombokModel(true); strategyConfig.setCapitalMode(true); strategyConfig.setNaming(NamingStrategy.underline_to_camel); strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel); String[] tableList = new String[] {"student"}; strategyConfig.setInclude(tableList); autoGenerator.setStrategy(strategyConfig); autoGenerator.execute(); }
public static StrategyConfig getStrategyConfigInfo(String... tableNames) { StrategyConfig strategyConfigInfo = new StrategyConfig(); strategyConfigInfo.setCapitalMode(true); strategyConfigInfo.setNaming(NamingStrategy.underline_to_camel); strategyConfigInfo.setColumnNaming(NamingStrategy.underline_to_camel); strategyConfigInfo.setInclude(tableNames); strategyConfigInfo.setLogicDeleteFieldName("deleted"); strategyConfigInfo.setEntityLombokModel(true); strategyConfigInfo.setTablePrefix(""); strategyConfigInfo.setRestControllerStyle(true); return strategyConfigInfo; } }
|
运行代码生成器
文件生成成功!

移动mapper.xml
配置文件application.yml,SpringBoot扫描xml文件的路径。
1 2
| mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml
|
classpath*:mapper/**/*.xml
表示在classpath(也就是resources文件夹)下的mapper
目录以及其子目录中查找所有的xml
文件。

3.项目开发通用流程
在使用代码生成器生成文件后,编写通用的增删改查接口。
MybatisPlus分页插件
配置MybatisPlus分页插件和扫描mapper文件夹
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.example.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration @MapperScan({"com.example.mapper"}) public class MybatisPlusConfig {
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; }
}
|
实体类配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Getter @Setter @TableName("student") public class Student implements Serializable {
private static final long serialVersionUID=1L;
@TableId(value = "id", type = IdType.AUTO) private Integer id;
private String name;
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" , timezone = "GMT+8") @TableField(fill = FieldFill.INSERT) private LocalDateTime createdTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" , timezone = "GMT+8") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updatedTime; }
|
时间填充配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Component public class MyMetaObjectHandler implements MetaObjectHandler {
@Override public void insertFill(MetaObject metaObject) { this.setFieldValByName("createTime", LocalDateTime.now(),metaObject); this.setFieldValByName("updateTime", LocalDateTime.now(),metaObject); }
@Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("updateTime", LocalDateTime.now(),metaObject); } }
|
Ext.增加时间、更新时间
如果我们不想像上面一样,在代码级别
添加时间注释,我们也可以在数据库表创建的时候,在数据库级别
,设置自动更新创建时间和更新时间。但是这种相对困难,我们不一定有权限修改数据库。
1 2 3 4 5 6
| CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
|
4.代码编写
五个方法:1、分页查询(可模糊查询) 2、查询一个 3、更新一个 4、删除一个 5、添加一个。
Result与Response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.lhcc.common.result;
import lombok.Data;
import java.io.Serializable;
@Data public class Result<T> implements Serializable {
private static final long serialVersionUID = 6308315887056661996L; private Integer code; private String message; private T data;
public Result setResult(ResultCode resultCode) { this.code = resultCode.getCode(); this.message = resultCode.getMessage(); return this; }
public Result setResult(ResultCode resultCode, T data) { this.code = resultCode.getCode(); this.message = resultCode.getMessage(); this.setData(data); return this; }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.lhcc.common.result;
import lombok.Getter;
@Getter public enum ResultCode {
SUCCESS(200, "成功"), BAD_REQUEST(400, "失败"), UNAUTHORIZED(401, "认证失败"), NOT_FOUND(404, "接口不存在"), INTERNAL_SERVER_ERROR(500, "服务器内部错误"), METHOD_NOT_ALLOWED(405,"方法不被允许"), ILLEGAL_HEADER(406,"请求头无效"), REPLAY_ERROR(410,"请求重复"), PARAMS_IS_INVALID(1001, "参数无效"), PARAMS_IS_BLANK(1002, "参数为空");
private Integer code; private String message;
ResultCode(int code, String message) { this.code = code; this.message = message; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.lhcc.common.result;
public class ResultResponse {
public static Result success() { return new Result() .setResult(ResultCode.SUCCESS); }
public static Result success(Object data) { return new Result() .setResult(ResultCode.SUCCESS, data);
}
public static Result failure(ResultCode resultCode) { return new Result() .setResult(resultCode); }
public static Result failure(ResultCode resultCode, Object data) { return new Result() .setResult(resultCode, data); }
public static Result paramInvalid(Object data) { return new Result() .setResult(ResultCode.PARAMS_IS_INVALID, data); }
}
|
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| @RestController @RequestMapping("/student") public class StudentController {
@Resource IStudentService iStudentService;
@GetMapping("/list") public Result list(Student student, Page<Student> page) { return ResultResponse.success(iStudentService.selectByPage(student, page)); }
@GetMapping("/{id}") public Result getInfo(@PathVariable BigInteger id) { return ResultResponse.success(iStudentService.getById(id)); }
@PostMapping("/update") public Result update(@RequestBody Student student) { return ResultResponse.success(iStudentService.updateById(student)); }
@DeleteMapping("/{id}") public Result remove(@PathVariable BigInteger id) { return ResultResponse.success(iStudentService.removeById(id)); }
@PostMapping("/add") public Result add(@RequestBody Student student) { iStudentService.save(student); return ResultResponse.success(); }
}
|
Service
1 2 3
| public interface IStudentService extends IService<Student> { Page<Student> selectByPage(Student student, Page<Student> page); }
|
ServiceImpl
在分页的同时,对必要的空值做判断,同时支持模糊查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Service public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements IStudentService {
@Resource StudentMapper studentMapper;
@Override public Page<Student> selectByPage(Student student, Page<Student> page) {
QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(student.getName())) { queryWrapper.like("name", student.getName()); }
if (student.getAge() != null) { queryWrapper.eq("age", student.getAge()); } Page<Student> studentPage = studentMapper.selectPage(page, queryWrapper); return studentPage; } }
|
5.接口测试
项目文件目录

测试一:添加一条数据


测试二:全部查询


测试三:分页查询
Student属性与Page属性可传入的参数直接拼接URL就行

测试四:查询一条数据

测试五:更新一条数据
注意属性必须要完整,如果想要简单一点的方法,可以使用updateById方法

更新前:

更新后:

测试六:删除一条数据

