MyBatis-Generator源码学习及修改
所需jar包:generator-mybatis-generator-1.3.2.jar
背景:
公司数据库的做了分库,查询时候,必须修改customerId,否则查询效率会变低,数据库表60+,新工程每个表几乎都加了新的字段,需要生成新的mybatis的mapper文件。
方案:
打算采用MyBatis-Generator插件的方式生成实体类,接口以及xml。
需求:
生成的sql和接口,对于改查来说,不仅要生成主键的查询,还有携带有customerId字段,提升查询速率。
原有的MyBatis-Generator插件不满足条件,MyBatis-Generator插件可以生成依赖于主键的查询select,依赖于主键的选择性修改update。故需要修改MyBatis-Generator插件中的代码。
目标:
通过修改源码的方式,生成达到目的mybatis的mapper
解决方案:
下载所需的MyBatis-Generator插件的源码包,解压后的得到
这里只需要修改core中的文件即可
太熟悉了,简简单单的maven项目,直接动手撸代码,目标很明确,selectByPrimaryKey和updateByPrimaryKey修改为满足条件的sql语句(及携带customerId)
xml生成代码位置:
标红处为生成xml的java代码
原理:
这几个类通过拼接StringBuilder.append()方法,最后通过解析元素的方式生成,可以理解为xml解析。
xml的生成代码如何修改:
这里修改mapper.xml中selectByPrimaryKey()方法,updateByPrimaryKey()同理
@Override
public void addElements(XmlElement parentElement) {
XmlElement answer = new XmlElement("select"); //$NON-NLS-1$
answer.addAttribute(new Attribute(
"id", introspectedTable.getSelectByPrimaryKeyStatementId())); //$NON-NLS-1$
if (introspectedTable.getRules().generateResultMapWithBLOBs()) {
answer.addAttribute(new Attribute("resultMap", //$NON-NLS-1$
introspectedTable.getResultMapWithBLOBsId()));
} else {
answer.addAttribute(new Attribute("resultMap", //$NON-NLS-1$
introspectedTable.getBaseResultMapId()));
}
String parameterType;
if (introspectedTable.getRules().generatePrimaryKeyClass()) {
parameterType = introspectedTable.getPrimaryKeyType();
} else {
// PK fields are in the base class. If more than on PK
// field, then they are coming in a map.
if (introspectedTable.getPrimaryKeyColumns().size() > 1) {
parameterType = "map"; //$NON-NLS-1$
} else {
parameterType = introspectedTable.getPrimaryKeyColumns().get(0)
.getFullyQualifiedJavaType().toString();
}
}
answer.addAttribute(new Attribute("parameterType", //$NON-NLS-1$
parameterType));
context.getCommentGenerator().addComment(answer);
StringBuilder sb = new StringBuilder();
sb.append("select "); //$NON-NLS-1$
if (stringHasValue(introspectedTable
.getSelectByPrimaryKeyQueryId())) {
sb.append('\'');
sb.append(introspectedTable.getSelectByPrimaryKeyQueryId());
sb.append("' as QUERYID,"); //$NON-NLS-1$
}
answer.addElement(new TextElement(sb.toString()));
answer.addElement(getBaseColumnListElement());
if (introspectedTable.hasBLOBColumns()) {
answer.addElement(new TextElement(",")); //$NON-NLS-1$
answer.addElement(getBlobColumnListElement());
}
sb.setLength(0);
sb.append("from "); //$NON-NLS-1$
sb.append(introspectedTable
.getAliasedFullyQualifiedTableNameAtRuntime());
answer.addElement(new TextElement(sb.toString()));
boolean and = false;
for (IntrospectedColumn introspectedColumn : introspectedTable
.getPrimaryKeyColumns()) {
sb.setLength(0);
if (and) {
sb.append(" and "); //$NON-NLS-1$
} else {
sb.append("where "); //$NON-NLS-1$
and = true;
}
//这里为生成sql的最后位置
sb.append(MyBatis3FormattingUtilities
.getAliasedEscapedColumnName(introspectedColumn));
sb.append(" = "); //$NON-NLS-1$
//原来的代码是 sb.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn));
sb.append(MyBatis3FormattingUtilities
.getParameterClause1(introspectedColumn));
answer.addElement(new TextElement(sb.toString()));
}
if (context.getPlugins()
.sqlMapSelectByPrimaryKeyElementGenerated(answer,
introspectedTable)) {
parentElement.addElement(answer);
}
}
修改核心拼接代码
public static String getParameterClause(
IntrospectedColumn introspectedColumn) {
return getParameterClause(introspectedColumn, null);
}
public static String getParameterClause1(
IntrospectedColumn introspectedColumn) {
return getParameterClause1(introspectedColumn, null);
}
public static String getParameterClause1(
IntrospectedColumn introspectedColumn, String prefix) {
StringBuilder sb = new StringBuilder();
sb.append("#{"); //$NON-NLS-1$
sb.append(introspectedColumn.getJavaProperty(prefix));
sb.append(",jdbcType="); //$NON-NLS-1$
sb.append(introspectedColumn.getJdbcTypeName());
if (stringHasValue(introspectedColumn.getTypeHandler())) {
sb.append(",typeHandler="); //$NON-NLS-1$
sb.append(introspectedColumn.getTypeHandler());
}
sb.append('}');
sb.append(" and CUSTOMER_ID = #{customerId,jdbcType=VARCHAR}");
return sb.toString();
}
public static String getParameterClause(
IntrospectedColumn introspectedColumn, String prefix) {
StringBuilder sb = new StringBuilder();
sb.append("#{"); //$NON-NLS-1$
sb.append(introspectedColumn.getJavaProperty(prefix));
sb.append(",jdbcType="); //$NON-NLS-1$
sb.append(introspectedColumn.getJdbcTypeName());
if (stringHasValue(introspectedColumn.getTypeHandler())) {
sb.append(",typeHandler="); //$NON-NLS-1$
sb.append(introspectedColumn.getTypeHandler());
}
sb.append('}');
return sb.toString();
}
注意:
getParameterClause()和getParameterClause()为源代码
getParameterClause1()和getParameterClause1()为源代码
直接复制代码并在最后加入sb.append(" and CUSTOMER_ID = #{customerId,jdbcType=VARCHAR}");
同理修改mapper.xml中updateByPrimaryKey()方法也是如此,可复用
生成之后效果图
mybatis接口的修改:
原有java接口代码
MalltTrade selectByPrimaryKey(String tradeId);
需要生成
MalltTrade selectByPrimaryKey(Map map);
这里为生成接口代码的位置
读代码:
if中条件为true时:单主键,false时:联合主键。
简单点先看true
第二行代码,FullyQualifiedJavaType要映射我们所需的参数,及MalltTrade selectByPrimaryKey(Map map);方法的参数,查看他的类型
好烦!
Map的包是import java.util.Map;
和Map不是同一个包下的,这里改动较大,故采用另一种方式修改这个接口。
java的io流处理
直接上代码:
public void handle(String filename){
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(filename, "rw");
String line = null;
long lastPoint = 0; //记住上一次的偏移量
int i=0;
int m=3;
StringBuffer stringBuffer = new StringBuffer();
while ((line = raf.readLine()) != null) {
final long ponit = raf.getFilePointer();
if(line.contains("selectByPrimaryKey")){
//不可这里进行string的修改,他这个是边读边写,偏移量是有问题的,例如多一个字符少一个字符都会引起文件的串行,不信的可以试试。
raf.seek(lastPoint);
raf.writeBytes(line);
}
//导入Map,import
if (line.contains("import com.sitech.mios.modules.order.dao.po")){
System.out.println(i);
line=line+"\nimport java.util.Map;\n";
}
//修改参数,为什么不用replace,因为replace对于联合主键来说他生成的形式是MalltDataDictionary selectByPrimaryKey(@Param("xxx") xxx,@Param("yyy ") xxx); 忘记保存了,可自己尝试生成一下,括号太多,使用正则太麻烦,反正我写不出来这个正则,h
if(line.contains("selectByPrimaryKey")){
String[] split = line.split("\\(");
String str=split[0]+"(Map map); ";//line.replace(split[1], "Map map); ");
line=str;
}
stringBuffer.append(line+"\n");
lastPoint = ponit;
i++;
}
String s = stringBuffer.toString();
//目标文件位置,与上方一致
File file = new File(filename);
FileWriter fout = new FileWriter(file);// 创建文件输出流
fout.write(s);
fout.close();// 关闭输出流
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
String filename为mapper.java的位置
拿下拿下,完美收工!