java实现代码自动生成工具,基于spring boot

前言

此项目主要解决在项目搭建初期,创建项目时很多代码手动创建太过繁琐,耗费不必要的开发时间。通过此代码生成工具可以自动生成相关代码,当然不局限于controller层、service层、entity层、mapper层的代码生成!因为本项目中自定义代码生成规则的配置比较简单,只需自定义模板并创建工厂实例即可。同时可自定义代码的生成路径,未设置则默认生成在本项目下(可更直观查看生成的结构效果,文末有效果图)。

本项目基于SpringBoot,通过beetl模板引擎自动渲染生成代码。

项目源码地址:bhy702-generator


项目结构

在这里插入图片描述


一: 导入pom文件相关依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

<!-- mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

<dependency>
    <groupId>com.ibeetl</groupId>
    <artifactId>beetl-framework-starter</artifactId>
    <version>1.1.68.RELEASE</version>
</dependency>
<!-- 升级beetl的依赖,保证在1.8上不出现警告 -->
<dependency>
    <groupId>org.antlr</groupId>
    <artifactId>antlr4-runtime</artifactId>
    <version>4.7.1</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

二: 编写beetl配置类
/**
 * @author: brbai
 * @create: 2019-10-16 17:12:45
 * @description:
 */
@Configuration
@Slf4j
@Data
public class BeetlConfiguration {

    @Value("${beetl.template-path}")
    private String templatePath;

    @Value("${beetl.delimiter-statement-start}")
    private String delimiterStatementStart;

    @Value("${beetl.delimiter-statement-end}")
    private String delimiterStatementEnd;

    @Bean(name = "beetlConfig")
    public BeetlGroupUtilConfiguration beetlGroupUtilConfiguration() {
        BeetlGroupUtilConfiguration beetlGroupUtilConfiguration = new BeetlGroupUtilConfiguration();

        // Beetl的配置
        Properties properties = new Properties();
        properties.setProperty("statementStart",delimiterStatementStart);
        properties.setProperty("statementEnd",delimiterStatementEnd);
        properties.setProperty("DELIMITER_STATEMENT_START", delimiterStatementStart);
        properties.setProperty("DELIMITER_STATEMENT_END", delimiterStatementEnd);
        beetlGroupUtilConfiguration.setConfigProperties(properties);

        ClasspathResourceLoader resourceLoader = new ClasspathResourceLoader(templatePath);

        beetlGroupUtilConfiguration.setResourceLoader(resourceLoader);
        // 调用Beetl的初始化方法
        beetlGroupUtilConfiguration.init();

        return beetlGroupUtilConfiguration;
    }

}

三: 配置properties文件

application.properties文件:

server.port=8090
server.servlet.context-path=/

spring.datasource.url=jdbc:mysql://localhost:3306/building_materials?useUnicode=true&characterEncoding=UTF-8&nullCatalogMeansCurrent=true&tinyInt1isBit=false
spring.datasource.username=root
spring.datasource.password=bhy702

# beetl模板引擎的加载路径。以resources为根路径,此时表示加载resources/template文件夹中的模板文件
beetl.template-path = template
# beetl模板引擎语法开始标记
beetl.delimiter-statement-start = @
# beetl模板引擎语法结束标记。为空时在有开始标记@的行末结束
beetl.delimiter-statement-end =

# 代码文件的保存路径,注释后默认保存在本项目中
#project.base-path = F:\\360MoveData\\Users\\n551\\Desktop

为了便于查看代码生成效果,默认代码生成在此项目内,同时提供自定义代码生成位置。自定义代码生成位置只需配置application.properties中的project.base-path


四: 设计代码模板(代码模板没限制,想怎么设计都行)
下面以Entity.tpl代码模板文件为例:
package ${props.params.packageName};

import lombok.Data;
@for(column in props.columnList){
@if(column.type=='Date'){
import java.util.Date;
@break;
@}}

\@Data
public class ${props.className}{

    @for(column in props.columnList){
    private ${column.type} ${column.lowerPropertyName};

    @}
}


五: 根据代码模板确定所需参数数据,添加代码模板的工厂实例。

为了便于开发,我封装了一个模板所需的参数类TplProperties

TplProperties参数类:
/**
 * @author: brbai
 * @create: 2019-12-26 11:13:42
 * @description: 模板参数
 */
@Data
public class TplProperties {

    private String basePath;
    private String rootPackage;
    private String tableName;
    private List<Column> columnList;

    private Map<String,Object> params = new HashMap();;
    /**
     * 表名格式转换
     * xxx_yyy->XxxYyy
     */
    private String className;

    /**
     * 表名格式转换
     * xxx_yyy->xxxYyy
     */
    private String propertyName;

    public TplProperties(String basePath, String rootPackage, String tableName, List<Column> columnList) {
        this.basePath = basePath;
        this.rootPackage = rootPackage;
        this.tableName = tableName;
        this.columnList = columnList;
    }

    public TplProperties(String rootPackage, String tableName, List<Column> columnList) {
        this.rootPackage = rootPackage;
        this.tableName = tableName;
        this.columnList = columnList;
    }

    public String getClassName() {
        return StringUtil.mapTableNameToClassName(tableName);
    }
    public String getPropertyName() {
        return StringUtil.mapTableNameToPropertyName(tableName);
    }
    
    public void setParam(String key,Object value) {
        this.params.put(key,value);
    }

    public String getBasePath() {
        if(basePath == null){
            //未在properties文件中设置代码生成路径时,代码默认生成在此项目下
            return System.getProperty("user.dir") + "/src";
        }
        return basePath;
    }
}

工厂实例:
/**
 * @author: brbai
 * @create: 2019-12-14 19:12:59
 * @description:
 */
public class Entity implements Code {

    @Override
    public void create(GroupTemplate gt, TplProperties properties, String tplPath) throws IOException {

        String packageName =  properties.getRootPackage()+ ".entity";
        properties.setParam("packageName",packageName);

        Template t = gt.getTemplate(tplPath);
        t.binding("props", properties);

        GenerateUtil.createFile(t,properties.getBasePath()+"/main/java/"
                + packageName.replace(".", "/") + "/" + properties.getClassName() + ".java");
    }
}

六: 识别数据库类型,读取数据库表结构
/**
 * @Description: 获取数据库表结构
 * @Param: [sqlSessionFactory]
 * @return: java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>
 */
public static Map<String, Map<String, String>> getDatabaseAttribute(SqlSession sqlSession) throws SQLException {

    Map<String, Map<String, String>> databaseAttribute = new HashMap<>();

    Connection connection = sqlSession.getConnection();

    //获得数据库信息
    DatabaseMetaData metaData = connection.getMetaData();

    String databaseName = metaData.getDatabaseProductName();

    if ("MySQL".equals(databaseName)) {
        //获得数据库表
        ResultSet resultSet = metaData.getTables(null, null, null, new String[]{"TABLE"});
        while (resultSet.next()) {
            String tableName = resultSet.getString(3);
            String sql = "SELECT * FROM " + tableName;
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            ResultSet set = preparedStatement.executeQuery();
            //获得表信息
            ResultSetMetaData md = set.getMetaData();
            //获得表字段数
            int columnCount = md.getColumnCount();

            Map<String, String> attributes = new LinkedHashMap<>();

            for (int i = 1; i <= columnCount; i++) {
                //字段名
                String columnName = md.getColumnName(i);
                //字段属性
                String columnType = md.getColumnTypeName(i);

                attributes.put(columnName, columnType);
            }
            databaseAttribute.put(tableName,attributes);
        }
    }else if("Oracle".equals(databaseName)){
    		//DEVTEST是oracle的用户名。此Oracle代码还没怎么测试。
            ResultSet rs = metaData.getTables("null", "DEVTEST", "%", new String[]{"TABLE"});

            while (rs.next()) {
                String tableName = rs.getString("TABLE_NAME");
                ResultSet columns = metaData
                        .getColumns(null, "DEVTEST", tableName, "%");

                Map<String, String> attributes = new LinkedHashMap<>();
                while (columns.next()) {
                    attributes.put(columns.getString("COLUMN_NAME"), columns.getString("TYPE_NAME"));
                }
                databaseAttribute.put(tableName, attributes);
            }
    }


    return databaseAttribute;
}

七: 数据清洗,设置生成代码的包名,获取工厂实例生成代码文件
/**
 * @author: brbai
 * @create: 2019-11-20 14:12:12
 * @description: test
 */

@RunWith(SpringRunner.class)
@SpringBootTest
public class CodeTest {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Autowired
    private BeetlGroupUtilConfiguration beetlConfig;

    @Autowired
    private CodeFactory codeFactory;

    @Value("${project.base-path:#{null}}")
    private String basePath;

    @Test
    public void codeGeneratorTest() throws SQLException{

		//生成代码的项目包名
        String rootPackage = "aaa.bbb.ccc";
        
        GroupTemplate gt = beetlConfig.getGroupTemplate();
        //获取数据库表结构
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Map<String, Map<String, String>> databaseAttribute = DBUtil.getDatabaseAttribute(sqlSession);

        String databaseName = sqlSession.getConnection().getMetaData().getDatabaseProductName();
  
        databaseAttribute.forEach((tableName,columnMap)->{
            List<Column> columnList = new ArrayList<>();
            columnMap.forEach((name,type)->{
                String javaType = null;
                //数据库行字段类型以及字段名格式转换,并存入模板参数集合
                if("MySQL".equals(databaseName)){
                    javaType = DBUtil.sqlTypeToJavaType(type);
                }else if("Oracle".equals(databaseName)){
                    javaType = DBUtil.oracleSqlTypeToJavaType(type);
                }
                columnList.add(new Column(name, javaType, StringUtil.mapUnderscoreToCamelCase(name), StringUtil.mapTableNameToClassName(name)));
            });
            
            //构建参数
            TplProperties properties = null;
            if(basePath != null){
                properties = new TplProperties(basePath,rootPackage,tableName,columnList);
            }else{
                properties = new TplProperties(rootPackage,tableName,columnList);
            }

            try {
                //代码生成
                codeFactory.getCodeInstance("CONTROLLER").create(gt,properties,"/Controller.tpl");
                codeFactory.getCodeInstance("SERVICE").create(gt,properties,"/Service.tpl");
                codeFactory.getCodeInstance("ENTITY").create(gt,properties,"/Entity.tpl");
                codeFactory.getCodeInstance("MAPPER").create(gt,properties,"/Mapper.tpl");
                codeFactory.getCodeInstance("MAPPER_XML").create(gt,properties,"/MapperXml.tpl");
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

    }
}

运行codeGeneratorTest()方法

效果图如下:

在这里插入图片描述
未配置代码生成路径时:
在这里插入图片描述
配置了代码生成路径时:
在这里插入图片描述


由于项目代码比较多,没能全部贴出来,源码我已经上传码云了,想看源码的小伙伴可以点这里。bhy702-generator


欢迎访问本文的个人博客链接: https://br-bai.github.io/2019/12/26/Java实现代码自动生成工具,基于Spring Boot/

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一. 生成器模板路径可以引用相关变量 如 ${basepackage}/${className}.java,根据该变量生成输出文件 二. 自动搜索某个目录所有模板文件,无需配置 三.代码生成器模板可以引用的相关变量 1. g.generateByTable("table_name") 方法可以引用的变量 table : cn.org.rapid_framework.generator.provider.db.table.model.Table 2. g.generateByClass(UserInfo.class) 方法可以引用的变量 clazz : cn.org.rapid_framework.generator.provider.java.model.JavaClass 3. g.generateBySql("select * from user_info where pwd=:pwd") 方法可以引用的变量 sql : cn.org.rapid_framework.generator.provider.db.sql.model.Sql 4.公共变量 env : 系统环境变量 System.getProperties() : 直接引用,没有前缀 generator.properties 文件中的所有属性,直接引用,没有前缀 gg : 模板控制变量, cn.org.rapid_framework.generator.GeneratorControl 四.每个模板有gg变量可以控制自身的自定义配置 (每一个模板都会创建新的gg实例) 如是否生成,是否覆盖目标文件,甚至是生成其它文件 ${gg.setIgnoreOutput(true)}: 如果为true则不生成输出文件 ${gg.generateFile(outputFile,content)} 在模板中生成其它文件 ${gg.getProperty(key,defaultValue)}: 得到proproty,如果没有找到,则返回默认值 ${gg.getInputProperty(key)}: 会弹出一个输入框,提示用户输入值 具体参考: http://code.google.com/p/rapid-framework/wiki/rapid_generator_gg 五.支持生成(gen)及删除操作(del),即生成的代码也可以很方便的删除 六. 自动删除模板扩展名: .ftl,.vm 举例: 如你有一个模板 SqlMap.xml.ftl 将变为 SqlMap.xml 所以你要生成ftl扩展名的文件,应该将文件名从 list.ftl => list.ftl.ftl 七. 模板自动include所有父目录的:macro.include文件,可以存放公共的macro 示例: 如你的模板为 com/project/UserDao.java, 将自动include: com/project/macro.include, com/macro.include, macro.include 八. generator.xml (或者generator.properties)配置文件 1.类似ant可以变量引用,引用环境变量使用${env.JAVA_HOME}, 引用System.getProperties()直接引用 2.自动替换generator.properties中的句号(.)为反斜杠,设置key为key+"_dir"后缀 示例: pkg=com.company => pkg_dir=com/company 九.自动拷贝二进制文件至输出目录 如模板目录下的 zip,rar,doc文件将会自动拷贝至输出目录,不会破坏文件格式 (通过扩展名自动识别) 十. 数据库表配置,用于自定义生成器模板引用的table变量,配置文件必须存放在classpath: generator_config/table/table_name.xml (该文件生成器可以生成,自己再自定义修改) <!-- <数据库列名 columnAlias="列的别名" javaType="自定义javaType" unique="是否唯一性约束" nullable="是否可以为空" pk="是否主键,在表没有主键的情况下,可以指定一个代理主键" updatable="是否可以更新" insertab
基于spring boot的景区预约平台是一个基于Java语言和spring boot框架开发的系统,通过该平台用户可以实现在线预约景区门票、导览服务等功能。 在设计实现这个平台的过程中,首先需要搭建一个基于spring boot的web应用。然后利用spring boot框架提供的自动配置和快速开发特性,设计系统的模块和接口,实现各种功能的逻辑。 针对景区预约平台的功能,我们可以设计用户注册登录模块、景区信息管理模块、订单管理模块、支付模块、以及导览服务模块等。 在用户注册登录模块中,用户可以通过填写个人信息和账号密码等来注册并登录系统。在景区信息管理模块中,管理员可以发布和管理景区的详细信息、门票价格、以及景区的导览信息等。在订单管理模块中,用户可以选择景区、预约时间、人数等信息生成订单。支付模块可以提供用户线上支付功能,使用户可以快捷便捷地完成支付操作。在导览服务模块中,用户可以获取对应景区的导览信息,帮助用户更好地了解景区。 在实现这些功能时,可以利用spring boot框架的依赖管理功能,并结合spring的各种组件和注解,来简化开发流程,提高代码的可维护性和可扩展性。 总的来说,基于spring boot的景区预约平台通过利用spring boot框架的快速开发优势,结合丰富的Java生态系统,可以设计出一个功能完善、性能稳定的景区预约平台。同时也可以通过spring boot的特性实现系统的模块化、可配置性和高可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值