Это на самом деле довольно просто, используя Spring 3.0 и выше.Однако, глядя на приведенные выше примеры, я не понимаю, почему вы относитесь к пружинному контроллеру как к простому сервлету и печатаете напрямую в поток ответов.Этого следует избегать.Было бы намного лучше, если бы вы просто возвращали POJO, представляющий ваш массив JSON, и позволяли анализатору JSON создать ответ.
Первая задача - заставить Spring вернуть JSON.Это легко сделать, добавив @ResponseBody к вашему контроллеру, сказав контроллеру сериализовать POJO клиенту.Если в вашем пути к классам есть Джексон, он будет автоматически отправлен как JSON с помощью MappingJacksonHttpMessageConverter, который включен с помощью mvc: annotation-driven.
Но JSON недостаточно.Вы хотите JSON-P, предполагая, что клиент хочет использовать JSON в междоменном сценарии.Это может быть достигнуто несколькими различными способами.Вы можете реализовать фильтр сервлетов с помощью Springating DelegationFilterProxy.Фильтр может определить, запрашивается ли JSON-P, и вы можете соответствующим образом настроить ответ.
Так что для моего использования я предпочитаю расширять Spring 3.0 (+) MappingJacksonJsonView вместо фильтра и проверять, если параметр запросасодержал ключ «обратного вызова».Если я хочу JSON или JSONP, я могу просто добавить второе отображение сервлета в * .jsonp и отправить либо JSON, либо JSONP в зависимости от наличия параметра обратного вызова.
Вот код:
Поместите в свой контроллер следующее:
@RequestMapping(value="/ad", method=RequestMethod.GET)
public ModelMap getAvailabilityModel(@RequestParam(required = false) String callback) {
ModelMap modelMap = new ModelMap();
modelMap.addAttribute("html", "<strong>Hello World!</strong>");
return modelMap;
}
Возвращение ModelMap или даже ModelAndView позволяет мне делать разные вещи на основе сервлетаmapping.
Вот пользовательское представление для обработки расширения JSON-P (только для кишок, пропущено несколько переопределений для краткости):
public class MappingJacksonJsonpView extends MappingJacksonJsonView {
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if("GET".equals(request.getMethod().toUpperCase())) {
Map<String, String[]> params = request.getParameterMap();
if(params.containsKey("callback")) {
String callbackName = params.get("callback")[0];
response.getOutputStream().write(new String(callbackName + "(").getBytes());
log.info("GETTER Found for a .jsonp method, callback name is : " + callbackName);
super.render(model, request, response);
response.getOutputStream().write(new String(");").getBytes());
response.setContentType("application/javascript");
}
else {
super.render(model, request, response);
}
}
else {
super.render(model, request, response);
}
}
}
Если запрос сопоставлен с * .jsonpи я вижу параметр запроса с «обратным вызовом» в качестве ключа, я предполагаю, что JSON-P, и я обертываю JSON информацией обратного вызова прямо над потоком ответа.Я позволю процессору JSON Джексона обрабатывать особенности преобразования POJO в надлежащий JSON во всех случаях.В моем контроллере я просто возвращаю POJO или ModelMap;не возиться писать свой собственный JSON в ответе.В качестве альтернативы я мог бы использовать модель и представление для возвращаемого типа.Это позволит правильно обрабатывать запросы * .do vs * .json.Используйте Firebug, чтобы убедиться, что вы получаете правильный тип мультимедиа в заголовках ответов, application / json для JSON и application / javascript для JSON-P.
Вот вывод для JSON-P с GET наhttp://localhost:8080/jsonpex/ad.jsonp?callback=xyz (Обратите внимание на оболочку с xyz, для использования JQuery?)
xyz({"html":"<strong>Hello World!</strong>"});
Если вы не укажете параметр запроса, он просто вернет JSON: http://localhost:8080/jsonpex/ad.jsonp
{"html":"<strong>Hello World!</strong>"}
Наконец, убедитесь, что вы правильно подключили новый вид:
<!-- Add our new View to the Application Context -->
<beans:bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<beans:property name="order" value="1" />
<beans:property name="favorPathExtension" value="true"/>
<beans:property name="mediaTypes">
<beans:map>
<beans:entry key="json" value="application/json"/>
<beans:entry key="jsonp" value="application/javascript"/>
</beans:map>
</beans:property>
<beans:property name="defaultViews">
<beans:list>
<beans:bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView"/>
<beans:bean class="com.yourpackagename.spring.web.servlet.view.jsonp.MappingJacksonJsonpView"/>
</beans:list>
</beans:property>
</beans:bean>
Пара замечаний, я бы не стал отсылать обратно весь дополнительный HTML-код и максимально сократил бы его, оставив суть работы.должно быть сделано поверх возвращаемых данных.Я провел много исследований и попробовал много подходов;этот выше работал лучше всего для меня.В качестве альтернативы и дополнительного прочтения я предлагаю следующее, поскольку именно они привели меня к этому окончательному решению (я не могу вспомнить их всех, иначе я бы отдал должное):
http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
и для фильтрационного решения:
http://jpgmr.wordpress.com/2010/07/28/tutorial-implementing-a-servlet-filter-for-jsonp-callback-with-springs-delegatingfilterproxy/
Отключение