springMVC4(15)RestFul多视图混合输出

  1. 云栖社区>
  2. 博客>
  3. 正文

springMVC4(15)RestFul多视图混合输出

jeanheo 2016-04-07 00:19:00 浏览2275
展开阅读全文

4# 混合使用多种视图技术。
在前面文章里,我们对jsp、json、xml个中视图都进行了较为详细的实例解析,但涉及到的都是单视图使用配置。在实际开发中,我们可能需要混合是使用多种视图技术。尤其是针对REST编程风格,我们可以通过一个URL、多种视图来切合REST风格的同一资源、多种表述
现在加入我们要输出JSP、JSON、XML多种视图技术,如果使用我之前文章《springMVC4(4)json与对象互转实例解析请求响应数据转换器 》提到的HttpMessageConvert来完成数据类型输出切换。它相对于多视图输出的局限性是:
1. 必须通过HTTP请求头的Accept来控制转换器的使用类型,如果客户端是安卓等还能通过HttpClient、RestTemplate等控制,但如果客户端是游览器,除非使用AJAX技术,否则很难控制请求头内容
2. 无法通过URL扩展名或请求参数来控制服务端的资源输出类型。而使用多种视图技术,我们可以通过以下形式控制输出不同视图:
1. 扩展名:
1. /user.xml 呈现xml文件
2. /user.json 呈现json格式
3. /user.xls 呈现excel文件
4. /user.pdf 呈现pdf文件
5. /user 使用默认view呈现,比如jsp等
2. 请求参数:
1. /user?type=xml 呈现xml文件
2. /user?type=json 呈现json格式
3. /user?type=xls 呈现excel文件
4. /user?type=pdf 呈现pdf文件
5. /user? 使用默认view呈现,比如jsp等

ContentNegotiatingViewResolver

我们使用ContentNegotiatingViewResolver视图解析器来完成多种视图混合解析,从它的名字上看,它是一个视图协调器,负责根据请求信息从当前环境选择一个最合适的解析器进行解析,也即是说,它本身并不负责解析视图。
它有3个关键属性:
1. favorPathExtension:如果设置为true(默认为true),则根据URL中的文件拓展名来确定MIME类型
2. favorPathExtension:如果设置为true(默认为false),可以指定一个请求参数确定MIME类型,默认的请求参数为format,可以通过parameterName属性指定一个自定义属性。
3. ignoreAcceptHeader(默认为false),则采用Accept请求报文头的值确定MIME类型。由于不同游览器产生的Accept头不一致,不建议采用Accept确定MIME类型。
在实际流程中,ContentNegotiatingViewResolver也是根据以上三个互斥属性的配置情况来确定视图类型,其中属性1优先级最高,属性3优先级最低

除了以上三个属性,还有一个关键属性是mediaTypes,用来配置不同拓展名或参数值映射到不同的MIME类型
在前面,我们展示了使用jsp/模板、json、xml、Excel等来呈现我们的视图,下面我们通过整合上述视图来分析我们的多视图混合技术

多视图混合Rest呈现实例

1. 配置视图解析器

<!-- 根据确定出的不同MIME名,使用不同视图解析器解析视图 -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <!-- 设置优先级 -->
    <property name="order" value="1" />
    <!-- 设置默认的MIME类型,如果没有指定拓展名或请求参数,则使用此默认MIME类型解析视图 -->
    <property name="defaultContentType" value="text/html" />
    <!-- 是否不适用请求头确定MIME类型 -->
    <property name="ignoreAcceptHeader" value="true" />
     <!-- 是否根据路径拓展名确定MIME类型 -->
    <property name="favorPathExtension" value="false" />
   <!-- 是否使用参数来确定MIME类型 -->
    <property name="favorParameter" value="true" /> 
    <!-- 上一个属性配置为true,我们指定type请求参数判断MIME类型 -->
    <property name="parameterName" value="type" />
    <!-- 根据请求参数或拓展名映射到相应的MIME类型 -->
    <property name="mediaTypes">
        <map>
            <entry key="html" value="text/html" />
            <entry key="xml" value="application/xml" />
            <entry key="json" value="application/json" />
            <entry key="excel" value="application/vnd.ms-excel"></entry>
        </map>
    </property>
    <!-- 设置默认的候选视图,如果有合适的MIME类型,将优先从以下选择视图,找不到再在整个Spring容器里寻找已注册的合适视图 -->
    <property name="defaultViews">
        <list>
            <bean class="org.springframework.web.servlet.view.InternalResourceView">
                <property name="url" value="WEB-INF/views/hello.jsp"></property>
            </bean>
            <bean
                class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
            <ref local="myXmlView" />
            <bean class="com.mvc.view.ExcelView" />

        </list>
    </property>
