Descobri que é realmente difícil insistir em escrever um blog, e várias razões levarão à necessidade de cuidar do blog. Originalmente, planejava escrever uma implementação de bricolage do ORM e ver a hora. Prefiro implementar um SQL dinâmico primeiro e adicionar a implementação completa do ORM na próxima vez que tiver tempo.
As pessoas que usaram Mybatis provavelmente estão familiarizadas com o SQL dinâmico. Se você ainda não o usou, dê uma olhada na diversão. A primeira vez que entrei em contato com o MySQL foi quando eu estava no meu último ano. Naquela época, eu pensei que o SQL dinâmico era muito incrível e flexível. Eu sempre quis descobrir como implementá -lo. Embora eu pudesse escrever o IOC, o MVC e as estruturas simples do ORM naquele momento (imitar MyBaits, mas não há parte dinâmica do SQL), ainda não consegui encontrar onde implementar o SQL dinâmico no núcleo de Mybatis e como implementá -lo. Talvez o código estivesse muito emaranhado e eu não conseguia entender. Até agora, eu não tinha coragem de ler a parte dinâmica de SQL de Mybatis. Talvez eu tenha nascido com admiração inexplicável de algoritmos.
Alguns anos atrás, porque eu queria criar uma plataforma de configuração e queria usar um idioma de análise para substituir a implementação do Java, o que permitia que o pessoal da configuração escrevesse facilmente uma pequena quantidade de código na página para implementar a lógica de negócios complexa (incluindo operações de banco de dados). Naquela época, Java já tinha um mecanismo de análise JS, mas a maioria das pessoas disse que a eficiência era muito baixa. Se eu não soubesse o que eu era louco, pensei em implementar uma linguagem de análise. No entanto, sempre sonhei em perceber minha própria língua. É mais fácil começar com idiomas analíticos do que os idiomas compilados, então comecei a fazê -lo decisivamente. Depois de escrevê -lo, percebi que minha implementação provavelmente não é tão eficiente quanto o mecanismo JS naquele momento. Naquela época, eu era muito jovem e simples. A implementação dinâmica de SQL sobre a qual estou falando hoje é realmente inspirada na linguagem de análise naquele momento.
Vamos falar sobre SQL dinâmico sem dizer muita bobagem. Por favor, veja o exemplo a seguir. Primeiro, declaro que o exemplo aqui não é uma maneira correta de escrever SQL. Eu só quero escrever uma estrutura aninhada que seja o mais complexa possível. Se essa situação complexa for implementada, é ainda mais difícil torná -la simples.
Exclua de pl_pagewidget <if test = "widgetCodes! = null"> where PageWidgetCode em <foreach collection = "widgetcodes" item = "item" index = "index" Open = "(" Separator = "Close =") "> <se test =" Índice == 0 "> #{}} </se> Open = "(" separador = "," Close = ")"> #{b} </ -foreach> </foreach> </if> <se test = "a! = null"> e a = #{a} </f>Para implementar o SQL para analisar o exemplo acima, uma das dificuldades é semelhante a como determinar as condições verdadeiras ou falsas no atributo de teste. No entanto, essa dificuldade está mais na frente da expressão de OGNL aprendida no Struts2. Não sei se um amigo encontrou um fenômeno bastante estranho, ou seja, às vezes a seguinte expressão é escrita no SQL dinâmico de Mybatis, mas quando n = 0, na verdade atende à condição, ou seja, o valor no teste é falso e 0 não pode atender às condições dessa expressão. Esta é a razão da biblioteca Ognl. Não há como isso apenas toca como este, apenas lembre -se disso como uma situação especial
teste = "n! = nulo e n! = ''"
A expressão de Ognl é muito conveniente de usar da seguinte maneira
importar java.util.hashmap; importar java.util.map; importar ognl.ognl; public class OgnlTest {// Resultado da saída: false public static void main (string [] args) lança exceção {string con1 = "n! = null e n! = '' ';; Mapa <string, object> root = new hashmap <> (); root.put ("n", 0); System.out.println (Ognl.getValue (con1, root)); }}Para implementar o SQL para analisar o exemplo acima, a segunda dificuldade é que, embora esse SQL seja coberto com uma camada de XML, é um SQL padrão, como segue
<sql> Exclua de pl_pageWidget <if test = "widgetCodes! = null"> where PageWidgetCode em <foreach collection = "widgetcodes" item = "item" index = "index" "BEIRS =" ("Item =", "Close =") "> <se test =" = "para" B ">} (}}", "Close =") "> <se test =" = "=="> index = "index1" Open = "(" separador = "," Close = ")"> #{b} </fastyeeach> </foueach> </f if> <if test = "a! = null"> e a = #{a} </if> </sql>No entanto, analisar o XML acima é diferente dos nossos habituais. Este XML é uma mistura de tags e texto. Normalmente, raramente devemos usar a análise deste XML no desenvolvimento. No entanto, a ferramenta comumente usada para analisar XML DOM4J pode realmente analisar esse tipo de SQL muito bem, mas raramente é usado. O método content () da classe elemento pode retornar uma coleção de nós, depois atravessar esta coleção e julgar o tipo de cada nó. Depois de resolver esses dois pontos -chave, você só precisa adicionar um pequeno truque para analisar esse SQL dinâmico.
O truque que usei foi inspirado no formato de sintaxe Java. Por exemplo, existem variáveis locais e variáveis globais em Java, e a situação de passagem de referência não é considerada. Se a variável global int i = 1; A variável global é passada para o método e depois modificada no método. O que você vê no método é o valor alterado, mas o que você vê fora do método ainda é 1. Na verdade, você deve conhecer esse fenômeno depois de aprender Java. Além disso, quando o método é chamado, você pode ver variáveis globais e variáveis locais no método. Depois que a chamada do método é concluída, as variáveis locais serão limpas e liberadas (fique feliz em ver o coletor de lixo). Eu os apresentei e adicionei diretamente o código
importar java.io.stringReader; importar java.text.simpledateFormat; importar java.util.arrays; importar java.util.date; importar java.util.hashmap; import java.util.list; import java.util.athAp; importação; org.apache.commons.collections.maputils; importar org.apache.commons.lang.stringutils; importar org.dom4j.document; importar org.dom4j.element; import org.dom4j.node; importar org.dom4j.text; import ousl; com.rd.sql.basenode; import com.rd.sql.nodeFactory; public class sqlparser {private map <string, object> currparams = new hashmap <string, object> (); /** Exclua de pl_pagewidget <if test = "widgetCodes! = null"> onde página widgetCode em <foreach collection = "widgetCodes" item = "item" index = "index" "(" bys) (")," ry Índice = "Índice", "Índice", "Index =" Index = "ndInd =" " #" #" #" Index = "Index =" Index = "ndInd =" " #" BETATATATETETATATATETATETATETATETETE ") open = "(" separador = "," close = ")"> #{b} </freeach> </temeach> </if> <se test = "a! map.put ("widgetCodes", Arrays.asList ("1", "2")); map.put ("BS", Arrays.asList ("3", "4")); map.put ("A", 1); Pastor sqlparser = new sqlParser (); System.out .println (parser.parser ("Excluir de pl_pagewidget/n" + "/t <se test =/" widgetCodes! separador =/",/" close =/")/">/n " +"/t/t <se test =/"index == 0/">/n " +"/t/t #{item}/n " +"/t/t </se>/n " +"/t/t <forech coletor =/"bs/" item =/"b/" b/"b/" b/"b/" close =/")/">/n " +"/t/t/t #{b}/n " +"/t/t </foreach>/n " +"/t/t </foreach>/n " +"/t </if>/n " +"/t <se teste =/"a! mapa)); System.out.println (parser.getparams ()); } public string parser (string xml, map <string, object> params) lança a exceção {// xml = "<? xml versão =/" 1.0/"coding =/" utf-8/"?>"+xml; // Defina uma camada de tags xml para a dinâmica de entrada sql xml = "<sql>"+xml+"</sql>"; SAXReader Reader = new SaxReader (false); Documento documento = leitor.read (new StringReader (xml)); Elemento elemento = document.getrootelement (); Mapa <string, objeto> currParams = new Hashmap <string, object> (); Stringbuilder sb = new stringbuilder (); // iniciar o pálido (elemento, currparams, params, sb); return sb.toString (); } / ** * Use o analisador recursivo para analisar sql dinâmico * @param ele1 xml tag para ser analisado * @param currparams * @param globalparams * @param sb * @ThThrows Exception * / private void parserelement (elemento ele1, mapa <string, object> strpParams <string <string, string (strings) (elemento e elemento, mapa <string, stringsb) / string (strings) (elementos e elemento, mapa <string, strings) / strings) Um nó, por exemplo, analise um nó if, se o teste determina true, ele retorna true. Tempval val = parseroneElement (currparams, globalparams, ele1, sb); // O objeto de nó abstrato do nó diminuiu o nó Basenode = val.getNode (); /*** De fato, a declaração acima desta frase apenas analisa a tag XML e não analisa o conteúdo na tag. Aqui * significa que, antes de analisar o conteúdo, se houver uma pré-operação, faça alguma pré-operação */ node.pre (currparams, GlobalParams, ele1, sb); // Defende se o conteúdo no nó ainda precisa ser analisado, por exemplo, se o resultado do teste for verdadeiro sinalizador booleano = val.ISCONTinue (); // Obtenha uma coleção de todos os nós filhos neste nó, incluindo a lista de texto normal <Node> nós = ele1.content (); if (sinalizador &&! modes.isempty ()) { /*** Isso significa que você deseja analisar ainda mais o conteúdo no nó. Você pode comparar o nó no shell de um método* O conteúdo do interior é análogo às instruções específicas no método. Antes de começar a analisar o conteúdo do nó* Crie um contêiner com parâmetros locais neste nó. O mais conveniente é obviamente mapa */ mapa <string, object> params = new hashmap <string, object> (); /*** Coloque os parâmetros locais passados diretamente diretamente para o contêiner, porque os parâmetros neste exemplo são tipos de dados comuns* Não haverá tipo de referência; portanto, isso é equivalente a uma cópia. Para não afetar o objeto passado por fora*, você pode comparar o caso em que o método chama os parâmetros de entrada*/ params.putall (currParams); // loop todos os nós filhos para (int i = 0; i <modes.size ();) {nó n = modes.get (i); // se o nó for um texto normal se (n instanceof text) {string text = ((text) n) .getStringValue (); if (stringUtils.isnotEmpty (text.trim ())) {// treinar o texto, como o processamento #{xx}, substitua diretamente $ {yy} pelo valor real aprovado em sb.append (manutenção manual (text, params, globalParams)); } i ++; } else if (n instanceof elemento) {elemento e1 = (elemento) n; // Analisar recursivamente os elementos infantis XML (E1, Params, GlobalParams, SB); // Se o sinalizador de loop não for verdadeiro, analise a próxima tag // Isso significa que você precisa analisar repetidamente a etiqueta de loop, então não mudarei; caso contrário, continuarei processando o próximo elemento boolean while_flag = maputils.getboonen (params, attrs.while_flag, false); if (! while_flag ||! nodeFactory.ishile (n.getName ()) || e1.attributeValue (atts.index) == null ||! e1.attributeValue (atts.index) .equals (params.get (atts.while_index)) {i ++; }}} // o que devo fazer após o node nó node.after (currparams, globalparams, ele1, sb); // Recicle o parâmetro de escopo atual params.clear (); params = null; }} /** * Processe o texto para substituir o parâmetro #{item} * @param str * @param params * @return * @throws exceção * /private string manualtText (string str, map <string, object> params, map <string, object> GlobalParams) lança excepção {// obtenha o variável stringstr = maputils.get; Índice inteiro = nulo; if (stringUtils.isnotEmpty (indexstr)) {index = maputils.getInteger (params, indexstr); } // corresponde a #{a} parâmetro string reg1 = "( #// {) (// w+) (//})"; // corresponde ao parâmetro de $ {a} string reg2 = "(// $ // {) (// w+) (//})"; Padrão p1 = padrão.compile (reg1); Matcher M1 = P1.Matcher (STR); Padrão p2 = padrão.compile (reg2); Matcher M2 = P2.Matcher (STR); String whilelist = maputils.getString (params, atts.while_list); Mapa <string, objeto> allParams = getAllParams (params, globalParams); while (m1.find ()) {string tmpkey = m1.group (2); String key = whilelist == null? Tmpkey: (whilelist+"_"+tmpkey); key = index == NULL? Tecla: (chave+índice); String rekey = "#{"+key+"}"; // Se em um loop semelhante ao foreach, pode ser necessário substituir o parâmetro #{xx} por #{xx_0}, #{xx_1} str = str.replace (m1.group (0), rekey); currparams.put (chave, allParams.get (tmpkey)); } while (m2.find ()) {string tmpkey = m2.group (2); Valor do objeto = allParams.get (tmpkey); if (value! = null) {str = str.replace (m2.group (0), getValue (valor)); }} retornar str; } private string getValue (valor do objeto) {string result = ""; if (Instância do valor de data de data) {SimpleDateFormat sdf = new SimpleDateFormat ("AAAA-MM-DD HH: MM: SS"); resultado = sdf.format ((date) valor); } else {resultado = string.valueof (value); } resultado de retorno; } mapa privado <string, objeto> getAllParams (map <string, object> currparams, map <string, object> globalParams) {map <string, object> allParams = new hashmap <string, object> (); allParams.putall (GlobalParams); allParams.putall (currparams); devolver allparams; } // Analisar um elemento XML ParseroneElement privado de Tempval (map <string, objeto> currparams, map <string, object> globalparams, elemento ele, elemento, stringbuilder sb) lança exceção {// obtendo o nome da tag xml string elename = ele.getname (); // continua depois de analisar um nó? Se você encontrar um nó como se, precisar determinar se o teste está vazio. boolean isContinue = false; // Declare um nó abstrato Basenode Node = NULL; if (stringutils.isnotEmpty (elename)) {// use a fábrica do nó para obter um objeto de nó com base no nome do nó, como se o nó ou foreach node = nodeFactory.create (elename); // Analise esse nó e retorne se o conteúdo no nó ainda precisa ser analisado ISCONTinue = Node.parse (currparams, GlobalParams, ELE, SB); } retornar novo tempval (iscontinue, ele, nó); } mapa público <string, objeto> getParams () {return currParams; } / *** encapsula o resultado após o elemento XML ser analisado* @author rongdi* / classe estática final tempval {private boolean isContinue; elemento privado ele; Nó basenode privado; public tempval (boolean iscontinue, elemento ele, nó de basénete) {this.iscontinue = isContinue; this.ele = ele; this.node = node; } public boolean isContinue () {return isContinue; } public void setContinue (boolean isContinue) {this.ISCONTinue = isContinue; } elemento público getEle () {return ele; } public void setEle (elemento ele) {this.ele = ele; } public basenode getNode () {return node; } public void setNode (nó Basenode) {this.node = node; }}} importar org.dom4j.Element; importar java.util.hashmap; importar java.util.map;/*** nó abstrato* @author rongdi*/public class Basenode {public abstract boolean parse (map <string, objeto> Currparams, mapa <string, object> globalParams, elentee eLese, (string, string> currparams, mapa <string, object> globalParams, elentee, ele. public void pré (map <string, objeto> currparams, mapa <string, object> globalParams, elemento ele, stringbuilder sb) lança exceção {} public void depois (map <string, object> currParams, mapa <string, object> object> globalParams, element eLe, stringbuilder sb) throws excepção <} mapa <} mapa <protegido> Mapa <string, object> globalParams) {map <string, object> allParams = new Hashmap <string, object> (); allParams.putall (GlobalParams); allParams.putall (currparams); devolver 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 extends BaseNode{ @Override public boolean parse(Map<String, Object> currParams, Map<String, Object> globalParams, Element ele, Stringbuilder sb) lança exceção {// obtenha o atributo de teste de se node string teststr = ele.attributeValue ("teste"); teste booleano = false; tente {if (stringUtils.isnotEmpty (teststr)) {// mescla variáveis globais e variáveis locais mapear <string, object> allParams = getAllParams (currparams, globalparams); // Use o OGNL para determinar o teste verdadeiro ou falso = (booleano) ognl.getValue (teststr, allParams); }} catch (Exceção e) {e.printStackTrace (); lançar uma nova exceção ("parâmetros de operação do juiz"+teststr+"ilegal"); } if (ele.content ()! = null && ele.content (). size () == 0) {test = true; } teste de retorno; }} importar java.util.ArrayList; importar java.util.hashmap; importar java.util.list; importar java.util.map; importar java.util.set; importar ognl. org.dom4j.Element;/** Os atributos do nó foreach são os seguintes itens de coleta que precisam ser atravessados. O índice variável armazenado em cada elemento após atravessar a coleção. O número de índice da coleção é como 0, 1, 2 ... separador após atravessar, emenda aberta com um separador especificado. Os símbolos que iniciam a emenda após a travessia são os seguintes (fecham os símbolos que terminam o splicing após a travessia são os seguintes) */classe pública foreachnode estende basenode {@Override public boolean parse (map <string, objeto> currparams, map <string> objectParams, elemento ELEME (stringbu, String, string> strings, string); String collectionstr = ele.attributeValue ("coleção"); String itemstr = ele.attributeValue ("item"); String index = ele.attributeValue ("index"); String separatorstr = ele.attributeValue ("separador"); String openStr = ele.attributeValue ("aberto"); String throuchSet = ele.attributeValue ("Close"); if (stringutils.isEmpty (index)) {index = "index"; } if (stringUtils.isEmpty (separatorStr)) {separatortr = ","; } if (stringUtils.isnotEmpty (OpenStr)) {currparams.put (atts.while_open, openStr); } if (stringUtils.isnotEmpty (ClosetST)) {currParams.put (atts.while_close, touchetST); } if (stringUtils.isnotEmpty (coletionStr)) {currParams.put (atts.while_list, coletionCring); } currParams.put (atts.while_separator, separatortr); if (index! = null) { /*** Se houver o valor da variável de loop atual na variável local, significa que não é a primeira vez que você inseriu a etiqueta do loop. Remova a etiqueta inicial * e adicione 1 ao valor da variável local */ if (currparams.get (index)! = Null) {currparams.remove (atts.while_start); currParams.put (index+"_", (inteiro) currParams.get (index+"_")+1); } else {// A primeira vez que você insere o rótulo de loop currparams.put (attrs.while_start, true); currParams.put (índice+"_", 0); } currparams.put (índice, (inteiro) currParams.get (index+"_")); } condição booleana = true; Mapa <string, objeto> allParams = getAllParams (currparams, GlobalParams); Coleção de objetos = nulo; if (stringUtils.isnotEmpty (coletionStr)) {// Obtenha a coleção a ser looped collection = Ognl.getValue (coleção, allParams); // Se a propriedade de coleção não estiver vazia, mas a condição é nula, uma condição de contorno será adicionada por padrão se (stringutils.isempty (conditionStr)) {// aqui vou usar apenas uma coleção para demonstrá -la. Você também pode adicionar uma matriz, mas basta alterá -la para .length if (coleta de instância de list) {conditionStr = index+"_ <"+collectionStr+". Size ()"; } else if (coleta instância do mapa) {map map = (map) coleta; Set set = map.entrySet (); Lista da lista = new ArrayList (set); allParams.put ("_ list_", lista); conditionstr = index+"_ <_ list _"+". size ()"; }}} currparams.remove (atts.while_end); if (stringUtils.isnotEmpty (conditionStr)) {// o valor da condição de cálculo da condição = (boolean) ognl.getValue (conditionStr, allParams); Mapa <string, objeto> tempmap = new hashmap <> (); tempmap.putall (allParams); tempmap.put (index+"_", (inteiro) currParams.get (index+"_")+1); currParams.put (atts.while_end ,! (boolean) ognl.getValue (condicionalstr, tempmap)); } bandeira booleana = true; currParams.put (atts.while_index, index); currParams.put (atts.while_flag, true); if (condition) {try {if (stringUtils.isnotEmpty (itemstr) && stringUtils.isnotEmpty (collectionStr)) {value objeto = null; int idx = intoger.parseInt (currparams.get (index+"_"). tostring ()); if (Coleção Instância de lista) {value = ((list) coleta) .get (idx); currParams.put (itemstr, valor); } else if (coleta instância do mapa) {map map = (map) coleta; Set <pap.entry <string, object >> set = map.entrySet (); List <pap.entry <string, object >> list = new ArrayList (set); currParams.put (itemstr, list.get (idx) .getValue ()); currParams.put (índice, list.get (idx) .getKey ()); }}} Catch (Exceção e) {THRET NOVA Exceção ("Obtenha valor de uma coleção ou mapa"+currParams.get (index)+"Error"+E.getMessage ()); }} else {flag = false; DestroyVars (currparams, índice, itemstr); } retornar sinalizador; } / *** Se for a primeira vez que você insere a etiqueta do loop, soletre o conteúdo de Open* / @Override public void pré (map <string, objeto> currparams, map <string, objeto> globalparams, elemento elem, stringbuilder sb) lança exceção {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 (aberto); }} / *** Se a etiqueta do loop for finalmente inserida, o conteúdo de fechamento será escrito no final* / @Override public void depois (map <string, objeto> currparams, map <string, object> globalparams, elemento elemento, stringbuilder sb) lança excepção {super.after (currParams, GlobalParams, eLE, eLe, SB) SB); BOOLEAN END = MAPUTILS.GETBOOLEAN (currparams, attrs.while_end, false); String separador = maputils.getString (currparams, atts.while_separator); if (! end && stringUtils.isnotEmpty (separador)) {sb.append (separador); } if (end) {string close = maputils.getString (currparams, attrs.while_close); if (sb.toString (). endswith (separador)) {sb.deleteCharat (sb.length () - 1); } sb.append (feche); }} // Libere a variável temporária private privarvarvars (map <string, objeto> currparams, string índice, string varstr) {currparams.remove (atts.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); }} importar org.dom4j.element; importar java.util.map; classe pública sqlnode estende basenode {@Override public boolean parse (map <string, object> currparams, map <string, objeto> globalparams, elemento ele, stringbuilder sb) Throws Exception {return; }} importar java.util.arrays; importar java.util.list; importar java.util.map; importar java.util.concurrent.concurrenthashmap;/*** node fábrica*/public classe NodeFactory {private static <String, Basenode> nodemApTory = NewMAHATH = NewMaTh; Lista estática final privada <String> whilelist = Arrays.asList ("foreach"); static {nodeMap.put ("se", novo ifNode ()); nodemap.put ("sql", new sqlNode ()); nodeMap.put ("foreach", novo foreachnode ()); } public static boolean iswhile (string elementName) {return whilelist.contains (elementName); } public static void addNode (string nodename, nó basenode) {nodemap.put (nodename, nó); } public static basenode Create (string nodename) {return nodeMap.get (nodename); }}/*** Várias tags* @author rongdi*/public class Attrs {public final static string transactional = "transacional"; string estática final pública while_start = "while-start"; string estática final pública while_end = "while-end"; string estática final pública whren_open = "while-aben"; string estática final pública while_close = "whilefLose"; string estática final pública while_separator = "while-Separator"; string estática final pública whrening_index = "while-index"; string estática final pública while_flag = "while-flag"; string estática final pública while_list = "while-list"; string estática final pública quando_flag = "when-flag"; public static final string process_var = "process-var"; public final Static String result_flag = "Result-Flag"; public final Static String return_flag = "Return-flag"; public final Static String Console_var = "Console-Var"; Public final Static String do = "Do"; Public final Static String Index = "Index"; Public final Static String Condition = "Condição"; Public final Static String Name = "Nome"; Public final Static Static String value = "value"; public static final string type = "type"; public static final string format = "formato"; public static final string if = "if"; public static final string else = "else"; public final Static String file = "arquivo"; public static final string date = "date"; public static final string agora = "agora"; public static final string decimal = "decimal"; public static final string id = "id"; public static final string params = "params"; public static final string Target = "Target"; public static final string único = "single"; public static final string paging = "paging"; public static final string desc = "desc"; public static final final string break = "break"; Public Static Final String continuar = "Continuar"; Coleção public estática final de string = "Coleção"; public static final string var = "var"; public Static final String Execoror = "Executor-1"; public static final string rollback_flag = "rollback-flag"; public static final string Service = "Service"; public static final string ref = "ref"; public static final string bizs = "bizs"; public static final string titles = "títulos"; public static final string colunns = "colunas"; public static final string curruser = "curruser"; public static final string currperm = "currperm"; public static final string task_executor = "taskexecutor"; public static final string delimiter = "delimiter"; public static final string operername = "OperName"; } currparams.remove (varstr); currparams.remove (índice); currparams.remove (índice+"_"); }}Anexe o arquivo 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/4.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> <name>myparser</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>opensymphony</groupId> <artifactId>ognl</artifactId> <version>2.6.11</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependency> </dependencies> <build> <resources> <resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </inclui> </Resource> <cource> <Directory> src/main/recursos </diretório> <inclui> <cluir> **/*</incluir> </Resource> </Resources> </testResources> <TestResOrces> <TestResource> <Directory> $ {Project.basedir}/src/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/testrc/teste <Directory> $ {Project.Basedir}/src/test/Resources </Diretório> </testResource> </souseResources> <flugins> <puperid> org.apache.maven.plugins </groupid> <stifactId> maven-compiler-plugin </</ArtifactId7 <-Target> 1.8 </-TARGEN> <Coding> utf-8 </coding> </figuration> </plugin> </plugins> </fruct> </project>O método acima para implementar o Mybatis Dynamic SQL sozinho é todo o conteúdo que compartilhei com você. Espero que você possa lhe dar uma referência e espero que você possa apoiar mais o wulin.com.