代码生成器——实现生成pojo,sql,mapper接口
代码生成器(记录一次兴趣代码,多多指教。转载请标明作者)
在我们开始实现代码生成器之前我们先来对代码生成器有一个简单的了解。
1.什么是代码生成器?
故名思义,也就是生成代码的一个程序。那它是一个什么样的机制?怎么体现这种机制?
比如:
我们学习的 JSP 技术,浏览器并不能直接识别 JSP 文件。当用户通过浏览器访问某个 JSP 页
面的时候,其中的交互分为分为几个步骤:
用户通过浏览器访问 JSP 页面
Tomcat 找到对应 JSP 资源,将 JSP 资源转化(编译,翻译)成为 HTML 数据
Tomcat 将 HTML 数据进行返回
在此,我们就可以这样理解
我们所编写 JSP ===》 HTML 的模板。
JSP 页面的标签 ===》模板中的占位符。
Tomcat 根据 JSP 模板,生成 HTML 页面。 数据库的数据不同,则生成的 HTML 页面也不同。
最后我们得出一个结论:
Tomcat 可以根据 JSP 模板和数据生成不同的 HTML 页面。
所以 Tomcat 对 JSP 的处理过程我们就可以认为是一个代码生成器的机制,其实也就是代码生成器的原理。
2.我们为什么要编写代码生成器?
我们先不说它在我们软件之中处处可见,单单就作为一个程序员的辅助工具而言,也是极大的提高了开发效率。
比如我们的实体类,一个项目中表的数量不会少于二三十个吧,倘若每一个实体类,都手动编写,这种重复的代码编写,嗯,作为程序员应该都懂得。
所以,代码生成器节省人力成本,提高了开发效率。
3.开始编写代码生成器。
前面铺垫了那么多,干货终于要来了。
3.1 编写工具:idea
3.2 依赖模板引擎: FreeMarker(FreeMarker 所需要的功能简介:请点击我的另一篇博客 FreeMarker)
maven依赖freemarker jar
<!-- https://mvnrepository.com/artifact/freemarker/freemarker -->
<dependency>
<groupId>freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.8</version>
</dependency>
3.3 代码体系组成:
- 模板:生成文件的模板文件。
- 数据:生成文件所需要的关键数据。
- 合成机制:使用数据置换模板中的占位符,生成新的文件的机制。


