API REST com Jersey e Spring
[.s1] ##
1. Visão geral
Jersey é uma estrutura de software livre para desenvolver RESTful Web Services. Serve como uma implementação de referência do JAX-RS.
Neste artigo,we’ll explore the creation of a RESTful Web Service using Jersey 2. Além disso, usaremos a injeção de dependência (DI) do Spring com configuração Java.
2. Dependências do Maven
Vamos começar adicionando dependências apom.xml:
org.glassfish.jersey.containers
jersey-container-servlet
2.26
org.glassfish.jersey.media
jersey-media-json-jackson
2.26
Além disso, para integração com Spring, temos que adicionar a dependênciajersey-spring4:
org.glassfish.jersey.ext
jersey-spring4
2.26
A versão mais recente dessas dependências está disponível emjersey-container-servlet,jersey-media-json-jacksonejersey-spring4.
3. Configuração da Web
Next, we need to set up a web project to do Servlet configuration. Para isso, usaremosWebApplicationInitializer do 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.example.server");
}
}
Aqui, estamos adicionando a anotação@Order(Ordered.HIGHEST_PRECEDENCE) para garantir que nosso inicializador seja executado antes do inicializador padrão Jersey-Spring.
4. Um serviço usando Jersey JAX-RS
4.1. Classe de representação de recursos
Vamos usar um exemplo de classe de representação de recursos:
@XmlRootElement
public class Employee {
private int id;
private String firstName;
// standard getters and setters
}
Observe que as anotações JAXB como@XmlRootElement são necessárias apenas se o suporte XML for necessário (além de JSON).
4.2. Implementação de Serviço
Vejamos agora como podemos usar anotações JAX-RS para criar serviços da web 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. Também podemos incorporar variáveis na sintaxe do URI, como mostra a variável{id}. Em seguida, as variáveis serão substituídas no tempo de execução. Para obter o valor da variável, podemos usar a anotação@PathParam.
@GET, @PUT, @POST, @DELETE and @HEAD define the HTTP method of the request, que será processado por métodos anotados.
The @Produces annotation defines the endpoint’s response type (tipo de mídia MIME). Em nosso exemplo, nós o configuramos para retornar JSON ou XML, dependendo do valor do cabeçalho HTTPAccept (application/json ouapplication/xml).
On the other hand, the @Consumes annotation defines the MIME media types that the service can consume. Em nosso exemplo, o serviço pode consumir JSON ou XML, dependendo do cabeçalho HTTPContent-Type (application/json ouapplication/xml).
A anotação@Context é usada para injetar informações em um campo de classe, propriedade de bean ou parâmetro de método. Em nosso exemplo, estamos usando para injetarUriInfo. Também podemos usá-lo para injetarServletConfig,ServletContext,HttpServletRequesteHttpServletResponse.
5. UsandoExceptionMapper
ExceptionMapper nos permite interceptar as exceções e retornar o código de resposta HTTP apropriado para o cliente. No exemplo a seguir, o código de resposta HTTP 404 será retornado se a exceçãoEmployeeNotFound for lançada:
@Provider
public class NotFoundExceptionHandler
implements ExceptionMapper {
public Response toResponse(EmployeeNotFound ex) {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
6. Gerenciando classes de recursos
Finalmente,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. Teste de API
Vamos agora testar as APIs com alguns testes ao vivo:
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. Conclusão
Neste artigo, apresentamos a estrutura Jersey e desenvolvemos uma API simples. Usamos Spring para recursos de injeção de dependência. Também vimos o uso deExceptionMapper.
Como sempre, o código-fonte completo está disponível emthis Github project.