根據Ibatis的SqlMap配置檔案生成表結構
有一份應用完整的原始碼,不過就是缺少了表結構,如果讓我根據DO物件一個個去慢慢建立,也是個讓人頭痛的問題,一是因為有幾十個表,二是這個東西拷貝貼上一點技術含量都沒有,這真不是我願意乾的活。本來是想在網上搜索一份這樣的工具,關鍵字到是用了一大堆,中文英文都試過了,如“如何根據SqlMap建立表結構”、"How to generate table from sqlmap"等,還是木有找到,畢竟有幾個是像我這樣有物件原始碼卻木有表結構的,於是就打算自己搞定了。
幸好我對這份應用本身還是比較熟悉,知道用的是什麼樣的資料庫,檔案的命名風格是怎麼樣的等,想來根據物件生成表結構應該不是什麼驗事。剛開始想的方式是根據DO物件來生成,後來根據找到的MYSQL欄位型別與JAVA物件的對映一看,發現一對多的情況有不少,覺得這種不靠譜,於是就放棄這種方案;後面發現SQLMPA配置檔案中有物件與欄位的對映,這個倒是省事了,直接分析這個檔案就OK了,於是乎就有了下面這些程式碼:
[java] view plain copy
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);
/**
* 這裡要把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("class");
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 (jdbcType.toUpperCase().equals("VARCHAR")) {
jdbcType = DEFAULT_VARCHAR_LENGTH;
}
createTableString.append(child.getAttributeValue("column")).append(" ").append(jdbcType);
if (size < children.size() - 1) {
createTableString.append(",\n\t");
} else {
createTableString.append("\n");
}
size++;
}
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在讀出來的時候要去掉,否則生成物件的時候會報錯。
差不多了,我是跑成功了。