Spring mvc 发现不明确的映射。无法映射控制器 bean 方法

Posted

技术标签:

【中文标题】Spring mvc 发现不明确的映射。无法映射控制器 bean 方法【英文标题】:Spring mvc Ambiguous mapping found. Cannot map controller bean method 【发布时间】:2015-07-09 01:47:45 【问题描述】:

我正在尝试构建一个应用程序,该应用程序可以列出数据库中的一些值,并在必要时使用 Spring 4 修改、添加、删除,我收到以下错误(仅当我的两个控制器文件,如果我从它可以工作的文件之一中删除注释,但我在控制台中收到一条消息“没有找到映射......在具有名称的调度程序servlet中......):

    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

这是我的 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>

这是我的 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>

这是我的 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>

这是我的 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";
            



这是我的 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";
        



谢谢

【问题讨论】:

哇。这是很多代码。你确定这是minimal complete verifiable example,强调最小?创建一个最小的示例可以帮助其他人更快地识别您的错误,也可以帮助您自己找到问题。 对不起,我试图提供尽可能多的信息,以便更容易地追踪问题。如果您注意 pom、web 和 servlet 上下文 xml 文件是必要的,因为可能存在错误,除此之外,您可以找到同样重要的错误日志和两个类文件,我可以将它们以完整格式放置,因为问题出在这两个文件的底部。还是谢谢 当我收到这个错误时,是因为我正在将 Spring Boot 升级到更新的版本。我不得不为控制器删除预先存在的“@Bean”,因为“@RestController”注释让 spring 已经创建了它! 【参考方案1】:

你应该写

@Controller("/review")
public class ReviewController 

@Controller("/book")
public class BookController 

因为在您的代码中,您有两种方法没有明确/唯一的映射路径(例如,如果我们有一个调用 /edit/1 ,则不可能从您的 editBook BookController 或 @987654324 清楚地确定控制器的方法@)

【讨论】:

非常感谢这是问题所在,首先我将 ReviewController 的“编辑”和“删除”的名称修改为“编辑评论”和“删除评论”,我不能t 将@Controller 更改为@Controller(/book) 所以我使用了@Controller(value="book"),我希望它是正确的。也许这是一个不同的春季版本。现在我只有控制台消息:No mapping found for HTTP request with URI [/BookReviewApp/] in DispatcherServlet with name 'servlet' 我不知道它是否与这个问题有关【参考方案2】:

如果问题是关于模棱两可的方法,可能@RequestMapping 应该是问题所在。 从 @RequestMapping(name =...) 更改为 @RequestMapping(value =...)

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

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

【讨论】:

这个答案是我在使用spring boot框架时对上述问题的解决方案。谢谢!【参考方案3】:

对我来说,在@RequestMapping 中添加“params”属性如图所示

  @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);
  

但是,在查询字符串中同时添加两个参数会给出 500 错误消息:

为 HTTP 路径映射的不明确的处理程序方法

在这种情况下,您可以使用另一种控制器方法同时获取两个参数,但只使用其中一个,我认为这是不必要的。

【讨论】:

【参考方案4】:

在我的例子中,我在 Spring Boot 应用程序的两个不同控制器中有两种方法,两者都具有相同的 @DeleteMapping("/detailbonadelete/id") // delete,我将其中一个更改为@DeleteMapping("/bonadelete/id") // delete,它可以工作。

如果你有同样的事情:

@PutMapping("/detailbonaupdate/id") // update

@PostMapping("/detailbonainsert") // insert

@GetMapping("/detailbonaidbon/idBona") // selectByBonaId

确保每个控制器都是唯一的。

【讨论】:

以上是关于Spring mvc 发现不明确的映射。无法映射控制器 bean 方法的主要内容,如果未能解决你的问题,请参考以下文章

Spring Batch Admin + Spring Boot - 不明确的映射。无法映射“org.springframework.batch.admin.web.JobController#1”方

java.lang.IllegalStateException:不明确的映射。无法映射方法

Spring MVC 实现 GET 请求下划线风格参数映射至驼峰风格的类

对于没有 XML 的 Spring MVC 中的双调度程序配置,URL 映射无法按预期工作

Spring MVC 请求映射不起作用

在 Spring MVC 中映射 Ajax 请求:不允许出现错误 405 方法