MyBatis Extracted Tools-(a) universal tag parser (i.e., ready to use)

Source: Internet
Author: User

In an in-depth understanding of the MyBatis principle, I'm not just trying to understand how the whole mybatis works, but I also want to extract some useful programming methods, programming ideas, annotations, and some utility classes from this process.

1. Introduction 1.1 Mybatis-config.xml in use

In the mybatis-config.xml file, we often see a similar configuration

  <properties> <property name= "Driver" value= "Com.mysql.jdbc.Driver"/> <property name= "url" Value= "Jdbc:mysql://localhost:3306/mybatis"/> <property name= "username" value= "root"/> <property name = "Password" value= "aaabbb"/></properties><environments default= "Development" > <environment id= " Development "> <transactionmanager type=" JDBC "> <property name=" "value=" "/> </t             Ransactionmanager> <datasource type= "Pooled" > <property name= "Driver" value= "${driver}"/> <property name= "url" value= "${url}"/> <!--fill in your database user name--<property name= "U Sername "value=" ${username} "/> <!--fill in your database password--<property name=" password "value=" ${PASSW Ord} "/> </dataSource> </environment></environments>  

Some properties are placed in properties a sub-label under the label, and the value can be removed from the configuration file in the form of ${key} .

You can also configure the properties in an external file to tell the parser the relative path of the external file:

<properties resource="jdbc.properties"></properties>
Used in 1.2 xxxmapper.xml

Of course, in Xxxmapper.xml , we also use it when we write SQL statements, such as

    select    <include refid="Base_Column_List" />    from student    where student_id=#{student_id, jdbcType=INTEGER}

will be #{student_id, jdbcType=INTEGER} replaced with the passed-in parameter.

2. Principle

In MyBatis, it is the class that deals with this process GenericTokenParser .

2.1 Generictokenparser member variables

GenericTokenParserClass has three member variables

// 开始标记private final String openToken;// 结束标记private final String closeToken;// 表处理器private final TokenHandler handler;

As an example,

Parse the ${driver}in the above configuration, then these member variables

openToken="${";closeToken="}";

handleris an TokenHandler interface

public interface TokenHandler {  String handleToken(String content);}

In the actual process, we need to define our own processor, the processor implementation TokenHandler can be, the following example will have an example.

2.2 Generictokenparser Constructors

The constructor is simple enough to assign values to several member variables.

public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {    this.openToken = openToken;    this.closeToken = closeToken;    this.handler = handler;}
2.3 Parsing Process 2.3.1 Overall process

The large process is as follows:

On the whole, it is to find the expression that needs to be processed, replace the contents of the expression with the processed content of the processor, and finally return the final string.

2.3.2 Process Detailed

First look at the code and the comments I gave

