Sometimes our database design may not be completely consistent with the code language. For example, we will add a specific prefix in front of each table in the database to distinguish it. In BeetlSQL, the name of the code Pojo corresponds to the name of the database Table. It is converted using NameConversion. BeetlSQL has built-in converters such as DefaultNameConversion, UnderlinedNameConversion and JPANameConversion, which can basically meet most requirements. Today I will show you how to customize NameConversion.
Foreword
To understand the content of this article, first of all, you need to understand the two projects Beetl and BeetlSQL. They are the Java template engine and Java database full-featured Dao that were painstakingly built by the Chinese @Xian·Dafu, and currently The official has provided integration solutions for Beetl and BeetlSQL with various mainstream MVC frameworks on the market
I dare not say how Beetl is better than some well-known template engines such as JSP, FreeMarker, Velocity, etc., but I want to say that in my personal opinion For comparison, Beetl will definitely not be worse than them, and BeetlSQL will not be worse than Hibernate and MyBatis. If you are interested in learning more about Beetl and BeetlSQL, you can visit the Beetl official forum for details.
Why not give Beetl a chance to prove Beetl yourself, and give yourself a chance to learn and work. Maybe you will fall in love with it accidentally like me.
Text
This article discusses the problem of removing the mapping table name prefix through a custom converter when using BeetlSQL to automatically generate Pojo objects.
Let’s first look at a set of development situations:
Suppose there is currently a project beetl. When designing the database, all table names have a project prefix bt_, that is, all tables start with bt_, such as bt_user, bt_role, bt_user_role, when we see such a table name design, the first thing we may think of is to use UnderlinedNameConversion for conversion, so:
bt_user-> BtUser
bt_role -> BtRole
bt_user_role -> BtUserRole
I believe that many people, like me, cannot accept such naming, so we need to define a NameConversion ourselves for conversion, and remove the Bt prefix automatically added when Table generates Pojo
The core methods getPropertyName and getColName in NameConversion , getTableName, getClassName, it is easy to understand based on the method name and parameters
So we only need to re-implement a NameConversion according to our own actual needs to convert the table name to a class name and the class name to table name. Re-implement the following methods .
Specific method: First, we create a new class that inherits from the DefaultNameConversion class, override the getClassName and getTableName methods respectively, and finally enable the Conversion we wrote in our project
@Override
@Overridepublic 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; }@Overridepublic 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); }
It backfired! ! ! Often we may encounter more special situations. Let's look at a set of situations that development may encounter:
Currently there is a project with some user data tables (such as User) and background management data tables. (such as Admin) and the data table that was previously shared between users and the backend (such as City). Then, in order to distinguish it during development, different prefixes were added to the tables of different functional modules. In the end, our table name may be: usr_user , mgr_admin and base_city. At this time, it will definitely not work if we use the above method to uniformly remove prefixes and then uniformly add prefixes. After all, the prefixes are different and it is difficult to directly restore them after removing the prefixes.
Initially I encountered this problem. My first idea was to let BeetlSQL reversely generate Pojos by removing the prefix and automatically adding @Table annotations to all Pojos, such as usr_user, mgr_admin and base_city in the example. The table may finally be generated in the following form:
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程序开发时也经常会使用不同的包名来区分不同的模块,我可以将不同前缀的实体放到对应的包下面,还原表名的时候读取一下包名即可反向解析出表名,下面是我的具体实现:
@Overridepublic 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); }@Overridepublic 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时要使用自己写好的NameConvertionSQLManager 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~