spring MVC自定义视图实现jsonp

约定的优先级规则:

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


}

效果图:

160810_89ZC_576855.png

160810_ZCOo_576855.png

160811_TKKt_576855.png

161831_1Mns_576855.png

161832_xsr2_576855.png

161832_JCGJ_576855.png

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


转载于:https://my.oschina.net/wnjustdoit/blog/612638

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值