3.4 所有实现代码
---------存放数据的对象
package cn.itrip.vo; /**
* 列对象
*/
public class ColumnVo {
private String name;//数据库中的列名
private String fieldName;//对应的Java属性名 private String dbType;//数据中的记录类型
private String javaType;//对应的Java属性类型 private String comment;//数据库中的注释
private String upperCaseColumnName;//转成帕斯卡后的属性名 public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getFieldName() {
return fieldName;
} public void setFieldName(String fieldName) {
this.fieldName = fieldName;
} public String getDbType() {
return dbType;
} public void setDbType(String dbType) {
this.dbType = dbType;
} public String getJavaType() {
return javaType;
} public void setJavaType(String javaType) {
this.javaType = javaType;
} public String getComment() {
return comment;
} public void setComment(String comment) {
this.comment = comment;
} public String getUpperCaseColumnName() {
return upperCaseColumnName;
} public void setUpperCaseColumnName(String upperCaseColumnName) {
this.upperCaseColumnName = upperCaseColumnName;
}
}
package cn.itrip.vo; import java.util.ArrayList;
import java.util.List; /**
* 表对象
*/
public class TableVo {
private String className;//帕斯卡风格的类名
private String tableName;//表名
private String comment;//注释
private String lowerClassName;//骆驼命名法 private List<ColumnVo> columns=new ArrayList<ColumnVo>();//列对象集合 public String getLowerClassName() {
return lowerClassName;
} public void setLowerClassName(String lowerClassName) {
this.lowerClassName = lowerClassName;
} public String getClassName() {
return className;
} public void setClassName(String className) {
this.className = className;
} public String getTableName() {
return tableName;
} public void setTableName(String tableName) {
this.tableName = tableName;
} public String getComment() {
return comment;
} public void setComment(String comment) {
this.comment = comment;
} public List<ColumnVo> getColumns() {
return columns;
} public void setColumns(List<ColumnVo> columns) {
this.columns = columns;
}
}
--------------帮助类
package cn.itrip.util; /**
* 命名转换工具类
*/
public class JavaNameUtil {
public static String translate(String underscoreName,boolean isPascal){
StringBuilder result = new StringBuilder();//返回字符结果
if(underscoreName!=null && underscoreName.length()>0){
boolean flag=false;
char firstChar =underscoreName.charAt(0);//判断获取首字母
if(isPascal){
result.append(Character.toUpperCase(firstChar));//将首字母转换成大写
}else{
result.append(firstChar);
}
//从第二个字符开始循环
for (int i=1;i<underscoreName.length();i++){
char ch=underscoreName.charAt(i);
//判断是否出现下划线
if('_'==ch){
flag=true;
}else {
if(flag){
result.append(Character.toUpperCase(ch));
flag=false;
}else {
result.append(ch);
}
}
}
}
return result.toString();//返回转换字符
} /**
* 骆驼命名法
* @param str
* @return
*/
public static String toCamel(String str){
return translate(str,false);
} /**
* 帕斯卡命名法
* @param str
* @return
*/
public static String toPascal(String str){
return translate(str,true);
} /**
* 转换数据类型
* @param dbTypeName
* @return
*/
public static String dbtype2JavaType(String dbTypeName){
String javaType=null;
switch (dbTypeName){
case "VARCHAR":javaType="String";break;
case "BIGINT":javaType="Long";break;
case "INT":javaType="Integer";break;
case "DATETIME":javaType="Date";break;
default: javaType="String";break;
}
return javaType;
} public static void main(String[] arg){
String testName =toCamel("user_liu_jh");
System.out.println(testName);
String testName2=toPascal("user_liu_jh");
System.out.println(testName2);
}
}
package cn.itrip.util; import java.sql.*;
import java.util.ArrayList;
import java.util.List; /**
* 负责连接数据库、获取表的元信息、列的元信息
*/
public class MetadataUtil {
private static Connection conn;//连接对象 /*2. DatabaseMetaData接口常用的方法:获取数据库元数据
(1) ResultSet getTables(String catalog,String schemaPattern,String tableNamePattern,String[] types); //获取表信息
(2) ResultSet getPrimaryKeys(String catalog,String schema,String table); //获取表主键信息
(3) ResultSet getIndexInfo(String catalog,String schema,String table,boolean unique,boolean approximate); //获取表索引信息
(4) ResultSet getColumns(String catalog,String schemaPattern,String tableNamePattern,String columnNamePattern); //获取表列信息*/
private static DatabaseMetaData meta; static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("数据库连接失败!");
}
} /**
* 连接数据库获取数据库元数据
*/
public static void openConnection() {
try {
if (conn == null || conn.isClosed()) {//isClosed:判断连接是否关闭
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/XXX?useUnicode=true&characterEncoding=utf-8"
, "XXX", "XXX");//连接数据库 XXX表示你自己的数据库名称 、用户名、密码
meta = conn.getMetaData();//获取元数据
}
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* 获取表的注释
* @param
* @return
*/
public static String getCommentByTableName(String tableName) throws SQLException {
openConnection();//打开连接
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SHOW CREATE TABLE " + tableName);
String comment = null;
if (rs != null && rs.next()) {
comment=rs.getString(2);
//判断字符,只获取注解部分
int index = comment.lastIndexOf("=");
comment = comment.substring(index+1);
}
rs.close();
stmt.close();
conn.close();
return comment;
} /**
* 获取所有的表名
* @return
*/
public static String[] getTableNames(){
openConnection();
ResultSet rs=null;
List<String> nameList = new ArrayList<>();
try{
rs=meta.getTables(null,
null,
null,
new String[]{"TABLE"});
while (rs.next()){
String tName =rs.getString("TABLE_NAME");
nameList.add(tName);//将取出来的表名放入集合中
}
}catch (SQLException e){
e.printStackTrace();
}
return (String[])nameList.toArray(new String[]{});
} /**
* 获取某个表中所有的列信息
* @param tableName
* @return
* @throws Exception
*/
public static List<String[]> getTableColumnsInfo(String tableName)throws Exception{
openConnection();
ResultSet rs= meta.getColumns(null,
"%",tableName,"%");
List<String[]> columnInfoList =new ArrayList<>();
while (rs.next()){
String[] colInfo = new String[3];
colInfo[0]=rs.getString("COLUMN_NAME");//COLUMN_NAME 列名
colInfo[1]=rs.getString("REMARKS");//REMARKS 获取列注释
colInfo[2]=rs.getString("TYPE_NAME");//TYPE_NAME 列类型
columnInfoList.add(colInfo);
}
return columnInfoList;
}
}
---------合成机制
package cn.itrip.generator; import cn.itrip.util.JavaNameUtil;
import cn.itrip.util.MetadataUtil;
import cn.itrip.vo.ColumnVo;
import cn.itrip.vo.TableVo;
import freemarker.template.Configuration;
import freemarker.template.Template; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* 抽象生成器
*/
public abstract class AbstractGenerator {
protected Configuration cfg;//Freemarker配置对象
protected Map valueMap;//填充到模板的数据
protected Template template;//模板对象
protected String savePath;//保存生成文件的路径
protected List<TableVo> tableList;//表信息 public AbstractGenerator() throws Exception {
cfg = new Configuration();
cfg.setClassForTemplateLoading(this.getClass(), "/templates/"); //获取模板文件位置
valueMap = new HashMap();
init();//初始化数据
} /**
* 获取所有的表信息列信息
* @throws Exception
*/
public void init()throws Exception{
tableList=new ArrayList<>();
String[] tableNameArr =MetadataUtil.getTableNames();//获取表名称
for(String tName:tableNameArr){
String tComment = MetadataUtil.getCommentByTableName(tName);//获取注释
TableVo table = new TableVo();//创建表信息对象
table.setClassName(JavaNameUtil.toPascal(tName));
table.setComment(tComment);
table.setTableName(tName);
List<String[]> colInfoList =MetadataUtil.getTableColumnsInfo(tName);
for (String[] colInfo:colInfoList){
String cName =colInfo[0];
String cComment =colInfo[1];
String cType =colInfo[2];
ColumnVo column = new ColumnVo();
column.setComment(cComment);
column.setName(cName);
column.setFieldName(JavaNameUtil.toCamel(cName));
column.setDbType(cType);
column.setJavaType(JavaNameUtil.dbtype2JavaType(cType));
column.setUpperCaseColumnName(JavaNameUtil.toPascal(cName));
table.getColumns().add(column);
}
tableList.add(table);
System.out.println(table);
}
System.out.println("构建元数据成功!");
} //抽象生成代码文件,各个子类实现
public abstract void generateCode() throws Exception; public void setSavePath(String savePath) {
this.savePath = savePath;
}
}
package cn.itrip.generator; import cn.itrip.vo.TableVo;
import freemarker.template.TemplateException; import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter; /**
* 实体类生成器
*/
public class EntityGenerator extends AbstractGenerator{ public EntityGenerator(String ftl) throws Exception {
try{
this.savePath="D:\\object\\itripljh\\itripbeans\\src\\main\\java\\cn\\itrip\\pojo";
//加载freemarker模板文件
super.template = cfg.getTemplate(ftl);
}catch (IOException e){
e.printStackTrace();
}
}
public void generateCode() throws Exception {
System.out.println("---------------开始生成代码");
valueMap.put("package","cn.itrip");//自定义包的位置
OutputStreamWriter writer=null;
for(TableVo table:tableList) {
valueMap.put("table",table);
try{
//创建一个写入器
writer = new FileWriter(savePath+"/"+table.getClassName()+".java");//根据不同的文件自行修改
//合成数据和模板,写入到文件
this.template.process(valueMap,writer);
writer.flush();
}catch (TemplateException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}finally {
writer.close();
}
}
System.out.println("生成代码成功!");
}
}
----------------模板文件(pojo.ftl)
package ${package}.pojo;
import java.io.Serializable;
import java.util.Date;
/**
* ${table.comment}
*/
public class ${table.className} implements Serializable{
//生成私有属性
<#list table.columns as col>
//${col.comment}
private ${col.javaType} ${col.fieldName};
</#list>
//生成getter、setter方法
<#list table.columns as col>
public void set${col.upperCaseColumnName} (${col.javaType} ${col.fieldName}){
this.${col.fieldName} =${col.fieldName};
}
public ${col.javaType} get${col.upperCaseColumnName} (){
return this.${col.fieldName};
}
</#list>
}
---------------入口
package cn.itrip;
import cn.itrip.generator.EntityGenerator;public class App {
public static void main(String[] args)throws Exception{
System.out.println("开始启动---------------");
String path=App.class.getClassLoader().getResource("").getPath();
System.out.println(path);
EntityGenerator generator =new EntityGenerator("pojo.ftl");
try {
generator.setSavePath("D:\\object\\itripljh\\itripbeans\\src\\main\\java\\pojo2");
generator.generateCode();
}catch (Exception e){
e.printStackTrace();
}
}
-----------最后执行的结果如下

完成。
代码生成器——实现生成pojo,sql,mapper接口的更多相关文章
- MyBatis-使用mybatis-generator-core.jar生成POJO和Mapper文件
Demo: http://pan.baidu.com/s/1pLeyVv9 1.pom.xml <dependencies> <!-- 用于生成日志 --> <depen ...
- Mybatis逆向工程生成po、mapper接口、mapper.xml
Mybatis逆向工程生成po.mapper接口.mapper.xml 一.新建一个maven工程 请查看我的另一篇博客:<使用idea创建一个maven工程> 二.引入所需依赖 需要my ...
- MyBatis逆向工程生成配置 generator (生成pojo、mapper.xml、mapper.java)
MyBatis逆向工程生成 mybatis需要程序员自己编写sql语句,mybatis官方提供逆向工程,可以针对单表自动生成mybatis执行所需要的代码(mapper.java.mapper.xml ...
- mybatis如何根据mapper接口生成其实现类
SpringBoot集成mybatis mybatis的statement的解析与加载 mybatis如何根据mapper接口生成其实现类 mybatis的mapper返回map结果集 mybatis ...
- mybatis如何根据mapper接口生成其实现类(springboot)
序 mybatis里头给sqlSession指定执行哪条sql的时候,有两种方式,一种是写mapper的xml的namespace+statementId,如下: public Student fin ...
- Mybatis在IDEA中使用generator逆向工程生成pojo,mapper
使用mybatis可以逆向生成pojo和mapper文件有很多种方式,我以前用的是mybtais自带的generator包来生成,连接如下:mybatis自己生成pojo 今天我用了IDEA上使用ma ...
- 使用maven的mybatis-generator代码生成器插件生成实体类、mapper配置文件和mapper接口(使用idea)
接着之前创建的ssmMaven项目 一: 在pom文件中加入mybatis-generator插件 <plugins> <plugin> <groupId>org. ...
- 5.7 Liquibase:与具体数据库独立的追踪、管理和应用数据库Scheme变化的工具。-mybatis-generator将数据库表反向生成对应的实体类及基于mybatis的mapper接口和xml映射文件(类似代码生成器)
一. liquibase 使用说明 功能概述:通过xml文件规范化维护数据库表结构及初始化数据. 1.配置不同环境下的数据库信息 (1)创建不同环境的数据库. (2)在resource/liquiba ...
- java web(七): mybatis的动态sql和mybatis generator自动生成pojo类和映射文件
前言: MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据 不同条件拼接 SQL 语句的痛苦.例如拼接时要确保不能忘记添加必要的空格,还 ...
随机推荐
- C#博客目录
基础加强 1.索引器 2.密闭类.静态类及扩展方法 3.值.引用类型及结构体 4.秒懂IL.CTS.CLS和CLR 5.装箱与拆箱 6.引用相等与运算符重载 7.ref与out 8.委托和事件 9.对 ...
- MVC模式笔记
参见:https://martinfowler.com/eaaCatalog/modelViewController.html 企业应用架构模式(P of EAA)第14章Web表现模式第一节MVC笔 ...
- C++生成GUID
#include <objbase.h> #include <stdio.h> //--生成GUID const char* newGUID() { ] = {}; GUID ...
- Qt QDateEdit QDateTimeEdit
展示一个效果,然后附上一个“笑话~~”...回想起来都是搞笑的. 笑话来了,,,,几个月前,为了做出时间选择界面,我亲自“创造”了一个...今天发现了QDateEdit的属性CalendarPopup ...
- 001-ADO.NET
Web.config <connectionStrings> <add name="connStr" connectionString="server= ...
- CSS之CSS的三种基本的定位机制(普通流,定位,浮动)
一.普通流 普通流中元素框的位置由元素在XHTML中的位置决定.块级元素从上到下依次排列,框之间的垂直距离由框的垂直margin计算得到.行内元素在一行中水平布置. 普通流就是html文档中的元素如块 ...
- CentOS 7 Sersync+Rsync 实现数据文件实时同步
rsync+inotify-tools与rsync+sersync架构的区别? 1.rsync+inotify-tools inotify只能记录下被监听的目录发生了变化(增,删,改)并没有把具体是哪 ...
- CentOS 7 zabbix添加监控服务器
CentOS 7 yum安装zabbix 设置中文界面 安装环境 CentOS 7 关闭防火墙和SElinux 在被监控端安装zabbix-agent [root@zabbix-agent ~]# ...
- sedlauncher.exe
这个进程很恐怖,屁大点的东西,但会造成磁盘爆满. 首先,这个99%不是病毒,而是win10更新后出现的东西. 关于解释,国内乱七八糟的,我没有搜到,只好在狗哥和微软官网搜了一下. 大多说是 KB402 ...
- 常用MSSQL语句
现在很少用SQL 写东西,但有时真用起来半天想不起来,看来还是有必要记录一下... 新建表: create table [表名] ( [自动编号字段] int IDENTITY (1,1) PRIMA ...