</bean>
<!-- Excel视图 -->
<bean class="com.mvc.view.ExcelView" id="excelView" /><!-- 注册自定义视图 -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView"
    id="myXmlView">
    <property name="modelKey" value="articles" />
    <property name="marshaller" ref="xmlMarshaller" />
</bean>
<bean class="org.springframework.oxm.xstream.XStreamMarshaller"
    id="xmlMarshaller"><!-- 将模型数据转换为XML格式 -->
    <property name="streamDriver">
        <bean class="com.thoughtworks.xstream.io.xml.StaxDriver" />
    </property>
</bean>

关于以上视图文件的配置实体讲解可移步参考我前面的文章

2. jsp视图文件

<%@page import="com.mvc.model.Article"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <title>hello spring mvc</title>
  </head>
  <body>
  <c:out value="${articles}"></c:out>
  </body>
</html>

3. Excel配置文件

package com.mvc.view;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.web.servlet.view.document.AbstractExcelView;

import com.mvc.model.Article;

public class ExcelView extends AbstractExcelView {

    @Override
    protected void buildExcelDocument(Map<String, Object> model,
            HSSFWorkbook workbook, HttpServletRequest request,
            HttpServletResponse response) throws Exception {
         List<Article> articles= (List<Article>) model.get("articles");

         HSSFSheet sheet = workbook.createSheet("文章列表");//创建一页
         HSSFRow header = sheet.createRow(0);//创建第一行
         header.createCell(0).setCellValue("标题");
         header.createCell(1).setCellValue("正文");
         for( int i = 0; i < articles.size();i++){
             HSSFRow row = sheet.createRow(i + 1);
             Article article = articles.get(i);
             row.createCell(0).setCellValue(article.getTitle());
             row.createCell(1).setCellValue(article.getContent());
         }
    }

}

4. Article POJO类

package com.mvc.model;

public class Article {
    private String title;
    private String content;

    //忽略get和set方法
    @Override
    public String toString() {
        return "Article [ title=" + title + ", content="
                + content + "]";
    }

}

5. 控制器测试方法

@RequestMapping("views")
public String views(ModelMap map,HttpServletRequest request){
    List<Article>articles = new ArrayList<Article>();
    for(int i = 0 ; i < 5; i ++){
        Article article = new Article();
        article.setTitle("title" +i);
        article.setContent("content" + i);
        articles.add(article);
    }
    map.addAttribute("articles",articles);//将文章对象绑定到
    return "views";
}

6. 进行测试

我们使用了参数type来映射不同的视图类型:

1. 默认参数类型:

这里写图片描述

2. html参数类型

这里写图片描述

3. json参数类型

这里写图片描述

4. xml参数类型

这里写图片描述

5. excel参数类型

这里写图片描述
点击下载后打开如下图所示:
这里写图片描述

7. 使用拓展名类型

上面我们使用参数的方法访问,如果我们改成使用拓展名的形式,如下所示,只需去掉其中的4行配置:

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><!-- 根据确定出的不同MIME名,使用不同视图解析器解析视图 -->
    <property name="order" value="1" /><!-- 设置优先级 -->
    <property name="defaultContentType" value="text/html" /><!-- 设置默认的MIME类型,如果没有指定拓展名或请求参数,则使用此默认MIME类型解析视图 -->
    <property name="mediaTypes"><!-- 根据请求参数映射到相应的MIME类型 -->
        <map>
            <entry key="html" value="text/html" />
            <entry key="xml" value="application/xml" />
            <entry key="json" value="application/json" />
            <entry key="excel" value="application/vnd.ms-excel"></entry>
        </map>
    </property>
    <property name="defaultViews"><!-- 设置默认的候选视图,如果有合适的MIME类型,将优先从以下选择视图,找不到再在整个Spring容器里寻找已注册的合适视图 -->
        <list>
            <bean class="org.springframework.web.servlet.view.InternalResourceView">
                <property name="url" value="WEB-INF/views/hello.jsp"></property>
            </bean>
            <bean
                class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
            <ref local="myXmlView" />
            <bean class="com.mvc.view.ExcelView" />
        </list>
    </property>
</bean>

这个时候,我们就可以使用:
http://localhost:8080/springMVC/views
http://localhost:8080/springMVC/views.html,
http://localhost:8080/springMVC/views.json
http://localhost:8080/springMVC/views.xml
来对应得到与上面相同的内容。感兴趣的朋友可在下面下载源码自行测试

源码下载

本节内容源码可到http://github.com/jeanhao/spring的multiViews文件夹下下载

网友评论

登录后评论
0/500
评论