我正在使用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/*");
}
}
以下是Dispatchers的配置:
@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());
}
}
修改
我已删除了关于magnama建议的ContextLoaderListener。但错误实际上是一样的。
Here(Pastebin)是Spring的完整输出。我认为有些事情是非常错误的。 Spring首先从serviceapplication上下文开始,并注册/ home(来自HomeController),它是WebApplication的一部分。 HomeController在io.theoperator.controller包中,它是不 ServiceApplicationConfiguration的ComponentScan的一部分...... 目前我不知道出了什么问题......
答案 0 :(得分:0)
所有人的权利。
我发现了我的错误!
我创建了一个只有七个文件的新项目:
2个初始化器,2个配置,2个控制器和1个RestController,我再现了相同的情况
我的错误是将初始化程序和配置全部放在同一个程序包中,#i ;.operator.configuration&#34;。
分裂为&#34; io.theoperator.configuration.web&#34;和&#34; io.theoperator.configuration.service&#34;并在配置中调整ComponentScan,服务应用程序仅映射RestControllers
我在github上创建了一个存储库:Project foo on github.com
主分支是工作分支和分支错误,具有不明确的映射错误。
特别感谢Magnamag和Pavel的双重扫描提示! ;)
问候 jomikel
答案 1 :(得分:0)
正在寻找解决我遇到的同样问题,在阅读完帖后得到了一个解决方案,没有将配置文件拆分到不同的文件夹。
主要思路:当您为每个servlet显式提供配置类时 - 在配置类中删除 @Configuration 注释以避免混乱。
假设我们有一个应用程序,提供与用户数据库一起使用的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/*");
}
web的配置:
@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...
}
希望它能帮助别人,至少......