文档章节

spring MVC自定义视图实现jsonp

菜蚜
 菜蚜
发布于 2016/02/01 16:08
字数 985
阅读 385
收藏 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";
    }


}

效果图:

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


© 著作权归作者所有

共有 人打赏支持
菜蚜
粉丝 28
博文 76
码字总数 36325
作品 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
Spring 3.x Web MVC

本文demo下载地址:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=1142 Spring 3.x Web MVC Spring mvc 特点 @ 功能组件划分细致 @ 灵活、强大 @ 设计思想优秀 MVC框......

智慧点点
08/26
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

没有更多内容

加载失败,请刷新页面

加载更多

Kafka如何做到1秒处理1500万条消息?

Apache Kafka 是一款流行的分布式数据流平台,它已经广泛地被诸如 New Relic(数据智能平台)、Uber、Square(移动支付公司)等大型公司用来构建可扩展的、高吞吐量的、且高可靠的实时数据流系统...

架构师springboot
24分钟前
5
0
如何清理Nexus Repository Manager

随着开发运维一体化的理念逐渐深入,持续集成流水线已经成为软件开发的标配。持续集成通过高度自动化的方式,使得构建发布变得非常简单,构建发布次数随之变的越来越多。我们在享受高频次的构...

JasonSE
37分钟前
1
0
聊聊storm的ack机制

序 本文主要研究一下storm的ack机制 实例 SentenceSpout public class AckSentenceSpout extends BaseRichSpout { private ConcurrentHashMap<UUID, Values> pending; private Spo......

go4it
47分钟前
1
0
《netty入门与实战》笔记-05:netty内置的channelHandler

Netty 内置了很多开箱即用的 ChannelHandler。下面,我们通过学习 Netty 内置的 ChannelHandler 来逐步构建我们的 pipeline。 ChannelInboundHandlerAdapter 与 ChannelOutboundHandlerAdap...

Funcy1122
今天
3
0
帧动画(wifi信号动态动画)

准备六张wifi不同信号强度的素材图片,复制到drawable目录中 在drawable目录中新建frame文件,并编写代码 <animation-list xmlns:android="http://schemas.android.com/apk/res/android"> ...

lanyu96
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部