如何通过网址扩展影响在AnnotationMethodHandlerAdapter
中为结果POJO选择邮件转换器的过程?
我希望有一个数据对象的更多表示,而数据表示应该由请求的URL扩展选择,例如/users/2.xml
或/users/2.json
。
消息处理程序的当前配置,应根据网址扩展名选择:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"
p:marshaller-ref="xmlMarshaller" p:unmarshaller-ref="xmlMarshaller" />
</list>
</property>
</bean>
有一种方法,我很熟悉并且正在使用ContentNegotiatingViewResolver,但是我想绕过视图解析过程并直接使用消息转换器。此外,在创建操作时,使用public ResponseEntity<User> showUser()
中的ResponseEntity可以对生成的http状态代码定义进行细粒度控制(OK,NOT_FOUND,NO_CONTENT,..)。我找不到使用ResponseEntity和ContentNegotiatingViewResolver的方法,这也可以满足我的需求。
另一种方法是根据网址扩展名将accept
标头修改为application/xml
或application/json
。这样,所有处理都应该直接进入配置的消息转换器。但是,我不知道篡改请求标头的合理方法。
感谢。
答案 0 :(得分:3)
由于选择HttpMessageConverter
s使用Accept
请求标头,因此实现内容协商的最简单方法可能是将此标头替换为URL扩展指定的所需媒体类型。
这可以作为Filter
(使用HttpServletRequestWrapper
替换标头值)或按照SPR-7517中的建议覆盖AnnotationMethodHanlderAdapter.createHttpInputMessage()
来实现(需要Spring 3.0.2)
另见SPR-6993。
答案 1 :(得分:2)
我有同样的需求并且将servlet过滤器一起攻击以完成任务。不是艺术品,而是完成工作:
public class UrlExtensionFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
if (httpServletRequest.getRequestURI().endsWith(".json")) {
MyAcceptHeaderRequest acceptHeaderRequest = new MyAcceptHeaderRequest(httpServletRequest);
acceptHeaderRequest.setAcceptHeader("application/json");
filterChain.doFilter(acceptHeaderRequest, response);
} else if (httpServletRequest.getRequestURI().endsWith(".xml")) {
MyAcceptHeaderRequest acceptHeaderRequest = new MyAcceptHeaderRequest(httpServletRequest);
acceptHeaderRequest.setAcceptHeader("text/xml");
filterChain.doFilter(acceptHeaderRequest, response);
} else {
filterChain.doFilter(request, response);
}
}
public void destroy() {
}
public class MyAcceptHeaderRequest extends HttpServletRequestWrapper {
private String accept = "application/json";
public MyAcceptHeaderRequest(HttpServletRequest request) throws IOException {
super(request);
}
public void setAcceptHeader(String value) {
accept = value;
}
@Override
public String getHeader(String name) {
if (name.equalsIgnoreCase("accept") || name.equalsIgnoreCase("content-type")) {
return accept;
} else {
return super.getHeader(name);
}
}
@Override
public Enumeration getHeaders(String name) {
if (name.equalsIgnoreCase("accept") || name.equalsIgnoreCase("content-type")) {
Enumeration enumeration = new StringTokenizer(accept);
return enumeration;
} else {
return super.getHeaders(name);
}
}
@Override
public String getContentType() {
return accept;
}
@Override
public String getParameter(String name) {
// When we're using this class and it is a POST operation then the body is JSON or XML so don't allow
// attempts to retrieve parameter names to consume the input stream
if (this.getMethod().equals("POST")) {
return null;
} else {
return super.getParameter(name);
}
}
@Override
public String[] getParameterValues(String name) {
// When we're using this class and it is a POST operation then the body is JSON or XML so don't allow
// attempts to retrieve parameter names to consume the input stream
if (this.getMethod().equals("POST")) {
return null;
} else {
return super.getParameterValues(name);
}
}
}
}