Фильтры запроса Dropwizard с шаблоном URI

Я создаю RESTful-приложение в Dropwizard. При подключении к базе данных, я хочу настроить UserNotFoundFilter который реализует ContainerRequestFilter так что входящие запросы сначала проходят через этот фильтр.

Идея состоит в том, что я хотел бы, чтобы этот конкретный фильтр отображался только на определенные шаблоны URI. Например, я хочу, чтобы фильтр применялся только к /users/* и ничего больше. Есть ли способ сделать это, не прибегая к пользовательским аннотациям и реализации с DynamicFeature?

@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
    }
}

Мой класс UserResource

public class UserResource {
    @GET
    @Path("/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);
    }
}

Мой класс ItemResource

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

Что я пытаюсь сделать

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("/users/*");

Я ценю любые примеры кода.

2 ответа

За Servlet фильтр -

Вероятно, вы ищете addMappingForUrlPatterns от javax.servlet.FilterRegistration интерфейс, который будет использоваться в вашем run() как -

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

Подпись использованного выше способа -

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

Редактировать - для динамического связывания:

Попробуйте и используйте DynamicFeature как

@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);
       }
    }
}

где вы можете определить UserRequired аннотация как -

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 {
}

и в пределах ваших ресурсов отметьте все /users/* API с той же аннотацией, что и -

@GET
@Path("/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);
}

Источник - трикотажные фильтры

Вы получите кучу полезных вещей в ((ContainerRequest) requestContext).getUriInfo()например, для соответствия /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 == "/users/{id}") {
        // matched!
    }

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

Получить фактического пользователя id аналогичным образом для поиска вашей БД.

Другие вопросы по тегам