【问题标题】:Mapping a single controller to several beans in spring在 spring 中将单个控制器映射到多个 bean
【发布时间】:2013-10-08 08:44:25
【问题描述】:

我需要使用单个控制器类为具有不同 ID 的静态页面创建多个 bean,该控制器类具有定义要显示的 jsp 名称的属性。

我曾经使用 FormControllers 对旧版本执行此操作,但在 3.2.4 版本中不能 我检查了几个主题并了解 Spring bean 是单例的,但是 我想知道这是否可行,或者是否有一种解决方法,无需为每个页面创建空控制器类。

这是 BaseController 类:

    public class BaseController extends AbstractController {

    public String contentPage;

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView mv = new ModelAndView("common/mainlayout");

        if(contentPage != null && !contentPage.equals("")){
            mv.addObject("mainContent", "maincontent/" + contentPage);
            mv.addObject("mainMenuSelect", contentPage);
        }

        return mv;
    }

    public String getContentPage() {
        return contentPage;
    }
    public void setContentPage(String contentPage) {
        this.contentPage = contentPage;
    }
}

这是我在 spring-servlet.xml 中的映射注意,我还尝试使用我的 BaseController 定义每个 bean 的类

<bean id="urlMapping"
    class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>

            <!-- STATIC PAGES -->
            <prop key="/index.dlg">indexPageController</prop>
            <prop key="/faq.dlg">faqController</prop>
            <prop key="/howto.dlg">howtoController</prop>
            <prop key="/contactUs.dlg">contactUsController</prop>
            <prop key="/aboutUs.dlg">aboutUsController</prop>

            <!-- DYNAMIC PAGES -->
            <prop key="/postBox.dlg">postBoxController</prop>
            <prop key="/invoiceBox.dlg">invoiceController</prop>
        </props>
    </property>

    <property name="interceptors">
        <list>
            <ref bean="siteInterceptor" />
        </list>
    </property>

</bean>

<bean id="siteInterceptor" class="com.entegrator.spring.interceptor.SiteInterceptor"></bean>

<!-- STATIC PAGE CONTROLLERS -->
<bean id="baseController" abstract="true" class="com.entegrator.spring.controller.BaseController" />

<bean id="indexPageController" parent="baseController" >
    <property name="contentPage" value="index" />
</bean>

<bean id="faqController" parent="baseController" >
    <property name="contentPage" value="faq" />
</bean>

<bean id="howtoController" parent="baseController" >
    <property name="contentPage" value="howto" />
</bean>

<bean id="contactUsController" parent="baseController" >
    <property name="contentPage" value="contactUs" />
</bean>

<bean id="aboutUsController" parent="baseController" >
    <property name="contentPage" value="aboutUs" />
</bean>
<!-- STATIC PAGE CONTROLLERS END -->


<!-- DYNAMIC PAGE CONTROLLERS -->
<bean id="postBoxController" class="com.entegrator.spring.controller.PostBoxController">
    <property name="postBoxManager" ref="postBoxManager" />
</bean>
<bean id="invoiceController" class="com.entegrator.spring.controller.InvoiceController">
    <property name="postBoxManager" ref="postBoxManager" />
</bean>
<!-- DYNAMIC PAGE CONTROLLERS END -->

我的 web.xml 是:

<display-name>EntegratorPortal</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>


    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>*.dlg</url-pattern>
    </servlet-mapping>

这是我的错误日志:

 SEVERE: StandardWrapper.Throwable
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping#0' defined in ServletContext resource [/WEB-INF/spring-servlet.xml]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Cannot map handler 'faqController' to URL path [/base*]: There is already handler 'indexPageController' mapped.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:651)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:599)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:665)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:518)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:459)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:160)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1280)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1193)
    at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:865)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:136)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.IllegalStateException: Cannot map handler 'faqController' to URL path [/base*]: There is already handler 'indexPageController' mapped.
    at org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.registerHandler(AbstractUrlHandlerMapping.java:294)
    at org.springframework.web.servlet.handler.AbstractUrlHandlerMapping.registerHandler(AbstractUrlHandlerMapping.java:266)
    at org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping.detectHandlers(AbstractDetectingUrlHandlerMapping.java:82)
    at org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping.initApplicationContext(AbstractDetectingUrlHandlerMapping.java:58)
    at org.springframework.context.support.ApplicationObjectSupport.initApplicationContext(ApplicationObjectSupport.java:119)
    at org.springframework.web.context.support.WebApplicationObjectSupport.initApplicationContext(WebApplicationObjectSupport.java:72)
    at org.springframework.context.support.ApplicationObjectSupport.setApplicationContext(ApplicationObjectSupport.java:73)
    at org.springframework.context.support.ApplicationContextAwareProcessor.invokeAwareInterfaces(ApplicationContextAwareProcessor.java:117)
    at org.springframework.context.support.ApplicationContextAwareProcessor.postProcessBeforeInitialization(ApplicationContextAwareProcessor.java:92)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:396)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1475)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    ... 32 more

感谢您的帮助

【问题讨论】:

  • 为什么他们需要请求范围?!那里没有任何东西需要请求范围,所以为什么这会增加复杂性。没有什么能阻止你做你想做的事,但你也有一个ControllerClassNameHandlerMapping 在某个地方也检测到控制器(再次?)。至少有些东西会导致重复映射。
  • 我删除了范围参数,反正只是在测试它。我猜你关于额外处理程序的建议是由于 url 警告(URL 路径 [/base*]),你可能是对的。但是我没有添加任何额外的处理程序。我刚刚添加了所有 spring jar 以确保我尽可能快地创建项目。有没有办法检查我是否有额外的控制器处理程序并将其删除?
  • 在某处配置了ControllerClassNameHandlerMapping,但是您只能将单个控制器映射到 URL。
  • 好的,我找到了,在 spring-servlet.xml 的某个地方有一个 ControllerClassNameHandlerMapping 的定义,来自我忘记删除的旧代码。完全是我的错 :( 没有你就无法注意到它.. 谢谢
  • 好吧,堆栈跟踪清楚地表明ControllerClassNameHandlerMapping 无法正确启动,因此它一定来自某个地方。

标签: java spring spring-mvc


【解决方案1】:

难道您不能在每个页面的一个控制器中简单地使用 @RequestMapping(value="/foo" method="RequestMethod.GET") 注释方法吗?

这似乎是最简单的解决方案。

你的控制器看起来像这样:

@Controller
public class BaseController
{

    @RequestMapping(value="/index", method="RequestMethod.GET")
    public String returnIndexPage()
    {
        return "Your Index JSP Page Location Here";
    }

    @RequestMapping(value="/faq", method="RequestMethod.GET")
    public String returnFAQPage()
    {
         return("Your FAQ JSP Page Location Here";
    }

等等……

如果您愿意,您可以将其修改为仅返回您的内容页面变量。

当然也可以。

让我知道你过得怎么样。

【讨论】:

  • 我创建这个项目的方式是我们所有项目的标准方式,所以我没有太多选择使用这个解决方案,除非我真的必须这样做,但我会记住它。
【解决方案2】:

为什么不利用新的 spring @Controller@RequestMapping 注释呢?这样你只需要一个控制器。

@Controller
public class StaticController {


    @RequestMapping({"/index.dlg", "/howto", // The rest of your mappings}
    public String handleStatic(HttpServletRequest request, Model model) {
        String contentPage = //Extract page-name from request 
        model.addObject("mainContent", "maincontent/" + contentPage);
        model.addObject("mainMenuSelect", contentPage);  
        return "common/mainlayout";      
    }
}

然后可以使用RequestMappingHandlermapping 检测和设置此控制器,并由RequestMappingHandlerAdapter 执行(这些控制器在您的xml 配置中使用&lt;mvc:annotation-driven /&gt; 注册)。

或者利用 springs 视图控制器 (&lt;mvc:view-controller .. /&gt;) 并添加一个拦截器来为模型添加所需的属性

<mvc:view-controller path="/index.dlg" view-name="common/mainlayout" />
<mvc:view-controller path="/faq.dlg" view-name="common/mainlayout" />

<mvc:interceptors>
    <mvc:interceptor>
        <mapping path="/index.dlg" />
        <mapping path="/faq/dlg" />
        <bean class="YourInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

这种方法的缺点是您基本上是在复制您的映射(一次用于控制器,一次用于拦截器)。

链接

  1. 实现控制器reference guide
  2. 查看控制器reference guide
  3. 配置拦截器reference guide

【讨论】:

    猜你喜欢
    • 2018-06-28
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多