springmvc controller 的继承问题
一、问题
在书写controller时 我们一般会先定义一个baseController,里面设置获取一些通用业务信息,比如获取当前登录用户信息等。
这种情况下的baseController里 ,不会做RequestMapping 也就是web请求不会直接到这个父类,这种继承是不会有任何问题的。
@Component
public class BaseController
* 获取当前用户对象
* @return
protected ShiroUser getCurrentUser() {
return (ShiroUser) SecurityUtils.getSubject().getPrincipal();
当有些业务的controller 也需要被继承呢,类似这种 带有requestMapping 注解
@Controller
@RequestMapping("/misSync")
public class MisSyncController extends BaseController {
如果我们写一个这样的业务类来继承它
@Controller
@RequestMapping("/misSync/")
public class MisSyncZYJController extends MisSyncController {
那么就会有惊喜
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'misSyncZYJController' method
public com.onlyou.mis.ext.bo.ResponseResultBO com.onlyou.mis.sas.web.MisSyncController.syncCorpInfo(com.onlyou.mis.ext.bo.MisSyncBO)
to {[/misSync/syncCorpInfo.json],methods=[POST]}: There is already 'misSyncController' bean method
public com.onlyou.mis.ext.bo.ResponseResultBO com.onlyou.mis.sas.web.MisSyncController.syncCorpInfo(com.onlyou.mis.ext.bo.MisSyncBO) mapped.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1583)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.addCandidateEntry(DefaultListableBeanFactory.java:1286)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1255)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveMultipleBeans(DefaultListableBeanFactory.java:1161)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1086)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
... 33 common frames omitted
Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'misSyncZYJController' method
简单说 就会告诉你 模糊的映射 也就是无法确定请求分配到哪个controller的方法
容易看出子类MisSyncZYJController 继承了MisSyncController 连带requestMapping 也设为一样,requestMapping 可以理解为请求派发的命名空间,相同的空间里,子类享有父类protected及其以上的访问权限,当容器启动做方法请求映射时,就会发现父类的一般请求方法,全部都没有明确派发地址了。
1、隔离命名空间,这是最简单的,直接把子类的requestMapping 多一级或者换个名称
@Controller
@RequestMapping("/misSync/zyj/")
public class MisSyncZYJController extends MisSyncController {
@Controller
@RequestMapping("/misSyncZYJ/")
public class MisSyncZYJController extends MisSyncController {
2、 放弃继承带有requestMapping的一般业务类,而只继承没有请求派发的一般父类,类似上文提到的baseController
3、带有疑问的不可行方案,技术上讲,如果把父类的方法设置为private(private方法不影响web请求派发),子类是不可访问的,那么我们不改requestMapping,把有问题的业务父类方法设置成private时可以吗,答案是 no
@RequestMapping(value = "/syncOrg.json", method = RequestMethod.POST)
@ResponseBody
private ResponseResultBO syncOrg(@RequestBody MisSyncBO misSyncBO) {
Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'misSyncZYJController' method
private com.onlyou.mis.ext.bo.ResponseResultBO com.onlyou.mis.sas.web.MisSyncController.syncOrg(com.onlyou.mis.ext.bo.MisSyncBO)
to {[/misSync/syncOrg.json],methods=[POST]}: There is already 'misSyncController' bean method
看到尽管已经标记为private ,依然还是报模糊的映射规则。
不过话说回来 就算这个方案技术可行,也是不符合主流规范的,纯粹测试,至于原因 有待深究。
如果两个没有关联 或者说并行的controller想用一样的映射空间 比如'/misSync', 可以吗,答案是没问题的。
只是在找请求的时候,本来只要在一个misSync对应的controller里找,现在变成要找其他也标记为misSync的controller,如果一个controller已经非常庞大,命名空间也不能改,确实也可以考虑这样拆分一部分出去。
当然最好还是一个命名空间一个controller,方便跟踪请求了。