文档预览: durcframework/easymybatis
Export by Gitee
easymybatis开发文档

easymybatis开发文档

easymybatis是一个mybatis增强类库,目的为简化mybatis的开发,让开发更高效。

easymybatis的特性如下:

  • 无需编写xml文件即可完成CRUD操作。
  • 支持多表查询、聚合查询、分页查询(支持多种数据库)。
  • 支持批量添加,指定字段批量添加。
  • 支持Dao层访问控制,如某个dao只有查询功能,某个dao有crud功能等。
  • 支持自定义sql,sql语句可以写在配置文件中,同样支持mybatis标签。
  • 支持mysql,sqlserver,oracle,其它数据库扩展方便(增加一个模板文件即可)。
  • 使用方式不变,与Spring集成只改了一处配置。
  • 支持与springboot集成。
  • mybatis参数设置灵活,继承mybatis官方设置方式。
  • 轻量级,无侵入性,可与传统mybatis用法共存。
  • 没有修改框架源码(无插件),可同时使用官方提供的功能。

easymybatis支持的功能如下:

  • 基本的CRUD
  • 主键策略设置
  • 字段填充功能
  • 枚举属性
  • 全局Dao
  • 乐观锁
  • 逻辑删除

架构组成

easymybatis的架构如下:

架构

运行流程

easymybatis的运行流程图:

运行流程

  1. 服务器启动的时候easymybatis负责扫描Dao.java。
  2. 扫描完成后解析出Dao.class以及实体类Entity.class。
  3. 代码生成组件根据Dao.class和Entity.class生成mapper文件内容,生成方式由velocity模板指定。
  4. 把mapper文件内容转化成Resource对象设置到SqlSessionFactory中。

快速开始

创建springboot项目

访问http://start.spring.io/ 生成一个springboot空项目,输入Group,Artifact点生成即可,如图: 创建空项目 点击Generate Project,下载demo.zip

导入项目

将下载的demo.zip解压,然后导入项目。eclipse中右键 -> Import... -> Existing Maven Project,选择项目文件夹。导入到eclipse中后等待maven相关jar包下载。

添加maven依赖

jar包下载完成后,打开pom.xml,添加如下依赖:

<!-- easymybatis的starter -->
<dependency>
    <groupId>net.oschina.durcframework</groupId>
    <artifactId>easymybatis-spring-boot-starter</artifactId>
    <version>1.8.4</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

添加数据库配置

在application.properties中添加数据库配置

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/stu?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
spring.datasource.username=root
spring.datasource.password=root

添加Java文件

假设数据库中有张t_user表,DDL如下:

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `username` varchar(255) DEFAULT NULL COMMENT '用户名',
  `state` tinyint(4) DEFAULT NULL COMMENT '状态',
  `isdel` bit(1) DEFAULT NULL COMMENT '是否删除',
  `remark` text COMMENT '备注',
  `add_time` datetime DEFAULT NULL COMMENT '添加时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

我们加入对应的实体类和Dao:

  • TUser.java :
@Table(name = "t_user")
public class TUser {    
    @Id
    @Column(name="id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id; // ID   
    private String username; // 用户名 
    private Byte state; // 状态   
    private Boolean isdel;  // 是否删除 
    private String remark;  // 备注   
    private Date addTime;   // 添加时间
    
    // 省略 getter setter
}

实体类文件采用和hibernate相同的方式,您可以使用我们的代码生成工具生成 https://gitee.com/durcframework/easymybatis-generator

  • TUserDao.java :
public interface TUserDao extends CrudDao<TUser> {
}

TUserDao继承CrudDao即可,这样这个Dao就拥有了CRUD功能。

添加测试用例

public class TUserDaoTest extends DemoApplicationTests {

    @Autowired
    TUserDao dao;

        @Test
    public void testInsert() {
        TUser user = new TUser();
        user.setIsdel(false);       
        user.setRemark("testInsert");       
        user.setUsername("张三");
        
        dao.save(user);
        
        System.out.println("添加后的主键:" + user.getId());       
    }
    
    @Test
    public void testGet() {
        TUser user = dao.get(3);
        System.out.println(user);                
    }

        @Test
    public void testUpdate() {
        TUser user = dao.get(3);
        user.setUsername("李四");     
        user.setIsdel(true);
        
        int i = dao.update(user);
        System.out.println("testUpdate --> " + i);
    }

        @Test
    public void testDel() {
        TUser user = new TUser();
        user.setId(3);
        int i = dao.del(user);
        System.out.println("del --> " + i);
    }
}

然后运行单元测试,运行成功后表示项目已经搭建完毕了。

最后项目结构图:

最后项目结构图

查询

本小节主要讲解easymybatis的查询功能。easymybatis提供丰富的查询方式,满足日常查询所需。

分页查询

方式1

前端传递两个分页参数pageIndex,pageSize

    // http://localhost:8080/page1?pageIndex=1&pageSize=10
    @GetMapping("page1")
    public List<TUser> page1(int pageIndex,int pageSize) {
        Query query = new Query().page(pageIndex, pageSize);
        List<TUser> list = dao.find(query);
        return list;
    }

方式2

PageParam里面封装了pageIndex,pageSize参数

    // http://localhost:8080/page2?pageIndex=1&pageSize=10
    @GetMapping("page2")
    public List<TUser> page2(PageParam param) {
        Query query = param.toQuery();
        List<TUser> list = dao.find(query);
        return list;
    }

返回结果集和总记录数

方式1和方式2只能查询结果集,通常我们查询还需返回记录总数并返回给前端,easymybatis的处理方式如下:

// http://localhost:8080/page3?pageIndex=1&pageSize=10
    @GetMapping("page3")
    public Map<String,Object> page3(PageParam param) {
        Query query = param.toQuery();
        List<TUser> list = dao.find(query);
        long total = dao.countTotal(query);
        
        Map<String,Object> result = new HashMap<String, Object>();
        result.put("list", list);
        result.put("total", total);
        
        return result;
    }

easymybatis提供一种更简洁的方式来处理:

// http://localhost:8080/page4?pageIndex=1&pageSize=10
    @GetMapping("page4")
    public PageInfo<TUser> page4(PageParam param) {
        PageInfo<TUser> result = QueryUtils.query(dao, param);
        return result;
    }

PageInfo里面包含了List,total信息,还包含了一些额外信息,完整数据如下:

{
    "currentPageIndex": 1, // 当前页
    "firstPageIndex": 1, // 首页
    "lastPageIndex": 2, // 尾页
    "list": [     // 结果集
        {},
        {}
    ],
    "nextPageIndex": 2, // 下一页
    "pageCount": 2, // 总页数
    "pageIndex": 1, // 当前页
    "pageSize": 10, // 每页记录数
    "prePageIndex": 1, // 上一页
    "start": 0,
    "total": 20 // 总记录数
}

完整代码

@RestController
public class UserSchController {

