转载自:
http://www.cnblogs.com/zhaoyang/archive/2012/01/07/2315428.html
http://www.cnblogs.com/zhaoyang/archive/2012/01/07/2315432.html
http://www.cnblogs.com/zhaoyang/archive/2012/01/07/2315436.html
这个解析器是做什么用的?
RESTful服务中很重要的一个特性即是同一资源,多种表述我们使用ContentNegotiatingViewResolver就可以做到,这个视图解析器允许你用同样的内容数据来呈现不同的view
如下面描述的三种方式:
方式1 使用扩展名
http://www.test.com/user.xml 呈现xml文件
http://www.test.com/user.json 呈现json格式
http://www.test.com/user 使用默认view呈现,比如jsp等
-----------------------------------------------------------------------------------------------------
方式2 使用http request header的Accept
GET /user HTTP/1.1
Accept:application/xml
GET /user HTTP/1.1
Accept:application/json
….
-----------------------------------------------------------------------------------------------------
方式3 使用参数
http://www.test.com/user?format=xml
http://www.test.com/user?format=json
这三种方式各自的优缺点这里就不再介绍了
如何使用ContentNegotiatingViewResolver?
假设我们有这么一个目标:
/user/{userid}.json 用于返回一个描述User的JSON
/user/{userid} 用于返回一个展示User的JSP页面
/user/{userid}.xml 用于返回一个展示User的XML文件
配置文件说明 (具体例子下篇文章放上)
我们知道有accept header,扩展名以及参数这三种方式,配置文件中
这里是解析器的执行顺序,如果有多个的话(前面多次解释过)
--------------------------------------------------------------------------------------------------------------
如果所有的mediaType都没匹配上,就会使用defaultContentType
这里是是否启用扩展名支持,默认就是true
例如 /user/{userid}.json
这里是是否启用参数支持,默认就是true
例如 /user/{userid}?format=json
这里是否忽略掉accept header,默认就是false
例如 GET /user HTTP/1.1
Accept:application/json
我们的例子是采用.json , .xml结尾的,所以关掉两个
--------------------------------------------------------------------------------------------------------------
这里是扩展名到mimeType的映射,
例如 /user/{userid}.json 中的 .json 就会映射到 application/json
注:
ContentNegotiatingViewResolver是根据客户提交的MimeType(如 text/html,application/xml)来跟服务端的一组viewResover的MimeType相比较,如果符合,即返回viewResover的数据.
而 /user/123.xml, ContentNegotiatingViewResolver会首先将 .xml 根据mediaTypes属性将其转换成 application/xml,然后完成前面所说的比较.
根据前篇文件的介绍,这里直接给出例子
配置xml
Model
@XmlRootElement
public class User {
private long userID;
private String userName;
private Date birth;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public long getUserID() {
return userID;
}
public void setUserID(long userID) {
this.userID = userID;
}
}
Contoller
@RequestMapping(value="/user/{userid}")
public String queryUser(@PathVariable("userid") long userID, ModelMap model)
{
User u = new User();
u.setUserID(userID);
u.setUserName("zhaoyang");
model.addAttribute("User", u);
return "User";
}
如果是返回text/html,还需要建立个jsp文件
UserName: ${requestScope.User.userID }
Age: ${requestScope.User.userName }
测试结果
json
xml
jsp
作用?
@RequestBody 将 HTTP 请求正文插入方法中,使用适合的HttpMessageConverter将请求体写入某个对象。
@ResponseBody 将内容或对象作为 HTTP 响应正文返回,使用@ResponseBody将会跳过视图处理部分,而是调用适合HttpMessageConverter,将返回值写入输出流。
默认给AnnotationMethodHandlerAdapter初始化的有(当然我们也可以添加自定义的converter)
ByteArrayHttpMessageConverter
StringHttpMessageConverter
ResourceHttpMessageConverter
SourceHttpMessageConverter
XmlAwareFormHttpMessageConverter
Jaxb2RootElementHttpMessageConverter
MappingJacksonHttpMessageConverter
1 首先获取注册的所有HttpMessageConverter集合
2 然后客户端的请求header中寻找客户端可接收的类型,
比如 Accept application/json,application/xml等,组成一个集合
3 所有的HttpMessageConverter 都有canRead和canWrite方法 返回值都是boolean,看这个HttpMessageConverter是否支持当前请求的读与写,读对应@RequestBody注解, 写对应@ResponseBody注解
4 遍历HttpMessageConverter集合与前面获取可接受类型进行匹配,如果匹配直接使用当前第一个匹配的HttpMessageConverter,然后return(一般是通过Accept和返回值对象的类型进行匹配)
例如
StringHttpMessageConverter
支持String , Accept所有类型
MappingJacksonHttpMessageConverter
支持Map List 实体对象等等 ,Accept:application/json
目标:
使用ResponseBody根据head的Accept不同对同一地址请求分别来呈现一个实体的json与xml结果
由于
默认会初始化AnnotationMethodHanlderAdapter,但我们返回xml内容需要对这个HandlerAdapter进行一定的修改,所以配置文件如下:
"stringHttpMessageConverter" />
"marshallingHttpMessageConverter" />
注:要使用Jaxb2Marshaller我们在对应的实体,比如User类上需要标明
@XmlRootElement 注解,需要引入
import javax.xml.bind.annotation.XmlRootElement;
这个包。
Controller中应对请求的方法
@RequestMapping(value="/user/{userid}", method=RequestMethod.GET)
public @ResponseBody User queryUser(@PathVariable("userid") long userID) {
Calendar d = Calendar.getInstance();
d.set(1987, 12, 9);
User u = new User();
u.setUserID(userID);
u.setUserName("zhaoyang");
u.setBirth(d.getTime());
return u;
}
接着我们使用curl这个工具进行测试
如下图: