Spring MVC 4.1 使用ResponseBodyAdvice支持jsonp
使用ResponseBodyAdvice支持jsonp
ResponseBodyAdvice是一个接口,接口描述,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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 方法的实现,
1
2
3
4
5
6
7
8
9
|
@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中实现的 ,如下,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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 ,如下,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
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" )
@ResponseBody
public Person jsonp2() {
return new Person( 1 , "lyx" , 12 );
}
@RequestMapping ( "/jsonp3" )
@ResponseBody
public 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,具体的代码如下,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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()方法真正写数据的时候了。看他是怎么写数据的,相关的代码如下,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@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);
}
} |
1
2
3
4
5
6
7
8
9
10
11
|
@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 + "(" );
}
} |
1
2
3
4
5
6
7
8
|
@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调用的结果。
1
|
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"});
=================END=================
http://my.oschina.net/xinxingegeya/blog/480510?fromerr=yYIwo0JR
相关推荐
**在 Spring Web MVC 环境下使用 Dojo** Dojo 是一个强大的 JavaScript 库,提供了丰富的 UI 组件、数据管理、异步通信等功能,广泛应用于构建富客户端应用。Spring Web MVC 是 Java 开发Web应用的主流框架,以其...
Jsonp(JSON with Padding)是资料格式 json 的一种“使用模式”,可以让网页从别的网域获取资料。 本资料 是 spring MVC系统中用jsonp进行跨域解析。可实现前后台交互。
在这个场景中,"兼容IE6的spring mvc框架"意味着我们需要确保在使用Spring MVC 3.2版本开发的Web应用能够在IE6上正常运行。 **Spring MVC 3.2的关键特性:** 1. **模型-视图-控制器架构**:Spring MVC遵循MVC设计...
Spring框架从4.1版本开始,增加了对JSONP的支持。在上述示例中,我们可以看到如何在Spring MVC中实现一个JSONP调用。首先,控制器中的@RequestMapping方法接收一个名为`callback`的参数,这通常是客户端提供的回调...
ASP.NET MVC3 实现 JSONP 是为了...总结来说,ASP.NET MVC3 中实现 JSONP 主要包括创建 `JsonpResult` 类来处理 JSONP 响应,并提供控制器扩展方法简化使用。这样,你就可以在你的应用程序中方便地支持跨域数据请求了。
1. **配置bboss mvc**:首先,你需要在bboss mvc的配置中开启对JSONP的支持,这通常涉及到对控制器或拦截器的设置,使得服务器能够识别并处理JSONP请求。 2. **创建回调函数**:在客户端,你需要定义一个JavaScript...
在这个项目中,我们看到Spring MVC被用来创建一个后端服务,该服务可以通过JSON数据格式与前端进行通信,同时也支持JSONP(JSON with Padding),这是一种跨域数据交互协议。 首先,让我们深入了解一下Spring MVC。...
在本教程中,我们将深入探讨如何在Spring Boot项目中整合JSONP,以便实现跨域请求。JSONP(JSON with Padding)是一种广泛用于解决浏览器同源策略限制的技术,它允许JavaScript从不同源获取数据,这对于前后端分离的...
因此,在使用JSONP时,服务器端应该对请求进行严格的验证,以防止恶意请求。 - 由于JSONP的本质是执行来自外部源的JavaScript代码,因此在生产环境中使用时应格外小心。 #### 结论 通过上述步骤,我们可以有效地...
在Spring MVC中,要处理JSONP请求非常简单。我们只需要在控制器(Controller)方法上使用`@ResponseBody`注解,并返回字符串。然后,在Spring的配置文件中,需要配置`MappingJackson2JsonView`,使其支持JSONP。 ...
对于移动端应用,虽然它们也可以使用JSONP,但现代浏览器普遍支持CORS(跨源资源共享),因此通常推荐使用JSON格式配合CORS进行前后端数据交换,以获得更好的安全性和灵活性。只需要服务端在响应头中设置相应的CORS...
3. 对 Spring MVC 的改进,如支持 JSONP(JSON with Padding)响应,增强了 RESTful API 的开发。 4. 提供了对 Java 8 的初步支持,包括日期和时间API的适配。 5. Spring Security 3.2.6.RELEASE 版本包含安全相关...
### JSONP 使用步骤 1. **定义回调函数**:在客户端,首先我们需要定义一个函数,这个函数将处理返回的JSON数据。例如,我们可以定义一个名为`handleData`的函数: ```javascript function handleData(data) { ...
1. 确保已引入必要的依赖包,如`spring-boot-starter-jersey`和`spring-boot-starter-web`,它们分别用于支持Jersey和Spring MVC。 2. 创建一个继承自`AbstractJsonpResponseBodyAdvice`的类,并使用`@...
为了解决这个问题,开发者们发明了各种跨域解决方案,其中JSONP(JSON with Padding)是一种广泛使用的非官方标准。本文将深入探讨JSONP的工作原理以及如何在实际项目中应用。 ### JSONP简介 JSONP全称是"JSON ...
- **Ajax请求**:GXT的AsyncProxy或JsonPProxy与Spring MVC的@ResponseBody结合,实现异步数据交互。 - **Model Binder**:Spring MVC的ModelBinder可以将请求参数绑定到Java对象,方便处理POST请求。 - **...