    @Autowired
    private TUserDao dao;
    
    // http://localhost:8080/page1?pageIndex=1&pageSize=10
    @GetMapping("page1")
    public List<TUser> page1(int pageIndex,int pageSize) {
        Query query = new Query().page(pageIndex, pageSize);
        List<TUser> list = dao.find(query);
        return list;
    }
    
    // http://localhost:8080/page2?pageIndex=1&pageSize=10
    @GetMapping("page2")
    public List<TUser> page2(PageParam param) {
        Query query = param.toQuery();
        List<TUser> list = dao.find(query);
        return list;
    }
    
    // http://localhost:8080/page3?pageIndex=1&pageSize=10
    @GetMapping("page3")
    public Map<String,Object> page3(PageParam param) {
        Query query = param.toQuery();
        List<TUser> list = dao.find(query);
        long total = dao.countTotal(query);
        
        Map<String,Object> result = new HashMap<String, Object>();
        result.put("list", list);
        result.put("total", total);
        
        return result;
    }
    
    // http://localhost:8080/page4?pageIndex=1&pageSize=10
    @GetMapping("page4")
    public PageInfo<TUser> page4(PageParam param) {
        PageInfo<TUser> result = QueryUtils.query(dao, param);
        return result;
    }
}

联表分页查询

  • 方式1:代码形式
/**
     * 联表分页
     * SELECT t.`id` , t.`username` , t.`state` , t.`isdel` , t.`remark` , t.`add_time` , t.`money` , t.`left_money` 
     * FROM `t_user` t 
     * LEFT JOIN user_info t2 ON t.id = t2.user_id 
     * WHERE t.isdel = 0 LIMIT ?,? 
     */
    @Test
    public void testJoinPage() {
        Query query = Query.build()
             // 左连接查询,主表的alias默认为t
                .join("LEFT JOIN user_info t2 ON t.id = t2.user_id")
                .page(1, 5); 
        
        List<TUser> list = dao.find(query);
        
        System.out.println("==============");
        for (TUser user : list) {
            System.out.println(
                user.getId() 
                + " " + user.getUsername() 
            );
        }
        System.out.println("==============");
    }
  • 方式2:xml形式:

xml:

<select id="findJoinPage"
        parameterType="net.oschina.durcframework.easymybatis.query.Pageable"
        resultMap="baseResultMap">
        SELECT t.*,t2.city,t2.address
        FROM t_user t LEFT JOIN user_info t2 ON t.id = t2.user_id
        <include refid="common.where" />
        <include refid="common.orderBy" />
        <include refid="common.limit" />
    </select>

java:

 @Test
    public void testJoinPageXml() {
        Query query = Query.build()
                    .page(1, 5); 
            
        List<TUser> list = dao.findJoinPage(query);
        
        System.out.println("==============");
        for (TUser user : list) {
            System.out.println(
                user.getId() 
                + " " + user.getUsername() 
            );
        }
        System.out.println("==============");
    }

根据参数字段查询

查询姓名为张三的用户

// http://localhost:8080/sch?username=张三
    @GetMapping("sch")
    public List<TUser> sch(String username) {
        Query query = new Query();
        query.eq("username", username);
        List<TUser> list = dao.find(query);
        return list;
    }

查询姓名为张三并且拥有的钱大于100块

// http://localhost:8080/sch2?username=张三
    @GetMapping("sch2")
    public List<TUser> sch2(String username) {
        Query query = new Query();
        query.eq("username", username).gt("money", 100);
        List<TUser> list = dao.find(query);
        return list;
    }

查询姓名为张三并带分页

// http://localhost:8080/sch3?username=张三&pageIndex=1&pageSize=5
    @GetMapping("sch3")
    public List<TUser> sch3(String username,PageParam param) {
        Query query = param.toQuery();
        query.eq("username", username);
        List<TUser> list = dao.find(query);
        return list;
    }

查询钱最多的前三名

// http://localhost:8080/sch4
    @GetMapping("sch4")
    public List<TUser> sch4() {
        Query query = new Query();
        query.orderby("money", Sort.DESC) // 按金额降序
            .page(1, 3);
        List<TUser> list = dao.find(query);
        return list;
    }

将参数放在对象中查询

// http://localhost:8080/sch5?username=张三
    @GetMapping("sch5")
    public List<TUser> sch5(UserParam userParam) {
        Query query = userParam.toQuery();
        query.eq("username", userParam.getUsername());
        List<TUser> list = dao.find(query);
        return list;
    }

UserParam继承PageSortParam类,表示支持分页和排序查询

使用普通bean查询

假设有个User类如下

public class User {
    private Integer id;
    private String userName;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

我们将这个类作为查询参数,那么在springmvc中可以这样写:

@GetMapping(path="findUserBean.do")
public List<User> findUser(User user) {
    Query query = Query.build(user);
    List<User> list = dao.find(query);
    return list;
}

Query query = Query.buildFromBean(user);这句是将User中的属性转换成对应条件,假设userName的值为"jim",那么会封装成一个条件where user_name='jim'

浏览器输入链接:http://localhost:8080/easymybatis-springmvc/findUserBean.do?userName=jim 后台将会执行如下SQL:

SELECT id,user_name FROM user t WHERE t.user_name = ?

?的值为jim

@Condition注解

@Condition注解用来强化查询,有了这个注解可以生成各种查询条件。

@Condition注解有三个属性:

