• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

fluent-mybatis初体验

武飞扬头像
freekaiQaQ
帮助1

最近的项目中都是springboot jpa的框架,jpa在开发上确实是能让效率很好的提升。但是项目运行中也会有一些问题(像1对1的映射、配置单项关联,延迟加载不生效、会冗余的查出一些不需要用到的字段或其他的信息)正好也是有了一个新项目,想着能不用jpa的框架,用mybatis,有同事说到了fluent-mybatis,那自己也是先写个demo玩玩,顺带记录着。

fluent-mybatis官网学新通https://gitee.com/fluent-mybatis/fluent-mybatis/wikis/fluent mybatis特性总览

1.搭建springboot项目

2.整合mybatis、fluent-mybatis。 pom文件如下

  1.  
    <properties>
  2.  
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  3.  
    <maven.compiler.source>1.8</maven.compiler.source>
  4.  
    <maven.compiler.target>1.8</maven.compiler.target>
  5.  
    <project.fluent.mybatis.version>1.9.8</project.fluent.mybatis.version>
  6.  
    </properties>
  7.  
     
  8.  
    <dependencies>
  9.  
    <dependency>
  10.  
    <groupId>junit</groupId>
  11.  
    <artifactId>junit</artifactId>
  12.  
    <version>4.11</version>
  13.  
    <!-- <scope>test</scope>-->
  14.  
    </dependency>
  15.  
     
  16.  
    <!--添加spring-boot -->
  17.  
    <dependency>
  18.  
    <groupId>org.springframework.boot</groupId>
  19.  
    <artifactId>spring-boot-starter-web</artifactId>
  20.  
    <version>2.1.10.RELEASE</version>
  21.  
    </dependency>
  22.  
    <dependency>
  23.  
    <groupId>org.mybatis.spring.boot</groupId>
  24.  
    <artifactId>mybatis-spring-boot-starter</artifactId>
  25.  
    <version>2.1.0</version>
  26.  
    </dependency>
  27.  
    <dependency>
  28.  
    <groupId>mysql</groupId>
  29.  
    <artifactId>mysql-connector-java</artifactId>
  30.  
    <version>5.1.49</version>
  31.  
    </dependency>
  32.  
    <dependency>
  33.  
    <groupId>com.github.atool</groupId>
  34.  
    <artifactId>fluent-mybatis</artifactId>
  35.  
    <version>${project.fluent.mybatis.version}</version>
  36.  
    </dependency>
  37.  
     
  38.  
    <dependency>
  39.  
    <groupId>com.github.atool</groupId>
  40.  
    <artifactId>fluent-mybatis-processor</artifactId>
  41.  
    <scope>provided</scope>
  42.  
    <version>${project.fluent.mybatis.version}</version>
  43.  
    </dependency>
  44.  
    <dependency>
  45.  
    <groupId>org.projectlombok</groupId>
  46.  
    <artifactId>lombok</artifactId>
  47.  
    <version>1.18.8</version>
  48.  
    </dependency>
  49.  
     
  50.  
    </dependencies>
学新通

3.配置application.yaml文件(数据源等信息)

  1.  
    spring:
  2.  
    datasource:
  3.  
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&serverTimezone=Asia/Shanghai
  4.  
    username: root
  5.  
    password: root
  6.  
    driver-class-name: com.mysql.jdbc.Driver
  7.  
     
  8.  
    server:
  9.  
    port: 8001
  10.  
    mybatis:
  11.  
    configuration:
  12.  
    # 配置打印sql语句到控制台
  13.  
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

项目的目录结构如下

学新通 

 学新通

 也是可以通过代码生成工具,完成dao、entity等类的生成。首先得自己先在库里把表建好。

  1.  
    package com.freekai;
  2.  
     
  3.  
    import cn.org.atool.generator.FileGenerator;
  4.  
    import cn.org.atool.generator.annotation.Relation;
  5.  
    import cn.org.atool.generator.annotation.RelationType;
  6.  
    import cn.org.atool.generator.annotation.Table;
  7.  
    import cn.org.atool.generator.annotation.Tables;
  8.  
    import com.freekai.custom.FreekaiMapper;
  9.  
    import org.junit.Test;
  10.  
     
  11.  
    public class EntityGenerator {
  12.  
    //数据源url
  13.  
    static final String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&serverTimezone=Asia/Shanghai";
  14.  
     
  15.  
    //数据库用户名
  16.  
    static final String username = "root";
  17.  
     
  18.  
    //数据库密码
  19.  
    static final String password = "root";
  20.  
     
  21.  
    @Test
  22.  
    public void generate() throws Exception {
  23.  
    //引用配置类,build方法允许有多个配置类
  24.  
    FileGenerator.build(Empty.class);
  25.  
    }
  26.  
     
  27.  
    @Tables(
  28.  
    //设置数据库连接信息
  29.  
    url = url,username = username,password = password,
  30.  
    driver = "com.mysql.jdbc.Driver",
  31.  
    //设置entity类生成src目录,相对于user.dir
  32.  
    srcDir = "src/main/java",
  33.  
    //设置entity类的package值
  34.  
    basePack = "com.freekai.fluent",
  35.  
    //设置dao接口和实现的src目录,相对于user.dir
  36.  
    daoDir = "src/main/java",
  37.  
    //设置哪些表要生成Entity文件
  38.  
    tables = {@Table(value = {"user_test_address","user_test"}, logicDeleted = "is_delete", superMapper = FreekaiMapper.class)},
  39.  
    relations = {
  40.  
    @Relation(method = "findAddressV2", source = "user_test", target = "user_test_address", type = RelationType.OneWay_0_1
  41.  
    , where = "id=user_test_id"),
  42.  
    @Relation(method = "findUserTestV2", source = "user_test_address", target = "user_test", type = RelationType.OneWay_0_1)
  43.  
    }
  44.  
    )
  45.  
    static class Empty{ //类名随便取,只是配置定义的一个载体
  46.  
     
  47.  
    }
  48.  
     
  49.  
    }
学新通
上面的tables中 user_test_address  user_test两张表配置了 1对1的映射。和hibernate中的@OneToOne含义一致。
另外也指定了逻辑删除的字段是is_delete。
细心的朋友会发现还有一个@Relation的配置。 method: findAddressV2即相当于会在生成的实体类中生成一个findAddressV2这个方法,这个方法的返回值是对应的关联表的实体类。where="id=user_test_id" 和source及target组合起来后,相当于 user_test.id = user_test_address.user_test_id (即在user_test_address表中有一个user_test_id字段,存储的是user_test表的id值),源码中也有注释。

学新通 

