欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > Java + Spring Boot + MyBatis 枚举变量传递给XML映射文件做判断

Java + Spring Boot + MyBatis 枚举变量传递给XML映射文件做判断

2025/6/18 11:15:24 来源:https://blog.csdn.net/BillKu/article/details/148723116  浏览:    关键词:Java + Spring Boot + MyBatis 枚举变量传递给XML映射文件做判断

枚举定义 ReagentStatus.java

package com.weiyu.utils.enums;import lombok.Getter;/*** 试剂状态枚举*/
@Getter
public enum ReagentStatus {// 常规REGULAR,// 少库存LESS_INVENTORY,// 零库存ZERO_INVENTORY,// 将过期WILL_EXPIRE,// 已过期EXPIRED,// 已注销LOGGED,// 全部ALL
}

查询对象 DTO ReagentQueryDTO.java

package com.weiyu.pojo;import com.weiyu.utils.enums.ReagentStatus;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDateTime;/*** 试剂管理查询 DTO*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ReagentQueryDTO {// 分页器private PageHelper pageHelper = new PageHelper(1, 20);// 试剂类型private String reagentCategory;// 试剂编号private String reagentNo;// 试剂名称private String reagentName;// 试剂状态private ReagentStatus status;// 当天零晨,用于过滤有效期private LocalDateTime currentStartOfDay;
}

ReagentMapper.java

    // 通过状态,查询试剂列表List<Reagent> selectByStatus(ReagentQueryDTO queryDTO, String userName);

ReagentMapper.xml

调用枚举的 name() 方法获取枚举常量名称字符串

    <!-- 通过状态,查询试剂列表 --><select id="selectByStatus" resultType="com.weiyu.pojo.Reagent">select<include refid="ReagentAllFields" />from Reagent<where><if test="queryDTO.reagentCategory != null and queryDTO.reagentCategory != ''">and rea_TypeName = #{queryDTO.reagentCategory}</if><if test="queryDTO.reagentName != null and queryDTO.reagentName != ''">and rea_Name like '%' + #{queryDTO.reagentName} + '%'</if><if test="queryDTO.status != null"><choose><!-- 常规 --><when test="queryDTO.status.name() == 'REGULAR'">and rea_State = 0 and rea_Amount > 0</when><!-- 少库存 --><when test="queryDTO.status.name() == 'LESS_INVENTORY'">and rea_State = 0 and rea_Amount between 1 and 3</when><!-- 零库存 --><when test="queryDTO.status.name() == 'ZERO_INVENTORY'">and rea_State = 0 and rea_Amount = 0</when><!-- 将过期 --><when test="queryDTO.status.name() == 'WILL_EXPIRE'">and rea_State = 0 and rea_Amount > 0 and rea_OverdueDate between dateadd(day, -1, getdate()) and dateadd(month, 1, getdate())</when><!-- 已过期 --><when test="queryDTO.status.name() == 'EXPIRED'">and rea_State = 0 and rea_Amount > 0 and rea_OverdueDate &lt; #{queryDTO.currentStartOfDay}</when><!-- 已注销 --><when test="queryDTO.status.name() == 'LOGGED'">and rea_State = 1</when><!-- 全部 --></choose></if>and exists (select 1from Employeewhere emp_ID = #{userName}and emp_DeptID = rea_DeptID)</where></select>

在Java中,将枚举变量从Mapper接口传递到MyBatis的XML文件时,MyBatis默认提供了两种处理枚举的方式,也可以通过自定义类型处理器实现更灵活的控制。以下是详细步骤和示例:


方法1:使用MyBatis内置枚举处理器(默认)

MyBatis默认使用EnumTypeHandler,将枚举的名称(name())作为字符串传递到XML。

示例代码
  1. 枚举定义

    java

    复制

    下载

    public enum UserStatus {ACTIVE, INACTIVE, PENDING
    }
  2. Mapper接口

    java

    复制

    下载

    public interface UserMapper {List<User> getUsersByStatus(@Param("status") UserStatus status);
    }
  3. XML映射文件

    xml

    复制

    下载

    运行

    <select id="getUsersByStatus" resultType="User">SELECT * FROM users WHERE status = #{status}<!-- 相当于 #{status, javaType=UserStatus} -->
    </select>
    • 实际执行的SQL:status = 'ACTIVE'(枚举的字符串名称)


方法2:使用枚举序号(ordinal)

通过EnumOrdinalTypeHandler,将枚举的序号(ordinal())作为整数传递。

步骤
  1. 全局配置(推荐在mybatis-config.xml中)

    xml

    复制

    下载

    运行

    <typeHandlers><typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.example.UserStatus"/> <!-- 替换为你的枚举全限定名 -->
    </typeHandlers>
  2. 或局部配置(在XML中指定)

    xml

    复制

    下载

    运行

    <select id="getUsersByStatus" resultType="User">SELECT * FROM users WHERE status = #{status, typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}
    </select>
    • 实际执行的SQL:status = 0(枚举的序号值)


方法3:自定义类型处理器(推荐)

当需要存储枚举的自定义属性(如数据库中的编码)时,需实现TypeHandler接口。

示例:将枚举的自定义编码存入数据库
  1. 枚举定义(添加自定义字段)

    java

    复制

    下载

    public enum UserStatus {ACTIVE("A"), INACTIVE("I"), PENDING("P");private final String code;UserStatus(String code) { this.code = code; }public String getCode() { return code; }
    }
  2. 自定义类型处理器

    java

    复制

    下载

    public class UserStatusTypeHandler implements TypeHandler<UserStatus> {@Overridepublic void setParameter(PreparedStatement ps, int i, UserStatus status, JdbcType jdbcType) throws SQLException {ps.setString(i, status.getCode()); // 存入枚举的code值}@Overridepublic UserStatus getResult(ResultSet rs, String columnName) throws SQLException {String code = rs.getString(columnName);return Arrays.stream(UserStatus.values()).filter(s -> s.getCode().equals(code)).findFirst().orElse(null);}// 其他getResult方法实现类似...
    }
  3. 注册类型处理器

    • 全局注册(在mybatis-config.xml中)

      xml

      复制

      下载

      运行

      <typeHandlers><typeHandler handler="com.example.handler.UserStatusTypeHandler"/>
      </typeHandlers>
    • 或局部使用(在XML中指定)

      xml

      复制

      下载

      运行

      <select id="getUsersByStatus" resultType="User">SELECT * FROM users WHERE status = #{status, typeHandler=com.example.handler.UserStatusTypeHandler}
      </select>
  4. Mapper接口保持不变

    java

    复制

    下载

    List<User> getUsersByStatus(@Param("status") UserStatus status);

关键点总结

方法传递的值配置方式适用场景
默认EnumTypeHandler枚举名称(字符串)无需配置直接存储枚举名称到VARCHAR列
EnumOrdinalTypeHandler枚举序号(整数)全局配置或局部指定存储序号到INT列
自定义TypeHandler任意自定义属性实现接口并注册复杂映射(如编码转换)

常见问题解决

  1. 枚举传递后值为null

    • 检查类型处理器是否匹配。

    • 确保XML中的参数名与@Param一致。

  2. 数据库存的是整数但枚举是字符串

    • 使用EnumOrdinalTypeHandler或自定义处理器。

  3. 自定义处理器不生效

    • 确认是否在mybatis-config.xml中全局注册,或在XML中局部指定。

通过以上方法,你可以灵活地在MyBatis中处理枚举类型的传递和映射。

在 MyBatis 的 XML 动态 SQL 中,直接使用 queryDTO.status == 'REGULAR' 这种写法通常是不正确的,因为枚举对象和字符串是不同类型。以下是正确做法和详细解释:

正确解决方案

1. 比较枚举名称(推荐)

xml

复制

下载

运行

<when test="queryDTO.status != null and queryDTO.status.name() == 'REGULAR'">AND user_type = 1
</when>
  • 原理:调用枚举的 name() 方法获取枚举常量名称字符串

  • 注意:需先检查 queryDTO.status 是否为 null 避免 NPE

2. 直接比较枚举常量(需全限定名)

xml

复制

下载

运行

<when test="queryDTO.status == @com.example.UserStatus@REGULAR">AND user_type = 1
</when>
  • 格式@包名.枚举类名@枚举常量

  • 缺点:路径较长且硬编码,修改枚举位置时需要同步更新

3. 使用枚举的 toString()(需重写方法)

java

复制

下载

// 枚举定义
public enum UserStatus {REGULAR("常规用户");private final String desc;UserStatus(String desc) { this.desc = desc; }@Overridepublic String toString() { return this.desc; // 或 return this.name(); }
}

xml

复制

下载

运行

<when test="queryDTO.status != null and queryDTO.status.toString() == '常规用户'">AND user_type = 1
</when>
  • 适用场景:需要比较自定义描述而非枚举名称时

  • 注意:默认 toString() 返回与 name() 相同,重写可实现自定义逻辑


❌ 为什么不推荐直接比较字符串

xml

复制

下载

运行

<!-- 错误示例 -->
<when test="queryDTO.status == 'REGULAR'"> 
  • 类型不匹配:左侧 queryDTO.status 是枚举对象,右侧 'REGULAR' 是字符串

  • 实际比较:相当于 enumObject.equals(String),永远返回 false

  • OGNL 处理:MyBatis 使用 OGNL 表达式,不会自动转换类型


最佳实践总结

场景推荐写法优点
比较枚举常量名queryDTO.status.name() == 'REGULAR'直观、无需修改枚举定义
需要精确匹配枚举实例queryDTO.status == @包名.UserStatus@REGULAR直接比较对象引用
比较枚举的自定义描述queryDTO.status.toString() == '描述文本'支持业务友好文本
多条件判断搭配 <choose> 使用枚举 name()清晰易维护

完整示例

xml

复制

下载

运行

<select id="searchUsers" resultType="User">SELECT * FROM users<where><choose><when test="queryDTO.status != null and queryDTO.status.name() == 'REGULAR'">AND user_type = 1</when><when test="queryDTO.status != null and queryDTO.status.name() == 'VIP'">AND user_type = 2</when><otherwise>AND user_type IS NOT NULL</otherwise></choose></where>
</select>

重要提醒

  1. 空值检查:始终优先判断 queryDTO.status != null

  2. 大小写敏感name() 返回的枚举名称是大小写敏感的

  3. 避免魔法值:考虑使用常量替代硬编码字符串

    xml

    复制

    下载

    运行

    <when test="queryDTO.status.name() == T(com.example.Constants).USER_REGULAR">

根据你的实际需求,推荐使用 枚举.name() == '常量名' 的方式,兼具可读性和类型安全性。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词