This is the 9th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

Mybatis supports OGNL syntax

OGNL is an object-graph Navigation Language with the syntax #{}.

Don’t you have any idea what this is?

OGNL function is to do data interaction between the object and the view, you can access the attributes of the object and call the method of the object, through the expression can iterate out the structure of the whole object.

e1 or e2 e1 and e2 e1 == e2,e1 eq e2 e1 ! = E2, E1 NEq e2 E1 lt e2: less than e1 LTE E2: less than or equal to other gt (greater than), GTE (greater than or equal to) E1 in E2 E1 not in E2 E1 + E2, E1 * e2, E1 /e2, E1-E2, E1 %e2! E, not e: E.thod (args) calls object methods e.perty Object property values E1 [e2] Values by index, List, array, and Map @class@method(args) calls static methods of a class @class@field calls static field values of a classCopy the code

There are also expressions for assigning or enhancing properties. The bind tag is often used for fuzzy searches:

<bind name="nameLike" value="'%'+ name + '%'"/>
Copy the code

E1 +e2 is the OGNL expression for the value e1+e2 is the OGNL expression for the value e1+e2.

  • e1*e2The multiplication
  • e1/e2division
  • e1-e2subtraction
  • e1%e2modulus

Used to resolve static methods

org.apache.ibatis.scripting.xmltags.TextSqlNode.BindingTokenParser#handleToken org.apache.ibatis.scripting.xmltags.OgnlCache#getValue Org. Apache. Ibatis. Scripting. Xmltags. OgnlCache# parseExpression analytic expression org. Apache. Ibatis. Ognl. Ognl# parseExpression org.apache.ibatis.ognl.OgnlParser#staticReference org.apache.ibatis.ognl.OgnlParser#staticMethodCall org.apache.ibatis.ognl.OgnlRuntime#callStaticMethodCopy the code

The following methods can be introduced in SQL mapping statements:

<select id="getUserById" resultMap="BaseResultMap">
       select * from user
       <if test="id ! = null">
           <where>
                 name = #{name}
                 and id =${id}
                 and id = ${user.id}
                 and id = ${@@abs(-12345678)}
                 and id = ${@@parseInt("654")}
                 and id='${@cn.followtry.mybatis.bean.User@name()}'
                 and id='${new cn.followtry.mybatis.bean.User()}'
                 and id=${@cn.followtry.mybatis.bean.User@haha}
                 and id='${@cn.followtry.mybatis.bean.User@arr[1]}'
                 and id='${@cn.followtry.mybatis.bean.User@list[1]}'
                 and id='${@[email protected]("123")}'
                 and id='${@[email protected]()}'
             </where>
         </if>
       limit 100
</select>
Copy the code
  • Variable: id =${id}

  • Attribute: id = ${user.id}

  • Static methods (public) : id = ‘${@ cn. Followtry. Mybatis. Beans. User @ the name ()}’

  • Static attributes (public) : id = ${@ cn. Followtry. Mybatis. Beans. User @ aaa}

  • Array index: id = ‘${@ cn. Followtry. Mybatis. Beans. User @ arr [1]}’

  • Collection: ‘${@ cn. Followtry. Mybatis. Beans. User @ the list [1]}’

  • The Map:

  • Method: id = ‘${new cn. Followtry. Mybatis. Bean. The User ()}’

  • Java.lang.Math method: id = ${@@abs(-12345678)} can omit class writing, the default class is java.lang.Math

The ${} syntax uses two @ characters, the former to locate a Java class, and the latter to locate a method or attribute in the class. This is only part of the list.


  • Let’s do a little example
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
 
import com.hotent.core.util.BeanUtils;
 
public class Ognl {
    public Ognl(a) {}public static boolean isEmpty(Object o) throws IllegalArgumentException {
        return BeanUtils.isEmpty(o);
    }
 
    public static boolean isNotEmpty(Object o) {
        return! isEmpty(o); }public static boolean isNotEmpty(Long o) {
        return! isEmpty(o); }public static boolean isNumber(Object o) {
        returnBeanUtils.isNumber(o); }}Copy the code
