springboot跨域请求,实现跨域jsonp请求服务端数据自动封装

IT黑名单 2016-11-28 13:50:20

前端代码

$.ajax({
	type:'get',
	dataType:'jsonp',
	url:'http://www.itblacklist.cn/test/jsonp',
	data:{'id':123},
	success:function(data){
		console.log('success...');
	}
});

$.ajax({
	type:'get',
	url:'http://www.itblacklist.cn/test/test2',
	data:{'id':123},
	success:function(data){
		console.log('success...');
	}
});

服务端增加以下类

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.context.request.NativeWebRequest;


public class ContentNegotiationStrategyWrap implements
		ContentNegotiationStrategy {
    private static Logger log = LoggerFactory.getLogger(ContentNegotiationStrategyWrap.class);
    private final ContentNegotiationStrategy strategy;
    private Set<String> jsonpParameterNames = new LinkedHashSet<String>(Arrays.asList("jsonp", "callback"));
    private static final Pattern CALLBACK_PARAM_PATTERN = Pattern.compile("[0-9A-Za-z_\\.]*");

    private String getJsonpParameterValue(NativeWebRequest request) {
        if (this.jsonpParameterNames != null) {
            for (String name : this.jsonpParameterNames) {
                String value = request.getParameter(name);
                if (StringUtils.isEmpty(value) || !isValidJsonpQueryParam(value))
                    continue;
                return value;
            }
        }
        return null;
    }

    protected boolean isValidJsonpQueryParam(String value) {
        return CALLBACK_PARAM_PATTERN.matcher(value).matches();
    }

    public ContentNegotiationStrategyWrap(ContentNegotiationStrategy strategy) {
        super();
        this.strategy = strategy;
    }

    @Override
    public List<MediaType> resolveMediaTypes(NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
        String jsonpParameterValue = getJsonpParameterValue(request);
        if (jsonpParameterValue != null) {
            List<MediaType> mediaTypes = new ArrayList<>(1);
            mediaTypes.add(MediaType.valueOf("application/javascript"));
            return mediaTypes;
        }
        return this.strategy.resolveMediaTypes(request);
    }
}
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.ServletPathExtensionContentNegotiationStrategy;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

@Configuration
public class ResponseBodyProcessor extends WebMvcConfigurerAdapter implements
		InitializingBean {
	@Autowired
    private RequestMappingHandlerAdapter adapter;
	@Autowired
    private ContentNegotiationManager manager;
	
	@Override
	public void afterPropertiesSet() throws Exception {
		List<HandlerMethodReturnValueHandler> returnValueHandlers = adapter.getReturnValueHandlers();
        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(returnValueHandlers);
        decorateHandlers(handlers);
        adapter.setReturnValueHandlers(handlers);
        processContentNegotiationManager();
	}

	 private void processContentNegotiationManager() {
	        List<ContentNegotiationStrategy> strategies = manager.getStrategies();
	        for (int i = 0; i < manager.getStrategies().size(); i++) {
	            if (manager.getStrategies().get(i) instanceof ServletPathExtensionContentNegotiationStrategy) {
	                strategies.set(i, new ContentNegotiationStrategyWrap(manager.getStrategies().get(i)));
	                manager = new ContentNegotiationManager(strategies);
	                break;
	            }
	        }
	    }

	    private void decorateHandlers(List<HandlerMethodReturnValueHandler> handlers) {
	        for (HandlerMethodReturnValueHandler handler : handlers) {
	            if (handler instanceof RequestResponseBodyMethodProcessor) {
	                ResponseBodyWrapHandler decorator = new ResponseBodyWrapHandler(handler);
	                int index = handlers.indexOf(handler);
	                handlers.set(index, decorator);
	                break;
	            }
	        }
	    }

	    @Override
	    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
	        for (HttpMessageConverter<?> httpMessageConverter : converters) {
	            if (httpMessageConverter instanceof MappingJackson2HttpMessageConverter) {
	                MappingJackson2HttpMessageConverter convert = (MappingJackson2HttpMessageConverter) httpMessageConverter;
	                List<MediaType> medisTypeList = new ArrayList<>(convert.getSupportedMediaTypes());
	                medisTypeList.add(MediaType.valueOf("application/javascript;charset=UTF-8"));
	                convert.setSupportedMediaTypes(medisTypeList);
	                break;
	            }
	        }
	        super.extendMessageConverters(converters);
	    }
}
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

public class ResponseBodyWrapHandler implements HandlerMethodReturnValueHandler {

	private static Logger log = LoggerFactory.getLogger(ResponseBodyWrapHandler.class);
	private final HandlerMethodReturnValueHandler delegate;  
    private Set<String> jsonpParameterNames = new LinkedHashSet<String>(Arrays.asList("jsonp", "callback"));
    private static final Pattern CALLBACK_PARAM_PATTERN = Pattern.compile("[0-9A-Za-z_\\.]*");

    private String getJsonpParameterValue(NativeWebRequest request) {
        if (this.jsonpParameterNames != null) {
            for (String name : this.jsonpParameterNames) {
                String value = request.getParameter(name);
                if (StringUtils.isEmpty(value) || !isValidJsonpQueryParam(value))
                    continue;
                return value;
            }
        }
        return null;
    }

    protected boolean isValidJsonpQueryParam(String value) {
        return CALLBACK_PARAM_PATTERN.matcher(value).matches();
    }

    public ResponseBodyWrapHandler(HandlerMethodReturnValueHandler delegate){  
      this.delegate=delegate;  
    }  

    @Override  
    public boolean supportsReturnType(MethodParameter returnType) {  
        return delegate.supportsReturnType(returnType);  
    }  

    @Override  
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {  
        String jsonpParameterValue = getJsonpParameterValue(webRequest);
        if (jsonpParameterValue != null) {
            if (!(returnValue instanceof MappingJacksonValue)) {
                MappingJacksonValue container = new MappingJacksonValue(returnValue);
                container.setJsonpFunction(jsonpParameterValue);
                returnValue = container;
            }
        }
        delegate.handleReturnValue(returnValue,returnType,mavContainer,webRequest);  
    }  
}

Conroller代码

/**
 * 描述: testController
 *
 * @author <a href="mailto:admin@itblacklist.com">admin</a>
 * @createDate 2016-11-28 13:37:55
 */
@RestController
@RequestMapping("/test")
public class TestController {
	@RequestMapping("/jsonp")
	public String jsonp(Long id) {
		return "success"+id;
	}
	
	@RequestMapping("/test2")
	public String test2(Long id) {
		return "success"+id;
	}
}

这样dataType:'jsonp'的请求服务端会自动封装成支持jsonp的响应,跨域的jsonp请求和普通的请求对Controller层没有任何影响。


转载请注明来源【IT黑名单

本文链接:http://blog.itblacklist.cn/20161128/8428.html

© Copyright 2016 IT黑名单 Inc.All Rights Reserved. 豫ICP备15018592号-2