文档章节

spring MVC自定义视图实现jsonp

菜蚜
 菜蚜
发布于 2016/02/01 16:08
字数 985
阅读 374
收藏 16
点赞 1
评论 0

约定的优先级规则:

Spring supports a couple of conventions for selecting the format required: URL suffixes and/or a URL parameter. These work alongside the use of Accept headers. As a result, the content-type can be requested in any of three ways. By default they are checked in this order:
Add a path extension (suffix) in the URL. So, if the incoming URL is something likehttp://myserver/myapp/accounts/list.html then HTML is required. For a spreadsheet the URL should be http://myserver/myapp/accounts/list.xls. The suffix to media-type mapping is automatically defined via the JavaBeans Activation Framework or JAF (so activation.jar must be on the class path).
A URL parameter like this: http://myserver/myapp/accounts/list?format=xls. The name of the parameter is format by default, but this may be changed. Using a parameter is disabled by default, but when enabled, it is checked second.
Finally the Accept HTTP header property is checked. This is how HTTP is actually defined to work, but, as previously mentioned, it can be problematic to use.

spring-web.xml配置:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>

<!--1、检查扩展名(如my.pdf);2、检查Parameter(如my?format=pdf);3、检查Accept Header-->
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <!-- 扩展名至mimeType的映射,即 /user.json => application/json -->
    <property name="favorPathExtension" value="true"/>
    <!-- 用于开启 /userinfo/123?format=json 的支持 -->
    <property name="favorParameter" value="true"/>
    <property name="parameterName" value="format"/>
    <!-- 是否忽略Accept Header -->
    <property name="ignoreAcceptHeader" value="false"/>
    <!-- 扩展名到MIME的映射;favorPathExtension, favorParameter是true时起作用 注:此项由默认后缀匹配 -->
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json"/>
            <entry key="xml" value="application/xml"/>
            <entry key="html" value="text/html"/>
        </map>
    </property>
    <!-- 默认的content type -->
    <property name="defaultContentType" value="application/json"/>
</bean>

<!-- 内容协商视图解析器;根据客户端不同的请求决定不同的view进行响应 -->
<!-- 会自动根据解析的contentType来决定使用哪个视图解析器(默认使用整个web应用中的viewResolver) -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <!-- 内容协商管理器 用于决定media type -->
    <property name="contentNegotiationManager" ref="contentNegotiationManager"/>
    <!-- 默认视图 放在解析链最后 -->
    <property name="defaultViews">
        <list>
            <!--<bean class="com.alibaba.fastjson.support.spring.FastJsonJsonView"/>-->
            <bean class="com.caiya.test.ExtendedJsonView"/>
        </list>
    </property>
    <property name="order" value="0"/>
</bean>

<!-- 默认的视图解析器 在上边的解析错误时使用 (默认使用 html)- -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

json和jsonp视图类:

package com.caiya.test;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.view.AbstractView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created by caiya on 16/2/1.
 */
public class ExtendedJsonView extends AbstractView {

    public static final String  DEFAULT_CONTENT_TYPE = "application/json";

    public final static Charset UTF8                 = Charset.forName("UTF-8");

    private Charset             charset              = UTF8;

    private SerializerFeature[] serializerFeatures    = new SerializerFeature[0];

    private Set<String> renderedAttributes;

    private boolean             disableCaching       = true;

    private boolean             updateContentLength  = false;

    public ExtendedJsonView(){
        setContentType(DEFAULT_CONTENT_TYPE);
        setExposePathVariables(false);
    }

    public void setRenderedAttributes(Set<String> renderedAttributes) {
        this.renderedAttributes = renderedAttributes;
    }

    @Deprecated
    public void setSerializerFeature(SerializerFeature... features) {
        this.setFeatures(features);
    }

    public Charset getCharset() {
        return this.charset;
    }

    public void setCharset(Charset charset) {
        this.charset = charset;
    }

    public SerializerFeature[] getFeatures() {
        return serializerFeatures;
    }

    public void setFeatures(SerializerFeature... features) {
        this.serializerFeatures = features;
    }

