Неоднозначное сопоставление обнаружено с помощью ControllerClassNameHandlerMapping

Как сопоставить запросы с методами без явных аннотаций поверх методов? Например, следующий запрос:

http://somedomain:8080/SampleSpring/access/loginFailed

должны быть сопоставлены с

Метод «loginFailed» для «AccessController» без необходимости явной аннотации к методу, например:

@RequestMapping("/access/loginFailed")

Вот моя весенняя конфигурация:

<context:component-scan base-package="com.robikcodes.samplespring"/>
<mvc:annotation-driven/>

<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
        <property name="basePackage" value="com.robikcodes.samplespring.controller"/>
        <property name="caseSensitive" value="true"/>
        <property name="defaultHandler">
            <bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
        </property>
</bean>   

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/views/"/>
            <property name="suffix" value=".jsp"/>
</bean>

Вот мой контроллер:

@Controller
public class AccessController{

    @RequestMapping(method = RequestMethod.GET)
    public void login(ModelMap m) {}

    @RequestMapping(method = RequestMethod.GET)
    public String loginFailed(ModelMap m) {
        m.addAttribute("error", "true");
        return "access/login";
    }

    @RequestMapping(method = RequestMethod.GET)
    public String logout(ModelMap m) {
        m.addAttribute("logoutStatus","true");
        return "access/login";
    }
}

Я получил следующую ошибку (похоже, правильно сопоставлен только метод входа в систему):

org.apache.catalina.LifecycleException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0': Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'accessController' bean method 
public java.lang.String com.robikcodes.samplespring.controller.AccessController.logout(org.springframework.ui.ModelMap)
to {[],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'accessController' bean method
public void com.robikcodes.samplespring.controller.AccessController.login(org.springframework.ui.ModelMap) mapped.

person coolscitist    schedule 23.12.2013    source источник
comment
Хотя это другой вопрос, но этот ответ также относится к вашему вопросу.   -  person nobeh    schedule 23.12.2013
comment
Да, это так. Я не знаю, как использовать DefaultAnnotationHandlerMapping и AnnotationMethodHandlerAdapter вместо RequestMappingHandlerMapping и RequestMappingHandlerAdapter. Даже если я заменю, они все равно устарели. Означает ли это, что нельзя использовать имена методов без использования устаревших классов?   -  person coolscitist    schedule 23.12.2013
comment
На самом деле RequestMappingHandlerAdapter не устарел, и вы должны использовать его, а также поддерживает полные сигнатуры методов.   -  person nobeh    schedule 23.12.2013
comment
Я имел в виду, что DefaultAnnotationHandlerMapping и AnnotationMethodHandlerAdapter устарели. В указанной вами ссылке Россен говорит: Новая пара HandlerMapping-HandlerAdapter включена по умолчанию. Тогда почему мой код не работает? Нужно ли явно объявлять RequestMappingHandlerAdapter? Если да, то как?   -  person coolscitist    schedule 23.12.2013


Ответы (1)


Вы используете ControllerClassNameHandlerMapping с неверным предположением; из документа Java:

Реализация HandlerMapping, которая следует простому соглашению для создания сопоставлений URL-адресов из имен классов зарегистрированных компонентов Controller, а также аннотированных компонентов @Controller.

В документации не сказано, что он также следует за именами методов. Основным ориентиром для сравнения «сопоставлений обработчиков» для вашего контроллера являются аннотации @RequestMapping, помещенные в ваши методы. Итак, с вашим контроллером Spring читает их как:

{methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}

для всех методов, определенных в AccessController, которые имеют следующие @RequestMapping:

@RequestMapping(method = RequestMethod.GET)

Вот почему вы видите неоднозначное исключение.

Насколько я понимаю, самым чистым решением является использование атрибута value для @RequestMapping для определения различных URI запросов. На самом деле не рекомендуется использовать решение, которое пытается сопоставить URI запроса с именами методов.

person nobeh    schedule 30.12.2013