  • joint:表达式之间的连接符,AND|OR,默认AND
  • column:数据库字段名,可选
  • operator:连接符枚举,存放了等于、大于、小于等连接符

如果要查询id大于2的用户只需在get方法上加上一个@Condition注解即可:

@Condition(operator=Operator.gt)
public Integer getId() {
    return this.id;
}

这样,当id有值时,会封装成一个where id>2的条件

  • 需要注意的是,如果不指定column属性,系统会默认取get方法中属性名,然后转换成数据库字段名。如果需要指定数据库字段名的话,可以使用@Condition的column属性。

public Integer get++UserName++() { return this.userName; }

这种情况下会取下划线部分字段,然后转换成数据库字段名。

@Condition(column="username") // 显示指定字段名
public Integer getUserName() {
    return this.userName;
}

使用@Condition可以生产更加灵活的条件查询,比如需要查询日期为2017-12-1~2017-12-10日的记录,我们可以这样写:

@Condition(column="add_date",operator=Operator.ge)
public Date getStartDate() {
    return this.startDate;
}

@Condition(column="add_date",operator=Operator.lt)
public Date getEndDate() {
    return this.endDate;
}

转换成SQL语句:

t.add_date>='2017-12-1' AND t.add_date<'2017-12-10'

IN查询

假设前端页面传来多个值比如checkbox勾选多个id=[1,2],那么我们在User类里面可以用Integer[]或List来接收.

private Integer[] idArr;

public void setIdArr(Integer[] idArr) {this.idArr = idArr;}

@Condition(column="id")
public Integer[] getIdArr() {return this.idArr;}

这样会生成where id IN(1,2)条件。

排序查询

// 根据添加时间倒序

Query query = new Query();
query.addSort("create_time",Sort.DESC);
dao.find(query);

多表关联查询

多表关联查询使用的地方很多,比如需要关联第二张表,获取第二张表的几个字段,然后返回给前端。

easymybatis的用法如下: 假如我们需要关联第二张表,并且获取第二张表里的city,address字段。步骤如下:

  • 在实体类中添加city,address字段,并标记@Transient注解。只要不是主表中的字段都要加上@Transient
@Transient
private String city;
@Transient
private String address;

// getter setter
  • 接下来是查询代码:
Query query = new Query();
// 添加第二张表的字段,跟主表字段一起返回
query.addOtherColumns(
    "t2.city"
    ,"t2.address"
);
// 左连接查询,主表的alias默认为t
query.join("LEFT JOIN user_info t2 ON t.id = t2.user_id"); 
// 添加查询条件
query.eq("t.username", "张三");

List<TUser> list = dao.find(query);

得到的SQL语句:

SELECT 
    t.`id` , t.`username` , t.`state` , t.`isdel` , t.`remark` , t.`add_time` , t.`money` , t.`left_money` 
    , t2.city , t2.address 
FROM `t_user` t LEFT JOIN user_info t2 ON t.id = t2.user_id 
WHERE t.username = ?
LIMIT ?,?

关联了user_info表之后,还可以筛选user_info的数据,也就是针对user_info表进行查询:

query.eq("t2.city","杭州");

使用@Select查询

@Select注解是mybatis官方提供的一个功能,easymybatis可以理解为是官方的一种扩展,因此同样支持此功能。 在Dao中添加如下代码:

@Select("select * from t_user where id=#{id}")
TUser selectById(@Param("id") int id);

编写测试用例

@Test
public void testSelectById() {
    TUser user = dao.selectById(3);

    System.out.println(user.getUsername());
}

除了@Select之外,还有@Update,@Insert,@Delete,这里就不多做演示了。

Query类详解

Query是一个查询参数类,通常配合Dao一起使用。

参数介绍

Query里面封装了一系列查询参数,主要分为以下几类:

  • 分页参数:设置分页
  • 排序参数:设置排序字段
  • 条件参数:设置查询条件
  • 字段参数:可返回指定字段

下面逐个讲解每个参数的用法。

分页参数

一般来说分页的使用比较简单,通常是两个参数, pageIndex:当前页索引,pageSize:每页几条数据。 Query类使用**page(pageIdnex, pageSize)**方法来设置。 假如我们要查询第二页,每页10条数据,代码可以这样写:

Query query = new Query().page(2, 10);
List<User> list = dao.find(query);

如果要实现不规则分页,可以这样写:

Query query = new Query().limit(3,5);
// 对应mysql:limit 3,5
  • 如果要查询所有数据,则可以这样写:
Query query = new Query();
List<User> list = dao.findAll(query);

排序参数

设置排序:

orderby(String sortname, Sort sort)

其中sortname为数据库字段,非javaBean属性

  • orderby(String sortname, Sort sort)则可以指定排序方式,Sort为排序方式枚举 假如要按照添加时间倒序,可以这样写:
Query query = new Query().orderby("create_time",Sort.DESC);
dao.find(query);

添加多个排序字段可以在后面追加:

query.orderby("create_time",Sort.DESC).orderby("id",Sort.ASC);

条件参数

条件参数是用的最多一个,因为在查询中往往需要加入各种条件。 easymybatis在条件查询上面做了一些封装,这里不做太多讲解,只讲下基本的用法,以后会单独开一篇文章来介绍。感兴趣的同学可以自行查看源码,也不难理解。

条件参数使用非常简单,Query对象封装一系列常用条件查询。

