使用 CXF 作为实现来限制 JAX-RS 查询参数的值

yas*_*nth 2 java rest spring cxf jax-rs

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

\n\n
@Path("/foo")\npublic interface Foo {\n\n    @GET\n    @Path("/details/id/{id}")\n    void getFooDetails(@PathParam("id") String id, @QueryParam("sort") String sortDirection);\n}\n\npublic class FooImpl {\n    public void getFooDetails(String id, String sortDir) {\n        //Implementation\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在上面的示例中,我想限制sort可以通过 API 传递到ASC, DESC.

\n\n

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

\n\n

我的方法:

\n\n
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\npublic @interface ValueSet {\n\n    String[] allowedValues();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

修改后的界面如下所示。

\n\n
@Path("/foo")\npublic interface Foo {\n\n    @GET\n    @PathParam("/details/id/{id}")\n    void getFooDetails(@PathParam("id") String id, @QueryParam("sort") @ValueSet(allowedValues = {"ASC", "DESC"}) String sortDirection);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我编写了一个 CXF 拦截器来拦截 API 调用。我使用反射来处理参数FooImpl.getFooDetails。但我面临的问题是,拦截器查看 FooImpl.getFooDetails 方法,但在方法参数上找不到注释 @QueryParam,因为 @QueryParam 位于基本方法上,并且注释不是继承的。

\n\n

拦截器实现:

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

有人能提出前进的方向吗?如果有人能提出替代方法,那就太好了。

\n\n

PS:我使用 CXF 作为 JAX-RS 的实现,并使用 spring 作为容器。

\n\n

更新:

\n\n

就像 @C\xc3\xa1ssio Mazzochi Molin 和 @Andy McCright 建议的那样,我将使用 @Pattern 注释。但我很好奇为什么 JAX-RS 注释不是从接口继承的,尽管规范说它们将被继承。

\n

cas*_*lin 5

注解继承

\n\n

根据JAX-RS 规范\xc2\xa73.6 Annotation Inheritance部分,建议始终重复注释而不是依赖注释继承。

\n\n

请参阅此答案以获取完整报价。

\n\n

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

\n\n

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

\n\n
    \n
  • 资源方法参数
  • \n
  • 资源类字段
  • \n
  • 资源类 bean 属性
  • \n
\n\n

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

\n\n

使用 Bean 验证

\n\n

出于验证目的,您应该考虑Bean Validation。考虑@Pattern带有允许值的注释:

\n\n
@Pattern(regexp = "ASC|DESC")\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
@GET\n@Path("foo")\npublic Response getFoos(@QueryParam("sort") \n                        @Pattern(regexp = "ASC|DESC") String sortDirection) {\n    ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您喜欢不区分大小写的值,请使用:

\n\n
@Pattern(regexp = "ASC|DESC", flags = Pattern.Flag.CASE_INSENSITIVE)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
@Provider \npublic class ConstraintViolationExceptionMapper \n        implements ExceptionMapper<ConstraintViolationException> {\n\n    @Override\n    public Response toResponse(ConstraintViolationException exception) {\n        ...\n    } \n}\n
Run Code Online (Sandbox Code Playgroud)\n