Руководство Java RESTful Web Services для начинающих

1- Введение

Статья основана на:
  • Eclipse 4.6 (NEON).

  • Jersey

Если вы начинающий с  RESTful Web Service, вам нужно выделить 10 минут чтобы узнать что такое RESTful Web service перед тем как начать с приложением Java RESTful serivce.

Можете посмотреть "Что такое RESTful web service" здесь:

2- Что такое Jersey?

Jersey это платформа Java с открытым исходным кодом, который помогает вам разрабатывать приложение RESTful Web service и другие связанные приложения Client. Jersey выполняет спесификации  JSR 311.
Jersey предоставляет библиотеку для выполнения  Resful web service в контейнере servlet (Servlet Container).

На стороне сервера Jersey предоставляет servlet, он используется для сканирования предопределенных классов для различия ресурсов  RESTful. В web.xml нужно зарегистрировать этот servlet с вашим приложением.

Jersey так же предоставляет библиотеки client для связи с RESTful web service.
Ниже является структура ссылок ресурсов предложенных Jersey.
В котором  com.sun.jersey.spi.container.servlet.ServletContainer, это servlet предоставленный  JERSEY, и должен быть объявлен в  web.xml.

3- Создать приложение Maven

В Eclipse выберите:
  • File/New/Other..
Введите:
  • Group Id: org.o7planning
  • Artifact Id: HelloRESTful

4- Объявить maven & web.xml

Вам нужно объявить библиотеки JERSEY, и Servlet в pom.xml:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/maven-v4_0_0.xsd">
   
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.o7planning</groupId>
    <artifactId>HelloRESTful</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>HelloRESTful Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>


        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/asm/asm -->
        <dependency>
            <groupId>asm</groupId>
            <artifactId>asm</artifactId>
            <version>3.3.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-bundle -->
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-bundle</artifactId>
            <version>1.19.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.json/json -->
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20160810</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-server -->
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.19.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.sun.jersey/jersey-core -->
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-core</artifactId>
            <version>1.19.2</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>HelloRESTful</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <path>/HelloRESTful</path>
                    <port>8080</port>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>
Объявление RESTful Servlet - com.sun.jersey.spi.container.servlet.ServletContainer - Servlet предоставленный  Jersey REST API.

Вам нужно объявить пакет, содержащий ваши классы RESTful с этим servlet через параметр  com.sun.jersey.config.property.packages.

(Заметьте, использование servlet >= 3.0)
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <display-name>Hello RESTful Service</display-name>

    <servlet>
        <servlet-name>jerseyServlet</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>org.o7planning.hellorestful</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>  
    </servlet>
    <servlet-mapping>
        <servlet-name>jerseyServlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>


</web-app>

5- RESTful Service class

В следующем шаге, создайте ваши классы RESTful service. Например следующий класс  WeatherRESTfulService является веб сервисом обеспечивающим информацию прогноза погоды.
WeatherRESTfulService.java
package org.o7planning.hellorestful;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

@Path("/weather")
public class WeatherRESTfulService {

   private static final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

   //
   // http://localhost:8080/contextPath/rest/weather/{location}/{date}
   // Example:
   // http://localhost:8080/contextPath/rest/weather/chicago/2016-09-27
   // http://localhost:8080/contextPath/rest/weather/hanoi/2016-09-27
   //
   @Path("{location}/{date}")
   @GET
   @Produces("application/xml")
   public String getWeather_XML(@PathParam("location") String location,//
            @PathParam("date") String dateStr) {
       Date date = null;
       if (dateStr == null || dateStr.length() == 0) {
           date = new Date();
       } else {
           try {
               date = df.parse(dateStr);
           } catch (ParseException e) {
               date = new Date();
           }
       }
       dateStr = df.format(date);

       String[] weathers = new String[] { "Hot", "Rain", "Cold" };
       int i = new Random().nextInt(3);
       String weather = weathers[i];

       return "<weather>"//
               + "<date>" + dateStr + "</date>"//
               + "<location>" + location + "</location>"//
               + "<info>" + weather + "</info>"//
               + "</weather>";
   }

   //
   // http://localhost:8080/contextPath/rest/weather/{location}
   // Example:
   // http://localhost:8080/contextPath/rest/weather/chicago
   // http://localhost:8080/contextPath/rest/weather/hanoi
   //
   @Path("{location}")
   @GET
   @Produces("application/xml")
   public String getWeather_XML(@PathParam("location") String location) {
       return getWeather_XML(location, null);
   }

   //
   // http://localhost:8080/contextPath/rest/weather/{location}/{date}
   // Example:
   // http://localhost:8080/contextPath/rest/weather/chicago/2016-09-27
   // http://localhost:8080/contextPath/rest/weather/hanoi/2016-09-27
   //
   @Path("{location}/{date}")
   @GET
   @Produces("application/json")
   public String getWeather_JSON(@PathParam("location") String location,//
           @PathParam("date") String dateStr) {
     
       Date date = null;
       if (dateStr == null || dateStr.length() == 0) {
           date = new Date();
       } else {
           try {
               date = df.parse(dateStr);
           } catch (ParseException e) {
               date = new Date();
           }
       }
       dateStr = df.format(date);

       String[] weathers = new String[] { "Hot", "Rain", "Cold" };
       int i = new Random().nextInt(3);
       String weather = weathers[i];

       return "{" //
               + "'date': '" + dateStr + "'," //
               + "'location': '" + location + "'," //
               + "'info': '" + weather + "'" //
               + "}";
   }

   //
   // http://localhost:8080/contextPath/rest/weather/{location}
   // Example:
   // http://localhost:8080/contextPath/rest/weather/chicago
   // http://localhost:8080/contextPath/rest/weather/hanoi
   //
   @Path("{location}")
   @GET
   @Produces("application/json")
   public String getWeather_JSON(@PathParam("location") String location) {
       return getWeather_JSON(location, null);
   }

}

6- Запуск приложения

Конфигурация для запуска приложения:

7- Объяснить RESTful

Скопируем URL ниже и запустим на браузере:
Когда вы запустите URL выше, она эквивалентна тому, что вы отправите запрос на сервер:
GET /HelloRESTful/rest/weather/chicago/2016-08-27 HTTP/1.1
Host: localhost:8080
В случае если Request не определяет вид данных для возврата (MINE type), возвращенные данные будут по умолчанию зависеть от используемого веб сервиса.
Отправленные запросы могут ясно определить возвращенные данные.
GET /HelloRESTful/rest/weather/chicago/2016-08-27 HTTP/1.1
Host: localhost:8080
Accept: application/xml
Или:
GET /HelloRESTful/rest/weather/chicago/2016-08-27 HTTP/1.1
Host: localhost:8080
Accept: application/json
В примере выше, если запрос определяет вид возврата как  application/json вы получите результат, как в изображении ниже:
Чтобы определить вид возврата вам нужно написать приложения Client чтобы создать кастомизированные запросы и отправить к веб сервису. При эт вы можете так же использовать AddOns для браузера чтобы устанавливать запросы перед тем, как отправить к RESTful service.

RESTClient AddOns является таким плагином, вы можете установить его в  Firefox или  Chrome. Он помогает вам тестировать RESTful web service во время разработки приложения.

Как работает Jersey RESTful?

contextPath:
REST Path: