Spring Наследование и маршрутизация контроллера MVC
В моем Spring MVC webapp у меня есть общий 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
. Но это выглядит как довольно уродливый грязный хак, потому что мы выставляем некоторые поддельные ресурсы uri, вместо того чтобы отключать его. Может быть, есть лучшая практика?
Любые идеи?
//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 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
Вы пытаетесь достичь ресурса, подресурсного типа джерси, используя spring? Возможно, это невозможно. Вместо объявления универсальной службы 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 не существует.