J'ai trouvé qu'il est vraiment difficile d'insister pour écrire un blog, et diverses raisons ne feront pas besoin de s'occuper du blog. J'ai initialement prévu d'écrire une implémentation de bricolage d'ORM et de voir l'heure. Je préfère d'abord implémenter un SQL dynamique et ajouter l'implémentation complète d'ORM la prochaine fois que j'aurai le temps.
Les gens qui ont utilisé MyBatis connaissent probablement Dynamic SQL. Si vous ne l'avez pas utilisé, jetez un œil au plaisir. La première fois que je suis entré en contact avec MySQL, c'était quand j'étais dans ma dernière année. À cette époque, je pensais que Dynamic SQL était très génial et flexible. J'ai toujours voulu comprendre comment l'implémenter. Bien que je puisse écrire IOC, MVC et des cadres ORM simples à ce moment-là (imitez les Mybaits mais il n'y a pas de partie SQL dynamique), je n'ai toujours pas trouvé où implémenter le SQL dynamique dans le cœur de MyBatis et comment l'implémenter. Peut-être que le code était trop emmêlé et que je ne pouvais pas le comprendre du tout. Jusqu'à présent, je n'avais pas le courage de lire la partie dynamique SQL de Mybatis. Peut-être que je suis né avec une crainte inexplicable d'algorithmes.
Il y a quelques années, car je voulais créer une plate-forme de configuration et que je voulais utiliser un langage d'analyse pour remplacer l'implémentation Java, qui a permis au personnel de configuration d'écrire facilement une petite quantité de code sur la page pour implémenter une logique métier complexe (y compris les opérations de base de données). À cette époque, Java avait déjà un moteur JS d'analyse, mais la plupart des gens ont dit que l'efficacité était trop faible. Si je ne savais pas de quoi j'étais fou, j'ai pensé à mettre en œuvre moi-même une langue d'analyse. Cependant, j'ai toujours rêvé de réaliser ma propre langue. Il est plus facile de commencer avec les langues analytiques que les langues compilées, alors j'ai commencé à le faire de manière décisive. Après l'avoir écrit, j'ai réalisé que mon implémentation n'est probablement pas aussi efficace que le moteur JS à ce moment-là. À ce moment-là, j'étais vraiment jeune et simple. L'implémentation Dynamic SQL dont je parle aujourd'hui est en fait inspirée par la langue d'analyse à ce moment-là.
Parlons de Dynamic SQL sans dire beaucoup de bêtises. Veuillez consulter l'exemple suivant. Tout d'abord, je déclare que l'exemple ici n'est pas une façon correcte d'écrire SQL. Je veux juste écrire une structure imbriquée aussi complexe que possible. Si cette situation complexe est mise en œuvre, il est encore plus difficile de simplifier les choses.
delete de pl_pagewidget <if test = "widgetcodes! = null"> où pagewidgetcode dans <foreach collection = "widgetcodes" item = "item" index = "index" open = "(" séparateur = "," close = ")"> <if test = " open = "(" séparateur = "," close = ")"> # {b} </foreach> </foreach> </ if> <if test = "a! = null"> et a = # {a} </ if>Pour implémenter SQL pour analyser l'exemple ci-dessus, l'une des difficultés est similaire à la façon de déterminer les conditions vraies ou fausses dans l'attribut de test. Cependant, cette difficulté est plus devant l'expression OGNL apprise dans Struts2. Je ne sais pas si un ami a rencontré un phénomène plutôt étrange, c'est-à-dire, parfois l'expression suivante est écrite dans MyBatis dynamique SQL, mais quand n = 0, elle répond en fait à la condition, c'est-à-dire que la valeur du test est fausse et 0 ne peut pas remplir les conditions de cette expression. C'est la raison de la bibliothèque OGNL. Il n'y a aucun moyen que ça joue comme ça, n'oubliez pas cela comme une situation spéciale
test = "n! = null et n! = ''"
L'expression OGNL est très pratique à utiliser comme suit
Importer java.util.hashmap; import java.util.map; import ognl.ognl; classe publique ognltest {// résultat de sortie: faux public static void main (string [] args) lève une exception {chaîne con1 = "n! = null et n! = ''"; Map <string, object> root = new hashmap <> (); root.put ("n", 0); System.out.println (ognl.getValue (Con1, root)); }}Pour implémenter SQL pour analyser l'exemple ci-dessus, la deuxième difficulté est que bien que ce SQL soit couvert d'une couche de XML, c'est un SQL standard, comme suit
<sql> Delete de PL_PageWidget <if test = "widgetcodes! = null"> où pagewidgetcode dans <foreach collection = "widgetcodes" item = "item" index = "index" open = "(" séparateur = "," close = ")"> <if test = "index == 0"> # # #} </ if> <pour collection = "bs" bs "bs" index = "index1" open = "(" séparateur = "," close = ")"> # {b} </foreach> </ foreach> </ if> <if test = "a! = null"> et a = # {a} </ if> </ql>Cependant, analyser le XML ci-dessus est différent de nos habituels. Ce XML est un mélange de balises et de texte. Normalement, nous devons rarement utiliser l'analyse de ce XML en développement. Cependant, l'outil couramment utilisé pour analyser XML Dom4j peut en fait analyser ce type de SQL, mais il est rarement utilisé. La méthode Content () de la classe d'éléments peut renvoyer une collection de nœuds, puis traverser cette collection et juger le type de chaque nœud. Après avoir résolu ces deux points clés, il vous suffit d'ajouter une petite astuce pour analyser ce SQL dynamique.
L'astuce que j'ai utilisée a été inspirée par le format de syntaxe Java. Par exemple, il existe des variables locales et des variables globales en Java, et la situation de passage de référence n'est pas prise en compte. Si la variable globale int i = 1; La variable globale est transmise dans la méthode puis modifiée dans la méthode. Ce que vous voyez dans la méthode, c'est la valeur modifiée, mais ce que vous voyez en dehors de la méthode est toujours 1. En fait, vous devez connaître ce phénomène après avoir appris Java. De plus, lorsque la méthode est appelée, vous pouvez voir des variables globales et des variables locales dans la méthode. Une fois l'appel de méthode terminé, les variables locales seront effacées et publiées (soyez heureux de voir le collecteur des ordures). Je les ai présentés et ajouté directement le code
Importer java.io.stringReader; import java.text.simpledateformat; import java.util.arrays; import java.util.date; import java.util.map; import java.util.regex.matcher; import java.util.regex.; org.apache.commons.collections.maputils; import org.apache.comons.lang.stringutils; import org.dom4j.document; import org.dom4j.element; import org.dom4j.node; import org.dom4j.text; import org.dom4j.io.saxreader; import com.rd.sql.atrs; com.rd.sql.basenode; import com.rd.sql.nodefactory; classe publique sqlparser {map private <string, objet> currParams = new hashmap <string, objet> (); / ** Supprimer de PL_PageWidget <if test = "widgetcodes! = null"> où pageWidgetCode dans <foreach collection = "widgetcodes" item = "item" index = "index" open = "(" séparator = "," close = ")"> <if test = "item == 0"> # # élément} </ if> <pour la collection = "bs" bs "bs" open = "(" séparateur = "," close = ")"> # {b} </foreach> </foreach> </ if> <if test = "a! = null"> et a = # {a} </ if> * / public static void main (String [] args) lance l'exception {map <string, objet> map = new hashmap <string, objet> ();); map.put ("widgetcodes", arrays.aslist ("1", "2")); map.put ("bs", arrays.aslist ("3", "4")); map.put ("a", 1); SqlParser parser = new sqlParser (); System.out .println (parser.parser ("Supprimer de PL_PageWidget / n" + "/ t <if test = /" widgetcodes! = Null / "> / n" + "/ t / twhere pagewidgetcode in / n" + "/ t / t <ForEach Collection = /" widgetcodes / "item = /" item / "item /" index = "index /" index! séparateur = / ", /" close = / ") /"> / n "+" / t / t <if test = / "index == 0 /"> / n "+" / t / t # {item} / n "+" / t / t </ if> / n "+" / t / t <foreach collection = / "bs /" item = / "b /" index = "index1 /" open = / "" " close = / ") /"> / n "+" / t / t / t # {b} / n "+" / t / t </ foreach> / n "+" / t / t </ foreach> / n "+" / t </ if> / n "+" / t <if test = / "a! = null /"> / n "+" / t / t a = # {a} / n "" / t </ n "+ t / t a = # {a} / n" "/ t </ n". carte)); System.out.println (parser.getParams ()); } Public String Parser (String xml, map <String, Object> Params) lève l'exception {// xml = "<? xml version = /" 1.0 / "Encoding = /" utf-8 / "?>" + xml; // Définissez une couche de balises XML pour la dynamique d'entrée sql xml = "<sql>" + xml + "</ql>"; SAXREDER Reader = new saxReader (false); Document document = reader.read (new StringReader (xml)); Élément élément = document.getRootelement (); Map <string, objet> currParams = new HashMap <String, objet> (); StringBuilder sb = new StringBuilder (); // Démarrer PARSERELlement (élément, CurrParams, Params, SB); return sb.toString (); } / ** * Utiliser l'analyseur récursif pour analyser dynamique sql * @param ele1 tag xml à analyser * @param currparams * @param globalparams * @param sb * @throws exception * / private void parserelement (élément ele1, map <string, objet> curparams, map <string, objet> globalParams, stringbuilder SB) Analyser un nœud, par exemple, analyser un nœud si, si le test détermine true, il renvoie true. Tempval Val = ParseroneElement (CurrParams, GlobalParams, Ele1, SB); // L'objet Node abstrait du nœud analysé Basenode Node = val.getNode (); / ** * En fait, l'instruction au-dessus de cette phrase analyse uniquement la balise XML et n'analyse pas le contenu dans la balise. Ici * signifie qu'avant d'analyser le contenu, s'il y a une préopération, faites une préopération * / node.pre (CurrParams, GlobalParams, Ele1, SB); // Défendez-vous si le contenu dans le nœud doit encore être analysé, par exemple, si le résultat du test est un vrai drapeau booléen = val.iscontinue (); // Obtenez une collection de tous les nœuds enfants sous ce nœud, y compris la liste de texte normale <NODE> NODES = ele1.Content (); if (flag &&! nœuds.isempty ()) {/ ** * Cela signifie que vous souhaitez analyser davantage le contenu dans le nœud. Vous pouvez comparer le nœud dans le shell d'une méthode * Le contenu à l'intérieur est analogue aux instructions spécifiques de la méthode. Avant de commencer à analyser le contenu du nœud * Créez un conteneur avec des paramètres locaux sous ce nœud. Le plus pratique est bien sûr map * / map <string, object> params = new hashmap <string, object> (); / ** * Mettez les paramètres locaux passés à l'extérieur directement dans le conteneur, car les paramètres de cet exemple sont des types de données courants * Il n'y aura pas de type de référence, donc cela équivaut à une copie. Afin de ne pas affecter l'objet passé à l'extérieur *, vous pouvez comparer le cas où la méthode appelle les paramètres entrants * / params.putall (currParams); // Loucle tous les nœuds enfants pour (int i = 0; i <nœuds.size ();) {nœud n = nœuds.get (i); // Si le nœud est un texte normal if (n instanceof text) {String text = ((texte) n) .getStringValue (); if (stringUtils.isnotempty (text.trim ())) {// entraîner le texte, tel que le traitement # {xx}, remplace directement $ {yy} par la valeur réelle transmise dans sb.append (HandText (texte, params, globalParams)); } i ++; } else if (n instanceof élément) {élément e1 = (élément) n; // analyse récursivement les éléments enfants XML PARSERELlement (E1, Params, GlobalParams, SB); // Si l'indicateur de boucle n'est pas vrai, analysez la balise suivante // Cela signifie que vous devez analyser à plusieurs reprises la balise de boucle, alors je ne changerai pas, sinon continuer à traiter l'élément suivant booléen while_flag = maputils.getboolean (params, attributs.Thile_flag, false); if (! while_flag ||! nodefactory.is what (n.getName ()) || e1.attributeValue (att.Index) == null ||! e1.attributeValue (att.index) .equals (params.get (att. WHIT_INDEX))) {i ++; }}} // Que dois-je faire après le traitement du nœud Node.After (CurrParams, GlobalParams, Ele1, SB); // recycler le paramètre de portée actuel paramètre.Clear (); params = null; }} / ** * Processus Texte pour remplacer le paramètre # {item} * @param str * @param params * @return * @throws exception * / private String HandText (String str, map <string, object> params, map <string) lance exception {// obtient la chaîne variable indexStr = maputils.getString (params, attributs. Index entier = null; if (stringUtils.isnotempty (indexstr)) {index = maputils.getInteger (params, indexstr); } // correspond # {a} String de paramètre reg1 = "(# // {) (// w +) (//})"; // correspond au paramètre de $ {a} string reg2 = "(// $ // {) (// w +) (//})"; Modèle P1 = Pattern.Compile (Reg1); Matcher M1 = P1.Matcher (STR); Pattern p2 = motif.compile (reg2); Matcher M2 = P2.Matcher (Str); Chaîne whileList = maputils.getString (params, att. While_list); Map <string, objet> allParams = getAllParams (params, globalParams); while (m1.find ()) {string tmpkey = m1.group (2); String key = whileList == null? Tmpkey: (whileList + "_" + tmpkey); key = index == null? key: (key + index); String rekey = "# {" + key + "}"; // Si dans une boucle similaire à ForEach, vous devrez peut-être remplacer le paramètre # {xx} par # {xx_0}, # {xx_1} str = str.replace (m1.group (0), rekey); currParams.put (key, allparams.get (tmpkey)); } while (m2.find ()) {string tmpkey = m2.group (2); Valeur d'objet = AllParams.get (tmpkey); if (valeur! = null) {str = str.replace (m2.group (0), getValue (valeur)); }} return str; } String privé getValue (Valeur d'objet) {String result = ""; if (valeur instanceof date) {SimpledateFormat sdf = new SimpledateFormat ("yyyy-mm-dd hh: mm: ss"); result = sdf.format ((date) value); } else {result = string.valueof (valeur); } Retour Résultat; } Private Map <String, objet> getAllParams (map <string, objet> currParams, map <string, objet> globalParams) {map <string, object> allparams = new hashmap <string, object> (); AllParams.putall (GlobalParams); AllParams.putall (CurrParams); retourner AllParams; } // analyse un élément xml privé tempval parserOneelement (map <string, object> currParams, map <string, object> globalParams, element ele, stringBuilder sb) lève exception {// obtenir le nom de balise xml string elename = ele.getname (); // Continue-t-il après l'analyse d'un nœud? Si vous rencontrez un nœud comme si, vous devez déterminer si le test est vide. booléen isContinue = false; // Déclare un nœud abstrait Basenode Node = NULL; if (stringUtils.isnotempty (eLename)) {// Utilisez l'usine de nœuds pour obtenir un objet de nœud basé sur le nom de nœud, comme si le nœud ou foreach node node = nodefactory.create (eLename); // Analyser ce nœud et renvoyer si le contenu du nœud doit encore être analysé isContinue = node.parse (CurrParams, GlobalParams, Ele, SB); } return new tempval (isContinue, ele, nœud); } Public Map <String, objet> getParams () {return CurrParams; } / ** * Encapsulez le résultat après qu'un élément XML est analysé * @author rongdi * / classe statique finale tempval {private booléen isContinue; élément privé Ele; Node privé de Basenode; public tempval (booléen iscontinue, élément ele, nœud basenode) {this.iscontinue = isContinue; this.ele = ele; this.node = node; } public boolean isContinue () {return isContinue; } public void setContinue (boolean isContinue) {this.iscontinue = isContinue; } élément public getele () {return ele; } public void selele (élément ele) {this.ele = ele; } public basenode getNode () {RETOUR NODE; } public void setNode (Basenode Node) {this.node = node; }}} import org.dom4j.element; import java.util.hashmap; import java.util.map; / ** * nœud abstrait * @author rongdi * / public abstrait class basenode {public abstrait booléan parse (map <string, objet> currparams, map <string, objet> globalparams, élément ele, stringbuilder sb) public void pre (map <string, objet> currparams, map <string, objet> globalParams, element ele, stringbuilder sb) lève exception {} public void after (map <string, object> currparams, map <string> GlobalParams, element ele, stringbuilder sb) lance un {} map <string, objet> objet> getAllParams (map <strimber> Map <string, objet> globalParams) {map <string, objet> allparams = new hashmap <string, object> (); AllParams.putall (GlobalParams); AllParams.putall (CurrParams); retourner AllParams; }} Importer java.util.map; import ognl.ognl; import org.apache.commons.lang.stringutils; import org.dom4j.element; / ** * si nœud * @author rongdi * / public class ifnode étend Basenode {@Override public parse (map <string, objet> curparams, maph, maph, globalSara ele, stringBuilder sb) lève une exception {// obtenir l'attribut de test de si nœud string testStr = ele.attributeValue ("test"); Test booléen = false; try {if (stringUtils.isnotempty (teststr)) {// fusionner les variables globales et les variables locales map <string, objet> allparams = getAllParams (currParams, globalParams); // Utilisez OGNL pour déterminer le test vrai ou faux = (boolean) ognl.getValue (teststr, allparams); }} catch (exception e) {e.printStackTrace (); Jetez une nouvelle exception ("Paramètres de fonctionnement du juge" + TestStr + "illégal"); } if (ele.content ()! = null && ele.content (). size () == 0) {test = true; } test de retour; }} import java.util.arraylist; import java.util.hashmap; import java.util.list; import java.util.map; import java.util.set; import ognl.ognl; import org.apache.commons.collections.maputils; import org.apache.commons.lang.stringutils; import; org.dom4j.element; / ** Les attributs du nœud foreach sont les suivants l'élément de collecte qui doit être traversé. L'indice de variable stocké dans chaque élément après avoir traversé la collection. Le numéro d'index de la collection est tel que 0, 1, 2 ... séparateur après traversant, épissant l'ouverture avec un séparateur spécifié. Les symboles qui commencent l'épissage après la traversée sont les suivants (fermez les symboles qui terminent l'épissage après la traversée sont les suivants) * / classe publique ForEachNode étend Basenode {@Override public Boolean Parse (Map <String, objet> Currparams, Map <String, objet> GlobalParams, élément Ele, StringBuilder SB) Loul Exception {String ConditionStr = Null; String CollectionTr = ele.AttributeValue ("Collection"); String itemStr = ele.attributeValue ("item"); String index = ele.attributeValue ("index"); String séparateursTr = ele.AttributeValue ("séparateur"); String openstr = ele.AttributeValue ("Open"); String CloserStr = ele.AttributeValue ("close"); if (stringUtils.isempty (index)) {index = "index"; } if (stringUtils.isempty (séparatorstr)) {séparatorstr = ","; } if (stringUtils.isnotempty (openstr)) {currParams.put (att. While_Open, openstr); } if (stringUtils.isnotempty (Closerstr)) {currParams.put (att. WHIP_CLOSE, CLOSTRER); } if (stringUtils.isnotempty (collectiontr)) {currParams.put (attr. while_list, collectiontr); } currParams.put (att. While_separator, séparatorstr); if (index! = null) {/ ** * S'il y a la valeur de la variable de boucle actuelle dans la variable locale, cela signifie que ce n'est pas la première fois que vous entrez l'étiquette de boucle. Supprimez la balise de démarrage * et ajoutez 1 à la valeur de variable locale * / if (currParams.get (index)! = Null) {currParams.remove (att. While_start); currParams.put (index + "_", (entier) currParams.get (index + "_") + 1); } else {// La première fois que vous entrez dans l'étiquette de boucle currParams.put (att. While_start, true); currParams.put (index + "_", 0); } currParams.put (index, (entier) currParams.get (index + "_")); } condition booléenne = true; Map <string, objet> allParams = getAllParams (currParams, globalParams); Collection d'objets = null; if (stringUtils.isnotempty (collectiontr)) {// Obtenez la collection collection en boucle = ognl.getValue (collectiontr, allParams); // Si la propriété de collection n'est pas vide, mais la condition est nul, une condition aux limites est ajoutée par défaut si (stringUtils.isempty (conditionstr)) {// je vais simplement utiliser une collection pour le démontrer. Vous pouvez également ajouter un tableau, mais il suffit de le modifier en .Length if (Collection instanceof list) {conditionstr = index + "_ <" + Collectionstr + ". Size ()"; } else if (Collection instanceof map) {map map = (map) Collection; Set set = map.entryset (); List list = new ArrayList (set); allparams.put ("_ list_", list); conditionstr = index + "_ <_ list _" + ". size ()"; }}} currParams.remove (attrs.Thile_end); if (stringUtils.isnotempty (conditionstr)) {// la valeur de la condition de calcul condition = (boolean) ognl.getValue (conditionstr, allparams); Map <string, object> tempmap = new hashmap <> (); tempmap.putall (AllParams); tempmap.put (index + "_", (entier) currParams.get (index + "_") + 1); currParams.put (att. While_end ,! (boolean) ognl.getValue (conditionstr, tempmap)); } booléen drapeau = true; currParams.put (att. While_index, index); currParams.put (att. WHIP_FLAG, true); if (condition) {try {if (stringUtils.isnotempty (itemStr) && stringUtils.isnotempty (collectiontr)) {object value = null; int idx = Integer.ParseInt (currParams.get (index + "_"). toString ()); if (Collection instanceOf list) {value = ((list) collection) .get (idx); currParams.put (itemstr, valeur); } else if (Collection instanceof map) {map map = (map) Collection; Set <map.entry <string, objet >> set = map.entryset (); List <map.entry <string, objet >> list = new ArrayList (set); currParams.put (itemStr, list.get (idx) .getValue ()); currParams.put (index, list.get (idx) .getKey ()); }}} catch (exception e) {lancer une nouvelle exception ("obtenir la valeur d'une collection ou une carte" + currParams.get (index) + "error" + e.getMessage ()); }} else {flag = false; Destroyvars (CurrParams, index, itemstr); } drapeau de retour; } / ** * Si c'est la première fois que vous entrez dans la balise de boucle, épelez le contenu d'Open * / @Override public void pre (map <String, Object> CurrParams, Map <String, Object> GlobalParams, Element ele, StringBuilder SB) lance l'exception; booléen start = maputils.getboolean (currParams, attrs.Thile_start, false); if (start) {string open = maputils.getString (currParams, att. WHIP_OPEN); SB.APPEND (ouvert); }} / ** * Si l'étiquette de boucle est enfin entrée, le contenu de Close est orthographié à la fin * / @Override public void after (map <String, object> currparams, map <string, object> globalparams, element ele, stringbuilder sb) lance l'exception {super.after (Curparams, GlobalParams, Ele, SB); booléen end = maputils.getboolean (currParams, att. the-them_end, false); String séparateur = maputils.getString (currParams, attrs.Thile_separator); if (! end && stringUtils.isnotempty (séparateur)) {sb.append (séparateur); } if (end) {String close = maputils.getString (currParams, attrs. While_close); if (sb.toString (). Endswith (séparateur)) {sb.deletecharat (sb.length () - 1); } sb.append (close); }} // Libérez la variable temporaire privée void destrustvars (map <string, objet> currParams, String index, String varstr) {currParams.remove (attrs. While_index); currParams.remove (attrs.Thile_flag); currParams.remove (attrs.Thile_separator); currParams.remove (att. While_start); currParams.remove (att. While_end); currParams.remove (att. While_list); }} import org.dom4j.element; import java.util.map; classe publique Sqlnode étend Basenode {@Override public booléen parse (map <string, objet> currparams, map <string, objet> globalParams, élément ele, stringbuilder sb) lance l'exception {return true; }} import java.util.arrays; import java.util.list; import java.util.map; import java.util.concurrent.concurrenthashmap; / ** * nœud usine * / public class nodefactory {map static privé <string, basenode>; Liste statique finale privée <string> whileList = arrays.aslist ("foreach"); statique {nodemap.put ("if", new ifnode ()); nodemap.put ("sql", new sqlNode ()); nodemap.put ("foreach", new foreachNode ()); } public static boolean is wrand (string elementName) {return whileList.contains (elementName); } public static void addNode (String NodeName, Basenode Node) {nodeMap.put (NodeName, Node); } public static basenode create (string nodeName) {return nodemap.get (nodeName); }} / ** * Divers balises * @author rongdi * / classe publique attrs {public final static String transactional = "transactional"; chaîne statique finale publique while_start = "while-start"; chaîne statique finale publique while_end = "while-end"; chaîne statique finale publique while_open = "while-open"; chaîne statique finale publique while_close = "while-close"; chaîne statique finale publique while_separator = "while-separator"; chaîne statique finale publique while_index = "while-index"; chaîne statique finale publique while_flag = "while-fllag"; chaîne statique finale publique while_list = "while-list"; chaîne statique finale publique quand_flag = "quand-fllag"; public static final String process_var = "process-var"; public final static String result_flag = "result-fllag"; public final static String return_flag = "return-fllag"; public final static String console_var = "console-var"; Public Final Static String Do = "DO"; index de chaîne statique finale publique = "index"; Public Final Static String condition = "Condition"; public final static String name = "name"; Valeur de chaîne statique finale publique = "valeur"; public statique final String type = "type"; public statique final String format = "format"; chaîne finale statique publique si = "if"; String final statique publique Else = "else"; public final static String file = "file"; Public statique final String Date = "Date"; String final statique publique maintenant = "Now"; public static final string décimal = "décimal"; public statique final string id = "id"; public static final String params = "params"; public static final String Target = "Target"; public static final string single = "single"; Public Static Final String Paging = "Paging"; String final statique publique desc = "desc"; Public statique final final String Break = "Break"; String final statique publique continue = "Continuer"; COLLECTION PUBLIQUE STATIQUE STATIQUE STRATIQUE = "Collection"; String final statique publique var = "var"; public static final String exécutor = "exécutor-1"; public static final string rollback_flag = "rollback-fllag"; public static final String Service = "Service"; public statique final string ref = "ref"; public statique final String bizs = "bizs"; public static final string titres = "titres"; public statique final String colonnes = "colonnes"; String final statique publique currusen = "curruse"; String final statique publique currperm = "currperm"; public static final string task_executor = "taskexecutor"; public statique final String Delimiter = "Delimiter"; public static final String opername = "opername"; } currParams.remove (varstr); currParams.remove (index); currParams.remove (index + "_"); }}Joindre le fichier POM
<project xmlns = "http://maven.apache.org/pom/4.0.0" xmlns: xsi = "http://www.w3.org/2001/xmlschema-instance" xsi: schemalation = "http://maven.apache.org/pom/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd "> <ModelVersion> 4.0.0 </ ModelVersion> <ProupId> com.rd </rom grouped> <Artifactid> PARSER </ ARTIFACTID> <MAPPORMO <url> http://maven.apache.org </url> <dépendances> <dependency> <proupId> Dom4j </proncId> <ArtifActid> Dom4j </ artifactid> <version> 1.6.1 </ version> </ dépendance> <dependency> <proupId> opensymphony </proupId> <ArtifActid> ognl </ artifact> <version> 2.6.11 </ version> </ dépendance> <dependency> <proupId> Commons-Collections </rom groupeid> <lefactId> Commons-Collections </ Artifactid> <Dersion> 3.2.1 </ Version> </ Dependency> <Dedency> <ProupId> Commons-Lang </proupId> </ Version> </pteridence> Comons-Lang </ ArtifActid> <dependency> <proupId> JUnit </rom grouped> <ArtefactId> JUnit </ artifactId> <DERSE> 3.8.1 </ version> <ccope> Test </ccope> </ Dependency> </ Dependency> </Dependces> <Duild> <Sesource> <SercecE> <Derendency> <Affinet> Src / Main / Java </cluctory> <rupture> <clude>> <clude>> <clustrac </clure> </ Resource> <Resource> <Arnutory> SRC / Main / Resources </ Directory> <clustr> <clust> ** / * </ include> </source> </sessherse> </sestResources> <SestResources> <SestResource> <Areamory> $ {project.basedir} / src / test / java </ingory> <Archalcythiscortif> $ {project.basedir} / src / test / ressources </ répertoire> </ testResource> </SestResources> <Glugins> <ProupId> org.apache.maven.plugins </prougId> <Ertifactid> Maven-Compiler-Plugin </Rifactid> <version> 3.1 </DERNIONDATION> <Barget> 1.8 </ Target> <encoding> UTF-8 </coding> </FIGIGRUend> </gingin> </Glugins> </Duild> </ Project>La méthode ci-dessus pour implémenter MyBatis Dynamic SQL par vous-même est tout le contenu que j'ai partagé avec vous. J'espère que vous pourrez vous faire référence et j'espère que vous pourrez soutenir Wulin.com plus.