spring mvc 处理 xml 与 dtd 的相对路径
spring mvc processing xml with relative path to dtd
我的网络服务从第三方来源收到 xml,其中包含 !DOCTYPE 声明。因此我必须在我的控制器中使用第二种方法来解析 xml 文档,第一种方法给了我这个异常:
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not unmarshal to [class com.example.MeterBusXml]: null; nested exception is javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 48; DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.]
我无法控制发布 xml 的应用程序,因此我必须调整我的网络服务以使用 dtd 解析它。
我的问题是,spring 框架将 EntityResolver
注入每个 XMLReader
实例的方式是什么?
@RestController
public class MeterBusDataController {
@RequestMapping (
consumes = APPLICATION_XML_VALUE,
method = POST,
path = "/meterbus1"
)
public void method1(@RequestBody MeterBusXml xml) {
System.out.println(xml);
}
@RequestMapping(
method = POST,
path = "/meterbus2"
)
public void method2(HttpServletRequest rq) throws IOException, ParserConfigurationException, SAXException, JAXBException {
JAXBContext jc = newInstance(MeterBusXml.class);
Unmarshaller um = jc.createUnmarshaller();
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setValidating(true);
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
xr.setEntityResolver(new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
return new InputSource(new StringReader(""));
}
});
BufferedReader reader = rq.getReader();
InputSource inputSource = new InputSource(reader);
SAXSource saxSource = new SAXSource(xr, inputSource);
MeterBusXml xml = (MeterBusXml)um.unmarshal(saxSource);
System.out.println(xml);
}
}
有关 mbus.xml 我正在尝试解组的示例,请参阅以下文档。
http://prevodniky.sk/products/product_EthMBus_common/download/Ethernet_converters_exports_v1_02_EN.pdf
我找到了问题的根源。首先,我尝试创建和配置 Jaxb2Marshaller bean,但没有成功。然后我意识到,我需要一个 HttpMessageConverter,所以我不得不重写 WebMvcConfigurerAdapter
class 中的 extendMessageConverters
方法,并在 Jaxb2RootElementHttpMessageConverter
上设置所需的属性。此消息转换器不使用 Jaxb2Marshaller
,但其内部工作方式非常相似。
setSupportDtd(true) 是必需的,以强制解析器接受 !DOCTYPE 声明。
setProcessExternalEntities(false) 是必需的,因为如果此 属性 为假,则转换器使用空白 EntityResolver
,就像我在方法 2 中所做的那样。
@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(List<HttpMessageConverter<Jaxb2RootElementHttpMessageConverter?>> converters) {
for (final Iterator<HttpMessageConverter<?>> iterator = converters.iterator(); iterator.hasNext();) {
HttpMessageConverter<?> next = iterator.next();
if (next instanceof Jaxb2RootElementHttpMessageConverter) {
Jaxb2RootElementHttpMessageConverter jaxbConverter = (Jaxb2RootElementHttpMessageConverter) next;
jaxbConverter.setProcessExternalEntities(false);
jaxbConverter.setSupportDtd(true);
}
}
}
}
我的网络服务从第三方来源收到 xml,其中包含 !DOCTYPE 声明。因此我必须在我的控制器中使用第二种方法来解析 xml 文档,第一种方法给了我这个异常:
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not unmarshal to [class com.example.MeterBusXml]: null; nested exception is javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 48; DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true.]
我无法控制发布 xml 的应用程序,因此我必须调整我的网络服务以使用 dtd 解析它。
我的问题是,spring 框架将 EntityResolver
注入每个 XMLReader
实例的方式是什么?
@RestController
public class MeterBusDataController {
@RequestMapping (
consumes = APPLICATION_XML_VALUE,
method = POST,
path = "/meterbus1"
)
public void method1(@RequestBody MeterBusXml xml) {
System.out.println(xml);
}
@RequestMapping(
method = POST,
path = "/meterbus2"
)
public void method2(HttpServletRequest rq) throws IOException, ParserConfigurationException, SAXException, JAXBException {
JAXBContext jc = newInstance(MeterBusXml.class);
Unmarshaller um = jc.createUnmarshaller();
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setValidating(true);
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
xr.setEntityResolver(new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
return new InputSource(new StringReader(""));
}
});
BufferedReader reader = rq.getReader();
InputSource inputSource = new InputSource(reader);
SAXSource saxSource = new SAXSource(xr, inputSource);
MeterBusXml xml = (MeterBusXml)um.unmarshal(saxSource);
System.out.println(xml);
}
}
有关 mbus.xml 我正在尝试解组的示例,请参阅以下文档。 http://prevodniky.sk/products/product_EthMBus_common/download/Ethernet_converters_exports_v1_02_EN.pdf
我找到了问题的根源。首先,我尝试创建和配置 Jaxb2Marshaller bean,但没有成功。然后我意识到,我需要一个 HttpMessageConverter,所以我不得不重写 WebMvcConfigurerAdapter
class 中的 extendMessageConverters
方法,并在 Jaxb2RootElementHttpMessageConverter
上设置所需的属性。此消息转换器不使用 Jaxb2Marshaller
,但其内部工作方式非常相似。
setSupportDtd(true) 是必需的,以强制解析器接受 !DOCTYPE 声明。
setProcessExternalEntities(false) 是必需的,因为如果此 属性 为假,则转换器使用空白 EntityResolver
,就像我在方法 2 中所做的那样。
@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(List<HttpMessageConverter<Jaxb2RootElementHttpMessageConverter?>> converters) {
for (final Iterator<HttpMessageConverter<?>> iterator = converters.iterator(); iterator.hasNext();) {
HttpMessageConverter<?> next = iterator.next();
if (next instanceof Jaxb2RootElementHttpMessageConverter) {
Jaxb2RootElementHttpMessageConverter jaxbConverter = (Jaxb2RootElementHttpMessageConverter) next;
jaxbConverter.setProcessExternalEntities(false);
jaxbConverter.setSupportDtd(true);
}
}
}
}