在上一篇文章 代码自动生成(一)中废了很多话,下面注解入正题:
首先定义列Col类,积累列中相应的信息,具体如下:
public class Col {
private Integer index;
private String name;
private String fieldName;
private String methodName;
private String desc;
private Type type;
private String default_;
private String isPK = "no";
private String allowNull = "no";
private Boolean hasNext = true;
/** 基本参数的构造
* @author hym
* @time 2017年7月20日 下午7:37:27
* @param index
* @param fieldName
* @param type
*/
public Col(Integer index,String fieldName,Type type){
this.index=index;
this.fieldName=fieldName;
this.type=type;
}
/**构造校验
* @author hym
* @time 2017年7月22日 下午5:19:20
* @param tab
* @param index
* @param defs
* @param isColMap
*/
public Col(String tab, int index, List<Object> defs, Boolean isColMap) {
int size = defs.size();
this.index = index;
if (size < 2) {
throw new RuntimeException("表'" + tab + "'的第'" + index + "'字段没有定义字段名");
}
name = (String) defs.get(1);
if (name == null || name.trim().length() == 0) {
throw new RuntimeException("表'" + tab + "'的第'" + index + "'字段没有定义字段名");
}
desc = (String) defs.get(2);
if (size < 4) {
throw new RuntimeException("表'" + tab + "'的'" + name + "'字段没有定义类型");
}
String typeStr = (String) defs.get(3);
if (typeStr == null || typeStr.trim().length() == 0) {
throw new RuntimeException("表'" + tab + "'的'" + name + "'字段没有定义字类型");
}
typeStr = typeStr.trim().toLowerCase();
type = Type.get(typeStr);
if (type == null) {
throw new RuntimeException("表'" + tab + "'的'" + name + "'字段类型定义错误");
}
fieldName = format();
if (size >= 6) {
default_ = defs.get(5).toString().trim();
if (default_.length() == 0) {
default_ = null;
}
}
if (size >= 7) {
isPK = defs.get(6).toString().trim().toLowerCase();
if (isPK.length() == 0) {
isPK = "no";
}
}
if (size >= 8) {
allowNull = defs.get(7).toString().trim().toLowerCase();
if (allowNull.length() == 0) {
allowNull = "no";
}
}
if (isColMap) {
name = removeDBKeyword(name);
}
}
public Integer getIndex() {
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public String getName() {
return new StringBuffer(name).toString();
}
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
private String format() {
String _name = this.getName();
int idx = -1;
while ((idx = _name.indexOf("_")) != -1) {
String pre = _name.substring(0, idx);
String tmpSuf = _name.substring(idx + 1).trim();
String suf_ = "";
if (tmpSuf.length() > 0) {
String suf = tmpSuf.substring(0, 1).toUpperCase();
if (tmpSuf.length() > 1) {
suf_ = suf + tmpSuf.substring(1);
} else {
suf_ = suf;
}
}
_name = pre + suf_;
}
methodName = _name.substring(0, 1).toUpperCase() + _name.substring(1);
return _name.substring(0, 1).toLowerCase() + _name.substring(1);
}
private String removeDBKeyword(String name) {
String result = name;
if (DBKeyword.get(name.toUpperCase()) != null) {
result = "`" + name + "`";
}
return result;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public String getDefault() {
return default_;
}
public void setDefault(String default_) {
this.default_ = default_;
}
public String getIsPK() {
return isPK;
}
public void setPK(String isPK) {
this.isPK = isPK;
}
public String getIsAllowNull() {
return allowNull;
}
public void setAllowNull(String allowNull) {
this.allowNull = allowNull;
}
public Boolean getHasNext() {
return hasNext;
}
public void setHasNext(Boolean hasNext) {
this.hasNext = hasNext;
}
}
Type类是定义mysql列数据类型和java中数据类型的转换,写的比较单一,该项可以再以后进行扩展改变,因为数据库除了mysql还有oracle,sqlserver等;
public class Type {
private String sqlType;
private String javaType;
private static HashMap<String, String> typeMap=new HashMap<>();
static{
//基本的sql数据类型
typeMap.put("VARCHAR", "String");
typeMap.put("CHAR", "String");
typeMap.put("BLOB", "byte[]");
typeMap.put("TEXT", "String");
typeMap.put("INT", "Integer");
typeMap.put("INT UNSIGNED", "Integer");
typeMap.put("INTEGER", "Long");
typeMap.put("INTEGER UNSIGNED", "Long");
typeMap.put("TINYINT", "Integer");
typeMap.put("TINYINT UNSIGNED", "Integer");
typeMap.put("SMALLINT", "Integer");
typeMap.put("SMALLINT UNSIGNED", "Integer");
typeMap.put("MEDIUMINT", "Integer");
typeMap.put("MEDIUMINT UNSIGNED", "Integer");
typeMap.put("FLOAT", "Float");
typeMap.put("FLOAT UNSIGNED", "Float");
typeMap.put("DOUBLE", "Double");
typeMap.put("BIT", "Boolean");
typeMap.put("BIGINT", "java.math.BigInteger");
typeMap.put("DECIMAL", "java.math.BigDecimal");
typeMap.put("BOOLEAN", "Long");
typeMap.put("DATE", "java.sql.Date");
typeMap.put("TIME", "java.sql.Time");
typeMap.put("DATETIME", "java.sql.Timestamp") ;
typeMap.put("TIMESTAMP", "java.sql.Timestamp");
typeMap.put("YEAR", "java.sql.Date");
typeMap.put("OTHER", "String");
}
/**
* @author hym
* @time 2017年7月20日 下午5:21:52
* @param sqlType
* @param javaType
*/
public Type(String sqlType, String javaType) {
this.sqlType = sqlType.toLowerCase();
this.javaType = javaType;
}
public String getSqlType() {
return sqlType;
}
public void setSqlType(String sqlType) {
this.sqlType = sqlType;
}
public String getJavaType() {
return javaType;
}
public void setJavaType(String javaType) {
this.javaType = javaType;
}
/**
* 当返回值找不到的时候,直接返回other-string
* @author hym
* @time 2017年7月20日下午5:22:09
* @param sqlType
* @return
*/
public static Type get(String sqlType) {
String javaType=typeMap.get(sqlType.toUpperCase());
if (StringUtils.isEmpty(javaType)) {
javaType=typeMap.get("OTHER");
}
Type result = new Type(sqlType, javaType);
return result;
}
}
当我们准备好工具类之后,那么就进入主类了,如下:
public class AutoGenerationJavaCode {
private String url;
private String name;
private String passWord;
private String driver;
private String sql;
private String tableName;
private String templateDir;
private String autoGeneratedFile;
//包的基础路径 比如com.xx等
private String basePath;
private static String[][] fileNameArray = new String[6][2];
static {
fileNameArray[0][0] = "entityTemplate.ftl";
fileNameArray[0][1] = ".java";
fileNameArray[1][0] = "serviceTemplate.ftl";
fileNameArray[1][1] = "Service.java";
fileNameArray[2][0] = "serviceImplTemplate.ftl";
fileNameArray[2][1] = "ServiceImpl.java";
fileNameArray[3][0] = "daoTemplate.ftl";
fileNameArray[3][1] = "Dao.java";
fileNameArray[4][0] = "daoImplTemplate.ftl";
fileNameArray[4][1] = "DaoImpl.java";
fileNameArray[5][0] = "mapper.ftl";
fileNameArray[5][1] = "Mapper.xml";
}
public AutoGenerationJavaCode(String url, String name, String passWord, String driver, String tableName,
String autoGeneratedFile,String basePath) {
this.url = url;
this.name = name;
this.passWord = passWord;
this.driver = driver;
this.sql = "select * from " + tableName;
this.tableName = tableName;
this.templateDir = this.getClass().getResource("").getPath().replace("target/classes/com/xx/common/code/autocode/", "")
+"src/main/java/com/xx/common/code/template";
this.autoGeneratedFile = autoGeneratedFile;
this.basePath=basePath;
}
public void autoGenerationJavaCode() throws IOException, TemplateException, ClassNotFoundException,
SQLException {
Configuration cfg = new Configuration();
cfg.setDefaultEncoding("utf-8");
String className = dealClassName(dealTableName());
String fileName = className;
// Map<String, Object> columnMap = getColumn();
//设置模板文件路径
cfg.setDirectoryForTemplateLoading(new File(templateDir));
Map<String, Object> rootMap = new HashMap<String, Object>();
rootMap.put("className", className);
//rootMap.put("columnMap", columnMap);
rootMap.put("columns", getColumnList());
rootMap.put("basePath", basePath);
for (int i = 0; i < fileNameArray.length; i++) {
String packageName=null;
String filePath=null;
//设定包名
switch(fileNameArray[i][0]){
case "entityTemplate.ftl":
packageName=basePath+".entity";
filePath=autoGeneratedFile+"/entity";
break;
case "daoTemplate.ftl":
packageName=basePath+".dao";
filePath=autoGeneratedFile+"/dao";
break;
case "daoImplTemplate.ftl":
packageName=basePath+".dao.impl";
filePath=autoGeneratedFile+"/dao/impl";
break;
case "serviceTemplate.ftl":
packageName=basePath+".service";
filePath=autoGeneratedFile+"/service";
break;
case "serviceImplTemplate.ftl":
packageName=basePath+".service.impl";
filePath=autoGeneratedFile+"/service/impl";
break;
case "mapper.ftl":
packageName=basePath;
filePath=autoGeneratedFile+"/mapper";
rootMap.put("tableName", tableName);
break;
}
rootMap.put("packageName", packageName);
File dir=new File(filePath);
//检查目录是否存在,不存在则创建
if (!dir.exists()) {
dir.mkdir();
}
Template temp = cfg.getTemplate(fileNameArray[i][0]);
File docFile = new File(filePath + "//" + fileName + fileNameArray[i][1]);
Writer docout = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
//输出文件
temp.process(rootMap, docout);
}
System.out.println("==============所有的文件已成功生成===============");
}
public List<Col> getColumnList() throws ClassNotFoundException, SQLException {
Connection conn;
PreparedStatement pStemt = null;
Class.forName(driver);
conn = DriverManager.getConnection(url, name, passWord);
pStemt = conn.prepareStatement(sql);
ResultSetMetaData rsmd = pStemt.getMetaData();
List<Col> listColumn=new ArrayList<Col>();
int size = rsmd.getColumnCount();
for (int i = 0; i < size; i++) {
// String columnName = dealColumnName(rsmd, i);
Col col=getColumnInfo(rsmd, i);
if(i==size-1){
col.setHasNext(false);
}
listColumn.add(col);
}
conn.close();
return listColumn;
}
/**
* 获取列信息 需要设置多属性,该处生成mapper.xml的时候需要各种属性
* @author hym
* @time 2017年7月20日下午7:48:39
* @param rsmd
* @param i
* @return
* @throws SQLException
*/
private Col getColumnInfo(ResultSetMetaData rsmd,int i) throws SQLException{
String columnName = rsmd.getColumnName(i + 1).toLowerCase();
String charAfterLine = String.valueOf(columnName.charAt((columnName.indexOf("_") + 1)));
String convertedChar = charAfterLine.toUpperCase();
String fieldName = columnName.replace("_" + charAfterLine, convertedChar);//映射到类中的名称
String columntype=rsmd.getColumnTypeName(i+1);//sql的列类型
Type type=new Type(columntype, Type.get(columntype).getJavaType());
Col col=new Col(i, fieldName, type);
col.setMethodName(dealClassName(fieldName));
col.setName(columnName);//表中的列名
if (columnName.equalsIgnoreCase("id")) {
col.setPK("yes");
}
return col;
}
/**
* 将表名转换为DMO的字段名,比如 operate_type 转换后为 operateType
* @author hym
* @time 2017年7月22日下午4:22:14
* @param rsmd
* @param i
* @return
* @throws SQLException
*/
private String dealColumnName(ResultSetMetaData rsmd, int i) throws SQLException {
String columnName = rsmd.getColumnName(i + 1).toLowerCase();
String charAfterLine = String.valueOf(columnName.charAt((columnName.indexOf("_") + 1)));
String convertedChar = charAfterLine.toUpperCase();
columnName = columnName.replace("_" + charAfterLine, convertedChar);
return columnName;
}
/**
* 将表名转换为类型类名 比如 t_operate_log 转换后为 operateLog ,类名首字母应为大写,这里在freemarker的模板里直接转换
* @author hym
* @time 2017年7月22日下午4:22:05
* @return
*/
private String dealTableName() {
String className = tableName.toLowerCase().substring(tableName.indexOf("_") + 1);
String charAfterLine = String.valueOf(className.charAt((className.indexOf("_") + 1)));
String convertedChar = charAfterLine.toUpperCase();
className = className.replace("_" + charAfterLine, convertedChar);
return className;
}
public static void main(String[] args) {
String tableName="t_operate_table_test";
String className = tableName.toLowerCase().substring(tableName.indexOf("_") + 1);
String charAfterLine = String.valueOf(className.charAt((className.indexOf("_") + 1)));
String convertedChar = charAfterLine.toUpperCase();
className = className.replace("_" + charAfterLine, convertedChar);
}
/**
* 将类名转换为文件名,java公共类名与其文件名应该相同,这里将首字母转换为大写 如operateLog 转换后为 OperateLog
* @author hym
* @time 2017年7月22日下午4:22:25
* @param className
* @return
*/
private String dealClassName(String className) {
String first = className.substring(0, 1).toUpperCase();
String rest = className.substring(1, className.length());
String fileName = new StringBuffer(first).append(rest).toString();
return fileName;
}
}
Ok,上面的基本完成了生成所需的java类文件;
测试代码如下:
public static void main(String[] args) throws ClassNotFoundException, IOException, TemplateException, SQLException {
String url="jdbc:mysql://10.67.18.17:3306/xx";
String username="xx";
String password="xx";
String driver="com.mysql.jdbc.Driver";
String tableName="t_test_operate";
String basePath="com.xx.test";
String templateDir=System.getProperty("user.dir")+"/src/main/java/"+"com/xx/common/code/template";
String generateFilePath=System.getProperty("user.dir")+"/src/main/java/"+basePath.replace(".", "/");
AutoGenerationJavaCode autoGenerationJavaCode=
new AutoGenerationJavaCode(url, username, password, driver, tableName, generateFilePath, "com.xx.test");
autoGenerationJavaCode.autoGenerationJavaCode();
}
考虑到可能会用到不同类型的数据库,后面会对上面的类进行改造;