lichking2019

lichking2019 查看完整档案

沈阳编辑沈阳大学  |  计算机科学与技术 编辑北京蚂蚁动力科技有限公司  |  资深研发工程师 编辑 github.com/lichking2019/master 编辑
编辑

WOLFTOTEM

个人动态

lichking2019 发布了文章 · 2019-06-19

动手搭建后端框架-Velocity模板引擎的应用

为了提高开发效率,通常会想办法把一些模式固定的重复性的劳动抽取出来,以后再使用的时候,拿来主义就可以了。这样既可以提高开发效率,又降低了出错的风险。

这一思想在我们的日常工作中可以说随处可见,我们完成一项复杂的工程,并不需要面面俱到什么都自己写,我们完全可以利用第三方的jar包让我们达到事半功倍的效果,比如经常使用的apche的commons-lang3包。再比如java中的继承、我们自己封装的工具类等等。 另外一方面,对于源码文件,如果公司有成熟的框架,我们的开发都是遵循着框架制定的约定来进行开发的,我们在创建某一个业务的控制层、业务层、持久层的时候,实际上有相当一部分的工作是重复的。

那么对于源码文件的编写我们能否偷偷懒呢?答案肯定是可以的,我们可以利用模板引擎技术,将不变的部分写在模板文件中,将可变的部分作为变量传递到模板引擎的上下文中,最终生成我们想要的源码文件。

模板引擎的产品有很多,比如前端模板artTemplate、后端模板Velocity、FreeMarker等 本文以Velocity为例,总结一下它在实战中的应用

1.基础知识

搭建过程涉及到的基础知识包括:Maven、Velocity、工厂模式、建造者模式、单元测试
对于基础不熟悉的同学,建议看一下下面的两篇文章
Velocity基础
Velocity语法摘要

2.搭建工程

2.1模块目录

代码生成功能,在我设计的后台框架中,作为一个独立的模块存在,使用Maven构建。
builder目录:建造者模式应用。由于代表表结构的Table实体稍显复杂,因此使用了建造者模式构建Table对象。其实不用也可以,因为Table不是很复杂,只是为了复习一下所学过的设计模式知识
factory目录:工厂模式应用。在构建源码文件的时候,由于涉及到了Controller、Service、Dao、Domain这几种类型的文件,因此针对不同类型的文件,要使用其对应的处理类,因此使用了工厂模式
handler目录:生成源文件的核心代码
model目录:在生成domain的时候,由于字段需要从数据库中的表中读取,因此构造了与表对应的实体类方便处理
utils目录:工具类
Generator.java:程序主文件,调用入口
test目录:单元测试

.
├── generator.iml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── wt
    │   │           └── master
    │   │               └── generator
    │   │                   ├── Generator.java
    │   │                   ├── builder
    │   │                   │   ├── MySqlTableBuilder.java
    │   │                   │   └── TableBuilder.java
    │   │                   ├── factory
    │   │                   │   └── GeneratorFactory.java
    │   │                   ├── handler
    │   │                   │   ├── BaseGenerator.java
    │   │                   │   ├── ControllerGeneratorHandler.java
    │   │                   │   ├── DomainGeneratorHandler.java
    │   │                   │   ├── MapperGeneratorHandler.java
    │   │                   │   └── ServiceGeneratorHandler.java
    │   │                   ├── model
    │   │                   │   └── Table.java
    │   │                   └── util
    │   │                       ├── JdbcUtils.java
    │   │                       ├── SpringContextUtils.java
    │   │                       ├── TableColumnUtils.java
    │   │                       └── TableInfoUtils.java
    │   └── resources
    │       ├── config
    │       │   ├── applicationContext.xml
    │       │   └── db.properties
    │       └── template
    │           ├── controller.java.vm
    │           ├── dao.java.vm
    │           ├── domain.java.vm
    │           ├── service.java.vm
    │           └── serviceimpl.java.vm
    └── test
        └── com.wt.master.generator
            └── GeneratorTest.java

2.2引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>j2ee</artifactId>
        <groupId>com.wt.master</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../version/</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>generator</artifactId>
    <dependencies>
        <!-- 模板引擎 -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.wt.master</groupId>
            <artifactId>core</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.4</version>
        </dependency>
    </dependencies>
</project>

3.核心代码

3.1模板文件的定义

