Spring Rest and Jsonp

I am trying to return my Spring controller to return jsonp , but I have no joy

The exact same code works fine if I want to return json, but I have a requirement to return jsonp I added to the converter, I found the source code for online to perform jsonp conversion

I am using Spring version 4.1.1.RELEASE and Java 7

Any help is appreciated

Here is the code in question

MVC-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> <property name="favorPathExtension" value="false" /> <property name="favorParameter" value="true" /> <property name="parameterName" value="mediaType" /> <property name="ignoreAcceptHeader" value="false"/> <property name="useJaf" value="false"/> <property name="defaultContentType" value="application/json" /> <property name="mediaTypes"> <map> <entry key="atom" value="application/atom+xml" /> <entry key="html" value="text/html" /> <entry key="jsonp" value="application/javascript" /> <entry key="json" value="application/json" /> <entry key="xml" value="application/xml"/> </map> </property> </bean> <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="contentNegotiationManager" ref="contentNegotiationManager" /> <property name="viewResolvers"> <list> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/templates/slim/${views.template.directory}/" /> <property name="suffix" value=".jsp" /> </bean> </list> </property> <property name="defaultViews"> <list> <bean class="com.webapp.handler.MappingJacksonJsonpView" /> </list> </property> </bean> </beans> 

com.webapp.handler.MappingJacksonJsonpView

 package com.webapp.handler; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.view.json.MappingJackson2JsonView; public class MappingJacksonJsonpView extends MappingJackson2JsonView { /** Local log variable. **/ private static final Logger LOG = LoggerFactory.getLogger(MappingJacksonJsonpView.class); /** * Default content type. Overridable as bean property. */ public static final String DEFAULT_CONTENT_TYPE = "application/javascript"; @Override public String getContentType() { return DEFAULT_CONTENT_TYPE; } /** * Prepares the view given the specified model, merging it with static * attributes and a RequestContext attribute, if necessary. * Delegates to renderMergedOutputModel for the actual rendering. * @see #renderMergedOutputModel */ @Override public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { LOG.info("Entered render Method :{}", request.getMethod()); if("GET".equals(request.getMethod().toUpperCase())) { LOG.info("Request Method is a GET call"); Map<String, String[]> params = request.getParameterMap(); if(params.containsKey("callback")) { String callbackParam = params.get("callback")[0]; LOG.info("callbackParam:{}", callbackParam); response.getOutputStream().write(new String(callbackParam + "(").getBytes()); super.render(model, request, response); response.getOutputStream().write(new String(");").getBytes()); response.setContentType(DEFAULT_CONTENT_TYPE); } else { LOG.info("Callback Param not contained in request"); super.render(model, request, response); } } else { LOG.info("Request Method is NOT a GET call"); super.render(model, request, response); } } } 

Controller method in question

  @RequestMapping(value = { "/sources"}, method = RequestMethod.GET, produces={MediaType.ALL_VALUE, "text/javascript", "application/javascript", "application/ecmascript", "application/x-ecmascript", "application/x-javascript", MediaType.APPLICATION_JSON_VALUE}) @ResponseBody public Object getSources(@PathVariable(value = API_KEY) String apiKey, @RequestParam(value = "searchTerm", required = true) String searchTerm, @RequestParam(value = "callBack", required = false) String callBack) { LOG.info("Entered getSources - searchTerm:{}, callBack:{} ", searchTerm, callBack); List<SearchVO> searchVOList = myServices.findSources(searchTerm); if (CollectionUtils.isEmpty(searchVOList)) { LOG.error("No results exist for the searchterm of {}", searchTerm); return searchVOList; } LOG.debug("{} result(s) exist for the searchterm of {}", searchVOList.size(), searchTerm); LOG.info("Exiting getSources"); return searchVOList; } 

** JQuery Ajax Code **

 $.ajax({ type: "GET", url: "http://localhost:8080/my-web/rest/sources, data: { "searchTerm": request.term }, //contentType: "application/json; charset=utf-8", //dataType: "json", contentType: "application/javascript", dataType: "jsonp", success: function(data) { alert("success"); }, error: function(XMLHttpRequest, textStatus, errorThrown) { alert("Failure"); } }); 

The following is a snippet of the stacktrace error that I get:

 org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:168) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:101) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:198) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71) ~[spring-web-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:122) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:620) [servlet-api.jar:na] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) [servlet-api.jar:na] 
+8
source share
1 answer

As stated in the spring.io blog regarding Spring 4.1 release:

JSONP is now supported by Jackson. For response body methods, declare @ControllerAdvice as shown below. For view-based rendering, simply configure the JSONP request parameter name MappingJackson2JsonView .

 @ControllerAdvice private static class JsonpAdvice extends AbstractJsonpResponseBodyAdvice { public JsonpAdvice() { super("callback"); } } 

[...] In 4.1, the @ControllerAdvice application can also implement ResponseBodyAdvice, in which case it will be called after the controller method returns, but before the response is recorded and therefore committed. It has a number of useful applications with @JsonView JSONP already running on two examples built on it.

Javadoc taken from MappingJackson2JsonView :

Specify the JSONP request parameter names. Each time a request has one of these parameters, the received JSON will be wrapped in a function named as specified by the value of the JSONP request parameter. The default parameter names are jsonp and callback.

You do not need to implement this material yourself. Just reuse the bits from the Spring Framework.

Spring Boot Example

The following simple Spring Boot application demonstrates the use of builds in JSONP support in Spring MVC 4.1. The example requires at least Spring Boot 1.2.0.RC1.

 import com.fasterxml.jackson.annotation.JsonAutoDetect; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.web.HttpMessageConverters; import org.springframework.context.annotation.Bean; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice; import java.util.Collections; import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RestController @SpringBootApplication class Application { @JsonAutoDetect(fieldVisibility = ANY) static class MyBean { String attr = "demo"; } @ControllerAdvice static class JsonpAdvice extends AbstractJsonpResponseBodyAdvice { public JsonpAdvice() { super("callback"); } } @Bean public HttpMessageConverters customConverters() { return new HttpMessageConverters(false, Collections.<HttpMessageConverter<?> >singleton(new MappingJackson2HttpMessageConverter())); } @RequestMapping MyBean demo() { return new MyBean(); } @RequestMapping(produces = APPLICATION_JSON_VALUE) String demo2() { return "demo2"; } public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 

URL http://localhost:8080/demo?callback=test converts POJO to JSONP response:

 test({"attr":"demo"}); 

URL http://localhost:8080/demo2?callback=test converts a String to a JSONP response:

 test("demo2"); 
+11
source

Source: https://habr.com/ru/post/978282/


All Articles