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和端口号根据自己实际项目

最后修改:2022 年 04 月 13 日
给我一点小钱钱也很高兴啦!o(* ̄▽ ̄*)ブ