BeetlSQL自定义NameConversion去除Pojo和表前缀

Stella981
• 阅读 470

有的时候我们数据库设计可能不会完全和代码语言一致,比如我们会在数据库的每一张表前面加上一个特定的前缀用于区分,在BeetlSQL中将代码Pojo的名称和数据库Table名称对应起来是使用NameConversion来转换的,BeetlSQL内置了DefaultNameConversionUnderlinedNameConversionJPANameConversion等转换器基本上可以满足绝大部分的要求的,今天就来给大家演示一下如何自定义NameConversion

###前言

要了解本文的内容,首先你需要先了解BeetlBeetlSQL这两个项目,它们是来自于国人@闲·大赋呕心沥血精心打造的Java模板引擎和Java数据库全功能Dao,而且目前官方已经提供了Beetl和BeetlSQL与市面上各种主流MVC框架的整合方案

我不敢说Beetl比JSP、FreeMarker、Velocity等大家熟知的一些模板引擎怎么怎么的好,但是我想说以我个人的使用经历来做对比,Beetl绝对不会比它们差,BeetlSQL更是不会比Hibernate和MyBatis等差

如果有兴趣想了解一下Beetl和BeetlSQL,可以访问Beetl官方论坛查阅详情。

何不给Beetl一个机会来证明Beetl自己,更是给你自己一个学习工作尝试的机会,说不定你就和我一样一不留神就爱上了它。

###正文

本文讨论的是在使用BeetlSQL自动生成Pojo对象时,通过自定义转换器去除映射表名前缀的问题。

先看一组开发遇到的情况:

假定当前有个项目beetl在数据库设计的时候,所有的表名都有一个项目前缀bt_,即所有的表都以bt_开头,如bt_userbt_rolebt_user_role,看到这样的表名设计我们可能第一想到的是使用UnderlinedNameConversion来进行转化,于是乎:

bt_user-> BtUser

bt_role -> BtRole

bt_user_role -> BtUserRole

相信很多人肯定和我一样是不能接受这样的命名的,所以我们需要自己定义一个NameConversion来进行转换,去除掉Table生成Pojo时自动加上的Bt前缀

NameConversion中核心的几个方法getPropertyNamegetColNamegetTableNamegetClassName,根据方法名和参数很容易理解

方法名

方法解释

getPropertyName

根据数据库的列名通过一系列自定义方法转化后生成Pojo的属性名

getColName

根据Pojo的属性名称通过一系列自定义方法转化后生成数据库列名

getClassName

根据数据库的表名通过一系列自定义方法转化后生成Pojo类的类名字符串

getTableName

根据Pojo的类的类型通过一系列自定义方法转化后生成数据库表名

因此我们只需要根据我们自己的实际需求重新实现一个NameConversion将表名转类名、类名转表名的方法重新实现以下即可。

具体做法:首先我们新建一个类继承自DefaultNameConversion类,分别重写getClassNamegetTableName两个方法,最后在我们的项目中启用自己写的Conversion

@Override
public String getTableName(Class<?> c) {
    //遵循BeetlSQL规范,@Table拥有最高优先级
    Table table = (Table)c.getAnnotation(Table.class);
    if(table!=null){
        return table.name();
    }
    //UserRole -> user_role
    String tableName = StringKit.enCodeUnderlined(c.getSimpleName());
    //user_role -> bt_user_role
    return "bt_"+tableName;
}

@Override
public  String getClassName(String tableName){
    //假定所有表都是以bt_开头
    //bt_user_role -> user_role
    tableName = tableName.substring(tableName.indexOf("_")+1);
    //user_role -> userRole
    String clsName = StringKit.deCodeUnderlined(tableName);
    //userRole -> UserRole
    return StringKit.toUpperCaseFirstOne(clsName);
}

就这样轻松的完成的整个数据库的表名去前缀。

事与愿违!!! 往往我们可能还会遇到更特殊的情况,下面让我们再来看一组开发可能遇到的情况:

当前有一个项目,里面有一些用户的数据表(如User),后台管理的数据表(如Admin)和以前用户与后台公共的数据表(如City),然后在开发时为了做区分,分别给不同的功能模块的表加上了不同的前缀,最后我们的表名可能是:usr_usermgr_adminbase_city这样的形式,这时候我们再使用上面的方式统一去前缀再统一加前缀肯定是行不通的,毕竟前缀不一样你去掉前缀后是很难直接还原的。

最初我遇到这样的问题,第一想法是,让BeetlSQL反向生成Pojo的时候,去除前缀然后自动给所有的Pojo加上@Table的注解,例如例子中的usr_usermgr_adminbase_city三张表 最后可能生成如下形式:

usr_user -> @Table(name="usr_user") User

mgr_admin -> @Table(name="mgr_admin") Admin

base_city -> @Table(name="base_city") City

理想是丰满的,现实是骨感的。在QQ上与作者沟通遇到这种情况时的解决方案时发现可能会出现这样的情况: 前台用户使用的数据表可能是 usr_user,而后台管理员也属于用户呀,因此可能后台管理员的数据表为mgr_user,最后这样会导致两个类冲突了,生成代码的时候可能会被覆盖一个类,是有问题的。好在机智如我~遇到这样的根据功能模块给不同的表加上不同的前缀,我们在Java程序开发时也经常会使用不同的包名来区分不同的模块,我可以将不同前缀的实体放到对应的包下面,还原表名的时候读取一下包名即可反向解析出表名,下面是我的具体实现:

@Override
public  String getClassName(String tableName){
    //为了安全起见,做了个判断,理论上项目数据库设计好了应该是无需判断直接截取所有前缀
    //usr_user_role -> user_role
    if(tableName.matches("^(usr_|base_|mgr_).*")){
        tableName = tableName.substring(tableName.indexOf("_")+1);
    }
    //user_role -> UserRole
    String clsName = StringKit.deCodeUnderlined(tableName);
    return StringKit.toUpperCaseFirstOne(clsName);
}

@Override
public String getTableName(Class<?> c) {
    Table table = (Table)c.getAnnotation(Table.class);
    if(table!=null){
        return table.name();
    }
    //获取Package 最后一层 xxx.pojo.usr  ->  Usr
    String pkg = c.getPackage().getName();
    pkg = pkg.substring(pkg.lastIndexOf(".")+1);
    pkg = Character.toUpperCase(pkg.charAt(0))+pkg.substring(1);
    //Usr+User -> UsrUser -> usr_user
    return StringKit.enCodeUnderlined(pkg+c.getSimpleName());
}

然后在使用BeetlSQL反向生成Pojo的时候,使用Filter将数据表分门别类的生成到不同的包下面:

//记得初始化SQLManager时要使用自己写好的NameConvertion
SQLManager sql = initSQLManager();
GenConfig config = new GenConfig();
sql.genALL("xxxx.pojo.usr", config, new GenFilter(){
    @Override
    public boolean accept(String tableName) {
        return tableName.startsWith("usr_");
    }
});
sql.genALL("xxxx.pojo.mgr", config, new GenFilter(){
    @Override
    public boolean accept(String tableName) {
        return tableName.startsWith("mgr_");
    }
});
sql.genALL("xxxx.pojo.base", config, new GenFilter(){
    @Override
    public boolean accept(String tableName) {
        return tableName.startsWith("base_");
    }
});

最终会在项目中会生成以下Pojo

usr_user -> xxxx.pojo.usr.User.java

mgr_admin -> xxxx.pojo.mgr.Admin.java

base_city -> xxxx.pojo.base.City.java

即便是有类名冲突的,因为在不同的包下,所以也不会影响

就这样一次轻松而又愉快的BeetlSQL自定义去除Pojo和表前缀被解决啦~

###最后 之前所有项目的开发都是Jsp,几乎没使用过其他第三方模板库,因为一次误打误撞让我认识了Beetl,它的轻巧,它独特的语法都深深的吸引了我,因为Beetl又让我认识了BeetlSQL,抱着试一试的心态尝试过之后总有一种把当前项目(使用的Hibernate)推倒重来的冲动,虽然最后因为项目的工程量和工期原因,当前的这个项目最终还是使用了Hibernate,但是我可以确定的是,在以后的开发道路上,如果允许,如果没有能让我更心动的通用Dao,BeetlSQL将会是我不二的选择。

今天在这里分享这篇自定义NameConvertion的功能,其实并没有多少技术含量,更多的是想做一次简单的推广,让更多人知道Beetl,让更多人爱上Beetl~

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Java修道之路,问鼎巅峰,我辈代码修仙法力齐天
<center<fontcolor00FF7Fsize5face"黑体"代码尽头谁为峰,一见秃头道成空。</font<center<fontcolor00FF00size5face"黑体"编程修真路破折,一步一劫渡飞升。</font众所周知,编程修真有八大境界:1.Javase练气筑基2.数据库结丹3.web前端元婴4.Jav
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这