Spring RequestMapping

Spring RequestMapping

1. Überblick

In diesem Artikel konzentrieren wir uns auf eine der Hauptanmerkungen inSpring MVC – @RequestMapping.

Einfach ausgedrückt wird die Annotation verwendet, um Webanforderungen Spring Controller-Methoden zuzuordnen.

Weitere Lektüre:

Statische Ressourcen mit Spring bereitstellen

So ordnen Sie statische Ressourcen mit Spring MVC zu und verarbeiten sie - verwenden Sie die einfache Konfiguration, die flexiblere Version 3.1 und schließlich die neuen Resource Resolver der Version 4.1.

Read more

Erste Schritte mit Formularen in Spring MVC

Erfahren Sie, wie Sie mit Spring MVC mit Formularen arbeiten - Zuordnen einer Basisentität, Senden und Anzeigen von Fehlern.

Read more

HTTP-Nachrichtenkonverter mit dem Spring Framework

Konfigurieren von HttpMessageConverters für eine REST-API mit Spring und Verwenden dieser Konverter mit RestTemplate

Read more

2. @RequestMapping Grundlagen

Beginnen wir mit einem einfachen Beispiel: Zuordnen einer HTTP-Anforderung zu einer Methode anhand einiger grundlegender Kriterien.

2.1. @RequestMapping - nach Pfad

@RequestMapping(value = "/ex/foos", method = RequestMethod.GET)
@ResponseBody
public String getFoosBySimplePath() {
    return "Get some Foos";
}

Führen Sie Folgendes aus, um diese Zuordnung mit einem einfachen Befehlcurl zu testen:

curl -i http://localhost:8080/spring-rest/ex/foos

2.2. @RequestMapping - die HTTP-Methode

Der Parameter HTTPmethodhatno default. Wenn wir also keinen Wert angeben, wird er jeder HTTP-Anforderung zugeordnet.

Hier ist ein einfaches Beispiel, ähnlich dem vorherigen - diesmal jedoch einer HTTP-POST-Anforderung zugeordnet:

@RequestMapping(value = "/ex/foos", method = POST)
@ResponseBody
public String postFoos() {
    return "Post some Foos";
}

So testen Sie den POST mit dem Befehlcurl:

curl -i -X POST http://localhost:8080/spring-rest/ex/foos

3. RequestMapping und HTTP-Header

3.1. @RequestMapping mit dem Attributheaders

Die Zuordnung kann noch weiter eingegrenzt werden, indem ein Header für die Anforderung angegeben wird:

@RequestMapping(value = "/ex/foos", headers = "key=val", method = GET)
@ResponseBody
public String getFoosWithHeader() {
    return "Get some Foos with Header";
}

Um den Vorgang zu testen, verwenden wir die Header-Unterstützung voncurl:

curl -i -H "key:val" http://localhost:8080/spring-rest/ex/foos

Und sogar mehrere Header über das Attributheader von@RequestMapping:

@RequestMapping(
  value = "/ex/foos",
  headers = { "key1=val1", "key2=val2" }, method = GET)
@ResponseBody
public String getFoosWithHeaders() {
    return "Get some Foos with Header";
}

Wir können dies mit dem Befehl testen:

curl -i -H "key1:val1" -H "key2:val2" http://localhost:8080/spring-rest/ex/foos

Beachten Sie, dass für die Syntax voncurlzum Trennen des Header-Schlüssels und des Header-Werts ein Doppelpunkt wie in der HTTP-Spezifikation verwendet wird, während in Spring das Gleichheitszeichen verwendet wird.

3.2. @RequestMapping verbraucht und produziert

Die Zuordnung dermedia types produced by a controller-Methode verdient besondere Aufmerksamkeit. Wir können eine Anforderung basierend auf ihremAccept-Header über das oben eingeführte@RequestMapping-Header-Attribut zuordnen:

@RequestMapping(
  value = "/ex/foos",
  method = GET,
  headers = "Accept=application/json")
@ResponseBody
public String getFoosAsJsonFromBrowser() {
    return "Get some Foos with Header Old";
}

Der Abgleich für diese Art der Definition des Headers vonAcceptist flexibel - er verwendet enthält anstelle von gleich, sodass eine Anforderung wie die folgende immer noch korrekt zugeordnet wird:

curl -H "Accept:application/json,text/html"
  http://localhost:8080/spring-rest/ex/foos

Beginnend mit Spring 3.1 werden die@RequestMapping annotation now has the produces and the consumes attributes speziell für diesen Zweck:

