Erstellen Sie eine REST-API mit Spring und Java Config

Erstellen Sie eine REST-API mit Spring und Java Config

1. Überblick

Dieser Artikel zeigt, wieset up REST in Spring - die Controller- und HTTP-Antwortcodes, die Konfiguration des Payload-Marshalling und die Inhaltsverhandlung.

Weitere Lektüre:

Verwenden von Spring @ResponseStatus zum Festlegen des HTTP-Statuscodes

Sehen Sie sich die Anmerkung @ResponseStatus an und erfahren Sie, wie Sie damit den Antwortstatuscode festlegen.

Read more

Die Anmerkungen zu Spring @Controller und @RestController

Erfahren Sie mehr über die Unterschiede zwischen @Controller- und @RestController-Annotationen in Spring MVC.

Read more

2. REST im Frühjahr verstehen

Das Spring-Framework unterstützt zwei Möglichkeiten, RESTful-Services zu erstellen:

  • unter Verwendung von MVC mitModelAndView

  • Verwendung von HTTP-Nachrichtenkonvertern

Der Ansatz vonModelAndViewist älter und viel besser dokumentiert, aber auch ausführlicher und konfigurationsintensiver. Es wird versucht, das REST-Paradigma in das alte Modell zu integrieren, was nicht ohne Probleme ist. Das Spring-Team verstand dies und bot ab Spring 3.0 erstklassigen REST-Support.

The new approach, based on HttpMessageConverter and annotations, is much more lightweight and easy to implement. Die Konfiguration ist minimal und bietet sinnvolle Standardeinstellungen für das, was Sie von einem RESTful-Service erwarten würden.

3. Die Java-Konfiguration

@Configuration
@EnableWebMvc
public class WebConfig{
   //
}

Die Annotation des neuen@EnableWebMvcführt einige nützliche Dinge aus - insbesondere im Fall von REST erkennt sie die Existenz von Jackson und JAXB 2 im Klassenpfad und erstellt und registriert automatisch Standard-JSON- und XML-Konverter. Die Funktionalität der Annotation entspricht der XML-Version:

Dies ist eine Verknüpfung, die zwar in vielen Situationen nützlich sein kann, aber nicht perfekt ist. Wenn eine komplexere Konfiguration erforderlich ist, entfernen Sie die Anmerkung und erweitern SieWebMvcConfigurationSupport direkt.

3.1. Spring Boot verwenden

Wenn wir die Annotation@SpringBootApplication verwenden und sich die Bibliothekspring-webmvc im Klassenpfad befindet, wird die Annotation@EnableWebMvcautomatisch mita default autoconfiguration hinzugefügt.

Wir können dieser Konfiguration weiterhin MVC-Funktionalität hinzufügen, indem wir dieWebMvcConfigurer-Schnittstelle in einer@Configuration annotierten Klasse implementieren. Wir können auch eineWebMvcRegistrationsAdapter-Instanz verwenden, um unsere eigenen Vereinfachungen fürRequestMappingHandlerMapping,RequestMappingHandlerAdapter oderExceptionHandlerExceptionResolver bereitzustellen.

Wenn wir die MVC-Funktionen von Spring Boot verwerfen und eine benutzerdefinierte Konfiguration deklarieren möchten, können wir dies mithilfe der Annotation@EnableWebMvctun.

4. Testen des Frühlingskontexts

Ab Spring 3.1 erhalten wir erstklassige Testunterstützung für@Configuration Klassen:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
  classes = {WebConfig.class, PersistenceConfig.class},
  loader = AnnotationConfigContextLoader.class)
public class SpringContextIntegrationTest {

   @Test
   public void contextLoads(){
      // When
   }
}

Wir geben die Java-Konfigurationsklassen mit der Annotation@ContextConfigurationan. Das neueAnnotationConfigContextLoader lädt die Bean-Definitionen aus den@Configuration-Klassen.

Beachten Sie, dass die KonfigurationsklasseWebConfignicht in den Test einbezogen wurde, da sie in einem Servlet-Kontext ausgeführt werden muss, der nicht bereitgestellt wird.

4.1. Spring Boot verwenden

Spring Boot bietet mehrere Anmerkungen, um die SpringApplicationContext für unsere Tests intuitiver einzurichten.

Wir können nur einen bestimmten Teil der Anwendungskonfiguration laden oder den gesamten Kontextstartprozess simulieren.

