簡體   English   中英

Spring MVC:與多個Dispatchers一起發現的模糊映射

[英]Spring MVC: Ambiguous mapping found with multiple Dispatchers

我正在使用Spring4構建WebApplication。 WebApplication Dispatcher映射到/ app / *,因為我有第二個用於REST服務的Spring Dispatcher with mapping / services / *

當我嘗試啟動WebApplication Spring拋出異常(發現模糊映射),因為我在兩個不同的控制器中有相同的映射(“/ persons”)。 這是正確的,我在WebApplication中的Controller中有這個映射,在RestController中有相同的映射。 但控制器在不同的Dispatchers中具有不同的調度程序映射。 有沒有辦法解釋Spring這個映射是否正確? 或者這是我自己的錯誤,我走的路是完全錯誤的?

Jetty的輸出(刪除一些不需要的東西):

INFO: Root WebApplicationContext: initialization started
INFO: Mapped "{[/home],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView io.theoperator.controller.Home.showMessage()
INFO: Mapped "{[/home],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView io.theoperator.controller.Home.showMessage()
INFO: Mapped "{[/persons],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView io.theoperator.controller.PersonController.list()
INFO: Mapped "{[/persons],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView io.theoperator.controller.PersonController.save(io.theoperator.model.Person)
INFO: Root WebApplicationContext: initialization completed in 1319 ms
INFO: FrameworkServlet 'serviceapplication': initialization started
INFO: Mapped "{[/persons/page],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.util.Map<java.lang.String, java.lang.Object> io.theoperator.restservice.PersonServiceController.getPage(java.lang.String,java.lang.String,java.lang.String,java.lang.String)
INFO: Mapped "{[/persons],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public io.theoperator.restservice.PersonServiceController$PersonList io.theoperator.restservice.PersonServiceController.getAll()
INFO: Mapped "{[/persons/{id}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public io.theoperator.model.Person io.theoperator.restservice.PersonServiceController.getPerson(java.lang.String)
Mar 01, 2015 12:36:03 PM org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping registerHandlerMethod
INFO: Mapped "{[/persons/page],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.util.Map<java.lang.String, java.lang.Object> io.theoperator.restservice.PersonServiceController.getPage(java.lang.String,java.lang.String,java.lang.String,java.lang.String)
Mar 01, 2015 12:36:03 PM org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping registerHandlerMethod
INFO: Mapped "{[/persons],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public io.theoperator.restservice.PersonServiceController$PersonList io.theoperator.restservice.PersonServiceController.getAll()
Mar 01, 2015 12:36:03 PM org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping registerHandlerMethod
INFO: Mapped "{[/persons/{id}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public io.theoperator.model.Person io.theoperator.restservice.PersonServiceController.getPerson(java.lang.String)
Mar 01, 2015 12:36:03 PM org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping registerHandlerMethod
INFO: Mapped "{[/home],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView io.theoperator.controller.Home.showMessage()
Mar 01, 2015 12:36:03 PM org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping registerHandlerMethod
INFO: Mapped "{[/persons/{id}],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.web.servlet.ModelAndView io.theoperator.controller.PersonController.details(java.lang.String)
Mar 01, 2015 12:36:03 PM org.springframework.web.context.support.AnnotationConfigWebApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'personController' bean method 
public org.springframework.web.servlet.ModelAndView io.theoperator.controller.PersonController.list()
to {[/persons],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'personServiceController' bean method
public io.theoperator.restservice.PersonServiceController$PersonList io.theoperator.restservice.PersonServiceController.getAll() mapped.
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
    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:762)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:663)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:535)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:489)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:244)
    at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:613)
    at org.eclipse.jetty.servlet.ServletHolder.initialize(ServletHolder.java:396)
    at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:871)
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:341)
    at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1343)
    at org.eclipse.jetty.maven.plugin.JettyWebAppContext.startWebapp(JettyWebAppContext.java:296)
    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1336)
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:742)
    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:499)
    at org.eclipse.jetty.maven.plugin.JettyWebAppContext.doStart(JettyWebAppContext.java:365)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:163)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
    at org.eclipse.jetty.server.Server.start(Server.java:399)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
    at org.eclipse.jetty.server.Server.doStart(Server.java:366)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:516)
    at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:359)
    at org.eclipse.jetty.maven.plugin.JettyRunMojo.execute(JettyRunMojo.java:167)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:355)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:155)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:584)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:216)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:160)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
    at org.codehaus.classworlds.Launcher.main(Launcher.java:47)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

這是我的WebApplication的WebApplicationInitializer:

public class WebApplicationInitializer implements org.springframework.web.WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {

    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(WebApplicationConfiguration.class);

    container.addListener(new ContextLoaderListener(rootContext));

