最近在项目中遇到一个很棘手的问题,需求是这样的:项目是springboot项目,要求提供对外的一个接口,并根据一个入参output来控制返回的是json数据还是xml数据,我http请求接口返回出去的是一个ResponseEntity对象,需求需要增加一个拦截器继承WebMvcConfigurerAdapter去重写一些业务,在没加拦截器之前接口正常返回数据,但加入拦截器后,接口正常返回200,debug一下也没问题,但postman和浏览器打开接口就是没有数据,相应体为空,此时将ResponseEntity换成自定义的一个对象或字符串返回出去就很正常,这个问题一直没搞明白,想着应该是ResponseEntity的问题,导致响应体是空的。
以上是本次的一个问题,然后我又换了另一种解决方法,将返回的ResponseEntity对象改为Object对象,并通过@ResponseBody控制返回的json或xml。返回的两种数据格式如下:
1. 若返回json数据,则直接返回一个对象,@ResponseBody会解析成json数据返回,此时查看接口的响应头中Content-Type为application/json;charset=UTF-8,这是正常的
2. 若返回xml数据,则通过jdk自带的转换类实现将对象转为xml格式数据JAXBContext context = JAXBContext.newInstance(obj.getClass());,最后返回xml格式的字符串,此时查看接口返回的Content-Type为application/json;charset=UTF-8,这是不正常的,然后代码中修改相应头的Content-Type:application/xml;charset=UTF-8也不生效,数据类似:
出现以上问题后,就想着用springboot同时返回json和xml的控制方法,引入依赖jackson-dataformat-xml,通过拦截器对指定参数名来控制返回的数据格式
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new WebInterceptor()).addPathPatterns("/**");
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false) //是否支持后缀的方式
.favorParameter(true) //是否支持请求参数的方式
.ignoreAcceptHeader(true) //是否忽略HttpHeader上的Accept指定
.parameterName("output") //请求参数名
.defaultContentType(MediaType.APPLICATION_JSON_UTF8); //默认返回格式
}
}
当output参数不传入或传入“json”时,默认返回json格式,当传入"xml"时返回xml格式,但是这里会有个问题,就是当传入随意参数时可能就无法返回数据了。
通过这种方法就暂时解决了我的问题!!!
附上我另外的一个定制需求:项目中有多个接口,有点接口默认返回json,但有的接口默认返回xml,这个时候光通过上面拦截器的方式可能不足够满足要求了。简单的方法就是重写上面new WebInterceptor()方法,在重写的postHandle方法中通过对outpu参数或某个接口进行控制。
public class WebInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
String output = request.getParameter("output");
String requestURI = request.getRequestURI();
//若传入参数为json
if (StringUtils.equalsIgnoreCase(output, "json")) {
//设置ContentType为application/json;charset=UTF-8
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
} else if (StringUtils.equalsIgnoreCase(output, "xml")) {
//若传入参数为xml
//设置ContentType为application/atom+xml
response.setContentType(MediaType.APPLICATION_ATOM_XML_VALUE);
} else {
if (StringUtils.containsIgnoreCase(requestURI, "a")) {
//当不传入output参数时,若接口是a接口,默认返回json
//则设置ContentType为application/json;charset=UTF-8
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
} else {
//当不传入output参数时,若接口是b接口,默认返回xml
//则设置ContentType为application/atom+xml
response.setContentType(MediaType.APPLICATION_ATOM_XML_VALUE);
}
}
}
}
返回json和xml格式的三种方法:https://www.cnblogs.com/SunArmy/p/9988950.html
Spring MVC ContentNegotiation内容协商机制(一个请求路径返回多种数据格式)源码解析:https://blog.csdn.net/qq_27529917/article/details/78447806