15 Stimmen

Spring MVC Controller Vererbung und Routing

In meiner Spring MVC-Webanwendung habe ich einen generischen RESTful-Controller für CRUD-Operationen. Und jeder konkrete Controller musste nur ein @RequestMapping deklarieren, zum Beispiel /foo. Der generische Controller hat alle Anfragen an /foo und /foo/{id} behandelt.

Jetzt muss ich jedoch einen etwas komplexeren CRUD-Controller schreiben, der zusätzliche Anfragemöglichkeiten oder Pfadvariablen erhält, z.B. /foo/{date} und /foo/{id}/{date}. Daher erweitere ich meinen generischen CRUD-Controller und schreibe eine überladene fetch(id, date)-Methode, die sowohl mit {id} als auch mit {date} umgehen wird. Das ist kein Problem.

Aber ich muss auch die fetch(id)-Implementierung der Basisklasse deaktivieren (die Ressource sollte nicht mehr unter /foo/{id} verfügbar sein, nur noch unter /foo/{id}/{date}). Die einzige Idee, die mir dazu einfällt, ist diese Methode im konkreten Controller zu überschreiben, sie auf eine falsche URI zu mappen und null zurückzugeben. Aber das scheint eher wie ein hässlicher, schmutziger Hack, da wir eine falsche Ressourcen-URI freilegen, anstatt sie zu deaktivieren. Gibt es vielleicht eine bessere Praxis?

Irgendwelche Ideen?

//Mein generischer CRUD-Controller
public abstract class AbstractCRUDControllerBean implements AbstractCRUDController {

  @RequestMapping(method=RequestMethod.GET)
  public @ResponseBody ResponseEntity fetchAll() { ... }

  @RequestMapping(value="/{id}", method=RequestMethod.GET)
  public @ResponseBody ResponseEntity fetch(@PathVariable("id") PK id) { ... }

  @RequestMapping(method=RequestMethod.POST)
  public @ResponseBody ResponseEntity add(@RequestBody E entity) { ... }

  @RequestMapping(value="/{id}", method=RequestMethod.PUT)
  public @ResponseBody ResponseEntity update(@PathVariable("id") PK id, @RequestBody E entity) { ... }

  @RequestMapping(value="/{id}", method=RequestMethod.DELETE)
  public @ResponseBody ResponseEntity remove(@PathVariable("id") PK id) { .. }
} 

.

//Konkreter Controller, der mit Foo-Entitäten arbeitet
@Controller
@RequestMapping("/foo")
public class FooControllerImpl extends
        AbstractCRUDControllerBean implements FooController { 

  //Hässliches Überschreiben der Methode aus der Elternklasse
  @RequestMapping(value="/null",method=RequestMethod.GET)
  public @ResponseBody ResponseEntity fetch(@PathVariable("id") PK id) { 
    return null;
  }

  //Neue Fetch-Implementierung
  @RequestMapping(value="/{id}/{date}", method=RequestMethod.GET)
  public @ResponseBody ResponseEntity fetch(@PathVariable("id") PK id, @PathVariable("date") Date date) { .... }

}

19voto

kalyan Punkte 3047

Versuchen Sie, den Ressourcentyp Jersey mit Spring zu erreichen? Das ist möglicherweise nicht direkt möglich. Anstatt den generischen RESTful Service als Controller zu deklarieren, warum delegieren Sie es nicht an sie?

//Meine generischen CRUD-Operationen
public abstract class AbstractCRUDControllerBean implements AbstractCRUDController {

  public ResponseEntity fetchAll() { ... }

  public ResponseEntity fetch(@PathVariable("id") PK id) { ... }

  public ResponseEntity add(@RequestBody E entity) { ... }

  public ResponseEntity update(@PathVariable("id") PK id, @RequestBody E entity) { ... }

  public ResponseEntity remove(@PathVariable("id") PK id) { .. }
} 

und delegieren Sie im Controller.

//Konkreter Controller, der mit Foo-Entitäten arbeitet
@Controller
@RequestMapping("/foo")
public class FooControllerImpl extends
        AbstractCRUDControllerBean implements FooController { 

  //Wir interessieren uns für fetchall, aber nicht für andere
  @RequestMapping(method=RequestMethod.GET)
  public @ResponseBody ResponseEntity fetch(@PathVariable("id") PK id) { 
    return fetchAll();
  }

  //fetch mit id und Datum
  @RequestMapping(value="/{id}/{date}", method=RequestMethod.GET)
  public @ResponseBody ResponseEntity fetch(@PathVariable("id") PK id, @PathVariable("date") Date date) { .... }

}

Sie können Methoden auch basierend auf der Verfügbarkeit der Parameter zuordnen,

@RequestMapping(value="/{id}/{date}", params={"param1","param2","!param3"})
public @ResponseBody ResponseEntity customFetch(@PathVariable("id") PK id, 
            @PathVariable("date") Date date, @RequestParam("param1") String param1,                
            @RequestParam("param2") String param2) {...}

Diese Methode ordnet /foo/id/date zu, wenn param1 und param2 existieren und param3 nicht existiert.

0 Stimmen

Vielen Dank für diese Idee. Es passt sehr gut zu meinen Bedürfnissen. Manchmal, wenn man feststeckt, ist alles was man braucht, um die Perspektive zu ändern.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X