Spring MVC @RequestMapping继承

gar*_*ryj 34 java spring-mvc

来自Struts2我习惯于@Namespace在超类(或package-info.java)上声明注释,继承类随后将获取@Namespace其祖先注释中的值,并将其添加到Action的请求路径中.我现在尝试使用@RequestMapping注释在Spring MVC中执行类似的操作,如下所示(为简洁起见,代码已修剪):

package au.test

@RequestMapping(value = "/")
public abstract class AbstractController {
    ...
}

au.test.user

@RequestMapping(value = "/user")
public abstract class AbstractUserController extends AbstractController {

    @RequestMapping(value = "/dashboard")   
    public String dashboard() {
        ....
    }
}

au.test.user.twitter

@RequestMapping(value = "/twitter")
public abstract class AbstractTwitterController extends AbstractUserController {
    ...
}

public abstract class TwitterController extends AbstractTwitterController {

    @RequestMapping(value = "/updateStatus")    
    public String updateStatus() {
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)
  • / 按预期工作
  • /user/dashboard 按预期工作
  • 但是,当我希望/user/twitter/updateStatus工作时它没有并检查日志我可以看到一个类似于的日志条目:

org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - 映射的URL路径[/ tweeter/updateStatus]到处理程序'twitterController'上

是否有一个我可以启用的设置,它将扫描超类的@RequestMapping注释并构造正确的路径?

另外我认为@RequestMapping在包装上定义package-info.java是非法的?

chr*_*ris 27

以下基本上变成了/tweeter/updateStatus而不是/user/tweeter/updateStatus

public abstract class TwitterController extends AbstractTwitterController {

    @RequestMapping(value = "/updateStatus")    
    public String updateStatus() {
        ....
    }
}
Run Code Online (Sandbox Code Playgroud)

这是预期的行为,因为你已经覆盖了@RequestMapping你在AbstractController和中声明的原始内容AbstractUserController.

事实上,当你声明AbstractUserController它也覆盖了@RequestMappingfor AbstractController.它只是给你一种幻觉,即来自AbstractController遗传.

"我可以启用@RequestMapping哪个设置来扫描超类的注释并构建正确的路径?" 从来没听说过.

  • 你有没有机会得到任何其他建议如何实现这一目标.在我看来,浪费不得不将/ x/y/z放在子类环境中.然后如果我决定将/ x /更改为/ k /我必须转到定义它的代码中的所有位置并手动更改它! (8认同)

igo*_*.zh 5

根据在启动修改@RequestMappings中介绍的技术,可以,可以用您想要的方式从超类构造URL模式。

本质上,您必须将RequestMappingHandlerMapping子类化(很可能是您的HandlerMapping实现,但是请先检查),然后重写受保护的getMappingForMethod方法。一旦这变得可行,就可以完全控制URL模式的生成。

从您给出的示例中,您还不能完全清楚确切的合并策略,例如,如果超类AbstractTwitterControllerupdateStatus()使用自己的方法实现方法,那么您想要的路径是什么@RequestMapping,或者您想如何在整个层次结构中串联URL模式,自上而下或自下而上((我假设是前者),但是,希望以下片段能给您一些想法:

    private static class PathTweakingRequestMappingHandlerMapping extends RequestMappingHandlerMapping {

                @Override
                protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
                    RequestMappingInfo methodMapping = super.getMappingForMethod(method, handlerType);
                    if (methodMapping == null)
                        return null;
                    List<String> superclassUrlPatterns = new ArrayList<String>();
                    boolean springPath = false;
                    for (Class<?> clazz = handlerType; clazz != Object.class; clazz = clazz.getSuperclass())
                        if (clazz.isAnnotationPresent(RequestMapping.class))
                            if (springPath)
                                superclassUrlPatterns.add(clazz.getAnnotation(RequestMapping.class).value()[0]);// TODO handle other elements in the array if necessary
                            else
                                springPath = true;
                    if (!superclassUrlPatterns.isEmpty()) {
                        RequestMappingInfo superclassRequestMappingInfo = new RequestMappingInfo("",
                                new PatternsRequestCondition(String.join("", superclassUrlPatterns)), null, null, null, null, null, null);// TODO implement specific method, consumes, produces, etc depending on your merging policies
                        return superclassRequestMappingInfo.combine(methodMapping);
                    } else
                        return methodMapping;
                }
    }
Run Code Online (Sandbox Code Playgroud)

另一个好问题是如何截获的实例化RequestMappingHandlerMapping。在Internet中,有许多用于各种配置策略的示例。但是,使用JavaConfig时,请记住,如果您WebMvcConfigurationSupport@Configuration集合中提供,则@EnableWebMvc(显式或隐式)将停止工作。我得出以下结论:

@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration{

    @Configuration
    public static class UnconditionalWebMvcAutoConfiguration extends WebMvcAutoConfiguration {//forces @EnableWebMvc 
    }

    @Override
    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
        return new PathTweakingRequestMappingHandlerMapping();
    }

    @Bean
    @Primary
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping() { 
        return super.requestMappingHandlerMapping();
    }

}
Run Code Online (Sandbox Code Playgroud)

但想了解更好的方法。