如何让实现ContainerRequestFilter和ContainerResponseFilter的过滤器匹配特定正则URL?
嗨,我来帮你搞定这个问题!在JAX-RS框架中,要让你的ContainerRequestFilter和ContainerResponseFilter只对符合特定正则表达式的URL生效,有两种实用方案,我给你拆解清楚:
方案一:过滤器内部直接做URL匹配(最简单直接)
这种方式不需要额外注解,直接在过滤器代码里判断请求URL是否符合正则,不符合就跳过过滤逻辑。
步骤示例:
- 编写过滤器类,预编译正则表达式(提升性能),然后在
filter方法里做匹配判断:
import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.container.ContainerResponseContext; import java.io.IOException; import java.util.regex.Pattern; // 请求过滤器示例 public class TargetUrlRequestFilter implements ContainerRequestFilter { // 预编译目标URL正则,比如匹配 /api/v1/users/数字 这类路径 private static final Pattern TARGET_URL_PATTERN = Pattern.compile("/api/v1/users/\\d+"); @Override public void filter(ContainerRequestContext requestContext) { // 获取请求的相对路径(自动去掉应用的base URI,更准确) String requestPath = requestContext.getUriInfo().getPath(); // 如果URL不匹配正则,直接返回,不执行后续过滤逻辑 if (!TARGET_URL_PATTERN.matcher(requestPath).matches()) { return; } // 这里写你的请求过滤逻辑,比如校验Token、修改请求头等 System.out.println("处理符合正则的请求:" + requestPath); } } // 响应过滤器示例(逻辑类似) public class TargetUrlResponseFilter implements ContainerResponseFilter { private static final Pattern TARGET_URL_PATTERN = Pattern.compile("/api/v1/users/\\d+"); @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { String requestPath = requestContext.getUriInfo().getPath(); if (!TARGET_URL_PATTERN.matcher(requestPath).matches()) { return; } // 这里写你的响应过滤逻辑,比如添加响应头、修改响应体等 responseContext.getHeaders().add("X-Filtered", "true"); } }
- 注册过滤器:
- 给过滤器类添加
@Provider注解,让JAX-RS自动扫描注册; - 或者在你的
Application子类中手动注册:import javax.ws.rs.core.Application; import java.util.HashSet; import java.util.Set; public class MyApplication extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> classes = new HashSet<>(); classes.add(TargetUrlRequestFilter.class); classes.add(TargetUrlResponseFilter.class); return classes; } }
- 给过滤器类添加
方案二:使用自定义注解+动态绑定(灵活适配不同URL规则)
如果需要给不同的资源方法/类指定不同的正则规则,或者想通过注解来标记需要过滤的目标,这种方案更灵活。
步骤示例:
- 定义带正则参数的自定义绑定注解:
import javax.ws.rs.NameBinding; import java.lang.annotation.*; @NameBinding @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface FilterForRegex { // 用来指定目标URL的正则表达式 String value(); }
- 编写动态绑定类,根据资源上的注解决定是否应用过滤器:
import javax.ws.rs.container.DynamicFeature; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.FeatureContext; import java.util.regex.Pattern; public class RegexFilterDynamicBinder implements DynamicFeature { @Override public void configure(ResourceInfo resourceInfo, FeatureContext context) { // 先检查资源方法有没有注解,没有再检查资源类 FilterForRegex annotation = resourceInfo.getResourceMethod().getAnnotation(FilterForRegex.class); if (annotation == null) { annotation = resourceInfo.getResourceClass().getAnnotation(FilterForRegex.class); } if (annotation != null) { // 拿到注解里的正则,注册对应的过滤器实例 String regex = annotation.value(); context.register(new DynamicRequestFilter(regex)); context.register(new DynamicResponseFilter(regex)); } } }
- 编写支持动态正则的过滤器:
import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import java.io.IOException; import java.util.regex.Pattern; public class DynamicRequestFilter implements ContainerRequestFilter { private final Pattern targetPattern; // 构造函数传入正则表达式 public DynamicRequestFilter(String regex) { this.targetPattern = Pattern.compile(regex); } @Override public void filter(ContainerRequestContext requestContext) { String requestPath = requestContext.getUriInfo().getPath(); if (targetPattern.matcher(requestPath).matches()) { // 执行请求过滤逻辑 System.out.println("处理正则[" + targetPattern.pattern() + "]的请求"); } } } public class DynamicResponseFilter implements ContainerResponseFilter { private final Pattern targetPattern; public DynamicResponseFilter(String regex) { this.targetPattern = Pattern.compile(regex); } @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { String requestPath = requestContext.getUriInfo().getPath(); if (targetPattern.matcher(requestPath).matches()) { // 执行响应过滤逻辑 responseContext.getHeaders().add("X-Dynamic-Filter", "true"); } } }
- 在资源类/方法上标注注解:
@Path("/api/v1/users") public class UserResource { // 只对这个方法的URL应用过滤器,正则匹配 /api/v1/users/数字 @FilterForRegex("/api/v1/users/\\d+") @GET @Path("/{id}") public Response getUser(@PathParam("id") String id) { return Response.ok("User: " + id).build(); } // 这个方法不会被过滤器处理 @GET @Path("/list") public Response getUserList() { return Response.ok("User List").build(); } }
- 注册动态绑定类:
同样在Application子类中添加RegexFilterDynamicBinder.class,或者给它加@Provider注解。
注意事项:
- 正则表达式尽量预编译(比如方案一中的
static final Pattern),避免每次请求都重复编译,影响性能; - 使用
requestContext.getUriInfo().getPath()获取路径时,会自动去掉应用的base URI,比直接拿请求URL更可靠; - 如果是
ContainerResponseFilter,判断逻辑和请求过滤器完全一致,只需要在filter方法里先做URL匹配再执行逻辑。
内容的提问来源于stack exchange,提问作者Luciano Borges
相关产品推荐
相关产品推荐