<select id="getAll" parameterType="java.util.Map" resultMap="TaskEntity">
  SELECT task.*,run.subject subject,run.processName processName
  FROM ACT_RU_TASK task left join BPM_PRO_RUN run
  on task.PROC_INST_ID_=run.actInstId
  where 1=1
  <if test="@Ognl@isNotEmpty(name)"> AND task.name_ LIKE #{name} </if>
  <if test="@Ognl@isNotEmpty(subject)"> AND run.subject LIKE #{subject} </if>
  <if test="@Ognl@isNotEmpty(processName)"> AND run.processName LIKE #{processName} </if>
  <if test="@Ognl@isEmpty(orderField)">
    order by task.CREATE_TIME_ desc
  </if>
  <if test="@Ognl@isNotEmpty(orderField)">
    order by ${orderField} ${orderSeq}
  </if>		
</select>
Copy the code

Class built-in methods

Mybatis mapper. XML can also use the built-in method of the object, for example, we need to determine whether a java.util.Collection is empty, we can say:

<if test="collection! =null and collection.size()> 0"> and some_col = #{some_val} </if>Copy the code

This uses the object’s built-in method collection.size ().

We can also call the static method of our custom object CollectionUtils to determine if the collection is empty:

package cn.felord.util; public final class CollectionUtils { public static boolean isNotEmpty( Collection<? > collection) { return (collection ! = null && ! collection.isEmpty()); }}Copy the code

<if test="@cn.felord.util.CollectionUtils@isNotEmpty(collection)">
  and some_col = #{some_val}
</if>
Copy the code

Don’t forget to include the fully qualified name of the class.

Operating values

Value, if the object is directly e.p roperty, if it is a collection or Map can e [index | key], by index or keys to values. Here are some examples:

# array[1] # map['username']Copy the code

Static attributes can also be called, like the static method above:

@cn.felord.Cache@user
Copy the code

Corresponding Java code:

package cn.felord;

public final class Cache {
    public static User user = new User ("felord.cn") ;
}
Copy the code

The assignment operation

The above values can also be used to assign values to SQL parameters:

<where> <! Username = #{username} <! And user_id =${userId} <! And id = ${user.id} <! -- Math. Abs double @ shorthand - > and age = ${@ @ abs (12345678)} <! And gender =${@[email protected]()} and id=${@[email protected]} </where>Copy the code

The ${} symbol allows you to use OGNL expressions to assign values to SQL parameters, but feels like a rare use.


  • right<bind>Arguments can be called through# {}orThe ${}Method to obtain,# {}Can prevent injection:<bind>thevalueValues are computed using OGNL
<bind name="username_bind" value='@java.util.UUID@randomUUID().toString().replace("-", "")' />
Copy the code
  • Use OGNL to achieve a single table table function

This function is a new function in the general Mapper, allows you to specify a table name at runtime, by the specified table name operations on the table. This functionality is implemented using OGNL.

First, not all tables need this functionality, so we define an interface that allows dynamic table names when arguments (interface methods have only one argument, the entity class) objects inherit this interface.

public interface IDynamicTableName {
    /** * gets the dynamic table name - as long as there is a return value, other than null and '', the return value is used as the table name *@return* /
    String getDynamicTableName(a);
}
Copy the code

Then write the table name in XML using:

<if test="@tk.mybatis.mapper.util.OGNL@isDynamicParameter(_parameter) and dynamicTableName ! = null and dynamicTableName ! = "">
    ${dynamicTableName}
</if>
<if test="@tk.mybatis.mapper.util.OGNL@isNotDynamicParameter(_parameter) or dynamicTableName == null or dynamicTableName == ''">
    defaultTableName
</if>
Copy the code

Since I need to determine whether _parameter inherits the IDynamicTableName interface, simple writing is not possible, so I use static methods, which are as follows:

/** * Check whether the parameter supports dynamic table names **@param parameter
 * @returnFalse */ is not supported
public static boolean isDynamicParameter(Object parameter) {
    if(parameter ! =null && parameter instanceof IDynamicTableName) {
        return true;
    }
    return false;
}

/** * Check whether b supports dynamic table names **@param parameter
 * @returnFalse */ is supported
public static boolean isNotDynamicParameter(Object parameter) {
    return! isDynamicParameter(parameter); }Copy the code

Select which table name to use based on the result of the

judgment. DynamicTableName = getDynamicTableName = getDynamicTableName = getDynamicTableName = getDynamicTableName = getDynamicTableName