web-dev-qa-db-fra.com

Spring mvc Une cartographie ambiguë a été trouvée. Impossible de mapper la méthode du haricot du contrôleur

J'essaie de créer une application qui peut répertorier certaines valeurs de la base de données et modifier, ajouter, supprimer si nécessaire à l'aide de Spring 4 et recevoir l'erreur suivante (uniquement si l'annotation "@Controller" est présente dans mes deux fichiers de contrôleur, si je supprime l'annotation de l'un des fichiers, cela fonctionne mais je reçois un message dans la console "aucun mappage trouvé ... dans dispatcherservlet avec le nom ...):

    INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/edit/{id}],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public Java.lang.String com.bookReview.app.BookController.editBook(int,org.springframework.ui.Model)
WARN : org.springframework.web.context.support.XmlWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt
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 'reviewController' bean method 
public Java.lang.String com.bookReview.app.ReviewController.editReview(int,org.springframework.ui.Model)
to {[/edit/{id}],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'bookController' bean method
public Java.lang.String com.bookReview.app.BookController.editBook(int,org.springframework.ui.Model) mapped.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1574)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.Java:539)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.Java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.Java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.Java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.Java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.Java:755)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.Java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.Java:480)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.Java:403)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.Java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.Java:106)
    at org.Apache.catalina.core.StandardContext.listenerStart(StandardContext.Java:4728)
    at org.Apache.catalina.core.StandardContext.startInternal(StandardContext.Java:5166)
    at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:150)
    at org.Apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.Java:1409)
    at org.Apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.Java:1399)
    at Java.util.concurrent.FutureTask.run(FutureTask.Java:266)
    at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1142)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:617)
    at Java.lang.Thread.run(Thread.Java:745)
Caused by: Java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'reviewController' bean method 
public Java.lang.String com.bookReview.app.ReviewController.editReview(int,org.springframework.ui.Model)
to {[/edit/{id}],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'bookController' bean method
public Java.lang.String com.bookReview.app.BookController.editBook(int,org.springframework.ui.Model) mapped.
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.Java:212)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.Java:184)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.Java:144)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.Java:123)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.Java:126)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.Java:1633)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1570)
    ... 21 more

Ceci est mon fichier pom.xml

<project xmlns="http://maven.Apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.bookReview.app</groupId>
  <artifactId>BookReviewApp</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>BookReviewApp</name>
  <description>review app</description>

   <!--   <properties>

        Generic properties
        <Java.version>1.8</Java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        Spring
        <spring-framework.version>4.0.3.RELEASE</spring-framework.version>

        Hibernate / JPA
        <hibernate.version>4.3.5.Final</hibernate.version>
        <hibernate.version>3.6.9.Final</hibernate.version>

        Logging
        <logback.version>1.0.13</logback.version>
        <slf4j.version>1.7.5</slf4j.version>

    </properties> -->

  <dependencies>
  <!-- Spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.1.6.RELEASE</version>
        <!-- Exclude Commons Logging in favor of SLF4j -->
            <exclusions>
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                 </exclusion>
            </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <!-- Hibernate -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>4.3.9.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>4.3.9.Final</version>
    </dependency>
    <!-- Apache Commons DBCP -->
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <!-- Spring ORM -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <!-- AspectJ -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.5</version>
    </dependency>
    <!-- Logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.12</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.12</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.12</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.15</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.mail</groupId>
                    <artifactId>mail</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>javax.jms</groupId>
                    <artifactId>jms</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.Sun.jdmk</groupId>
                    <artifactId>jmxtools</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.Sun.jmx</groupId>
                    <artifactId>jmxri</artifactId>
                </exclusion>
            </exclusions>
            <scope>runtime</scope>
        </dependency>
        <!-- @Inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
        <!-- Servlet -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2.1-b03</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- Test -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-Java</artifactId>
            <version>5.1.35</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.1.6.RELEASE</version>
        </dependency>
  </dependencies>
</project>

Ceci est mon fichier web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://Java.Sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://Java.Sun.com/xml/ns/javaee http://Java.Sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/app/root-context.xml</param-value>
    </context-param>

    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Processes application requests -->
    <servlet>
        <servlet-name>servlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/app/servlet/sevlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>servlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

Ceci est mon fichier sevlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing 
        infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
    <annotation-driven />

    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
    <beans:bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <beans:bean id="dataSource" class="org.Apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <beans:property name="url"
            value="jdbc:mysql://localhost:3306/test" />
        <beans:property name="username" value="serban" />
        <beans:property name="password" value="serban" />
    </beans:bean>

    <!-- Hibernate 4 SessionFactory Bean definition -->
    <beans:bean id="hibernate4AnnotatedSessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <beans:property name="dataSource" ref="dataSource" />
        <beans:property name="annotatedClasses">
            <beans:list>
                <beans:value>com.bookReview.app.model.book</beans:value>
                <beans:value>com.bookReview.app.model.review</beans:value>
            </beans:list>
        </beans:property>
        <beans:property name="hibernateProperties">
            <beans:props>
                <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
                </beans:prop>
                <beans:prop key="hibernate.show_sql">true</beans:prop>
            </beans:props>
        </beans:property>
    </beans:bean>

    <beans:bean id="bookDAO" class="com.bookReview.app.dao.bookDAOImpl">
        <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </beans:bean>
    <beans:bean id="bookService" class="com.bookReview.app.service.BookServiceImpl">
        <beans:property name="bookDAO" ref="bookDAO"></beans:property>
    </beans:bean>

    <beans:bean id="reviewDAO" class="com.bookReview.app.dao.reviewDAOImpl">
        <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </beans:bean>
    <beans:bean id="reviewService" class="com.bookReview.app.service.ReviewServiceImpl">
        <beans:property name="reviewDAO" ref="reviewDAO"></beans:property>
    </beans:bean>

    <!-- <default-servlet-handler/> -->

    <context:component-scan base-package="com.bookReview.app" />

    <tx:annotation-driven transaction-manager="transactionManager"/>

        <beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <beans:property name="sessionFactory" ref="hibernate4AnnotatedSessionFactory" />
    </beans:bean>

    </beans:beans>

