文档章节

spring MVC自定义视图实现jsonp

菜蚜
 菜蚜
发布于 2016/02/01 16:08
字数 985
阅读 377
收藏 16

约定的优先级规则:

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";
    }


}

效果图:

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


© 著作权归作者所有

共有 人打赏支持
菜蚜
粉丝 25
博文 75
码字总数 35439
作品 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
0
Spring4 + Spring MVC + MyBatis 整合思路

原文出处:斯武丶风晴 1、Spring框架的搭建 这个很简单,只需要web容器中注册org.springframework.web.context.ContextLoaderListener,并指定spring加载配置文件,那么spring容器搭建完成。...

斯武丶风晴
2017/09/21
0
0
Spring4+SpringMVC+MyBatis整合思路

本文主要简单讲解框架整合的思路。 1、Spring框架的搭建 这个很简单,只需要web容器中注册org.springframework.web.context.ContextLoaderListener,并指定spring加载配置文件,那么spring容...

Java团长17
07/11
0
0
SpringMVC知识梳理(一)

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

iHuawen
2017/12/28
0
0
SpringMVC 基于注解的Controller @RequestMapping @Request

概述 继 Spring 2.0 对 Spring MVC 进行重大升级后,Spring 2.5 又为 Spring MVC 引入了注解驱动功能。现在你无须让 Controller 继承任何接口,无需在 XML 配置文件中定义请求和 Controller...

蓝狐乐队
2014/02/28
0
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

[雪峰磁针石博客]软件测试专家工具包1web测试

web测试 本章主要涉及功能测试、自动化测试(参考: 软件自动化测试初学者忠告) 、接口测试(参考:10分钟学会API测试)、跨浏览器测试、可访问性测试和可用性测试的测试工具列表。 安全测试工具...

python测试开发人工智能安全
今天
2
0
JS:异步 - 面试惨案

为什么会写这篇文章,很明显不符合我的性格的东西,原因是前段时间参与了一个面试,对于很多程序员来说,面试时候多么的鸦雀无声,事后心里就有多么的千军万马。去掉最开始毕业干了一年的Jav...

xmqywx
今天
2
0
Win10 64位系统,PHP 扩展 curl插件

执行:1. 拷贝php安装目录下,libeay32.dll、ssleay32.dll 、 libssh2.dll 到 C:\windows\system32 目录。2. 拷贝php/ext目录下, php_curl.dll 到 C:\windows\system32 目录; 3. p...

放飞E梦想O
今天
0
0
谈谈神秘的ES6——(五)解构赋值【对象篇】

上一节课我们了解了有关数组的解构赋值相关内容,这节课,我们接着,来讲讲对象的解构赋值。 解构不仅可以用于数组,还可以用于对象。 let { foo, bar } = { foo: "aaa", bar: "bbb" };fo...

JandenMa
今天
1
0
OSChina 周一乱弹 —— 有人要给本汪介绍妹子啦

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子 :分享水木年华的单曲《中学时代》@小小编辑 手机党少年们想听歌,请使劲儿戳(这里) @须臾时光:夏天还在做最后的挣扎,但是晚上...

小小编辑
今天
54
8

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部