虽然SpringMVC技术已经很成熟了,视图渲染技术相信大神们都熟透了,因为项目中使用到了多视图渲染,因此在这里记录一下。欢迎大家批评指点。
SpringMVC的视图和视图解析器实现了MVC的充分解耦,使得采用哪种视图对象对模型数据渲染的工作,不需要处理器去操心。
首先说下视图:其作用是讲模型数据以某种形式呈现给用户。(text/html、json、xml等)。Spring为我们实现了高度抽象接口 org.springframework.web.servlet包中的View接口,该接口中有两个方法:
- String getContentType(): 视图对应的MIME 类型,如text/html、json、xml等 。数据渲染成哪种类型
- void render(Map model,HttpServletRequest request,HttpServletResponse response); 渲染数据
不同类型的视图实现对应不同View实现类。这里不多说了。
然后是视图解析器:Spring MVC为逻辑视图名的解析提供了不同的解析策略,可以在Spring WEB 上下文中配置(这里我定义的名称为:dispatcher-servlet.xml)一种或者多种解析策略,并指定他们的先后顺序。所有视图解析器都实现ViewResolver接口。
因为要多视图解析,这里就只说一下多视图解析器 ContentNegotiatingViewResolver,也被成为内容协商解析器。该解析是在Spring 3.0新增的,它不负责具体的视图解析,而是作为一个中间角色,根据请求的MIME类型,从ApplicationContext中选择一个适合的视图解析器去做视图解析的工作。
通过下面的实例详细说明,
例如项目中使用到REST风格的URL以不同的MIME类型获取相同的资源。
- /spring-web/jsonfeed 默认访问方式,返回text/html
- spring-web/jsonfeed?content=json 返回json格式的数据
<span style="color:#009900;"><!-- 根据客户端不同的请求,决定不同的view进行响应 --></span>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<span style="color:#33cc00;"><!-- 该视图解析器启动顺序设置为最高 --></span>
<property name="order" value="0"/>
<property name="defaultContentType" value="text/html"></property>
<span style="color:#009900;"><!-- 因为不同浏览器产生的AcceptHeader不同,所以不采用Accept确定MIME类型,忽略对Accept Header的支持 --></span>
<property name="ignoreAcceptHeader" value="true" />
<span style="color:#009900;"><!-- 取消根据URL扩展名确认MIMEtype的方式 ex:aa.json --></span>
<property name="favorPathExtension" value="false"/>
<span style="color:#009900;"><!-- 通过参数content,确定MIME type ,ex: xx/aa.html?content=json --></span>
<property name="favorParameter" value="true" />
<property name="parameterName" value="content"/>
<span style="background-color: rgb(255, 255, 255);"><span style="color:#009900;"><!--根据请求参数值和MIME类型的映射列表 --></span></span>
<property name="mediaTypes">
<map>
<entry key="html" value="text/html" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<span style="color:#009900;"><!--for application/json --></span>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
</list>
</property>
</bean>
以上方式便实现了多视图解析功能,但是一般ApplicationContext中需要有默认的视图解析,来支持默认的text/html类型请求的解析,以下系统默认支持的配置。
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="10"/>
</bean>
<span style="color:#009900;"><!-- URL中不带参数content,由于通过defaultContentType="text/html"指定了默认的MIME类型,因此使用该解析 --></span>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="20"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/views" />
<property name="suffix" value=".jsp"></property>
</bean>
到此为止,应用上下文中的多视图支持配置完成,在Controller中实现一个restful 接口。
@RequestMapping(value="jsonfeed")
@ResponseBody
public Object getJson(Model model){
List<TournameContent> tournameCountList = new ArrayList<TournameContent>();
tournameCountList.add(TournameContent.generateContent("test", new Date(), "wo", "http:123.com"));
tournameCountList.add(TournameContent.generateContent("www", new Date(), "www", "http:www.com"));
tournameCountList.add(TournameContent.generateContent("rrr", new Date(), "rrr", "http:rrr.com"));
model.addAttribute("items", tournameCountList);
model.addAttribute("status", 0);
return model;
}
然后我们通过spring-test做一下单元测试,通过post方式执行HTTP请求,查看一下返回数据。
@ContextConfiguration(locations={"dispatcher-servlet.xml"})
public class SpringTest extends AbstractTestNGSpringContextTests {
@Test
public void post(){
String url = "http://127.0.0.1:18080/spring-web/jsonfeed?content=json";
HttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
StringBuffer sb = new StringBuffer();
InputStream is = null;
try {
HttpResponse response = client.execute(httpPost);
System.out.println("响应状态码"+response.getStatusLine().getStatusCode());
is= response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while((line=reader.readLine())!=null){
sb.append(line);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(sb.toString());
}
}
该测试类的以TESTNG方式运行,控制台输出结果为:
响应状态码200
{"items":[{"author":"test","publicationDate":1421125676544,"name":"wo","link":"http:123.com","id":0},{"author":"www","publicationDate":1421125676544,"name":"www","link":"http:www.com","id":0},{"author":"rrr","publicationDate":1421125676544,"name":"rrr","link":"http:rrr.com","id":0}],"status":0}
PASSED: post
json方式输出成功,然后测试默认方式,直接在浏览器中执行 http://127.0.0.1:18080/spring-web/jsonfeed,浏览器会加载jsonfeed.jsp。