2016-03-09 32 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. 
} 

這將防止踢註釋掃描並保存你從重構(再次)當您升級到版本春是刪除過時的類。

相關問題