@RequestMapping(
  value = "/ex/foos",
  method = RequestMethod.GET,
  produces = "application/json"
)
@ResponseBody
public String getFoosAsJsonFromREST() {
    return "Get some Foos with Header New";
}

Außerdem wird der alte Zuordnungstyp mit dem Attributheaders ab Spring 3.1 automatisch in den neuen Mechanismusproduceskonvertiert, sodass die Ergebnisse identisch sind.

Dies wird übercurl auf die gleiche Weise verbraucht:

curl -H "Accept:application/json"
  http://localhost:8080/spring-rest/ex/foos

Darüber hinaus unterstützenproducesauch mehrere Werte:

@RequestMapping(
  value = "/ex/foos",
  method = GET,
  produces = { "application/json", "application/xml" }
)

Beachten Sie, dass diese - die alte und die neue Art, den Header vonacceptanzugeben - im Grunde die gleiche Zuordnung sind, sodass Spring sie nicht zusammen zulässt. Wenn beide Methoden aktiv sind, würde dies zu Folgendem führen:

Caused by: java.lang.IllegalStateException: Ambiguous mapping found.
Cannot map 'fooController' bean method
java.lang.String
org.example.spring.web.controller
  .FooController.getFoosAsJsonFromREST()
to
{ [/ex/foos],
  methods=[GET],params=[],headers=[],
  consumes=[],produces=[application/json],custom=[]
}:
There is already 'fooController' bean method
java.lang.String
org.example.spring.web.controller
  .FooController.getFoosAsJsonFromBrowser()
mapped.

Ein letzter Hinweis zum neuen Mechanismus vonproduces undconsumes- diese verhalten sich anders als die meisten anderen Anmerkungen: Wenn sie auf Typebene angegeben werden, sindthe method level annotations do not complement but override die Informationen auf Typebene.

Und natürlich, wenn Sie tiefer in die Erstellung einer REST-API mit Spring -check outthe new REST with Spring course eintauchen möchten.

4. RequestMapping mit Pfadvariablen

Teile des Mapping-URI können über die Annotation@PathVariablean Variablen gebunden werden.

4.1. Einzelne@PathVariable

Ein einfaches Beispiel mit einer einzelnen Pfadvariablen:

@RequestMapping(value = "/ex/foos/{id}", method = GET)
@ResponseBody
public String getFoosBySimplePathWithPathVariable(
  @PathVariable("id") long id) {
    return "Get a specific Foo with id=" + id;
}

Dies kann mitcurl getestet werden:

curl http://localhost:8080/spring-rest/ex/foos/1

Wenn der Name des Methodenparameters genau mit dem Namen der Pfadvariablen übereinstimmt, kann dies umusing @PathVariable with no value vereinfacht werden:

@RequestMapping(value = "/ex/foos/{id}", method = GET)
@ResponseBody
public String getFoosBySimplePathWithPathVariable(
  @PathVariable String id) {
    return "Get a specific Foo with id=" + id;
}

Beachten Sie, dass@PathVariable von der automatischen Typkonvertierung profitiert, sodass wir die ID auch wie folgt deklarieren könnten:

@PathVariable long id

4.2. Mehrere@PathVariable

Bei komplexeren URIs müssen möglicherweise mehrere Teile des URIsmultiple values zugeordnet werden:

@RequestMapping(value = "/ex/foos/{fooid}/bar/{barid}", method = GET)
@ResponseBody
public String getFoosBySimplePathWithPathVariables
  (@PathVariable long fooid, @PathVariable long barid) {
    return "Get a specific Bar with id=" + barid +
      " from a Foo with id=" + fooid;
}

Dies kann leicht mit einemcurl auf die gleiche Weise getestet werden:

curl http://localhost:8080/spring-rest/ex/foos/1/bar/2

4.3. @PathVariable mit RegEx

Reguläre Ausdrücke können auch verwendet werden, wenn@PathVariable zugeordnet werden. Beispielsweise beschränken wir die Zuordnung so, dass nur numerische Werte fürid akzeptiert werden:

@RequestMapping(value = "/ex/bars/{numericId:[\\d]+}", method = GET)
@ResponseBody
public String getBarsBySimplePathWithPathVariable(
  @PathVariable long numericId) {
    return "Get a specific Bar with id=" + numericId;
}

Dies bedeutet, dass die folgenden URIs übereinstimmen:

http://localhost:8080/spring-rest/ex/bars/1

Aber das wird nicht:

http://localhost:8080/spring-rest/ex/bars/abc

5. RequestMapping mit Anforderungsparametern

@RequestMapping ermöglicht einfachemapping of URL parameters with the @RequestParam annotation. __

