Spring MVC и Ajax или как я боролся с получением JSON ответа от сервера?

В данном уроке решил поделится проблемой, которая у меня возникла, и как я её решил, дело пойдет о том как в Spring MVC, а точней с контроллера отправить JSON ответ который Ajax примет и обработает.

Задача

Создать Spring MVC приложение, которое будет общаться с клиентской частью (в нашем случае это JSP) посредством JSON c использованием Ajax.

Проблема!

В процессе решение данной задачи возникла проблема, а именно когда я обращался по URL к контролеру, который отдает JSON я получал Error 406.

Теперь давайте посмотрим решение этой проблемы и почему она возникла.

Шаг 1

Создадим простой Spring MVC проект, это можно сделать в Intelij IDEA нажав File -> New Project -> Spring MVC.

Теперь открываем src\main\webapp\WEB-INF\web.xml и меняем мапинг на *.html:

<web-app version="2.4"
	xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

	<display-name>Spring MVC Application</display-name>

    <servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>*.html</url-pattern>
	</servlet-mapping>
</web-app>

Теперь наши контролеры будут в url как <name controller>.html

Шаг 2

Теперь давайте добавим зависимости в pom.xml:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.2.2</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.2.2</version>
</dependency>

Это Jackson библиотека, которая позволяет конвертировать с Java Object в JSON и обратно детальней тут Конвертация Java объектов в JSON

Шаг 3

Теперь заходим в контролер src\main\java\com\devcolibri\mvc\HelloController.java и у вас должно быть следующее содержимое:

package com.devcolibri.mvc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashSet;
import java.util.Set;

@Controller
public class HelloController {

    @RequestMapping(value = "/page", method = RequestMethod.GET)
    public String printWelcome(){
        return "hello";
    }

    @RequestMapping(value = "/ajaxtest", method = RequestMethod.GET)
    @ResponseBody
    public Set<String> ajaxTest() {
        Set<String> records = new HashSet<String>();
        records.add("Record #1");
        records.add("Record #2");

        return records;
    }

}

После этого если собрать и запустить, по URL http://localhost:8080/test/ajaxtest.html, то вы увидите проблему, с которой я боролся.

Шаг 4 (Решение)

Первое, что нужно сделать это добавить в mvc-dispatcher-servlet.xml конфигурацию, которая поддерживает @ResponseBody:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans ... >

    <context:component-scan base-package="com.devcolibri.mvc"/>

    <mvc:annotation-driven />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

И второе, это изменить мапинг в web.xml с *.html обратно на ‘/’

<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>Spring MVC Application</display-name>

<servlet>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

После этого пересобираем проект и деплоим его, после этого обращаемся по URL http://localhost:8080/test/ajaxtest и вы увидите:

["Record #1","Record #2"]

Теперь когда в web.xml мы перемапились на <url-pattern>/</url-pattern> мы не сможем видеть такие файл как css, js, png и другие.

Для того, что бы решить это перечислите нужные вам форматы в том же web.xml:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>

После этого эти форматы будут мапиться.

UPD: Или есть еще один способ мапить все ресурсы без явного указывания их, для этого в mvc-dispatcher-servlet.xml укажите следующий tag.

<mvc:resources mapping="/**" location="/" />

Шаг 5

Теперь сделаем обращение к этому контроллеру через Ajax.

Изменим содержимое файла src\main\webapp\WEB-INF\pages\hello.jsp на это:

<html>
<script src="http://code.jquery.com/jquery-1.10.2.min.js" type="text/javascript" ></script>
<script type="text/javascript">
    $(document).ready(function() {
        $("#test").click(function(){
            $.get("/test/ajaxtest",function(data,status){
                alert("Data: " + data + "\nStatus: " + status);
            });
        });
    });
</script>
<body>
    <button id="test">Load</button>
</body>
</html>

После деплоя заходим на URL http://localhost:8080/test/page и жмем на кнопку:

На этом все. Надеюсь я вам помог. Если будут вопросы пишите в комментариях.

Урок создан: 22 августа 2013 | Просмотров: 23976 | Автор: Александр Барчук | Правила перепечатки


Добавить комментарий

Добавить комментарий

Ваш e-mail не будет опубликован.

Комментарии:

  • 22 августа 2013 в 20:41

    Виталий

    Замечательная статья. Есть так же замечательная библиотека DWR.
    Конечно она всех проблем не решит, но все же… многое упростит. А по поводу css и js то их лучше вынести в отдельную папку проекта и в конфиге mvc-dispatcher-servlet.xml указать следующее, к примеру

    Спасибо за прекрасные статьи!

  • 26 ноября 2014 в 16:55

    Николай

    Скачал исходники, задеплоил на сервер, перешел на страницу /page, при нажатии на кнопку Load не происходит никаких действий, в чем может быть причина?

  • 21 апреля 2015 в 22:57

    Дима

    Спасибо огромное!

  • 29 апреля 2017 в 19:54

    Aleksei Mironov

    Не совсем понятно как здесь отрабатывает jackson. Мы же тупо возвращаем HashSet.