JAX-RS中必需的@QueryParam(以及在他们不在时需要做什么)

我使用RESTEasy JAX-RS实现将一个Web服务组件部署到JBoss应用服务器7

是否有注释可用于在JAX-RS中声明必需的强制性@QueryParam参数? 而且,如果不是,那么处理这些参数丢失的情况的“标准”方法是什么?

我的networking服务(资源)方法返回JSONstring化的结果时正确调用所有的强制性的参数,但我不知道什么是最好的方式向调用者表明一个必需的参数丢失。

好问题。 不幸的是(或者幸运的是)JAX-RS没有任何机制来强制实现任何参数。 如果没有提供参数,它的值将是NULL ,你的资源应该相应地处理它。 我会build议使用WebApplicationException来通知您的用户:

 @GET @Path("/some-path") public String read(@QueryParam("name") String name) { if (name == null) { throw new WebApplicationException( Response.status(HttpURLConnection.HTTP_BAD_REQUEST) .entity("name parameter is mandatory") .build() ); } // continue with a normal flow } 

您可以使用javax.validation注释来强制使用@javax.validation.constraints.NotNull注释这些参数。 看泽西岛的例子和RESTeasy 的例子 。

所以你的方法会变成:

 @GET @Path("/some-path") public String read(@NotNull @QueryParam("name") String name) { String something = // implementation return something; } 

请注意,由JAX-RS提供程序将exception转换为一些错误代码。 通常可以通过注册自己的javax.ws.rs.ext.ExceptionMapper<javax.validation.ValidationException>实现来覆盖它。

这提供了一种集中的方式来将强制参数转换为错误响应,并且不需要代码重复。

我遇到了同样的问题,并决定我不希望在我的REST代码中散布大量的模板null检查,所以这就是我决定做的事情:

  1. 创build一个注释,当未指定必需的参数时,会引发exception。
  2. 处理抛出的exception,就像我处理在我的REST代码中抛出的所有其他exception一样。

对于1) ,我实现了以下注释:

 import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Required { // This is just a marker annotation, so nothing in here. } 

…和下​​面的JAX-RS ContainerRequestFilter来执行它:

 import java.lang.reflect.Parameter; import javax.ws.rs.QueryParam; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.Context; import javax.ws.rs.ext.Provider; @Provider public class RequiredParameterFilter implements ContainerRequestFilter { @Context private ResourceInfo resourceInfo; @Override public void filter(ContainerRequestContext requestContext) { // Loop through each parameter for (Parameter parameter : resourceInfo.getResourceMethod().getParameters()) { // Check is this parameter is a query parameter QueryParam queryAnnotation = parameter.getAnnotation(QueryParam.class); // ... and whether it is a required one if (queryAnnotation != null && parameter.isAnnotationPresent(Required.class)) { // ... and whether it was not specified if (!requestContext.getUriInfo().getQueryParameters().containsKey(queryAnnotation.value())) { // We pass the query variable name to the constructor so that the exception can generate a meaningful error message throw new YourCustomRuntimeException(queryAnnotation.value()); } } } } } 

您需要以与使用JAX-RS库注册其他@Provider类相同的方式注册ContainerRequestFilter 。 也许RESTEasy自动为你做。

对于2) ,我使用genericsJAX-RS ExceptionMapper处理所有运行时ExceptionMapper

 import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; @Provider public class MyExceptionMapper implements ExceptionMapper<RuntimeException> { @Override public Response toResponse(RuntimeException ex) { // In this example, we just return the .toString() of the exception. // You might want to wrap this in a JSON structure if this is a JSON API, for example. return Response .status(Response.Status.BAD_REQUEST) .entity(ex.toString()) .build(); } } 

和以前一样,记得用JAX-RS库注册这个类。