REST очень популярная технология в последнее время, которая позволяет обмениваться данными. В этом уроке я покажу как реализовать правильный на моё мнение REST в Spring MVC.
Шаг 0. Что такое Web Service?
Web Service (Веб служба) – это технология позволяющая предоставлять общий доступ к определённым данным системы.
Существует несколько видов Web Service (в дальнейшем WS), но мы будем рассматривать в этом уроке только один из них, а именно WS REST.
REST (Representational State Transfer), «передача состояния представления» — стиль построения архитектуры распределенного приложения. Был описан и популяризован в 2000 году Роем Филдингом (Roy Fielding), одним из создателей протокола HTTP. Самой известной системой, построенной в значительной степени по архитектуре REST, является современная Всемирная паутина.
Такое разъяснение WS REST дает Википедия, но если чесно, то мне слабо понятно что это из выше указанного термина.
Если своими словами, то REST – это технология, которая обеспечит возможность предоставление доступа к данным внешним системам, а также она описывает набор правил, которые нужно соблюдать, чтобы реализовать WS REST.
Если например брать WS SOAP, который является технологией у которой есть стандарты, то REST в свою очередь не имеет стандартов, а всеголишь имеет набор общепринятых правил для его реализации.
Задача
Любая работа программиста состоит с составления задачи, которую он должен решить. Наша задача следуящая:
– Реализовать WS REST и протестировать его в боевых условиях с помощью тестового приложения.
Шаг 1. Создание проекта и подключение зависимостей
Создаем Maven проект называем его SpringRESTExam:
Теперь давайте подключим зависимости, так как мы будем реализовывать REST с помощью Spring Framework, то нам потребуются следующие зависимости:
<properties> <javax.servlet>3.0.1</javax.servlet> <spring.version>3.2.6.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${javax.servlet}</version> <scope>provided</scope> </dependency> </dependencies>
Мы подключили две зависимости, первая это Spring MVC, вторая это поддержка Servlet API.
Еще для удобства я использую следующие два плагина:
<plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins>
Первый плагимы говорит о том, что проект будет компилироваться Java 7, а второй конфигурирует сборку war архива и говорит, что мы не требуемся в использовании web.xml файла.
Шаг 2. Создание сущности
Для того чтобы продемонстрировать REST в котором мы будем манипулировать данными мы создадим объект MyDataObject в который добавим все необходимые для наших целей поля.
package com.devcolibri.rest.domain; import java.util.Calendar; public class MyDataObject { private Calendar time; private String message; public MyDataObject(Calendar time, String message) { this.time = time; this.message = message; } public MyDataObject() { } public Calendar getTime() { return time; } public void setTime(Calendar time) { this.time = time; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
Я предпочел хранить в этом объекте время и сообщение.
И так что же нам надо сделать?
Мы создадим веб-страницу на которой будет 4 кнопки, которые будут демонстрировать 4 метода протокола HTTP.
Шаг 3. Конфигурирование Spring
Прежде чем преступить к созданию REST нам нужно сконфигурировать Spring, это не сложно.
Для начало создадим класс WebAppConfig:
package com.devcolibri.rest.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.view.JstlView; import org.springframework.web.servlet.view.UrlBasedViewResolver; // Говорим, что это конфигурация @Configuration // Включаем MVC @EnableWebMvc // Указываем где искать контроллеры и остальные компоненты @ComponentScan("com.devcolibri.rest") public class WebAppConfig { @Bean public UrlBasedViewResolver setupViewResolver() { UrlBasedViewResolver resolver = new UrlBasedViewResolver(); // указываем где будут лежать наши веб-страницы resolver.setPrefix("/pages/"); // формат View который мы будем использовать resolver.setSuffix(".jsp"); resolver.setViewClass(JstlView.class); return resolver; } }
Теперь нужно зарегистрировать эту конфигурацию в Spring Context, для этого создадим еще один класс Initializer:
package com.devcolibri.rest.config; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; public class Initializer implements WebApplicationInitializer { private static final String DISPATCHER_SERVLET_NAME = "dispatcher"; @Override public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); // регистрируем конфигурацию созданую высше ctx.register(WebAppConfig.class); // добавляем в контекст слушателя с нашей конфигурацией servletContext.addListener(new ContextLoaderListener(ctx)); ctx.setServletContext(servletContext); // настраиваем маппинг Dispatcher Servlet-а ServletRegistration.Dynamic servlet = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(ctx)); servlet.addMapping("/"); servlet.setLoadOnStartup(1); } }
Теперь можно приступать к созданию REST сервиса.
Шаг 4. Создание REST сервиса
Возможно вам уже приходилось работать с API, любым. Так вот мы сейчас с помощью REST создадим свой маленький API.
В виде REST сервиса будет выступать Spring Controller, поэтому создаем MainController:
package com.devcolibri.rest.controller; import com.devcolibri.rest.domain.MyDataObject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.Calendar; import java.util.GregorianCalendar; @Controller // мапим наш REST на /myservice @RequestMapping(value = "/myservice") public class MainController { // этот метод будет принимать время методом GET и на его основе // отвечать клиенту @RequestMapping(value= "/{time}", method = RequestMethod.GET) @ResponseBody public MyDataObject getMyData(@PathVariable long time) { return new MyDataObject(Calendar.getInstance(), "Это ответ метода GET!"); } // этот метод будет принимать Объект MyDataObject и отдавать его клиенту // обычно метод PUT используют для сохранения либо для обновления объекта @RequestMapping(method = RequestMethod.PUT) @ResponseBody public MyDataObject putMyData(@RequestBody MyDataObject md) { return md; } // этот метод будет методом POST отдавать объект MyDataObject @RequestMapping(method = RequestMethod.POST) @ResponseBody public MyDataObject postMyData() { return new MyDataObject(Calendar.getInstance(), "это ответ метода POST!"); } // этот метод будет принимать время методом DELETE // и на его основе можно удалит объект @RequestMapping(value= "/{time}", method = RequestMethod.DELETE) @ResponseBody public MyDataObject deleteMyData(@PathVariable long time) { return new MyDataObject(Calendar.getInstance(), "Это ответ метода DELETE!"); } }
Данные REST не выполняет действий с БД либо другими WS он просто имитирует работу REST.
Значит в результате у нас будет одна ссылка:
http://localhost:8080/myservice – обращаясь по этой ссылке разными HTTP методами можно выполнять разные действия.
Например:
http://localhost:8080/myservice/101245648 (GET) – числа, это время в милисекундах.
http://localhost:8080/myservice (PUT) – но HTTP запрос должен содержать объект (ниже будет пример).
http://localhost:8080/myservice (POST) – позволит получить готовый объект.
http://localhost:8080/myservice/101245648 (DELETE) – позволит удалить объект по времени например.
Как вы видите обращаясь по одной и той же ссылке мы выполняем разные действия.
Шаг 5. Создаем веб-страницу для проверки нашего WS REST
Для этого я решил в этом же проекте создать простую JSP страницу в папке /pages/ назвал её index.jsp и в ней с помощью JQuery и технологии Ajax выполняю запросы к нашему WS.
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Devcolibri.com exam REST</title> </head> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script type="text/javascript"> var prefix = '/devcolibri-rest/myservice'; var RestGet = function() { $.ajax({ type: 'GET', url: prefix + '/' + Date.now(), dataType: 'json', async: true, success: function(result) { alert('Время: ' + result.time + ', сообщение: ' + result.message); }, error: function(jqXHR, textStatus, errorThrown) { alert(jqXHR.status + ' ' + jqXHR.responseText); } }); } var RestPut = function() { var JSONObject= { 'time': Date.now(), 'message': 'Это пример вызова PUT метода' }; $.ajax({ type: 'PUT', url: prefix, contentType: 'application/json; charset=utf-8', data: JSON.stringify(JSONObject), dataType: 'json', async: true, success: function(result) { alert('Время: ' + result.time + ', сообщенеи: ' + result.message); }, error: function(jqXHR, textStatus, errorThrown) { alert(jqXHR.status + ' ' + jqXHR.responseText); } }); } var RestPost = function() { $.ajax({ type: 'POST', url: prefix, dataType: 'json', async: true, success: function(result) { alert('Время: ' + result.time + ', сообщение: ' + result.message); }, error: function(jqXHR, textStatus, errorThrown) { alert(jqXHR.status + ' ' + jqXHR.responseText); } }); } var RestDelete = function() { $.ajax({ type: 'DELETE', url: prefix + '/' + Date.now(), dataType: 'json', async: true, success: function(result) { alert('Время: ' + result.time + ', сообщение: ' + result.message); }, error: function(jqXHR, textStatus, errorThrown) { alert(jqXHR.status + ' ' + jqXHR.responseText); } }); } </script> <body> <h3>Это простой пример использования REST c помощью Ajax</h3> <button type="button" onclick="RestGet()">Метод GET</button> <button type="button" onclick="RestPost()">Метод POST</button> <button type="button" onclick="RestDelete()">Метод DELETE</button> <button type="button" onclick="RestPut()">Метод PUT</button> </body> </html>
Выглядеть эта страничка будет следующим образом:
Шаг 6. Деплоим и тестируем
Собираем проект:
Теперь запускам Tomcat либо в моём случае Glassfish4 и деплоим:
На этом все :) Возникнут вопросы, задавайте их в коментариях.
ПОХОЖИЕ ПУБЛИКАЦИИ
- None Found
21 комментариев к статье "REST на примере Spring MVC"
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.
Спасибо за статью.
Не могли бы Вы написать статью про работу с REST с использованием Spring Security. Всё таки сейчас без аутентификации и авторизации врят ли делают REST сервисы.
Вполне с вами согласен :) Но делают, например API какие-то. Да вот какраз работаю над этим уроком, как только его доделаю опубликую :)
А вы чтобы не пропустить публикацию урока, подпишитесь на форме сайта :)
Спасибо.
Еще интересна статья про Cross Origin Requests. Для REST это тоже важно.
Добрый день.
Подскажите, какой частью кода отдается сам файл index.jsp? На tomcat не смог запустить весь код
Буду очень благодарен
Попробовал пример c Jetty и Tomcat стартовая страница отображается. Но при нажатии на кнопку.
WARNING: No mapping found for HTTP request with URI [/devcolibri-rest/myservice/1414185917916] in DispatcherServlet with name ‘dispatcher’
Аналогично…
В WebAppConfig наверное не справили @ComponentScan(свой пакет)
Хорошее руководство, но в нем пропущена информация о создании контроллера IndexController. Без него не удавалось запустить проект, а когда посмотрел, как сделано в исходниках автора и внес соответствующие коррективы в свой проект, все заработало.
Не хватило:
jstl
jstl
1.2
где класс JstlView и что в нем должно быть?
При запуске проекта .
java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config
У всех у кого вылетает подобный exception включите в pom.xml еще одну зависимость
jstl
jstl
1.2
а где прописывается, что MyDataObject должен конвертироваться в json?
Автору 3- (т.к. есть недароботки, + код в некоторых местах не оптимален). Если на сервере не лежит библиотека jstl – то либо добавляем в папку lib, либо в Мавене добавляем зависимость. Также пропущен стартовый контроллер(“/”) – правда, он есть в прилагаемом коде, но на данной станице его нет. Также необходимо добавить. + Необходимо вынести javascript в отдельный файл. И т.д. и т.п.
Очень познавательно! Спасибо автору
А можно ли использовать в качестве отображаемых страниц html? И как?
есть шаблонизатор Thymeleaf http://www.thymeleaf.org/index.html
Заработало с первого раза. Исходный код лучше брать из архива. В статье код неполный.
Это же не РЕСТ нихрена! Обыкновенный Спринг контроллер!
А откуда такие выводы? “Обыкновенный Спринг контроллер” возвращает обьект типа ModelAndView. Здесь же мы возвращаем обьект MyDataObject. Возможно не наилучшим образом реализовано, но это самый простой учебный пример…
Зачем использовать для REST сервиса обычный @Controller, когда есть @RestController который будет возвращать все в json ?