  • 等值查询eq(String columnName, Object value),columnName为数据库字段名,value为查询的值 假设我们要查询姓名为张三的用户,可以这样写:
Query query = new Query();
query.eq("username","张三");
List<User> list = dao.find(query);

通过方法名即可知道eq表示等于'=',同理lt表示小于<,gt表示大于>

查询方式 说明
eq 等于=
gt 大于>
lt 小于<
ge 大于等于>=
le 小于等于<=
notEq 不等于<>
like 模糊查询
in in()查询
notIn not in()查询
isNull NULL值查询
notNull IS NOT NULL
notEmpty 字段不为空,非NULL且有内容
isEmpty 字段为NULL或者为''

如果上述方法还不能满足查询需求的话,我们可以使用自定sql的方式来编写查询条件,方法为:

Query query = new Query();
query.sql(" username='Jim' OR username='Tom'");

注意:sql()方法不会处理sql注入问题,因此尽量少用。

字段参数

在某些场景下,我们只想获取表里面几个字段的信息,不想查询所有字段。此时使用方式如下:

Query query = new Query();
// 只返回id,username
query.setColumns(Arrays.asList("id","username"));
List<TUser> list = dao.find(query);

这里的"id","username"都为数据库字段。

主键策略设置

跟hibernate的主键生成策略一致

主键自增

数据库主键设置自增后,这样设置:

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

这样在做insert后,id会自动填充自增后的值。

主键使用uuid

数据库主键是varchar类型,insert后自动填充uuid,并返回。

@Id
@Column(name = "id")
@GeneratedValue(generator = "system-uuid")
private String id;

这样在做insert后,id字段会自动填充uuid。

  • 注:uuid的生成方式是调用数据库底层实现,如MySql的实现方式为: SELECT UUID()

自定义uuid

如果不希望使用底层数据库的uuid,可自定义自己实现,实现方式如下:

  • 首先entity中的id字段@GeneratedValue注解设置成AUTO
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.AUTO)
private String id;
  • 创建一个类UUIDFill并继承FillHandler类
public class UUIDFill extends FillHandler<String> {
    @Override
    public String getColumnName() {
        return "id"; // 作用在id字段上
    }
    @Override
    public FillType getFillType() {
        return FillType.INSERT; // INSERT时触发
    }
    @Override
    protected Object getFillValue(String defaultValue) {
        return UUID.randomUUID().toString(); // 自定义的uuid生成方式
    }
}
  • 在application.properties中添加
# key:填充器全路径类名,value:构造函数参数值,没有可不填
mybatis.fill.com.xx.aa.UUIDFill=

格式为mybatis.fill.类路径=构造参数(没有可不填)

到此已经可以了,当进行insert操作后,id字段会自动插入自定义的uuid。

但是使用过程中还会有个问题,如果数据库中既有自增主键的表,也有自定义UUID主键的表,那么上面的做法就没办法区分了。因此我们要找出自定义UUID主键的表,解决办法是重写FillHandler的match(Class<?> entityClass, Field field, String columnName)方法,完整的代码如下:

public class UUIDFill extends FillHandler<String> {
    /* 重写方法,自定义匹配
        entityClass     实体类class
        field           字段信息
        columnName      给定的数据库字段名
    */
    @Override
    public boolean match(Class<?> entityClass, Field field, String columnName) {
        boolean isPk = field.getAnnotation(Id.class) != null; // 是否有@Id注解
        
        GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
        boolean isAuto = gv != null && gv.strategy() == GenerationType.AUTO; // 是否有@GeneratedValue注解,并且策略是AUTO
        
        return isPk && isAuto;
    }

    @Override
    public String getColumnName() {
        return "id"; // 作用在id字段上
    }
    @Override
    public FillType getFillType() {
        return FillType.INSERT; // INSERT时触发
    }
    @Override
    protected Object getFillValue(String defaultValue) {
        return UUID.randomUUID().toString(); // 自定义的uuid生成方式
    }

}

这样就能区分出自增主键和自定义主键了。

自定义uuid生成的配置方式采用的是easymybatis提供的字段填充功能,具体说明可参考 字段自动填充 小节。

字段自动填充

填充器设置

假设数据库表里面有两个时间字段gmt_create,gmt_update。

当进行insert操作时gmt_create,gmt_update字段需要更新。当update时,gmt_update字段需要更新。

通常的做法是通过Entity手动设置:

User user = new User();
user.setGmtCreate(new Date());
user.setGmtUpdate(new Date());

因为表设计的时候大部分都有这两个字段,所以对每张表都进行手动设置的话很容易错加、漏加。 easymybatis提供了两个辅助类DateFillInsert和DateFillUpdate,用来处理添加修改时的时间字段自动填充。配置了这两个类之后,时间字段将会自动设置。

springboot项目配置方式如下:

在application.properties中添加

mybatis.fill.net.oschina.durcframework.easymybatis.support.DateFillInsert=
mybatis.fill.net.oschina.durcframework.easymybatis.support.DateFillUpdate=

如果要指定字段名,可以写成:

mybatis.fill.net.oschina.durcframework.easymybatis.support.DateFillInsert=add_time

在springmvc的xml中配置如下:

<bean id="sqlSessionFactory"
        class="net.oschina.durcframework.easymybatis.ext.SqlSessionFactoryBeanExt">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:mybatis/mybatisConfig.xml</value>
        </property>
        <property name="mapperLocations">
            <list>
                <value>classpath:mybatis/mapper/*.xml</value>
            </list>
        </property>
        
        <!-- 以下是附加属性 -->
        
        <!-- dao所在的包名,跟MapperScannerConfigurer的basePackage一致 
            多个用;隔开
        -->
        <property name="basePackage" value="com.myapp.dao" />
        <property name="config">
            <bean class="net.oschina.durcframework.easymybatis.EasymybatisConfig">
                                <!-- 定义填充器 -->
                <property name="fills">
                    <list>
                                        <bean class="net.oschina.durcframework.easymybatis.support.DateFillInsert"/>
                                        <bean class="net.oschina.durcframework.easymybatis.support.DateFillUpdate"/>
                    </list>
                </property>
            </bean>
        </property>
    </bean>

自定义填充器

除了使用easymybatis默认提供的填充之外,我们还可以自定义填充。

自定义填充类要继承FillHandler类。 表示填充字段类型,如Date,String,BigDecimal,Boolean。

实战(springboot)

现在有个remark字段,需要在insert时初始化为“备注默认内容”,新建一个StringRemarkFill类如下:

public class StringRemarkFill extends FillHandler<String> {

    @Override
    public String getColumnName() {
        return "remark";
    }

    @Override
    public FillType getFillType() {
        return FillType.INSERT;
    }

    @Override
    protected Object getFillValue(String defaultValue) {
        return "备注默认内容";
    }

}

StringRemarkFill类中有三个重写方法:

  • getColumnName() : 指定表字段名
  • getFillType() : 填充方式,FillType.INSERT:仅insert时填充; FillType.UPDATE:insert,update时填充
  • getFillValue(String defaultValue) :返回填充内容

然后在application.properties中添加

mybatis.fill.com.xx.StringRemarkFill=

这样就配置完毕了,调用dao.save(user);时会自动填充remark字段。

指定目标类

上面说到StringRemarkFill填充器,它作用在所有实体类上,也就是说实体类如果有remark字段都会自动填充。这样显然是不合理的,解决办法是指定特定的实体类。只要重写FillHandler类的getTargetEntityClasses()方法即可。

@Override
public Class<?>[] getTargetEntityClasses() {
    return new Class<?>[] { TUser.class };
}

这样就表示作用在TUser类上,多个类可以追加。最终代码如下:

public class StringRemarkFill extends FillHandler<String> {

    @Override
    public String getColumnName() {
        return "remark";
    }

    @Override
    public Class<?>[] getTargetEntityClasses() {
        return new Class<?>[] { TUser.class }; // 只作用在TUser类上
    }

    @Override
    public FillType getFillType() {
        return FillType.INSERT;
    }

    @Override
    protected Object getFillValue(String defaultValue) {
        return "备注默认内容"; // insert时填充的内容
    }

}

高级匹配

覆盖FillHandler类中的match方法可以让填充器做更高级的匹配,match方法如下

/**
 * 是否能够作用到指定字段
 * @param entityClass 实体类class
 * @param field 字段信息
 * @param columnName 给定的数据库字段名
 * @return
 */
public boolean match(Class<?> entityClass, Field field, String columnName)

这个方法返回的是一个boolean,返回true则代表作用到该属性上。例如下面的代码:

