用CXF将查询参数jax-rs的值限制为实现



我有一个用例,我需要限制可以通过查询参数传递的值。

@Path("/foo")
public interface Foo {
    @GET
    @Path("/details/id/{id}")
    void getFooDetails(@PathParam("id") String id, @QueryParam("sort") String sortDirection);
}
public class FooImpl {
    public void getFooDetails(String id, String sortDir) {
        //Implementation
    }
}

在上面的示例中,我想限制可以通过API传递到ASC, DESC的查询参数sort的值。

是否有任何现有的CXF注释可以用来限制参数上的值?我还没有找到任何东西,所以我尝试了以下解决方案。

我的方法:

@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ValueSet {
    String[] allowedValues();
}

修改的接口看起来像这样。

@Path("/foo")
public interface Foo {
    @GET
    @PathParam("/details/id/{id}")
    void getFooDetails(@PathParam("id") String id, @QueryParam("sort") @ValueSet(allowedValues = {"ASC", "DESC"}) String sortDirection);
}

我写了一个CXF拦截器,该拦截器拦截了API调用。我使用反射来获取FooImpl.getFooDetails参数的处理。但是我遇到的问题是拦截器查看fooimpl.getfoodetails方法,并且在方法参数上没有找到@queryparam的注释,因为 @queratyparam @queratyparam在基本方法上,并且注释没有继承。

拦截器实现:

@Provider
public class ParamValidationInterceptor extends AbstractPhaseInterceptor<Message> {
    public ParamValidationInterceptor() {
        super(Phase.PRE_INVOKE);
        super.addBefore(someInterceptor);
    }
    @Override
    public void handleMessage(Message message) throws Fault {
        UriInfo uriInfo = new UriInfoImpl(message);
        MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
        Method methodToInvoke = (Method) message.get("org.apache.cxf.resource.method");
        Parameter[] parameters = methodToInvoke.getParameters();
        for (Parameter parameter : parameters) {
            if (parameter.isAnnotationPresent(ValueSet.class)) {
                ValueSet valueSet = parameter.getAnnotation(ValueSet.class);
                QueryParam queryParam = parameter.getAnnotation(QueryParam.class);
                Object invokedVal = queryParams.get(queryParam.value());
                String[] allowedValues = valueSet.allowedValues();
                if (!Arrays.asList(allowedValues).contains(invokedVal)) {
                    throw new CustomException();
                }
            }
        }
    }
}

谁能提出前进的道路?如果有人可以提出另一种方法,那就太好了。

P.S:我正在使用CXF作为JAX-RS和Spring的实现,用作容器。

更新:

喜欢 @cássioMazzochiMolin和@andy McCright建议,我会随@Pattern注释。但是我很想知道为什么jax-rs注释不是从界面继承而来的,尽管规格说它们将是继承的。

注释继承

根据§3.6nenotation sentaritance jax-rs规范,建议始终重复注释而不是依靠注释sentaritance。

请参阅此答案的完整报价。

@QueryParam可以应用于不同的目标

请记住,@QueryParam注释可以应用于:

  • 资源方法参数
  • 资源类字段
  • 资源类Bean属性

因此,手动验证可能很棘手。

使用bean验证

出于验证目的,您应考虑bean验证。考虑具有允许值的@Pattern注释:

@Pattern(regexp = "ASC|DESC")

,只需注释您的资源方法参数:

@GET
@Path("foo")
public Response getFoos(@QueryParam("sort") 
                        @Pattern(regexp = "ASC|DESC") String sortDirection) {
    ...
}

如果您喜欢案例不敏感的值,请使用:

@Pattern(regexp = "ASC|DESC", flags = Pattern.Flag.CASE_INSENSITIVE)

如果给定值无效,则将抛出ConstraintViolationException。要处理此类例外并返回自定义响应,您可以使用ExceptionMapper

@Provider 
public class ConstraintViolationExceptionMapper 
        implements ExceptionMapper<ConstraintViolationException> {
    @Override
    public Response toResponse(ConstraintViolationException exception) {
        ...
    } 
}

也许只是错字,但是CXF可能无法识别getFoodetails方法(在接口上(,因为它用@pathparam注释而不是@path。

我使用的是beanvalidation,而不是使用您的Valueet方法,但是以下代码对我有用。

foo.java

@Path("/foo")
public interface Foo {
    @GET
    @Path("/details/id/{id}")
    Response getFooDetails(
            @PathParam("id") @Pattern(regexp="[0-9]*") String id,
            @QueryParam("sort") @Pattern(regexp = "ASC|DESC") String sortDirection);
}

fooimpl.java

public class FooImpl implements Foo {
    @Override
    public Response getFooDetails(String id, String sortDirection) {
        Integer idInt = Integer.parseInt(id);
        if ("ASC".equals(sortDirection) || sortDirection == null) {
            ...
        } else if ("DESC".equals(sortDirection)) {
            ...
        }
        return ...;
    }

我已经在WebSphere Liberty 17.0.0.2上工作,该1.0.0.2基于CXF 3.1.11。

希望这会有所帮助,安迪

最新更新