لقد وجدت أنه من الصعب حقًا الإصرار على كتابة مدونة ، ولن تؤدي الأسباب المختلفة إلى عدم الحاجة إلى رعاية المدونة. لقد خططت في الأصل لكتابة تنفيذ DIY لـ ORM ورؤية الوقت. أفضل تنفيذ SQL ديناميكي أولاً وإضافة التنفيذ الكامل لـ ORM في المرة القادمة التي لديّ وقت.
الأشخاص الذين استخدموا MyBatis ربما يكونون على دراية بـ SQL الديناميكي. إذا لم تستخدمه ، فما عليك سوى إلقاء نظرة على المرح. كانت المرة الأولى التي تتواصل فيها مع MySQL عندما كنت في سنتي العليا. في ذلك الوقت ، اعتقدت أن Dynamic SQL كانت رائعة ومرنة للغاية. كنت أرغب دائمًا في معرفة كيفية تنفيذها. على الرغم من أنني أستطيع كتابة IOC و MVC وأطر ORM البسيطة في ذلك الوقت (تقليد myBaits ولكن لا يوجد جزء ديناميكي SQL) ، ما زلت لا أستطيع العثور على مكان تنفيذ SQL الديناميكي في قلب MyBatis وكيفية تنفيذه. ربما كان الكود متشابكًا جدًا ولم أستطع فهمه على الإطلاق. حتى الآن ، لم يكن لدي الشجاعة لقراءة جزء SQL الديناميكي من MyBatis. ربما ولدت مع الرهبة التي لا يمكن تفسيرها من الخوارزميات.
قبل بضع سنوات ، لأنني أردت إنشاء منصة تكوين وأردت استخدام لغة التحليل لاستبدال تطبيق Java ، مما سمح لموظفي التكوين بكتابة كمية صغيرة من التعليمات البرمجية بسهولة على الصفحة لتنفيذ منطق العمل المعقد (بما في ذلك عمليات قاعدة البيانات). في ذلك الوقت ، كان لدى Java بالفعل محرك تحليل JS ، لكن معظم الناس قالوا إن الكفاءة كانت منخفضة للغاية. إذا لم أكن أعرف ما الذي كنت مجنونة ، فكرت في تنفيذ لغة التحليل بنفسي. ومع ذلك ، لطالما حلمت بتحقيق لغتي الخاصة. من الأسهل البدء باللغات التحليلية من اللغات المترجمة ، لذلك بدأت في القيام بذلك بشكل حاسم. بعد كتابتها ، أدركت أن تنفيذي ربما لا يكون فعالًا مثل محرك JS في ذلك الوقت. في ذلك الوقت ، كنت شابًا وبسيطًا حقًا. إن تطبيق SQL الديناميكي الذي أتحدث عنه اليوم مستوحى بالفعل من لغة التحليل في ذلك الوقت.
دعونا نتحدث عن SQL الديناميكي دون أن نقول الكثير من الهراء. يرجى الاطلاع على المثال التالي. أولاً ، أعلن أن المثال هنا ليس طريقة صحيحة لكتابة SQL. أريد فقط أن أكتب هيكلًا متداخلًا معقدًا قدر الإمكان. إذا تم تنفيذ هذا الموقف المعقد ، فمن الصعب جعله بسيطًا.
حذف من pl_pageWidget <if test = "widgetCodes! = null"> حيث pageWidGetCode في <foreach collection = "widgetCodes" item = "item" index = "index" open = "(" deplator = "،" extra = ") open = "(" sepanator = "،" elut = ")"> #{b} </foreach> </foreach> </fort> <if test = "a! = null"> و a = #{a} </ff>لتنفيذ SQL لتحليل المثال أعلاه ، تشبه إحدى الصعوبات كيفية تحديد الشروط الحقيقية أو الخاطئة في سمة الاختبار. ومع ذلك ، فإن هذه الصعوبة هي أكثر أمام تعبير ognl المستفادة في Struts2. لا أعرف ما إذا كان أحد الأصدقاء قد واجه ظاهرة غريبة إلى حد ما ، أي في بعض الأحيان يتم كتابة التعبير التالي في MyBatis Dynamic SQL ، ولكن عندما يكون n = 0 ، فإنه يفي بالشرط بالفعل ، أي ، القيمة في الاختبار خاطئة ، ولا يمكن أن تلبي 0 شروط هذا التعبير. هذا هو سبب مكتبة ognl. لا توجد طريقة تلعب مثل هذا فقط ، فقط تذكرها كوضع خاص
test = "n! = null and n! = ''"
تعبير ognl مناسب جدًا للاستخدام على النحو التالي
استيراد java.util.hashmap ؛ استيراد java.util.map ؛ استيراد ognl.ognl ؛ الفئة العامة ognltest {// النتيجة الناتجة: الفراغ العام الخاطئة (سلسلة [] args) يلقي الاستثناء {String con1 = "n! = null and n! = ''" ؛ خريطة <string ، object> root = new HashMap <> () ؛ root.put ("n" ، 0) ؛ system.out.println (ognl.getValue (con1 ، root)) ؛ }}لتنفيذ SQL لتحليل المثال أعلاه ، فإن الصعوبة الثانية هي أنه على الرغم من أن هذا SQL مغطى بطبقة من XML ، إلا أنه SQL قياسي ، على النحو التالي
<sql> حذف من pl_pageWidget <if test = "widgetCodes! = null"> حيث pageWidgetCode في <foreach collection = "widgetcodes" item = "item" index = "index" "open =" "learator =" ، "bs =") index = "index1" open = "(" deplator = "،" close = ")"> #{b} </foreach> </foreach> </fort> <if test = "a! = null"> و A = #{a} </ff> </sql>ومع ذلك ، فإن تحليل XML أعلاه يختلف عن تلك المعتادة. XML هذا هو مزيج من العلامات والنص. عادة ، نادراً ما نستخدم تحليل هذا XML في التطوير. ومع ذلك ، فإن الأداة الشائعة الاستخدام لتحليل XML DOM4J يمكنها بالفعل تحليل هذا النوع من SQL بشكل جيد للغاية ، ولكن نادراً ما يتم استخدامه. يمكن أن تُرجع طريقة المحتوى () لفئة العناصر مجموعة من العقد ، ثم اجتياز هذه المجموعة والحكم على نوع كل عقدة. بعد حل هاتين النقطتين الرئيسيتين ، تحتاج فقط إلى إضافة خدعة صغيرة لتحليل هذا SQL الديناميكي.
كانت الحيلة التي استخدمتها مستوحاة من تنسيق بناء جملة Java. على سبيل المثال ، هناك متغيرات محلية ومتغيرات عالمية في Java ، ولا يتم النظر في حالة المرور المرجعي. إذا كان المتغير العالمي int i = 1 ؛ يتم تمرير المتغير العالمي في الطريقة ثم تعديلها في الطريقة. ما تراه في هذه الطريقة هو القيمة المتغيرة ، ولكن ما تراه خارج الطريقة لا يزال 1. في الواقع ، يجب أن تعرف هذه الظاهرة بعد تعلم Java. أيضًا ، عندما يتم استدعاء الطريقة ، يمكنك رؤية المتغيرات العالمية والمتغيرات المحلية في هذه الطريقة. بعد الانتهاء من استدعاء الطريقة ، سيتم مسح المتغيرات المحلية وإصدارها (يرجى أن تكون سعيدًا برؤية جامع القمامة). لقد قدمت هذه وأضفت الكود مباشرة
استيراد java.io.stringreader org.apache.commons.collections.maputils ؛ استيراد org.apache.commons.lang.stringutils ؛ استيراد org.dom4j.document ؛ استيراد org.dom4j.element ؛ import org.dom4j.node com.rd.sql.basenode ؛ import com.rd.sql.nodefactory ؛ public class sqlparser {private map <string ، object> currparams = new hashmap <string ، Object> () ؛ /** حذف من pl_pageWidget <if test = "widgetCodes! = null"> حيث pageWidgetCode في <foreach collection = "widgetCodes" item = "item" index = "index" open = "(" separator = "،" extress = ") open = "(" sepanator = "،" elut = ")"> #{b} </foreach> </foreach> </fort> <if test = "a! = null"> و a = #{a} </frick> */public static void main (string) args stisply {map <string ، object> map = new alshmap <string> () ؛ map.put ("widgetcodes" ، arrays.aslist ("1" ، "2")) ؛ map.put ("bs" ، arrays.aslist ("3" ، "4")) ؛ map.put ("A" ، 1) ؛ sqlparser parser = جديد sqlparser () ؛ system.out .println (parser.parser ("حذف من pl_pageWidget/n" + "/t <if test =/" widgetcodes! = null/">/n" + "/t/twwere pagewidgetcode in/n" + "/t <foreach collection =/" widgetcodes/"item = فاصل =/"،/" إغلاق =/")/">/n " +"/t/t <test =/"index == 0/">/n " +"/t/t #{item}/n " +"/t/t </s>/n alware =/")/">/n " +"/t/t/t #{b}/n " +"/t/t </foreach>/n " +"/t/t </foreach>/n " +"/t </if>/n " +"/t <test =/"a! خريطة)) ؛ System.out.println (parser.getParams ()) ؛ } سلسلة متقلبة (سلسلة XML ، خريطة <سلسلة ، كائن> params) يلقي الاستثناء {// xml = "<؟ // قم بتعيين طبقة من علامات XML للإدخال Dynamic SQL XML = "<SQL>"+XML+"</sql>" ؛ قارئ SaxReader = New SaxReader (false) ؛ وثيقة المستند = reader.read (stringReader New StringReader (XML)) ؛ element element = document.getRootElement () ؛ خريطة <سلسلة ، كائن> currparams = new hashmap <string ، Object> () ؛ StringBuilder sb = new StringBuilder () ؛ // ابدأ التحليل (العنصر ، currparams ، params ، sb) ؛ إرجاع sb.tostring () ؛ } /** * استخدم محللًا متكررًا لتحليل Dynamic SQL * param ele1 xml tag ليتم تحليله * param currparams * param globalparams * @param sb * @throws استثناء * /private void) تحليل العقدة ، على سبيل المثال ، تحليل IF IF ، إذا كان الاختبار يحدد صحيح ، فإنه يعود صحيح. tempval val = parseroneElement (currparams ، GlobalParams ، ELE1 ، SB) ؛ // كائن العقدة المجردة للعقدة Basenode Node = Val.GetNode () ؛ /*** في الواقع ، فإن العبارة أعلاه هذه الجملة لا تؤدي إلا إلى تحليل علامة XML ولا يحلل المحتوى في العلامة. هنا * يعني أنه قبل تحليل المحتوى ، إذا كان هناك ما قبل التشغيل ، فقم ببعض الأداء المسبق */ node.pre (currparams ، GlobalParams ، ELE1 ، SB) ؛ // الدفاع عن ما إذا كان المحتوى في العقدة لا يزال بحاجة إلى تحليل ، على سبيل المثال ، إذا كانت نتيجة الاختبار هي العلم المنطقي الحقيقي = val.iscontinue () ؛ // احصل على مجموعة من جميع العقد الفرعية تحت هذه العقدة ، بما في ذلك القائمة النصية العادية <Node> nodes = ele1.content () ؛ if (flag &&! nodes.isempty ()) { /*** هذا يعني أنك تريد أن تزيد من تحليل المحتوى في العقدة. يمكنك مقارنة العقدة في قشرة الطريقة* المحتوى في الداخل مماثل للبيانات المحددة في الطريقة. قبل البدء في تحليل محتوى العقدة* قم بإنشاء حاوية مع معلمات محلية تحت هذه العقدة. الأكثر ملاءمة هو بالطبع خريطة */ خريطة <سلسلة ، كائن> params = new hashmap <string ، Object> () ؛ /*** ضع المعلمات المحلية التي تم تمريرها في الخارج مباشرة في الحاوية ، لأن المعلمات في هذا المثال هي أنواع البيانات الشائعة* لن يكون هناك نوع مرجعي ، لذلك يعادل نسخة. من أجل عدم التأثير على الكائن الذي تم تمريره في الخارج*، يمكنك مقارنة الحالة التي تستدعي فيها الطريقة المعلمات الواردة*/ params.putall (currparams) ؛ // حلقة جميع العقد الفرعية لـ (int i = 0 ؛ i <nodes.size () ؛) {node n = nodes.get (i) ؛ // إذا كانت العقدة نصًا عاديًا إذا كان (n stietyof text) {string text = ((text) n) .getStringValue () ؛ if (stringUtils.isnotempty (text.trim ())) {// تدريب النص ، مثل معالجة #{xx} ، استبدل مباشرة $ {yy} بالقيمة الحقيقية التي تم تمريرها في sb.append (handtext (text ، params ، globalparams)) ؛ } i ++ ؛ } else if (n eastyof element) {element e1 = (element) n ؛ // متكرر عناصر XML Child Elements (E1 ، Params ، GlobalParams ، SB) ؛ // إذا لم تكن علامة الحلقة صحيحة ، فاجعل العلامة التالية // هذا يعني أنك بحاجة إلى تحليل علامة الحلقة بشكل متكرر ، فلن أتغير بشكل متكرر ، وإلا أتابع معالجة العنصر التالي Boolean While_flag = maputils.getBoolean (params ، attrs.while_flag ، false) ؛ if (! while_flag ||! nodefactory.iswhile (n.getName ()) || e1.attributeValue (attrs.index) == null ||! e1.attributeValue (attrs.index) .equals (params.get (attrs.while_index))) {i ++ ؛ }}} // ما الذي يجب أن أفعله بعد معالجة العقدة. // إعادة تدوير المعلمة النطاق الحالية params.clear () ؛ params = null ؛ }} /** * نص معالجة لاستبدال المعلمة #{item} * param str * param params * @return * @throws استثناء * /private string handtext (string str ، map <string ، object> params ، map <string ، object> globalparams) revision {// get indexstr indexstr = mapuTiLsTring (params ، attr.hile -whysle. فهرس عدد صحيح = فارغ ؛ if (stringUtils.isNotEmpty (indexTr)) {index = mapUtils.getInteger (params ، indexTr) ؛ } // match #{a} parameter string reg1 = "( #// {) (// w+) (//})" ؛ // تطابق معلمة $ {a} string reg2 = "(// $ // {) (// w+) (//})" ؛ نمط p1 = pattern.compile (Reg1) ؛ Matcher M1 = P1.Matcher (Str) ؛ نمط p2 = pattern.compile (reg2) ؛ Matcher M2 = p2.matcher (str) ؛ سلسلة whilelist = mapUtils.getString (params ، attrs.while_list) ؛ الخريطة <string ، Object> allParams = getAllParams (params ، GlobalParams) ؛ بينما (m1.find ()) {string tmpkey = m1.group (2) ؛ مفتاح السلسلة = whiLelist == null؟ tmpkey: (whiLelist+"_"+tmpkey) ؛ KEY = index == null؟ key: (key+index) ؛ String rekey = "#{"+key+"}" ؛ // إذا كان في حلقة مماثلة لـ Foreach ، فقد تحتاج إلى استبدال المعلمة #{xx} بـ #{xx_0} ، #{xx_1} str = str.replace (m1.group (0) ، rekey) ؛ currparams.put (key ، allparams.get (tmpkey)) ؛ } بينما (m2.find ()) {string tmpkey = m2.group (2) ؛ قيمة الكائن = allparams.get (tmpkey) ؛ if (value! = null) {str = str.replace (m2.group (0) ، getValue (value)) ؛ }} return str ؛ } سلسلة خاصة getValue (قيمة الكائن) {String result = "" ؛ if (value exateof date) {simpleDateFormat sdf = new SimplEdateFormat ("yyyy-mm-dd hh: mm: ss") ؛ النتيجة = sdf.format ((التاريخ) القيمة) ؛ } آخر {result = string.valueof (value) ؛ } نتيجة الإرجاع ؛ } الخريطة الخاصة <string ، Object> getAllParams (Map <String ، Object> currparams ، Map <String ، Object> GlobalParams) {Map <String ، Object> allParams = new HashMap <String ، Object> () ؛ allparams.putall (GlobalParams) ؛ allparams.putall (currparams) ؛ إعادة allparams. }. // هل تستمر بعد تحليل العقدة؟ إذا واجهت عقدة مثل IF ، فأنت بحاجة إلى تحديد ما إذا كان الاختبار فارغًا. منطقية isContinue = false ؛ // إعلان عقدة Basenode Node مجردة = null ؛ if (stringUtils.isnotempty (elename)) {// استخدم مصنع العقدة للحصول على كائن عقدة على أساس اسم العقدة ، مثل إذا العقدة أو node foreach = nodefactory.create (elename) ؛ // تحليل هذه العقدة وإرجاع ما إذا كان المحتوى في العقدة لا يزال بحاجة إلى تحليل isContinue = node.parse (currparams ، globalparams ، ele ، sb) ؛ } إرجاع tempval جديد (isContinue ، ele ، node) ؛ } الخريطة العامة <string ، object> getParams () {return currparams ؛ } / *** تغليف النتيجة بعد تحليل عنصر XML* Author Rongdi* / Final Static Class Tempval {private boolean isContinue ؛ العنصر الخاص ele ؛ عقدة basenode الخاصة ؛ public tempval (iScontinue boolean ، element ele ، basenode node) {this.iscontinue = isContinue ؛ this.ele = ele ؛ this.node = العقدة ؛ } boolean public isContinue () {return isContinue ؛ } public void setContinue (boolean isContinue) {this.iscontinue = isContinue ؛ } العنصر العام getEle () {return ele ؛ } public void setele (element ele) {this.ele = eLe ؛ } public basenode getNode () {return node ؛ } public void setNode (basenode node) {this.node = node ؛ }}} استيراد org.dom4j.element ؛ استيراد java.util.hashmap ؛ استيراد java.util.map ؛/*** مجردة Node* Author Rongdi*/Public Abstract Class Basenode {Public Abstract Boolean Parse (MAP ، Object> currparams ، map <string ، object> globalparams ، element ele ele ، Public Void Pre (Map <String ، Object> currparams ، Map <String ، Object> GlobalParams ، Element Ele ، StringBuilder SB) يرمي الاستثناء {} public void بعد (MAP <String ، Object> currparams ، map <string ، Object> globalparams ، element ele ، stringbuilder sb) throws throws {} map < MAP <String ، Object> GlobalParams) {map <string ، Object> allParams = new HashMap <string ، Object> () ؛ allparams.putall (GlobalParams) ؛ allparams.putall (currparams) ؛ إعادة allparams. }} استيراد java.util.map ؛ استيراد ognl.ognl ؛ استيراد org.apache.commons.lang.stringUtils ؛ استيراد org.dom4j.Element ؛/*** if node* author rongdi*/public class ifnode يمتد basenode ELE ، StringBuilder SB) يلقي استثناء {// الحصول على سمة الاختبار IF node string testStR = eLe.AttributeValue ("test") ؛ اختبار منطقي = خطأ ؛ جرب {if (stringUtils.isnotempty (testStr)) {// دمج المتغيرات العالمية والمتغيرات المحلية خريطة <string ، object> allParams = getAllParams (currparams ، globalparams) ؛ // استخدم ognl لتحديد اختبار حقيقي أو خطأ = (منطقي) ognl.getValue (TestStr ، allparams) ؛ }} catch (استثناء e) {E.PrintStackTrace () ؛ رمي استثناء جديد ("قاضي المعلمات العملية"+TestStr+"غير شرعي") ؛ } if (ele.content ()! = null && eLe.Content (). size () == 0) {test = true ؛ } اختبار الإرجاع ؛ }} استيراد java.util.arraylist ؛ استيراد java.util.hashmap ؛ استيراد java.util.list ؛ استيراد java.util.map ؛ استيراد java.util.set ؛ استيراد ognl.ognl org.dom4j.element ؛/** سمات عقدة foreach هي كما يلي عنصر المجموعة الذي يجب اجتيازه. الفهرس المتغير المخزن في كل عنصر بعد اجتياز المجموعة. رقم فهرس المجموعة هو مثل 0 ، 1 ، 2 ... فاصل بعد عبور ، الربط مفتوح مع فاصل محدد. الرموز التي تبدأ الربط بعد اجتيازها هي كما يلي (إغلاق الرموز التي تنهي الربط بعد اجتيازها كما يلي) */فئة عامة foreachnode يمتد Basenode {Override public boolean parse (map <string ، Object> currparams ، map <string> globalparams ، element ele ele ، سلسلة collectionstr = ele.attributeValue ("collection") ؛ String headstr = ele.attributeValue ("item") ؛ سلسلة فهرس = ele.attributeValue ("الفهرس") ؛ سلسلة الفاصل = ele.attributeValue ("فاصل") ؛ String Openstr = eLe.AttributeValue ("Open") ؛ string lelogestr = ele.attributeValue ("Close") ؛ if (stringUtils.isempty (index)) {index = "index" ؛ } if (stringUtils.isempty (frectorsstr)) {freffordstr = "،" ؛ } if (stringUtils.isnotempty (openstr)) {currparams.put (attrs.while_open ، openstr) ؛ } if (stringUtils.isnotempty (closestr)) {currparams.put (attrs.while_close ، lelogestr) ؛ } if (stringUtils.isnotempty (collectionstr)) {currparams.put (attrs.while_list ، collectionstr) ؛ } currparams.put (attrs.while_separator ، freftorsstr) ؛ إذا كان (index! = null) { /*** إذا كانت هناك قيمة متغير الحلقة الحالي في المتغير المحلي ، فهذا يعني أنه ليست المرة الأولى التي تدخل فيها علامة الحلقة. قم بإزالة علامة البدء * وأضف 1 إلى القيمة المتغيرة المحلية */ if (currparams.get (index)! = null) {currparams.remove (attrs.while_start) ؛ currparams.put (index+"_" ، (integer) currparams.get (index+"_")+1) ؛ } آخر {// في المرة الأولى التي تقوم فيها بإدخال Loop Label currparams.put (attrs.while_start ، true) ؛ currparams.put (index+"_" ، 0) ؛ } currparams.put (index ، (integer) currparams.get (index+"_")) ؛ } حالة منطقية = صواب ؛ خريطة <سلسلة ، كائن> allParams = getAllParams (currparams ، GlobalParams) ؛ جمع الكائن = فارغ ؛ if (stringUtils.isnotempty (collectionstr)) {// احصل على المجموعة لتكون مجموعة looped = ognl.getValue (collectionstr ، allparams) ؛ // إذا لم تكن خاصية المجموعة فارغة ، ولكن الشرط فارغ ، تتم إضافة شرط الحدود افتراضيًا إذا كان (stringUtils.isempty (ظروف)) {// هنا سأستخدم مجموعة فقط لإظهارها. يمكنك أيضًا إضافة صفيف ، ولكن فقط قم بتغييره إلى .Length if (collection extoryof list) {inspertr = index+"_ <" collectionstr+". size ()" ؛ } آخر إذا (collection eastyof map) {map map = (map) collection ؛ set set = map.entryset () ؛ قائمة قائمة = جديد arraylist (set) ؛ allparams.put ("_ list_" ، قائمة) ؛ ظروف = index+"_ <_ list _"+". size ()" ؛ }}} currparams.remove (attrs.while_end) ؛ if (stringUtils.isnotempty (intisionstr)) {// قيمة شرط الحساب = (boolean) ognl.getValue (ظروف ، allparams) ؛ خريطة <string ، object> tempmap = new hashmap <> () ؛ tempmap.putall (allparams) ؛ tempmap.put (index+"_" ، (integer) currparams.get (index+"_")+1) ؛ currparams.put (attrs.while_end ،! (boolean) ognl.getValue (ظروف ، tempmap)) ؛ } العلم المنطقي = صحيح ؛ currparams.put (attrs.while_index ، index) ؛ currparams.put (attrs.while_flag ، true) ؛ if (ظروف) {try {if (stringUtils.isnotempty (heatSr) && stringUtils.isNotEmpty (collectionstr)) {object value = null ؛ int idx = integer.parseint (currparams.get (index+"_"). toString ()) ؛ if (collection estamueof list) {value = ((list) collection) .get (idx) ؛ currparams.put (عناصر ، القيمة) ؛ } آخر إذا (collection eastyof map) {map map = (map) collection ؛ set <map.entry <string ، object >> set = map.entryset () ؛ قائمة <map.entry <string ، object >> list = new ArrayList (set) ؛ currparams.put (عناصر ، list.get (idx) .getValue ()) ؛ currparams.put (index ، list.get (idx) .getKey ()) ؛ }}} catch (استثناء e) {رمي استثناء جديد ("احصل على قيمة من مجموعة أو خريطة"+currparams.get (index)+"error"+e.getMessage ()) ؛ }} آخر {flag = false ؛ DriterVars (currparams ، index ، heatstr) ؛ } العلم الإرجاع ؛ } / *** إذا كانت هذه هي المرة الأولى التي تدخل فيها علامة الحلقة ، فقم بتهجئة محتوى Open* / Override public void (MAP <STRANG ، OBJECT> CURMPRAMS ، MAP <String ، Object> GlobalParams ، Element ELE ، StringBuilder SB) استثناء {super.pre (currparams ، globalparams ، ele ، sb) ؛ boolean start = maputils.getBoolean (currparams ، attrs.while_start ، false) ؛ if (start) {string open = maputils.getString (currparams ، attrs.while_open) ؛ sb.append (مفتوح) ؛ }} / *** إذا تم إدخال تسمية الحلقة أخيرًا ، يتم توضيح محتوى الإغلاق في النهاية* / Override Public Void بعد (Map <String ، Object> currparams ، Map <String ، Object> GlobalParams ، element ele ، stringbuilder sb) يلقي استثناءً {super.after (currparams ، globalparams ، ele ، sb) ؛ نهاية منطقية = mapUtils.getBoolean (currparams ، attrs.while_end ، false) ؛ فاصل السلسلة = mapUtils.getString (currparams ، attrs.while_separator) ؛ if (! end && stringutils.isnotempty (فاصل)) {sb.append (فاصل) ؛ } if (end) {string close = maputils.getString (currparams ، attrs.while_close) ؛ if (sb.toString (). endswith (فاصل)) {sb.deletecharat (sb.length () - 1) ؛ } sb.append (close) ؛ }} // احرص على تدمير الفراغ الخاص المتغير المؤقت (MAP <String ، Object> currparams ، index string ، string varstr) {currparams.remove (attrs.while_index) ؛ currparams.remove (attrs.while_flag) ؛ currparams.remove (attrs.while_separator) ؛ currparams.remove (attrs.while_start) ؛ currparams.remove (attrs.while_end) ؛ currparams.remove (attrs.while_list) ؛ }} import org.dom4j.element ؛ import java.util.map ؛ public class sqlnode يمتد basenode {Override public boolean parse (map <string ، object> currparams ، map <string ، object> globalparams ، element ele ، stringbuilder sb) throws throws {return true ؛ }} استيراد java.util.arrays ؛ استيراد java.util.list ؛ استيراد java.util.map ؛ استيراد java.util.concurrent.concurrenthashmap ؛/*** node factory*/public class nodefactory القائمة الثابتة النهائية الخاصة <Tring> whilelist = arrays.aslist ("foreach") ؛ ثابت {nodemap.put ("if" ، new ifnode ()) ؛ nodemap.put ("sql" ، new sqlnode ()) ؛ nodemap.put ("foreach" ، new foreachnode ()) ؛ ) } public static void addNode (string nodename ، basenode node) {nodemap.put (nodename ، node) ؛ } create basenode static public create (string nodename) {return nodemap.get (nodeName) ؛ }}/*** علامات مختلفة* Author rongdi*/class public attrs {public final static string actactional = "Transactional" ؛ السلسلة الثابتة النهائية العامة whide_start = "بينما تبدأ" ؛ السلسلة الثابتة النهائية العامة whide_end = "WhiLe-end" ؛ السلسلة الثابتة النهائية العامة Whide_open = "While-Open" ؛ السلسلة الثابتة النهائية العامة whids_close = "بينما الانطلاق" ؛ السلسلة الثابتة النهائية العامة whiles_separator = "While-separator" ؛ السلسلة الثابتة النهائية العامة whide_index = "While-Index" ؛ السلسلة الثابتة النهائية العامة whide_flag = "While-Flag" ؛ السلسلة الثابتة النهائية العامة Whide_List = "Lih-List" ؛ السلسلة الثابتة النهائية العامة when_flag = "when-flag" ؛ Static Final String Process_Var = "Process-var" ؛ السلسلة الثابتة النهائية العامة result_flag = "result-flag" ؛ السلسلة الثابتة النهائية العامة Return_Flag = "Return-Flag" ؛ السلسلة الثابتة العامة Console_var = "Console-var" ؛ السلسلة الثابتة النهائية العامة do = "do" ؛ فهرس السلسلة الثابتة النهائية العامة = "الفهرس" ؛ شرط السلسلة الثابتة النهائية العامة = "الشرط" ؛ اسم السلسلة الثابتة النهائية العامة = "الاسم" ؛ قيمة السلسلة الثابتة النهائية العامة = "القيمة" ؛ نوع السلسلة النهائية الثابتة العامة = "type" ؛ تنسيق السلسلة النهائية الثابتة العامة = "التنسيق" ؛ السلسلة النهائية الثابتة العامة if = "if" ؛ سلسلة نهائية ثابتة أخرى = "آخر" ؛ ملف السلسلة الثابتة النهائية العامة = "ملف" ؛ تاريخ السلسلة النهائية الثابتة العامة = "التاريخ" ؛ السلسلة النهائية الثابتة العامة الآن = "الآن" ؛ السلسلة النهائية الثابتة العامة = "عشرية" ؛ المعرف النهائي الثابت العام = "id" ؛ السلسلة النهائية الثابتة العامة = "params" ؛ السلسلة النهائية الثابتة العامة = "Target" ؛ سلسلة نهائية ثابتة واحدة = "Single" ؛ Static Final String Paging = "Paging" ؛ السلسلة النهائية الثابتة العامة desc = "desc" ؛ السلسلة النهائية الثابتة للعام الثابت = "Break" ؛ السلسلة النهائية الثابتة العامة تستمر = "متابعة" ؛ مجموعة سلسلة نهائية ثابتة = "Collection" ؛ السلسلة النهائية الثابتة العامة var = "var" ؛ STATIC Final Final eventor = "Executor-1" ؛ Static Static Final String Rollback_flag = "Rollback-Flag" ؛ Service Final String Service = "الخدمة" ؛ Static Final String ref = "Ref" ؛ Bizs Final Static Static = "bizs" ؛ عناوين السلسلة النهائية الثابتة العامة = "العناوين" ؛ أعمدة السلسلة النهائية الثابتة العامة = "الأعمدة" ؛ السلسلة النهائية الثابتة العامة = "العملات المعمل" ؛ السلسلة النهائية الثابتة العامة currperm = "currperm" ؛ السلسلة النهائية الثابتة العامة TAST_EXECUTOR = "Taskexecutor" ؛ SELIMITER FIND STATIC STATIC SELIMITER = "SELIMITER" ؛ السلسلة النهائية الثابتة العامة OperName = "OperName" ؛ } currparams.remove (varstr) ؛ currparams.remove (index) ؛ currparams.remove (index+"_") ؛ }}إرفاق ملف POM
<project xmlns = "http://maven.apache.org/pom/4.0.0" http://maven.apache.org/maven-v4_0_0.xsd "> <Dodeversion> 4.0.0 </modelversion> <roupiD> com.rd </groupid> <Url> http://maven.apache.org </url> <ependencies> <reperence> <roupiD> dom4j </roughid> <StifactId> dom4j </sonfactid> <sophiD> 1.6.1 </version> <sophy> 2.6.11 </version> </sependency> <redency> <roupiD> Commons-Collections </GroupId> <StifactId> Commons-Collections </stifactid> <sored> 3.2.1 </version> </respency> <sperence> <sropency> <Rependency> <roupeD> junit </ropressid> <StifactId> Junit </stifactId> <sored> 3.8.1 </version> <scope> اختبار </scope> </sependency> </rependency> </reperencies> <bustr> <srosser> <srossors> </sults> </srosesf> <sroperS> <cirli> src/main/resources </directory> <sudge> <supture> **/*</include> </sroses> </specials> </testresources> <testResources> <StresResource> <cironsory> $ {project.baseir}/src/test/java </java> <Criptory> $ {project.basedir}/src/test/resources </directory> </testresource> </sestresources> <plugins> <roupiD> org.apache.maven.plugins </rouctid> </stifactid> maven-compiler-plugin-plugin </tevactid> <Target> 1.8 </sugres> <ceroding> UTF-8 </ispling> </isplicuration> </suncloy> </spliveins> </buys> </project>الطريقة أعلاه لتنفيذ MyBatis Dynamic SQL بنفسك هي كل المحتوى الذي شاركته معك. آمل أن تتمكن من إعطائك مرجعًا وآمل أن تتمكن من دعم wulin.com أكثر.