mybatis OGNL+优雅处理简单逻辑

mybatis 对 mccmncs 字符串处理 :310_-1,311_-1,312_-1,313_-1

复制代码
mybatis 
<if test="params.mccmncs != null and params.mccmncs != ''">
                AND (
                <foreach collection="params.mccmncs.split(',')" item="mccmnc" separator=" OR ">
                    <if test="mccmnc != null and mccmnc != ''">
                        <choose>
                            <!-- 如果当前项是 -1,只匹配 country -->
                            <when test="mccmnc.split('_')[1] == '-1'">
                                rbi.country = ${mccmnc.split('_')[0]}
                            </when>
                            <!-- 如果当前项不是 -1,需要检查同一个 country 是否存在 -1 -->
                            <otherwise>
                                <choose>
                                    <!-- 检查是否存在同 country 的 -1 项 -->
                                    <when test="params.mccmncs.contains(mccmnc.split('_')[0] + '_-1')">
                                        <!-- 如果存在 -1,跳过此条件(通过 1=0 实现) -->
                                        1 = 0
                                    </when>
                                    <!-- 如果不存在 -1,正常匹配 -->
                                    <otherwise>
                                        (rbi.country = ${mccmnc.split('_')[0]} AND rbi.operator = ${mccmnc.split('_')[1]})
                                    </otherwise>
                                </choose>
                            </otherwise>
                        </choose>
                    </if>
                </foreach>
                )
            </if>

这是 **MyBatis 动态 SQL** 的语法,它使用 **OGNL (Object-Graph Navigation Language)** 表达式语言。让我详细解析一下:

OGNL 表达式语言

MyBatis 的动态 SQL 中的 `test` 属性使用的是 OGNL 表达式,它支持很多 Java 对象的方法和操作。

1. **支持的字符串方法**

OGNL 可以调用 Java String 类的所有方法:

```xml

XML 复制代码
<!-- 常用的字符串方法 -->
<if test="params.mccmncs != null and params.mccmncs != ''">
    <!-- split() - 分割字符串 -->
    <foreach collection="params.mccmncs.split(',')" item="item">
    
    <!-- contains() - 包含检查 -->
    <when test="params.mccmncs.contains('_-1')">
    
    <!-- startsWith() - 开头检查 -->
    <when test="item.startsWith('460')">
    
    <!-- endsWith() - 结尾检查 -->
    <when test="item.endsWith('-1')">
    
    <!-- length() - 长度 -->
    <when test="item.length() > 5">
    
    <!-- substring() - 截取 -->
    <when test="item.substring(0, 3) == '460'">
    
    <!-- trim() - 去除空格 -->
    <when test="item.trim() != ''">
    
    <!-- toUpperCase() / toLowerCase() - 大小写转换 -->
    <when test="item.toUpperCase() == 'ABC'">
    
    <!-- replace() - 替换 -->
    <when test="item.replace('_', '-') == '460-0'">
    
    <!-- indexOf() - 查找位置 -->
    <when test="item.indexOf('_') > 0">
    
    <!-- matches() - 正则匹配 -->
    <when test="item.matches('\\d+_-1')">
</if>

2. **支持的集合方法**

```

XML 复制代码
```xml
<!-- List/Collection 方法 -->
<if test="list != null and list.size() > 0">
<if test="list.isEmpty()">
<if test="list.contains(item)">

<!-- Map 方法 -->
<if test="map.containsKey('key')">
<if test="map.get('key') != null">

3. **支持的运算符**

XML 复制代码
<!-- 比较运算符 -->
<when test="value == 1">        <!-- 等于 -->
<when test="value != 1">        <!-- 不等于 -->
<when test="value > 1">         <!-- 大于 -->
<when test="value >= 1">        <!-- 大于等于 -->
<when test="value &lt; 1">      <!-- 小于 (需要转义) -->
<when test="value &lt;= 1">     <!-- 小于等于 (需要转义) -->

<!-- 逻辑运算符 -->
<when test="a and b">           <!-- 与 -->
<when test="a or b">            <!-- 或 -->
<when test="!a">                <!-- 非 -->
<when test="a || b">            <!-- 或 (另一种写法) -->
<when test="a &amp;&amp; b">    <!-- 与 (另一种写法,需要转义) -->

<!-- 空值检查 -->
<when test="value == null">
<when test="value != null">

<!-- 字符串检查 -->
<when test="str == ''">
<when test="str != ''">

4. **支持的特殊操作**

``

XML 复制代码
<!-- 三元运算符 -->
<when test="value > 0 ? 'positive' : 'negative'">

<!-- 访问对象属性 -->
<when test="user.name == 'admin'">
<when test="user.age > 18">

<!-- 访问数组/列表元素 -->
<when test="array[0] == 'first'">
<when test="list.get(0) == 'first'">

<!-- 调用静态方法 (需要完整类名) -->
<when test="@java.lang.Math@max(a, b) > 10">

<!-- 创建新对象 -->
<when test="new java.util.Date().getTime() > 0">

```

6. **注意事项和限制**

```xml

XML 复制代码
<!-- ❌ 不支持:复杂的 Java 语法 -->
<!-- 不能使用 for 循环、while 循环等 -->
<!-- 不能定义变量 -->
<!-- 不能使用 lambda 表达式 -->

<!-- ⚠️ XML 特殊字符需要转义 -->
<when test="value &lt; 10">     <!-- < 需要写成 &lt; -->
<when test="value &gt; 10">     <!-- > 需要写成 &gt; -->
<when test="a &amp;&amp; b">    <!-- && 需要写成 &amp;&amp; -->

<!-- ✅ 推荐:简单清晰的表达式 -->
<!-- 复杂逻辑建议在 Java 代码中预处理 -->

```

7. **常见陷阱**

XML 复制代码
<!-- ❌ 错误:数组越界 -->
<when test="mccmnc.split('_')[1] == '-1'">
<!-- 如果 mccmnc 是 "460" (没有下划线),会抛出 ArrayIndexOutOfBoundsException -->

<!-- ✅ 正确:先检查长度 -->
<when test="mccmnc.split('_').length > 1 and mccmnc.split('_')[1] == '-1'">

<!-- ❌ 错误:多次调用 split -->
<when test="mccmnc.split('_')[0] == '460' and mccmnc.split('_')[1] == '-1'">
<!-- 每次都会重新分割字符串,效率低 -->

<!-- ✅ 建议:在 Java 中预处理 -->
<!-- 复杂的字符串操作建议在 Service 层完成 -->

```

总结

  • **语法**:OGNL (Object-Graph Navigation Language)

  • **支持**:Java 对象的大部分方法(String、List、Map 等)

  • **限制**:不支持复杂的 Java 语法结构

  • **建议**:简单逻辑用 OGNL,复杂逻辑用 Java 预处理

你的代码是**可以运行的**,但需要注意:

  1. 确保 `mccmnc.split('_')` 总是返回至少 2 个元素

  2. 多次调用 `split()` 会影响性能

  3. 对于复杂的业务逻辑,建议在 Java 层面预处理数据

相关推荐
道可到4 小时前
阿里面试原题 面试通关笔记05 | 异常、泛型与反射——类型擦除的成本与优化
java·后端·面试
神仙别闹4 小时前
基于Java(Spring Boot)+MySQL实现电商网站
java·spring boot·mysql
瀚高PG实验室4 小时前
HGDB集群(安全版)repmgr手动切换主备库
java·数据库·安全·瀚高数据库
刘新明19895 小时前
Frida辅助分析OLLVM虚假控制流程(下)
java·开发语言·前端
第二只羽毛5 小时前
重载和继承的实践
java·开发语言
王嘉俊9255 小时前
设计模式--适配器模式:优雅解决接口不兼容问题
java·设计模式·适配器模式
王嘉俊9255 小时前
设计模式--组合模式:统一处理树形结构的优雅设计
java·设计模式·组合模式
道19935 小时前
50 台小型无人车与50套穿戴终端 5 公里范围内通信组网方案深度研究
java·后端·struts
迎風吹頭髮5 小时前
UNIX下C语言编程与实践35-UNIX 守护进程编写:后台执行、脱离终端、清除掩码与信号处理
java·c语言·unix