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 层面预处理数据

相关推荐
Dolphin_Home4 分钟前
深度解析:SpringBoot 静态类调用 Bean 的底层逻辑与最优实践
java·spring boot·后端
故渊ZY10 分钟前
Spring JavaConfig:注解驱动的配置革命
java·spring
一水鉴天13 分钟前
整体设计 定稿 之20 拼语言表述体系之3 dashboard.html完整代码
java·前端·javascript
静若繁花_jingjing14 分钟前
Spring Bean基础
java·后端·spring
CoderYanger17 分钟前
A.每日一题——2141.同时运行N台电脑的最长时间
java·算法·leetcode·职场和发展·1024程序员节
旺仔Sec17 分钟前
2025年广东省职业院校技能大赛应用软件系统开发赛项(高职组)赛题(一)
java·应用软件系统开发
雨中飘荡的记忆23 分钟前
Spring AI + Redis 向量库实战
java·redis·spring
CC.GG26 分钟前
【C++】面向对象三大特性之一——继承
java·数据库·c++
零匠学堂202528 分钟前
woapi-server为Office Online Server文档在线预览提供文档加载地址
java·运维·服务器·oos·wopi
Hui Baby29 分钟前
maven自动构建到镜像仓库
java·maven