How to automatically generate the entire bean layer and service layer according to the database file

introduction

The first task of coming to the company is to use the company's framework leap ( http://leapframework.org/ ORM layer is really awesome) for project development, in this framework it specifies its own javabean annotations (such as using @Id describes the primary key, and @Column describes the field), so as to achieve the function of persisting objects like in hibernate. Although the ORM layer is very easy to use, it is really troublesome to write javabeans and annotations (because it is not jpa Specifications, all tools such as hibernate-tool) cannot be used to create javabeans. Even if ordinary javabeans are created, it is very troublesome to write annotations on fields. So how to write a tool to help us complete these tedious operations?

Design ideas

First you need to abstract the javabean

数据库表名->类名
数据库字段->类字段
数据库类型->java类型
数据库主键->需要做标志,使用特殊的注解

//其他需要传入的参数
类的包名
生成的文件地址

With the above ideas, it means that as long as there is

数据库文件
一套javabean的模版

It can dynamically perform a database to javabean conversion

Technical selection

1. Database
access JDBC is used directly for database access. Because there will be no frequent database access, it is enough to use JDBC. The information we need to collect here is

//数据库里面所有的表
show tables;
//根据表名,获取表里面的所有字段(包括字段类型,字段是否主键等信息)
desc your_table_name;

2. Create templates and replace template information
. Here I once thought of using regular expressions to solve this problem, and define my own expressions to replace. Later, when I collected ideas, I found a great framework, freemarks , which can help me solve this problem . question.

You can read the documentation first, or you can refer to my understanding of this framework and then read the documentation,

First of all, let's talk about the purpose of the freemarks framework. In fact, it was designed to replace a rendering engine such as jsp.

The idea of ​​using the jsp template rendering engine is probably like this:
the changed values ​​are stored in the request, response, session, the jsp engine parses the expressions in the jsp file, and then goes to the request, response, and session to get the value of the relevant expression to build the entire page, and then Output to the response to the user. The whole process is combined with request, response, session and other objects.

If you have used spring mvc, you should know that the advantage of mvc is that it uses a model object in the control layer to help you encapsulate the value you want to pass to the request, abstracting the user, making you feel like

值->model->传递(request..)->jsp->动态页面

But in fact, the bottom layer still uses request.

Then the emergence of freemarks is to solve this problem. The two concepts he proposed are "model" and "template". He proposed such a process

值->model->传递->模版->动态页面

It can be seen that it does not rely on objects such as request, and completely encapsulates a set of its own things.
I can't say whether freemarks can replace jsp, but it is very suitable for our needs.
At this time, you need to read through the documentation (actually similar to El expressions) and prepare for development.

3. File storage You can
use IO to complete this function, but I want to play a little bit, so I use NIO, and use a memory map to complete the whole function.

actual development

Send the git address first, in case some places are incomplete https://git.oschina.net/jjtHappy/leap-tools
first from bottom to top

The first is the database link. The ordinary JDBC link does not need to be introduced. The sql for taking the table name and taking the field according to the table name has already been discussed.

Mainly how to do it

数据库表名->类名
数据库字段->类字段
数据库类型->java类型
数据库主键->需要做标志,使用特殊的注解

First of all, the table name to the class name is very simple, just a format conversion

/**
     * 
     * Title:把传入的字段转为驼峰
     * Description:
     * @param table 传入的字段
     * @param mod 切割字符
     * @return
     * @author jjtEatJava
     * @date 2017年8月8日
     */
    public static String toCamel(String string,String mod) {
        String[] tableNameSplit = string.split(mod);
        StringBuffer entityName = new StringBuffer();
        for(String s : tableNameSplit) {
            char[] cs=s.toLowerCase().toCharArray();
            cs[0]-=32;
            entityName.append(String.valueOf(cs));
        }
        return entityName.toString();
    }

The table field is converted to javabean in the same way, and the first letter is converted to lowercase.

Converting database type to java type is actually a very simple operation

    /**
     * Title:将数据库类型转为java类型
     * Description:
     * @param tableType 数据库类型
     * @return
     * @author jjtEatJava
     * @date 2017年7月30日
     */
    public static String tableTypeToJavaType(String tableType) {
        //去括号
        int lastIndex = tableType.lastIndexOf("(");
        tableType = tableType.substring(0, lastIndex==-1?tableType.length():lastIndex).toLowerCase();
        String javaType;
        switch(tableType) {
            case    "char":
            case    "varchar":
            case    "tinytext":
            case    "text":
            case    "mediumtext":
            case    "longtext":
                javaType="String";
                break;
            case    "tinyblob":
            case    "blob":
            case    "mediumblob":
            case    "longblob":
                javaType="byte[]";
                break;      
            case    "tinyint":
            case    "smallint":
            case    "mediumint":
            case    "int":
            case    "bigint":
                javaType="Integer";
                break;
            case    "float":
                javaType="float";
                break;
            case    "double":
                javaType="double";
                break;
            case    "decimal":
                javaType="BigDecimal";
                break;
            case    "date":
            case    "time":
            case    "year":
            case    "datetime":
            case    "timestamp":
                javaType="Date";
                break;
            default:
                throw new RuntimeException("无法解析"+tableType+"类型");
        }
        return javaType;
    }

Mainly, you can understand the comparison table between mysql type and java type, just write a switch.

For convenience, you can write a javabean and encapsulate it when the database is retrieved.

