Java Jersey/Jax-RS:如何过滤资源和子资源
在Jersey 2中,如何将筛选器绑定到资源的所有方法及其子资源的所有方法 例如,如果我有以下两种资源:Java Jersey/Jax-RS:如何过滤资源和子资源,java,rest,jersey,jax-rs,jersey-2.0,Java,Rest,Jersey,Jax Rs,Jersey 2.0,在Jersey 2中,如何将筛选器绑定到资源的所有方法及其子资源的所有方法 例如,如果我有以下两种资源: import javax.inject.Singleton; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.model.Resource;
@Path("/myresource/{id: \\d+}")
@Produces(MediaType.APPLICATION_JSON)
@Singleton
class RootResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response get(@PathParam("id") Long id) {
return Response.ok().build();
}
@Path("/sub")
public Resource getSubResource() {
return Resource.from(SubResource.class);
}
}
@Produces(MediaType.APPLICATION_JSON)
@Singleton
class SubResource {
@GET
@Path("/{subid: \\d+}")
public Response get(@PathParam("id") Long id, @PathParam("subid") Long subid) {
return Response.ok().build();
}
}
我想筛选RootResource.get(Long)
和SubResource.get(Long,Long)
。但如果我有其他资源,就不应该过滤这些资源
使用DynamicFeature
,我们只有关于类和方法的信息
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
public class MyFeature implements DynamicFeature {
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
// Here how can I find out that SubResource is actually a sub-resource of RootResource
}
}
我的想法是,我希望能够过滤掉对某一组id的所有调用(该组id是动态的),大致如下:
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
public class MyFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
for(Object resource:requestContext.getUriInfo().getMatchedResources()) {
if(resource instanceof RootResource) {
Long id = Long.valueOf(requestContext.getUriInfo().getPathParameters().getFirst("id"));
// ...
}
}
}
}
@Path("/api/sample")
@Produces(MediaType.APPLICATION_JSON)
public class SampleResource {
@Path("/filtered")
@GET
@Sample(value = "a sample value")
public Hello filtered() {
return new Hello("filtered hello");
}
@Path("/nonfiltered")
@GET
public Hello raw() {
return new Hello("raw hello");
}
}
但我希望避免搜索匹配的资源。这可能吗?我不能100%肯定我理解这个问题,但您似乎想限制哪些资源应该通过过滤器。为此,您可以简单地使用 基本步骤:
@NameBinding
注释
@NameBinding
@Target({METHOD, TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Filtered {
}
boolean isHttpPresent = false;
for (Class annot : Arrays.asList(GET.class, POST.class, PUT.class, DELETE.class)) {
if (method.isAnnotationPresent(annot)) {
isHttpPresent = true;
break;
}
}
@Filtered
@Provider
public class MyFilter implements ContainerRequestFilter {
if (method.isAnnotationPresent(Path.class) && !isHttpPresent) {
Class subResourceClass = method.getReturnType();
if (subResourceClass == possibleSubResource) {
context.register(SomeFilter.class);
}
}
更新 好的,在玩了一些游戏之后,我想出了一些解决方案。。其中很多都很漂亮,但它完成了任务 请记住,
DynamicFeature
中的configure
是为我们拥有的每个资源(方法)调用的
算法1:
for (Resource childResource : resource.getChildResources()) {
if (childResource.getResourceLocator() != null) {
ResourceMethod sub = childResource.getResourceLocator();
Class responseClass = sub.getInvocable().getRawResponseType();
if (responseClass == possibleSubResource) {
context.register(SomeFilter.class);
}
资源
。(您可以尝试使用资源
,但我还没有弄明白)
下面是可以工作的完整代码(未经过战斗测试:-)
方法
s
Class<?> possibleSubResource =
resourceInfo.getResourceMethod().getDeclaringClass();
Class<?> possibleSubResource =
resourceInfo.getResourceMethod().getDeclaringClass();
for (Method method : SomeResource.class.getDeclaredMethods()) {
@NameBinding
@Target({METHOD, TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Filtered {
}
boolean isHttpPresent = false;
for (Class annot : Arrays.asList(GET.class, POST.class, PUT.class, DELETE.class)) {
if (method.isAnnotationPresent(annot)) {
isHttpPresent = true;
break;
}
}
@Path
注释。如果有,并且没有Http方法注释,那么我们注册过滤器
@Filtered
@Provider
public class MyFilter implements ContainerRequestFilter {
if (method.isAnnotationPresent(Path.class) && !isHttpPresent) {
Class subResourceClass = method.getReturnType();
if (subResourceClass == possibleSubResource) {
context.register(SomeFilter.class);
}
}
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
Class<?> resourceClass = resourceInfo.getResourceClass();
if (resourceClass == SomeResource.class) {
context.register(SomeFilter.class);
}
Class<?> possibleSubResource = resourceInfo.getResourceMethod().getDeclaringClass();
for (Method method : SomeResource.class.getDeclaredMethods()) {
boolean isHttpPresent = false;
for(Class annot : Arrays.asList(GET.class,POST.class,PUT.class, DELETE.class)){
if (method.isAnnotationPresent(annot)) {
isHttpPresent = true;
break;
}
}
if(method.isAnnotationPresent(Path.class) && !isHttpPresent){
Class subResourceClass = method.getReturnType();
if (subResourceClass == possibleSubResource) {
context.register(SomeFilter.class);
}
}
}
}
@覆盖
公共void配置(ResourceInfo ResourceInfo、FeatureContext上下文){
Class resourceClass=resourceInfo.getResourceClass();
if(resourceClass==SomeResource.class){
register(SomeFilter.class);
}
类possibleSubResource=resourceInfo.getResourceMethod().getDeclaringClass();
for(方法:SomeResource.class.getDeclaredMethods()){
布尔值isHttpPresent=false;
for(类annot:Arrays.asList(GET.Class、POST.Class、PUT.Class、DELETE.Class)){
如果(方法isAnnotationPresent(annot)){
isHttpPresent=true;
打破
}
}
if(方法.isAnnotationPresent(Path.class)&&&!ishtppresent){
Class subResourceClass=method.getReturnType();
if(subResourceClass==possibleSubResource){
register(SomeFilter.class);
}
}
}
}
同样,这两种解决方案都没有经过测试,但都适用于我尝试过的少数案例。就我个人而言,我会选择名字绑定,但也许这是一个你可以向泽西队提出的问题。这(当根资源被注册时,子资源的自动注册)看起来确实像是应该解决的问题,或者至少可以进行配置。我也有类似的需求:
我想要一个注释来专门过滤资源方法,以实现
大概是这样的:
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
public class MyFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
for(Object resource:requestContext.getUriInfo().getMatchedResources()) {
if(resource instanceof RootResource) {
Long id = Long.valueOf(requestContext.getUriInfo().getPathParameters().getFirst("id"));
// ...
}
}
}
}
@Path("/api/sample")
@Produces(MediaType.APPLICATION_JSON)
public class SampleResource {
@Path("/filtered")
@GET
@Sample(value = "a sample value")
public Hello filtered() {
return new Hello("filtered hello");
}
@Path("/nonfiltered")
@GET
public Hello raw() {
return new Hello("raw hello");
}
}
我的注释是:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sample {
String value() default "";
}
最后,我使用DynamicFeature
在资源上注册了过滤器
@Provider
public class SampleFeature implements DynamicFeature {
private SampleFilter sampleFilter;
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if (resourceInfo.getResourceMethod().getAnnotation(Sample.class) != null) {
if (sampleFilter == null) {
this.sampleFilter = new SampleFilter();
}
context.register(sampleFilter);
}
}
}
棘手的问题是如何在过滤器中获取注释值,因此要了解extendederariinfo
,请参见以下内容:
public class SampleFilter implements ContainerRequestFilter {
public SampleFilter() {
}
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
String sampleValue = this.getAnnotation(containerRequestContext).value();
// do some filtering based on the Sample Value
}
private Sample getAnnotation(ContainerRequestContext requestContext) {
ResourceMethod method = ((ExtendedUriInfo) (requestContext.getUriInfo()))
.getMatchedResourceMethod();
Method invokedMethod = method.getInvocable().getHandlingMethod();
return invokedMethod.getAnnotation(Sample.class);
}
}
我也这么想,但这是我想避免的。如果明天我添加一个新方法和/或新的子资源,我不想知道我还需要添加那个注释。我希望这是尽可能通用,以避免任何未来的错误。但是谢谢你的回答。请看我的更新。我不喜欢,但它可能会给你一些想法。