Spring Boot + MyBatisPlus Project Setup and Implementation Guide
This article provides a comprehensive step‑by‑step guide on selecting technologies, configuring Gradle, integrating Spring Boot 2.1.5 with MyBatisPlus, setting up FastJSON, Hutool, Undertow, and other tools, and includes complete source code for entity, mapper, service, controller, and utility classes to build a clean Java backend application.
1. Technology Selection
Parser: FastJSON
Development tools: JDK 1.8, Gradle, IDEA
Framework: SpringBoot 2.1.5.RELEASE
ORM: MyBatisPlus 3.1.2
Database: MySQL 8.0.21
Apache tools: HttpClient, Lang3
Version control: Git
Web server: Undertow
Utility library: Hutool
Lombok, Druid connection pool
2. Brief Description of Spring Boot Evolution
With the rise of dynamic languages (Ruby, Groovy, Scala, Node.js), Java development became cumbersome due to extensive configuration, low efficiency, complex deployment, and difficult third‑party integration. Spring Boot emerged to address these issues by adopting a "convention over configuration" approach, enabling rapid creation of standalone, production‑grade applications with minimal manual setup.
3. Spring Boot Plugins Used
spring-boot-devtools – hot deployment to avoid frequent restarts during development.
spring-boot-starter-aop – provides powerful AOP capabilities for decoupling.
spring-boot-starter-undertow – integrates Undertow as the embedded servlet container.
spring-boot-starter-test – testing utilities.
mybatis-plus-boot-starter – integrates MyBatisPlus.
spring-boot-configuration-processor – assists with configuration metadata.
4. FastJSON
Alibaba's JSON parser. Official documentation: https://github.com/alibaba/fastjson
5. Hutool
Hutool is a Java utility library that simplifies code, reduces boilerplate, and provides a rich set of reusable components.
6. Gradle
Gradle is an open‑source build automation tool based on Apache Ant and Maven concepts, using a Groovy‑based DSL (also Kotlin DSL) to replace XML configuration.
Official site: https://gradle.org/
Install Gradle, configure environment variables, and learn basic usage before proceeding.
7. Project Structure
The project combines Kotlin, SpringBoot, and MyBatisPlus to create a minimal front‑back separation framework. It upgrades a Java‑based SpringBoot + MyBatisPlus 3.x + Gradle stack; source code is available for download.
8. Gradle Configuration
plugins {
id 'java'
id 'idea'
}
/**
* Use Groovy syntax to define version variables
*/
def spring_boot_version = "2.1.5.RELEASE"
def mybatis_plus_version = "3.1.2"
def mysql_version = "8.0.21"
def druid_version = "1.1.23"
def logback_version = "1.2.1"
def fastjson_version = "1.2.73"
def lombok_version = "1.18.12"
def lang_version = "3.4"
def io_version = "2.6"
def guava_version = "18.0"
def hutool_version = "5.3.10"
group = 'com.flong'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
repositories {
// Alibaba Cloud mirror
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
mavenLocal()
mavenCentral()
}
dependencies {
implementation "org.springframework.boot:spring-boot-starter:${spring_boot_version}"
// Exclude Tomcat, use Undertow
compile("org.springframework.boot:spring-boot-starter-web:${spring_boot_version}") { exclude module: "spring-boot-starter-tomcat" }
compile "org.springframework.boot:spring-boot-starter-undertow:${spring_boot_version}"
runtime "mysql:mysql-connector-java:5.1.42"
compile "org.springframework.boot:spring-boot-devtools:${spring_boot_version}"
compile "org.springframework.boot:spring-boot-configuration-processor:${spring_boot_version}"
compile "org.springframework.boot:spring-boot-starter-test:${spring_boot_version}"
compile "com.baomidou:mybatis-plus-extension:${mybatis_plus_version}"
compile "com.baomidou:mybatis-plus-boot-starter:${mybatis_plus_version}"
compile "mysql:mysql-connector-java:${mysql_version}"
compile "com.alibaba:druid:${druid_version}"
compile "ch.qos.logback:logback-classic:${logback_version}"
compile "com.alibaba:fastjson:${fastjson_version}"
annotationProcessor "org.projectlombok:lombok:${lombok_version}"
compileOnly "org.projectlombok:lombok:${lombok_version}"
compile "org.apache.commons:commons-lang3:${lang_version}"
compile "commons-io:commons-io:${io_version}"
compile "com.google.guava:guava:${guava_version}"
compile "cn.hutool:hutool-all:${hutool_version}"
}
tasks.withType(JavaCompile) { options.encoding = "UTF-8" }
[compileJava, javadoc, compileTestJava]*.options*.encoding = "UTF-8"9. Database SQL Script
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
`user_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '用户Id主键,IdWork生成',
`user_name` varchar(255) DEFAULT '' COMMENT '用户名',
`pass_word` varchar(255) DEFAULT '' COMMENT '密码',
`del_flag` int(2) unsigned NOT NULL DEFAULT '0' COMMENT '是否删除,0-不删除,1-删除',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`user_id`) USING BTREE,
UNIQUE KEY `id` (`id`) USING BTREE
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';10. SpringBoot + MyBatisPlus Pagination Configuration
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
/** Pagination plugin */
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}11. Condition Wrapper Builder
package com.flong.springboot.core.util;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.flong.springboot.core.vo.Condition;
import java.lang.reflect.Field;
import java.util.List;
import com.flong.springboot.core.enums.JoinType;
import com.flong.springboot.core.exception.BaseException;
/** Convert condition list to QueryWrapper */
public class BuildConditionWrapper {
public static
QueryWrapper
build(List
conditions, Class
clazz) {
QueryWrapper wrapper = Wrappers.query();
if (conditions == null || conditions.size() == 0) { return wrapper; }
try {
for (int i = 0; i < conditions.size(); i++) {
Condition condition = conditions.get(i);
if (condition.getFieldName() == null) { throw new BaseException("Missing fieldName!"); }
String columnName = getColumnName(condition.getFieldName(), clazz);
if (condition == null || condition.getOperation() == null) { throw new BaseException("Operation cannot be null!"); }
switch (condition.getOperation()) {
case EQ: wrapper.eq(columnName, condition.getValue()); break;
case GT: wrapper.gt(columnName, condition.getValue()); break;
case LT: wrapper.lt(columnName, condition.getValue()); break;
case NEQ: wrapper.ne(columnName, condition.getValue()); break;
case GTANDEQ: wrapper.ge(columnName, condition.getValue()); break;
case LTANDEQ: wrapper.le(columnName, condition.getValue()); break;
case LIKE: wrapper.like(columnName, condition.getValue()); break;
case ISNULL: wrapper.isNull(columnName); break;
case IN: wrapper.inSql(columnName, condition.getValue()); break;
default: break;
}
if (condition.getJoinType() == JoinType.OR && i < conditions.size() - 1) { wrapper.or(); }
}
return wrapper;
} catch (Exception e) { throw new BaseException("Invalid query condition"); }
}
public static
QueryWrapper
buildWarpper(List
conditions) {
QueryWrapper wrapper = Wrappers.query();
if (conditions == null || conditions.size() == 0) { return wrapper; }
try {
for (int i = 0; i < conditions.size(); i++) {
Condition condition = conditions.get(i);
if (condition.getFieldName() == null) { throw new BaseException("Missing fieldName!"); }
String columnName = condition.getFieldName();
if (condition == null || condition.getOperation() == null) { throw new BaseException("Operation cannot be null!"); }
switch (condition.getOperation()) {
case EQ: wrapper.eq(columnName, condition.getValue()); break;
case GT: wrapper.gt(columnName, condition.getValue()); break;
case LT: wrapper.lt(columnName, condition.getValue()); break;
case NEQ: wrapper.ne(columnName, condition.getValue()); break;
case GTANDEQ: wrapper.ge(columnName, condition.getValue()); break;
case LTANDEQ: wrapper.le(columnName, condition.getValue()); break;
case LIKE: wrapper.like(columnName, condition.getValue()); break;
case IN: wrapper.inSql(columnName, condition.getValue()); break;
default: break;
}
if (condition.getJoinType() == JoinType.OR && i < conditions.size() - 1) { wrapper.or(); }
}
return wrapper;
} catch (Exception e) { throw new BaseException("Invalid query condition"); }
}
public static String getColumnName(String fieldName, Class clazz) {
try {
Field field = clazz.getDeclaredField(fieldName);
TableField tableFieldAnno = field.getAnnotation(TableField.class);
String columnName = "";
if (tableFieldAnno != null && StrUtil.isNotBlank(tableFieldAnno.value())) {
columnName = tableFieldAnno.value();
} else {
columnName = NamingStrategyUtils.camelToUnderline(field.getName());
}
return columnName;
} catch (NoSuchFieldException e) {
throw new BaseException("Invalid query condition");
}
}
}12. Entity Definition
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.*;
import java.io.Serializable;
import java.util.Date;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@TableName("t_user")
public class User extends Model
implements Serializable {
@TableId(type = IdType.ID_WORKER)
private Long userId;
private String userName;
private String passWord;
@TableLogic
private String delFlag;
private Date createTime;
}13. Mapper Interface
BaseMapper extends MyBatisPlus core mapper.
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.flong.springboot.modules.entity.User;
public interface UserMapper extends BaseMapper
{}14. Service Implementation
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.flong.springboot.modules.entity.User;
import com.flong.springboot.modules.mapper.UserMapper;
import org.springframework.stereotype.Service;
@Service
public class UserService extends ServiceImpl
{}15. Controller (CRUD & Pagination)
package com.flong.springboot.modules.controller;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.flong.springboot.modules.entity.User;
import com.flong.springboot.modules.mapper.UserMapper;
import com.flong.springboot.modules.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.flong.springboot.core.vo.Conditions;
import com.flong.springboot.core.util.BuildConditionWrapper;
import java.util.List;
/**
* @Author: liangjl
* @Date: 2020-08-16
* @Description: User controller
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@Autowired
private UserService userService;
@RequestMapping("/add")
public void add() {
userMapper.insert(User.builder().userName("周伯通").passWord("123456").build());
}
@PutMapping("/updateById")
public void updateById(@RequestBody User user) {
userMapper.updateById(user);
}
@DeleteMapping("/deleteByIds")
public void deleteByIds(@RequestBody List
ids) {
userMapper.deleteBatchIds(ids);
}
@GetMapping("/getOne/{userId}")
public void getOne(@PathVariable("userId") Long userId) {
User user = userMapper.selectById(userId);
System.out.println(JSON.toJSON(user));
}
@GetMapping("/page")
public IPage
page(Page page, Conditions conditions) {
QueryWrapper
build = BuildConditionWrapper.build(conditions.getConditionList(), User.class);
// Order by createTime descending via lambda reflection
build.lambda().orderByDesc(User::getCreateTime);
return userService.page(page, build);
}
}16. WebConfig – Global Configuration
@Configuration
@ConditionalOnClass(WebMvcConfigurer.class)
@Order(Ordered.HIGHEST_PRECEDENCE)
public class WebConfig implements WebMvcConfigurer {
@Bean
public HttpMessageConverters customConverters() {
FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullListAsEmpty
);
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
SerializeConfig serializeConfig = SerializeConfig.globalInstance;
serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
serializeConfig.put(Long.class, ToStringSerializer.instance);
serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
fastJsonConfig.setSerializeConfig(serializeConfig);
List
fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastJsonConverter.setSupportedMediaTypes(fastMediaTypes);
fastJsonConverter.setFastJsonConfig(fastJsonConfig);
return new HttpMessageConverters(fastJsonConverter);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(logInterceptor).addPathPatterns("/**");
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(Boolean.TRUE);
}
}17. Running Results
Add user: http://localhost:7011/user/add
Paginated query: http://localhost:7011/user/page?conditionList[0].fieldName=userName&conditionList[0].operation=LIKE&conditionList[0].value=%E5%91%A8
Default page = 1, size = 10; can be customized via current and size parameters.
18. Conclusion & Further Notes
The article summarizes the author's learning experience, invites readers to provide feedback, and encourages joining the Java architecture community for further discussion.
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.
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.