Zum Beispiel können wir die Annotation@SpringBootTestverwenden, wenn der gesamte Kontext erstellt werden soll, ohne den Server zu starten.

Wenn dies geschehen ist, können wir die@AutoConfigureMockMvc hinzufügen, um eineMockMvc -Sinstanz zu injizieren und HTTP-Anforderungen: zu senden

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class FooControllerAppIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void whenTestApp_thenEmptyResponse() throws Exception {
        this.mockMvc.perform(get("/foos")
            .andExpect(status().isOk())
            .andExpect(...);
    }

}

Um zu vermeiden, dass der gesamte Kontext erstellt wird und nur unsere MVC-Controller getestet werden, können wir@WebMvcTest: verwenden

@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerWebLayerIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private IFooService service;

    @Test()
    public void whenTestMvcController_thenRetrieveExpectedResult() throws Exception {
        // ...

        this.mockMvc.perform(get("/foos")
            .andExpect(...);
    }
}

Detaillierte Informationen zu diesem Thema finden Sie unterour ‘Testing in Spring Boot' article.

5. Der Controller

The @RestController is the central artifact in the entire Web Tier of the RESTful API. Für diesen Beitrag modelliert der Controller eine einfache REST-Ressource -Foo:

@RestController
@RequestMapping("/foos")
class FooController {

    @Autowired
    private IFooService service;

    @GetMapping
    public List findAll() {
        return service.findAll();
    }

    @GetMapping(value = "/{id}")
    public Foo findById(@PathVariable("id") Long id) {
        return RestPreconditions.checkFound(service.findById(id));
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Long create(@RequestBody Foo resource) {
        Preconditions.checkNotNull(resource);
        return service.create(resource);
    }

    @PutMapping(value = "/{id}")
    @ResponseStatus(HttpStatus.OK)
    public void update(@PathVariable( "id" ) Long id, @RequestBody Foo resource) {
        Preconditions.checkNotNull(resource);
        RestPreconditions.checkNotNull(service.getById(resource.getId()));
        service.update(resource);
    }

    @DeleteMapping(value = "/{id}")
    @ResponseStatus(HttpStatus.OK)
    public void delete(@PathVariable("id") Long id) {
        service.deleteById(id);
    }

}

Möglicherweise haben Sie bemerkt, dass ich ein einfaches Dienstprogramm im Guava-StilRestPreconditionsverwende:

public class RestPreconditions {
    public static  T checkFound(T resource) {
        if (resource == null) {
            throw new MyResourceNotFoundException();
        }
        return resource;
    }
}

Die Controller-Implementierung ist nicht öffentlich - dies liegt daran, dass dies nicht erforderlich ist.

Normalerweise ist der Controller der letzte in der Abhängigkeitskette. Es empfängt HTTP-Anforderungen vom Spring Front Controller (DispatcherServlet) und delegiert sie einfach an eine Service-Schicht weiter. Wenn es keinen Anwendungsfall gibt, in dem der Controller über eine direkte Referenz injiziert oder manipuliert werden muss, möchte ich ihn lieber nicht als öffentlich deklarieren.

Die Anforderungszuordnungen sind unkompliziert. As with any controller, the actual value of the mapping, as well as the HTTP method, determine the target method for the request. @RequestBody bindet die Parameter der Methode an den Hauptteil der HTTP-Anforderung, während@ResponseBody dasselbe für den Antwort- und Rückgabetyp tut.

Die@RestController  sind ashorthand, um sowohl die@ResponseBody- als auch die @Controller-Annotationen in unserer Klasse. einzuschließen

Sie stellen auch sicher, dass die Ressource mit dem richtigen HTTP-Konverter gemarshallt und nicht gemarshallt wird. Die Inhaltsverhandlung findet statt, um auszuwählen, welcher der aktiven Konverter verwendet wird, hauptsächlich basierend auf demAccept-Header, obwohl auch andere HTTP-Header verwendet werden können, um die Darstellung zu bestimmen.

6. Zuordnung der HTTP-Antwortcodes

Die Statuscodes der HTTP-Antwort sind einer der wichtigsten Teile des REST-Service, und das Thema kann schnell sehr kompliziert werden. Das Richtige zu tun, kann dazu führen, dass der Service beeinträchtigt oder beeinträchtigt wird.

6.1. Nicht zugeordnete Anfragen

Wenn Spring MVC eine Anforderung ohne Zuordnung empfängt, betrachtet es die Anforderung als nicht zulässig und gibt eine 405-METHODE, die NICHT ERLAUBT ist, an den Client zurück.

Es wird auch empfohlen, den HTTP-HeaderAlloweinzuschließen, wenn405an den Client zurückgegeben werden, um anzugeben, welche Vorgänge zulässig sind. Dies ist das Standardverhalten von Spring MVC und erfordert keine zusätzliche Konfiguration.

6.2. Gültige zugeordnete Anforderungen

Für jede Anforderung, die eine Zuordnung enthält, betrachtet Spring MVC die Anforderung als gültig und antwortet mit 200 OK, wenn kein anderer Statuscode angegeben ist.

Aus diesem Grund deklariert der Controller unterschiedliche@ResponseStatus für die Aktionencreate,update unddelete, jedoch nicht fürget, was tatsächlich den Standardwert 200 zurückgeben sollte OK.

6.3. Client-Fehler

Im Falle eines Clientfehlers werden benutzerdefinierte Ausnahmen definiert und den entsprechenden Fehlercodes zugeordnet.

Durch einfaches Auslösen dieser Ausnahmen aus einer beliebigen Ebene der Webschicht wird sichergestellt, dass Spring den entsprechenden Statuscode in der HTTP-Antwort abbildet:

@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadRequestException extends RuntimeException {
   //
}
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
   //
}

