Есть ли «провал», чтобы попробовать 2 метода контроллера в Spring MVC?

#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.

Есть ли готовый способ сделать это?

Мои выводы до сих пор:

  1. Я могу пойти за фронт-контроллером и идти один за другим. Это решение работает, но быстро выходит из-под контроля. Кроме того, я изобретаю колесо здесь, потому что все мои регулярные выражения я бы получил от 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)
    }
}
 
  1. Как я понимаю, Spring MVC в любом случае является фронт-контроллером, мне просто нужно, чтобы он был настроен
    так, как я хочу.
    Однако, поскольку DispatcherServlet единственный находит ровно один mappedHandler и
    вызывает его, я не могу легко «провалиться».

    Я не пробовал, но, похоже, я мог бы это понять, настроив 2 HandlerMapping компонента. getHandler() попробовал бы каждый из них, и я мог бы вернуться null , чтобы пропустить. Но это звучит как много усилий, и я не уверен на 100%, что смогу даже использовать RequestMappingHandlerMapping или мне придется снова изобретать велосипед.


Есть ли лучший способ?

Комментарии:

1. Нет, этого нет, и это даже не сработает, так как ваше приложение не запустится. Как бы вы различали /foo/bar и /bar/foo вызывали какой метод? Нет механизма для сопоставления нескольких обработчиков с 1 URL-адресом. ИМХО, ваш дизайн несовершенен, и вы должны переосмыслить свой дизайн.