私はジャージを使用してWebサービスを作成しました。 ContainerRequestFilter
を使用してリクエストフィルターを作成しました。 特定のURIでのみジャージーリクエストフィルター の質問を行いましたが、一部のURLのみのフィルターを除外します。
@Provider
public class AuthFilter implements ContainerRequestFilter{
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// business logic
}
}
グローバルフィルターからURIを除外する代わりに、名前バインディングフィルターを使用して、フィルターがバインドされるエンドポイントを選択することを検討できますに。
名前バインディングフィルターの例については、 この回答 も確認してください。
それでもグローバルフィルターアプローチに満足している場合は、 UriInfo
インターフェイスを使用して、要求されたURIの詳細を取得することを検討できます。次のいずれかの方法を使用して、 UriInfo
のインスタンスを取得します。
@Context
アノテーションの使用:
@Provider
public class AuthFilter implements ContainerRequestFilter {
@Context
private UriInfo info;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
...
}
}
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回(resourceInfo
にgetHello()
メソッドに関する情報が含まれるようになると)2回実行されますそして、それがgetVeryLongString()
を指すようになります)。
動的バインディングプロバイダーが実際のリソースメソッドのプロバイダーを登録する場合は、提供された FeatureContext
を使用してそれを行います。これにより、JAX-RS構成可能APIが拡張されます。フィルターまたはインターセプターのクラスまたはインスタンスを登録するためのすべてのメソッドを使用できます。このような動的に登録されたフィルターまたはインターセプターは、実際のリソースメソッドにのみバインドされます。上記の例では、GZIPWriterInterceptor
はメソッドgetVeryLongString()
にのみバインドされるため、データはこのメソッドでのみ圧縮され、メソッドgetHello()
では圧縮されません。
動的バインディングを使用して登録されたフィルターおよびインターセプターは、リソースメソッドに対して実行される追加のフィルターにすぎないことに注意してください。名前にバインドされたプロバイダーまたはグローバルプロバイダーがある場合でも、それらは実行されます。
詳細については、 フィルターとインターセプターに関するジャージーのドキュメント を確認してください。
@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;
}
}
他の人が述べたように、代わりに動的バインディングを使用できますが、フィルターがすべてのリソースに適用されないことは明らかでないため、かなり醜いです。