Spring MVC контроллер наследования и маршрутизации - PullRequest
15 голосов
/ 12 сентября 2011

В моем веб-приложении Spring MVC у меня есть универсальный контроллер RESTful для операций CRUD. И каждый конкретный контроллер должен был объявить только @RequestMapping, например /foo. Общий контроллер обработал все запросы к /foo и /foo/{id}.

Но теперь мне нужно написать немного более сложный контроллер CRUD, который будет получать дополнительные параметры запроса или переменные пути, например, /foo/{date} и /foo/{id}/{date}. Поэтому я расширяю свой общий CRUD-контроллер и пишу перегруженный метод fetch(id, date), который будет работать как с {id}, так и с {date}. Это не проблема.

Но мне также нужно «отключить» реализацию fetch(id), полученную из базового класса (ресурс больше не должен быть доступен в /foo/{id}, только в /foo/{id}/{date}). Единственная идея, которую я придумал, - переопределить этот метод в моем конкретном контроллере, отобразить его на поддельном URI и вернуть null. Но это выглядит как уродливый грязный хак, потому что мы выставляем некоторый фальшивый ресурс, вместо того, чтобы отключать его. Может быть, есть лучшая практика?

Есть идеи?

//My generic CRUD controller
public abstract class AbstractCRUDControllerBean<E, PK extends Serializable> implements AbstractCRUDController<E, PK> {

  @RequestMapping(method=RequestMethod.GET)
  public @ResponseBody ResponseEntity<E[]> fetchAll() { ... }

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

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

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

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

.

//Concrete controller, working with Foo entities
@Controller
@RequestMapping("/foo")
public class FooControllerImpl extends
        AbstractCRUDControllerBean<Foo, Long> implements FooController { 

  //ugly overriding parent's method
  @RequestMapping(value="/null",method=RequestMethod.GET)
  public @ResponseBody ResponseEntity<Foo> fetch(@PathVariable("id") PK id) { 
    return null;
  }

  //new fetch implementation
  @RequestMapping(value="/{id}/{date}", method=RequestMethod.GET)
  public @ResponseBody ResponseEntity<Foo> fetch(@PathVariable("id") PK id, @PathVariable("date") Date date) { .... }

}

1 Ответ

18 голосов
/ 12 сентября 2011

Пытаетесь ли вы получить ресурс, субресурсный тип трикотажа, используя пружину?Это может быть невозможно напрямую.Вместо того, чтобы объявлять общую службу RESTful в качестве контроллера, почему бы вам не делегировать ее им?

//My generic CRUD Operations
public abstract class AbstractCRUDControllerBean<E, PK extends Serializable> implements AbstractCRUDController<E, PK> {

  public ResponseEntity<E[]> fetchAll() { ... }

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

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

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

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

и делегировать в контроллере.

//Concrete controller, working with Foo entities
@Controller
@RequestMapping("/foo")
public class FooControllerImpl extends
        AbstractCRUDControllerBean<Foo, Long> implements FooController { 

  //we are interested in using fetchall but not others
  @RequestMapping(method=RequestMethod.GET)
  public @ResponseBody ResponseEntity<Foo> fetch(@PathVariable("id") PK id) { 
    return fetchAll();
  }

  //fetch with id and date
  @RequestMapping(value="/{id}/{date}", method=RequestMethod.GET)
  public @ResponseBody ResponseEntity<Foo> fetch(@PathVariable("id") PK id, @PathVariable("date") Date date) { .... }

}

также вы можете отобразить метод на основе доступности параметров, также

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

Этот метод отображает / foo / id / date, когда есть param1 и param2, а param3 делаетне существует.

...