Spring项目中基于MyBatis读取Oracle SYS.XMLTYPE字段及解析内部指定字段值的方法
Spring + MyBatis 处理 Oracle XMLTYPE 字段完全指南
我来帮你搞定这个在Spring项目里用MyBatis操作Oracle XMLTYPE字段的问题,分字段映射到实体和XML内容提取两个核心部分来讲解:
一、将XMLTYPE字段映射到Java实体
这里有两种简单可行的方案,你可以根据自己的场景选择:
方案1:SQL层面直接转换(推荐,无需额外代码)
在查询SQL中,利用Oracle内置函数getClobVal()把XMLTYPE字段转成字符串,直接映射到实体类的String类型字段。
1. 定义Student实体类
public class Student { private String name; // 用String存储XML内容,后续解析更方便 private String xmlContent; // 省略getter、setter和toString方法 }
2. 编写Mapper接口和XML映射文件
Mapper接口:
public interface StudentMapper { // 根据姓名查询学生(包含XML字段) Student selectStudentByName(String name); }
Mapper XML文件:
<mapper namespace="com.example.mapper.StudentMapper"> <select id="selectStudentByName" resultType="com.example.entity.Student"> SELECT name, -- 把XMLTYPE字段转成字符串 xml_column.getClobVal() AS xml_content FROM student_table WHERE name = #{name} </select> </mapper>
这样查询出来的xml_content会直接映射到Student的xmlContent字段,非常省心。
方案2:自定义MyBatis类型处理器(适合复杂场景)
如果不想在SQL里做转换,可以自定义TypeHandler来处理Oracle XMLTYPE和Java类型的互相转换。
1. 自定义类型处理器
import oracle.xdb.XMLType; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class OracleXmlTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { // 把Java字符串转成Oracle XMLTYPE XMLType xmlType = XMLType.createXML(ps.getConnection(), parameter); ps.setObject(i, xmlType); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { // 把Oracle XMLTYPE转成Java字符串 XMLType xmlType = (XMLType) rs.getObject(columnName); return xmlType != null ? xmlType.getStringVal() : null; } @Override public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException { XMLType xmlType = (XMLType) rs.getObject(columnIndex); return xmlType != null ? xmlType.getStringVal() : null; } @Override public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { XMLType xmlType = (XMLType) cs.getObject(columnIndex); return xmlType != null ? xmlType.getStringVal() : null; } }
2. 注册类型处理器并配置ResultMap
在MyBatis配置文件中注册:
<configuration> <typeHandlers> <typeHandler handler="com.example.handler.OracleXmlTypeHandler" javaType="String" jdbcType="OTHER"/> </typeHandlers> </configuration>
然后在Mapper XML中用ResultMap指定字段映射:
<mapper namespace="com.example.mapper.StudentMapper"> <resultMap id="StudentResultMap" type="com.example.entity.Student"> <result property="name" column="name"/> <result property="xmlContent" column="xml_column" typeHandler="com.example.handler.OracleXmlTypeHandler"/> </resultMap> <select id="selectStudentByName" resultMap="StudentResultMap"> SELECT name, xml_column FROM student_table WHERE name = #{name} </select> </mapper>
二、从XML内容中提取指定字段
拿到XML字符串后,有3种常用的提取方式,按需选择:
方式1:JDK原生DOM解析(无依赖)
适合简单场景,不需要额外引入依赖:
import org.w3c.dom.Document; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.StringReader; public class XmlParseUtil { /** * 从XML字符串中提取指定标签的内容 * @param xmlContent XML字符串 * @param tagName 要提取的标签名 * @return 标签内容,失败返回null */ public static String extractTagContent(String xmlContent, String tagName) { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(new InputSource(new StringReader(xmlContent))); return doc.getElementsByTagName(tagName).item(0).getTextContent(); } catch (Exception e) { e.printStackTrace(); return null; } } }
使用示例:
Student student = studentMapper.selectStudentByName("张三"); String age = XmlParseUtil.extractTagContent(student.getXmlContent(), "age"); String gender = XmlParseUtil.extractTagContent(student.getXmlContent(), "gender");
方式2:Jackson XML解析(推荐,优雅高效)
如果需要提取多个字段,推荐把XML映射成Java实体类,用Jackson XML来解析。
首先添加依赖:
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.15.2</version> <!-- 使用最新稳定版 --> </dependency>
定义XML对应的实体类:
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; @JacksonXmlRootElement(localName = "studentInfo") // XML根节点名称 public class StudentInfo { private String age; private String gender; private String major; // 省略getter、setter }
编写解析工具类:
import com.fasterxml.jackson.dataformat.xml.XmlMapper; public class XmlParseUtil { private static final XmlMapper XML_MAPPER = new XmlMapper(); public static StudentInfo parseToStudentInfo(String xmlContent) { try { return XML_MAPPER.readValue(xmlContent, StudentInfo.class); } catch (Exception e) { e.printStackTrace(); return null; } } }
使用示例:
Student student = studentMapper.selectStudentByName("张三"); StudentInfo info = XmlParseUtil.parseToStudentInfo(student.getXmlContent()); String age = info.getAge(); String major = info.getMajor();
方式3:XPath解析(灵活通用)
适合需要复杂路径提取的场景,比如嵌套标签:
import javax.xml.xpath.XPath; import javax.xml.xpath.XPathFactory; import org.xml.sax.InputSource; import java.io.StringReader; public class XmlParseUtil { public static String extractByXPath(String xmlContent, String xpathExpr) { try { XPath xpath = XPathFactory.newInstance().newXPath(); InputSource source = new InputSource(new StringReader(xmlContent)); return xpath.evaluate(xpathExpr, source); } catch (Exception e) { e.printStackTrace(); return null; } } }
使用示例:
// 提取根节点下的age字段 String age = XmlParseUtil.extractByXPath(student.getXmlContent(), "/studentInfo/age"); // 如果有嵌套,比如/studentInfo/detail/address String address = XmlParseUtil.extractByXPath(student.getXmlContent(), "/studentInfo/detail/address");
内容的提问来源于stack exchange,提问作者Самир Шахмурад
相关产品推荐
相关产品推荐

