REST API с Джерси и Спринг

REST API с Джерси и Весной

[.s1] ##

1. обзор

Jersey - это платформа с открытым исходным кодом для разработки веб-служб RESTful. Он служит эталонной реализацией JAX-RS.

В этой статьеwe’ll explore the creation of a RESTful Web Service using Jersey 2. Кроме того, мы будем использовать Spring Dependency Injection (DI) с конфигурацией Java.

2. Maven Зависимости

Начнем с добавления зависимостей кpom.xml:


    org.glassfish.jersey.containers
    jersey-container-servlet
    2.26


    org.glassfish.jersey.media
    jersey-media-json-jackson
    2.26

Также для интеграции Spring мы должны добавить зависимостьjersey-spring4:


    org.glassfish.jersey.ext
    jersey-spring4
    2.26

Последняя версия этих зависимостей доступна по адресуjersey-container-servlet,jersey-media-json-jackson иjersey-spring4.

3. Веб-конфигурация

Next, we need to set up a web project to do Servlet configuration. Для этого мы будем использовать SpringWebApplicationInitializer:

@Order(Ordered.HIGHEST_PRECEDENCE)
public class ApplicationInitializer
  implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext)
      throws ServletException {

        AnnotationConfigWebApplicationContext context
          = new AnnotationConfigWebApplicationContext();

        servletContext.addListener(new ContextLoaderListener(context));
        servletContext.setInitParameter(
          "contextConfigLocation", "com.example.server");
    }
}

Здесь мы добавляем аннотацию@Order(Ordered.HIGHEST_PRECEDENCE), чтобы гарантировать, что наш инициализатор выполняется до инициализатора по умолчанию Jersey-Spring.

4. Сервис, использующий Jersey JAX-RS

4.1. Класс представления ресурса

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

@XmlRootElement
public class Employee {
    private int id;
    private String firstName;

    // standard getters and setters
}

Обратите внимание, что аннотации JAXB, такие как@XmlRootElement, требуются, только если требуется поддержка XML (в дополнение к JSON).

4.2. Внедрение сервиса

Давайте теперь посмотрим, как мы можем использовать аннотации JAX-RS для создания веб-сервисов RESTful:

@Path("/employees")
public class EmployeeResource {

    @Autowired
    private EmployeeRepository employeeRepository;

    @GET
    @Path("/{id}")
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Employee getEmployee(@PathParam("id") int id) {
        return employeeRepository.getEmployee(id);
    }

    @POST
    @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    public Response addEmployee(
      Employee employee, @Context UriInfo uriInfo) {

        employeeRepository.addEmployee(new Employee(employee.getId(),
          employee.getFirstName(), employee.getLastName(),
          employee.getAge()));

        return Response.status(Response.Status.CREATED.getStatusCode())
          .header(
            "Location",
            String.format("%s/%s",uriInfo.getAbsolutePath().toString(),
            employee.getId())).build();
    }
}

The @Path annotation provides the relative URI path to the service. Мы также можем встраивать переменные в синтаксис URI, как показывает переменная{id}. Затем переменные будут заменены во время выполнения. Чтобы получить значение переменной, мы можем использовать аннотацию@PathParam.

@GET, @PUT, @POST, @DELETE and @HEAD define the HTTP method of the request, который будет обрабатываться аннотированными методами.

The @Produces annotation defines the endpoint’s response type (тип носителя MIME). В нашем примере мы настроили его для возврата либо JSON, либо XML в зависимости от значения HTTP-заголовкаAccept (application/json илиapplication/xml).

On the other hand, the @Consumes annotation defines the MIME media types that the service can consume. В нашем примере служба может использовать JSON или XML в зависимости от HTTP-заголовкаContent-Type (application/json илиapplication/xml).

Аннотация@Context используется для вставки информации в поле класса, свойство компонента или параметр метода. В нашем примере мы используем его для вводаUriInfo. Мы также можем использовать его для вводаServletConfig,ServletContext,HttpServletRequest иHttpServletResponse.

5. ИспользуяExceptionMapper

ExceptionMapper позволяет нам перехватывать исключения и возвращать клиенту соответствующий код ответа HTTP. В следующем примере код ответа HTTP 404 возвращается при возникновении исключенияEmployeeNotFound:

@Provider
public class NotFoundExceptionHandler
  implements ExceptionMapper {

    public Response toResponse(EmployeeNotFound ex) {
        return Response.status(Response.Status.NOT_FOUND).build();
    }
}

6. Управление классами ресурсов

Наконец,let’s wire up all service implementation classes and exception mappers against an application path:

@ApplicationPath("/resources")
public class RestConfig extends Application {
    public Set> getClasses() {
        return new HashSet>(
          Arrays.asList(
            EmployeeResource.class,
            NotFoundExceptionHandler.class,
            AlreadyExistsExceptionHandler.class));
    }
}

7. Тестирование API

Давайте теперь протестируем API с помощью некоторых живых тестов:

public class JerseyApiLiveTest {

    private static final String SERVICE_URL
      = "http://localhost:8082/spring-jersey/resources/employees";

    @Test
    public void givenGetAllEmployees_whenCorrectRequest_thenResponseCodeSuccess()
      throws ClientProtocolException, IOException {

        HttpUriRequest request = new HttpGet(SERVICE_URL);

        HttpResponse httpResponse = HttpClientBuilder
          .create()
          .build()
          .execute(request);

        assertEquals(httpResponse
          .getStatusLine()
          .getStatusCode(), HttpStatus.SC_OK);
    }
}

8. Заключение

В этой статье мы познакомились с фреймворком Jersey и разработали простой API. Мы использовали Spring для функций внедрения зависимостей. Мы также видели использованиеExceptionMapper.

Как всегда, полный исходный код доступен вthis Github project.