블로그 작성을 주장하기가 정말 어렵다는 것을 알았으며 여러 가지 이유로 블로그를 돌볼 필요가 없습니다. 나는 원래 ORM의 DIY 구현을 작성하고 시간을 볼 계획이었습니다. 차라리 동적 SQL을 먼저 구현하고 다음에 시간이있을 때 ORM의 전체 구현을 추가합니다.
mybatis를 사용한 사람들은 동적 SQL에 익숙 할 것입니다. 당신이 그것을 사용하지 않았다면, 그냥 재미를 살펴보십시오. MySQL과 처음 연락을 취한 것은 제가 시니어 시절에 있었을 때였습니다. 당시 나는 동적 SQL이 매우 훌륭하고 유연하다고 생각했습니다. 나는 항상 그것을 구현하는 방법을 알아 내고 싶었습니다. 당시 IOC, MVC 및 Simple ORM 프레임 워크를 쓸 수는 있지만 (MyBaits이지만 동적 SQL 부분은 없음) MyBatis의 핵심에서 동적 SQL을 구현할 위치와 구현 방법을 찾을 수 없었습니다. 어쩌면 코드가 너무 엉키고 전혀 이해할 수 없었습니다. 지금까지 나는 Mybatis의 역동적 인 SQL 부분을 읽을 용기가 없었습니다. 어쩌면 나는 알고리즘에 대한 설명 할 수없는 경외감으로 태어 났을 것입니다.
몇 년 전, 구성 플랫폼을 구축하고 싶었고 구문 분석 언어를 사용하여 Java 구현을 대체하기를 원했기 때문에 구성 인력은 복잡한 비즈니스 로직 (데이터베이스 운영 포함)을 구현하기 위해 페이지에 소량의 코드를 쉽게 작성할 수있었습니다. 당시 Java는 이미 JS 구문 분석 엔진을 가지고 있었지만 대부분의 사람들은 효율이 너무 낮았다 고 말했습니다. 내가 무엇에 대해 무엇을 몰랐는지, 나는 구문 분석 언어를 직접 구현할 생각을했다. 그러나 나는 항상 내 언어를 실현하는 꿈을 꾸었습니다. 컴파일 된 언어보다 분석 언어로 시작하는 것이 더 쉽기 때문에 결정적으로 그렇게하기 시작했습니다. 작성한 후, 나는 그 당시 JS 엔진만큼 효율적이지 않다는 것을 깨달았습니다. 그 당시 나는 정말 젊고 단순했습니다. 내가 오늘 이야기하고있는 동적 SQL 구현은 실제로 그 당시 구문 분석 언어에서 영감을 얻었습니다.
많은 말도 안되는 말로 동적 SQL에 대해 이야기합시다. 다음 예제를 참조하십시오. 먼저, 여기의 예제가 SQL을 작성하는 올바른 방법이 아니라고 선언합니다. 가능한 한 복잡한 중첩 구조를 쓰고 싶습니다. 이 복잡한 상황이 구현되면 간단하게 만드는 것이 훨씬 어렵습니다.
pl_pagewidget <if test = "widgetCodes! = null">에서 삭제하여 <foreach collection = "widgetCodes"item = "item"index = "index"al Open = "("separator = ","close = ")"> #{b} </foreach> </foreach> </if> <if test = "a! = null"> 및 a = #{a} </if>위의 예를 구문 분석하기위한 SQL을 구현하려면 어려움 중 하나는 테스트 속성에서 True 또는 False 조건을 결정하는 방법과 유사합니다. 그러나이 어려움은 Struts2에서 배운 Ognl 표현 앞에 더 많이 있습니다. 친구가 다소 이상한 현상을 만났는지, 즉 다음 표현이 Mybatis Dynamic SQL로 작성되지만, n = 0이면 실제로 조건을 충족 할 때, 즉 테스트의 값은이 표현의 조건을 충족시킬 수 없습니다. 이것이 OGNL 라이브러리의 이유입니다. 이렇게하는 방법은 없습니다. 특별한 상황으로 기억하십시오.
test = "n! = null 및 n! = '' '"
Ognl 표현식은 다음과 같이 사용하기에 매우 편리합니다.
import java.util.hashmap; import java.util.map; import ognl.ognl; public class ognltest {// 출력 결과 : False public static void main (string [] args) 예외 {String con1 = "n! = null 및 n! = '' '; map <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">에서 삭제합니다. <foreach collection = "pagewidgetCode in <foreachodes"item = "item"index = "index"( "seplicator =", "close =") ")") ")"< "item = {item} <" "" "" "" ""BS = "bs ="bs. index = "index1"Open = "("Separator = ","Close = ")"> #{b} </foreach> </foreach> </if> <test = "a! = null"> 및 a = #{a} </if> </sql>그러나 위의 XML을 구문 분석하는 것은 일반적인 XML과 다릅니다. 이 XML은 태그와 텍스트의 혼합입니다. 일반적 으로이 XML을 구문 분석하는 데 거의 사용하지 않아야합니다. 그러나 XML Dom4J를 구문 분석하는 데 일반적으로 사용되는 도구는 실제로 이러한 종류의 SQL을 잘 구문 분석 할 수 있지만 거의 사용되지 않습니다. 요소 클래스의 내용 () 메소드는 노드 모음을 반환 한 다음이 컬렉션을 가로 지르고 각 노드의 유형을 판단 할 수 있습니다. 이 두 가지 핵심 사항을 해결 한 후에는이 동적 SQL을 구문 분석하기 위해 약간의 트릭 만 추가하면됩니다.
내가 사용한 트릭은 Java Syntax 형식에서 영감을 얻었습니다. 예를 들어, Java에는 로컬 변수와 글로벌 변수가 있으며 참조 통과 상황은 고려되지 않습니다. 글로벌 변수 int i = 1 인 경우; 글로벌 변수는 방법으로 전달 된 다음 방법에서 수정됩니다. 이 방법에서 보는 것은 변경된 값이지만, 방법 외부에서 볼 수있는 것은 여전히 1입니다. 실제로, 당신은 Java를 배우고 나면이 현상을 알아야합니다. 또한 메소드가 호출되면이 메소드에서 글로벌 변수와 로컬 변수를 볼 수 있습니다. 메소드 호출이 완료되면 로컬 변수가 지워지고 릴리스됩니다 (쓰레기 수집가를 만나서 기쁘다). 나는 이것들을 소개하고 코드를 직접 추가했습니다
import java.io.stringReader; import java.text.simpledateformat; import java.util.arrays; import java.util.date; import java.util.hashmap; import java.util.list; import java.util.map; import java.util.regex.matcher; java.util. org.apache.commons.collections.maputils; import org.apache.commons.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 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">에서 삭제됩니다. <foreach collection = "widgetCode"item = "item"index = "index"( "seplicator =", "close ="). Open = "("분리기 = ","close = ")"> #{b} </foreach> </foreach> </if> <test = "a! = null"> 및 a = #{a} </if> */public static void main (Strows) 예외 {map <string, object = new hashmap <string, object> (); map.put ( "위젯 코드", arrays.aslist ( "1", "2")); map.put ( "bs", arrays.aslist ( "3", "4")); map.put ( "a", 1); sqlparser parser = new sqlparser (); system.out .println (parser.parser ( "pl_pagewidget/n" + "/t <if test =/"widgetCodes에서 삭제! = null/">/n" + "/t/t/t/tphere pagewidgetCode in/n" + "/t/t <foreach Collection =/"index/"index/"index/"index/"index/"index/"index/"index/"index/"index/"index/"index. 분리기 =/",/"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 =/"index =/", ",", ",", " close =/")/">/n " +"/t/t/t #{b}/n " +"/t/t </foreach>/n " +"/t/t </foreach>/n " +"/t </if>/n " +"/t <test =/"a! = null/">/n " +"/t/t a = #<a}/n "/n", 지도)); System.out.println (parser.getParams ()); } public String Parser (String XML, Map <String, Object> Params)는 예외를 {// xml = "<? xml 버전 =/"1.0/"encoding =/"utf-8/"?>"+xml; // 입력 동적 SQL XML = "<SQL>"+XML+"</sql>"에 대한 XML 태그 레이어를 설정합니다. SaxReader Reader = New SaxReader (False); 문서 문서 = reader.read (새 StringReader (XML)); 요소 요소 = document.getRootElement (); Map <String, Object> Currparams = New Hashmap <String, Object> (); StringBuilder sb = new StringBuilder (); // Parserlement 시작 (요소, Currparams, Params, SB); 반환 sb.toString (); } /** * 재귀 파서를 사용하여 동적 sql * @param ele1 xml 태그를 구문 분석하기 위해 * @param currparams * @param globalparams * @param sb * @throws 예외 * /private void parserlement (요소 ele1, map <string, object> currparams, map <Strows, 객체, stringbuilder {stringbuilder sb). 예를 들어 노드를 구문 분석합니다. 예를 들어, IF 노드를 구문 분석하고 테스트가 true를 결정하면 true가 반환됩니다. tempval val = parseroneelement (Currparams, GlobalParams, ELE1, SB); // 노드 구문 분석 된 Basenode 노드의 추상 노드 객체 = val.getNode (); /*** 실제로,이 문장 위의 진술은 XML 태그 만 구문 분석하고 태그의 내용을 구문 분석하지 않습니다. 여기에서 * 컨텐츠를 구문 분석하기 전에 사전 수용이있는 경우 일부 사전 수용 */ node.pre (Currparams, GlobalParams, Ele1, SB); // 테스트 결과가 true boolean flag = val.iscontinue () 인 경우 노드의 내용이 여전히 구문 분석 해야하는지 여부를 방어합니다. // 일반 텍스트 목록 <Node> 노드 = ele1.content (); if (flag &&! nodes.isempty ()) { /*** 이것은 노드의 내용을 추가로 구문 분석하고 싶다는 것을 의미합니다. 노드를 메소드의 쉘과 비교할 수 있습니다* 내부의 내용은 메소드의 특정 문과 유사합니다. 노드의 내용을 구문 분석하기 전에*이 노드 아래에 로컬 매개 변수가있는 컨테이너를 만듭니다. 가장 편리한 것은 물론 맵 */ map <string, object> params = new Hashmap <String, Object> ()입니다. /***이 예제의 매개 변수는 공통 데이터 유형이기 때문에 로컬 매개 변수를 컨테이너에 직접 넣습니다.* 참조 유형이 없으므로 사본과 동일합니다. 외부에서 전달 된 물체에 영향을 미치지 않기 위해서는 방법이 들어오는 매개 변수를 호출하는 경우를 비교할 수 있습니다.*/ params.putall (Currparams); // (int i = 0; i <nodes.size ();) {node n = nodes.get (i); // 노드가 일반 텍스트 인 경우 (n 인스턴스 텍스트) {문자열 text = ((text) n) .getStringValue (); if (stringUtils.isNotEmpty (text.trim ())) {// 처리 #{xx}와 같은 텍스트를 훈련하고 $ {yy}를 sb.append (핸드 텍스트 (텍스트, 매개 변수, GlobalParams)로 전달한 실제 값으로 직접 대체합니다. } i ++; } else if (n 인스턴스 요소) {element e1 = (요소) n; // 재귀 적으로 XML 어린이 요소 Parserlement (E1, Params, GlobalParams, SB); // 루프 플래그가 사실이 아닌 경우 다음 태그를 구문 분석하십시오. // 루프 태그를 반복적으로 구문 분석해야한다는 것을 의미합니다. 그렇지 않으면 변경하지 않으면 다음 요소 boolean whink_flag = maputils.getBoolean (attr.shile_flag, false)을 계속 처리합니다. if (! while_flag ||! nodefactory.ishile (n.getName ()) || e1.attributeValue (attss.Index) == null ||! e1.attributeValue (attrs.index) .Equals (params.get (attrs.while_index)) {i ++; }}} // 노드 처리 노드 후 어떻게해야합니까? // 현재 스코프 매개 변수를 재활용합니다. params = null; }} /** * 매개 변수 #{item}을 대체하는 프로세스 텍스트 #{item} * @param str * @param params * @return * @throws 예외 * /private string handtext (String str, map <string, 객체> 매개 변수, 객체, globalparams) {// variable string indexstrs = maputilstring (attr., attrs.gets.getstring)을 얻습니다. 정수 색인 = null; if (stringUtils.isnotempty (indexstr)) {index = maputils.getInteger (params, indexstr); } // match #{a} 매개 변수 문자열 reg1 = "( #// {) (// w+) (//})"; // $ {a} string reg2 = "(// $ // {) (// w+) (//})의 매개 변수와 일치합니다. 패턴 p1 = pattern.compile (reg1); 매치 자 M1 = P1.matcher (str); 패턴 p2 = pattern.compile (reg2); 매치 자 M2 = P2.matcher (str); 문자열 whilist = maputils.getString (params, attrs.while_list); map <string, object> allparams = getAllParams (params, globalParams); while (m1.find ()) {문자열 tmpkey = m1.group (2); 문자열 키 = whilelist == null? tmpkey : (whilist+"_"+tmpkey); key = index == null? key : (key+index); 문자열 rekey = "#{"+key+"}"; // foreach와 유사한 루프에서 매개 변수 #{xx}를 #{xx_0}, #{xx_1} str = str.replace (m1.group (0), rekey)로 바꾸어야 할 수도 있습니다. currparams.put (key, allparams.get (tmpkey)); } while (m2.find ()) {문자열 tmpkey = m2.group (2); 객체 값 = allparams.get (tmpkey); if (value! = null) {str = str.replace (m2.group (0), getValue (value)); }} return str; } 개인 문자열 getValue (개체 값) {문자열 result = ""; if (value instanceof date) {simpledateformat sdf = new simpledateformat ( "yyyy-mm-dd hh : mm : ss"); 결과 = sdf.format ((날짜) 값); } else {result = string.valueof (값); } 반환 결과; } private map <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를 반환합니다. } // XML 요소 개인 tempval parserOneElement (map <string, object> currparams, map <string, 객체> GlobalParams, Element Ele, StringBuilder sb) 예외 {// XML 태그 이름 elename = ele.getName (); // 노드를 구문 분석 한 후에도 계속됩니까? if와 같은 노드가 발생하면 테스트가 비어 있는지 확인해야합니다. 부울 iscontinue = false; // 초록 노드 Basenode 노드 = null을 선언합니다. if (stringUtils.isnotempty (elename)) {// 노드 팩토리를 사용하여 노드 이름을 기준으로 노드 객체를 가져옵니다. //이 노드를 분석하고 노드의 내용이 여전히 구문 분석 해야하는지 iscontinue = node.parse (Curparams, GlobalParams, Ele, SB); } 새 tempval을 반환합니다 (IsContinue, Ele, 노드); } public map <string, object> getParams () {return currparams; } / *** XML 요소가 구문 분석 된 후 결과를 캡슐화* @Author rongdi* / 최종 정적 클래스 tempval {private boolean iscontinue; 개인 요소 엘레; 개인베이스 노드 노드; public tempval (부울 iscontinue, element ele, basenode 노드) {this.iscontinue = iscontinue; this.ele = ele; 이 .node = 노드; } public boolean iscontinue () {return iscontinue; } public void setContinue (boolean iscontinue) {this.iscontinue = iscontinue; } 공개 요소 getELe () {return ele; } public void setele (요소 ele) {this.ele = ele; } public basenode getNode () {return 노드; } public void setNode (Basenode 노드) {this.node = 노드; }}} import org.dom4j.element; import java.util.hashmap; import java.util.map;/*** 추상 노드* @author rongdi*/public baseNode {public actract boolean parse (map <string, map <string, 객체> globalparams, elementbuilder sb). public void pre (map <string, object> currparams, map <string, 객체> globalparams, element ele, stringbuilder sb) 예외 {} public void 이후 (map <string, object> currparams, map <string, 객체> GlobalParams, 요소, StringBuilder SB) 예외 {}, getAllparam (getAllparam) map <String, Object> GlobalParams) {map <String, Object> AllParams = new Hashmap <String, Object> (); allparams.putall (GlobalParams); allparams.putall (currparams); AllParams를 반환합니다. }} import java.util.map; import ognl.ognl; import org.apache.commons.lang.stringUtils; import org.dom4j.element;/*** if node* @author rongdi*/public class ifnode는 basenode {@override public boolean parse (map <string, orver <string, object <string, object <string, object <string, object <string, object <string <string, vaseR. ele, StringBuilder SB)는 예외를 던집니다. {// if node string teststr = ele.attributeValue ( "test")의 테스트 속성을 가져옵니다. 부울 테스트 = 거짓; try {if (stringUtils.isnotempty (teststr)) {// 전체 변수 및 로컬 변수 map <string, object> allparams = getAllParams (curpparams, globalParams); // Ognl을 사용하여 true 또는 false test = (boolean) getValue (teststr, allparams); }} catch (예외 e) {e.printstacktrace (); 새로운 예외 ( "판사 조작 매개 변수"+teststr+"불법"); } if (ele.content ()! = null && ele.content (). size () == 0) {test = true; } 반환 테스트; }} 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; org.dom4j.element;/** foreach 노드의 속성은 다음과 같습니다. 컬렉션을 통과 한 후 각 요소에 저장된 변수 인덱스. 컬렉션의 인덱스 수는 0, 1, 2 ... 횡단 후 분리기가 지정된 분리기와 함께 개방됩니다. Traversal 후 스 플라이 싱을 시작하는 기호는 다음과 같습니다 (Traversal이 다음과 같이 스 플라이 싱을 종료하는 기호를 닫습니다) */public class foreachnode 확장 Basenode {@override public boolean parse (map <String, Object> Currparams, Map <String, GlobalParams, Element Ele, StringBuilder SB) {Stringstrest = null 조건증; 문자열 collectionstr = ele.attributeValue ( "Collection"); 문자열 itemttr = ele.attributeValue ( "항목"); 문자열 index = ele.attributeValue ( "index"); 문자열 분리기 스트트 = ele.attributeValue ( "분리기"); String OpenStr = ele.attributeValue ( "Open"); 문자열 closeStrest = ele.attributeValue ( "Close"); if (stringUtils.isempty (index)) {index = "index"; } if (stringUtils.isempty (SeparatorStr)) {sequorStr = ","; } if (stringUtils.isnotempty (OpenStr)) {CurrParams.put (attrs.while_open, openStr); } if (stringUtils.isnotempty (closest)) {currparams.put (attrs.while_close, closest); } if (stringUtils.isnotempty (collectionstr)) {currparams.put (attrs.while_list, collectionst); } currparams.put (attrs.while_separator, separatorstr); if (index! = null) { /*** 로컬 변수에 전류 루프 변수의 값이 있으면 루프 레이블에 처음 입력 한 것은 아닙니다. 시작 태그 *를 제거하고 로컬 변수 값 */ if (currparams.get (index)! = null) {currparams.remove (attrs.while_start); Currparams.put (Index+"_", (Integer) Currparams.get (index+"_")+1); } else {// 루프 레이블 Currparams.put을 처음 입력 할 때 (attrs.while_start, true); currparams.put (index+"_", 0); } currparams.put (index, (Integer) currparams.get (index+"_"); } 부울 조건 = true; map <string, object> allparams = getAllParams (Currparams, GlobalParams); 객체 수집 = null; if (stringUtils.isnotempty (collectionstr)) {// 컬렉션을 루프로 가져옵니다. Collection = Ognl.getValue (Collectionstr, AllParams); // 수집 속성이 비어 있지 않지만 조건이 null이면 (stringUtils.isempty (conditionStr)) if If (// 여기서는 컬렉션을 사용하여 시연하기 위해 경계 조건이 기본적으로 추가됩니다. 배열을 추가 할 수도 있지만 .length if (collection instanceof list) {condationstr = index+"_ <"+collectionstr+". size ()"; } else if (collection instancef) {map map = (map) 컬렉션; set set = map.entryset (); 목록 List = New ArrayList (SET); allparams.put ( "_ list_", list); 컨디스트 스트 = 인덱스+"_ <_ list _"+". size ()"; }}} currparams.remove (attrs.while_end); if (stringUtils.isnotempty (컨디스트 스트)) {// 계산 조건 조건의 값 = (부울) ognl.getValue (조건, allparams); Map <string, object> tempmap = new Hashmap <> (); tempmap.putall (AllParams); tempmap.put (index+"_", (Integer) currparams.get (index+"_")+1); currparams.put (attrs.while_end,! (boolean) ognl.getValue (conditionstr, tempmap)); } 부울 플래그 = true; currparams.put (attrs.while_index, index); currparams.put (attrs.while_flag, true); if (조건) {try {if (stringUtils.isnotempty (itemstr) && stringUtils.isnotempty (collectionstr)) {object value = null; int idx = integer.parseint (currparams.get (index+"_"). toString ()); if (collection instanceof list) {value = ((list) collection) .get (idx); currparams.put (itemstr, value); } else if (collection instancef) {map map = (map) 컬렉션; set <map.entry <string, object >> set = map.entryset (); list <map.entry <string, object >> list = new arraylist (set); currparams.put (itemstr, list.get (idx) .getValue ()); currparams.put (index, list.get (idx) .getKey ()); }}} catch (예외 e) {새 예외 던지기 ( "컬렉션 또는 맵에서 값 가져 오기"+currparams.get (index)+"error"+e.getMessage ()); }} else {flag = false; Destrovevars (Currparams, Index, itemtr); } 반환 플래그; } / *** 루프 태그를 처음으로 입력 할 때 Open* / @override public void pre (map <string, object> currparams, map <string, 객체> 요소 Ele, StringBuilder SB)의 내용을 철자하는 경우 {super.pre (Curparams, GlobalParams, Ele, SB); 부울 start = maputils.getBoolean (Currparams, attrs.while_start, false); if (start) {string open = maputils.getString (Currparams, attrs.while_open); sb.append (오픈); }} / *** 루프 레이블이 마침내 입력되면 Close의 내용은 끝에 철자가 있습니다* / @override public void (map <string, object> currparams, map <string, 객체> 요소 Ele, StringBuilder SB)는 {super.fter (curparams, globalparams, ele, sb); 부울 end = maputils.getBoolean (Currparams, attrs.while_end, false); 문자열 분리기 = maputils.getString (Currparams, attrs.while_separator); if (! end && stringutils.isnotempty (분리기)) {sb.append (분리기); } if (end) {문자열 close = maputils.getString (Currparams, attrs.while_close); if (sb.tostring (). endswith (분리기)) {sb.deletecharat (sb.length () -1); } sb.append (Close); }} // 임시 변수 개인 void destrovevars (map <string, object> currparams, String Index, 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 extends basenode {@override public boolean parse (map <string, object> currparams, map <string, 객체> GlobalParams, 요소 Ele, StringBuilder SB) 예외 {true; }} import java.util.arrays; import java.util.list; import java.util.map; import java.util.concurrent.concurrenthashmap;/*** node factory*/public class nodefactory {private static map <string, basenode> nodemap = new concurrthashmap <string, basenode> (); 개인 최종 정적 목록 <string> whillest = arrays.aslist ( "foreach"); static {nodemap.put ( "if", new ifnode ()); nodemap.put ( "sql", new sqlnode ()); nodemap.put ( "foreach", new foreachnode ()); } public static boolean은 (String ElementName) {return whilist.contains (elementName); } public static void addnode (String Nodename, Basenode 노드) {nodemap.put (Nodename, Node); } public static basenode create (String nodename) {return nodemap.get (nodename); }}/*** 다양한 태그* @author rongdi*/public class attrs {public final static string transactional = "transactional"; public final static string while_start = "while-Start"; 공개 최종 정적 문자열 while_end = "while-end"; public final static string while_open = "while-open"; 공개 최종 정적 문자열 while_close = "while-close"; 공개 최종 정적 문자열 while_separator = "while-separator"; 공개 최종 정적 문자열 while_index = "while-index"; 공개 최종 정적 문자열 while_flag = "while-flag"; public final static string while_list = "while-list"; public final static string when_flag = "when-flag"; 공개 정적 최종 문자열 process_var = "process-var"; 공개 최종 정적 문자열 result_flag = "result-flag"; 공개 최종 정적 문자열 return_flag = "return-flag"; 공개 최종 정적 문자열 console_var = "Console-Var"; 공개 최종 정적 문자열 do = "do"; 공개 최종 정적 문자열 색인 = "인덱스"; 공개 최종 정적 문자열 조건 = "조건"; 공개 최종 정적 문자열 이름 = "이름"; 공개 최종 정적 문자열 값 = "값"; 공개 정적 최종 문자열 유형 = "유형"; 공개 정적 최종 문자열 형식 = "형식"; 공개 정적 최종 문자열 if = "if"; 공개 정적 최종 문자열 else = "else"; 공개 최종 정적 문자열 파일 = "파일"; 공개 정적 최종 문자열 날짜 = "날짜"; 공개 정적 최종 문자열 now = "now"; 공개 정적 최종 문자열 10 진수 = "십진"; 공개 정적 최종 문자열 ID = "ID"; 공개 정적 최종 문자열 params = "params"; 공개 정적 최종 문자열 대상 = "대상"; 공개 정적 최종 문자열 단일 = "단일"; 공개 정적 최종 문자열 페이징 = "페이징"; 공개 정적 최종 문자열 desc = "desc"; 공개 정적 최종 최종 문자열 break = "break"; 공개 정적 최종 문자열 계속 = "계속"; 공개 정적 최종 문자열 Collection = "Collection"; 공개 정적 최종 문자열 var = "var"; 공개 정적 최종 문자열 executor = "Executor-1"; 공개 정적 최종 문자열 rollback_flag = "롤백 플래그"; 공개 정적 최종 문자열 서비스 = "서비스"; 공개 정적 최종 문자열 ref = "Ref"; 공개 정적 최종 문자열 bizs = "bizs"; 공개 정적 최종 문자열 제목 = "제목"; 공개 정적 최종 문자열 열 = "열"; 공개 정적 최종 문자열 Curruser = "Curruser"; public static final string currperm = "currperm"; 공개 정적 최종 문자열 task_executor = "taskexecutor"; 공개 정적 최종 문자열 delimiter = "Delimiter"; public static final string orpername = "opername"; } currparams.remove (varstr); Currparams.remove (색인); currparams.remove (index+"_"); }}POM 파일을 첨부하십시오
<project xmlns = "http://maven.apache.org/pom/4.0.0"xmlns : xsi = "http://www.w3.org/2001/xmlschema-instance"xsi : schemalocation = "http://maven.apache.org/pom/0.0.0.0 http://maven.apache.org/maven-v4_0_0.xsd "> <modelversion> 4.0.0 </modelversion> <groupid> com.rd </groupid> <artifactid> parser </artifactid> <packaging> jar </packaging> <version> 1.0-snapshot </version> myparer </version> myparer <Url> http://maven.apache.org </url> <pection 살자> <pectionency> <groupid> dom4j </groupid> <artifactid> dom4j </artifactid> <version> 1.6.1 </version> </fexendency> <groupid> opensymphony </groupid> <artifactid> </artifactid> <버전> 2.6.11 </version> </dependency> <pectomency> <groupId> Commons-Collection </groupId> <artifactid> Commons-Collections </artifactid> <bersion> 3.2.1 </dependency> <pectionency> <groupid> commons-lang </groupid> <artifactid </artifactid> <version> 2.6 </version> 2.6. <pectionency> <groupId> junit </groupId> <artifactID> junit </artifactid> <bersion> 3.8.1 </version> <scope> 테스트 </scope> </dependency> </dependency> <build> <Resources> <Resource> <Resource> <irectory> src/main/java </drierctor> <포함>***. </include> </resource> <bersore> <bersore> <sirectory> <directory> </directory/resource </directory> <clenuary> <clener> <cluper> **/*</resource> </resource> </resources> <TestResources> <TestResource> <directory> $ {project.bausedir}/src/test/testresour> <directory> $ {project.basedir}/src/test/resources </directory> </testresource> </testResources> <플러그인> <groupid> org.apache.maven.plugins </groupid> <artifactid> maven-compiler-plugin </artifactid> </source> </source> 3. <garget> 1.8 </target> <인코딩> UTF-8 </encoding> </configuration> </plugin> </plugins> </build> </project>MyBatis Dynamic SQL을 직접 구현하는 위의 방법은 내가 공유 한 모든 컨텐츠입니다. 나는 당신이 당신에게 참조를 줄 수 있기를 바랍니다. 그리고 당신이 wulin.com을 더 지원할 수 있기를 바랍니다.