    @Override
    protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
                                           HttpServletResponse response) throws Exception {
        Object value = filterModel(model);

        String text = JSON.toJSONString(value, serializerFeatures);

        String callback = request.getParameter("callback");
        if(StringUtils.isNotBlank(callback)){
            text = new StringBuilder(callback).append("(").append(text).append(")").toString();
        }

        byte[] bytes = text.getBytes(charset);

        OutputStream stream = this.updateContentLength ? createTemporaryOutputStream() : response.getOutputStream();
        stream.write(bytes);

        if (this.updateContentLength) {
            writeToResponse(response, (ByteArrayOutputStream) stream);
        }
    }

    @Override
    protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
        setResponseContentType(request, response);
        response.setCharacterEncoding(UTF8.name());
        if (this.disableCaching) {
            response.addHeader("Pragma", "no-cache");
            response.addHeader("Cache-Control", "no-cache, no-store, max-age=0");
            response.addDateHeader("Expires", 1L);
        }
    }

    /**
     * Disables caching of the generated JSON.
     * <p>
     * Default is {@code true}, which will prevent the client from caching the generated JSON.
     */
    public void setDisableCaching(boolean disableCaching) {
        this.disableCaching = disableCaching;
    }

    /**
     * Whether to update the 'Content-Length' header of the response. When set to {@code true}, the response is buffered
     * in order to determine the content length and set the 'Content-Length' header of the response.
     * <p>
     * The default setting is {@code false}.
     */
    public void setUpdateContentLength(boolean updateContentLength) {
        this.updateContentLength = updateContentLength;
    }

    /**
     * Filters out undesired attributes from the given model. The return value can be either another {@link Map}, or a
     * single value object.
     * <p>
     * Default implementation removes {@link BindingResult} instances and entries not included in the
     * {@link #setRenderedAttributes(Set) renderedAttributes} property.
     *
     * @param model the model, as passed on to {@link #renderMergedOutputModel}
     * @return the object to be rendered
     */
    protected Object filterModel(Map<String, Object> model) {
        Map<String, Object> result = new HashMap<String, Object>(model.size());
        Set<String> renderedAttributes = !CollectionUtils.isEmpty(this.renderedAttributes) ? this.renderedAttributes : model.keySet();
        for (Map.Entry<String, Object> entry : model.entrySet()) {
            if (!(entry.getValue() instanceof BindingResult) && renderedAttributes.contains(entry.getKey())) {
                result.put(entry.getKey(), entry.getValue());
            }
        }
        return result;
    }

}

测试controller:

package com.caiya.test.controllers;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by caiya on 16/1/28.
 */
@Controller
@RequestMapping(value = "/test")
public class TestController {


    private static final Logger logger = Logger.getLogger(TestController.class);

    @RequestMapping(value = {"/test2.json"})
    public Object test2(){
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("key", "value");
        return map;
    }

    @RequestMapping(value = {"/test2"}, produces = {"application/json"})
    public Object test22(){
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("key", "value");
        return map;
    }

    @RequestMapping(value = {"/test2"}, produces = {"text/html"})
    public Object test222(){

        return "cookie";
    }


}

效果图:

--------------------------------------


© 著作权归作者所有

共有 人打赏支持
菜蚜
粉丝 21
博文 56
码字总数 30515
作品 0
杭州
程序员
SpringMVC知识梳理(一)

什么是SpringMVC SpringMVC其实就是spring框架的一个模块,SpringMVC和spring之间可以无缝整合,SpringMVC也是一个非常优秀的基于MVC的web框架,什么是MVC这里就不多说了,下面来了解一下spr...

iHuawen ⋅ 2017/12/28 ⋅ 0

Spring MVC

Spring MVC一、什么是 Spring MVC Spring MVC 属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 里面,是一个强大灵活的 Web 框架。Spring MVC 提供了一个 DispatcherServlet ...

任任任任师艳 ⋅ 2017/11/20 ⋅ 0

SpringMVC ------自定义视图

一、视图和视图解析器 -- 请求处理方法执行完成后,最终返回一个 ModelAndView • 对象。对于那些返回 String,View 或 ModeMap 等类型的 处 理方法,Spring MVC 也会在内部将它们装配成一个...

Rickxue ⋅ 2015/12/17 ⋅ 0

Spring4.1新特性——Spring MVC增强

1、GroovyWebApplicationContext 在Spring 4.1之前没有提供Web集成的ApplicationContext,在《Spring4新特性——Groovy Bean定义DSL》中我们自己去实现的com.sishuok.spring4.context.suppo...

莱茵河水怪v241Beta ⋅ 2015/07/23 ⋅ 0

Spring Boot干货系列: (四)开发Web应用之Thymeleaf篇

        前言   Web开发是我们平时开发中至关重要的,这里就来介绍一下Spring Boot对Web开发的支持。   正文   Spring Boot提供了spring-boot-starter-web为Web开发予以支持,s...

后端编程嘟 ⋅ 2017/03/13 ⋅ 0

Spring3.2 MVC 分析

Spring3.2 MVC 分析: SpringMVC现在应该用得很广泛了,其配置清晰,灵活度,定制能力等都是很强的,相比Struts2也是胜过一筹,还是从源码来分析一下,SpringMVC为我们做了什么。 先从配置文...

