1.前言
Fluent MyBatis诞生于2019年底,即使与MyBatis Dynamic SQL相比都是晚辈,然而尚处成长期的它就已透出了青出于蓝而胜于蓝的味道。我也是偶然间看了个别微信公众号的软文才知道有这么个东西,然后在网上搜了一下虽然有些教程和介绍文章但都是星星点点。目前来看,论影响力完全没法和MyBatis-Plus进行比较。由于所谓的"官方"git仓库页面的入门教程又臭又长而且作为演示的Demo比较混乱搞得仓库里提的基本上都是沙雕问题,而开发团队也只能不厌其烦的每次都贴出对应的文档链接……我体验下来感觉刚开始接触的时侯稍微还是有些难度的,但是逐渐熟练起来觉得异常简洁,省去了大量无用的创建模板和crud的操作。但是考虑到其在市面上的流传度较为局限,是否应用到正式的项目开发当中就仁者见仁、智者见智了。
相对小白而言MyBatis-Plus更加友好一些,了解访问链接:http://youthme.org/53.html
2.特性
相关特性可以看一下阿里云开发者社区的这篇文章:(传送门)
3.开始使用
(1)创建一个SpringBoot工程项目。
环境:
开发工具:IDEA、JDK版本:1.8、SpringBoot版本:2.5.1,选择添加模块:SpringWeb/MySQL Driver。
(2)工程准备好之后,在pom.xml
中引入相关依赖:
Maven依赖:
<!-- 引入fluent-mybatis 运行依赖包, scope为compile -->
<dependency>
<groupId>com.github.atool</groupId>
<artifactId>fluent-mybatis</artifactId>
<version>1.9.5</version>
</dependency>
<!-- 引入fluent-mybatis-processor, scope设置为provider 编译需要,运行时不需要 -->
<dependency>
<groupId>com.github.atool</groupId>
<artifactId>fluent-mybatis-processor</artifactId>
<scope>provided</scope>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<!--swagger 接口说明文档框架-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
(3)MySQL建表,增加测试用户数据:
测试数据SQL:
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(0) NOT NULL COMMENT '主键ID',
`name` varchar(30) CHARACTER SET utf8mb3 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '姓名',
`age` int(0) NULL DEFAULT NULL COMMENT '年龄',
`email` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'Jone', 18, 'test1@baomidou.com');
INSERT INTO `user` VALUES (2, 'Jack', 20, 'test2@baomidou.com');
INSERT INTO `user` VALUES (3, 'Tom', 28, 'test3@baomidou.com');
(4)依赖准备好后,创建Java类,然后配置连接mysql数据库信息+调用自动生成API并设置各类参数,根据自定义策略,执行自动生成代码操作。这里新建一个EntityGenerator.java和项目启动类在同一级别目录,提供主方法@Test。
代码生成器配置类:
package com.fluent;
import cn.org.atool.generator.FileGenerator;
import cn.org.atool.generator.annotation.Table;
import cn.org.atool.generator.annotation.Tables;
import org.junit.jupiter.api.Test;
/**
* @Author zf
* @ClassName EntityGenerator.java
* @ProjectName fluent
*/
public class EntityGenerator {
public static final String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8";
@Test
public void generate() throws Exception {
FileGenerator.build(Empty.class);
}
@Tables(
// 设置数据库连接信息
url = url, username = "root", password = "abc123",
// 设置entity类生成src目录, 相对于 user.dir
srcDir = "src/main/java",
// 设置entity类的package值
basePack = "com.fluent",
// 设置dao接口和实现的src目录, 相对于 user.dir
daoDir = "src/main/java",
// 设置哪些表要生成Entity文件
tables = {@Table(value = {"user"})}
)
static class Empty {
}
}
配置类是必须的(放到
config
包下面):FluentConfig:
package com.fluent.config;
import cn.org.atool.fluent.mybatis.spring.MapperFactory;
import org.apache.commons.dbcp2.BasicDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
/**
* @Author zf
* @ClassName FluentConfig.java
* @ProjectName fluent
*/
@ComponentScan(basePackages = "com.fluent")
@MapperScan("com.fluent.mapper")
@Configuration
public class FluentConfig {
/**
* 设置dataSource属性
*
* @return
*/
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8");
dataSource.setUsername("root");
dataSource.setPassword("abc123");
return dataSource;
}
/**
* 定义mybatis的SqlSessionFactoryBean
*
* @param dataSource
* @return
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean;
}
@Bean
public MapperFactory mapperFactory() {
return new MapperFactory();
}
}
SwaggerConfiguration:
package com.fluent.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @Author zf
* @ClassName SwaggerConfiguration.java
* @ProjectName fluent
*/
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("Fluent API Doc")
.description("This is a restful api document of Fluent.")
.version("1.0")
.build();
}
}
新建一个
constant
包,把Result相关的东西放进去:Result:
package com.fluent.constant;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel("统一api响应结果封装")
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 状态编码
*/
@ApiModelProperty(value = "状态编码")
private int code;
/**
* 信息
*/
@ApiModelProperty(value = "消息")
private String msg;
/**
* 数据
*/
@ApiModelProperty(value = "数据")
private T data;
private Result(int code, String msg) {
this.code = code;
this.data = null;
this.msg = msg;
}
private Result(int code, T data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
}
public static <T> Result<T> data(T data) {
return data(data, ResultEnum.SUCCESS.msg);
}
public static <T> Result<T> data(T data, String msg) {
return data(ResultEnum.SUCCESS.code, data, msg);
}
public static <T> Result data(int code, T data, String msg) {
return new Result(code, data, msg);
}
public static <T> Result<T> success() {
return success(ResultEnum.SUCCESS.msg);
}
public static <T> Result<T> success(String msg) {
return new Result<>(ResultEnum.SUCCESS.code, msg);
}
public static <T> Result<T> fail() {
return fail(ResultEnum.FAIL.msg);
}
public static <T> Result<T> fail(String msg) {
return fail(ResultEnum.FAIL.code, msg);
}
public static <T> Result<T> fail(int code, String msg) {
return new Result<>(code, msg);
}
public static <T> Result<T> error() {
return new Result<>(ResultEnum.INTERNAL_SERVER_ERROR.code, ResultEnum.INTERNAL_SERVER_ERROR.msg);
}
public static <T> Result<T> error(String msg) {
return new Result<>(ResultEnum.INTERNAL_SERVER_ERROR.code, msg);
}
public static <T> Result<T> status(boolean flag) {
return flag ? success() : fail();
}
}
ResultEnum:
package com.fluent.constant;
public enum ResultEnum {
// 成功
SUCCESS(200,"操作成功!"),
// 失败
FAIL(400,"操作失败!"),
// 未认证(签名错误/token错误)
UNAUTHORIZED(401,"未认证!"),
// 接口不存在
NOT_FOUND(404,"接口不存在!"),
// 服务器内部错误
INTERNAL_SERVER_ERROR(500,"服务器内部错误!");
public int code;
public String msg;
ResultEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
(5)到这里所有的准备工程已完成,直接在test包下面的FluentApplicationTests里面测试。
FluentApplicationTests:
package com.fluent;
import com.fluent.config.FluentConfig;
import com.fluent.entity.UserEntity;
import com.fluent.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
@SpringBootTest
@ContextConfiguration(classes = FluentConfig.class)
class FluentApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void findById(){
UserEntity entity = userMapper.findById(1);
System.out.println(entity);
}
}
注意:上面的测试类必须引入
@ContextConfiguration(classes = FluentConfig.class)
注解,即你自定义的Fluent-Mybatis配置类。另外,代码生成以后在UserDaoImpl
层100%报错说import com.fluent.dao.base.UserBaseDao;
包不存在,这时侯你只需要在IDEA的Maven里面点击一下clean
然后再点击一下complie
即可完美解决。原因是:Fluent-Mybatis把一些预置的东西都生成到了target目录下,这就涉及到了(专业解释忘记了,等想起来再填坑.)
当然你也可以新建一个controller通过Swagger在线调试:
UserController:
package com.fluent.controller;
import com.fluent.constant.Result;
import com.fluent.entity.UserEntity;
import com.fluent.mapper.UserMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author zf
* @ClassName UserController.java
* @ProjectName fluent
*/
@RestController
@Api(tags = "测试操作")
@RequestMapping("/test")
public class UserController {
@Autowired
private UserMapper userMapper;
@ApiOperation("通过ID查询")
@GetMapping("{id}")
public Result<UserEntity> getOne(@PathVariable Integer id){
return Result.data(userMapper.findById(id));
}
}
Swagger在线调试地址:
http://127.0.0.1:8080/doc.html
#IP和端口号根据自己实际项目