Diese Ausnahmen sind Teil der REST-API und sollten daher nur in den entsprechenden REST-Ebenen verwendet werden. Wenn beispielsweise eine DAO / DAL-Schicht vorhanden ist, sollten die Ausnahmen nicht direkt verwendet werden.

Beachten Sie auch, dass dies keine geprüften Ausnahmen, sondern Laufzeitausnahmen sind - in Übereinstimmung mit den Praktiken und Redewendungen von Spring.

6.4. Verwenden von@ExceptionHandler

Eine weitere Option zum Zuordnen von benutzerdefinierten Ausnahmen zu bestimmten Statuscodes ist die Verwendung der Annotation@ExceptionHandlerin der Steuerung. Das Problem bei diesem Ansatz ist, dass die Anmerkung nur für den Controller gilt, in dem sie definiert ist. Dies bedeutet, dass wir in jedem Controller einzeln deklarieren müssen.

Natürlich gibt es sowohl in Spring als auch in Spring Boot mehrways to handle errors, die mehr Flexibilität bieten.

7. Additional Maven Dependencies **

Zusätzlich zurspring-webmvc-Abhängigkeitrequired for the standard web application müssen wir das Marshalling und Unmarshalling von Inhalten für die REST-API einrichten:


   
      com.fasterxml.jackson.core
      jackson-databind
      2.9.8
   
   
      javax.xml.bind
      jaxb-api
      2.3.1
      runtime
   

Dies sind die Bibliotheken, die zum Konvertieren der Darstellung der REST-Ressource in JSON oder XML verwendet werden.

7.1. Spring Boot verwenden

Wenn wir JSON-formatierte Ressourcen abrufen möchten, bietet Spring Boot Unterstützung für verschiedene Bibliotheken, nämlich Jackson, Gson und JSON-B.

Die automatische Konfiguration wird ausgeführt, indem nur eine der Zuordnungsbibliotheken in den Klassenpfad eingeschlossen wird.

Wenn wir eine Webanwendung entwickeln, werden normalerweisewe’ll just add the spring-boot-starter-web dependency and rely on it to include all the necessary artifacts to our project:


    org.springframework.boot
    spring-boot-starter-web
    2.1.2.RELEASE

Spring Boot verwendet standardmäßig Jackson.

Wenn wir unsere Ressourcen in einem XML-Format serialisieren möchten, müssen wir die Jackson-XML-Erweiterung (jackson-dataformat-xml) zu unseren Abhängigkeiten hinzufügen oder auf die JAXB-Implementierung (standardmäßig im JDK bereitgestellt) zurückgreifen, indem wir das verwenden @XmlRootElement Anmerkung zu unserer Ressource.

8. Fazit

Dieses Tutorial zeigt, wie Sie einen REST-Service mithilfe der Spring- und Java-basierten Konfiguration implementieren und konfigurieren.

In den nächsten Artikeln der Reihe werde ich mich aufDiscoverability of the API, erweiterte Inhaltsverhandlung und die Arbeit mit zusätzlichen Darstellungen vonResource. konzentrieren

Der gesamte Code dieses Artikels ist inover on Github verfügbar. Dies ist ein Maven-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein.