如果一个项目中跨域请求太多,那么在后端需要给很多controller方法的返回值拼接callback。显然太麻烦。我们可以给spring扩展一下,使其统一支持jsonp。
创建消息转换器
package com.nongmall.manage.json;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonProcessingException;
@ControllerAdvice
public class CallbackMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
//jsonp标识
private String callbackName;
@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
//从threadLocal中获取当前的Request对象
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
String callbackParam = request.getParameter(callbackName);
if (StringUtils.isEmpty(callbackParam)) {
//如果没有callback参数,直接返回数据
super.writeInternal(object, outputMessage);
}else {
JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
try {
String result = callbackParam+"("+super.getObjectMapper().writeValueAsString(object)+");";
IOUtils.write(result, outputMessage.getBody(), encoding.getJavaName());
} catch (JsonProcessingException e) {
throw new HttpMessageNotWritableException("Could not write JSON:"+e.getMessage(), e);
}
}
}
public String getCallbackName() {
return callbackName;
}
public void setCallbackName(String callbackName) {
this.callbackName = callbackName;
}
}
配置消息转换器
spring-mvc.xml中
<mvc:annotation-driven>
<mvc:message-converters>
<!-- 设置直接响应纯文本时的编码格式 -->
<!-- <bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg index="0" value="utf-8"></constructor-arg>
</bean> -->
<!-- 统一支持jsonp,返回jsonp,没有中文乱码,放在bean-StringHttpMessageConverter后无效 -->
<bean class="com.nongmall.manage.json.CallbackMappingJackson2HttpMessageConverter">
<property name="callbackName" value="callback"></property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
项目B的controller方法中不用做判断返回jsonp,也能适时返回jsonp
package com.nongmall.manage.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("test")
public class TestController {
@RequestMapping("jsonp")
@ResponseBody
public String show() {
//获取数据
String name = "hello 世界";
//响应数据
return name;
}
}
项目A.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script src="js/jquery-3.2.1.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<h1></h1>
</body>
<script type="text/javascript">
$.ajax({
type:'get',
url:'http://nongmall.com/rest/test/jsonp',//ajax会在url后自动接上callback参数
dataType:'jsonp',//预期的服务器响应的数据类型为jsonp
success:function(data){
//处理数据
$('h1').text(data);
}
});
</script>
</html>