Java 系列 - SpringBoot-1 - 入参及出参扩展 XML 支持
程序员七平Java 系列 - SpringBoot-1 - 入参及出参扩展 XML 支持
前言
现在 Java 后端项目基本都使用 json 格式请求和响应数据,因此一般的配置返回 json 格式数据便能够满足需求。但仍有一些场景需要支持 xml 格式的请求和响应数据,针对此类需求,
本文在 SpringBoot 框架上进行配置说明。
注:原 spring mvc 使用 xml 配置也支持此配置。
环境
- SpringBoot 版本:2.2.8.RELEASE
相关知识点
Http 报头分为通用报头,请求报头,响应报头和实体报头。
请求方的 http 报头结构:通用报头 | 请求报头 | 实体报头
响应方的 http 报头结构:通用报头 | 响应报头 | 实体报头
Accept
:属于请求头,代表发送端(客户端)希望接受的数据类型。
application/xml
,
application/json
;java 枚举:MediaType
Content-Type
:代表发送端(客户端 | 服务器)发送的实体数据的数据类型
application/xml
,
application/json
;java 枚举:MediaType
常见的媒体格式类型如下:
- text/html : HTML 格式
- text/plain :纯文本格式
- text/xml : XML 格式
- image/gif :gif 图片格式
- image/jpeg :jpg 图片格式
- image/png:png 图片格式
- multipart/form-data : 表单中进行文件上传时使用该格式
以 application 开头的媒体格式类型:
- application/xhtml+xml :XHTML 格式
- application/xml : XML 数据格式
- application/atom+xml :Atom XML 聚合格式
- application/json : JSON 数据格式
- application/pdf :pdf 格式
- application/msword : Word 文档格式
- application/octet-stream : 二进制流数据(如常见的文件下载)
- application/x-www-form-urlencoded :
Spring 中 consumes 和 produces 的区别
SpringMvc
中如 @RequestMapping
之类的注解(@PostMapping
等)有 consumes
和 produces
这两个属性;
consumes
: 指定处理请求的提交内容类型(Content-Type),例如 application/json, text/html;
produces
: 指定返回的内容类型,仅当 request 请求头中的 (Accept) 类型中包含该指定类型才返回;
params
: 指定 request 中必须包含某些参数值是,才让该方法处理
headers
: 指定 request 中必须包含某些指定的 header 值,才能让该方法处理请求
使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @RestController @RequestMapping("/api/v1") public class ApiTestController { @PostMapping(value = "/pay", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}) public ApiResponse<TestResponse> testPay(@Validated @RequestBody TestRequest request) { log.info("测试post方法:【{}】", JSON.toJSONString(request)); TestResponse response = TestResponse.builder() .field1("field1") .field2("field2") .field3("field3") .build(); return ApiResponse.ok("请求成功", "1234", "业务成功", response); } }
|
SpringMVC 输出格式
在 SpringMVC 使用 ContentNegotiation 来判断用户请求希望得到什么格式的数据。
ContentNegotiation 设置了三种方式来设置相应数据的格式,优先级由上至下:
- 通过请求 URL 后缀:/list.html 返回 html 格式;
- 通过请求的参数:/list?format=html 该设置默认不开启,默认 key 是 format。
- 通过 HTTP Header 的 Accept:Accept:application/xml
本文在 springboot 中配置扩展 xml 格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
@Configuration public class ApiMessageConverterConfig implements WebMvcConfigurer { @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer .favorPathExtension(true) .favorParameter(true) .parameterName("mediaType") .ignoreAcceptHeader(false) .defaultContentType(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML) .mediaType("xml", MediaType.APPLICATION_XML) .mediaType("html", MediaType.TEXT_HTML) .mediaType("json", MediaType.APPLICATION_JSON); } }
|
pom.xml 中引入依赖:
1 2 3 4 5
| <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
|
请求实体类配置,需要使用上述依赖中 @JacksonXmlRootElement
和 @JacksonXmlProperty
注解:
注:xml 格式的必须指定根节点;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Data @Builder @NoArgsConstructor @AllArgsConstructor @JacksonXmlRootElement(localName = "request") public class TestRequest extends ApiPayV1Request<TestResponse> implements Serializable { private static final long serialVersionUID = -3135169148798610260L;
@JacksonXmlProperty(localName = "field1") private String field1; private String field2; private String field3;
@Override public Class<TestResponse> getResponseClass() { return TestResponse.class; } }
|
响应实体类配置,同上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| @JacksonXmlRootElement(localName = "root") public class ApiResponse<T> implements Serializable { private static final long serialVersionUID = -3798634638472229369L;
@JacksonXmlProperty(localName = "success") private boolean success;
@JacksonXmlProperty(localName = "code") private String code;
@JacksonXmlProperty(localName = "message") private String message;
@JacksonXmlProperty(localName = "sub_code") private String sub_code;
@JacksonXmlProperty(localName = "sub_msg") private String sub_msg;
@JacksonXmlProperty(localName = "time") @JsonFormat(pattern = "yyyyMMddHHmmssSSS", timezone = "GMT+8") private Timestamp time;
@JacksonXmlProperty(localName = "data") private T data;
@JacksonXmlProperty(localName = "sign") private String sign;
}
|
参考资料