2011-03-11 17 views
27

Struts2から来ている私は、スーパクラス(またはpackage-info.java)で@Namespaceアノテーションを宣言するのに慣れていて、継承クラスはその先祖の@Namespaceアノテーションの値を受け取り、それをリクエストパスの前に追加しますアクションのために。しかし、ときに私が希望 Spring MVC @RequestMapping継承

  • を期待されるよう
  • /user/dashboard作品を期待するよう

    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() { 
         .... 
        } 
    } 
    
    • /作品:私は今(簡潔にするためにトリミングされたコード)を次のように@RequestMappingアノテーションを使って春のMVCで同様の何かをしようとしています期待しています/user/twitter/updateStatusは動作しませんし、ログをチェックしています。次のようなログエントリが表示されます。

    org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping - マップされたURLパス[/ツイーター/ UpdateStatusを]ハンドラへ 'twitterController'

    私はそれがスキャンします有効にすることができます設定があります@RequestMapping注釈のスーパークラスと正しいパスを作成しますか?

    package-info.javaのパッケージに@RequestMappingを定義することは、違法ですか?次

  • 答えて

    24

    基本的に/tweeter/updateStatusとはなりません/user/tweeter/updateStatus

    あなたは AbstractControllerAbstractUserControllerにあなたが宣言した元 @RequestMappingをオーバーライドしましたので、予想される動作をだ
    public abstract class TwitterController extends AbstractTwitterController { 
    
        @RequestMapping(value = "/updateStatus")  
        public String updateStatus() { 
         .... 
        } 
    } 
    

    実際にAbstractUserControllerと宣言したときには、AbstractControllerの場合は@RequestMappingも上書きされます。 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'sを提供してもスーパークラスの' @ RequestMapping'sをオーバーライドしたり置き換えたりすることはなく、追加するだけです。上のOPの質問では、例えば、これらのパスはすべて有効です: '/ user/dashboard'、'/twitter/updateStatus'です。 – kuporific

    0

    Modifying @RequestMappings on startupで説明されている方法によれば、 はい、あなたが望む方法でスーパークラスからURLパターンを構築することは可能です。

    は本質的には、RequestMappingHandlerMapping(ほとんどの場合、それはあなたのHandlerMapping実装であるが、最初に確認してくださいます) をサブクラス化し、保護getMappingForMethodメソッドをオーバーライドする必要があります。 これが実行可能になると、URLパターンの生成を完全に制御できます。例から

    あなたは、それが正確なマージポリシー、完全に明確ではありません与え例えば、あなたが 場合も@RequestMapping、独自にupdateStatus()メソッドを実装し、またはどのようにURLを連結したいAbstractTwitterControllerスーパークラスを持つようにしたいものをパス階層間のパターン、トップダウンかボトムアップ、(私は下の元を仮定)、 たが、うまくいけば、次のスニペットは、あなたにいくつかのアイデアを与えるだろう。

    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のインスタンス化。インターネットには、さまざまな構成戦略のための非常に多くのさまざまな例があります。 JavaConfigでは、@ConfigurationWebMvcConfigurationSupportを指定すると、@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(); 
        } 
    
    } 
    

    しかし、より良い方法について学びたいと思います。