Статьи

Веб-сервисы RESTful с RESTeasy JAX-RS на Tomcat 7 — проект Eclipse и Maven

Подход RESTful к разработке веб-сервисов постоянно привлекает все больше и больше внимания и, кажется, подталкивает SOAP к устареванию. Я не буду обсуждать, какой подход лучше, но я полагаю, что мы все согласны с тем, что REST намного легче. В этом руководстве я собираюсь показать вам, как разрабатывать RESTful-сервисы с помощью RESTeasy и как их развертывать на сервере Tomcat. На этом пути также создается проект Maven на основе Eclipse.

Недавно я хотел протестировать REST-клиент, который планировал использовать в создаваемом приложении, поэтому мне нужен был быстрый способ настройки инфраструктуры RESTful. Джастин написал классное руководство о том, как использовать Spring для предоставления сервисов RESTful . Однако я хотел чего-то быстрее и не связываться с Spring ни разу. По этой причине я решил пойти с JBoss RESTeasy . С официального сайта:

RESTEasy — это проект JBoss, который предоставляет различные среды, помогающие создавать веб-службы RESTful и приложения Java RESTful. Это полностью сертифицированная и портативная реализация спецификации JAX-RS . JAX-RS — это новая спецификация JCP, которая предоставляет Java API для веб-служб RESTful по протоколу HTTP.
RESTEasy может работать в любом контейнере сервлетов, но также доступна более тесная интеграция с сервером приложений JBoss, чтобы сделать работу пользователей в этой среде более приятной.

Последнюю версию RESTeasy можно найти здесь и соответствующую документацию здесь . На данный момент последней версией является 2.1.0.GA. Вам также, вероятно, понадобится RESTeasy JavaDoc и JAX-RS JavaDoc .

Поскольку использование JBoss AS отменило бы всю «легковесную» концепцию, я решил пойти с нашим старым другом Tomcat. Я скачал последнюю версию (7.0.5 бета) контейнера любимого сервлета отсюда. Обратите внимание, что в настоящее время он находится в бета-фазе, но Tomcat оказался очень надежным, и я думаю, никаких проблем не должно возникнуть.

Начнем с создания проекта Maven на основе Eclipse под названием «RESTeasyProject». Используемый архетип «webapp-jee5», как показано на следующем рисунке:

Для параметров мы используем «com.javacodegeeks» в качестве идентификатора группы и «resteasy» в качестве идентификатора артефакта.

Следующим шагом является добавление зависимостей RESTeasy в наш файл pom.xml. URL хранилища: http://repository.jboss.org/maven2/, но, к сожалению, последняя версия, представленная в этом хранилище, — 2.0-beta-2. В любом случае, строки, которые нам нужно добавить в файл maven:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<repositories>
 <repository>
       <id>org.jboss.resteasy</id>
 </repository>
</repositories>
<dependencies>
<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>resteasy-jaxrs</artifactId>
 <version>2.0-beta-2</version>
</dependency>
<dependency>
 <groupId>org.jboss.resteasy</groupId>
 <artifactId>resteasy-jaxb-provider</artifactId>
 <version>2.0-beta-2</version>
</dependency>
<dependency>
      <groupId>org.jboss.resteasy</groupId>
      <artifactId>resteasy-jettison-provider</artifactId>
      <version>2.0-beta-2</version>
</dependency>
</dependencies>

Артефакт resteasy-jaxrs относится к базовому классу RESTeasy для реализации JAX-RS. Кроме того, мы используем как resteasy-jaxb-provider, так и resteasy-jettison-provider, поскольку мы хотим поддерживать форматы ответов XML и JSON. Архитектура JAXB используется для сериализации XML, а среда Jettison — для написания JSON.

Вот полный pom.xml:

01
02
03
04
05
06
07
08
09
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.javacodegeeks</groupId>
  <artifactId>resteasy</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
 
  <name>resteasy JEE5 Webapp</name>
   
  <repositories>
    <repository>
      <id>org.jboss.resteasy</id>
    </repository>
    </repositories>
 
  <dependencies>
 
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>
 
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
 
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
     
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>2.0-beta-2</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxb-provider</artifactId>
        <version>2.0-beta-2</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jettison-provider</artifactId>
        <version>2.0-beta-2</version>
    </dependency>
 
  </dependencies>
 
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>
    <finalName>resteasy</finalName>
  </build>
</project>

Давайте сначала посмотрим класс модели, который будет использоваться в нашем сервисе:

01
02
03
04
05
06
07
08
09
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 com.javacodegeeks.resteasy.model;
 
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement(name = "employee")
public class Employee {
     
    private String employeeId;
    private String employeeName;
    private String job;
     
    @XmlElement
    public String getEmployeeId() {
        return employeeId;
    }
     
    public void setEmployeeId(String employeeId) {
        this.employeeId = employeeId;
    }
     
    @XmlElement
    public String getEmployeeName() {
        return employeeName;
    }
     
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
     
    @XmlElement
    public String getJob() {
        return job;
    }
     
    public void setJob(String job) {
        this.job = job;
    }
     
}

Типичный класс модели с некоторыми полями и соответствующими методами получения / установки. Аннотации JAXB используются для указания, какие поля будут сериализованы и с какими элементами они будут отображаться. Более конкретно, аннотация XmlRootElement используется для указания элемента класса верхнего уровня. Аналогично, методы получения помечаются XmlElement для сопоставления соответствующего свойства JavaBean с элементом XML. По умолчанию используется имя свойства, но мы можем переопределить его, указав произвольное имя .

Давайте создадим наш первый класс с поддержкой RESTeasy, который называется «SampleService».

01
02
03
04
05
06
07
08
09
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package com.javacodegeeks.resteasy;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
 
import com.javacodegeeks.resteasy.model.Employee;
 
@Path("/sampleservice")
public class SampleService {
     
    private static Map<String, Employee> employees = new HashMap<String, Employee>();
     
    static {
         
        Employee employee1 = new Employee();
        employee1.setEmployeeId("1");
        employee1.setEmployeeName("Fabrizio");
        employee1.setJob("Software Engineer");
        employees.put(employee1.getEmployeeId(), employee1);
         
        Employee employee2 = new Employee();
        employee2.setEmployeeId("2");
        employee2.setEmployeeName("Justin");
        employee2.setJob("Business Analyst");
        employees.put(employee2.getEmployeeId(), employee2);
         
    }
 
    @GET
    @Path("/hello")
    @Produces("text/plain")
    public String hello(){
        return "Hello World";   
    }
     
    @GET
    @Path("/echo/{message}")
    @Produces("text/plain")
    public String echo(@PathParam("message")String message){
        return message;   
    }
     
    @GET
    @Path("/employees")
    @Produces("application/xml")
    public List<Employee> listEmployees(){
        return new ArrayList<Employee>(employees.values());
    }
     
    @GET
    @Path("/employee/{employeeid}")
    @Produces("application/xml")
    public Employee getEmployee(@PathParam("employeeid")String employeeId){
        return employees.get(employeeId);       
    }
     
    @GET
    @Path("/json/employees/")
    @Produces("application/json")
    public List<Employee> listEmployeesJSON(){
        return new ArrayList<Employee>(employees.values());
    }
 
    @GET
    @Path("/json/employee/{employeeid}")
    @Produces("application/json")
    public Employee getEmployeeJSON(@PathParam("employeeid")String employeeId){
        return employees.get(employeeId);       
    }
     
}

Как видите, наш сервис сильно аннотирован. Мы можем определить декларативно метод HTTP, на который отвечает каждый метод, например, GET или POST . Для URL, по которому обслуживаются ресурсы, мы используем PATH , как на уровне сервиса, так и на уровне метода. Если метод принимает параметр или попадает под определенный сегмент пути, это обозначается PathParam . Наконец, аннотация Consumes определяет типы мультимедиа, которые могут принимать методы ресурса, а Produces определяет типы, которые могут быть созданы.

Давайте рассмотрим еще несколько деталей. Мы храним некоторые фиктивные данные на статической карте, которая в реальном приложении будет заменена на DAO . Обратите внимание, что классы моделей будут сериализованы библиотекой как для представлений XML, так и для JSON. Давайте теперь посмотрим на открытые методы:

  • привет : метод, который просто печатает предопределенную строку с типом содержимого text / plain.
  • echo : этот метод возвращает любой предоставленный аргумент. Обратите внимание, что имя поля в скобках должно совпадать с именем параметра. Подобный тип контента с выше.
  • listEmployees : этот метод предоставляет XML-представление списка объектов модели. Формат указывается аннотацией Productions.
  • getEmployee : то же самое с предыдущим, но возвращает только один объект модели на основе аргумента ID.
  • listEmployeesJSON : аналогично XML-аналогу, но созданный формат — JSON.
  • getEmployeeJSON : то же самое с предыдущим, но возвращает только один объект модели на основе аргумента ID.

Затем мы должны соответствующим образом настроить файл web.xml наших веб-приложений, чтобы RESTeasy позаботился о входящих REST-запросах. В нашем проекте Maven это можно найти в каталоге «src / main / webapp / WEB-INF». Вот как выглядит наш файл декларации:

01
02
03
04
05
06
07
08
09
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
<?xml version="1.0" encoding="UTF-8"?>
 
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
     
    <display-name>resteasy</display-name>
 
    <listener>
        <listener-class>
            org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
        </listener-class>
    </listener>
 
    <servlet>
        <servlet-name>Resteasy</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>Resteasy</servlet-name>
        <url-pattern>/restful-services/*</url-pattern>
    </servlet-mapping>
     
    <context-param>
         <param-name>resteasy.scan</param-name>
        <param-value>true</param-value>   
    </context-param>
 
     
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/restful-services</param-value>
    </context-param>
     
</web-app>

Прослушиватель контекста ResteasyBootstrap необходимо развернуть, чтобы создать реестр для resteasy, а сервлет HttpServletDispatcher используется для правильной маршрутизации входящих запросов в соответствующие службы. Мы настроили конкретный сервлет с именем «Resteasy» для перехвата запросов по пути «/ restful-services / *». Нам нужно определить это для инфраструктуры RESTeasy с помощью параметра конфигурации resteasy.servlet.mapping.prefix. Обратите внимание, что значение не содержит ни косую черту, ни подстановочный знак. Наконец, мы используем переключатель resteasy.scan для автоматического сканирования файлов WEB-INF / lib jars и каталога WEB-INF / classes для различных аннотированных классов. Существует также ряд других переключателей конфигурации RESTeasy, которые вы можете использовать для точной настройки поведения вашего приложения.

Последний шаг — построить проект и развернуть его в контейнере сервлеров. Запустите конфигурацию Eclipse и выберите «Установка Maven». При условии, что все в порядке, будет создан веб-архив с именем «resteasy.war» в папке «target» вашего проекта. Разорванная папка также может быть найдена в том же каталоге. Скопируйте файл WAR в репозиторий приложений Tomcat, то есть в папку «apache-tomcat-7.0.5 \ webapps». Запустите сервер, если вы этого еще не сделали, и вы должны увидеть следующую строку в консоли:

Добавление отсканированного ресурса: com.javacodegeeks.resteasy.SampleService

Теперь, когда приложение развернуто, давайте проверим его. Обратите внимание, что, поскольку все методы обрабатывают запросы GET, тестирование можно выполнить, используя ваш любимый браузер и просто написав URL. Для ленивого разработчика вот они (в случаях XML и JSON я также добавляю публичную ссылку с ожидаемым результатом):

HTTP: // локальный: 8080 / Resteasy / успокоительная-услуга / sampleservice / привет

HTTP: // локальный: 8080 / Resteasy / успокоительные-услуги / sampleservice / эхо / сообщение

http: // localhost: 8080 / resteasy / restful-services / sampleservice / employee ( ссылка )

http: // localhost: 8080 / resteasy / restful-services / sampleservice / employee / 1 ( ссылка )

http: // localhost: 8080 / resteasy / restful-services / sampleservice / json / employee ( ссылка )

http: // localhost: 8080 / resteasy / restful-services / sampleservice / json / employee / 1 ( ссылка )

Обратите внимание, что полный путь состоит из контекста веб-приложения («resteasy»), контекста, который мы определили для обработки RESTeasy («restful-services»), пути службы («sampleservice») и, наконец, соответствующего пути метода.

Это было бы все. Как всегда, вы можете найти проект Eclipse здесь .

Статьи по Теме :