以controller层生成模板为例
将不变的部分直接写到.vm文件中
将模板文件中,有可能发生变化的部分,抽取为变量,变量的值从VelocityContext中获取
在Velocity架构中,有一个上下文的定义,通过上下文,程序将变量放入上下文对象中。而模板从上下文中获取对应变量的值,获取的方式是${变量名},关于Velocity模板文件中的语法,参见上文提到的两篇文章

package ${packagePath}.controller;

import ${packagePath}.domain.${moduleName};
import ${packagePath}.service.${moduleName}Service;
import com.wt.master.core.base.BaseController;
import com.wt.master.core.helper.QueryHelper;
import com.wt.master.core.request.HttpResultEntity;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ${moduleNameCN}控制器
 *
 * @author
 * @date
 */
@Api(value = "${moduleNameCN}控制器", tags = "${moduleName}Controller", description = "${moduleNameCN}控制器" )
@RestController
@RequestMapping("/${moduleName}" )
@Slf4j
public class ${moduleName}Controller extends BaseController<${moduleName}, ${moduleName}Service> {
    @Autowired
    private ${moduleName}Service ${lowerModuleName}Service;

    @Override
    protected ${moduleName}Service getService() {
        return ${lowerModuleName}Service;
    }

}

3.2工厂类定义

根据源码文件类型的不同,定义了不同的处理类,通过工厂模式返回对应的处理类

package com.wt.master.generator.factory;

import com.wt.master.generator.Generator;
import com.wt.master.generator.handler.*;

/**
 * 生成器工厂
 *
 * @author lichking2019@aliyun.com
 * @date Jun 18, 2019 at 4:02:23 PM
 */
public class GeneratorFactory {
    public static BaseGenerator create(Generator.GenerateItem item) {
        BaseGenerator baseGenerator = null;
        switch (item) {
            case service:
                baseGenerator = new ServiceGeneratorHandler();
                break;
            case controller:
                baseGenerator = new ControllerGeneratorHandler();
                break;
            case mapper:
                baseGenerator = new MapperGeneratorHandler();
                break;
            case domain:
                baseGenerator = new DomainGeneratorHandler();
                break;
            default:
                baseGenerator = new ControllerGeneratorHandler();
        }
        return baseGenerator;
    }
}

3.3源码生成处理类定义

以controller处理类为例
定义抽象类,作为基类
定义了抽象方法generate,生成源码文件的处理方法
定义了抽象方法getFilePath,获取生成文件的路径
方法的实现由具体的实现类来实现

package com.wt.master.generator.handler;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;

/**
 * 生成器抽象
 *
 * @author lichking2019@aliyun.com
 * @date May 12, 2019 at 10:44:53 AM
 */
public abstract class BaseGenerator {
    /**
     * 生成代码
     *
     * @param tableName    表名
     * @param moduleName   模块英文名
     * @param moduleNameCN 模块中文名
     * @param packagePath  包路径
     * @return
     */
    public abstract BaseGenerator generate(String tableName, String moduleName, String moduleNameCN,
                                           String packagePath);

    /**
     * 生成文件路径
     * @param packagePath
     * @return
     */
    public abstract String getFilePath(String packagePath,String moduleName);

    /**
     * 获取 模板
     *
     * @param templateName 模板文件名称
     * @return
     */
    Template getTemplate(String templateName) {
        VelocityEngine ve = new VelocityEngine();
        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath" );
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        ve.setProperty("input.encoding","utf-8");
        ve.setProperty("output.encoding","utf-8");
        ve.init();
        Template t = ve.getTemplate("/template/" + templateName);
        return t;
    }

