公司最新项目让我做,刚好就试试spring framework5响应式编程,写了几个接口后发现json序列化正常,想返回前端xml报文时报异常406,具体接口是这样的
@GetMapping(path = "/test/xml", produces = MediaType.APPLICATION_XML_VALUE)
public Mono<BaseResponse> xmlTest() {
    return Mono.just(BaseResponse.buildSuccessfully());

}

其中BaseResponse类,设计为一个基本返回类,安装以往springMvc return对象的时候自动根据content-type自动转化xml字符串

@Data @AllArgsConstructor @NoArgsConstructor @ApiModel(description = "返回响应数据") @SuppressWarnings({"unchecked", "WeakerAccess"}) public class BaseResponse<t> {</t>@ApiModelProperty(value = "是否返回成功", required = true, example = "true") private Boolean success; @ApiModelProperty(value = "错误编号", required = true, example = "1") private Integer resultCode; @ApiModelProperty(value = "返回信息", required = true, example = "hello world") private String msg; @ApiModelProperty(value = "返回对象") private T data; public static BaseResponse buildSuccessfully() { return buildSuccessfully(null); } public static <e> BaseResponse<e> buildSuccessfully(E resultContent) {</e></e>return new BaseResponse(true, 1, "success", resultContent); } public static <e> BaseResponse<e> build(Boolean success, Integer resultCode, String msg, E data) {</e></e>return new BaseResponse<>(success, resultCode, msg, data); } public static BaseResponse buildSuccessfullyMsg(String msg) { return new BaseResponse(true, 1, msg, null); } public static <e> BaseResponse<e> buildFailure() {</e></e>return new BaseResponse<>(false, 0, "fail", null); } public static BaseResponse buildFailure(String resultMessage) { return new BaseResponse(false, 0, resultMessage, null); } }
Postman测试结果
HTTP/1.1 406 Not Acceptable
Content-Type: application/json;charset=UTF-8
Content-Length: 137
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1 ; mode=block
connection: close

{
"timestamp": 1533741660881,
"path": "/test/xml",
"status": 406,
"error": "Not Acceptable",
"message": "Could not find acceptable representation"
}
到底哪里出了问题呢,研究一下源码发现和原来springMVC的http消息换行又很大不同,具体源码如下:
@Configuration
@ConditionalOnClass(CodecConfigurer.class)
@AutoConfigureAfter(JacksonAutoConfiguration.class)
public class CodecsAutoConfiguration {

private static final MimeType[] EMPTY_MIME_TYPES = {};

@Configuration
@ConditionalOnClass(ObjectMapper.class)
static class JacksonCodecConfiguration {

@Bean
@ConditionalOnBean(ObjectMapper.class)
public CodecCustomizer jacksonCodecCustomizer(ObjectMapper objectMapper) {
return (configurer) -> {
CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs();
defaults.jackson2JsonDecoder(
new Jackson2JsonDecoder(objectMapper, EMPTY_MIME_TYPES));
defaults.jackson2JsonEncoder(
new Jackson2JsonEncoder(objectMapper, EMPTY_MIME_TYPES));
};
}

}

}
源码里面只配置了json的序列化器,没有xml序列化配置,好吧研究一下CodecCustomizer部分的源码给他加上如下:啥都不说看注释哈哈
@Configuration

@EnableScheduling

public class AppConfig implements ApplicationContextAware {

private MimeType[] jsonMimeTypes = {

new MimeType("application", "json", StandardCharsets.UTF_8),

new MimeType("application", "*+json", StandardCharsets.UTF_8),

MimeTypeUtils.TEXT_PLAIN

};

@Override

public void setApplicationContext(ApplicationContext applicationContext) {

AppContextUtils.setCtx(applicationContext);

}

/**

* XML报文序列化器

* JsonInclude.Include.NON_NULL 序列化是忽略null字段

* SerializationFeature.FAIL_ON_EMPTY_BEANS, false懒加载异常消除

*

* @return xmlMapper

*/

@Bean

public XmlMapper xmlMapper() {

final XmlMapper xmlMapper = new XmlMapper();

xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

xmlMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

return xmlMapper;

}

/**

* Json报文序列化器

* JsonInclude.Include.NON_NULL 序列化是忽略null字段

* SerializationFeature.FAIL_ON_EMPTY_BEANS, false懒加载异常消除

*

* @return xmlMapper

*/

@Bean

public ObjectMapper objectMapper() {

return Jackson2ObjectMapperBuilder.json()

.serializationInclusion(JsonInclude.Include.NON_NULL)

.build()

.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

}

/**

* 默认就有多种httpMessage消息序列化器,这里自定义json和xml转换器

*

* @return CodecCustomizer 自定义转换器

*/

@Bean

@ConditionalOnBean(ObjectMapper.class)

public CodecCustomizer jacksonCodecCustomizer(@Qualifier("jsonEncoder") Jackson2JsonEncoder jackson2JsonEncoder,

Jackson2JsonDecoder jackson2JsonDecoder,

CustomJaxb2XmlDecoder jaxb2XmlDecoder,

@Qualifier("xmlEncoder") Jackson2JsonEncoder xmlEncoder) {

return (configurer) -> {

CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs();

/*

json反序列化器注册

*/

defaults.jackson2JsonDecoder(

jackson2JsonDecoder);

/*

json序列化器注册

*/

defaults.jackson2JsonEncoder(

jackson2JsonEncoder);

final CodecConfigurer.CustomCodecs customCodecs = configurer.customCodecs();

/*

xml序列化反序列化器注册

*/

customCodecs.decoder(jaxb2XmlDecoder);

customCodecs.encoder(xmlEncoder);

};

}

@Bean("jsonEncoder")

public Jackson2JsonEncoder jackson2JsonEncoder(ObjectMapper objectMapper) {

return new Jackson2JsonEncoder(objectMapper, this.jsonMimeTypes);

}

@Bean

public Jackson2JsonDecoder jackson2JsonDecoder(ObjectMapper objectMapper) {

return new Jackson2JsonDecoder(objectMapper, this.jsonMimeTypes);

}

@Bean

public CustomJaxb2XmlDecoder jaxb2XmlDecoder() {

return new CustomJaxb2XmlDecoder(this.xmlMimeType());

}

@Bean("xmlEncoder")

public Jackson2JsonEncoder xmlEncoder(XmlMapper xmlMapper) {

return new Jackson2JsonEncoder(xmlMapper, this.xmlMimeType());

}

private MimeType[] xmlMimeType() {

return new MimeType[]{MimeTypeUtils.APPLICATION_XML, MimeTypeUtils.TEXT_HTML, MimeTypeUtils.TEXT_XML};

}

最后自动配置排除CodecsAutoConfiguration
SpringBootApplication(
exclude = {CodecsAutoConfiguration.class})

发表评论

电子邮件地址不会被公开。 必填项已用*标注