web-dev-qa-db-ja.com

ジャージーフィルターから一部のURLを除外する方法は?

私はジャージを使用してWebサービスを作成しました。 ContainerRequestFilterを使用してリクエストフィルターを作成しました。 特定のURIでのみジャージーリクエストフィルター の質問を行いましたが、一部のURLのみのフィルターを除外します。

@Provider
public class AuthFilter implements ContainerRequestFilter{

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

// business logic

   }
}
14
curiousmind

名前バインディングフィルター

グローバルフィルターからURIを除外する代わりに、名前バインディングフィルターを使用して、フィルターがバインドされるエンドポイントを選択することを検討できますに。

名前バインディングフィルターの例については、 この回答 も確認してください。

グローバルフィルター

それでもグローバルフィルターアプローチに満足している場合は、 UriInfo インターフェイスを使用して、要求されたURIの詳細を取得することを検討できます。次のいずれかの方法を使用して、 UriInfo のインスタンスを取得します。

  1. @Context アノテーションの使用:

    @Provider
    public class AuthFilter implements ContainerRequestFilter {
    
        @Context
        private UriInfo info;
    
        @Override
        public void filter(ContainerRequestContext requestContext) throws IOException {
            ...
        }
    }
    
  1. ContainerRequestContext から取得する:

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        UriInfo info = requestContext.getUriInfo();
        ...
    }
    

UriInfoインスタンスを取得すると、便利な一連のメソッドにアクセスできるようになります。

  • getAbsolutePath() :リクエストの絶対パスを取得します。
  • getBaseUri() :アプリケーションのベースURIを取得します。
  • getMatchedResources() :現在一致しているリソースクラスインスタンスの読み取り専用リストを取得します。
  • getMatchedURIs() :一致したリソースのURIの読み取り専用リストを取得します。
  • getPath() :現在のリクエストのベースURIからの相対パスを文字列として取得します。
  • getPathSegments() :ベースURIに対する現在のリクエストのパスを PathSegment のリストとして取得します。
  • getRequestUri() :クエリパラメータを含む絶対リクエストURIを取得します。
  • relativize(URI) :現在のリクエストURIに対してURIを相対化します。
  • resolve(URI) :アプリケーションのベースURIに対する相対URIを解決します。

詳細については、 UriInfo のドキュメントを確認してください。

要求されたURIがフィルターを適用するURIと一致しない場合は、単にreturn命令を使用します。

@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
    UriInfo info = requestContext.getUriInfo();
    if (!info.getPath().contains("secured")) {
        return;
    }
}

動的バインディング

別のアプローチはdynamic bindingです。動的な方法でリソースメソッドにフィルターとインターセプターを割り当てることができます。上記の名前バインディングは静的アプローチを使用しており、バインディングの変更にはソースコードの変更と再コンパイルが必要です。動的バインディングを使用すると、アプリケーションの初期化時にバインディングを定義するコードを実装できます。

Jerseyのドキュメント から抜粋した次の例は、動的バインディングを実装する方法を示しています。

@Path("helloworld")
public class HelloWorldResource {

    @GET
    @Produces("text/plain")
    public String getHello() {
        return "Hello World!";
    }

    @GET
    @Path("too-much-data")
    public String getVeryLongString() {
        String str = ... // very long string
        return str;
    }
}
// This dynamic binding provider registers GZIPWriterInterceptor
// only for HelloWorldResource and methods that contain
// "VeryLongString" in their name. It will be executed during
// application initialization phase.
public class CompressionDynamicBinding implements DynamicFeature {

    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) {
        if (HelloWorldResource.class.equals(resourceInfo.getResourceClass())
                && resourceInfo.getResourceMethod().getName().contains("VeryLongString")) {
            context.register(GZIPWriterInterceptor.class);
        }
    }
}

バインディングは、 DynamicFeature インターフェースを実装するプロバイダーを使用して行われます。インターフェースは、2つの引数 configure および ResourceInfo を持つ1つのFeatureContextメソッドを定義します。

ResourceInfo には、バインディングを実行できるリソースとメソッドに関する情報が含まれています。 configureメソッドは、アプリケーションで定義されているリソースメソッドごとに1回実行されます。上記の例では、プロバイダーはgetHello()メソッドに対して1回、getVeryLongString()に対して1回(resourceInfogetHello()メソッドに関する情報が含まれるようになると)2回実行されますそして、それがgetVeryLongString()を指すようになります)。

動的バインディングプロバイダーが実際のリソースメソッドのプロバイダーを登録する場合は、提供された FeatureContext を使用してそれを行います。これにより、JAX-RS構成可能APIが拡張されます。フィルターまたはインターセプターのクラスまたはインスタンスを登録するためのすべてのメソッドを使用できます。このような動的に登録されたフィルターまたはインターセプターは、実際のリソースメソッドにのみバインドされます。上記の例では、GZIPWriterInterceptorはメソッドgetVeryLongString()にのみバインドされるため、データはこのメソッドでのみ圧縮され、メソッドgetHello()では圧縮されません。

動的バインディングを使用して登録されたフィルターおよびインターセプターは、リソースメソッドに対して実行される追加のフィルターにすぎないことに注意してください。名前にバインドされたプロバイダーまたはグローバルプロバイダーがある場合でも、それらは実行されます。


詳細については、 フィルターとインターセプターに関するジャージーのドキュメント を確認してください。

28
cassiomolin

@NameBindingを使用するのが最も洗練された方法ですが、単一のリソースを除外して他のすべてのリソースにフィルタを適用する場合は、すべてのリソースにバインディングアノテーションを付けることを覚えておく必要があります。この場合、ContainerRequestContext.getUriInfo().getMatchedResources()を使用して、ターゲットリソースが一致しているかどうかを確認できます。これは、変更される可能性のあるパスをハードコーディングするよりも優れています。

以下の例では、StatusResourceを除くすべてのリソースにフィルターロジックを適用します。

public class CorsContainerRequestFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext req) {
        if (!matchesStatusResource(req)) {
            // filter logic
        }
    }

    private boolean matchesStatusResource(ContainerRequestContext req) {
        List<Object> matchedResources = req.getUriInfo().getMatchedResources();
        for (Object matchedResource : matchedResources) {
            if (matchedResource instanceof StatusResource) {
                return true;
            }
        }
        return false;
    }
}

他の人が述べたように、代わりに動的バインディングを使用できますが、フィルターがすべてのリソースに適用されないことは明らかでないため、かなり醜いです。

2
Jonathan