  • 匹配出含有@Id和@GeneratedValue(strategy=GenerationType.AUTO)的字段
public boolean match(Class<?> entityClass, Field field, String columnName) {
        boolean isPk = field.getAnnotation(Id.class) != null; // 是否有@Id注解
        
        GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
        boolean isAuto = gv != null && gv.strategy() == GenerationType.AUTO; // 是否有@GeneratedValue注解,并且策略是AUTO
        
        return isPk && isAuto;
    }

关于自动填充的原理是基于mybatis的TypeHandler实现的,这里就不多做介绍了。感兴趣的同学可以查看FillHandler源码。

Entity中使用枚举字段

数据库中一些状态字段通常用0,1,2或者简单的字符串进行维护,然后JavaBean实体类中用枚举类型来保存,这样做便于使用和维护。

easymybatis上使用枚举属性很简单:枚举类实现net.oschina.durcframework.easymybatis.handler.BaseEnum接口即可。

下面是具体例子:

第一步

public enum UserInfoType implements BaseEnum<String> {
    INVALID("0"),VALID("1")
    ;

    private String status;

    UserInfoType(String type) {
        this.status = type;
    }
    
    @Override
    public String getCode() {
        return status;
    }
}

首先定义一个枚举类,实现BaseEnum接口,接口类型参数用String,表示保存的值是String类型,如果要保存Int类型的话改用BaseEnum。

第二步

在javaBean添加该枚举属性:

public class UserInfo {
    ...
    private UserInfoType status;

    // 省略getter setter
}

接下来就可以使用dao来进行数据操作了,下面是完整测试用例:

public class UserInfoDaoTest extends EasymybatisSpringbootApplicationTests {
    
    @Autowired
    UserInfoDao userInfoDao;
    
    @Test
    public void testGet() {
        UserInfo userInfo = userInfoDao.get(3);
        print("枚举字段status:" + userInfo.getStatus().getCode());
        print(userInfo);
    }
    
    @Test
    public void testUpdate() {
        UserInfo userInfo = userInfoDao.get(3);
        // 修改枚举值
        userInfo.setStatus(UserInfoType.INVALID);
        userInfoDao.update(userInfo);
    }
    
    @Test
    public void testSave() {
        UserInfo userInfo = new UserInfo();
        userInfo.setAddress("aa");
        userInfo.setCity("杭州");
        userInfo.setCreateTime(new Date());
        userInfo.setUserId(3);
        // 枚举值
        userInfo.setStatus(UserInfoType.VALID);
        userInfoDao.save(userInfo);
    }
}
 

SQL写在xml中

easymybatis提供的一些查询方式已经满足大部分的查询需求,但是有些复杂的sql语句还是需要写在xml文件中。easymybatis同样支持将sql语句写在xml中,具体配置如下:

  • 在application.properties添加一句
mybatis.mapper-locations=classpath:/mybatis/mapper/*.xml

这句话用来指定xml文件的存放地。

  • 在resources目录下新建一个mybatis文件夹,在mybatis文件夹下新建mapper文件夹。 新建一个xml文件,名字跟Dao名字一致,如TUserDao.xml,建完后的文件路径是resources/mybatis/mapper/TUserDao.xml

  • 在xml中添加sql语句,如下:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 注意:文件名必须跟Dao类名字一致,因为是根据文件名做关联。 -->
<mapper>
    
    <select id="selectByName" parameterType="String" resultMap="baseResultMap">
        select * from t_user t where t.username = #{username} limit 1
    </select>
    
</mapper>

这个xml文件跟其它的mybatis配置文件一样,namespace可不写。这里baseResultMap没有看到定义,但是确实存在,因为这个是easymybatis提供的一个内置resultMap。

  • 在TUseroDao.java中添加:
TUser selectByName(@Param("username")String username);
  • 编写单元测试用例
@Test
public void testSelectByName() {
    TUser user = dao.selectByName("张三");

    System.out.println(user.getUsername());
}
    

配置说明

easymybatis存放一些配置参数,这些参数都有默认值,一般情况下可以不用。如果使用springboot的话可以方便的对参数进行设置,只需在application.properties中设置即可,除此之外还可以设置其他mybatis官方参数,具体可参考MyBatis-Spring-Boot-Application configuration parameters

mybatis.camel2underline=true
mybatis.common-sql-classpath=
mybatis.mapper-save-dir=
mybatis.mapper-executor-pool-size=50
mybatis.template-classpath=

下面就讲解下各个属性的作用:

  • camel2underline 如果为true,则开启驼峰转换下划线功能。实体类中的java字段映射成数据库字段将自动转成下划线形式。可以省略@Column注解。默认true。

  • mapper-executor-pool-size mapper处理线程数,此项配置可以加快启动速度。默认值50,生产环境可以设置成较小的数,比如5

  • template-classpath 指定模板文件class路径,开头结尾必须包含"/"。如果没有指定,则默认读取easymybatis/tpl/下的模板,一般情况下不做配置。

  • common-sql-classpath 指定公共SQL模块class路径,如果没有指定,则默认读取easymybatis/commonSql.xml,一般情况下不做配置。

  • mapper-save-dir 指定mapper文件存放路径。因为easymybatis是直接将mapper内容注入到内存当中,开发人员无感知,并且不知道mapper内容是什么样子,这个功能就是让开发人员能够查看到对应的mapper内容,方便定位和排查问题。一般情况下此项不用开启。

其他功能

指定外部模板

easymybatis依赖模板文件来生成mapper,默认的模板存放在easymybatis/tpl/下,模板文件名对应某一种数据库,如mysql.vm对应mysql数据库。

我们可以通过更改template-classpath的值来改变模板读取的位置。默认template-classpath的值为/easymybatis/tpl/。假如你想对mysql.vm做一些修改,那么可以按照如下步骤进行:

  1. 使用解压工具解压easymybatis.jar
  2. 在easymybatis/tpl/下找到mysql.vm,拷贝一份出来,放到你的项目中的classpath下(src/main/resources)
  3. 在application.properties中添加一行
mybatis.template-classpath=/ 

这样在启动时会自动读取classpath根目录下的mysql.vm。控制台也会打印读取模板的信息:

2017-12-26 19:32:31.021  INFO 13476 --- [           main] n.o.d.e.ext.MapperLocationsBuilder       : 使用模板:/mysql.vm

如果你的项目是springmvc,采用xml配置形式,前两步不变,第三步改为:

<!-- 替换org.mybatis.spring.SqlSessionFactoryBean -->
    <bean id="sqlSessionFactory"
        class="net.oschina.durcframework.easymybatis.ext.SqlSessionFactoryBeanExt">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:mybatis/mybatisConfig.xml</value>
        </property>
        <property name="mapperLocations">
            <list>
                <value>classpath:mybatis/mapper/*.xml</value>
            </list>
        </property>
        
        <!-- 以下是附加属性 -->
        
        <!-- dao所在的包名,跟MapperScannerConfigurer的basePackage一致 
            多个用;隔开
        -->
        <property name="basePackage" value="com.myapp.dao" />
        <property name="config">
            <bean class="net.oschina.durcframework.easymybatis.EasymybatisConfig">
                <!-- 指定外部模板 -->
                <property name="templateClasspath" value="/"/>
            </bean>
        </property>
    </bean>

全局Dao

easymybatis提供了全局Dao支持。

easymybatis设置全局Dao的方式如下:

  1. 在resources下新建一个base.vm内容如下
<select id="getMySqlVersion" resultType="String">
    select version()
</select>

获取数据库版本号SQL.

  1. 在application.properties新增一行
mybatis.global-vm-location=/base.vm

用来指定文件位置,支持file:,classpath:方式。

  1. 新建一个全局Dao:GlobalDao.java
public interface GlobalDao {
    String getMySqlVersion();
}
  1. 自定义的Dao继承GlobalDao.java
public interface AddressDao extends CrudDao<Address>,GlobalDao {

}

这样AddressDao就具备了getMySqlVersion()功能。base.vm中的文件编写可参考velocity变量说明

乐观锁

easymybatis提供的乐观锁使用方式跟JPA一样,使用@Version注解来实现。即:数据库增加一个int或long类型字段version,然后实体类version字段上加上@Version注解即可。实现原理是根据mysql的行锁机制(InnoDB下),同一条记录只能被一条SQL执行,后面的SQL排队等待。这样version改变后,等待中的SQL还是老的version号,因此更新失败。

@Version  
private Long version;  
  • 注:更新不成功不会抛出异常,而是update返回值为0

逻辑删除

从1.7版本开始支持逻辑删除功能,即更新一个字段标记为已删除。查询的时候会自动过滤掉已删除的数据。

假设数据库表中有一个字段is_deleted类型为tinyint,0表示未删除,1表示已删除。

实体类对应代码如下:

public class User {
    @LogicDelete
    private Byte isDeleted;
}

在执行dao.del(user);时会触发UPDATE语句,将is_deleted字段更新为1。

如果is_deleted类型为char(1),f表示未删除,t表示已删除。

@LogicDelete(notDeleteValue = "f", deleteValue = "t")
private String isDeleted;

@LogicDelete提供两个属性

  • notDeleteValue:指定未删除时的值,不指定默认为0
  • deleteValue:指定删除后保存的值,不指定默认为1

假设1表示未删除,2表示已删除,@LogicDelete的设置方法如下:@LogicDelete(notDeleteValue = "1", deleteValue = "2")。如果每个实体类都要这样设置的话会很麻烦,easymybatis提供了全局配置

  • springboot下,application.properties添加
# 未删除数据库保存的值,默认为0
mybatis.logic-not-delete-value=1
# 删除后数据库保存的值,默认为1
mybatis.logic-delete-value=2
  • springmvc设置方式如下:
<!-- 替换org.mybatis.spring.SqlSessionFactoryBean -->
    <bean id="sqlSessionFactory"
        class="net.oschina.durcframework.easymybatis.ext.SqlSessionFactoryBeanExt">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:mybatis/mybatisConfig.xml</value>
        </property>
        <property name="mapperLocations">
            <list>
                <value>classpath:mybatis/mapper/*.xml</value>
            </list>
        </property>
        
        <!-- 以下是附加属性 -->
        
        <!-- dao所在的包名,跟MapperScannerConfigurer的basePackage一致 
            多个用;隔开
        -->
        <property name="basePackage" value="com.myapp.dao" />
        <property name="config">
            <bean class="net.oschina.durcframework.easymybatis.EasymybatisConfig">        
                <property name="logicNotDeleteValue" value="1"/>
                                <property name="logicDeleteValue" value="2"/>
            </bean>
        </property>
    </bean>
  • 注:如果同时设置了@LogicDelete参数和全局配置,会优先读取注解中的配置。

多数据源配置

这里主要介绍在springboot下进行多数据源配置:

首先application.properties配置:

# 主数据源
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://${mysql.ip}:3306/stu?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
spring.datasource.username=${mysql.username}
spring.datasource.password=${mysql.password}

# 第二个数据源
spring.datasourceSecond.driver-class-name=com.mysql.jdbc.Driver
spring.datasourceSecond.url=jdbc:mysql://${mysql.ip}:3306/easydoc?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
spring.datasourceSecond.username=${mysql.username}
spring.datasourceSecond.password=${mysql.password}
  • 禁掉springboot自带的DataSourceAutoConfiguration
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
  • pom移除easymybatis-spring-boot-starter依赖
  • pom添加:
<dependency>
    <groupId>net.oschina.durcframework</groupId>
    <artifactId>easymybatis</artifactId>
    <version>1.8.4</version>
</dependency>    
  • 新建一个数据库配置文件,作为主数据源
/**
 * 主数据源,使用方式:
 * <pre>
 * 1. pom移除easymybatis-spring-boot-starter依赖
 * 2. pom添加:
 * <code>
 * &lt;dependency&gt;
        &lt;groupId&gt;net.oschina.durcframework&lt;/groupId&gt;
        &lt;artifactId&gt;easymybatis&lt;/artifactId&gt;
        &lt;version&gt;1.8.4&lt;/version&gt;
    &lt;/dependency&gt;
    3. 打开注释:
    @Configuration
    @MapperScan(basePackages = { DbMasterConfig.basePackage }, sqlSessionFactoryRef = DbMasterConfig.sqlSessionFactoryName)
 * </code>
 * </pre>
 * @author tanghc
 */
@Configuration
@MapperScan(basePackages = { DbMasterConfig.basePackage }, sqlSessionFactoryRef = DbMasterConfig.sqlSessionFactoryName)
public class DbMasterConfig {
    
