2011-03-11 122 views
27

來自Struts2我習慣於在超類(或package-info.java)上聲明@Namespace註解,並且繼承類將隨後選取其祖先的@Namespace註釋中的值並將其預先加載到請求路徑爲行動。我現在要做的使用@RequestMapping註釋在Spring MVC類似如下(修剪簡碼):Spring MVC @RequestMapping繼承

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() { 
     .... 
    } 
} 
  • /作品預計
  • /user/dashboard按預期工作
  • 然而,當我想預計/user/twitter/updateStatus工作它沒有和檢查日誌我可以看到一個日誌條目,看起來像這樣:

org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - 映射的URL路徑[/高音/ updateStatus]在處理 'twitterController'

是否有設置我可以啓用將掃描超類爲@RequestMapping註釋並構建正確的路徑?

另外我還認爲在package-info.java的封裝上定義@RequestMapping是非法的?

回答

24

以下基本上成爲/tweeter/updateStatus,而不是/user/tweeter/updateStatus

public abstract class TwitterController extends AbstractTwitterController { 

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

這是預期的行爲,因爲你已經重寫你聲明的原始@RequestMappingAbstractControllerAbstractUserController

實際上,當您聲明AbstractUserController時,它也覆蓋@RequestMappingAbstractController。它只是給你一個錯覺,認爲AbstractController已被繼承。

「是否有可以啓用的設置,將掃描@RequestMapping批註的超類並構建正確的路徑?」從來沒聽說過。

+6

你有沒有任何機會得到任何其他建議,如何實現這一點。在我看來,像一個廢物不得不把/ x/y/z放在一個子類環境中。然後,如果我決定更改/ x/to/k /,我必須到代碼中定義的所有位置並手動更改它! – garyj

+0

@chris:這不適合我。是否涉及配置步驟,還是僅僅是註釋問題?基本控制器確實與擴展基本控制器的控制器在同一個包中。但是,基本控制器的URI/RequestMapping被忽略和/或未找到。 「org.springframework.web.servlet.DispatcherServlet:947 - 沒有找到具有URI的HTTP請求的映射」。所以,如果我只是使用擴展控制器的「基礎」RequestMapping,那很好。如果我嘗試使用由基本控制器繼承的RequestMapping,則無法找到URI。 – Rick

+0

它的值得明確指出,超類路徑仍然可路由。也就是說,覆蓋一個類並提供新的@ RequestMapping不會覆蓋或替換超類的@ RequestMapping,它只是增加了一些。例如,在OP的問題中,這意味着所有這些路徑都是有效的:'/ user/dashboard','/ twitter/updateStatus'。 – kuporific

0

根據Modifying @RequestMappings on startup, 中解釋的技術,可以根據需要從超類構建URL模式。

從本質上說,你必須繼承RequestMappingHandlerMapping(最有可能的,這將是你HandlerMapping實現,但請先檢查) 和覆蓋保護getMappingForMethod方法。 一旦這個可行,你完全可以控制URL模式的生成。

從你給它不是完全清楚確切的合併方針,例如例如,你想擁有什麼樣的路徑,如果 一個超AbstractTwitterController還實現了updateStatus()方法都有自己的@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; 
       } 
    } 

另一個很好的問題是如何截獲實例化爲RequestMappingHandlerMapping。在互聯網上有各種配置策略的各種示例。 但是,請記住,如果您在@Configuration集合中提供了WebMvcConfigurationSupport,那麼您的@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(); 
    } 

} 

但希望瞭解更好的方法。