2016-03-09 35 views
0

JDK版本:1.7(最新更新) 春:3.2.16释放春:同一类的多个控制器实例

我有一个通用的控制器类,可重复使用的多重功能。由于这些需求的基于注解的方法的局限性,我正在使用基于XML的配置。另外,我禁用了XML中的组件扫描。

我配置了多个相同类的bean实例,并使用SimpleUrlHandlerMapping将URL映射到控制器。如果我在一次启用一个控制器的情况下测试该项目,则工作正常。然而,当启用所述第二实例,弹簧抱怨有以下错误:

ERROR: org.springframework.web.servlet.DispatcherServlet - Context initialization failed 
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 'deviceController' bean method 
public java.lang.String com.smvc.pr05.controllers.SearchController.search(java.util.Locale,org.springframework.ui.ModelMap) 
to {[],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'searchController' bean method 
public java.lang.String com.smvc.pr05.controllers.SearchController.search(java.util.Locale,org.springframework.ui.ModelMap) mapped. 
... 
Caused by: java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'installerController' bean method 
public java.lang.String com.smvc.pr05.controllers.SearchController.search(java.util.Locale,org.springframework.ui.ModelMap) 
to {[],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'deviceController' bean method 
public java.lang.String com.smvc.pr05.controllers.SearchController.search(java.util.Locale,org.springframework.ui.ModelMap) mapped. 
... 

我与范围=单和范围=原型控制器bean定义尝试过。我尝试过启用组件扫描(保留XML中手动定义的bean)并禁用相同的功能。错误仍然存​​在。

虽然这可能是固定的,但如果我为每个实例创建具体类,我真的想保留它作为最后一个选项。我对Spring的功能有很强的信念,因为我对非控制器类使用了类似的技术。

请让我知道,我错过了什么。

弹簧配置(EDITED与控制器单)

... 
<beans:bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
    <beans:property name="mappings"> 
     <beans:props> 
    <beans:prop key="/">homeController</beans:prop> 
    <beans:prop key="/deviceSearch/">deviceController</beans:prop> 
    <beans:prop key="/installerSearch/">installerController</beans:prop> 
    <beans:prop key="/customerSearch/">customerController</beans:prop> 
     </beans:props> 
    </beans:property> 
</beans:bean> 
... 
<beans:bean id="homeController" class="com.smvc.pr05.controllers.HomeController" > 
</beans:bean> 
<beans:bean id="deviceController" class="com.smvc.pr05.controllers.SearchController"> 
    <beans:property name="metaModel" ref="deviceModel"/> 
    <beans:property name="searchService" ref="deviceService" /> 
</beans:bean> 
<beans:bean id="installerController" class="com.smvc.pr05.controllers.SearchController" > 
    <beans:property name="metaModel" ref="installerModel"/> 
    <beans:property name="searchService" ref="installerService" /> 
</beans:bean> 
<beans:bean id="customerController" class="com.smvc.pr05.controllers.SearchController" > 
    <beans:property name="metaModel" ref="customerModel"/> 
    <beans:property name="searchService" ref="customerService" /> 
</beans:bean> 

Java的控制器类:

... 
@Controller 
public class SearchController { 

    private static final Logger LOG = LoggerFactory.getLogger(SearchController.class); 

    private SearchService searchService; //Has explicit set() method 

    private MetaModel metaModel; //Has explicit set() method 

    @SuppressWarnings({ "unchecked" }) 
    @RequestMapping(method = RequestMethod.POST) 
    public String search(Locale locale, ModelMap modelMap) { 
     ... 
    } 

    public void setSearchService(SearchService searchService) { 
     this.searchService = searchService; 
    } 

    public void setMetaModel(MetaModel metaModel) { 
     this.metaModel = metaModel; 
    } 
} 
+0

为什么你这样做?控制器意味着单身。你想要达到什么目的? –

+0

在上述情况下,请忽略属性范围。它被添加用于测试目的。基本上,控制器是单身人士。根据bean定义设置的属性,我可以使用相同的控制器来服务多个功能。例如,如果设置了“deviceModel”,则控制器将搜索设备。 – ajoshi

+0

你在xml配置中使用''吗? –

回答

0

似乎是部件扫描仍在工作。因为有人根据@Controller注释创建了SearchController的实例。这就是为什么你得到Cannot map 'deviceController' bean method

另一个问题是,如果在xml config中使用<mvc:annotation-driven/>,mvc引擎将查找标有@Controller注释的所有bean,并将根据方法注释试图映射此bean。因为你有三个同类控制器,并且这个类标记为@Controller,所以mvc引擎会尝试映射所有这些控制器。由于它们将具有相同的方法注释,因此它们将映射到相同的路径(在您的情况下它是空路径)。这就是为什么你得到Cannot map 'installerController' bean method

两种情况下的解决方案:从SearchController类删除@Controller注释。

+0

谢谢。我已经禁用了标记,并添加了下面ekem chitsiga指定的AnnotationMethodHandlerAdapter。它正在工作。 – ajoshi

0

控制器只是一个与组件扫描结合使用的刻板印记。这里的罪魁祸首是@RequestMapping,它将所有方法映射到相同的url。为了让你的配置工作,删除<mvc:annotation-driven/>元素,该元素注册一个RequestMappingHandlerMapping bean,它使用@RequestMapping进行URL映射。现在你的SimpleUrlHandlerMapping将被用来代替通过mvc配置的那个:注解驱动或者@EnableWebMvc

但是你需要注册一个HandlerAdapter,它知道如何处理@RequestMapping方法,比如org.springframework.web.servlet.mvc 。注解。AnnotationMethodHandlerAdapter上

如下

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/> 
+0

谢谢你的帮助。添加完成后,它现在正在工作。但是,在Spring 3.2.16中,这个类似乎已被弃用。有没有其他的课程? – ajoshi

+0

AnnotationMethodHandlerAdapter被org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter所取代 –

1

的主要问题是,使用@Controller<mvc:annotation-driven />时就是RequestMappingHandlerMappingRequestMappingHandlerAdapter会一命呜呼第一个将检测所有@Controller注解的bean以及基于@RequestMapping创建一个映射为了它。

由于您已经注册了3个相同类型的bean,它将导致3个相同的映射,因此它会停止并告诉您这个异常。基本上,随着RequestMappingHandlerAdapter/RequestMappingHandlerMapping的引入,使用SimpleUrlHandlerMapping的能力和选择该方法的注释方式丢失了。

然而,您可以删除<mvc:annotation-driven />并添加AnnotationMethodHandlerAdapter,但该类或多或少被弃用(至少在未来的Spring版本中将被删除)。

我会建议使用旧的可靠接口而不是注释。你只有一个你想使用的方法,因此使用旧的支持类是一个可行的选择。

public class SearchController extends AbstractController { 

    private static final Logger LOG = LoggerFactory.getLogger(SearchController.class); 

    private SearchService searchService; //Has explicit set() method 

    private MetaModel metaModel; //Has explicit set() method 

    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception; 

     if (!("post".equalsIgnoreCase(request.getMethod()))) { 
      return null; // or throw exception or .... 
     } 
     final Locale locale = LocaleContextHolder.getLocale(); // retrieve current locale. 

     ModelAndView mav = new ModelAndView("your-view"); 
     // prepare your model instead of adding to ModelMap 
     mav.addObject("name", object); 
     return mav; 
    } 
    // Omitted setters. 
} 

这将防止踢注释扫描并保存你从重构(再次)当您升级到版本春是删除过时的类。

相关问题