如何定义HTTP过滤器并将生成对象作为@RequestScoped实例供REST资源使用?
在Jersey中通过ContainerRequestFilter传递对象到REST资源方法
要实现解析请求头/参数构建对象并传递给资源方法,核心是利用Jersey的请求上下文存储对象,再通过参数注入或直接获取的方式让资源方法访问。以下是具体实现方案:
1. 定义待传递的对象类
先创建你需要的上下文对象,比如存储用户信息的UserContext:
public class UserContext { private String userId; private String authToken; public UserContext(String userId, String authToken) { this.userId = userId; this.authToken = authToken; } // Getter方法 public String getUserId() { return userId; } public String getAuthToken() { return authToken; } }
2. 实现ContainerRequestFilter解析请求并存储对象
在过滤器中解析请求头、参数,构建对象后存入ContainerRequestContext的Properties中:
@Provider public class UserContextFilter implements ContainerRequestFilter { // 用类全限定名作为唯一key,避免冲突 private static final String USER_CONTEXT_KEY = UserContext.class.getName(); @Override public void filter(ContainerRequestContext requestContext) throws IOException { // 解析请求头示例:获取Authorization头 String authToken = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); // 解析Query参数示例:获取userId参数 String userId = requestContext.getUriInfo().getQueryParameters().getFirst("userId"); // 构建上下文对象(实际场景可加入token验证、用户信息查询等逻辑) UserContext userContext = new UserContext(userId, authToken); // 将对象存入请求上下文 requestContext.setProperty(USER_CONTEXT_KEY, userContext); } }
3. 让资源方法访问对象:两种方式
方式一:直接通过@Context获取(简单快速)
在资源方法中注入ContainerRequestContext,手动取出对象:
@Path("/demo") public class DemoResource { @GET public Response getDemoData(@Context ContainerRequestContext requestContext) { UserContext userContext = (UserContext) requestContext.getProperty(UserContext.class.getName()); return Response.ok(String.format("当前用户ID:%s,Token:%s", userContext.getUserId(), userContext.getAuthToken())).build(); } }
方式二:自定义注解+参数注入(优雅推荐)
这种方式无需手动从上下文取对象,直接注入到方法参数中,代码更简洁。
步骤1:定义自定义注解
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface RequestUserContext { }
步骤2:实现参数注入的Provider
创建ValueFactoryProvider,用于向Jersey提供UserContext实例:
@Provider public class UserContextValueFactoryProvider extends AbstractValueFactoryProvider { private static final String USER_CONTEXT_KEY = UserContext.class.getName(); @Inject public UserContextValueFactoryProvider(MultivaluedParameterExtractorProvider extractorProvider, ServiceLocator serviceLocator) { super(extractorProvider, serviceLocator, Parameter.Source.UNKNOWN); } @Override protected Factory<?> createValueFactory(Parameter parameter) { // 判断参数类型和注解是否匹配 if (parameter.getType() == UserContext.class && parameter.isAnnotationPresent(RequestUserContext.class)) { return new Factory<UserContext>() { @Context private ContainerRequestContext requestContext; @Override public UserContext provide() { return (UserContext) requestContext.getProperty(USER_CONTEXT_KEY); } @Override public void dispose(UserContext userContext) { // 无需清理操作 } }; } return null; } }
步骤3:注册过滤器和Provider
确保过滤器和Provider被Jersey识别,可通过ResourceConfig手动注册:
public class JerseyApplication extends ResourceConfig { public JerseyApplication() { // 注册过滤器 register(UserContextFilter.class); // 注册参数注入Provider register(UserContextValueFactoryProvider.class); // 注册资源类 register(DemoResource.class); } }
步骤4:在资源方法中使用注解注入
@Path("/demo") public class DemoResource { @GET public Response getDemoData(@RequestUserContext UserContext userContext) { return Response.ok(String.format("当前用户ID:%s,Token:%s", userContext.getUserId(), userContext.getAuthToken())).build(); } }
注意事项
- 如果需要解析POST请求的请求体,注意请求流只能读取一次,需将流包装为可重复读取的
CachedOutputStream后再解析,避免后续资源方法无法读取请求体。 - 确保
@Provider注解的类被Jersey扫描到,或手动注册到配置类中。 - 存储对象时使用唯一的key,避免与其他组件的属性冲突。
内容的提问来源于stack exchange,提问作者Kostas Pagratis
相关产品推荐
相关产品推荐