ihaolin ⋅ 2014/02/03 ⋅ 2

Archx/spring-agg

#SPRING-AGG 这个一个框架整合案列,包含 SpringMVC/MyBatis/Apache Shiro 。 演示数据 演示数据请导入 db.sql 演示账号密码均为 SpringMVC 配置 演示项目使用的是 RESTful 风格,不是传统的...

Archx ⋅ 2015/01/12 ⋅ 0

springmvc学习笔记(1)-框架原理和入门配置

springmvc学习笔记(1)-框架原理和入门配置 标签: springmvc [TOC] 本文主要介绍springmvc的框架原理,并通过一个入门程序展示环境搭建,配置以及部署调试。 springmvc是spring框架的一个模块...

brianway ⋅ 2016/03/08 ⋅ 0

springMVC初认识

本文为转载学习 原文链接:http://jinnianshilongnian.iteye.com/blog/1594806 Spring Web MVC处理请求的流程 具体执行步骤如下: 1、首先用户发送请求————>前端控制器,前端控制器根据请...

heroShane ⋅ 2014/01/25 ⋅ 0

带着问题学 Spring MVC 源码: 一、概述

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! 简单就好,生活可以很德国 Q:什么是 Spring MVC ? ※ Spring MVC 是 Spring Web 的一个重要模块。Spring 支持...

泥沙砖瓦浆木匠 ⋅ 2016/10/23 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

思路分析 如何通过反射 给 bean entity 对象 的List 集合属性赋值?

其实 这块 大家 去 看 springmvc 源码 肯定可以找到实现办法。 因为 spirngmvc 的方法 是可以 为 对象 参数里面的 list 属性赋值的。 我也没有看 具体的 mvc 源码实现,我这里只是 写一个 简...

之渊 ⋅ 27分钟前 ⋅ 0

vim使用手册--配对括号的查找

1、把光标放在标记有(、[或{处。 2、按%字符 3、此时光标的位置应当在配对的括号处 4、再次按%就可以跳回配对的第一个括号处。

dragon_tech ⋅ 31分钟前 ⋅ 0

c++ 、object-c printf,%02X和%x有什么区别 ?

%x即按十六进制输出,英文字母小写,右对齐。 %02X有以下变化:英文字母变大写,如果输出字符不足两位的,输出两位宽度,右对齐,空的一位补0。超过两位的,全部输出。 如果不用 %02x 会出现...

yizhichao ⋅ 36分钟前 ⋅ 0

Spring源码解析(七)——实例创建(中)

前言 上一节讲到了,Spring 会根据实例的作用域执行不同的创建逻辑,分别是 Singleton、Prototype、其他 Scope,其中 Singleton 会调用 getSingleton 从缓存中获取,缓存中没有才会创建实例;...

MarvelCode ⋅ 36分钟前 ⋅ 0

Thrift RPC实战(六) spring集成thrift

1.服务端设置 对泛型Thrift Service的支持, 通过采用spring配置以及反射的方式来实现.对于一个服务提供者来说,需要提供端口,接口以及接口实现类,因此在接口中spring配置文件中配置如下 <!...

lemonLove ⋅ 39分钟前 ⋅ 0

oracle11g自动分区使用

为什么使用自动分区? 在oracle11g之前,oracle是不支持自动分区功能的,这就可能导致我们系统在运行一段时间之后,就需要看看分区是否创建或者写触发器进行创建分区,否则就会导致数据无法入...

strict_nerd ⋅ 50分钟前 ⋅ 0

Spring mvc ViewResolver视图解析器实现机制

概要 我们在controller里面经常这样return一个ModelAndView。 return new ModelAndView("userList", "users", userList); DispatcherServlet 靠 ViewResolver 把 userList 解析为 /WEB-INF......

轨迹_ ⋅ 今天 ⋅ 0

策略模式

1.策略模式 策略模式是同一个行为的不同处理办法。策略模式和简单工厂模式的区别:1.策略模式主要是方法的执行方式,工厂模式要获取的对象。两者的侧重点不同。 ...

Cobbage ⋅ 今天 ⋅ 0

行政区划代码转为字典形式

原数据为: http://www.mca.gov.cn/article/sj/xzqh/2018/201804-12/201804-06041553.html 手动替换了一下格式,并使用下面的代码处理. # 输入格式s = """110000:北京市110101:东城区1101...

漫步海边小路 ⋅ 今天 ⋅ 0

android apk 签名

创建key,需要用到keytool.exe (位于C:\Program Files\Java\jdk1.6.0_10\bin目录下),使用产生的key对apk签名用到的是jarsigner.exe (位于C:\Program Files\Java\jdk1.6.0_10\bin目录下),把...

国仔饼 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部