`

SpringMVC中内容协商【统一资源多种展现json xml html】

 
阅读更多

      在我们实际的开发中,往往需要SpringMVC服务提供多种的格式的数据。如:JSON、XML、HTML

当然我们知道SpringMVC已经提供了很多种转换器,供我们使用将数据转换成我们想要的数据格式。但是服务者怎么知道使用者,想要使用哪种数据格式哪?这就使用到了SpringMVC中的内容协商。

既然是内容协商,那么使用者肯定会告诉服务者,你给我返回什么类型的数据。使用者可以通过如下方式通知服务者。

一、内容协商

    1、使用参数

    

/userController/getUser?format=json
/userController/getUser?format=xml

    2、使用扩展名

 

   

/userController/getUser.html
/userController/getUser.json
/userController/getUser.xml

    3、使用http的Request Headers中的Accpet

 

   

GET /userController/getUser HTTP/1.1
Accept: application/xml                 //将返回xml格式数据

GET /userController/getUser HTTP/1.1
Accept: application/json               //将返回json格式数据

 以上三种方式分析:

 

   1、使用参数

     现在很多open API是使用这种方式,但可能由于要编写的字符较多。

    淘宝的开放平台就是使用的此种方式



 

2、使用扩展名称

   丧失了同一url多种展现的方式,但现在这种在实际环境中是使用比较方便的。

3、使用Request Header中Accpet

   这种方式是最理想的,但如果你的资源要给用户直接通过浏览器访问(即html展现),那么由于浏览器的差异,发送上来的Accept Header头将是不一样的. 将导致服务器不知要返回什么格式的数据给你. 下面是浏览器的Accept Header:

Chrome:



 

Firefox:



 

IE9:



 我们使用第一种方式和第二种方式,在Spring中如何让配置

 

二、SpringMVC配置

   现spring完成内容协商(content negotiation)的工作是由ContentNegotiatingViewResolver来完成的。

它的工作模式支持我上面讲的三种,ContentNegotiatingViewResolver是根据客户提交的MimeType(如 text/html,application/xml)来跟服务端的一组viewResover的MimeType相比较,如果符合,即返回viewResover的数据。
而 /userController/getUser.xml, ContentNegotiatingViewResolver会首先将 .xml 根据mediaTypes属性将其转换成 application/xml,然后完成前面所说的比较。

 

1、我们看下ContentNegotiatingViewResolver的配置:

<!-- 根据客户端的不同的请求决定不同的view进行响应, 如 /user/getUser.json /user/getUser.xml -->
	<bean
		class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
		<!-- 设置为true以忽略对Accept Header的支持 -->
		<property name="ignoreAcceptHeader" value="true" />
		<!-- 在没有扩展名时即: "/user/getUser" 时的默认展现形式 -->
		<property name="defaultContentType" value="text/html" />

		<!-- 扩展名至mimeType的映射,即 /getUser.json => application/json -->
		<property name="mediaTypes">
			<map>
				<entry key="json" value="application/json" />
				<entry key="xml" value="application/xml" />
			</map>
		</property>
		<!-- 用于开启 /user/getUser?format=json 的支持 -->
		<property name="favorParameter" value="false" />
		<property name="viewResolvers">
			<list>
				<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
				<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
					<property name="viewClass"
						value="org.springframework.web.servlet.view.JstlView" />
					<property name="prefix" value="/WEB-INF/page/" />
					<property name="suffix" value=".jsp"></property>
				</bean>
			</list>
		</property>
		<property name="defaultViews">
			<list>
				<!-- for application/json -->
				<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
				<!-- for application/xml -->
				<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
					<property name="marshaller">
						<!-- xstream.XStreamMarshaller -->
						<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
							<property name="classesToBeBound" >
								<list>
									<value>com.wy.pojo.User</value>
								</list>
							</property>
						</bean> 
					</property>
				</bean>
			</list>
		</property>
	</bean>

 我们在创建User对象

 

@XmlRootElement(name = "User")
public class User implements Serializable {

	private static final long serialVersionUID = 1L;
	private String username;
	private String password;
	private int age;
	private String sex;
	private String birthday;

	@XmlElement
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@XmlElement
	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@XmlElement
	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@XmlElement
	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	@XmlElement
	public String getBirthday() {
		return birthday;
	}

	public void setBirthday(String birthday) {
		this.birthday = birthday;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return this.username + "#" + this.password + "#" + this.age + "#"
				+ this.sex + "#" + this.birthday;
	}

}

 我们的控制层很简单的

 

@Controller
@RequestMapping("/userController")
public class UserController {
	@RequestMapping(value="getUser")
	public User getUser(){
		User user = new User();
		user.setUsername("wy");
		user.setPassword("123");
		user.setAge(123);
		user.setSex("male");
		user.setBirthday("2013-09-10");
		
		return user;
	}
}

 好,我们看下效果会是怎样子:

 

当我们在浏览器中输入:http://localhost:8080/SpringMVC/userController/getUser.json

结果:

{"user":{"username":"wy","password":"123","age":123,"sex":"male","birthday":"2013-09-10"}}

当我们在浏览器中输入:http://localhost:8080/SpringMVC/userController/getUser.xml

结果:

 

<User><age>123</age><birthday>2013-09-10</birthday><password>123</password><sex>male</sex><username>wy</username></User>

 

将配置文件中的

<!-- 用于开启 /user/getUser?format=json 的支持 -->
		<property name="favorParameter" value="false" />

 中false修改为true

 

我们再次在浏览器中输入:http://localhost:8080/SpringMVC/userController/getUser?format=json

 结果是:

{"user":{"username":"wy","password":"123","age":123,"sex":"male","birthday":"2013-09-10"}}

 

我们再次在浏览器中输入:http://localhost:8080/SpringMVC/userController/getUser?format=xml

结果是:

<User><age>123</age><birthday>2013-09-10</birthday><password>123</password><sex>male</sex><username>wy</username></User>

 

发现两次的请求结果是等效的。

 

下面是ContentNegotiatingViewResolver的完全配置:

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xmlns:util="http://www.springframework.org/schema/util" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context-3.0.xsd
          http://www.springframework.org/schema/mvc    
          http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
          http://www.springframework.org/schema/util 
          http://www.springframework.org/schema/util/spring-util-3.0.xsd" >
          
    <!-- 默认的注解映射的支持 ,它会自动注册DefaultAnnotationHandlerMapping 与AnnotationMethodHandlerAdapter--> 
    <mvc:annotation-driven />
    
    <!-- 自动扫描注解的Controller -->
	<context:component-scan base-package="com.wy.controller" />
	
	<!-- 根据客户端的不同的请求决定不同的view进行响应, 如 /user/getUser.json /user/getUser.xml -->
	<bean
		class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
		<!-- 设置为true以忽略对Accept Header的支持 -->
		<property name="ignoreAcceptHeader" value="true" />
		<!-- 在没有扩展名时即: "/user/getUser" 时的默认展现形式 -->
		<property name="defaultContentType" value="text/html" />

		<!-- 扩展名至mimeType的映射,即 /getUser.json => application/json -->
		<property name="mediaTypes">
			<map>
				<entry key="json" value="application/json" />
				<entry key="xml" value="application/xml" />
			</map>
		</property>
		<!-- 用于开启 /user/getUser?format=json 的支持 -->
		<property name="favorParameter" value="true" />
		<property name="viewResolvers">
			<list>
				<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
				<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
					<property name="viewClass"
						value="org.springframework.web.servlet.view.JstlView" />
					<property name="prefix" value="/WEB-INF/page/" />
					<property name="suffix" value=".jsp"></property>
				</bean>
			</list>
		</property>
		<property name="defaultViews">
			<list>
				<!-- for application/json -->
				<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
				<!-- for application/xml -->
				<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
					<property name="marshaller">
						<!-- xstream.XStreamMarshaller -->
						<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
							<property name="classesToBeBound" >
								<list>
									<value>com.wy.pojo.User</value>
								</list>
							</property>
						</bean> 
					</property>
				</bean>
			</list>
		</property>
	</bean>

</beans>

 

2、重载MappingJacksonJsonView

  我们在返回JSON格式的数据时,发现并不是我们常见的json。 也就是我们期望的返回是{success:true,message:”return ok”};  但实际返回的却是 {"jsonResult":{"success":true,"msg":"return ok"}}
原因是MappingJacksonJsonView中对返回值的处理未考虑modelMap中只有一个值的情况, 直接是按照mapName:{mapResult}的格式来返回数据的。

public class CustomJsonView extends MappingJacksonJsonView {
	protected Object filterModel(Map<String, Object> model) {  
        Map<?, ?> result = (Map<?, ?>) super.filterModel(model);  
        if (result.size() == 1) {  
            return result.values().iterator().next();  
        } else {  
            return result;  
        }  
    }  
}

 3、我们将

<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />

 替换为我们刚修改的

<bean class="com.wy.view.CustomJsonView"/>

 再次浏览器中输入:http://localhost:8080/SpringMVC/userController/getUser.json

看到的结果这是我们期望的:

{"username":"wy","password":"123","age":123,"sex":"male","birthday":"2013-09-10"}

 

 参考:http://badqiu.iteye.com/blog/552806

  • 大小: 52.7 KB
  • 大小: 87.1 KB
  • 大小: 44.4 KB
  • 大小: 22.3 KB
分享到:
评论
1 楼 zhmy0129 2013-10-18  



相关推荐

    SpringMVC框架中传递JSON数据时前台报406错误解决办法

    在Spring MVC框架中,开发人员经常需要处理JSON数据进行前后端交互。然而,在实际操作中,我们可能会遇到一个常见的问题,即HTTP状态码406(Not Acceptable)。这个错误通常意味着服务器生成了响应,但客户端无法...

    eclipse + maven多模块项目 + SpringMVC + jetty热部署实现验证码图片实例源码

    并且基于Spring MVC提供了一个完整功能:实现了生成验证码图片,以及验证输入是否匹配的两个接口,接口为Rest风格,符合内容协商原则(同一资源,多种展现:xml,json,html)。 另外,演示了注解(Annotation)的用法,实现...

    springmvc3.0所需jar绿色包

    4. **内容协商**:这个特性允许服务器根据客户端的偏好返回不同的格式,比如 JSON 或 XML,可以通过 `@RequestMapping` 注解的 `produces` 和 `consumes` 属性来指定。 5. **MVC 视图解析**:Spring MVC 3.0 引入了...

    测试springmvc3

    4. **内容协商**:此版本引入了内容协商功能,允许服务器根据客户端的接受类型(如 Accept 头)返回不同的格式,如 JSON、XML 或 HTML,增强了服务的可复用性。 5. **RESTful 支持**:通过 `@RequestMapping` 注解...

    SpringMVC3.0_Demo

    5. **内容协商**: 允许服务器根据客户端的能力返回不同格式的数据,如JSON、XML等,通过`@RequestMapping`的produces属性实现。 6. **国际化支持**: `MessageSource`接口提供国际化消息管理,使应用能适应不同地区...

    SpringMVC环境下实现的Ajax异步请求JSON格式数据

    在SpringMVC环境中实现Ajax异步请求JSON格式数据是一项常见的任务,这有助于创建更高效、交互性更强的Web应用程序。以下是一份详细的步骤指南和关键知识点解析: 首先,环境搭建是基础。确保你已经设置了标准的...

    spring 3.0 应用springmvc 构造RESTful URL 详细讲解

    RESTful服务应支持多种数据格式,如JSON、XML等。Spring MVC通过`produces`和`consumes`属性来指定控制器方法支持的媒体类型。 8. **安全性** 考虑到RESTful服务可能暴露给公众,安全性是重要的考虑因素。Spring ...

    springmvc 中文手册详细带书签.pdf

    Spring 3.2版本新增了对Servlet 3异步请求处理的支持、改进了Spring MVC的测试框架、增强了内容协商功能、支持泛型的RestTemplate、对@RequestBody参数的支持,以及对日期和时间格式化的全球支持等。另外,Spring ...

    Springmvc项目

    - **内容协商**: 支持多种格式的响应,如 JSON、XML。 4. **CRUD 操作** - **Create**: 创建新记录,通常使用 POST 请求。 - **Read**: 获取记录,GET 请求用于查询。 - **Update**: 更新记录,PUT 请求用于...

    SpringMVC使用@ResponseBody.rar

    通过这种方式,我们可以创建资源的CRUD操作,如GET、POST、PUT和DELETE,返回JSON或XML数据,使得客户端可以方便地进行交互。 6. **优化与最佳实践** - 避免过度使用`@ResponseBody`。对于复杂视图,使用视图解析...

    05、Web开发1

    1. **内容协商视图解析器(ContentNegotiatingViewResolver)** 和 **BeanNameViewResolver**:这两个视图解析器帮助Spring MVC根据请求的格式(如JSON、XML等)选择合适的视图来展示响应内容。BeanNameViewResolver...

    Jquery $.ajax 请求部署在 Tomcat报HTTP 406上解决方法

    在Jquery的$.ajax请求中,如果遇到部署在Tomcat上的Spring MVC应用返回HTTP 406错误,这通常是由于内容协商不成功导致的。本文将深入探讨这个问题,并提供解决方案。 首先,我们需要理解HTTP 406错误的含义。406 ...

    spring-boot-microservice-sample

    Spring Boot 微服务应用 这个小的 Spring Boot 应用程序充当了典型微服务... java -jar target/swagger-springmvc-bug.1.1.8.RELEASE.jar ( mvn spring-boot:run有效但 index.html 中使用的资源过滤无效) http://loca

    SSM框架常用核心接口和类.txt

    - **功能**: 内容协商视图解析器,根据请求头中的Accept类型选择合适的视图。 - **应用场景**: 实现响应不同格式的数据(如JSON或XML)。 **HandlerExceptionResolver** - **功能**: 异常处理程序,用于处理控制器...

    spring官方文档pdf

    - Spring 3.2版本中,支持Servlet 3异步请求处理基础,SpringMVC的测试框架得到增强,内容协商和@ControllerAdvice注释的改进。 - 引入了基于代码的Servlet 3+容器初始化抽象基类,以及...

    Spring MVC 3.0实战指南.ppt

    输出XML和JSON 使用HttpEntity&lt;T&gt;/ResponseEntity&lt;T&gt; 目录 数据绑定机理 数据类型转换 PropertyEditor依然有效 强大的ConversionService,让很多梦想成真 基于ConversionService体系,定义自定义的类型转换器 格式化...

Global site tag (gtag.js) - Google Analytics