另一个@Relation同理,反着配置一下就可以了。 执行上述代码中的generate()方法,可以发现目录下有生成的文件。

 学新通

 UserTestEntity.java

  1.  
    package com.freekai.fluent.entity;
  2.  
     
  3.  
    import cn.org.atool.fluent.mybatis.annotation.FluentMybatis;
  4.  
    import cn.org.atool.fluent.mybatis.annotation.LogicDelete;
  5.  
    import cn.org.atool.fluent.mybatis.annotation.RefMethod;
  6.  
    import cn.org.atool.fluent.mybatis.annotation.TableField;
  7.  
    import cn.org.atool.fluent.mybatis.annotation.TableId;
  8.  
    import cn.org.atool.fluent.mybatis.base.RichEntity;
  9.  
    import com.freekai.custom.FreekaiMapper;
  10.  
    import java.util.Date;
  11.  
    import lombok.AllArgsConstructor;
  12.  
    import lombok.Data;
  13.  
    import lombok.EqualsAndHashCode;
  14.  
    import lombok.NoArgsConstructor;
  15.  
    import lombok.experimental.Accessors;
  16.  
     
  17.  
    /**
  18.  
    * UserTestEntity: 数据映射实体定义
  19.  
    *
  20.  
    * @author Powered By Fluent Mybatis
  21.  
    */
  22.  
    @SuppressWarnings({"rawtypes", "unchecked"})
  23.  
    @Data
  24.  
    @Accessors(
  25.  
    chain = true
  26.  
    )
  27.  
    @EqualsAndHashCode(
  28.  
    callSuper = false
  29.  
    )
  30.  
    @AllArgsConstructor
  31.  
    @NoArgsConstructor
  32.  
    @FluentMybatis(
  33.  
    table = "user_test",
  34.  
    schema = "test",
  35.  
    superMapper = FreekaiMapper.class,
  36.  
    desc = "userTest表的简单描述"
  37.  
    )
  38.  
    public class UserTestEntity extends RichEntity {
  39.  
    private static final long serialVersionUID = 1L;
  40.  
     
  41.  
    @TableId(
  42.  
    value = "id",
  43.  
    auto = false
  44.  
    )
  45.  
    private Integer id;
  46.  
     
  47.  
    @TableField("address_id")
  48.  
    private Integer addressId;
  49.  
     
  50.  
    @TableField("age")
  51.  
    private Integer age;
  52.  
     
  53.  
    @TableField("create_time")
  54.  
    private Date createTime;
  55.  
     
  56.  
    @TableField("tel")
  57.  
    private String tel;
  58.  
     
  59.  
    @TableField("update_time")
  60.  
    private Date updateTime;
  61.  
     
  62.  
    @TableField("user_name")
  63.  
    private String userName;
  64.  
     
  65.  
    @TableField("version")
  66.  
    private Integer version;
  67.  
     
  68.  
    @TableField(
  69.  
    value = "is_delete",
  70.  
    insert = "0",
  71.  
    desc = "是否删除"
  72.  
    )
  73.  
    @LogicDelete
  74.  
    private Boolean isDelete;
  75.  
     
  76.  
    @Override
  77.  
    public final Class entityClass() {
  78.  
    return UserTestEntity.class;
  79.  
    }
  80.  
     
  81.  
    /**
  82.  
    * @see com.freekai.fluent.IEntityRelation#findAddressV2OfUserTestEntity(java.util.List)
  83.  
    */
  84.  
    @RefMethod("userTestId = id")
  85.  
    public UserTestAddressEntity findAddressV2() {
  86.  
    return super.invoke("findAddressV2", true);
  87.  
    }
  88.  
    }
学新通

userTestAddress.java

  1.  
    package com.freekai.fluent.entity;
  2.  
     
  3.  
    import cn.org.atool.fluent.mybatis.annotation.FluentMybatis;
  4.  
    import cn.org.atool.fluent.mybatis.annotation.RefMethod;
  5.  
    import cn.org.atool.fluent.mybatis.annotation.TableField;
  6.  
    import cn.org.atool.fluent.mybatis.annotation.TableId;
  7.  
    import cn.org.atool.fluent.mybatis.base.RichEntity;
  8.  
    import com.freekai.custom.FreekaiMapper;
  9.  
    import lombok.AllArgsConstructor;
  10.  
    import lombok.Data;
  11.  
    import lombok.EqualsAndHashCode;
  12.  
    import lombok.NoArgsConstructor;
  13.  
    import lombok.experimental.Accessors;
  14.  
     
  15.  
    /**
  16.  
    * UserTestAddressEntity: 数据映射实体定义
  17.  
    *
  18.  
    * @author Powered By Fluent Mybatis
  19.  
    */
  20.  
    @SuppressWarnings({"rawtypes", "unchecked"})
  21.  
    @Data
  22.  
    @Accessors(
  23.  
    chain = true
  24.  
    )
  25.  
    @EqualsAndHashCode(
  26.  
    callSuper = false
  27.  
    )
  28.  
    @AllArgsConstructor
  29.  
    @NoArgsConstructor
  30.  
    @FluentMybatis(
  31.  
    table = "user_test_address",
  32.  
    schema = "test",
  33.  
    superMapper = FreekaiMapper.class
  34.  
    )
  35.  
    public class UserTestAddressEntity extends RichEntity {
  36.  
    private static final long serialVersionUID = 1L;
  37.  
     
  38.  
    @TableId(
  39.  
    value = "id",
  40.  
    auto = false
  41.  
    )
  42.  
    private Integer id;
  43.  
     
  44.  
    @TableField("address")
  45.  
    private String address;
  46.  
     
  47.  
    @TableField("user_test_id")
  48.  
    private Integer userTestId;
  49.  
     
  50.  
    @Override
  51.  
    public final Class entityClass() {
  52.  
    return UserTestAddressEntity.class;
  53.  
    }
  54.  
     
  55.  
    /**
  56.  
    * @see com.freekai.fluent.IEntityRelation#findUserTestV2OfUserTestAddressEntity(UserTestAddressEntity)
  57.  
    */
  58.  
    @RefMethod
  59.  
    public UserTestEntity findUserTestV2() {
  60.  
    return super.invoke("findUserTestV2", true);
  61.  
    }
  62.  
    }
学新通

 思考有个问题,如何像JPA一样根据主键 是否删除这个字段查询呢? 实现是比较简单,那么是不是每个实体类都需要再写一遍很类似的代码呢? ans:不需要。见下方

superMapper指定了自定义的一个类FreekaiMapper,这个类里,我自定义了一个根据主键 是否删除这个字段查询的方法。 相当于Jpa中 findByIdAndIsDelete(id, isDelete)..., FreekaiMapper.class内容如下
  1.  
    package com.freekai.custom;
  2.  
     
  3.  
    import cn.org.atool.fluent.mybatis.If;
  4.  
    import cn.org.atool.fluent.mybatis.base.IEntity;
  5.  
    import cn.org.atool.fluent.mybatis.base.crud.IQuery;
  6.  
    import cn.org.atool.fluent.mybatis.base.crud.IWrapper;
  7.  
    import cn.org.atool.fluent.mybatis.base.entity.IMapping;
  8.  
    import cn.org.atool.fluent.mybatis.base.free.FreeQuery;
  9.  
    import cn.org.atool.fluent.mybatis.base.mapper.IEntityMapper;
  10.  
    import cn.org.atool.fluent.mybatis.base.mapper.IMapper;
  11.  
    import cn.org.atool.fluent.mybatis.base.mapper.IRichMapper;
  12.  
    import cn.org.atool.fluent.mybatis.base.model.SqlOp;
  13.  
    import cn.org.atool.fluent.mybatis.base.provider.SqlKitFactory;
  14.  
    import cn.org.atool.fluent.mybatis.exception.FluentMybatisException;
  15.  
    import cn.org.atool.fluent.mybatis.segment.WhereBase;
  16.  
    import cn.org.atool.fluent.mybatis.segment.model.WrapperData;
  17.  
    import org.apache.ibatis.annotations.Mapper;
  18.  
    import org.springframework.stereotype.Component;
  19.  
    import org.springframework.util.StringUtils;
  20.  
     
  21.  
    import java.util.List;
  22.  
     
  23.  
    /**
  24.  
    * 自定义mapper,在代码生成时 配置一个supperMapper
  25.  
    * 或者是在entity实体类上的@FluentMybatis注解中配置superMapper值
  26.  
    * @FluentMybatis(
  27.  
    * table = "user_test",
  28.  
    * schema = "test",
  29.  
    * superMapper = FreekaiMapper.class
  30.  
    * )
  31.  
    *
  32.  
    *
  33.  
    * @param <E>
  34.  
    */
  35.  
    public interface FreekaiMapper<E extends IEntity> extends IEntityMapper<E>, IRichMapper<E> {
  36.  
     
  37.  
    default E findByIdAndIsDelete(Object id, Boolean isDelete) {
  38.  
    final IMapping mapping = this.mapping();
  39.  
    IQuery query = mapping.emptyQuery();
  40.  
    String primary = mapping.primaryId(true);
  41.  
    // 逻辑删除的字段
  42.  
    final String loginDeleteColumn = mapping.logicDeleteColumn();
  43.  
    final WhereBase apply = query.where().apply(primary, SqlOp.EQ, new Object[]{id});
  44.  
    if(!StringUtils.isEmpty(loginDeleteColumn)){
  45.  
    apply.and.apply(loginDeleteColumn, SqlOp.EQ, isDelete);
  46.  
    }
  47.  
    final List<E> list = this.listEntity(query);
  48.  
    if (If.isEmpty(list)) {
  49.  
    return null;
  50.  
    } else if (list.size() == 1) {
  51.  
    return list.get(0);
  52.  
    } else {
  53.  
    throw new FluentMybatisException("Expected one result (or null) to be returned, but found " list.size() " results.");
  54.  
    }
  55.  
    }
  56.  
    }
学新通
其中fluent-mybatis语法可以去官方查看对应的文档。下面一个controller是自己随便写的一些,完整的项目代码在github上。 https://github.com/freekai777/freekai-fluent-mybatis-demo学新通https://github.com/freekai777/freekai-fluent-mybatis-demo
  1.  
    package com.freekai.controller;
  2.  
     
  3.  
    import cn.org.atool.fluent.mybatis.base.free.FreeQuery;
  4.  
    import cn.org.atool.fluent.mybatis.base.model.FieldMapping;
  5.  
    import cn.org.atool.fluent.mybatis.model.StdPagedList;
  6.  
    import com.freekai.dto.SimpleUserTestDTO;
  7.  
    import com.freekai.entity.HelloFluentEntity;
  8.  
    //import com.freekai.mapper.HelloFluentMapper;
  9.  
    import com.freekai.fluent.entity.UserTestEntity;
  10.  
    import com.freekai.fluent.mapper.UserTestMapper;
  11.  
    import com.freekai.fluent.wrapper.UserTestQuery;
  12.  
    import com.freekai.mapper.HelloFluentMapper;
  13.  
    import org.springframework.beans.factory.annotation.Autowired;
  14.  
    import org.springframework.util.StringUtils;
  15.  
    import org.springframework.web.bind.annotation.*;
  16.  
     
  17.  
    import java.util.HashMap;
  18.  
    import java.util.List;
  19.  
    import java.util.Map;
  20.  
    import java.util.Random;
  21.  
     
  22.  
    @RestController
  23.  
    public class HelloFluentMybatisController {
  24.  
     
  25.  
    @Autowired
  26.  
    private UserTestMapper userTestMapper;
  27.  
     
  28.  
    @PostMapping("/addHello")
  29.  
    public int addHello(){
  30.  
    UserTestEntity entity = new UserTestEntity();
  31.  
    entity.setId(1000*new Random().nextInt(10) 1);
  32.  
    final int insert = userTestMapper.insertWithPk(entity);
  33.  
    return insert;
  34.  
    }
  35.  
     
  36.  
    @PutMapping("/updateUser")
  37.  
    public int updateUser(@RequestParam String id){
  38.  
    final UserTestEntity byIdAndIsDelete = userTestMapper.findByIdAndIsDelete(id, false);
  39.  
    return 1;
  40.  
    }
  41.  
     
  42.  
    @GetMapping("/user")
  43.  
    public UserTestEntity get(@RequestParam Integer userId ){
  44.  
    final UserTestEntity byId = userTestMapper.findById(userId);
  45.  
    return byId;
  46.  
    }
  47.  
     
  48.  
    /**
  49.  
    * 聚合的语法
  50.  
    * @return
  51.  
    */
  52.  
    @GetMapping("/agg")
  53.  
    public List<Map<String,Object>> aggregation(){
  54.  
    final List<Map<String, Object>> maps = userTestMapper.listMaps(userTestMapper.query().select.userName("userNameAlias")
  55.  
    .count("cc").end().groupBy.userName().end().orderBy.desc("cc").end());
  56.  
    return maps;
  57.  
    }
  58.  
     
  59.  
    /**
  60.  
    * 分页查询
  61.  
    * @param userName
  62.  
    * @param page
  63.  
    * @param size
  64.  
    * @return
  65.  
    */
  66.  
    @GetMapping("/users")
  67.  
    public StdPagedList<UserTestEntity> list(@RequestParam(required = false, value = "userName") String userName,
  68.  
    @RequestParam(value = "page", defaultValue = "1",required = false) Integer page,
  69.  
    @RequestParam(value = "size", defaultValue = "10",required = false) Integer size){
  70.  
    final StdPagedList<UserTestEntity> res = userTestMapper.stdPagedEntity(new UserTestQuery().where.userName()
  71.  
    .like(userName, !StringUtils.isEmpty(userName)).end().limit((page - 1) * size, size));
  72.  
    return res;
  73.  
    }
  74.  
     
  75.  
    /**
  76.  
    * 分页且映射成自定义实体类的查询
  77.  
    *
  78.  
    * 查询出来的 字段取的别名一定要求在 映射的实体类中存在。否则会报错!!
  79.  
    *
  80.  
    */
  81.  
    @GetMapping("/users2")
  82.  
    public StdPagedList<SimpleUserTestDTO> listWithDtos(@RequestParam(required = false, value = "userName") String userName,
  83.  
    @RequestParam(value = "page", defaultValue = "1",required = false) Integer page,
  84.  
    @RequestParam(value = "size", defaultValue = "10",required = false) Integer size){
  85.  
    final StdPagedList<SimpleUserTestDTO> res = userTestMapper.stdPagedPoJo(SimpleUserTestDTO.class, new UserTestQuery()
  86.  
    .select.id("idNew").createTime("createTime").end().where.userName()
  87.  
    .like(userName, !StringUtils.isEmpty(userName)).end().limit((page - 1) * size, size));
  88.  
    return res;
  89.  
    }
  90.  
     
  91.  
    /**
  92.  
    * 自定义sql查询
  93.  
    * 通过占位符的形式 username
  94.  
    * @return
  95.  
    */
  96.  
    @GetMapping("/custom_sql")
  97.  
    public List<Map<String,Object>> customQuery(@RequestParam String userName){
  98.  
    Map<String,String> param = new HashMap<>(16);
  99.  
    param.put("userNN", userName "%");
  100.  
     
  101.  
    final FreeQuery freeQuery = new FreeQuery(null).customizedByPlaceholder(" select * from user_test t where t.user_name like #{userNN} ", param);
  102.  
    final List<Map<String, Object>> maps = userTestMapper.listMaps(freeQuery);
  103.  
    return maps;
  104.  
    }
  105.  
    }
学新通

另外也有一种,甚至连实现都不用写的,直接用Jpa的写法。需要在类上加注解

@FormService(table = "user_test")

,然后在启动类上配置扫描路径

@SpringBootApplication
@MapperScan({"com.freekai.mapper","com.freekai.fluent"})
@FormServiceScan("com.freekai.controller")
public class FluentMybatisApplication {...}
  1.  
    @RestController
  2.  
    @FormService(table = "user_test")
  3.  
    public interface HelloFluentRestApi {
  4.  
     
  5.  
    @GetMapping("/findByUserName")
  6.  
    UserTestEntity findByUserName(@RequestParam("userName") @Entry(value = "userName") String userName);
  7.  
    }

通过postMan调用,发现也可以出现正确的结果。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgjgeai
系列文章
更多 icon
同类精品
更多 icon
继续加载