我有一个用例,我需要限制可以作为查询参数传递的值。
@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传递给sort
的查询参数ASC, DESC
的值。
是否有任何现有的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);
}
我编写了一个拦截API调用的CXF拦截器。我使用反射来处理FooImpl.getFooDetails
参数。但我遇到的问题是拦截器查看FooImpl.getFooDetails方法并且没有在方法参数上找到注释@QueryParam,因为@QueryParam在基本方法上并且注释不是继承的。
拦截器实施:
@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注释不是从接口继承的,尽管规范说它们将被继承。
答案 0 :(得分:1)
根据JAX-RS specification的§3.6注释继承部分,建议始终重复注释,而不是依赖注释继承。
有关完整的引用,请参阅此answer。
@QueryParam
可以应用于不同的目标请记住,@QueryParam
注释可以应用于:
因此,手动验证可能很棘手。
出于验证目的,您应该考虑Bean Validation。考虑带有允许值的@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) {
...
}
}
答案 1 :(得分:1)
也许这只是一个错字,但CXF可能无法识别getFooDetails方法(在界面上),因为它使用@PathParam而不是@Path进行注释。
我没有使用您的ValueSet方法,而是使用了BeanValidation,但以下代码适用于我。
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 ...;
}
我已经开始使用基于CXF 3.1.11的WebSphere Liberty 17.0.0.2。
希望这有帮助, 安迪