Перейти к основному содержимому

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

· 4 мин. чтения

1. Обзор

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

В этой статье мы рассмотрим создание веб-службы RESTful с использованием Jersey 2 . Кроме того, мы будем использовать Spring Dependency Injection (DI) с конфигурацией Java.

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

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

<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.26</version>
</dependency>

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

<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring4</artifactId>
<version>2.26</version>
</dependency>

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

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

Далее нам нужно настроить веб-проект для настройки сервлета. Для этого мы будем использовать WebApplicationInitializer Spring :

@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.foreach.server");
}
}

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

4. Сервис, использующий Джерси 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();
}
}

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

@GET , @PUT , @POST, @DELETE и @HEAD определяют HTTP-метод запроса , который будет обрабатываться аннотированными методами.

Аннотация @Produces определяет тип ответа конечной точки (тип носителя MIME). В нашем примере мы настроили его для возврата JSON или XML в зависимости от значения HTTP-заголовка Accept ( application/json или application/xml ).

С другой стороны, аннотация @Consumes определяет типы мультимедиа MIME, которые может использовать служба. В нашем примере служба может использовать JSON или XML в зависимости от типа содержимого HTTP- заголовка ( application/json или application/xml ).

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

5. Использование ExceptionMapper

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

@Provider
public class NotFoundExceptionHandler
implements ExceptionMapper<EmployeeNotFound> {

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

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

Наконец, давайте свяжем все классы реализации службы и сопоставители исключений с путем приложения:

@ApplicationPath("/resources")
public class RestConfig extends Application {
public Set<Class<?>> getClasses() {
return new HashSet<Class<?>>(
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. Заключение

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

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