Wir ordnen jetzt eine Anfrage einem URI zu, wie zum Beispiel:

http://localhost:8080/spring-rest/ex/bars?id=100
@RequestMapping(value = "/ex/bars", method = GET)
@ResponseBody
public String getBarBySimplePathWithRequestParam(
  @RequestParam("id") long id) {
    return "Get a specific Bar with id=" + id;
}

Wir extrahieren dann den Wert des Parametersid unter Verwendung der Annotation@RequestParam(“id”) in der Signatur der Controller-Methode.

Um eine Anfrage mit dem Parameterid zu senden, verwenden wir die Parameterunterstützung incurl:

curl -i -d id=100 http://localhost:8080/spring-rest/ex/bars

In diesem Beispiel wurde der Parameter direkt gebunden, ohne zuvor deklariert worden zu sein.

Für fortgeschrittenere Szenarien@RequestMapping can optionally define the parameters - eine weitere Möglichkeit, die Anforderungszuordnung einzugrenzen:

@RequestMapping(value = "/ex/bars", params = "id", method = GET)
@ResponseBody
public String getBarBySimplePathWithExplicitRequestParam(
  @RequestParam("id") long id) {
    return "Get a specific Bar with id=" + id;
}

Noch flexiblere Zuordnungen sind zulässig - es können mehrereparams-Werte festgelegt werden, und nicht alle müssen verwendet werden:

@RequestMapping(
  value = "/ex/bars",
  params = { "id", "second" },
  method = GET)
@ResponseBody
public String getBarBySimplePathWithExplicitRequestParams(
  @RequestParam("id") long id) {
    return "Narrow Get a specific Bar with id=" + id;
}

Und natürlich eine Anfrage an eine URI wie:

http://localhost:8080/spring-rest/ex/bars?id=100&second=something

Wird immer der besten Übereinstimmung zugeordnet - dies ist die engere Übereinstimmung, die sowohl denid- als auch densecond-Parameter definiert.

6. RequestMapping Eckfälle

6.1. @RequestMapping - Mehrere Pfade, die derselben Controller-Methode zugeordnet sind

Obwohl der Pfadwert eines einzelnen@RequestMappingnormalerweise für eine einzelne Controller-Methode verwendet wird, ist dies nur eine gute Vorgehensweise, keine feste Regel. In einigen Fällen kann es erforderlich sein, mehrere Anforderungen derselben Methode zuzuordnen. In diesem Fallthe value attribute of @RequestMapping does accept multiple mappings, nicht nur ein einziger:

@RequestMapping(
  value = { "/ex/advanced/bars", "/ex/advanced/foos" },
  method = GET)
@ResponseBody
public String getFoosOrBarsByPath() {
    return "Advanced - Get some Foos or Bars";
}

Jetzt sollten diese beiden Curl-Befehle dieselbe Methode verwenden:

curl -i http://localhost:8080/spring-rest/ex/advanced/foos
curl -i http://localhost:8080/spring-rest/ex/advanced/bars

6.2. @RequestMapping - Mehrere HTTP-Anforderungsmethoden an dieselbe Controller-Methode

Mehrere Anforderungen, die unterschiedliche HTTP-Verben verwenden, können derselben Controller-Methode zugeordnet werden:

@RequestMapping(
  value = "/ex/foos/multiple",
  method = { RequestMethod.PUT, RequestMethod.POST }
)
@ResponseBody
public String putAndPostFoos() {
    return "Advanced - PUT and POST within single method";
}

Mitcurl treffen beide jetzt dieselbe Methode:

curl -i -X POST http://localhost:8080/spring-rest/ex/foos/multiple
curl -i -X PUT http://localhost:8080/spring-rest/ex/foos/multiple

6.3. @RequestMapping - Ein Fallback für alle Anfragen

So implementieren Sie einen einfachen Fallback für alle Anforderungen mithilfe einer bestimmten HTTP-Methode, z. B. für ein GET:

@RequestMapping(value = "*", method = RequestMethod.GET)
@ResponseBody
public String getFallback() {
    return "Fallback for GET Requests";
}

Oder auch für alle Anfragen:

@RequestMapping(
  value = "*",
  method = { RequestMethod.GET, RequestMethod.POST ... })
@ResponseBody
public String allFallback() {
    return "Fallback for All Requests";
}

6.4. Mehrdeutiger Zuordnungsfehler

Der mehrdeutige Zuordnungsfehler tritt auf, wenn Spring zwei oder mehr Anforderungszuordnungen für verschiedene Controller-Methoden als gleich bewertet. Eine Anforderungszuordnung ist identisch, wenn sie über dieselbe HTTP-Methode, dieselbe URL, dieselben Parameter, dieselben Header und denselben Medientyp verfügt. Dies ist beispielsweise eine mehrdeutige Zuordnung:

@GetMapping(value = "foos/duplicate")
public String duplicate() {
    return "Duplicate";
}

@GetMapping(value = "foos/duplicate")
public String duplicateEx() {
    return "Duplicate";
}

Die normalerweise ausgelöste Ausnahme enthält folgende Fehlermeldungen:

Caused by: java.lang.IllegalStateException: Ambiguous mapping.
  Cannot map 'fooMappingExamplesController' method
  public java.lang.String org.example.web.controller.FooMappingExamplesController.duplicateEx()
  to {[/ex/foos/duplicate],methods=[GET]}:
  There is already 'fooMappingExamplesController' bean method
  public java.lang.String org.example.web.controller.FooMappingExamplesController.duplicate() mapped.

Ein sorgfältiges Lesen der Fehlermeldung weist darauf hin, dass Spring die Methodeorg.example.web.controller.FooMappingExamplesController.duplicateEx() nicht zuordnen kann, da eine widersprüchliche Zuordnung zu einer bereits zugeordnetenorg.example.web.controller.FooMappingExamplesController.duplicate().vorliegt

Das folgende Code-Snippet führt nicht zu mehrdeutigen Zuordnungsfehlern, da beide Methoden unterschiedliche Inhaltstypen zurückgeben:

@GetMapping(value = "foos/duplicate/xml", produces = MediaType.APPLICATION_XML_VALUE)
public String duplicateXml() {
    return "Duplicate";
}

@GetMapping(value = "foos/duplicate/json", produces = MediaType.APPLICATION_JSON_VALUE)
public String duplicateJson() {
    return "Duplicate";
}

Die naheliegende Lösung besteht darin, die URL zu aktualisieren, die einer der beiden beteiligten Methoden zugewiesen wurde.

7. Neue Verknüpfungen für die Anforderungszuordnung

In Spring Framework 4.3 wurdena few new HTTP-Zuordnungsanmerkungen eingeführt, die alle auf@RequestMapping basieren:

  • @ GetMapping

  • @ PostMapping

  • @ PutMapping

  • @ DeleteMapping

  • @PatchMapping

Diese neuen Anmerkungen können die Lesbarkeit verbessern und die Ausführlichkeit des Codes verringern. Sehen wir uns diese neuen Annotationen in Aktion an, indem wir eine RESTful-API erstellen, die CRUD-Operationen unterstützt:

@GetMapping("/{id}")
public ResponseEntity getBazz(@PathVariable String id){
    return new ResponseEntity<>(new Bazz(id, "Bazz"+id), HttpStatus.OK);
}

@PostMapping
public ResponseEntity newBazz(@RequestParam("name") String name){
    return new ResponseEntity<>(new Bazz("5", name), HttpStatus.OK);
}

@PutMapping("/{id}")
public ResponseEntity updateBazz(
  @PathVariable String id,
  @RequestParam("name") String name) {
    return new ResponseEntity<>(new Bazz(id, name), HttpStatus.OK);
}

@DeleteMapping("/{id}")
public ResponseEntity deleteBazz(@PathVariable String id){
    return new ResponseEntity<>(new Bazz(id), HttpStatus.OK);
}

Ein tiefer Einblick in diese kannhere gefunden werden.

8. Federkonfiguration

Die Spring MVC-Konfiguration ist einfach genug - wenn man bedenkt, dass unsereFooController im folgenden Paket definiert sind:

package org.example.spring.web.controller;

@Controller
public class FooController { ... }

Wir benötigen lediglich eine@Configuration-Klasse, um die vollständige MVC-Unterstützung zu aktivieren und das Scannen von Klassenpfaden für den Controller zu konfigurieren:

@Configuration
@EnableWebMvc
@ComponentScan({ "org.example.spring.web.controller" })
public class MvcConfig {
    //
}

9. Fazit

Dieser Artikel konzentriert sich auf@RequestMapping annotation in Spring - Erörterung eines einfachen Anwendungsfalls, die Zuordnung von HTTP-Headern, das Binden von Teilen des URI mit@PathVariable und das Arbeiten mit URI-Parametern sowie die Annotation von@RequestParam.

Wenn Sie lernen möchten, wie Sie eine andere Kernanmerkung in Spring MVC verwenden, können Siethe @ModelAttribute annotation here untersuchen.

Der vollständige Code aus dem Artikel ist inon GitHub verfügbar. Dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein.