使用 freemarker 制作代码生成器
在开发的过程中发现有大量的重复代码,比如 Controller 和 Service 以及 Mapper 和实体类,后两者都可以使用 Mybatis 自动生成,前两者只能自己写。本文介绍使用 freemarker 制作代码生成器,可以自动生成Controller 、 Service 、Dto、Vue 代码。首先解释一下为什么使用 freemarker ?他是一个模板语言,模板的特点就是有很多不变的,
在开发的过程中发现有大量的重复代码,比如 Controller
和 Service
以及 Mapper
和实体类,后两者都可以使用 Mybatis 自动生成,前两者只能自己写。
本文介绍使用 freemarker 制作代码生成器,可以自动生成 Controller
、 Service
、Dto
、Vue
代码。
首先解释一下为什么使用 freemarker
?
- 他是一个模板语言,模板的特点就是有很多不变的,还有一小部分变的;
- 观察我们的 controller 层代码,大部分是一样的,变的只是实体类的名字,所以动态的数据可以使用占位符;
- freemarker 提供了包括占位符在内的多种处理方式,所以我们选择它。
当然也可以使用 thymeleaf
,两者大同小异,都可以实现。
搭建环境
pom
<!-- 模板引擎freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.29</version>
</dependency>
<!-- 读xml -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
我们先将用到 freemarker 的地方单独拿出来,封装成一个 工具类 :
package com.lsu.generator.util;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
/**
* 代码生成器工具类
*
* @Author wang suo
* @Date 2020/10/12 0012 18:30
* @Version 1.0
*/
public class FreemarkerUtil {
private static String ftlPath = "generator\\src\\main\\java\\com\\lsu\\generator\\ftl\\";
private static Template temp;
public static void initConfig(String ftlName) throws IOException {
Configuration conf = new Configuration(Configuration.VERSION_2_3_29);
conf.setDirectoryForTemplateLoading(new File(ftlPath));
conf.setObjectWrapper(new DefaultObjectWrapper(Configuration.VERSION_2_3_29));
temp = conf.getTemplate(ftlName + ".ftl");
}
public static void generator(Map<String, Object> map, String fileName) throws IOException, TemplateException {
FileWriter fw = new FileWriter(fileName);
BufferedWriter bw = new BufferedWriter(fw);
temp.process(map, bw);
bw.flush();
fw.close();
}
}
然后我们就可以制作模板了,新建 controller.ftl
:
package com.lsu.${module}.controller.admin;
import com.lsu.server.dto.${Domain}Dto;
import com.lsu.server.dto.PageDto;
import com.lsu.server.dto.ResponseDto;
import com.lsu.server.service.${Domain}Service;
import com.lsu.server.util.ValidatorUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 测试
*
* @Author wang suo
* @Date 2020/10/9 0009 18:21
* @Version 1.0
*/
@RestController
@RequestMapping("/admin/${domain}")
public class ${Domain}Controller {
private static final Logger LOG = LoggerFactory.getLogger(${Domain}Controller.class);
public static final String BUSINESS_NAME = "${tableNameCn}";
@Resource
private ${Domain}Service ${domain}Service;
@PostMapping("/list")
public ResponseDto<PageDto> getAll(@RequestBody PageDto<${Domain}Dto> pageDto) {
ResponseDto<PageDto> responseDto = new ResponseDto<>();
${domain}Service.getAll(pageDto);
responseDto.setContent(pageDto);
return responseDto;
}
@PostMapping("/save")
public ResponseDto<${Domain}Dto> save(@RequestBody ${Domain}Dto ${domain}Dto) {
// 保存校验
<#list fieldList as field>
<#if !field.nullAble>
ValidatorUtil.require(${domain}Dto.get${field.nameBigHump}(), "${field.nameCn}");
</#if>
<#if (field.length > 0)>
ValidatorUtil.length(${domain}Dto.get${field.nameBigHump}(), "${field.nameCn}", 1, ${field.length});
</#if>
</#list>
ResponseDto<${Domain}Dto> responseDto = new ResponseDto<>();
${domain}Service.save(${domain}Dto);
responseDto.setContent(${domain}Dto);
return responseDto;
}
@DeleteMapping("/delete/{id}")
public ResponseDto delete(@PathVariable String id) {
ResponseDto responseDto = new ResponseDto();
${domain}Service.delete(id);
return responseDto;
}
}
其中 for
和 if
, ${field.nameCn}
,都是模板的语法:
// 保存校验
<#list fieldList as field>
<#if !field.nullAble>
ValidatorUtil.require(${domain}Dto.get${field.nameBigHump}(), "${field.nameCn}");
</#if>
<#if (field.length > 0)>
ValidatorUtil.length(${domain}Dto.get${field.nameBigHump}(), "${field.nameCn}", 1, ${field.length});
</#if>
</#list>
如上例中的 fieldList
就是我们事先定义好的变量:
private static String MODULE = "business";
private static String toControllerPath = MODULE + "\\src\\main\\java\\com\\lsu\\" + MODULE + "\\controller\\admin\\";
public static void main(String[] args) throws Exception {
Map<String, Object> map = new HashMap<>(3);
map.put("Domain", "Section");
map.put("domain", "section");
map.put("fieldList", "属性列表");
// 生成 controller
FreemarkerUtil.initConfig("controller");
FreemarkerUtil.generator(map, toControllerPath + bigDoMain + "Controller.java");
}
上例只是演示流程,具体的还需要补充,如 属性列表
,就需要连接数据库获取,这样才能获取到数据库的属性,然后转化为 Java 对应的类型。
生成数据传输对象
数据传输对象即 Dto:Data Transaction Object
。
他是介于实体类与 Service 中的一种对象,由于实体类通常与数据库中的字段相关联,所以一般确定之后不容易变化,但是如果今后我们的业务有一个需求需要添加字段,我们就可以使用位于中间的 Dto 对象来做协调,所以 Dto 就是一个媒介作为中间层,它具有自由可变性。
为了能确定 Dto 的属性列表,我们需要从数据库读取到属性,所以要连接数据库,我们写一个工具类:
package com.lsu.generator.util;
import com.lsu.generator.enums.EnumGenerator;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 数据库字段工具类
*
* @Author wang suo
* @Date 2020/10/12 0012 22:16
* @Version 1.0
*/
public class DbUtil {
/**
* 正则表达式规则: 匹配: _字母
*/
private static final Pattern PATTERN = Pattern.compile("_(\\w)");
/**
* 获取数据库连接
*
* @return 返回连接对象
*/
private static Connection getConnection() {
Connection conn = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/online_course?useUnicode=false&characterEncoding=UTF8&serverTimezone=UTC";
String user = "root";
String password = "root";
conn = DriverManager.getConnection(url, user, password);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 获取表的中文名称
*
* @param tableName 表名
* @return 返回表的注释
*/
public static String getTableComment(String tableName) throws SQLException {
Connection conn = getConnection();
Statement state = conn.createStatement();
ResultSet res = state
.executeQuery("select table_comment from information_schema.TABLES where TABLE_NAME = '"
+ tableName + "';");
String tableNameCh = "";
while (res.next()) {
tableNameCh = res.getString("table_comment");
}
res.close();
state.close();
conn.close();
System.out.println("表名 = " + tableNameCh);
return tableNameCh;
}
/**
* 获取所有列信息
*
* @param tableName 表名
* @return 返回属性的Field集合
* @throws Exception 抛出异常
*/
public static List<Field> getColumnByTableName(String tableName) throws Exception {
List<Field> fieldList = new ArrayList<>();
Connection conn = getConnection();
Statement state = conn.createStatement();
ResultSet res = state.executeQuery("show full columns from " + tableName);
while (res.next()) {
String columnName = res.getString("Field");
String type = res.getString("Type");
String comment = res.getString("Comment");
String nullAble = res.getString("Null");
Field field = new Field();
field.setName(columnName);
field.setNameHump(lineToHump(columnName));
field.setNameBigHump(lineToBigHump(columnName));
field.setComment(comment);
field.setJavaType(sqlTypeToJavaType(type));
field.setType(type);
if (comment.contains("|")) {
field.setNameCn(comment.substring(0, comment.indexOf("|")));
} else {
field.setNameCn(comment);
}
field.setNullAble("YES".equals(nullAble));
if (type.toUpperCase().contains("VARCHAR")) {
String lengthStr = type.substring(type.indexOf("(") + 1, type.length() - 1);
field.setLength(Integer.valueOf(lengthStr));
} else {
field.setLength(0);
}
if (comment.contains("枚举")) {
field.setEnums(true);
// 以课程等级为例:从注释中的“枚举[CourseLevelEnum]”,得到COURSE_LEVEL
int start = comment.indexOf("[");
int end = comment.indexOf("]");
String enums = comment.substring(start + 1, end);
String enumsConst = EnumGenerator.toUnderline(enums);
field.setEnumsConst(enumsConst);
} else {
field.setEnums(false);
}
fieldList.add(field);
}
res.close();
state.close();
conn.close();
System.out.println("列信息 = " + fieldList);
return fieldList;
}
/**
* 下划线转小驼峰
*
* @param str 字符串
* @return 小驼峰
*/
private static String lineToHump(String str) {
Matcher matcher = PATTERN.matcher(str.toLowerCase());
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* 下划线转大驼峰
*
* @param str 字符串
* @return 大驼峰
*/
private static String lineToBigHump(String str) {
String s = lineToHump(str);
return s.substring(0, 1).toUpperCase() + s.substring(1);
}
/**
* 数据库类型转为 Java 类型
*
* @param sqlType 数据库类型
* @return 返回 Java 类型
*/
private static String sqlTypeToJavaType(String sqlType) {
final String varchar = "VARCHAR";
final String chr = "CHAR";
final String text = "TEXT";
final String datetime = "DATETIME";
final String integer = "INT";
final String aLong = "LONG";
final String decimal = "DECIMAL";
if (sqlType.toUpperCase().contains(varchar)
|| sqlType.toUpperCase().contains(chr)
|| sqlType.toUpperCase().contains(text)) {
return "String";
} else if (sqlType.toUpperCase().contains(datetime)) {
return "Date";
} else if (sqlType.toUpperCase().contains(integer)) {
return "Integer";
} else if (sqlType.toUpperCase().contains(aLong)) {
return "Long";
} else if (sqlType.toUpperCase().contains(decimal)) {
return "BigDecimal";
} else {
return "String";
}
}
}
这里涉及到两个 SQL:
# 根据表名获取表的注释信息
select table_comment
from information_schema.TABLES
where TABLE_NAME = 'chapter';
# 获取表的所有字段信息
show full columns from chapter;
为什么需要判断 | 符号呢?
因为我们的数据库定义的时候是这样的:
create table `section`
(
`id` char(8) not null default '' comment 'id',
`title` varchar(50) not null comment '标题',
`course_id` char(8) comment '课程|course.id',
`chapter_id` char(8) comment '大章|chapter.id',
`video` varchar(200) comment '视频',
`time` int comment '时长|单位秒',
`charge` char(1) comment '收费|C 收费;F 免费',
`sort` int comment '顺序',
`created_at` datetime(3) comment '创建时间',
`updated_at` datetime(3) comment '修改时间',
primary key (`id`)
) engine = innodb
default charset = utf8mb4 comment ='小节';
上述代码中的 Field
类如下:
package com.lsu.generator.util;
import lombok.Data;
import lombok.ToString;
/**
* 属性
*
* @Author wang suo
* @Date 2020/10/12 0012 22:03
* @Version 1.0
*/
@Data
@ToString
public class Field {
/**
* 字段名;
* 字段名小驼峰;
* 字段名大驼峰;
* 中文名;
* 字段类型;
* java类型;
* 注释;
* 是否可为空;
* 字符串长度;
* 是否是枚举;
* 枚举常量 COURSE_LEVEL;
*/
private String name;
private String nameHump;
private String nameBigHump;
private String nameCn;
private String type;
private String javaType;
private String comment;
private Boolean nullAble;
private Integer length;
private Boolean enums;
private String enumsConst;
}
最后我们的启动类就可以这样写:
package com.lsu.generator.server;
import com.lsu.generator.util.DbUtil;
import com.lsu.generator.util.Field;
import com.lsu.generator.util.FreemarkerUtil;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.*;
/**
* 代码生成
*
* @Author wang suo
* @Date 2020/10/12 0012 18:35
* @Version 1.0
*/
public class ServerGenerator {
private static String MODULE = "business";
private static String toServicePath = "server\\src\\main\\java\\com\\lsu\\server\\service\\";
private static String toDtoPath = "server\\src\\main\\java\\com\\lsu\\server\\dto\\";
private static String toControllerPath = MODULE + "\\src\\main\\java\\com\\lsu\\" + MODULE + "\\controller\\admin\\";
private static String generatorPath = "server\\src\\main\\resources\\generator\\generatorConfig.xml";
public static void main(String[] args) throws Exception {
String module = MODULE;
/*
读 generatorConfig.xml
*/
File file = new File(generatorPath);
SAXReader reader = new SAXReader();
Document dom = reader.read(file);
/*
获取文件的根节点
*/
Element rootElement = dom.getRootElement();
Element contextElement = rootElement.element("context");
/*
获取第一个 table 节点
*/
Element tableElement = contextElement.elementIterator("table").next();
/*
获得大驼峰类名
*/
String bigDoMain = tableElement.attributeValue("domainObjectName");
/*
获取小驼峰类名
*/
String domain = bigDoMain.substring(0, 1).toLowerCase() + bigDoMain.substring(1);
/*
获取表名
*/
String tableName = tableElement.attributeValue("tableName");
/*
获取表的中文名: 备注名
*/
String tableNameCn = DbUtil.getTableComment(tableName);
/*
将表名打印到控制台
*/
System.out.println("表名 = " + tableName);
System.out.println("Domain = " + bigDoMain);
/*
获取数据库表的属性列表
*/
List<Field> fieldList = DbUtil.getColumnByTableName(tableName);
/*
获取要导入的Java包
*/
Set<String> typeSet = getJavaTypes(fieldList);
/*
放到 Map 集合中供 freemarker 使用
*/
Map<String, Object> map = new HashMap<>(10);
map.put("Domain", bigDoMain);
map.put("domain", domain);
map.put("tableNameCn", tableNameCn);
map.put("module", module);
map.put("fieldList", fieldList);
map.put("typeSet", typeSet);
// 生成 dto
FreemarkerUtil.initConfig("dto");
FreemarkerUtil.generator(map, toDtoPath + bigDoMain + "Dto.java");
// 生成 service
FreemarkerUtil.initConfig("service");
FreemarkerUtil.generator(map, toServicePath + bigDoMain + "Service.java");
// 生成 controller
FreemarkerUtil.initConfig("controller");
FreemarkerUtil.generator(map, toControllerPath + bigDoMain + "Controller.java");
}
private static Set<String> getJavaTypes(List<Field> fieldList) {
Set<String> set = new HashSet<>();
for (Field field : fieldList) {
set.add(field.getJavaType());
}
return set;
}
}
其中的 generatorConfig.xml
是 mybatis-generator
的配置文件,这里使用 Dom4j 自动读取了从而获取表名,你也可以不获取,自己手动写。
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="Mysql" targetRuntime="MyBatis3" defaultModelType="flat">
<property name="autoDelimitKeywords" value="true"/>
<!-- 反引号:如果表名或字段名是 MySQL 的关键字就自动加上反引号 -->
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!-- 覆盖生成XML文件 -->
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
<!-- 生成的实体类添加 toString() 方法 -->
<plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
<!-- 不生成注释: 因为注释是英文 -->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/online_course?serverTimezone=UTC"
userId="root"
password="root">
</jdbcConnection>
<!-- domain类的位置 -->
<javaModelGenerator targetProject="src\main\java"
targetPackage="com.lsu.server.domain"/>
<!-- mapper xml的位置 -->
<sqlMapGenerator targetProject="src\main\resources"
targetPackage="mapper"/>
<!-- mapper类的位置 -->
<javaClientGenerator targetProject="src\main\java"
targetPackage="com.lsu.server.mapper"
type="XMLMAPPER" />
<!-- <table tableName="test" domainObjectName="Test"/>-->
<!-- <table tableName="chapter" domainObjectName="Chapter"/>-->
<table tableName="section" domainObjectName="Section"/>
<!-- <table tableName="course" domainObjectName="Course"/>-->
<!-- <table tableName="course_content" domainObjectName="CourseContent"/>-->
<!-- <table tableName="course_content_file" domainObjectName="CourseContentFile"/>-->
<!-- <table tableName="teacher" domainObjectName="Teacher"/>-->
<!-- <table tableName="file" domainObjectName="File"/>-->
<!-- <table tableName="user" domainObjectName="User"/>-->
<!-- <table tableName="resource" domainObjectName="Resource"/>-->
<!-- <table tableName="role" domainObjectName="Role"/>-->
<!-- <table tableName="role_resource" domainObjectName="RoleResource"/>-->
<!-- <table tableName="role_user" domainObjectName="RoleUser"/>-->
<!-- <table tableName="member" domainObjectName="Member"/>-->
<!-- <table tableName="sms" domainObjectName="Sms"/>-->
<!-- <table tableName="member_course" domainObjectName="MemberCourse"/>-->
</context>
<!-- mybatis-generator:generate -e 生成代码命令-->
</generatorConfiguration>
配合 mybatis-generator
使用就可以从持久层到控制层的代码一套打通了。
生成 Vue 代码
生成 vue 的模板文件:
<template>
<div>
<p>
<button @click="add" class="btn btn-white btn-default btn-round">
<i class="ace-icon fa fa-edit red2"></i>新增
</button>
<button @click="getAll(1)" class="btn btn-white btn-default btn-round">
<i class="ace-icon fa fa-refresh red2"></i>刷新
</button>
</p>
<table id="simple-table" class="table table-bordered table-hover">
<thead>
<tr>
<#list fieldList as field>
<th>${field.nameCn}</th>
</#list>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="${domain} in ${domain}s">
<#list fieldList as field>
<td>{{${domain}.${field.nameHump}}}</td>
</#list>
<td>
<div class="hidden-sm hidden-xs btn-group">
<button @click="edit(${domain})" class="btn btn-xs btn-info">
<i class="ace-icon fa fa-pencil bigger-120"></i>
</button>
<button @click="del(${domain}.id)" class="btn btn-xs btn-danger">
<i class="ace-icon fa fa-trash-o bigger-120"></i>
</button>
</div>
</td>
</tr>
</tbody>
</table>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">表单</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<#list fieldList as field>
<div class="form-group">
<label for="${field.nameHump}" class="col-sm-2 control-label">${field.nameCn}</label>
<div class="col-sm-10">
<input v-model="${domain}.${field.nameHump}" id="${field.nameHump}" class="form-control">
</div>
</div>
</#list>
</form>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button @click="save" type="button" class="btn btn-primary">保存</button>
</div>
</div>
</div>
</div>
</div>
<!--
:list="getAll"
list: 是子组件暴露出来的一个回调方法;
getAll: 是父组件的 getAll 方法;
-->
<pagination ref="pagination" :list="getAll" :itemCount="8"/>
</div>
</template>
<script>
import Pagination from '../../components/pagination'
export default {
name: "${domain}",
components: {
Pagination,
},
data() {
return {
${domain}s: [],
${domain}: {
<#list fieldList as field>
${field.nameHump}: '',
</#list>
},
}
},
created() {
},
mounted() {
let _this = this;
_this.$refs.pagination.size = 10;
_this.getAll(1);
},
methods: {
getAll(page) {
let _this = this;
Loading.show();
_this.$ajax.post(process.env.VUE_APP_SERVER + '/${module}/admin/${domain}/list', {
page: page,
size: _this.$refs.pagination.size,
}).then(response => {
Loading.hide();
let resp = response.data;
_this.${domain}s = resp.content.list;
// 渲染子组件
_this.$refs.pagination.render(page, resp.content.total);
})
},
add() {
let _this = this;
_this.${domain} = {};
$("#myModal").modal("show");
},
save() {
let _this = this;
// 保存校验
if (1 !== 1
<#list fieldList as field>
<#if !field.nullAble>
|| !Validator.require(_this.${domain}.${field.nameHump}, "${field.nameCn}")
</#if>
<#if (field.length > 0)>
|| !Validator.length(_this.${domain}.${field.nameHump}, "${field.nameCn}", 1, ${field.length})
</#if>
</#list>
) {return;}
Loading.show();
_this.$ajax.post(process.env.VUE_APP_SERVER + '/${module}/admin/${domain}/save',
_this.${domain}).then(response => {
Loading.hide();
let resp = response.data;
if (resp.success) {
$("#myModal").modal("hide");
_this.getAll(1);
Toast.success("保存成功");
}
})
},
edit(${domain}) {
let _this = this;
// 双向绑定问题: 输入的时候表格也会更新数据: 使用 JQuery 的函数解决问题
_this.${domain} = $.extend({}, ${domain});
$("#myModal").modal("show");
},
del(id) {
let _this = this;
Confirm.show("该操作不可逆转", function () {
Loading.show();
_this.$ajax.delete(process.env.VUE_APP_SERVER + '/${module}/admin/${domain}/delete/' + id).then(response => {
Loading.hide();
let resp = response.data;
if (resp.success) {
_this.getAll(1);
Toast.success("删除成功");
}
});
});
}
}
}
</script>
<style scoped>
</style>
启动类:
package com.lsu.generator.vue;
import com.lsu.generator.util.DbUtil;
import com.lsu.generator.util.Field;
import com.lsu.generator.util.FreemarkerUtil;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.*;
/**
* Vue 代码生成
*
* @Author wang suo
* @Date 2020/10/12 0012 18:35
* @Version 1.0
*/
public class VueGenerator {
private static String MODULE = "business";
private static String toVuePath = "admin\\src\\views\\admin\\";
private static String generatorPath = "server\\src\\main\\resources\\generator\\generatorConfig.xml";
public static void main(String[] args) throws Exception {
/*
读 generatorConfig.xml
*/
File file = new File(generatorPath);
SAXReader reader = new SAXReader();
Document dom = reader.read(file);
/*
获取文件的根节点
*/
Element rootElement = dom.getRootElement();
Element contextElement = rootElement.element("context");
/*
获取第一个 table 节点
*/
Element tableElement = contextElement.elementIterator("table").next();
/*
获得大驼峰类名
*/
String bigDoMain = tableElement.attributeValue("domainObjectName");
/*
获取小驼峰类名
*/
String domain = bigDoMain.substring(0, 1).toLowerCase() + bigDoMain.substring(1);
/*
获取表名
*/
String tableName = tableElement.attributeValue("tableName");
/*
获取数据库表的属性列表
*/
List<Field> fieldList = DbUtil.getColumnByTableName(tableName);
/*
放到 Map 集合中供 freemarker 使用
*/
Map<String, Object> map = new HashMap<>(10);
map.put("domain", domain);
map.put("module", MODULE);
map.put("fieldList", fieldList);
// 生成 vue
FreemarkerUtil.initConfig("vue");
FreemarkerUtil.generator(map, toVuePath + domain + ".vue");
}
}
生成之后设置一下 router.js
即可看到效果。
更多推荐
所有评论(0)