springmvc 混合视图解决方案

有这样子的需求,我想通过同一个url来返回不同的视图,可以通过url的后缀,或者直接给个参数,然后服务器就帮我返回不同的视图,例如

/task/taskList : 返回jsp页面
/task/taskList.json : 返回json数据
/task/taskList.xml : 返回xml数据

或者这样子

/task/taskList : 返回jsp页面
/task/taskList?format = json : 返回json数据
/task/taskList?format =xml : 返回xml数据

在方法级别上注解@Response可以根据请求信息头部的accept为application/xml或者application/json可以帮我实现这种需求,但是这种方式有缺点

1.需要显示设置accept,麻烦
2.很难通过指定url的后缀或者给个参数就直接返回不同视图

基于这样子的需求,springmvc给我们提供了ContentNegotiatingViewResolver,内容协商视图解析器,我们先来配置一下,然后再讲原理


<!--配置视图解析器 -->
<bean   class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="viewResolvers">
            <list>
                <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
                <bean
                    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/WEB-INF/jsp/"></property>
                    <property name="suffix" value=".jsp"></property>
                    <property name="viewClass" value = "org.springframework.web.servlet.view.JstlView"></property>
                </bean>
            </list>
        </property>

        <property name="defaultViews">
            <list>
                <bean
                    class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
                <bean
                    class="org.springframework.web.servlet.view.xml.MappingJackson2XmlView" />

            </list>
        </property>
    </bean>

注意不要把annotation-driven中的path-matching的suffix-pattern和trailing-slash设置false,例如下面,不然/task/taskList,/task/taskList.json,/task/taskList.xml不能映射到同一个方法中

<mvc:annotation-driven
    content-negotiation-manager="contentNegotiationManager">
    <mvc:path-matching
     suffix-pattern="false"
     trailing-slash="false"
    />
</mvc:annotation-driven>

ContentNegotiatingViewResolver的作用其实做为一个代理人,根据上下文信息选择一个合适的解析去负责解析视图,所以在所有的解析器中ContentNegotiatingViewResolver的优先级是最高的,居然他是一个代理,我们就需要专门配置视图解析器,在这里我们配置了,BeanNameViewResolver解析器还有InternalResourceViewResolver解析器

...
<property name="viewResolvers">
            <list>
                <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
                <bean
                    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/WEB-INF/jsp/"></property>
                    <property name="suffix" value=".jsp"></property>
                    <property name="viewClass" value = "org.springframework.web.servlet.view.JstlView"></property>
                </bean>
            </list>
        </property>
...

ContentNegotiatingViewResolver解析视图的步骤方法

1.根据请求的头部信息即accpet还有url后缀来获取客户端浏览器所需要的媒体类型

2.再根据所注册的视图解析器,BeanNameViewResolver和InternalResourceViewResolver解析出方法体返回值的视图,如果你还注册了默认的视图,例如我们这里还注册了MappingJackson2JsonView以及MappingJackson2XmlView,然后返回视图列表。

3.根据请求的媒体类型还有返回的视图列表,根据媒体类型匹配遍历获取最佳的视图,然后返回给客户端

ContentNegotiatingViewResolver可以配置属性ContentNegotiationManager,ContentNegotiationManager可以由ContentNegotiationManagerFactoryBean来具体实现

public class ContentNegotiationManagerFactoryBean
        implements FactoryBean<ContentNegotiationManager>, ServletContextAware, InitializingBean {

    private boolean favorPathExtension = true; //是否支持url后缀

    private boolean favorParameter = false;//是否支持参数

    private boolean ignoreAcceptHeader = false;

    private Map<String, MediaType> mediaTypes = new HashMap<String, MediaType>(); //注册映射的媒体类型

    private boolean ignoreUnknownPathExtensions = true;

    private Boolean useJaf;

    private String parameterName = "format";//可以通过参数来指定返回的视图,参数名默认是format

    private ContentNegotiationStrategy defaultNegotiationStrategy; //默认的媒体类型解析策略

    private ContentNegotiationManager contentNegotiationManager;

    private ServletContext servletContext;

    ....

这里如果我还想指定,excel的媒体类型,我们可以配置下ContentNegotiationManager

<bean id="contentNegotiationManager"
        class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="mediaTypes">
            <value>
                json=application/json
                xml=application/xml
                html=text/html
                excel=application/vnd.ms-excel <!--excel媒体类型-->
            </value>
        </property>
    </bean>

然后把contentNegotiationManager注册到ContentNegotiatingViewResolver中

<bean
        class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        **<property name="contentNegotiationManager" ref="contentNegotiationManager" />**
        <property name="viewResolvers">
            <list>
                <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
                <bean
                    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                    <property name="prefix" value="/WEB-INF/jsp/"></property>
                    <property name="suffix" value=".jsp"></property>
                    <property name="viewClass" value = "org.springframework.web.servlet.view.JstlView"></property>
                </bean>
            </list>
        </property>

        <property name="defaultViews">
            <list>
                <bean
                    class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
                <bean
                    class="org.springframework.web.servlet.view.xml.MappingJackson2XmlView" />
            </list>
        </property>

    </bean>

然后我们把定义个controller就可以通过指定后缀来生成excel,xml或者json视图了

@RequestMapping("/mvcTest10")
    public String   mvcTest10(ModelMap modelMap) {

        List<Task> tasks = new ArrayList<Task>();

        Task t = new Task();
        t.setCreateTime(new Date());
        t.setTaskDetail("taskDetail");
        t.setTaskName("taskName");

        Task t1 = new Task();
        t1.setCreateTime(new Date());
        t1.setTaskDetail("taskDetail");
        t1.setTaskName("taskName");

        tasks.add(t1);
        tasks.add(t);

        modelMap.addAttribute("tasks",tasks);

        //return "task/task";
        return "taskListExcelView";     
    }

taskListExcelView的视图需要自己定义

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.stereotype.Component;
import org.springframework.web.servlet.view.document.AbstractExcelView;
import com.liuxg.task.entity.Task;

/**
 * excel视图
 * @author liuxg
 * @date 2016年4月9日 下午4:08:10
 */
@Component("taskListExcelView")
public class TaskListExcelView extends AbstractExcelView {

    @SuppressWarnings("unchecked")
    @Override
    protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook workbook, HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        List<Task> tasks = (List<Task>) model.get("tasks");

        response.setHeader("Content-disposition", "inline;filename="+new String("任务列表".getBytes() , "iso8859-1") + ".xls");

        HSSFSheet sheet = workbook.createSheet("tasks");

        HSSFRow header = sheet.createRow(0);
        header.createCell(0).setCellValue("任务名");
        header.createCell(1).setCellValue("任务详细");
        header.createCell(2).setCellValue("创建时间");

        int rowNum = 1 ;
        for(Task task : tasks){
            HSSFRow row = sheet.createRow(rowNum++);
            row.createCell(0).setCellValue(task.getTaskName());
            row.createCell(1).setCellValue(task.getTaskDetail());
            row.createCell(2).setCellValue(task.getCreateTime());
        }

    }

}

然后我们在客户端输入

http://localhost:8086/whats/task/mvcTest10.json返回json数据
http://localhost:8086/whats/task/mvcTest10.xml返回xml数据
http://localhost:8086/whats/task/mvcTest10.excel下载excel

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值