public class Field {

    private String tableField;//数据库字段名
    private String tableType;//数据库类型
    private String tableKey;//索引类型

    private String javaField;//java字段名
    private String javaType;//java类型
    ....
}

How to judge whether it is a primary key here, just judge whether the index type has a "PRI" field

It is very convenient for the upper layer to encapsulate a useful dao layer. For the specific code, see SimpleDao

After solving the data acquisition problem, the next step is to solve the template problem. This depends on your abstraction of javabean. After you read the document, you can look at the template I wrote (combined with some content of the framework)

package ${packageName}.bean;

<#list importPacks as importPack>
import ${importPack};
</#list>
import leap.orm.annotation.Column;
import leap.orm.annotation.Id;
import leap.orm.annotation.Table;
import leap.orm.model.Model;

@Table("${tableName}")
public class ${entityName} extends Model implements java.io.Serializable {
    <#-- 构造属性 -->
    <#list fields as field>
    <#if field.tableKey?contains("PRI")>
    @Id
    </#if>
    @Column(name="${field.tableField}")
    private ${field.javaType} ${field.javaField?uncap_first};
    </#list>

    <#-- 构造set and get -->
    <#list fields as field >
    <#-- set -->
    public void set${field.javaField?cap_first}(${field.javaType} ${field.javaField?uncap_first}){
        this.${field.javaField?uncap_first}=${field.javaField?uncap_first};
    }
    <#-- get -->
    public ${field.javaType} get${field.javaField?cap_first}(){
        return this.${field.javaField?uncap_first};
    }
    </#list>
}

It can be seen that the template is very simple, the required data model is only

包名
导入的包
数据库表名
实体名(就是表名的驼峰转化)
上述封装的域列表(用freemarks表达式进行遍历)

The point to note here is how to decide which package to import, so you need to consider a few points

1.根据java类型寻找包,并获取包名
2.包名不能重复

So with this idea, it can be achieved by the following method

    /**
     * 
     * Title:根据所有的域获取导包列表
     * Description:
     * @param fields bean里面的所有的域
     * @return
     * @author jjtEatJava
     * @date 2017年8月8日
     */
    public  static Set<String> getPackByFields(List<Field> fields) {
        Set<String> set = new HashSet<String>();
        for(Field field:fields) {
            String javaType = field.getJavaType();
            String packageName=null;
            switch(javaType) {
                case "String":
                    packageName="java.lang.String";
                    break;
                case "Integer":
                    packageName="java.lang.Integer";
                    break;
                case "Double":
                    packageName="java.lang.Double";
                    break;
                case "Float":
                    packageName="";
                    break;
                case "byte[]":
                    packageName="";
                    break;
                case "Date":
                    packageName="java.util.Date";
                    break;
                case "BigDecimal":
                    packageName="java.math.BigDecimal";
                    break;
                default :
                packageName="";
            }
            set.add(packageName);
        }
        return set;
    }

After the template design is completed, the model is constructed and transferred. The transfer process is based on freemarks, and then NIO is used to create files. The
main key methods are as follows:

 /**
      * 
      * Title:创建文件
      * Description:
      * @param temp 模版
      * @param model 数据模型
      * @param basePah 基础路径
      * @param fileName 文件名
      * @throws TemplateException
      * @throws IOException
      * @throws FileNotFoundException
      * @author jjtEatJava
      * @date 2017年8月8日
      */
     private void createFile(Template temp, Map<String, Object> model,String basePah, String fileName)
            throws TemplateException, IOException, FileNotFoundException {
        //创建文件夹
        File baseDir = new File(basePah);
        if(!baseDir.exists())
            baseDir.mkdirs();
        File file =new File (baseDir,fileName);
        if(file.exists()) {
            file.delete();
            file.createNewFile();
        }else {
            file.createNewFile();
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        Writer writer = new OutputStreamWriter(out);
        //把模版加载到内存
        temp.process(model,writer);
        //获取缓存字符数组
        byte[] byteBuff = out.toByteArray();
        RandomAccessFile fileOutput= new RandomAccessFile(file,"rw");
        FileChannel chn =fileOutput.getChannel();
        //隧道 映射
        MappedByteBuffer buff = chn.map(FileChannel.MapMode.READ_WRITE, 0,byteBuff.length);
        for(int i=0;i<byteBuff.length;i++) {
            buff.put(byteBuff[i]);
        }
        out.close();
        fileOutput.close();
    }

For details, please refer to the code.

Such an idea allows you to complete the creation of the entire dao layer.
According this idea, you can complete the creation of the entire service layer. The
following is the generation result of the tool I wrote

- H:\test4\leap
  - bean
    - LeapPost.java
    - LeapUser.java
    - LeapUserPost.java
  - service
    - BaseService.java
    - impl
      - BaseServiceImpl.java
      - LeapPostServiceImpl.java
      - LeapUserPostServiceImpl.java
      - LeapUserServiceImpl.java
    - LeapPostService.java
    - LeapUserPostService.java
    - LeapUserService.java

You said that this article can't give you dry goods, but I don't believe that the real dry goods can be seen in an article. Honestly read the document, according to the ideas given in this article, you can create your own basic code writing tool step by step. With this tool, the work efficiency is improved by at least 10%.

I read some source code of hibernate-tools later...and found...it also uses freemarks, but there are still relatively few articles about code generation, so make a note.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326133631&siteId=291194637