    /* ********************只需要改这里的配置******************** */
    static final String dbName = "master";
    /** 配置文件前缀 */
    public static final String prefix = "spring.datasource";
    /** 存放mapper包路径 */
    public static final String basePackage = "com.myapp.dao";
    /** mybatis的config文件路径 */
    public static final String mybatisConfigLocation = "classpath:mybatis/mybatisConfig.xml";
    /** mybatis的mapper文件路径 */
    public static final String mybatisMapperLocations = "classpath:mybatis/mapper/*.xml";
    /** 表新增时间字段名 */
    public static final String dbInsertDateColumnName = "gmt_create";
    /** 表更新时间字段名 */
    public static final String dbUpdateDateColumnName = "gmt_update";
    /* **************************************************** */
    
    /** 数据源名称 */
    public static final String dataSourceName = "dataSource" + dbName;
    /** sqlSessionTemplate名称 */
    public static final String sqlSessionTemplateName = "sqlSessionTemplate" + dbName;
    /** sqlSessionFactory名称 */
    public static final String sqlSessionFactoryName = "sqlSessionFactory" + dbName;
    /** transactionManager名称 */
    public static final String transactionManagerName = "transactionManager" + dbName;
    /** transactionTemplate名称 */
    public static final String transactionTemplateName = "transactionTemplate" + dbName;
   

    @Bean(name = dataSourceName)
    @Primary
    @ConfigurationProperties(prefix = prefix) // application.properteis中对应属性的前缀
    public DataSource dataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    public EasymybatisConfig easymybatisConfig() {
        EasymybatisConfig config = new EasymybatisConfig();
        /*
         * 驼峰转下划线形式,默认是true 开启后java字段映射成数据库字段将自动转成下划线形式 如:userAge -> user_age
         * 如果数据库设计完全遵循下划线形式,可以启用 这样可以省略Entity中的注解,@Table,@Column都可以不用,只留
         * 
         * @Id
         * 
         * @GeneratedValue 参见:UserInfo.java
         */
        config.setCamel2underline(true);
        config.setFills(Arrays.asList(new DateFillInsert(dbInsertDateColumnName),
                new DateFillUpdate(dbUpdateDateColumnName)));

        return config;
    }

    @Bean(name = sqlSessionFactoryName)
    public SqlSessionFactory sqlSessionFactory(@Autowired @Qualifier(dataSourceName) DataSource dataSource,
            EasymybatisConfig config) throws Exception {
        Assert.notNull(dataSource, "dataSource can not be null.");
        Assert.notNull(config, "EasymybatisConfig can not be null.");
        
        SqlSessionFactoryBeanExt bean = new SqlSessionFactoryBeanExt();

        bean.setDataSource(dataSource);
        bean.setConfigLocation(this.getResource(mybatisConfigLocation));
        bean.setMapperLocations(this.getResources(mybatisMapperLocations));

        // ====以下是附加属性====

        // dao所在的包名,跟MapperScannerConfigurer的basePackage一致,多个用;隔开
        bean.setBasePackage(basePackage);
        bean.setConfig(config);

        return bean.getObject();

    }

    @Bean(name = sqlSessionTemplateName)
    public SqlSessionTemplate sqlSessionTemplate(
            @Autowired @Qualifier(sqlSessionFactoryName) SqlSessionFactory sessionFactory) throws Exception {
        SqlSessionTemplate template = new SqlSessionTemplate(sessionFactory); // 使用上面配置的Factory
        return template;
    }
    
    @Bean(name = transactionManagerName)
    public PlatformTransactionManager annotationDrivenTransactionManager(
            @Autowired @Qualifier(dataSourceName) DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    
    @Bean(name = transactionTemplateName)
    public TransactionTemplate transactionTemplate(@Autowired @Qualifier(transactionManagerName)PlatformTransactionManager transactionManager) {
        return new TransactionTemplate(transactionManager);
    }
    

    private Resource[] getResources(String path) throws IOException {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        return resolver.getResources(path);
    }

    private Resource getResource(String path) {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        return resolver.getResource(path);
    }
   
}

这个文件不用做多大的修改,只需要修改上面的配置内容即可。

