如何根据数据库文件自动生成整个bean层与service层
来源:互联网 发布:詹姆斯退役数据预测 编辑:程序博客网 时间:2024/06/15 16:17
引言
来到公司的第一个任务是使用公司的框架leap(http://leapframework.org/ ORM层真的非常牛逼)进行项目开发,在这个框架中它规定了自己的javabean的注解(如使用@Id描述主键,用@Column描述字段),从而达到像hibernate中的那种持久化对象的功能,虽然ORM层是非常好用,但是写javabean和注解确实非常麻烦的一件事情(因为不是jpa规范,所有无法使用hibernate-tool)等工具来创建javabean,即使创建了普通的javabean,也要在字段上面写上注解,非常麻烦。那如何写一个工具来帮我们完成这些繁琐的操作呢?
设计思路
首先需要先对javabean进行抽象
数据库表名->类名数据库字段->类字段数据库类型->java类型数据库主键->需要做标志,使用特殊的注解//其他需要传入的参数类的包名生成的文件地址
有了上述的思路,那么就是说只要有
数据库文件一套javabean的模版
便能动态的来进行一个数据库到javabean的转换
技术选型
1.数据库访问
数据库访问方面直接使用JDBC,因为不会出现频率性的数据库访问,所以使用JDBC就够了,在这里我们需要收集的信息是
//数据库里面所有的表show tables;//根据表名,获取表里面的所有字段(包括字段类型,字段是否主键等信息)desc your_table_name;
2.创建模版与模版信息替换
在这里我曾经想过使用正则表达式来解决这个问题,自己定义自己的表达式进行替换,后面在收集想法时,发现一个牛逼的框架 freemarks 可以帮我解决这个问题。
你可以先看文档,也可以参考一下我对这个框架的理解再去看文档,
首先,先说一下freemarks这个框架设计出来的目的,其实他设计出来的目的是为了代替jsp这样的渲染引擎的。
jsp模版渲染引擎使用的思路大概是这样:
变化的值存进request,response,session,jsp引擎解析jsp文件里面的表达式,再去request,response,session取到相关表达的值构建整个页面,再输出到response里面给用户。整个流程都与request,response,session等对象结合在一起。
用过spring mvc 的你应该知道mvc的优点是他在control层用到一个model的对象去帮你封装你要传递给request的值,对用户抽象,让你感觉是
值->model->传递(request..)->jsp->动态页面
但其实底层还是用的request。
那么freemarks的出现就是为了解决这个问题,他提出的两个概念就是“模型”与“模版”。他提出这么一个流程
值->model->传递->模版->动态页面
可见的是它不依赖request等对象,完全封装了一套自己的东西。
freemarks 能不能替代jsp我不能断定,但是和我们的需求是非常切合的。
这个时候你就需要通读一下文档(其实跟El表达式差不多),准备开发。
3.文件存储
使用IO就能完成这个功能,但是我想玩得花一点,就使用了NIO,使用一个内存映射来完成整个功能。
实际开发
先发一下git地址,以防一些地方讲的不全https://git.oschina.net/jjtHappy/leap-tools
先从下往上讲
首先就是数据库链接,普通的JDBC链接不用介绍,取表名,根据表名取字段的sql已经讲了
主要是如何进行的操作
数据库表名->类名数据库字段->类字段数据库类型->java类型数据库主键->需要做标志,使用特殊的注解
首先,表名转类名,很简单,只是一个格式的转换
/** * * 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(); }
表字段转javabean同理,开头字母转小写就行了
数据库类型转java类型,其实也是一个很简单的操作
/** * 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; }
主要你可以了解一下mysql类型与java类型的对照表,写个switch就行了
为了方便,你可以写个javabean,在数据库取出时,就进行一个封装
public class Field { private String tableField;//数据库字段名 private String tableType;//数据库类型 private String tableKey;//索引类型 private String javaField;//java字段名 private String javaType;//java类型 ....}
这里如何判断是否是主键,只要判断索引类型有没有带“PRI”字段即可
封装一个好用的dao层是对上层是非常方便的,具体代码可以查看SimpleDao
解决了数据获取问题,接下来就是解决模版问题,这个就是看你对javabean的抽象了,当你看完文档后你可以看看我写的模版(结合了框架的一些内容)
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>}
可以看模版非常简单,要求的数据模型只是
包名导入的包数据库表名实体名(就是表名的驼峰转化)上述封装的域列表(用freemarks表达式进行遍历)
这里需要注意的点是,如何决定导入的包,所以你需要考虑几个点
1.根据java类型寻找包,并获取包名2.包名不能重复
所以有了这个想法,可以通过下面的方法实现
/** * * 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; }
完成了模版设计,就是模型的构建与传递了,传递过程都是按着freemarks的来,再使用NIO进行文件创建
主要关键的方法如下:
/** * * 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(); }
详细可参照代码。
这样的一个思路便可以让你完成整个dao层的创建
按着这个思路你可以完成整个service层的创建
以下是我写的工具的生成结果
- 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
你说这篇文章给不了你干货,但真正的干货我就不信能在一篇文章中看出来的。老老实实看文档,根据本文给出的思路,一步一步才能创建自己的一个基础代码撰写工具,有了这个工具至少提高了10%的工作效率。
后面看了一些hibernate-tools的源码…发现…它用的也是freemarks,但是讲述代码生成的文章还比较少,所以做个笔记。
- 如何根据数据库文件自动生成整个bean层与service层
- 自动生成bean层dao层以及xml层工具
- 自动生成MVC中的Service层、Dao层及Model层
- 自动生成MVC中的Service层、Dao层及Model层
- DAO层与Service层区别?
- S2SH合并DAO层与service层
- 如何自动生成Jni的Java层调C++层的头文件
- Mybatis中根据数据库表结构自动生成dao层等代码的工具及其步骤
- service层
- 配置Spring,针对Service层的bean做事务处理
- dao层与service层傻傻分不清楚
- 如何写一个native层的service
- 如何在App层添加System Service
- 如何在iframe内部弹出浮层,浮层遮罩整个浏览器
- .NET中数据层自动生成工具
- .NET中数据层自动生成工具
- php 数据层自动生成类
- VB FSO自动生成N层目录!
- MySQL 5.7搭建备库 开启gtid 使用mysqldump
- POJ 2104 -- K-th Number (分桶法和平方分割)
- offsetTop-clientTop-scrollTop-各属性介绍
- Advice for New Graduate Students
- bat 2018自然语言处理校园招聘的要求
- 如何根据数据库文件自动生成整个bean层与service层
- learning
- 安装oracle问题总结
- mybatis的逆向工程一
- Eclipse 代码补全设置
- 2017年8月11日训练日记
- 协同过滤推荐算法的原理及实现
- 英语学习而得不到想要的结果思考
- [CODEVS4605]LCA