我正在使用Jersey学习JAX-RS(又名JSR-311)。我已经成功地创建了一个根资源,并正在摆弄参数:

@Path("/hello")
public class HelloWorldResource {

    @GET
    @Produces("text/html")
    public String get(
        @QueryParam("name") String name,
        @QueryParam("birthDate") Date birthDate) {

         // Return a greeting with the name and age
    }
}

这工作得很好,并处理当前区域内Date(String)构造函数能理解的任何格式(如YYYY/mm/dd和mm/dd/YYYY)。但如果我提供的值无效或无法理解,就会得到404响应。

例如:

GET /hello?name=Mark&birthDate=X

404 Not Found

如何自定义此行为?也许是一个不同的响应代码(可能是“400个坏请求”)?记录一个错误怎么样?也许可以在自定义报头中添加问题的描述(“糟糕的日期格式”)以帮助排除故障?或者返回一个完整的带有详细信息的Error响应,以及一个5xx状态码?


当前回答

有几种方法可以使用JAX-RS定制错误处理行为。这里有三个更简单的方法。

第一种方法是创建一个扩展WebApplicationException的Exception类。

例子:

public class NotAuthorizedException extends WebApplicationException {
     public NotAuthorizedException(String message) {
         super(Response.status(Response.Status.UNAUTHORIZED)
             .entity(message).type(MediaType.TEXT_PLAIN).build());
     }
}

要抛出这个新创建的异常,只需:

@Path("accounts/{accountId}/")
    public Item getItem(@PathParam("accountId") String accountId) {
       // An unauthorized user tries to enter
       throw new NotAuthorizedException("You Don't Have Permission");
}

注意,您不需要在throws子句中声明异常,因为WebApplicationException是一个运行时异常。这将向客户端返回401响应。

第二种更简单的方法是直接在代码中构造WebApplicationException的实例。只要您不需要实现自己的应用程序异常,这种方法就可以工作。

例子:

@Path("accounts/{accountId}/")
public Item getItem(@PathParam("accountId") String accountId) {
   // An unauthorized user tries to enter
   throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}

这段代码也向客户端返回401。

当然,这只是一个简单的例子。如果需要,您可以使异常更加复杂,并且您可以生成任何您需要的http响应代码。

另一种方法是用一个小的包装器类来包装一个现有的异常(可能是ObjectNotFoundException),该类实现了用@Provider注释注释的ExceptionMapper接口。这告诉JAX-RS运行时,如果引发包装异常,则返回ExceptionMapper中定义的响应代码。

其他回答

一个明显的解决方案:采用字符串,转换为日期自己。这样你就可以定义你想要的格式,捕捉异常并重新抛出或自定义发送的错误。 对于解析,SimpleDateFormat应该可以正常工作。

我相信也有一些方法可以为数据类型钩子处理程序,但是在这种情况下,您可能只需要一点点简单的代码。

有几种方法可以使用JAX-RS定制错误处理行为。这里有三个更简单的方法。

第一种方法是创建一个扩展WebApplicationException的Exception类。

例子:

public class NotAuthorizedException extends WebApplicationException {
     public NotAuthorizedException(String message) {
         super(Response.status(Response.Status.UNAUTHORIZED)
             .entity(message).type(MediaType.TEXT_PLAIN).build());
     }
}

要抛出这个新创建的异常,只需:

@Path("accounts/{accountId}/")
    public Item getItem(@PathParam("accountId") String accountId) {
       // An unauthorized user tries to enter
       throw new NotAuthorizedException("You Don't Have Permission");
}

注意,您不需要在throws子句中声明异常,因为WebApplicationException是一个运行时异常。这将向客户端返回401响应。

第二种更简单的方法是直接在代码中构造WebApplicationException的实例。只要您不需要实现自己的应用程序异常,这种方法就可以工作。

例子:

@Path("accounts/{accountId}/")
public Item getItem(@PathParam("accountId") String accountId) {
   // An unauthorized user tries to enter
   throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}

这段代码也向客户端返回401。

当然,这只是一个简单的例子。如果需要,您可以使异常更加复杂,并且您可以生成任何您需要的http响应代码。

另一种方法是用一个小的包装器类来包装一个现有的异常(可能是ObjectNotFoundException),该类实现了用@Provider注释注释的ExceptionMapper接口。这告诉JAX-RS运行时,如果引发包装异常,则返回ExceptionMapper中定义的响应代码。

如果你想打开浏览器登录窗口,就把@史蒂文拉文的答案作为一个扩展。我发现很难从过滤器中正确返回响应(MDN HTTP身份验证),如果用户还没有经过身份验证

这帮助我构建响应来强制浏览器登录,注意头的额外修改。这将把状态代码设置为401,并设置导致浏览器打开用户名/密码对话框的报头。

// The extended Exception class
public class NotLoggedInException extends WebApplicationException {
  public NotLoggedInException(String message) {
    super(Response.status(Response.Status.UNAUTHORIZED)
      .entity(message)
      .type(MediaType.TEXT_PLAIN)
      .header("WWW-Authenticate", "Basic realm=SecuredApp").build()); 
  }
}

// Usage in the Filter
if(headers.get("Authorization") == null) { throw new NotLoggedInException("Not logged in"); }

方法1:通过扩展WebApplicationException类

通过扩展WebApplicationException创建新的异常

public class RestException extends WebApplicationException {

         private static final long serialVersionUID = 1L;

         public RestException(String message, Status status) {
         super(Response.status(status).entity(message).type(MediaType.TEXT_PLAIN).build());
         }
}

现在在需要的时候抛出'RestException'。

public static Employee getEmployee(int id) {

         Employee emp = employees.get(id);

         if (emp == null) {
                 throw new RestException("Employee with id " + id + " not exist", Status.NOT_FOUND);
         }
         return emp;
}

您可以在此链接查看完整的应用程序。

方法2:实现ExceptionMapper

以下映射器处理类型为“DataNotFoundException”的异常

@Provider
public class DataNotFoundExceptionMapper implements
        ExceptionMapper<DataNotFoundException> {

    @Override
    public Response toResponse(DataNotFoundException ex) {
        ErrorMessage model = new ErrorMessage(ex.getErrorCode(),
                ex.getMessage());
        return Response.status(Status.NOT_FOUND).entity(model).build();
    }

}

您可以在此链接查看完整的应用程序。

我太喜欢StaxMan可能会实现QueryParam作为一个字符串,然后处理转换,重新抛出必要的。

如果特定于区域设置的行为是期望和预期的行为,您将使用以下命令返回400 BAD REQUEST错误:

抛出新的WebApplicationException(Response.Status.BAD_REQUEST);

有关更多选项,请参阅JavaDoc中的javax.ws.rs.core.Response.Status。