public string Parse (string text) {if (text = = NULL | | text.isempty ()) {return "";    }//Starting with the No. 0 bit, look for the start tag subscript int start = Text.indexof (Opentoken, 0);    if (start = =-1) {//cannot be found, return the original parameter return text;    } char[] src = text.tochararray ();    Offset is used to record which int offset = 0 is read by the builder variable;    Builder is the final returned string final StringBuilder builder = new StringBuilder ();    Expression is every time the found expressions are to be processed in the processor StringBuilder expression = null;            while (Start >-1) {if (Start > 0 && src[start-1] = = ' \ \ ') {//start tag is escaped, remove escape character ' \ '            Builder.append (src, offset, start-offset-1). Append (Opentoken);        Offset = start + opentoken.length (); } else {//This branch was found with the closing tag, to find the end tag if (expression = = null) {expression = new Stringbui            Lder ();            } else {expression.setlength (0); }//The string before the start tag is added to the builder builder.append (SRC, offSet, Start-offset);                        Calculates the new offset offset = start + opentoken.length ();            Starting from here find the end of the tag int end = Text.indexof (Closetoken, offset); while (End >-1) {if (End > Offset && src[end-1] = = ' \ \ ') {//This end tag is escaped                    Expression.append (src, offset, end-offset-1). Append (Closetoken);                    Offset = end + Closetoken.length ();                End = Text.indexof (Closetoken, offset);                    } else {expression.append (src, offset, end-offset);                    Offset = end + Closetoken.length ();                Break  }} if (end = =-1) {//Cannot find end tag builder.append (SRC, start, src.length                -start);            offset = src.length; } else {//found the end tag, it is put into the processor for processing builder.append (handler.handletoken (expression. toString ()));            Offset = end + Closetoken.length ();    }}//Because there may be many expressions in the string that need to be parsed, start looking for the next expression, start = Text.indexof (Opentoken, offset); }//The last time the start tag was not found, the offset string is added to the builder if (offset < src.length) {builder.append (src, offset, src.    Length-offset); } return Builder.tostring ();}

If you look at the code, you don't have to look at the detailed procedure below.

The first step: the non-empty processing of parameters

parameter is empty or "", returns "".

if (text == null || text.isEmpty()) {    return "";}

Step two: Find the start tag, declare the variable

    // 从第0位开始, 查找开始标记的下标    int start = text.indexOf(openToken, 0);    if (start == -1) { // 找不到则返回原参数        return text;    }    char[] src = text.toCharArray();    // offset用来记录 builder 变量读取到的位置    int offset = 0;    // builder 是最终返回的字符串    final StringBuilder builder = new StringBuilder();    // expression 是每一次找到的表达式, 要传入处理器中进行处理    StringBuilder expression = null;

If the incoming string does not have a start tag to process, it returns directly without the need to declare a bunch of variables.

If found, the declaration of the variable is made.

Step three: Loop through the tags and handle them

In this example, suppose the start tag is ${and the end tag is }

First, find the start tag first

It is only necessary to find the start tag to find the corresponding end tag, otherwise it is meaningless to find the end tag alone.

We found it ${ , there are two kinds of things:

    1. ${is the start tag
    2. ${is the character we want.

How to distinguish between these two situations, the normal situation is the situation 1, if you want to 2, in the parser, it is necessary to join the escape symbol \\ .

That is, we want to get the characters in the final character ${ , it should be written like this \\${ .

In case 2, the parser is treated like this

 builder.append(src, offset, start - offset - 1).append(openToken); offset = start + openToken.length();

Remove the transfer character and add the string to the builder. The location at which the record was resolved offset. Continue to find the next start tag.

For Case 1,

Next, find the end tag

We found it } , there are two kinds of things:

    1. } is the start tag
    2. } is the character we want.

Then, as before, Case 2 also needs to be transferred to distinguish between tokens. Case 2 Treatment

 // 此结束标记是转义的expression.append(src, offset, end - offset - 1).append(closeToken);offset = end + closeToken.length();end = text.indexOf(closeToken, offset);

Remove the transfer character and add the string to the builder. The location at which the record was resolved offset. Continue to find the next closing tag until you find Case 1, then jump out of the loop.

For Case 1, get ${ and } between the table string as expression , continue down

Processor Processing

 // 找到了结束的标记, 则放入处理器进行处理builder.append(handler.handleToken(expression.toString()));offset = end + closeToken.length();

Finally, as long as you haven't found the last one, continue looking for the next start tag

start = text.indexOf(openToken, offset);
3. Testing
  @Test  public void simpleTest() {    GenericTokenParser parser = new GenericTokenParser("${", "}", new VariableTokenHandler(new HashMap<String, String>() {      {        put("driver", "com.mysql.jdbc.Driver");        put("url", "jdbc:mysql://localhost:3306/mybatis");        put("username", "root");        put("password", "aaabbb");      }    }));    // 测试单个解析    assertEquals("com.mysql.jdbc.Driver", parser.parse("${driver}"));    // 多个一起测试    assertEquals("驱动=com.mysql.jdbc.Driver,地址=jdbc:mysql://localhost:3306/mybatis,用户名=root",            parser.parse("驱动=${driver},地址=${url},用户名=${username}"));  }
4 Code

If you need code, please visit my github.

If you have any questions, please communicate with me.

MyBatis Extracted Tools-(a) universal tag parser (i.e., ready to use)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.