REST API mit Jersey und Spring
[.s1] ##
1. Überblick
Jersey ist ein Open Source-Framework für die Entwicklung von RESTful Web Services. Es dient als Referenzimplementierung von JAX-RS.
In diesem Artikel werdenwe’ll explore the creation of a RESTful Web Service using Jersey 2. Außerdem verwenden wir Spring's Dependency Injection (DI) mit Java-Konfiguration.
2. Maven-Abhängigkeiten
Beginnen wir mit dem Hinzufügen von Abhängigkeiten zupom.xml:
org.glassfish.jersey.containers
jersey-container-servlet
2.26
org.glassfish.jersey.media
jersey-media-json-jackson
2.26
Für die Spring-Integration müssen wir außerdem die Abhängigkeit vonjersey-spring4hinzufügen:
org.glassfish.jersey.ext
jersey-spring4
2.26
Die neueste Version dieser Abhängigkeiten ist unterjersey-container-servlet,jersey-media-json-jackson undjersey-spring4 verfügbar.
3. Webkonfiguration
Next, we need to set up a web project to do Servlet configuration. Hierfür verwenden wir dieWebApplicationInitializer von 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");
}
}
Hier fügen wir die Annotation@Order(Ordered.HIGHEST_PRECEDENCE)hinzu, um sicherzustellen, dass unser Initialisierer vor dem Standardinitialisierer von Jersey-Spring ausgeführt wird.
4. Ein Service mit Jersey JAX-RS
4.1. Ressourcendarstellungsklasse
Verwenden wir eine Beispielressourcendarstellungsklasse:
@XmlRootElement
public class Employee {
private int id;
private String firstName;
// standard getters and setters
}
Beachten Sie, dass JAXB-Annotationen wie@XmlRootElement nur erforderlich sind, wenn XML-Unterstützung benötigt wird (zusätzlich zu JSON).
4.2. Service-Implementierung
Schauen wir uns nun an, wie wir JAX-RS-Annotationen verwenden können, um RESTful-Webdienste zu erstellen:
@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. Wir können auch Variablen in die URI-Syntax einbetten, wie die Variable{id} zeigt. Die Variablen werden dann zur Laufzeit ersetzt. Um den Wert der Variablen zu erhalten, können wir die Annotation@PathParamverwenden.
@GET, @PUT, @POST, @DELETE and @HEAD define the HTTP method of the request, die mit kommentierten Methoden verarbeitet werden.
The @Produces annotation defines the endpoint’s response type (MIME-Medientyp). In unserem Beispiel haben wir es so konfiguriert, dass es je nach Wert des HTTP-HeadersAccept (application/json oderapplication/xml) entweder JSON oder XML zurückgibt.
On the other hand, the @Consumes annotation defines the MIME media types that the service can consume. In unserem Beispiel kann der Dienst je nach HTTP-HeaderContent-Type (application/json oderapplication/xml) entweder JSON oder XML verwenden.
Die Annotation@Context wird verwendet, um Informationen in ein Klassenfeld, eine Bean-Eigenschaft oder einen Methodenparameter einzufügen. In unserem Beispiel verwenden wir es, umUriInfo zu injizieren. Wir können es auch verwenden, umServletConfig,ServletContext,HttpServletRequest undHttpServletResponse. zu injizieren
5. Verwenden vonExceptionMapper
ExceptionMapper ermöglicht es uns, die Ausnahmen abzufangen und den entsprechenden HTTP-Antwortcode an den Client zurückzugeben. Im folgenden Beispiel wird der HTTP-Antwortcode 404 zurückgegeben, wenn die Ausnahme vonEmployeeNotFoundausgelöst wird:
@Provider
public class NotFoundExceptionHandler
implements ExceptionMapper {
public Response toResponse(EmployeeNotFound ex) {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
6. Ressourcenklassen verwalten
Schließlichlet’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-Tests
Testen wir nun die APIs mit einigen Live-Tests:
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. Fazit
In diesem Artikel haben wir das Jersey-Framework vorgestellt und eine einfache API entwickelt. Wir haben Spring for Dependency Injection-Funktionen verwendet. Wir haben auch die Verwendung vonExceptionMapper gesehen.
Wie immer ist der vollständige Quellcode inthis Github project verfügbar.