1+ /*
2+ * Copyright (c) 2017.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+ package com .itfsw .mybatis .generator .plugins ;
18+
19+ import com .itfsw .mybatis .generator .plugins .utils .CommTools ;
20+ import com .itfsw .mybatis .generator .plugins .utils .CommentTools ;
21+ import org .mybatis .generator .api .IntrospectedColumn ;
22+ import org .mybatis .generator .api .IntrospectedTable ;
23+ import org .mybatis .generator .api .PluginAdapter ;
24+ import org .mybatis .generator .api .dom .java .*;
25+ import org .mybatis .generator .api .dom .xml .*;
26+ import org .mybatis .generator .codegen .mybatis3 .MyBatis3FormattingUtilities ;
27+ import org .mybatis .generator .internal .util .StringUtility ;
28+ import org .slf4j .Logger ;
29+ import org .slf4j .LoggerFactory ;
30+
31+ import java .util .List ;
32+
33+ /**
34+ * ---------------------------------------------------------------------------
35+ * 存在即更新插件
36+ * ---------------------------------------------------------------------------
37+ * @author: hewei
38+ * @time:2017/3/21 10:59
39+ * ---------------------------------------------------------------------------
40+ */
41+ public class UpsertPlugin extends PluginAdapter {
42+ private static final Logger logger = LoggerFactory .getLogger (BatchInsertPlugin .class );
43+ public static final String METHOD_UPSERT = "upsert" ; // 方法名
44+ public static final String METHOD_UPSERT_SELECTIVE = "upsertSelective" ; // 方法名
45+
46+ /**
47+ * {@inheritDoc}
48+ */
49+ @ Override
50+ public boolean validate (List <String > warnings ) {
51+ // 插件使用前提是targetRuntime为MyBatis3
52+ if (StringUtility .stringHasValue (getContext ().getTargetRuntime ()) && "MyBatis3" .equalsIgnoreCase (getContext ().getTargetRuntime ()) == false ) {
53+ logger .warn ("itfsw:插件" + this .getClass ().getTypeName () + "要求运行targetRuntime必须为MyBatis3!" );
54+ return false ;
55+ }
56+
57+ // 插件使用前提是数据库为MySQL
58+ if ("com.mysql.jdbc.Driver" .equalsIgnoreCase (this .getContext ().getJdbcConnectionConfiguration ().getDriverClass ()) == false ){
59+ logger .warn ("itfsw:插件" + this .getClass ().getTypeName () + "插件使用前提是数据库为MySQL!" );
60+ return false ;
61+ }
62+
63+ return true ;
64+ }
65+
66+ /**
67+ * Java Client Methods 生成
68+ * 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
69+ *
70+ * @param interfaze
71+ * @param topLevelClass
72+ * @param introspectedTable
73+ * @return
74+ */
75+ @ Override
76+ public boolean clientGenerated (Interface interfaze , TopLevelClass topLevelClass , IntrospectedTable introspectedTable ) {
77+ // ====================================== 1. upsert ======================================
78+ Method mUpsert = new Method (METHOD_UPSERT );
79+ // 返回值类型
80+ mUpsert .setReturnType (FullyQualifiedJavaType .getIntInstance ());
81+ // 添加参数
82+ mUpsert .addParameter (new Parameter (introspectedTable .getRules ().calculateAllFieldsClass (), "record" ));
83+ // 添加方法说明
84+ CommentTools .addGeneralMethodComment (mUpsert , introspectedTable );
85+ // interface 增加方法
86+ interfaze .addMethod (mUpsert );
87+ logger .debug ("itfsw(存在即更新插件):" + interfaze .getType ().getShortName () + "增加upsert方法。" );
88+
89+ // ====================================== 2. upsertSelective ======================================
90+ Method mUpsertSelective = new Method (METHOD_UPSERT_SELECTIVE );
91+ // 返回值类型
92+ mUpsertSelective .setReturnType (FullyQualifiedJavaType .getIntInstance ());
93+ // 添加参数
94+ mUpsertSelective .addParameter (new Parameter (introspectedTable .getRules ().calculateAllFieldsClass (), "record" ));
95+ // 添加方法说明
96+ CommentTools .addGeneralMethodComment (mUpsertSelective , introspectedTable );
97+ // interface 增加方法
98+ interfaze .addMethod (mUpsertSelective );
99+ logger .debug ("itfsw(存在即更新插件):" + interfaze .getType ().getShortName () + "增加upsertSelective方法。" );
100+
101+ return true ;
102+ }
103+
104+ /**
105+ * SQL Map Methods 生成
106+ * 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
107+ *
108+ * @param document
109+ * @param introspectedTable
110+ * @return
111+ */
112+ @ Override
113+ public boolean sqlMapDocumentGenerated (Document document , IntrospectedTable introspectedTable ) {
114+
115+ // ====================================== 1. upsert ======================================
116+ XmlElement eleUpsert = new XmlElement ("insert" );
117+ eleUpsert .addAttribute (new Attribute ("id" , METHOD_UPSERT ));
118+ // 添加注释(!!!必须添加注释,overwrite覆盖生成时,@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点,例子:@mbg.generated)
119+ CommentTools .addComment (eleUpsert );
120+
121+ // 参数类型
122+ eleUpsert .addAttribute (new Attribute ("parameterType" , introspectedTable .getRules ().calculateAllFieldsClass ().getFullyQualifiedName ()));
123+
124+ // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
125+ CommTools .useGeneratedKeys (eleUpsert , introspectedTable );
126+
127+ // insert
128+ eleUpsert .addElement (new TextElement ("insert into " + introspectedTable .getFullyQualifiedTableNameAtRuntime ()));
129+ eleUpsert .addElement (this .generateInsertClause (introspectedTable ));
130+ eleUpsert .addElement (new TextElement ("values" ));
131+ eleUpsert .addElement (this .generateValuesClause (introspectedTable ));
132+ eleUpsert .addElement (new TextElement ("on duplicate key update " ));
133+ eleUpsert .addElement (this .generateDuplicateClause (introspectedTable ));
134+
135+ document .getRootElement ().addElement (eleUpsert );
136+ logger .debug ("itfsw(存在即更新插件):" + introspectedTable .getMyBatis3XmlMapperFileName () + "增加upsert实现方法。" );
137+
138+ // ====================================== 2. upsertSelective ======================================
139+ XmlElement eleUpsertSelective = new XmlElement ("insert" );
140+ eleUpsertSelective .addAttribute (new Attribute ("id" , METHOD_UPSERT_SELECTIVE ));
141+ // 添加注释(!!!必须添加注释,overwrite覆盖生成时,@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点,例子:@mbg.generated)
142+ CommentTools .addComment (eleUpsertSelective );
143+
144+ // 参数类型
145+ eleUpsertSelective .addAttribute (new Attribute ("parameterType" , introspectedTable .getRules ().calculateAllFieldsClass ().getFullyQualifiedName ()));
146+
147+ // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
148+ CommTools .useGeneratedKeys (eleUpsertSelective , introspectedTable );
149+
150+ // insert
151+ eleUpsertSelective .addElement (new TextElement ("insert into " + introspectedTable .getFullyQualifiedTableNameAtRuntime ()));
152+ eleUpsertSelective .addElement (this .generateInsertSelectiveClause (introspectedTable ));
153+ eleUpsertSelective .addElement (new TextElement ("values" ));
154+ eleUpsertSelective .addElement (this .generateValuesSelectiveClause (introspectedTable ));
155+ eleUpsertSelective .addElement (new TextElement ("on duplicate key update " ));
156+ eleUpsertSelective .addElement (this .generateDuplicateSelectiveClause (introspectedTable ));
157+
158+ document .getRootElement ().addElement (eleUpsertSelective );
159+ logger .debug ("itfsw(存在即更新插件):" + introspectedTable .getMyBatis3XmlMapperFileName () + "增加upsertSelective实现方法。" );
160+
161+ return true ;
162+ }
163+
164+ /**
165+ * 普通insert
166+ *
167+ * @param introspectedTable
168+ * @return
169+ */
170+ private Element generateInsertClause (IntrospectedTable introspectedTable ){
171+ StringBuilder insertClause = new StringBuilder ();
172+
173+ insertClause .append (" (" );
174+
175+ List <IntrospectedColumn > columns = introspectedTable .getAllColumns ();
176+ for (int i = 0 ; i < columns .size (); i ++) {
177+ IntrospectedColumn introspectedColumn = columns .get (i );
178+
179+ insertClause .append (MyBatis3FormattingUtilities .getEscapedColumnName (introspectedColumn ));
180+
181+ if (i + 1 < columns .size ()) {
182+ insertClause .append (", " );
183+ }
184+ }
185+
186+ insertClause .append (") " );
187+
188+ return new TextElement (insertClause .toString ());
189+ }
190+
191+ /**
192+ * 普通 values
193+ *
194+ * @param introspectedTable
195+ * @return
196+ */
197+ private Element generateValuesClause (IntrospectedTable introspectedTable ){
198+ StringBuilder valuesClause = new StringBuilder ();
199+
200+ valuesClause .append (" (" );
201+
202+ List <IntrospectedColumn > columns = introspectedTable .getAllColumns ();
203+ for (int i = 0 ; i < columns .size (); i ++) {
204+ IntrospectedColumn introspectedColumn = columns .get (i );
205+
206+ valuesClause .append (MyBatis3FormattingUtilities .getParameterClause (introspectedColumn ));
207+ if (i + 1 < columns .size ()) {
208+ valuesClause .append (", " );
209+ }
210+ }
211+
212+ valuesClause .append (") " );
213+
214+ return new TextElement (valuesClause .toString ());
215+ }
216+
217+ /**
218+ * 普通duplicate
219+ *
220+ * @param introspectedTable
221+ * @return
222+ */
223+ private Element generateDuplicateClause (IntrospectedTable introspectedTable ){
224+ StringBuilder duplicateClause = new StringBuilder ();
225+
226+ List <IntrospectedColumn > columns = introspectedTable .getAllColumns ();
227+ for (int i = 0 ; i < columns .size (); i ++) {
228+ IntrospectedColumn introspectedColumn = columns .get (i );
229+
230+ duplicateClause .append (MyBatis3FormattingUtilities .getEscapedColumnName (introspectedColumn ));
231+ duplicateClause .append (" = " );
232+ duplicateClause .append (MyBatis3FormattingUtilities .getParameterClause (introspectedColumn ));
233+
234+ if (i + 1 < columns .size ()) {
235+ duplicateClause .append (", " );
236+ }
237+ }
238+
239+ return new TextElement (duplicateClause .toString ());
240+ }
241+
242+ /**
243+ * 普通insert
244+ *
245+ * @param introspectedTable
246+ * @return
247+ */
248+ private Element generateInsertSelectiveClause (IntrospectedTable introspectedTable ){
249+ XmlElement insertTrimEle = new XmlElement ("trim" );
250+ insertTrimEle .addAttribute (new Attribute ("prefix" , "(" ));
251+ insertTrimEle .addAttribute (new Attribute ("suffix" , ")" ));
252+ insertTrimEle .addAttribute (new Attribute ("suffixOverrides" , "," ));
253+
254+ StringBuffer sb = new StringBuffer ();
255+ for (IntrospectedColumn introspectedColumn : introspectedTable .getAllColumns ()) {
256+
257+ XmlElement insertNotNullElement = new XmlElement ("if" ); //$NON-NLS-1$
258+ sb .setLength (0 );
259+ sb .append (introspectedColumn .getJavaProperty ());
260+ sb .append (" != null" );
261+ insertNotNullElement .addAttribute (new Attribute ("test" , sb .toString ()));
262+
263+ sb .setLength (0 );
264+ sb .append (MyBatis3FormattingUtilities .getEscapedColumnName (introspectedColumn ));
265+ sb .append (',' );
266+ insertNotNullElement .addElement (new TextElement (sb .toString ()));
267+ insertTrimEle .addElement (insertNotNullElement );
268+ }
269+
270+ return insertTrimEle ;
271+ }
272+
273+ /**
274+ * 普通 values
275+ *
276+ * @param introspectedTable
277+ * @return
278+ */
279+ private Element generateValuesSelectiveClause (IntrospectedTable introspectedTable ){
280+ XmlElement valuesTrimEle = new XmlElement ("trim" );
281+ valuesTrimEle .addAttribute (new Attribute ("prefix" , "(" ));
282+ valuesTrimEle .addAttribute (new Attribute ("suffix" , ")" ));
283+ valuesTrimEle .addAttribute (new Attribute ("suffixOverrides" , "," ));
284+
285+ StringBuffer sb = new StringBuffer ();
286+ for (IntrospectedColumn introspectedColumn : introspectedTable .getAllColumns ()) {
287+
288+ XmlElement valuesNotNullElement = new XmlElement ("if" ); //$NON-NLS-1$
289+ sb .setLength (0 );
290+ sb .append (introspectedColumn .getJavaProperty ());
291+ sb .append (" != null" );
292+ valuesNotNullElement .addAttribute (new Attribute ("test" , sb .toString ()));
293+
294+ sb .setLength (0 );
295+ sb .append (MyBatis3FormattingUtilities .getParameterClause (introspectedColumn ));
296+ sb .append (',' );
297+ valuesNotNullElement .addElement (new TextElement (sb .toString ()));
298+ valuesTrimEle .addElement (valuesNotNullElement );
299+ }
300+ return valuesTrimEle ;
301+ }
302+
303+ /**
304+ * 普通duplicate
305+ *
306+ * @param introspectedTable
307+ * @return
308+ */
309+ private Element generateDuplicateSelectiveClause (IntrospectedTable introspectedTable ){
310+ XmlElement duplicateTrimEle = new XmlElement ("trim" );
311+ duplicateTrimEle .addAttribute (new Attribute ("suffixOverrides" , "," ));
312+
313+ StringBuffer sb = new StringBuffer ();
314+ for (IntrospectedColumn introspectedColumn : introspectedTable .getAllColumns ()) {
315+
316+ XmlElement duplicateNotNullElement = new XmlElement ("if" ); //$NON-NLS-1$
317+ sb .setLength (0 );
318+ sb .append (introspectedColumn .getJavaProperty ());
319+ sb .append (" != null" );
320+ duplicateNotNullElement .addAttribute (new Attribute ("test" , sb .toString ()));
321+
322+ sb .setLength (0 );
323+ sb .append (MyBatis3FormattingUtilities .getEscapedColumnName (introspectedColumn ));
324+ sb .append (" = " );
325+ sb .append (MyBatis3FormattingUtilities .getParameterClause (introspectedColumn ));
326+ sb .append ("," );
327+
328+ duplicateNotNullElement .addElement (new TextElement (sb .toString ()));
329+ duplicateTrimEle .addElement (duplicateNotNullElement );
330+ }
331+ return duplicateTrimEle ;
332+ }
333+
334+ }
0 commit comments