Ceci est mon fichier BookController.Java

package com.bookReview.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.bookReview.app.model.book;
import com.bookReview.app.service.BookService;


@Controller
public class BookController {

    private BookService  bookService;

    @Autowired(required=true)
    @Qualifier(value="bookService")
    public void setBookService(BookService bs){
        this.bookService = bs;
    }

    @RequestMapping(value = "/books", method = RequestMethod.GET)
    public String listBooks(Model model) {
        model.addAttribute("book", new book());
        model.addAttribute("listBooks", this.bookService.listBooks());
        return "book";
    }

    //For add and update book both
        @RequestMapping(value= "/book/add", method = RequestMethod.POST)
        public String addBook(@ModelAttribute("book") book b){

            if(b.getBookid() == 0){
                //new book, add it
                this.bookService.addBook(b);
            }else{
                //existing book, call update
                this.bookService.updateBook(b);
            }

            return "redirect:/books";

        }

        @RequestMapping("/remove/{id}")
        public String removeBook(@PathVariable("id") int id){

            this.bookService.removeBook(id);
            return "redirect:/books";
        }

         @RequestMapping("/edit/{id}")
            public String editBook(@PathVariable("id") int id, Model model){
                model.addAttribute("book", this.bookService.getBookById(id));
                model.addAttribute("listBooks", this.bookService.listBooks());
                return "book";
            }


}

Et voici mon fichier ReviewController.Java

package com.bookReview.app;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.bookReview.app.model.review;
import com.bookReview.app.service.ReviewService;


@Controller
public class ReviewController {

    private ReviewService  reviewService;

    @Autowired(required=true)
    @Qualifier(value="reviewService")
    public void setReviewService(ReviewService rs){
        this.reviewService = rs;
    }

    @RequestMapping(value = "/reviews", method = RequestMethod.GET)
    public String listReviews(Model model) {
        model.addAttribute("book", new review());
        model.addAttribute("listReviews", this.reviewService.listReviews());
        return "review";
    }

    //For add and update review both
    @RequestMapping(value= "/review/add", method = RequestMethod.POST)
    public String addReview(@ModelAttribute("review") review r){

        if(r.getId() == 0){
            //new review, add it
            this.reviewService.addReview(r);
        }else{
            //existing review, call update
            this.reviewService.updateReview(r);
        }

        return "redirect:/reviews";

    }

    @RequestMapping("/remove/{id}")
    public String removeReview(@PathVariable("id") int id){

        this.reviewService.removeReview(id);
        return "redirect:/reviews";
    }

     @RequestMapping("/edit/{id}")
        public String editReview(@PathVariable("id") int id, Model model){
            model.addAttribute("review", this.reviewService.getReviewById(id));
            model.addAttribute("listReviews", this.reviewService.listReviews());
            return "review";
        }


}

Je vous remercie 

25
Serban Gorcea

Tu devrais écrire 

@Controller("/review")
public class ReviewController {

et

@Controller("/book")
public class BookController {

parce que dans votre code vous avez les deux méthodes sans chemin explicite/unique pour le mappage (par exemple, si nous avons un appel/edit/1, il est impossible de déterminer clairement la méthode d'un contrôleur à partir de votre editBook BookController ou ReviewController editReview

36
Alexey Semenyuk

Si le problème concerne une méthode ambiguë, le problème devrait probablement être le @RequestMapping. Passez de @RequestMapping ( name = ...) à @RequestMapping ( value = ...)

@RequestMapping(name = "xxx.htm", method = RequestMethod.GET)

à 

@RequestMapping(value = "xxx.htm", method = RequestMethod.GET)
30
gilberto Nd

Pour moi, ajouter l'attribut "params" dans @RequestMapping a fonctionné comme indiqué

  @ResponseBody
  @RequestMapping(method = RequestMethod.GET, params = {"id"})
  public User getUserById(final @RequestParam(name="id", required = true) String Id)
    throws InvalidArgumentException {

    return userService.getUserById(UUID.fromString(Id));
  }

  /**
   * REST service endpoint.
   * @param name Unique name for the user in the system.
   * @return Object of type {@link User} if exists otherwise null.
   */
  @ResponseBody
  @RequestMapping(method = RequestMethod.GET, params = {"name"})
  public User getUserByName(final @RequestParam(name="name", required = true) String name)
    throws InvalidArgumentException {

    return userService.getUserByName(name);
  }

Cependant, l'ajout simultané des deux paramètres dans la chaîne de requête générera une erreur 500 avec le message suivant: 

Méthodes de gestionnaire ambiguë mappées pour le chemin HTTP

Dans ce cas, vous pouvez avoir une autre méthode de contrôleur prenant les deux paramètres, mais vous n’en utilisez qu’un, ce qui, à mon avis, n’est pas nécessaire. 

0
Shrikant Prabhu