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

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文件夹下下载

时间: 2024-10-31 01:10:04

springMVC4(15)RestFul多视图混合输出的相关文章

NodeJs——(15)动态视图助手

(38)动态视图助手 express版本:4.13.4 ①作用:假如我们需要一个变量,在不同地方的模板(jade文件)都需要调用. 显然,我们不应该使用全局变量(因为可能会带来污染): 事实上,我们需要的是仅仅在模板中起作用的变量,因此视图助手的作用就在这里了.     ②流程: [1]首先,调用express模块,就像我们之前做的那样(事实上,不需要额外声明,当我们使用express框架的时候自然会调用它):   [2]按照正常情况,我们需要进行路由处理,当使用视图助手时,有一件很重要的事情,

restful的实例论证

时下经常流行这各种概念型术语,一时间真的让很多人难以抓摸头脑.本文为大家讲解一下restful,以我的个人观点,带上实际例子来举证restful的优缺点和实现方法. 什么是restful? restful相信大家或多或少有听说/使用过.如果您还不直到restful是啥玩意,可以点击维基的说明进行知识增进. 从维基的说明中,可以明确知道restful具有四种状态请求:GET,POST,PUT,DELETE.四种请求中,仅有GET,POST可以直接用form表单进行提交请求.PUT和DELETE只有

Oracle学习(十八) 用户、角色和权限信息的视图总结

Oracle在sys用户方案中内置了许多视图,我们可以利用它们方便地查看系统相关的信息.在调用这 些视图的时候我们可以不加schema,以下是一些 关于用户.角色和权限信息的视图总结: (1)all_users视图:可以查看当前用户可以看到的所有用户 (2)dba_users视图:可以查看数据库中所有的用户信息 (3)user_users视图:可以查看当前用户的用户信息 (4)dba_ts_quotas视图:可以查看用户的表空间限额情况 (5)user_password_limits视图:可以查

跟我学Laravel之视图 &amp; Response_php实例

基本Response 从路由中返回字符串 复制代码 代码如下: Route::get('/', function() {     return 'Hello World'; }); 创建自定义Response Response类继承自Symfony\Component\HttpFoundation\Response类,提供了多种方法用于构建HTTP Response. 复制代码 代码如下: $response = Response::make($contents, $statusCode); $

UIView如何管理它的子视图

UIView的setNeedsDisplay和setNeedsLayout方法.首先两个方法都是异步执行的.而setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到UIGraphicsGetCurrentContext,就可以画画了.而setNeedsLayout会默认调用layoutSubViews,就可以处理子视图中的一些数据.宗上所诉,setNeedsDisplay方便绘图,而layoutSubViews方便出来数据. UIView提供了很多建立和管理视图的方法.

Qt之输出控制

简述 在Qt项目开发过程中,往往需要对程序的一些信息进行控制,比如:打印日志.调试信息等,便于我们后期查找.跟踪及定位问题. 下面,我们来分享下常用的几种方式.   简述 示例代码 应用程序输出 控制台输出 重定向至文件   示例代码 我们简单地写一些测试代码,用qDebug输出一些基本信息. #include <QApplication> #include <QWidget> #include <qDebug> int main(int argc, char *arg

求助——求解和为15的游戏棋盘问题

问题描述 publicclassGrid15{int[][]board;Grid15(){board=newint[3][3];}//输出棋盘的格线行privatevoidoutputGridRowBoard(){inti;System.out.print("+");for(i=0;i<5;i++){System.out.print("-");}System.out.println("+");}//输出棋盘的数据行(第i行,i只能为0.1或

加快敏捷、混合云基础设施的步伐

Gartner预测,到2020年"no-cloud policy"将像今天的"no internet policy"一样罕见,混合云将成为云基础设施的主流.尽管更多的公司向混合云迁移,但是混合基础设施的创新面临着巨大的挑战.环境的改变需要对IT部门.操作流程以及一般程序进行重大修改.但是"割裂和替换"战术,或者简单地在任务中添加,几乎都面临失败. 混合云的挑战根据目前的情况,专家估计,混合云计算仍然需要两到五年才能实现主流应用,目前只有15%的公

混合云计算模式的矛盾定义吓走客户

本文讲的是混合云计算模式的矛盾定义吓走客户,拥有一台电气动力车和一台燃油动力车并不意味着你就拥有了一台油电混合动力汽车.同样道理,云计算供应商不应把他们的云计算服务与其他托管或网络服务放在一起推销,然后还冠之以混合云计算模式之名. 但是,很不幸,现实世界中就是如此,这是因为业界内仍然缺乏混合云计算的通用定义.几乎每一家供应商都对其基础设施即服务(IaaS)有着一个定义范围,其中包括了公共云计算.私有云计算以及混合云计算,但是事实证明,众多混合云计算的定义方法并不相同,而其中相互矛盾之处也不少见.