  • 新建第二个文件,作为第二个数据源:

/**
 * 第二个数据源,后续有第三个数据,复制这个文件,然后改下配置即可
 * @author tanghc
 */
@Configuration
@MapperScan(basePackages = { DbSecondConfig.basePackage }, sqlSessionFactoryRef = DbSecondConfig.sqlSessionFactoryName)
public class DbSecondConfig {
    
    /* ********************只需要改这里的配置******************** */
    static final String dbName = "Second";
    /** 配置文件前缀 */
    public static final String prefix = "spring.datasourceSecond";
    /** 存放mapper包路径 */
    public static final String basePackage = "com.app2.dao";
    /** mybatis的config文件路径 */
    public static final String mybatisConfigLocation = "classpath:mybatis/mybatisConfig.xml";
    /** mybatis的mapper文件路径 */
    public static final String mybatisMapperLocations = "classpath:mybatis/mapper2/*.xml";
    /** 表新增时间字段名 */
    public static final String dbInsertDateColumnName = "gmt_create";
    /** 表更新时间字段名 */
    public static final String dbUpdateDateColumnName = "gmt_update";
    /* **************************************************** */
    
    /** 数据源名称 */
    public static final String dataSourceName = "dataSource" + dbName;
    /** sqlSessionTemplate名称 */
    public static final String sqlSessionTemplateName = "sqlSessionTemplate" + dbName;
    /** sqlSessionFactory名称 */
    public static final String sqlSessionFactoryName = "sqlSessionFactory" + dbName;
    /** transactionManager名称 */
    public static final String transactionManagerName = "transactionManager" + dbName;
    /** transactionTemplate名称 */
    public static final String transactionTemplateName = "transactionTemplate" + dbName;

    @Bean(name = dataSourceName)
    @ConfigurationProperties(prefix = prefix) // application.properteis中对应属性的前缀
    public DataSource dataSourceMater() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    public EasymybatisConfig easymybatisConfig() {
        EasymybatisConfig config = new EasymybatisConfig();
        /*
         * 驼峰转下划线形式,默认是true 开启后java字段映射成数据库字段将自动转成下划线形式 如:userAge -> user_age
         * 如果数据库设计完全遵循下划线形式,可以启用 这样可以省略Entity中的注解,@Table,@Column都可以不用,只留
         * 
         * @Id
         * 
         * @GeneratedValue 参见:UserInfo.java
         */
        config.setCamel2underline(true);
        config.setFills(Arrays.asList(new DateFillInsert(dbInsertDateColumnName),
                new DateFillUpdate(dbUpdateDateColumnName)));

        return config;
    }

    @Bean(name = sqlSessionFactoryName)
    public SqlSessionFactory sqlSessionFactory(@Autowired @Qualifier(dataSourceName) DataSource dataSource,
            EasymybatisConfig config) throws Exception {
        Assert.notNull(dataSource, "dataSource can not be null.");
        Assert.notNull(config, "EasymybatisConfig can not be null.");
        SqlSessionFactoryBeanExt bean = new SqlSessionFactoryBeanExt();

        bean.setDataSource(dataSource);
        bean.setConfigLocation(this.getResource(mybatisConfigLocation));
        bean.setMapperLocations(this.getResources(mybatisMapperLocations));

        // ====以下是附加属性====

        // dao所在的包名,跟MapperScannerConfigurer的basePackage一致,多个用;隔开
        bean.setBasePackage(basePackage);
        bean.setConfig(config);

        return bean.getObject();

    }

    @Bean(name = sqlSessionTemplateName)
    public SqlSessionTemplate sqlSessionTemplate(
            @Autowired @Qualifier(sqlSessionFactoryName) SqlSessionFactory sessionFactory) throws Exception {
        SqlSessionTemplate template = new SqlSessionTemplate(sessionFactory); // 使用上面配置的Factory
        return template;
    }
    
    @Bean(name = transactionManagerName)
    public PlatformTransactionManager annotationDrivenTransactionManager(
            @Autowired @Qualifier(dataSourceName) DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    
    @Bean(name = transactionTemplateName)
    public TransactionTemplate transactionTemplate(@Autowired @Qualifier(transactionManagerName)PlatformTransactionManager transactionManager) {
        return new TransactionTemplate(transactionManager);
    }
    

    private Resource[] getResources(String path) throws IOException {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        return resolver.getResources(path);
    }

    private Resource getResource(String path) {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        return resolver.getResource(path);
    }

}

第二个数据源,后续有第三个数据,复制这个文件,然后改下配置即可

[附录]velocity变量说明

${context}

  • ${context.dbName} : 数据库名称
  • ${context.packageName} : 包名
  • ${context.javaBeanName} : Java类名
  • ${context.javaBeanNameLF} : Java类名且首字母小写

${pk}

  • ${pk.isIdentity} : 是否自增
  • ${pk.javaFieldName} : 主键java字段名
  • ${pk.columnName} : 主键数据库字段名
  • ${pk.isUuid} : 主键是否使用UUID策略

${table}

  • ${table.tableName} : 数据库表名
  • ${table.comment} : 表注释
  • ${table.javaBeanNameLF} : java类名,并且首字母小写

#foreach($column in $columns)...#end

  • ${column.columnName} : 表中字段名
  • ${column.type} : java字段类型,String,Integer
  • ${column.fullType} : java字段完整类型,java.lang.String
  • ${column.javaFieldName} : java字段名
  • ${column.javaFieldNameUF} : java字段名首字母大写
  • ${column.javaType} : 字段的java类型
  • ${column.javaTypeBox} : 字段的java装箱类型,如Integer,Long
  • ${column.isIdentity} : 是否自增,返回boolean
  • ${column.isPk} : 是否自增主键,返回boolean
  • ${column.isIdentityPk} : 是否自增主键,返回boolean
  • ${column.isEnum} : 是否枚举类型,返回boolean
  • ${column.mybatisJdbcType} : 返回mybatis定义的jdbcType
  • ${column.comment} : 表字段注释