Mybatis生成器插件扩展,定制方法生成
public Criteria andNameIsEmpty() {addCriterion("`name` = ''");setCriterionPattern();return (Criteria) this;}public Criteria andNameFindInSet(String value) {addCriterion("find_in_set($value, `name`)", value, "name");setCriterionPattern();return (Criteria) this;}public Criteria andNameFindInSetIn(List<String> value) {addCriterion("find_in_set($value, `name`)", value, "name");setCriterionPattern();return (Criteria) this;}
一、生成模式原理
(1)Example.Criterion添加pattern字段
public static class Criterion {private String condition;private Object value;private Object secondValue;private boolean noValue;private boolean singleValue;private boolean betweenValue;private boolean listValue;private String typeHandler;private boolean pattern;
}
(2)Example.GeneratedCriteria加方法setCriterionPattern
protected abstract static class GeneratedCriteriaprotected void setCriterionPattern() {Criterion criterion = (Criterion)criteria.get(criteria.size()-1);criterion.setPattern(true);}
}
(3) 加对应列方法
protected abstract static class GeneratedCriteria {public Criteria andXXXOp(String value) {addCriterion("Op(##value##, `xxx`)", value, "xxx");setCriterionPattern();return (Criteria) this;}
}
(4)改造XXXSqlProvider.applyWhere的 if (criterion.isNoValue()) 前增加模式代码
if (criterion.isPattern()) {if (criterion.isListValue()) {//list参数sb.append(" (");List<?> listItems = (List<?>) criterion.getValue();boolean comma = false;for (int k = 0; k < listItems.size(); k++) {if (comma) {sb.append(" or ");} else {comma = true;}String value;if (criterion.getTypeHandler() == null) {value = String.format(parmPhrase3, i, j, k);} else {value = String.format(parmPhrase3_th, i, j, k, criterion.getTypeHandler());}sb.append(criterion.getCondition().replace("##value##", value));}sb.append(')');} else {//其他参数String value;if (criterion.getTypeHandler() == null) {value = String.format(parmPhrase1, "", i, j).trim();} else {value = String.format(parmPhrase1_th, "", i, j, criterion.getTypeHandler()).trim();}sb.append(criterion.getCondition().replace("##value##", value));}
} else if (criterion.isNoValue()) {sb.append(criterion.getCondition());
}
(5)改造XXXMapper.xml的<when test="criterion.noValue">前增加模式代码
<when test="criterion.pattern">and<choose><when test="criterion.listValue"><foreach close=")" collection="criterion.value" item="listItem" open="(" separator=" or "><foreach collection="criterion.condition.split('##value##')" item="criterionCond" separator="#{listItem}">${criterionCond}</foreach></foreach></when><otherwise><foreach collection="criterion.condition.split('##value##')" item="criterionCond" separator="#{criterion.value}">${criterionCond}</foreach></otherwise></choose>
</when>
<when test="criterion.noValue">and ${criterion.condition}
</when>
二、插件代码
package com.mk.mybatisgenerator.plugins;import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Element;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.ibatis2.Ibatis2FormattingUtilities;import java.util.*;public class MySQLMethodPlugin extends PluginAdapter {private String valueName = "##value##";//值占位符private String columnName = "##column##";//列名占位符private boolean listValue = true;//是否开启生成list参数private Map<String, String> methods = new HashMap<>();public MySQLMethodPlugin() {super();}@Overridepublic void setProperties(Properties properties) {super.setProperties(properties);final String valueNameStr = "VALUE_NAME";final String columnNameStr = "COLUMN_NAME";final String listValueStr = "LIST_VALUE";for (String name : properties.stringPropertyNames()) {String value = properties.getProperty(name);if (valueNameStr.equals(name)) {if (value != null && (value = value.trim()).length() > 0) {this.valueName = value;}} else if (columnNameStr.equals(name)) {if (value != null && (value = value.trim()).length() > 0) {this.columnName = value;}} else if (listValueStr.equals(name)) {if (value != null) {this.listValue = Boolean.parseBoolean(value);}} else {methods.put(name, value);}}}@Overridepublic boolean validate(List<String> warnings) {return true;}/*** 重写example** @param topLevelClass* @param introspectedTable* @return*/@Overridepublic boolean modelExampleClassGenerated(TopLevelClass topLevelClass,IntrospectedTable introspectedTable) {addCriterionPattern(topLevelClass, introspectedTable);//增加模式匹配if (methods.isEmpty()) {addFindInSet(topLevelClass, introspectedTable);//增加find_in_set方法addPattern(topLevelClass, introspectedTable);//增加模式方法} else {for (Map.Entry<String, String> entry : methods.entrySet()) {boolean hasValue = entry.getValue().contains(valueName);addMethodPattern(topLevelClass, introspectedTable, entry.getKey(), entry.getValue(), hasValue);}}return true;}//<when test="criterion.pattern">// and// <choose>// <when test="criterion.listValue">// <foreach close=")" collection="criterion.value" item="listItem" open="("// separator=" or ">// <foreach collection="criterion.conditionList('##value##')"// item="criterionCond" separator="#{listItem}">// ${criterionCond}// </foreach>// </foreach>//// </when>// <otherwise>// <foreach collection="criterion.conditionSplit('##value##')"// item="criterionCond" separator="#{criterion.value}">// ${criterionCond}// </foreach>// </otherwise>// </choose>//</when>//<when test="criterion.noValue">// and ${criterion.condition}//</when>/*** xml ExampleWhere重写** @param xmlElement* @param introspectedTable* @return*/@Overridepublic boolean sqlMapExampleWhereClauseElementGenerated(XmlElement xmlElement, IntrospectedTable introspectedTable) {List<Element> elementList = new LinkedList<>();elementList.add(xmlElement);while (!elementList.isEmpty()) {Element parent = elementList.remove(0);if(!(parent instanceof XmlElement)){continue;}XmlElement xmlParent = (XmlElement) parent;List<Element> elements = xmlParent.getElements();elementList.addAll(0, elements);for (int i = 0, len = elements.size(); i < len; i++) {Element ele = elements.get(i);if(!(ele instanceof XmlElement)){continue;}XmlElement element = (XmlElement) ele;if(!element.getName().equals("when")){continue;}for (Attribute attribute : element.getAttributes()) {//找到criterion.noValue行插入模式代码if (attribute.getName().equals("test") && attribute.getValue().equals("criterion.noValue")) {//isListXmlElement patternListWhenElement = new XmlElement("when");{XmlElement condForElement = new XmlElement("foreach");condForElement.addAttribute(new Attribute("collection", "criterion.conditionSplit('" + valueName + "')"));condForElement.addAttribute(new Attribute("item", "criterionCond"));condForElement.addAttribute(new Attribute("separator", "#{listItem}"));condForElement.addElement(new TextElement("${criterionCond}"));XmlElement listForElement = new XmlElement("foreach");listForElement.addAttribute(new Attribute("collection", "criterion.value"));listForElement.addAttribute(new Attribute("item", "listItem"));listForElement.addAttribute(new Attribute("separator", " or "));listForElement.addAttribute(new Attribute("open", "("));listForElement.addAttribute(new Attribute("close", ")"));listForElement.addElement(condForElement);patternListWhenElement.addAttribute(new Attribute("test", "criterion.listValue"));patternListWhenElement.addElement(listForElement);}//otherwiseXmlElement otherwiseElement = new XmlElement("otherwise");{XmlElement condForElement = new XmlElement("foreach");condForElement.addAttribute(new Attribute("collection", "criterion.conditionSplit('" + valueName + "')"));condForElement.addAttribute(new Attribute("item", "criterionCond"));condForElement.addAttribute(new Attribute("separator", "#{criterion.value}"));condForElement.addElement(new TextElement("${criterionCond}"));otherwiseElement.addElement(condForElement);}XmlElement patternChooseElement = new XmlElement("choose");patternChooseElement.addElement(patternListWhenElement);patternChooseElement.addElement(otherwiseElement);XmlElement patternElement = new XmlElement("when");patternElement.addAttribute(new Attribute("test", "criterion.pattern"));patternElement.addElement(new TextElement("and"));patternElement.addElement(patternChooseElement);xmlParent.addElement(i, patternElement);return true;}}}}throw new RuntimeException("ChooseElement not exist");}//if (criterion.isPattern()) {// if (criterion.isListValue()) {// sb.append(" (");// List<?> listItems = (List<?>) criterion.getValue();// boolean comma = false;// for (int k = 0; k < listItems.size(); k++) {// if (comma) {// sb.append(" or ");// } else {// comma = true;// }// String value;// if (criterion.getTypeHandler() == null) {// value = String.format(parmPhrase3, i, j, k);// } else {// value = String.format(parmPhrase3_th, i, j, k, criterion.getTypeHandler());// }// sb.append(criterion.getCondition().replace("##value##", value));// }// sb.append(')');// } else {// String value;// if (criterion.getTypeHandler() == null) {// value = String.format(parmPhrase1, "", i, j).trim();// } else {// value = String.format(parmPhrase1_th, "", i, j, criterion.getTypeHandler()).trim();// }// sb.append(criterion.getCondition().replace("##value##", value));// }//} else if (criterion.isNoValue()) {// sb.append(criterion.getCondition());//}/*** 重写ApplyWhere方法** @param method* @param topLevelClass* @param introspectedTable* @return*/@Overridepublic boolean providerApplyWhereMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {List<String> lines = method.getBodyLines();for (int i = 0, len = lines.size(); i < len; i++) {String line = lines.get(i).trim();//找到criterion.noValue行插入模式代码if (line.matches("if\\s*\\(criterion\\.isNoValue\\(\\)\\)\\s*\\{")) {lines.remove(i);List<String> appends = new ArrayList<>();appends.add("if (criterion.isPattern()) {");appends.add("if (criterion.isListValue()) {");appends.add("sb.append(\" (\");");appends.add("List<?> listItems = (List<?>) criterion.getValue();");appends.add("boolean comma = false;");appends.add("for (int k = 0; k < listItems.size(); k++) {");appends.add("if (comma) {");appends.add("sb.append(\" or \");");appends.add("} else {");appends.add("comma = true;");appends.add("}");appends.add("String value;");appends.add("if (criterion.getTypeHandler() == null) {");appends.add("value = String.format(parmPhrase3, i, j, k);");appends.add("} else {");appends.add("value = String.format(parmPhrase3_th, i, j, k, criterion.getTypeHandler());");appends.add("}");appends.add("sb.append(criterion.getCondition().replace(\"" + valueName + "\", value));");appends.add("}");appends.add("sb.append(')');");appends.add("} else {");appends.add("String value;");appends.add("if (criterion.getTypeHandler() == null) {");appends.add("value = String.format(parmPhrase1, \"\", i, j).trim();");appends.add("} else {");appends.add("value = String.format(parmPhrase1_th, \"\", i, j, criterion.getTypeHandler()).trim();");appends.add("}");appends.add("sb.append(criterion.getCondition().replace(\"" + valueName + "\", value));");appends.add("}");appends.add("} else " + line);method.addBodyLines(i, appends);return true;}}throw new RuntimeException("criterion.isNoValue() not exist");}/*protected void setCriterionPattern() {Criterion criterion = (Criterion)criteria.get(criteria.size()-1);criterion.setPattern(true);}*/public void addCriterionPattern(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {addCriterionPatternField(topLevelClass, introspectedTable);InnerClass criteria = null;// first, find the Criteria inner classfor (InnerClass innerClass : topLevelClass.getInnerClasses()) {if ("GeneratedCriteria".equals(innerClass.getType().getShortName())) { //$NON-NLS-1$criteria = innerClass;break;}}if (criteria == null) {throw new RuntimeException("GeneratedCriteria not exist");}//模式方法Method setCriterionPattern = new Method();setCriterionPattern.setVisibility(JavaVisibility.PROTECTED);setCriterionPattern.setName("setCriterionPattern");setCriterionPattern.addBodyLine("Criterion criterion = (Criterion)criteria.get(criteria.size()-1);");setCriterionPattern.addBodyLine("criterion.setPattern(true);");criteria.addMethod(setCriterionPattern);}public void addCriterionPatternField(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {InnerClass criterion = null;// first, find the Criteria inner classfor (InnerClass innerClass : topLevelClass.getInnerClasses()) {if ("Criterion".equals(innerClass.getType().getShortName())) { //$NON-NLS-1$criterion = innerClass;break;}}if (criterion == null) {throw new RuntimeException("Criterion not exist");}FullyQualifiedJavaType booleanPrimitive = FullyQualifiedJavaType.getBooleanPrimitiveInstance();Field pattern = new Field();pattern.setName("pattern");pattern.setVisibility(JavaVisibility.PRIVATE);pattern.setType(booleanPrimitive);criterion.addField(pattern);Method setPattern = new Method();setPattern.setVisibility(JavaVisibility.PUBLIC);setPattern.setName("setPattern");setPattern.addParameter(new Parameter(booleanPrimitive, "pattern"));setPattern.addBodyLine("this.pattern = pattern;");criterion.addMethod(setPattern);Method isPattern = new Method();isPattern.setVisibility(JavaVisibility.PUBLIC);isPattern.setReturnType(booleanPrimitive);isPattern.setName("isPattern");isPattern.addBodyLine("return pattern;");criterion.addMethod(isPattern);Method conditionList = new Method();conditionList.setVisibility(JavaVisibility.PUBLIC);conditionList.addParameter(new Parameter(FullyQualifiedJavaType.getStringInstance(), "valueName"));conditionList.setName("conditionSplit");conditionList.setReturnType(new FullyQualifiedJavaType("String[]"));conditionList.addBodyLine("return java.util.regex.Pattern.compile(valueName, java.util.regex.Pattern.LITERAL).split(this.condition);");criterion.addMethod(conditionList);}public void addFindInSet(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {String opName = "findInSet";String pattern = "find_in_set(" + valueName + ", " + columnName + ")";addMethodPattern(topLevelClass, introspectedTable, opName, pattern, true);}public void addMethodPattern(TopLevelClass topLevelClass, IntrospectedTable introspectedTable, String opName, String pattern, boolean hasValue) {addMethodPattern(topLevelClass, introspectedTable, opName, pattern, hasValue, false);if (hasValue && listValue) {addMethodPattern(topLevelClass, introspectedTable, opName, pattern, true, true);}}public void addMethodPattern(TopLevelClass topLevelClass, IntrospectedTable introspectedTable, String opName,String pattern, boolean hasValue, boolean isList) {InnerClass criteria = null;// first, find the Criteria inner classfor (InnerClass innerClass : topLevelClass.getInnerClasses()) {if ("GeneratedCriteria".equals(innerClass.getType().getShortName())) { //$NON-NLS-1$criteria = innerClass;break;}}if (criteria == null) {throw new RuntimeException("GeneratedCriteria not exist");}for (IntrospectedColumn introspectedColumn : introspectedTable.getNonBLOBColumns()) {if (!introspectedColumn.isJdbcCharacterColumn()|| !introspectedColumn.isStringColumn()) {continue;}Method method = new Method();method.setVisibility(JavaVisibility.PUBLIC);//判断是否有参数if (hasValue) {FullyQualifiedJavaType javaType = introspectedColumn.getFullyQualifiedJavaType();if (isList) {//判断是否是list参数javaType = FullyQualifiedJavaType.getNewListInstance();javaType.addTypeArgument(introspectedColumn.getFullyQualifiedJavaType());}method.addParameter(new Parameter(javaType, "value")); //$NON-NLS-1$}StringBuilder opNameBuilder = new StringBuilder(opName);opNameBuilder.setCharAt(0, Character.toUpperCase(opNameBuilder.charAt(0)));opName = opNameBuilder.toString();StringBuilder sb = new StringBuilder();sb.append(introspectedColumn.getJavaProperty());sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));sb.insert(0, "and"); //$NON-NLS-1$sb.append(opName);//list参数加In后缀if (hasValue && isList) {sb.append("In");}method.setName(sb.toString());method.setReturnType(FullyQualifiedJavaType.getCriteriaInstance());sb.setLength(0);//addCriterion方法sb.append("addCriterion(\"").append(pattern.replace(columnName, Ibatis2FormattingUtilities.getAliasedActualColumnName(introspectedColumn)));//有参数使用有参方法if (hasValue) {sb.append("\", value, \"").append(introspectedColumn.getJavaProperty());}sb.append("\");");method.addBodyLine(sb.toString());method.addBodyLine("setCriterionPattern();");method.addBodyLine("return (Criteria) this;");criteria.addMethod(method);}}public void addPattern(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {addPatternMethod(topLevelClass, introspectedTable, "pattern");}public void addPatternMethod(TopLevelClass topLevelClass, IntrospectedTable introspectedTable, String opName) {InnerClass criteria = null;// first, find the Criteria inner classfor (InnerClass innerClass : topLevelClass.getInnerClasses()) {if ("GeneratedCriteria".equals(innerClass.getType().getShortName())) { //$NON-NLS-1$criteria = innerClass;break;}}if (criteria == null) {throw new RuntimeException("GeneratedCriteria not exist");}for (IntrospectedColumn introspectedColumn : introspectedTable.getNonBLOBColumns()) {if (!introspectedColumn.isJdbcCharacterColumn()|| !introspectedColumn.isStringColumn()) {continue;}Method method = new Method();method.setVisibility(JavaVisibility.PUBLIC);method.addParameter(new Parameter(FullyQualifiedJavaType.getStringInstance(), "pattern"));method.addParameter(new Parameter(introspectedColumn.getFullyQualifiedJavaType(), "value"));StringBuilder opNameBuilder = new StringBuilder(opName);opNameBuilder.setCharAt(0, Character.toUpperCase(opNameBuilder.charAt(0)));opName = opNameBuilder.toString();StringBuilder sb = new StringBuilder();sb.append(introspectedColumn.getJavaProperty());sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));sb.insert(0, "and"); //$NON-NLS-1$sb.append(opName);method.setName(sb.toString());method.setReturnType(FullyQualifiedJavaType.getCriteriaInstance());sb.setLength(0);sb.append("addCriterion(pattern.replace(\"").append(columnName).append("\", \"").append(Ibatis2FormattingUtilities.getAliasedActualColumnName(introspectedColumn)).append("\")").append(", value, \"").append(introspectedColumn.getJavaProperty());sb.append("\");");method.addBodyLine(sb.toString());method.addBodyLine("setCriterionPattern();");method.addBodyLine("return (Criteria) this;");criteria.addMethod(method);}}}
三、配置插件
<plugin type="com.mk.mybatisgenerator.plugins.MySQLMethodPlugin"><!--是否开启生成list参数,默认true开启--><property name="LIST_VALUE" value="true"/><!--value参数占位符自定义,默认##value##--><property name="VALUE_NAME" value="$value"/><!--column列名占位符自定义,默认##column##--><property name="COLUMN_NAME" value="$column"/><!--其他定义,name为方法后缀名,属性值为模式--><property name="isEmpty" value="$column = ''"/><property name="findInSet" value="find_in_set($value, $column)"/>
</plugin>