2016-11-04 4 views
3

Ich baue eine RESTful Anwendung in Dropwizard. Bei der Verbindung mit einer Datenbank möchte ich eine UserNotFoundFilter einrichten, die ContainerRequestFilter implementiert, so dass eingehende Anforderungen zuerst diesen Filter durchlaufen.Dropwizard Request Filter mit URI-Muster

Die Idee ist, dass ich möchte diesen spezifischen Filter nur bestimmte URI-Muster zugeordnet haben. Zum Beispiel möchte ich, dass der Filter nur auf /users/* und nichts anderes angewendet wird. Gibt es eine Möglichkeit, dies zu tun, ohne auf benutzerdefinierte Anmerkungen und Implementierung mit DynamicFeature zurückgreifen zu müssen?

@Provider 
public class UserNotFoundFilter implements ContainerRequestFilter { 
    @Context 
    UriInfo uriInfo; 

    @Override 
    public void filter(ContainerRequestContext requestContext) throws IOException { 
     MultivaluedMap pathParams = uriInfo.getPathParameters(); // Should contain (uid: 1) pair for /users/1 
     boolean userExists = // check against the database using above pathparam pair to see if user exists 
     if (!userExists) 
      throw new WebApplicationException("User does not exist", Status.NOT_FOUND); 
     // let the request through as user exists 
    } 
} 

Meine UserResource Klasse

public class UserResource { 
    @GET 
    @Path("https://stackoverflow.com/users/{uid}") 
    @Produces(MediaType.APPLICATION_JSON) 
    public User getUser(@PathParam("uid") String uid) { 
     // Now I don't need to do the check here ! 
     // boolean userExists = check against database using uid path param 
     // if (!userExists) 
     //  throw new WebApplicationException("User does not exist", Status.NOT_FOUND); 
     return database.getUser(uid); 
    } 
} 

Meine ItemResource Klasse

public class ItemResource { 
    @GET 
    @Path("/items/{uid}") 
    @Produces(MediaType.APPLICATION_JSON) 
    public Item getItem(@PathParam("uid") String uid) { 
     return database.getItem(uid); 
    } 
} 

Was ich versuche

public class MyApplication extends Application<MyConfiguration> { 
    // ... 
    @Override 
    public void run(MyConfiguration config, Environment environment) throws Exception { 
     // ... do other things, register resources 
     // this pseudocode, the UserNotFoundFilter only applies to URIs of the kind /users/* 
     environment.jersey().register(new UserNotFoundFilter()).forUriPattern("https://stackoverflow.com/users/*"); 

ich Schnipsel alle Beispiel-Code zu schätzen wissen zu tun.

Antwort

0

Für Servlet Filter -

Wahrscheinlich, was Sie suchen, ist addMappingForUrlPatterns von javax.servlet.FilterRegistration Schnittstelle in Ihrer run() als verwendet werden -

environment.servlets().addFilter("FilterName", UserNotFoundFilter.class) 
      .addMappingForUrlPatterns(EnumSet 
         .allOf(DispatcherType.class), true, "https://stackoverflow.com/users/*"); 

Unterschrift der oben verwendete Methode ist -

public void addMappingForUrlPatterns(
     EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, 
     String... urlPatterns); 

bearbeiten - für die Bindung dynamisch:

Try und verwenden DynamicFeature als

@Provider 
public class UserNotFoundDynamicFilter implements DynamicFeature { 

    @Override 
    public void configure(ResourceInfo resourceInfo, FeatureContext featureContext) { 
     if (resourceInfo.getResourceMethod().getAnnotation(UserRequired.class) != null) { 
      featureContext.register(UserNotFoundFilter.class); 
     } 
    } 
} 

wo Sie die UserRequired Anmerkung definieren -

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface UserRequired { 
} 

und innerhalb Ihrer Ressourcen alle /users/* markieren apis mit der gleichen Anmerkung wie -

@GET 
@Path("https://stackoverflow.com/users/{uid}") 
@Produces(MediaType.APPLICATION_JSON) 
@UserRequired 
public User getUser(@PathParam("uid") String uid) { 
    // Now I don't need to do the check here ! 
    // boolean userExists = check against database using uid path param 
    // if (!userExists) 
    //  throw new WebApplicationException("User does not exist", Status.NOT_FOUND); 
    return database.getUser(uid); 
} 

Quelle-jersey-filters

+0

Wenn ich richtig verstehe, thatss ein ServletFilter impl und nicht eine ContainerRequestFilter Implementierung. Ich brauche eine Möglichkeit, ein Mapping für URL-Muster auf Letzterem zu setzen. – Kookz

+0

@Kookz richtig. Für 'DynamicFeature' wurde die Verwendung derselben für die ContainerRequestFilter-Implementierung aktualisiert. – nullpointer

+0

Im obigen Beispiel haben Sie den Filter an eine Annotation gebunden. Dann muss ich die Annotation zu allen Ressourcenmethoden unter '/ users' hinzufügen. Gibt es eine Möglichkeit, anstelle der Anmerkungen ein URL-Muster anzugeben? – Kookz

1

Sie werden eine Reihe von nützlichen Sachen in ((ContainerRequest) requestContext).getUriInfo() erhalten, z.B. zum Abgleichen /users/*

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

    String uriTemplate = ((ContainerRequest) requestContext).getUriInfo().getMatchedTemplates().stream().map(o -> o.getTemplate()).reduce("", (acc, template) -> template + acc); 
    if (uriTemplate == "https://stackoverflow.com/users/{id}") { 
     // matched! 
    } 

    String path = ((ContainerRequest) requestContext).getUriInfo().getPath(); 
    if (path.startsWith("users/")) { 
     // matched! 
    } 
} 

Holen Sie sich den aktuellen Benutzer id in ähnlicher Weise für die DB-Lookup.