JAX-RS jersey 异常映射器 用户自定义异常

38

我是一个新手,试图阅读一些文档,但出现了问题,请耐心等待。

我使用ExceptionMappers创建了一个名为UserNotFoundMapper的对象,代码如下:

public class UserNotFoundMapper implements ExceptionMapper<UserNotFoundException> {

@Override
public Response toResponse(UserNotFoundException ex) {
    return Response.status(404).entity(ex.getMessage()).type("text/plain").build();
}

}

这是我的服务:

@GET
@Path("/user")
public Response getUser(@QueryParam("id") String id) throws UserNotFoundException{
    //Some user validation code with DB hit, if not found then
    throw new UserNotFoundException();
}

"UserNotFoundException是一种用户定义的异常。

我尝试了这个:

"
public class UserNotFoundException extends Exception {
       //SOME block of code 
}

但是当我调用服务时,UserDefinedExceptionMapper 没有被调用。看起来我可能在 UserDefinedException 上漏掉了一些东西。那么如何定义这个异常呢?
请告诉我如何定义 UserNotFoundException
3个回答

55

你需要使用@Provider注释你的异常映射器,否则它将永远不会在JAX-RS运行时中注册。

@Provider
public class UserNotFoundMapper implements
        ExceptionMapper<UserNotFoundException> {
    @Override
    public Response toResponse(UserNotFoundException ex) {
        return Response.status(404).entity(ex.getMessage()).type("text/plain")
                .build();
    }
}

谢谢回复。我需要了解一些与此相关的事情:使用WebApplicationException和使用ExceptionMapper之间有什么区别?我不确定在哪种情况下应该使用哪种 :( 你能否提供你的意见? - WhoAmI
3
@WhoAmI - JAX-RS提供程序会自动映射Web应用程序异常。因此,与例如使用异常映射器不同,您可以扩展WebApplicationException并覆盖其getResponse方法。有些人喜欢为所有仅针对其JAX-RS实现定义的异常执行此操作。但是对于不扩展自WebApplicationException的异常(例如所有标准Java异常、第三方库的异常等等),映射器非常有效。 - Perception
1
@WhoAmI:如果没有详细的说明,Jersey用户指南也很清楚地阐述了这一点。这意味着WebApplicationException在其内部持有一个Response,当您抛出其中之一时,该Response就会返回给用户。 - Ryan Stewart
2
@WhoAmI:使用哪种异常处理方法取决于您。 ExceptionMapper 的优点是,您的代码可以独立于Jersey,并且您还可以映射超出您控制范围的异常(框架异常)。 WebApplicationException 的优点是它更简单易用。 - Ryan Stewart
1
@ryanstewart - 实际上,WebApplicationException的映射行为是JAX-RS规范的一部分,因此它在不同的提供者之间具有可移植性。这是一件非常棒的事情。 - Perception
显示剩余3条评论

3

在创建API时,我通常会创建自己的异常,该异常继承自RuntimeException,这样我就不必一定要捕获我的异常。

这里是一个例子:

注意: 我正在使用带有Jersey的JAX-RS

首先: 创建一个继承自RuntimeException的自定义异常。

public class ExceptionName extends RuntimeException {

private int code;
private String message;

public int getCode(){
    return code;
}

public String getMessage(){
    return message;
}

public ExceptionName(int code, String message) {
    this.code = code;
    this.message = message;
}

}

Also implement a ExceptionMapper

@Provider
public class ExceptionName implements ExceptionMapper<ExceptionName>{

    @Override
    public Response toResponse(ExceptionName exception) {
        return Response.status(exception.getCode()).entity(exception.getMessage()).build();
    }

}

每当我想抛出一个异常时,我只需要在任何地方像这样做,异常映射器会负责返回响应给使用API的客户端。

throw new ExceptionName(500,"there was an error with something here");

-1

有一点小建议,尽量使用Response.Status.NOT_FOUND而不是404等。代码会更易读且不容易出现拼写错误,对于"text/plain"也同样如此。以下是将异常处理的代码。 哦对了,还有一件事,请记得在您的接口中标注@Produces(MediaType.TEXT_PLAIN)

    public class UserNotFoundException extends Exception {
        //...
    }
public class UserServiceImpl implements UserService {
@Override public Response getUser(@QueryParam("id") String id) { final Response response; try{ // 调用用户方法 // 如果一切正常 response = Response.status(Response.Status.OK).entity(whateverYouWant).type(MediaType.TEXT_PLAIN).build(); } catch(UserNotFoundException ex) { response = new UserNotFoundMapper().toResponse(ex); }
return response; } }
在客户端幻灯片中,您可以检查
public static boolean isUserExists(final Response serverResp) { return serverResp != null && serverResp.getStatus() == Response.Status.NOT_FOUND.getStatusCode(); }

6
你不需要手动调用映射器,在服务层中也不应使用Jersey特定的类。这就是映射器存在的全部意义。 - Ryan Stewart
@RyanStewart 感谢您的意见。我是新手,正在尝试学习它。在上面发布的代码中,如果我删除具有throw new UserNotFoundException();的映射器调用行,则可以吗?我无法理解您所说的“您不会在服务层中使用特定于Jersey的类”。您能否稍微详细地解释一下? - WhoAmI
@WhoAmI 你所在的类名为UserServiceImpl,属于服务层而非控制器层。你不想将特定实现(如jax-rs)强加到代码中的其他部分。它的使用应该限制在控制器层。ExceptionMapper可以让你通过jersey处理异常,而无需在整个代码中添加“Response.status”...服务层代码只应执行业务逻辑。 - gaoagong

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接