鉴于以下POJO:
public class BaseEntity {
public Long id;
// ctor, getter & setter
}
public class Widget extends BaseEntity {
public String fizz;
public Boolean isBuzz;
// ctor, getters & setters
}
我有针对远程REST服务的CRUDding Widget
实例的以下客户端API:
public class WidgetServiceClient {
public void createWidget(Widget w) {
// RESTful call: POST localhost/widgets
}
public Widget getWidgetById(Long id) {
// RESTful call: GET localhost/widgets/{id}
}
}
暴露了以下RESTful服务端点:
public class WidgetService {
// Web server passes POST localhost/widgets/ calls to this method.
public Widget createWidget(Widget w) {
// Create the 'w' widget in the DB and return it with its DB-generated ID.
}
// Web server passes GET localhost/widgets/{id} calls to this method.
public Widget getWidgetById(Long id) {
// Ask the DB for the Widget with the passed-in 'id'. If it exist return it.
// Otherwise return NULL.
}
}
让我们假设我已经找到了将Widget
实例序列化/反序列化为JSON的“神奇”。
这个设计很棒,除了,当有一个服务器端Exception
,我想要回传给客户端,RESTful。
我的第一个倾向是修改BaseEntity
以获得可用于将服务器端错误传达回客户端的Throwable
:
public class BaseEntity {
public Long id;
public Throwable error;
// ctor, getters & setters
}
那么:
public class WidgetService {
// Web server passes POST localhost/widgets/ calls to this method.
public Widget createWidget(Widget w) {
try {
// Create the 'w' widget in the DB and return it with its DB-generated ID.
} catch(Throwable t) {
w.setError(t);
}
return w;
}
// Web server passes GET localhost/widgets/{id} calls to this method.
public Widget getWidgetById(Long id) {
Widget w = new Widget();
try {
// Ask the DB for the Widget with the passed-in 'id'. If it exist return it.
// Otherwise return NULL.
} catch(Throwable t) {
w.setError(t);
}
return w;
}
}
但是这感觉很糟糕/ hacky,我想知道Javaland的其他居民是否已经找到了解决这个问题的更好的方法/策略。我发生使用Jersey&杰克逊用于REST /序列化,但我认为解决方案应该与框架无关。
当服务返回NULL时,它也没有帮助,这可能发生。
所以我问:如何在客户端和服务器之间来回传递Widget
实例,RESTful,但仍然允许服务器返回NULL并Exceptions
/ Throwables
吗
答案 0 :(得分:2)
我建议将模型响应和错误响应分开 - 分离关注点。假设Jersey,Jersey了解如何从WebApplicationExceptions中获取响应,允许您在错误响应中提供丰富的错误信息,以帮助您的客户了解出现了什么问题。
作为一个简短的示例,您可以将签名保留为返回的Widget,并在出错时抛出WebApplicationException派生类。您的客户将在成功时收到200 Widget,在异常时收到404响应(例如下面)。
// Web server passes GET localhost/widgets/{id} calls to this method.
public Widget getWidgetById(Long id) {
Widget w = new Widget();
try {
// Ask the DB for the Widget with the passed-in 'id'. If it exist return it.
// Otherwise return NULL.
} catch(NotFoundException e) {
throw new NotFoundException(Response.status(Response.Status.NOT_FOUND)
.entity("Widget " + id + " not found.").build());
} catch(Exception e) {
throw new WebApplicationException(Response
.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("I don't know what happened, but trying again won't help: "
+ e.getMessage())
.build());
}
return w;
}
注意:除非您定义自定义ExceptionMapper
,否则仅将响应返回给客户端注意:如果您独立处理特定的异常,您的代码将更具可读性,而不是捕获Throwable。上面,我已将每个java异常映射到一般的Jersey内部服务器错误。
答案 1 :(得分:1)
我想你可能想要使用Jaxrs机制@Provider:JAX-RS jersey ExceptionMappers User-Defined Exception
@Provider
public class UserNotFoundMapper implements
ExceptionMapper<UserNotFoundException> {
@Override
public Response toResponse(UserNotFoundException ex) {
return Response.status(404).entity(ex.getMessage()).type("text/plain")
.build();
}
}