REST API mit Jersey und Spring

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.