javascript
Spring MVC 4.1 支持jsonp
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
使用ResponseBodyAdvice支持jsonp
ResponseBodyAdvice是一個接口,接口描述,
package?org.springframework.web.servlet.mvc.method.annotation;/***?Allows?customizing?the?response?after?the?execution?of?an?{@code?@ResponseBody}*?or?an?{@code?ResponseEntity}?controller?method?but?before?the?body?is?written*?with?an?{@code?HttpMessageConverter}.**?<p>Implementations?may?be?may?be?registered?directly?with*?{@code?RequestMappingHandlerAdapter}?and?{@code?ExceptionHandlerExceptionResolver}*?or?more?likely?annotated?with?{@code?@ControllerAdvice}?in?which?case?they*?will?be?auto-detected?by?both.**?@author?Rossen?Stoyanchev*?@since?4.1*/ public?interface?ResponseBodyAdvice<T>?{/***?Whether?this?component?supports?the?given?controller?method?return?type*?and?the?selected?{@code?HttpMessageConverter}?type.*?@param?returnType?the?return?type*?@param?converterType?the?selected?converter?type*?@return?{@code?true}?if?{@link?#beforeBodyWrite}?should?be?invoked,?{@code?false}?otherwise*/boolean?supports(MethodParameter?returnType,?Class<??extends?HttpMessageConverter<?>>?converterType);/***?Invoked?after?an?{@code?HttpMessageConverter}?is?selected?and?just?before*?its?write?method?is?invoked.*?@param?body?the?body?to?be?written*?@param?returnType?the?return?type?of?the?controller?method*?@param?selectedContentType?the?content?type?selected?through?content?negotiation*?@param?selectedConverterType?the?converter?type?selected?to?write?to?the?response*?@param?request?the?current?request*?@param?response?the?current?response*?@return?the?body?that?was?passed?in?or?a?modified,?possibly?new?instance*/T?beforeBodyWrite(T?body,?MethodParameter?returnType,?MediaType?selectedContentType,Class<??extends?HttpMessageConverter<?>>?selectedConverterType,ServerHttpRequest?request,?ServerHttpResponse?response);}作用:
Allows customizing the response after the execution of an {@code @ResponseBody} or an {@code ResponseEntity} controller method but before the body is written
with an {@code HttpMessageConverter}.
其中一個方法就是?beforeBodyWrite 在使用相應(yīng)的HttpMessageConvert 進(jìn)行write之前會被調(diào)用,就是一個切面方法。
和jsonp有關(guān)的實(shí)現(xiàn)類是AbstractJsonpResponseBodyAdvice,如下是?beforeBodyWrite 方法的實(shí)現(xiàn),
@Override public?final?Object?beforeBodyWrite(Object?body,?MethodParameter?returnType,MediaType?contentType,?Class<??extends?HttpMessageConverter<?>>?converterType,ServerHttpRequest?request,?ServerHttpResponse?response)?{MappingJacksonValue?container?=?getOrCreateContainer(body);beforeBodyWriteInternal(container,?contentType,?returnType,?request,?response);return?container; }位于AbstractJsonpResponseBodyAdvice的父類中,而beforeBodyWriteInternal是在AbstractJsonpResponseBodyAdvice中實(shí)現(xiàn)的?,如下,
@Override protected?void?beforeBodyWriteInternal(MappingJacksonValue?bodyContainer,?MediaType?contentType,MethodParameter?returnType,?ServerHttpRequest?request,?ServerHttpResponse?response)?{HttpServletRequest?servletRequest?=?((ServletServerHttpRequest)?request).getServletRequest();for?(String?name?:?this.jsonpQueryParamNames)?{String?value?=?servletRequest.getParameter(name);if?(value?!=?null)?{MediaType?contentTypeToUse?=?getContentType(contentType,?request,?response);response.getHeaders().setContentType(contentTypeToUse);bodyContainer.setJsonpFunction(value);return;}} }就是根據(jù)callback 請求參數(shù)或配置的其他參數(shù)來確定返回jsonp協(xié)議的數(shù)據(jù)。
如何實(shí)現(xiàn)jsonp?
首先繼承AbstractJsonpResponseBodyAdvice ,如下,
package?com.usoft.web.controller.jsonp;import?org.springframework.web.bind.annotation.ControllerAdvice; import?org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;/***?*/ @ControllerAdvice(basePackages?=?"com.usoft.web.controller.jsonp") public?class?JsonpAdvice?extends?AbstractJsonpResponseBodyAdvice?{public?JsonpAdvice()?{super("callback",?"jsonp");} }?super("callback", "jsonp");的意思就是當(dāng)請求參數(shù)中包含callback 或 jsonp參數(shù)時,就會返回jsonp協(xié)議的數(shù)據(jù)。其value就作為回調(diào)函數(shù)的名稱。
這里必須使用@ControllerAdvice注解標(biāo)注該類,并且配置對哪些Controller起作用。關(guān)于注解@ControllerAdvice?的作用這里不做描述。
Controller實(shí)現(xiàn)jsonp,
package?com.usoft.web.controller.jsonp;import?org.springframework.stereotype.Controller; import?org.springframework.web.bind.annotation.RequestMapping; import?org.springframework.web.bind.annotation.ResponseBody;import?com.usoft.web.controller.JsonMapper; import?com.usoft.web.controller.Person;/***?jsonp*/ @Controller public?class?JsonpController?{/***?callback({"id":1,"age":12,"name":"lyx"})*?*?@param?args*/public?static?void?main(String?args[])?{Person?person?=?new?Person(1,?"lyx",?12);System.out.println(JsonMapper.nonNullMapper().toJsonP("callback",person));}@RequestMapping("/jsonp1")public?Person?jsonp1()?{return?new?Person(1,?"lyx",?12);}@RequestMapping("/jsonp2")@ResponseBodypublic?Person?jsonp2()?{return?new?Person(1,?"lyx",?12);}@RequestMapping("/jsonp3")@ResponseBodypublic?String?jsonp3()?{return?JsonMapper.nonNullMapper().toJsonP("callback",new?Person(1,?"lyx",?12));} }jsonp2 方法就是 一個jsonp協(xié)議的調(diào)用。http://localhost:8081/jsonp2?callback=test可以直接調(diào)用這個方法,并且返回jsonp協(xié)議的數(shù)據(jù)。
通過debug代碼,我們來看一下他是怎么返回jsonp協(xié)議的數(shù)據(jù)的。
正因?yàn)槲覀兦懊嬖?該Controller 上配置了?JsonpAdvice 的?ControllerAdvice,在調(diào)用?MappingJackson2HttpMessageConverter的write()方法往回寫數(shù)據(jù)的時候,首先會調(diào)用
beforeBodyWrite,具體的代碼如下,
@Override protected?void?beforeBodyWriteInternal(MappingJacksonValue?bodyContainer,?MediaType?contentType,MethodParameter?returnType,?ServerHttpRequest?request,?ServerHttpResponse?response)?{HttpServletRequest?servletRequest?=?((ServletServerHttpRequest)?request).getServletRequest();for?(String?name?:?this.jsonpQueryParamNames)?{String?value?=?servletRequest.getParameter(name);if?(value?!=?null)?{MediaType?contentTypeToUse?=?getContentType(contentType,?request,?response);response.getHeaders().setContentType(contentTypeToUse);bodyContainer.setJsonpFunction(value);return;}} }當(dāng)請求參數(shù)中含有配置的相應(yīng)的回調(diào)參數(shù)時,就會bodyContainer.setJsonpFunction(value);這就標(biāo)志著 返回的數(shù)據(jù)時jsonp格式的數(shù)據(jù)。
然后接下來就到了?MappingJackson2HttpMessageConverter 的write()方法真正寫數(shù)據(jù)的時候了。看他是怎么寫數(shù)據(jù)的,相關(guān)的代碼如下,
@Override protected?void?writeInternal(Object?object,?HttpOutputMessage?outputMessage)throws?IOException,?HttpMessageNotWritableException?{JsonEncoding?encoding?=?getJsonEncoding(outputMessage.getHeaders().getContentType());JsonGenerator?generator?=?this.objectMapper.getFactory().createGenerator(outputMessage.getBody(),?encoding);try?{writePrefix(generator,?object);Class<?>?serializationView?=?null;Object?value?=?object;if?(value?instanceof?MappingJacksonValue)?{MappingJacksonValue?container?=?(MappingJacksonValue)?object;value?=?container.getValue();serializationView?=?container.getSerializationView();}if?(serializationView?!=?null)?{this.objectMapper.writerWithView(serializationView).writeValue(generator,?value);}else?{this.objectMapper.writeValue(generator,?value);}writeSuffix(generator,?object);generator.flush();}catch?(JsonProcessingException?ex)?{throw?new?HttpMessageNotWritableException("Could?not?write?content:?"?+?ex.getMessage(),?ex);} } @Override protected?void?writePrefix(JsonGenerator?generator,?Object?object)?throws?IOException?{if?(this.jsonPrefix?!=?null)?{generator.writeRaw(this.jsonPrefix);}String?jsonpFunction?=(object?instanceof?MappingJacksonValue???((MappingJacksonValue)?object).getJsonpFunction()?:?null);if?(jsonpFunction?!=?null)?{generator.writeRaw(jsonpFunction?+?"(");} } @Override protected?void?writeSuffix(JsonGenerator?generator,?Object?object)?throws?IOException?{String?jsonpFunction?=(object?instanceof?MappingJacksonValue???((MappingJacksonValue)?object).getJsonpFunction()?:?null);if?(jsonpFunction?!=?null)?{generator.writeRaw(");");} }代碼非常清晰。看我們jsonp調(diào)用的結(jié)果。
http://localhost:8081/jsonp2?callback=test響應(yīng)消息如下,
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/javascript
Transfer-Encoding: chunked
Date: Sun, 19 Jul 2015 13:01:02 GMT
?
test({"id":1,"age":12,"name":"lyx"});
轉(zhuǎn)載于:https://my.oschina.net/thinwonton/blog/1457254
總結(jié)
以上是生活随笔為你收集整理的Spring MVC 4.1 支持jsonp的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: DocumentManager 在标签位
 - 下一篇: WEB服务器、应用程序服务器、HTTP服