javascript
Spring MVC 4.1 支持jsonp
2019獨角獸企業重金招聘Python工程師標準>>>
使用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 在使用相應的HttpMessageConvert 進行write之前會被調用,就是一個切面方法。
和jsonp有關的實現類是AbstractJsonpResponseBodyAdvice,如下是?beforeBodyWrite 方法的實現,
@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中實現的?,如下,
@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;}} }就是根據callback 請求參數或配置的其他參數來確定返回jsonp協議的數據。
如何實現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");的意思就是當請求參數中包含callback 或 jsonp參數時,就會返回jsonp協議的數據。其value就作為回調函數的名稱。
這里必須使用@ControllerAdvice注解標注該類,并且配置對哪些Controller起作用。關于注解@ControllerAdvice?的作用這里不做描述。
Controller實現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協議的調用。http://localhost:8081/jsonp2?callback=test可以直接調用這個方法,并且返回jsonp協議的數據。
通過debug代碼,我們來看一下他是怎么返回jsonp協議的數據的。
正因為我們前面在 該Controller 上配置了?JsonpAdvice 的?ControllerAdvice,在調用?MappingJackson2HttpMessageConverter的write()方法往回寫數據的時候,首先會調用
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;}} }當請求參數中含有配置的相應的回調參數時,就會bodyContainer.setJsonpFunction(value);這就標志著 返回的數據時jsonp格式的數據。
然后接下來就到了?MappingJackson2HttpMessageConverter 的write()方法真正寫數據的時候了。看他是怎么寫數據的,相關的代碼如下,
@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調用的結果。
http://localhost:8081/jsonp2?callback=test響應消息如下,
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"});
轉載于:https://my.oschina.net/thinwonton/blog/1457254
總結
以上是生活随笔為你收集整理的Spring MVC 4.1 支持jsonp的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DocumentManager 在标签位
- 下一篇: WEB服务器、应用程序服务器、HTTP服