[英]Spring @RestController produces XML without namespaces
我有一個@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端點)並且拋出了異常,則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時,由於缺少LinkedHashMap
到html的轉換器,因此會返回http狀態406
。 所以我的解決方案是向我的應用程序中添加一個簡單的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());
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.