    protected void merge(Template template, VelocityContext ctx, String path) {
        File file = new File(path);
        if(!file.exists()){
            new File(file.getParent()).mkdirs();
        }else{
            System.out.println("替换文件"+file.getAbsolutePath());
        }

        PrintWriter writer = null;
        try {
            writer = new PrintWriter(path);
            template.merge(ctx, writer);
            writer.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
    }

    /**
     * 获得根目录
     * @return
     */
    protected String getRootPath(){
        String rootPath = "";
        try {
            File file = new File(BaseGenerator.class.getResource("/").getFile());
            rootPath = file.getParent();
            rootPath = java.net.URLDecoder.decode(rootPath.substring(0, rootPath.indexOf("target") - 1), "utf-8");
            return rootPath+"/src/main/java";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rootPath;
    }

    /**
     * 转换包路径为文件路径
     * @param packagePath
     * @return
     */
    protected String convertPackagePathToFilePath(String packagePath){
        StringBuilder path = new StringBuilder();
        path.append("/" );
        path.append(packagePath.replace(".", "/" ));
        path.append("/");
        return path.toString();
    }

}

3.4工具类的定义

该类主要是获取表的信息及对应的字段信息

package com.wt.master.generator.util;

import com.wt.master.generator.model.Table;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 表操作类
 *
 * @author lichking2019@aliyun.com
 * @date Apr 23, 2019 at 11:36:30 PM
 */
public class TableInfoUtils {

    public static final String JDBC_TEMPLATE = "jdbcTemplate";

    public static Table getTableColumnList(String tableName) {
        JdbcTemplate jdbcTemplate = (JdbcTemplate) SpringContextUtils.getBean(JDBC_TEMPLATE);

        List<Map<String,Object>> tableInfo = jdbcTemplate.queryForList(getTableStructureSql(tableName));
        if (CollectionUtils.isEmpty(tableInfo)) {
            throw new RuntimeException("表:" + tableName + "不存在" );
        }

        List<Map<String,Object>> columns = jdbcTemplate.queryForList(getColumnStructureSql(tableName));

        return TableColumnUtils.convertToColumn(columns, tableInfo.get(0));
    }

    /**
     * 获取查询表字段属性的SQL
     *
     * @param tableName 表名
     * @return
     */
    private static String getColumnStructureSql(String tableName) {
        StringBuilder sql = new StringBuilder();
        sql.append("select column_name, data_type,column_comment,column_key " );
        sql.append("from information_schema.columns " );
        sql.append("where table_name = '" + tableName + "'" );
        return sql.toString();
    }

    /**
     * 获取表的信息
     * @param tableName
     * @return
     */
    private static String getTableStructureSql(String tableName) {
        StringBuilder sql = new StringBuilder();
        sql.append("select table_name,table_comment " );
        sql.append("from information_schema.tables " );
        sql.append("where table_name= '" + tableName + "'" );
        return sql.toString();
    }


}

3.5应用入口

代用create方法来生成源码文件

package com.wt.master.generator;

import com.wt.master.generator.builder.MySqlTableBuilder;
import com.wt.master.generator.builder.TableBuilder;
import com.wt.master.generator.factory.GeneratorFactory;
import com.wt.master.generator.handler.BaseGenerator;
import com.wt.master.generator.model.Table;
import com.wt.master.generator.util.TableInfoUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;

import java.util.List;

/**
 * 代码生成工具
 *
 * @author lichking2019@aliyun.com
 * @date Apr 23, 2019 at 10:41:51 PM
 */
public class Generator {

    /**
     * 生成代码入口
     *
     * @param tableName    表名
     * @param moduleName   模块英文名
     * @param moduleNameCN 模块中文名
     * @param packagePath  打包路径
     * @param item         生成项目
     */
    public static void create(String tableName, String moduleName, String moduleNameCN, String packagePath,
                              GenerateItem... item) {
        if (StringUtils.isBlank(tableName) || StringUtils.isBlank(moduleName) || StringUtils.isBlank(moduleNameCN) || StringUtils.isBlank(packagePath)) {
            throw new IllegalArgumentException("参数非法!" );
        }

        for (GenerateItem generateItem : item) {
            BaseGenerator baseGenerator = GeneratorFactory.create(generateItem);
            baseGenerator.generate(tableName, moduleName, moduleNameCN, packagePath);
        }
    }


    public enum GenerateItem {
        controller, service, mapper, domain
    }

}

4.单元测试

package com.wt.master.generator;

import org.junit.Test;
import org.junit.Before;
import org.junit.After;

/**
 * Generator Tester.
 *
 * @author <Authors name>
 * @version 1.0
 * @since <pre>Jun 18, 2019</pre>
 */
public class GeneratorTest {
    @Test
    public void testCreate() throws Exception {
        //TODO: Test goes here...
        Generator.create("SecurityRoleT", "SecurityRole", "角色管理", "com.wt.common.security",
                Generator.GenerateItem.controller, Generator.GenerateItem.service, Generator.GenerateItem.mapper,
                Generator.GenerateItem.domain);
    }
} 

源码github地址

查看原文

赞 1 收藏 1 评论 0

lichking2019 发布了文章 · 2019-06-19

动手搭建后端框架-Velocity模板引擎的应用

为了提高开发效率,通常会想办法把一些模式固定的重复性的劳动抽取出来,以后再使用的时候,拿来主义就可以了。这样既可以提高开发效率,又降低了出错的风险。

这一思想在我们的日常工作中可以说随处可见,我们完成一项复杂的工程,并不需要面面俱到什么都自己写,我们完全可以利用第三方的jar包让我们达到事半功倍的效果,比如经常使用的apche的commons-lang3包。再比如java中的继承、我们自己封装的工具类等等。 另外一方面,对于源码文件,如果公司有成熟的框架,我们的开发都是遵循着框架制定的约定来进行开发的,我们在创建某一个业务的控制层、业务层、持久层的时候,实际上有相当一部分的工作是重复的。

那么对于源码文件的编写我们能否偷偷懒呢?答案肯定是可以的,我们可以利用模板引擎技术,将不变的部分写在模板文件中,将可变的部分作为变量传递到模板引擎的上下文中,最终生成我们想要的源码文件。

模板引擎的产品有很多,比如前端模板artTemplate、后端模板Velocity、FreeMarker等 本文以Velocity为例,总结一下它在实战中的应用

1.基础知识

搭建过程涉及到的基础知识包括:Maven、Velocity、工厂模式、建造者模式、单元测试
对于基础不熟悉的同学,建议看一下下面的两篇文章
Velocity基础
Velocity语法摘要

2.搭建工程

2.1模块目录

代码生成功能,在我设计的后台框架中,作为一个独立的模块存在,使用Maven构建。
builder目录:建造者模式应用。由于代表表结构的Table实体稍显复杂,因此使用了建造者模式构建Table对象。其实不用也可以,因为Table不是很复杂,只是为了复习一下所学过的设计模式知识
factory目录:工厂模式应用。在构建源码文件的时候,由于涉及到了Controller、Service、Dao、Domain这几种类型的文件,因此针对不同类型的文件,要使用其对应的处理类,因此使用了工厂模式
handler目录:生成源文件的核心代码
model目录:在生成domain的时候,由于字段需要从数据库中的表中读取,因此构造了与表对应的实体类方便处理
utils目录:工具类
Generator.java:程序主文件,调用入口
test目录:单元测试

.
├── generator.iml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── wt
    │   │           └── master
    │   │               └── generator
    │   │                   ├── Generator.java
    │   │                   ├── builder
    │   │                   │   ├── MySqlTableBuilder.java
    │   │                   │   └── TableBuilder.java
    │   │                   ├── factory
    │   │                   │   └── GeneratorFactory.java
    │   │                   ├── handler
    │   │                   │   ├── BaseGenerator.java
    │   │                   │   ├── ControllerGeneratorHandler.java
    │   │                   │   ├── DomainGeneratorHandler.java
    │   │                   │   ├── MapperGeneratorHandler.java
    │   │                   │   └── ServiceGeneratorHandler.java
    │   │                   ├── model
    │   │                   │   └── Table.java
    │   │                   └── util
    │   │                       ├── JdbcUtils.java
    │   │                       ├── SpringContextUtils.java
    │   │                       ├── TableColumnUtils.java
    │   │                       └── TableInfoUtils.java
    │   └── resources
    │       ├── config
    │       │   ├── applicationContext.xml
    │       │   └── db.properties
    │       └── template
    │           ├── controller.java.vm
    │           ├── dao.java.vm
    │           ├── domain.java.vm
    │           ├── service.java.vm
    │           └── serviceimpl.java.vm
    └── test
        └── com.wt.master.generator
            └── GeneratorTest.java

2.2引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>j2ee</artifactId>
        <groupId>com.wt.master</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../version/</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>generator</artifactId>
    <dependencies>
        <!-- 模板引擎 -->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.wt.master</groupId>
            <artifactId>core</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.4</version>
        </dependency>
    </dependencies>
</project>

3.核心代码

3.1模板文件的定义

以controller层生成模板为例
将不变的部分直接写到.vm文件中
将模板文件中,有可能发生变化的部分,抽取为变量,变量的值从VelocityContext中获取
在Velocity架构中,有一个上下文的定义,通过上下文,程序将变量放入上下文对象中。而模板从上下文中获取对应变量的值,获取的方式是${变量名},关于Velocity模板文件中的语法,参见上文提到的两篇文章

package ${packagePath}.controller;

import ${packagePath}.domain.${moduleName};
import ${packagePath}.service.${moduleName}Service;
import com.wt.master.core.base.BaseController;
import com.wt.master.core.helper.QueryHelper;
import com.wt.master.core.request.HttpResultEntity;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ${moduleNameCN}控制器
 *
 * @author
 * @date
 */
@Api(value = "${moduleNameCN}控制器", tags = "${moduleName}Controller", description = "${moduleNameCN}控制器" )
@RestController
@RequestMapping("/${moduleName}" )
@Slf4j
public class ${moduleName}Controller extends BaseController<${moduleName}, ${moduleName}Service> {
    @Autowired
    private ${moduleName}Service ${lowerModuleName}Service;

    @Override
    protected ${moduleName}Service getService() {
        return ${lowerModuleName}Service;
    }

}

3.2工厂类定义

根据源码文件类型的不同,定义了不同的处理类,通过工厂模式返回对应的处理类

package com.wt.master.generator.factory;

import com.wt.master.generator.Generator;
import com.wt.master.generator.handler.*;

/**
 * 生成器工厂
 *
 * @author lichking2019@aliyun.com
 * @date Jun 18, 2019 at 4:02:23 PM
 */
public class GeneratorFactory {
    public static BaseGenerator create(Generator.GenerateItem item) {
        BaseGenerator baseGenerator = null;
        switch (item) {
            case service:
                baseGenerator = new ServiceGeneratorHandler();
                break;
            case controller:
                baseGenerator = new ControllerGeneratorHandler();
                break;
            case mapper:
                baseGenerator = new MapperGeneratorHandler();
                break;
            case domain:
                baseGenerator = new DomainGeneratorHandler();
                break;
            default:
                baseGenerator = new ControllerGeneratorHandler();
        }
        return baseGenerator;
    }
}

3.3源码生成处理类定义

以controller处理类为例
定义抽象类,作为基类
定义了抽象方法generate,生成源码文件的处理方法
定义了抽象方法getFilePath,获取生成文件的路径
方法的实现由具体的实现类来实现

package com.wt.master.generator.handler;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;

/**
 * 生成器抽象
 *
 * @author lichking2019@aliyun.com
 * @date May 12, 2019 at 10:44:53 AM
 */
public abstract class BaseGenerator {
    /**
     * 生成代码
     *
     * @param tableName    表名
     * @param moduleName   模块英文名
     * @param moduleNameCN 模块中文名
     * @param packagePath  包路径
     * @return
     */
    public abstract BaseGenerator generate(String tableName, String moduleName, String moduleNameCN,
                                           String packagePath);

    /**
     * 生成文件路径
     * @param packagePath
     * @return
     */
    public abstract String getFilePath(String packagePath,String moduleName);

    /**
     * 获取 模板
     *
     * @param templateName 模板文件名称
     * @return
     */
    Template getTemplate(String templateName) {
        VelocityEngine ve = new VelocityEngine();
        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath" );
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        ve.setProperty("input.encoding","utf-8");
        ve.setProperty("output.encoding","utf-8");
        ve.init();
        Template t = ve.getTemplate("/template/" + templateName);
        return t;
    }

    protected void merge(Template template, VelocityContext ctx, String path) {
        File file = new File(path);
        if(!file.exists()){
            new File(file.getParent()).mkdirs();
        }else{
            System.out.println("替换文件"+file.getAbsolutePath());
        }

        PrintWriter writer = null;
        try {
            writer = new PrintWriter(path);
            template.merge(ctx, writer);
            writer.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
    }

    /**
     * 获得根目录
     * @return
     */
    protected String getRootPath(){
        String rootPath = "";
        try {
            File file = new File(BaseGenerator.class.getResource("/").getFile());
            rootPath = file.getParent();
            rootPath = java.net.URLDecoder.decode(rootPath.substring(0, rootPath.indexOf("target") - 1), "utf-8");
            return rootPath+"/src/main/java";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rootPath;
    }

    /**
     * 转换包路径为文件路径
     * @param packagePath
     * @return
     */
    protected String convertPackagePathToFilePath(String packagePath){
        StringBuilder path = new StringBuilder();
        path.append("/" );
        path.append(packagePath.replace(".", "/" ));
        path.append("/");
        return path.toString();
    }

}

3.4工具类的定义

该类主要是获取表的信息及对应的字段信息

package com.wt.master.generator.util;

import com.wt.master.generator.model.Table;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 表操作类
 *
 * @author lichking2019@aliyun.com
 * @date Apr 23, 2019 at 11:36:30 PM
 */
public class TableInfoUtils {

    public static final String JDBC_TEMPLATE = "jdbcTemplate";

    public static Table getTableColumnList(String tableName) {
        JdbcTemplate jdbcTemplate = (JdbcTemplate) SpringContextUtils.getBean(JDBC_TEMPLATE);

        List<Map<String,Object>> tableInfo = jdbcTemplate.queryForList(getTableStructureSql(tableName));
        if (CollectionUtils.isEmpty(tableInfo)) {
            throw new RuntimeException("表:" + tableName + "不存在" );
        }

        List<Map<String,Object>> columns = jdbcTemplate.queryForList(getColumnStructureSql(tableName));

        return TableColumnUtils.convertToColumn(columns, tableInfo.get(0));
    }

    /**
     * 获取查询表字段属性的SQL
     *
     * @param tableName 表名
     * @return
     */
    private static String getColumnStructureSql(String tableName) {
        StringBuilder sql = new StringBuilder();
        sql.append("select column_name, data_type,column_comment,column_key " );
        sql.append("from information_schema.columns " );
        sql.append("where table_name = '" + tableName + "'" );
        return sql.toString();
    }

    /**
     * 获取表的信息
     * @param tableName
     * @return
     */
    private static String getTableStructureSql(String tableName) {
        StringBuilder sql = new StringBuilder();
        sql.append("select table_name,table_comment " );
        sql.append("from information_schema.tables " );
        sql.append("where table_name= '" + tableName + "'" );
        return sql.toString();
    }


}

3.5应用入口

代用create方法来生成源码文件

package com.wt.master.generator;

import com.wt.master.generator.builder.MySqlTableBuilder;
import com.wt.master.generator.builder.TableBuilder;
import com.wt.master.generator.factory.GeneratorFactory;
import com.wt.master.generator.handler.BaseGenerator;
import com.wt.master.generator.model.Table;
import com.wt.master.generator.util.TableInfoUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;

import java.util.List;

/**
 * 代码生成工具
 *
 * @author lichking2019@aliyun.com
 * @date Apr 23, 2019 at 10:41:51 PM
 */
public class Generator {

    /**
     * 生成代码入口
     *
     * @param tableName    表名
     * @param moduleName   模块英文名
     * @param moduleNameCN 模块中文名
     * @param packagePath  打包路径
     * @param item         生成项目
     */
    public static void create(String tableName, String moduleName, String moduleNameCN, String packagePath,
                              GenerateItem... item) {
        if (StringUtils.isBlank(tableName) || StringUtils.isBlank(moduleName) || StringUtils.isBlank(moduleNameCN) || StringUtils.isBlank(packagePath)) {
            throw new IllegalArgumentException("参数非法!" );
        }

        for (GenerateItem generateItem : item) {
            BaseGenerator baseGenerator = GeneratorFactory.create(generateItem);
            baseGenerator.generate(tableName, moduleName, moduleNameCN, packagePath);
        }
    }


    public enum GenerateItem {
        controller, service, mapper, domain
    }

}

4.单元测试

package com.wt.master.generator;

import org.junit.Test;
import org.junit.Before;
import org.junit.After;

/**
 * Generator Tester.
 *
 * @author <Authors name>
 * @version 1.0
 * @since <pre>Jun 18, 2019</pre>
 */
public class GeneratorTest {
    @Test
    public void testCreate() throws Exception {
        //TODO: Test goes here...
        Generator.create("SecurityRoleT", "SecurityRole", "角色管理", "com.wt.common.security",
                Generator.GenerateItem.controller, Generator.GenerateItem.service, Generator.GenerateItem.mapper,
                Generator.GenerateItem.domain);
    }
} 

源码github地址

查看原文

赞 1 收藏 1 评论 0

lichking2019 关注了专栏 · 2019-04-15

阿里云栖号

汇集阿里技术精粹-yq.aliyun.com

关注 11803

lichking2019 关注了专栏 · 2019-04-15

服务端思维

微信公众号「服务端思维」

关注 1505

lichking2019 关注了专栏 · 2019-04-15

疯狂的技术宅

本专栏文章首发于公众号:前端先锋 。

关注 24297

lichking2019 关注了专栏 · 2019-04-15

终身学习者

我要先坚持分享20年,大家来一起见证吧。

关注 40744

lichking2019 关注了标签 · 2019-04-15

linux

Linux是一种自由和开放源代码的类Unix计算机操作系统。目前存在着许多不同的Linux,但它们全都使用了Linux内核。Linux可安装在各种各样的计算机硬件设备,从手机、平板电脑、路由器和视频游戏控制台,到台式计算机,大型机和超级计算机。

Linux家族家谱图,很全很强大!! 图中可以清楚的看出各个Linux发行版的血缘关系。无水印原图:http://url.cn/5ONhQb

关注 63651

lichking2019 关注了标签 · 2019-04-15

java

Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaSE, JavaEE, JavaME)的总称。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

Java编程语言的风格十分接近 C++ 语言。继承了 C++ 语言面向对象技术的核心,Java舍弃了 C++ 语言中容易引起错误的指針,改以引用取代,同时卸载原 C++ 与原来运算符重载,也卸载多重继承特性,改用接口取代,增加垃圾回收器功能。在 Java SE 1.5 版本中引入了泛型编程、类型安全的枚举、不定长参数和自动装/拆箱特性。太阳微系统对 Java 语言的解释是:“Java编程语言是个简单、面向对象、分布式、解释性、健壮、安全与系统无关、可移植、高性能、多线程和动态的语言”。

版本历史

重要版本号版本代号发布日期
JDK 1.01996 年 1 月 23 日
JDK 1.11997 年 2 月 19 日
J2SE 1.2Playground1998 年 12 月 8 日
J2SE 1.3Kestrel2000 年 5 月 8 日
J2SE 1.4Merlin2002 年 2 月 6 日
J2SE 5.0 (1.5.0)Tiger2004 年 9 月 30 日
Java SE 6Mustang2006 年 11 月 11 日
Java SE 7Dolphin2011 年 7 月 28 日
Java SE 8JSR 3372014 年 3 月 18 日
最新发布的稳定版本:
Java Standard Edition 8 Update 11 (1.8.0_11) - (July 15, 2014)
Java Standard Edition 7 Update 65 (1.7.0_65) - (July 15, 2014)

更详细的版本更新查看 J2SE Code NamesJava version history 维基页面

新手帮助

不知道如何开始写你的第一个 Java 程序?查看 Oracle 的 Java 上手文档

在你遇到问题提问之前,可以先在站内搜索一下关键词,看是否已经存在你想提问的内容。

命名规范

Java 程序应遵循以下的 命名规则,以增加可读性,同时降低偶然误差的概率。遵循这些命名规范,可以让别人更容易理解你的代码。

  • 类型名(类,接口,枚举等)应以大写字母开始,同时大写化后续每个单词的首字母。例如:StringThreadLocaland NullPointerException。这就是著名的帕斯卡命名法。
  • 方法名 应该是驼峰式,即以小写字母开头,同时大写化后续每个单词的首字母。例如:indexOfprintStackTraceinterrupt
  • 字段名 同样是驼峰式,和方法名一样。
  • 常量表达式的名称static final 不可变对象)应该全大写,同时用下划线分隔每个单词。例如:YELLOWDO_NOTHING_ON_CLOSE。这个规范也适用于一个枚举类的值。然而,static final 引用的非不可变对象应该是驼峰式。

Hello World

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

编译并调用:

javac -d . HelloWorld.java
java -cp . HelloWorld

Java 的源代码会被编译成可被 Java 命令执行的中间形式(用于 Java 虚拟机的字节代码指令)。

可用的 IDE

学习资源

常见的问题

下面是一些 SegmentFault 上在 Java 方面经常被人问到的问题:

(待补充)

关注 104794

lichking2019 关注了标签 · 2019-04-15

mysql

MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQL AB公司。在2008年1月16号被Sun公司收购。而2009年,SUN又被Oracle收购。MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内。这样就增加了速度并提高了灵活性。MySQL的SQL“结构化查询语言”。SQL是用于访问数据库的最常用标准化语言。MySQL软件采用了GPL(GNU通用公共许可证)。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。

关注 63020

lichking2019 关注了标签 · 2019-04-15

css

层叠样式表(英语:Cascading Style Sheets,简写CSS),又称串样式列表,由W3C定义和维护的标准,一种用来为结构化文档(如HTML文档或XML应用)添加样式(字体、间距和颜色等)的计算机语言。

关注 61528

认证与成就

  • 获得 1 次点赞
  • 获得 3 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 3 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2019-04-15
个人主页被 233 人浏览