    ServletRegistration.Dynamic dispatcher = container.addServlet("webapplication", new DispatcherServlet(rootContext));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/app/*");

}
}

這是我用於REST服務的WebApplicationInitializer

public class ServiceApplicationInitializer implements org.springframework.web.WebApplicationInitializer {

@Override
public void onStartup(ServletContext container) {

    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(ServiceApplicationConfiguration.class);

    ServletRegistration.Dynamic dispatcher = container.addServlet("serviceapplication", new DispatcherServlet(rootContext));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/services/*");

}
}

以下是調度員的配置:

@EnableWebMvc
@ComponentScan(basePackages = {
        "io.theoperator.controller",
        "io.theoperator.service",
        "io.theoperator.repository",
        "io.theoperator.configuration",
})
@Configuration
public class WebApplicationConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/pages/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

}

@EnableWebMvc
@ComponentScan(basePackages = {
        "io.theoperator.service",
        "io.theoperator.repository",
        "io.theoperator.configuration",
        "io.theoperator.restservice"
})
public class ServiceApplicationConfiguration extends WebMvcConfigurerAdapter {



}

在我的WebApplication中,我有這個控制器:

@Controller
@RequestMapping("/persons")
public class PersonController {

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView list() {
        return new ModelAndView("persons/list");
    }
}

在我的ServiceApplication中,我有一個RestController:

@RestController
@RequestMapping("/persons")
public class PersonServiceController {
@RequestMapping(method = RequestMethod.GET)
    public PersonList getAll() {
        return new PersonList(this.personService.list());
    }
}

編輯

我已經刪除了ContextLoaderListener magnama建議的方式。 但錯誤實際上是一樣的。

這里 (Pastebin)是Spring的完整輸出。 我認為有些事情是非常錯誤的。 Spring首先從serviceapplication上下文開始,並注冊/ home(來自HomeController),它是WebApplication的一部分。 HomeController是在io.theoperator.controller包中,它不是 ServiceApplicationConfiguration的ComponentScan的一部分...目前我不知道有什么問題...

感謝所有人。
我發現了我的錯誤!
我創建了一個只有七個文件的新項目:2個初始化器,2個配置,2個控制器和1個RestController,我已經重現了相同的情況。
我的錯誤是將Initializers和Configurations全部放在同一個包“io.theoperator.configuration”中。
拆分為“io.theoperator.configuration.web”和“io.theoperator.configuration.service”並調整Configurations中的ComponentScan之后,Service Application僅映射RestControllers

我在github上創建了一個存儲庫: github.com上的Project foo
主分支是工作分支和分支錯誤,具有不明確的映射錯誤。

特別感謝Magnamag和Pavel的雙重掃描技巧! ;)

關於jomikel

我正在尋找解決我遇到的同樣問題,並在閱讀你的帖子后得到一個解決方案沒有將配置文件拆分到不同的文件夾。

annotation in config classes to avoid mess. 主要思想:當您為每個servlet顯式提供配置類時 - 在配置類中刪除注釋以避免混亂。

假設我們有一個應用程序,提供與用戶數據庫一起使用的WEB和REST服務。 所以REST端點是http:// blah-blah-blah / rest和web - http:// blah-blah-blah / web 在這兩種情況下,當我們想要獲得時,即用戶列表 - 我們分別訪問... / rest / users或... / web / users; 對於選定的用戶地址將是... / rest / users / 1或... / web / users / 1等.App init類和配置類在同一個包中,REST和WEB控制器在rest和web包中,分別

App init:

public class AppInitializer implements WebApplicationInitializer  {

@Override
public void onStartup(ServletContext container) throws ServletException {
    // Create the 'root' Spring application context
      AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
      rootContext.register(RootConfig.class);
      //data access layer
      rootContext.register(DataConfig.class);
      // Manage the lifecycle of the root application context
      container.addListener(new ContextLoaderListener(rootContext));

      //--------WEB--------------         

      // Create web dispatcher servlet's application context
      AnnotationConfigWebApplicationContext webDispatcherContext = 
              new AnnotationConfigWebApplicationContext();
      webDispatcherContext.register(WebDispatcherConfig.class);

      // Register and map web dispatcher servlet
      ServletRegistration.Dynamic webDispatcher =
              container.addServlet("webDispatcher", new DispatcherServlet(webDispatcherContext));
      webDispatcher.setLoadOnStartup(1);
      webDispatcher.addMapping("/web/*");

      //--------REST-------------        

      // Create rest dispatcher servlet's application context
      AnnotationConfigWebApplicationContext restDispatcherContext = 
              new AnnotationConfigWebApplicationContext();
      restDispatcherContext.register(RESTDispatcherConfig.class);

      // Register and map rest dispatcher servlet
      ServletRegistration.Dynamic restDispatcher =
              container.addServlet("restDispatcher", new DispatcherServlet(restDispatcherContext));
      restDispatcher.setLoadOnStartup(1);
      restDispatcher.addMapping("/rest/*");

}

網絡配置:

@EnableWebMvc
@ComponentScan("io.github.d2edev.mywebapp.web")
public class WebDispatcherConfig extends WebMvcConfigurerAdapter {

@Bean
public ViewResolver viewResolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/WEB-INF/jsp/");
    resolver.setSuffix(".jsp");
    resolver.setExposeContextBeansAsAttributes(true);
    return resolver;
}



@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
}

休息-配置:

@EnableWebMvc
@ComponentScan("io.github.d2edev.mywebapp.rest")
public class RESTDispatcherConfig {

}

網絡控制器:

@Controller
@RequestMapping("/users")
public class UserController {

private UserRepository userRepository;

@Autowired
public UserController(UserRepository userRepository) {
    this.userRepository=userRepository;
}

//list all
@RequestMapping(method=RequestMethod.GET)
public String listAllUsers(Model model){
    model.addAttribute("userList", userRepository.findAll());
    return "user/users";
}

//show registration form
@RequestMapping(value="/newUser", method=RequestMethod.GET)
public String showRegistrationForm(){
    return "user/newUser";
}

//other methods here...

}

休息控制器:

@RestController
@RequestMapping("/users")
public class UserControllerREST {

// data source
private UserService userService;

@Autowired
public UserControllerREST(UserService userService) {
    this.userService = userService;
}

// get all
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<User>> getAllUsers() {
    List<User> users = userService.getAll();
    if (users.isEmpty()) {
        return new ResponseEntity<List<User>>(HttpStatus.NO_CONTENT);
    }
    return new ResponseEntity<List<User>>(users, HttpStatus.OK);

}

//other methods to follow...
}

希望它能幫助別人,至少......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM