#spring #spring-mvc
Вопрос:
У меня потенциально есть несколько вариантов использования под одним и тем же URL-адресом.
// simplified example
@Controller
@RequestMapping
class PostAssetOrTaxonomyTermController {
@GetMapping("/{postSlug}/{filename}")
fun useCase1(@PathVariable postSlug: String, @PathVariable filename: String): Any? {
if (postExists(postSlug))
return servePostAsset(postSlug, filename)
else
return null // maybe try useCase2()
}
@GetMapping("/{taxonomySlug}/{term}")
fun useCase2(@PathVariable taxonomySlug: String, @PathVariable term: String): Any? {
if (taxonomyExists(taxonomySlug))
return serveTaxonomyTerm(taxonomySlug, term)
else
return null // no use-case had a result -> HTTP 404
}
}
В этом упрощенном примере я, конечно, могу просто позвонить useCase2()
из useCase1()
. На самом деле оба варианта использования имеют разные зависимости, разные возвращаемые значения. Поэтому я, естественно, хочу разделить их на разные классы и использовать МоК Spring.
Есть ли готовый способ сделать это?
Мои выводы до сих пор:
- Я могу пойти за фронт-контроллером и идти один за другим. Это решение работает, но быстро выходит из-под контроля. Кроме того, я изобретаю колесо здесь, потому что все мои регулярные выражения я бы получил от Spring из коробки со
@GetMapping
значением.
@Controller
@RequestMapping("/**")
class FrontController {
@GetMapping
fun handleEverything(request: HttpServletRequest): Any {
val url = request.requestURI
regexp1_or_2.matchEntire(url)
?.also {
// Try use-case1
if (getPostIfItExists(it)) return handleUseCase1(it)
// No result? Try use-case2
if (getTaxonomyIfItExists(it)) return handleUseCase2(it)
// fall-through again, maybe another regexp matches or 404 in the end
}
regexp3.matchEntire(url)
?.also { return handleUseCase3(it) }
// ... having to put ALL URLs inside here -.-
throw ResponseStatusException(HttpStatus.NOT_FOUND)
}
}
- Как я понимаю, Spring MVC в любом случае является фронт-контроллером, мне просто нужно, чтобы он был настроен
так, как я хочу.
Однако, посколькуDispatcherServlet
единственный находит ровно одинmappedHandler
и
вызывает его, я не могу легко «провалиться».Я не пробовал, но, похоже, я мог бы это понять, настроив 2
HandlerMapping
компонента.getHandler()
попробовал бы каждый из них, и я мог бы вернутьсяnull
, чтобы пропустить. Но это звучит как много усилий, и я не уверен на 100%, что смогу даже использоватьRequestMappingHandlerMapping
или мне придется снова изобретать велосипед.
Есть ли лучший способ?
Комментарии:
1. Нет, этого нет, и это даже не сработает, так как ваше приложение не запустится. Как бы вы различали
/foo/bar
и/bar/foo
вызывали какой метод? Нет механизма для сопоставления нескольких обработчиков с 1 URL-адресом. ИМХО, ваш дизайн несовершенен, и вы должны переосмыслить свой дизайн.