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.