Spring @RestController生成没有命名空间的XML

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring @RestController生成没有命名空间的XML相关的知识,希望对你有一定的参考价值。

我有一个@RestController,它应该从SOAP Web服务返回一个结果。 Web服务客户端类是使用maven-jaxb2-plugin生成的,因此使用JAXB注释。

@RestController
public class ZemisPersonSearchController {

    @Autowired(required = true)
    private SoapClient soapClient;

    @RequestMapping(path = "/api/persons/{no}", produces = { MediaType.APPLICATION_JSON_UTF8_VALUE, MediaType.APPLICATION_XML_VALUE })
    @PreAuthorize("hasRole('ROLE_GET_PERSON_DETAILS')")
    public ResponseEntity<Object> getPersonDetails(HttpServletRequest httpReq, @PathVariable String no) {
        Result result = soapClient.getPersonDetails(UUID.randomUUID().toString(), no);
        return new ResponseEntity<>(result, HttpStatus.OK);
    }
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "responseHeader",
    "getPersonDetailsResponse",
    "searchPersonResponse",
    "systemException"
})
@XmlRootElement(name = "result")
public class Result {

    @XmlElement(name = "ResponseHeader")
    protected ResponseHeaderType responseHeader;
    @XmlElement(name = "GetPersonDetailsResponse")
    protected PersonType getPersonDetailsResponse;
    @XmlElement(name = "SearchPersonResponse")
    protected SearchPersonResponseType searchPersonResponse;
    @XmlElement(name = "SystemException")
    protected FaultInfoType systemException;
...

只要所有工作都按预期工作,结果如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:result
    xmlns:ns2="http://mynamespace/personsearchservice/v1">
    <ns2:ResponseHeader>
    ...

但是如果出现问题(即soap端点不可用)并且抛出了一个excpetion,则REST控制器将返回406 http状态,因为自动生成的响应无法转换为XML。

我试图用Jackson XML扩展我的应用程序并注册模块来处理我发现的文档和博客中建议的JAXB注释。

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-jaxb-annotations</artifactId>
</dependency>
@Bean
public Module jaxbModule() {
    return new JaxbAnnotationModule();
}

但是,如果我这样做,异常的错误现在可以生成为XML,我得到了正确的http状态500,但是没有错误发生时的响应不再包含命名空间,并且保留命名空间很重要,因为它很大和复杂的xml:

<result>
    <ResponseHeader>

有没有人知道我要做什么来获得带有jackson的命名空间或使用JAXB将错误转换为xml?

答案

我发现,那个弹簧会自动创建一个带有错误细节的LinkedHashMap。当这个地图应该在类路径上转换为没有jackson-xml的html时,由于缺少406到html的转换器,http状态LinkedHashMap会被返回。所以我的解决方案是在我的应用程序中添加一个简单的AbstractHttpMessageConverter,它将带有错误详细信息的地图转换为html。因此,我不需要类路径上的jackson-xml,我的XML是从包含名称空间的JAXB生成的。

转换器:

public class HttpXmlExceptionConverter extends AbstractHttpMessageConverter<Map<String, Object>> {

    public HttpXmlExceptionConverter() {
        super(MediaType.APPLICATION_XML, MediaType.TEXT_XML, new MediaType("application", "*+xml"));
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        return Map.class.isAssignableFrom(clazz);
    }

    @Override
    protected Map readInternal(Class<? extends Map<String, Object>> clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {
        throw new NotImplementedException("readFromSource is not supported!");
    }

    @Override
    protected void writeInternal(Map<String, Object> map, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {
        OutputStream s = outputMessage.getBody();
        StringBuilder sb = new StringBuilder();
        sb.append("<map>");
        for (Entry<String, Object> entry : map.entrySet()) {
            sb.append("<").append(entry.getKey()).append(">");
            if (entry.getValue() != null)
                sb.append(StringEscapeUtils.escapeXml(entry.getValue().toString()));
            sb.append("</").append(entry.getKey()).append(">");
        }
        sb.append("</map>");
        s.write(sb.toString().getBytes(Charset.defaultCharset()));
    }

}

并注册转换器:

@Configuration
//@EnableWebMvc
// -> EnableWebMvc is required if you don't want the spring boot auto configuration should be extended
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new HttpXmlExceptionConverter());
    }
}

以上是关于Spring @RestController生成没有命名空间的XML的主要内容,如果未能解决你的问题,请参考以下文章

从 Spring @RestController 收到的 AngularJS 显示 PDF (byte[])

如何在 Spring RestController 中下载 excel 文件

Spring @RestController,spring-boot 出现意外错误(类型=不可接受,状态=406)

spring4.0之三:@RestController

Spring @RestController 用于匿名和授权用户的单一方法

Spring 注解中@RestController与@Controller的区别