根据mybatis/ibatis sqlmapper文件解析生成数据库表

[size=small][color=blue][b]有一份应用完整的源码,不过就是缺少了表结构,如果让我根据DO对象一个个去慢慢创建,也是个让人头痛的问题,一是因为有几十个表,二是这个东西拷贝粘贴一点技术含量都没有,这真不是我愿意干的活。本来是想在网上搜索一份这样的工具,关键字到是用了一大堆,中文英文都试过了,如“如何根据SqlMap创建表结构”、"How to generate table from sqlmap"等,还是木有找到,毕竟有几个是像我这样有对象源码却木有表结构的,于是就打算自己搞定了。
幸好我对这份应用本身还是比较熟悉,知道用的是什么样的数据库,文件的命名风格是怎么样的等,想来根据对象生成表结构应该不是什么验事。刚开始想的方式是根据DO对象来生成,后来根据找到的MYSQL字段类型与JAVA对象的映射一看,发现一对多的情况有不少,觉得这种不靠谱,于是就放弃这种方案;后面发现SQLMPA配置文件中有对象与字段的映射,这个倒是省事了,直接分析这个文件就OK了,于是乎就有了下面这些代码:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;

/**
* 根据Ibatis的SqlMap配置文件,重新生成表结构。<br>
* 要求所有的sqlmap中对应的字段都有jdbcType这个属性。
*
* @author Administrator 2012-7-2 下午09:33:07
*/
public class Sqlmap2Table {

// 默认所有的varchar都是512,可以保证满足绝大多数的字段
private static final String DEFAULT_VARCHAR_LENGTH = "VARCHAR(256)";

public static void main(String[] args) throws JDOMException, IOException {
String sqlMapPath = "I:/Site/proc/xxx_trunk/dal/src/conf";//这里指定你的sqlmap配置文件所在路径
analysis(sqlMapPath);
}

/**
* 根据指定的目录进行遍历分析
*
* @param path
* @throws IOException
* @throws JDOMException
*/
private static void analysis(String path) throws IOException, JDOMException {
File filePath = new File(path);
if (filePath.isDirectory() && !filePath.getName().equals(".svn")) {
File[] fileList = filePath.listFiles();
for (File file : fileList) {
if (file.isDirectory()) {
analysis(file.getAbsolutePath());
} else {
analysisSqlMap(file.getAbsolutePath());
}
}
}
}

/**
* 分析单个的sqlmap配置文件
*
* @param sqlMapFile
* @throws IOException
* @throws JDOMException
*/
private static void analysisSqlMap(String sqlMapFile) throws IOException, JDOMException {
// System.out.println("************"+sqlMapFile);
boolean isNull=false;
/**
* 这里要把sqlmap文件中的这一行去掉:<br>
* <!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd"><br>
* 否则JDom根据文件创建Document对象时,会报找不到www.ibatis.com这个异常,导致渲染不成功。
*/
String xmlString = filterRead(sqlMapFile, "<!DOCTYPE");
Document doc = getDocument(xmlString);
List<Element> resultMap = (List<Element>) XPath.selectNodes(doc, "//resultMap");
for (Element e : resultMap) {
String alias = e.getAttributeValue("type");
String tableName = getTableName(doc, alias);
List<Element> children = e.getChildren();
StringBuilder createTableString = new StringBuilder("create table " + tableName + "(\n\t");
int size = 0;
for (Element child : children) {
String jdbcType = child.getAttributeValue("jdbcType");
if(StringUtils.isEmpty(jdbcType)){
isNull=true;
break;
}
if (jdbcType.toUpperCase().equals("VARCHAR")) {
jdbcType = DEFAULT_VARCHAR_LENGTH;
}
else if (jdbcType.toUpperCase().equals("CHAR")) {
jdbcType = "char(10)";
}
else if (jdbcType.toUpperCase().equals("BIGINT")) {
jdbcType = "bigint(20)";
}
if (jdbcType.toUpperCase().equals("INTEGER")) {
jdbcType = "int(11)";
}
else if (jdbcType.toUpperCase().equals("DECIMAL")) {
jdbcType = "decimal(10,2)";
}
else if (jdbcType.toUpperCase().equals("NUMERIC")) {
jdbcType = "decimal(10,2)";
}
if (jdbcType.toUpperCase().equals("DOUBLE")) {
jdbcType = "double";
}
if (jdbcType.toUpperCase().equals("REAL")) {
jdbcType = "double";
}

if (jdbcType.toUpperCase().equals("BOOLEAN")) {
jdbcType = "tinyint(1)";
}
if (jdbcType.toUpperCase().equals("FLOAT")) {
jdbcType = "float";
}

createTableString.append(child.getAttributeValue("column")).append(" ").append(jdbcType);
if (size < children.size() - 1) {
createTableString.append(",\n\t");

} else {
createTableString.append("\n");
}
size++;
}
if(isNull){
break;
}
createTableString.append(");");
System.out.println(createTableString.toString().toUpperCase());
}
}

private static String getTableName(Document doc, String alias) throws JDOMException {
String tableName = "";
String classPath = null;
// 这里的alias可能是一个别名,也可能是一个java类路径,这里我通过该alias是否有点"."这个符号来区别
if (alias.indexOf(".") > 0) {// 是JAVA类
classPath = alias;
} else {// 是别名,就到配置的别名中去找
Element aliasElement = (Element) XPath.selectSingleNode(doc, "//typeAlias[@alias=\"" + alias + "\"]");
classPath = aliasElement.getAttributeValue("type");
}
String[] classPathArray = classPath.split("\\.");
// 取到DO的名称
classPath = classPathArray[classPathArray.length - 1];
int i = classPath.lastIndexOf("DO");
// 取到根据表名生成的DO名称,无“DO”两个字符
classPath = classPath.substring(0, i);
char[] chars = classPath.toCharArray();
boolean isFirst = Boolean.TRUE;
// 生成真实的表名
for (char c : chars) {
if (!isFirst && c >= 65 && c <= 90) {
tableName += "_";
}
if (isFirst) {
isFirst = Boolean.FALSE;
}
tableName += c;
}
// 表名转换为大写返回
return tableName.toUpperCase();
}

/**
* 过滤性阅读
*
* @param filePath 文件路径
* @param notIncludeLineStartWith 不包括的字符,即某行的开头是这样的字符串,则在读取的时候该行忽略
* @return
* @throws IOException
*/
private static String filterRead(String filePath, String notIncludeLineStartWith) throws IOException {
String result = "";
FileReader fr = new FileReader(filePath);
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
while (line != null) {
if (!line.startsWith(notIncludeLineStartWith)) {
result += line;
}
line = br.readLine();
if (line != null && !line.startsWith(notIncludeLineStartWith)) {
result += "\n";
}
}
br.close();
fr.close();
return result;
}

/**
* 根据XML 字符串 建立JDom的Document对象
*
* @param xmlString XML格式的字符串
* @return Document 返回建立的JDom的Document对象,建立不成功将抛出异常。
* @throws IOException
* @throws JDOMException
*/
private static Document getDocument(String xmlString) throws JDOMException, IOException {

SAXBuilder builder = new SAXBuilder();
Document anotherDocument = builder.build(new StringReader(xmlString));
return anotherDocument;

}
}

这里需要JDOM的依赖。
不过需要注意几点:
1、这里体现不出主键、外键关系,没办法,这里只有手工补充了;
2、每个sqlmap的文件中,每个resultMap中的result字段,都必须有jdbcType这一行,否则会报找不到属性的空指针异常,当然这里可以搞一个javaType与jdbcType的映射关系,根据javaType去找jdbcType,我这里用不着,就没有弄了;
3、sqlmap的DOCTYPE在读出来的时候要去掉,否则生成对象的时候会报错。
差不多了,我是跑成功了。

代码在附件,请下载查看。
[/b][/color][/size]
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值