50.4. 将例外映射到 Responses
概述
有些实例会抛出 WebApplicationException 异常不现实或不可能。例如,您可能不希望捕获所有可能的异常,然后为它们创建一个 WebApplicationException。您可能还希望使用自定义例外来更轻松地处理应用程序代码。
为了处理这些情况,JAX-RS API 允许您实施自定义异常提供程序,该提供程序生成要发送到客户端的 Response
对象。通过实施 ExceptionMapper<E> 接口来创建自定义异常提供程序。当使用 Apache CXF 运行时注册时,每当抛出类型 E
异常时,将使用自定义供应商。
如何选择例外映射程序
两个情况下都会使用例外映射器:
- 当抛出任何异常或其子类时,运行时将检查适当的异常映射器。如果处理特定的异常抛出,则会选择一个异常映射器。如果抛出的具体例外映射程序没有例外,则会选择例外的超级类例外映射器。
默认情况下,WebApplicationException 将由默认的映射程序
WebApplicationExceptionMapper
处理。即使注册了额外的自定义映射器,它可能会处理 WebApplicationException 异常(例如,自定义RuntimeException
映射器),也不会 使用自定义映射器,而是使用WebApplicationExceptionMapper
。但是,可以通过在
Message
对象中将default.wae.mapper.least.specific
属性设为true
来更改此行为。启用此选项后,默认的WebApplicationExceptionMapper
会重新分配给最低优先级,以便处理带有自定义例外映射器的 WebApplicationException 异常。例如,如果启用了此选项,可以通过注册自定义RuntimeException
映射器来捕获 WebApplicationException 异常。请参阅 “为 WebApplicationException 注册异常映射器”一节。
如果没有为异常找到异常,则会将异常嵌套在 ServletException 异常中,并传递到容器运行时。然后,容器运行时将确定如何处理异常。
实施异常映射器
异常映射程序是通过实现 javax.ws.rs.ext.ExceptionMapper<E> 接口来创建的。如 例 50.5 “例外映射器接口” 所示,接口具有单一方法 toResponse ()
,它将原始异常取为参数并返回 Response
对象。
例 50.5. 例外映射器接口
public interface ExceptionMapper<E extends java.lang.Throwable> { public Response toResponse(E exception); }
异常映射程序创建的 Response
对象由运行时处理,就像任何其他 Response
对象一样。生成的对消费者的响应将包含在 Response
对象中封装的状态、标头和实体正文。
异常映射程序实现被视为运行时的供应商。因此,它们必须使用 @Provider
注释进行解码。
如果在构建 Response
对象时出现异常,则运行时会向消费者发送状态为 500 Server Error
的响应。
例 50.6 “将异常映射到响应” 显示一个例外映射程序,它截获 Spring AccessDeniedException 异常,并生成带有 403 Forbidden
状态和空实体正文的响应。
例 50.6. 将异常映射到响应
import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import org.springframework.security.AccessDeniedException; @Provider public class SecurityExceptionMapper implements ExceptionMapper<AccessDeniedException> { public Response toResponse(AccessDeniedException exception) { return Response.status(Response.Status.FORBIDDEN).build(); } }
运行时会捕获任何 AccessDeniedException 异常,并创建没有实体正文和 403
状态的 Response
对象。然后,运行时会将 Response
对象处理为正常响应。结果是消费者将收到 HTTP 响应,状态为 403
。
注册异常映射器
在 JAX-RS 应用可以使用异常映射程序之前,必须将异常映射器注册到运行时。异常映射程序使用应用程序配置文件中的 jaxrs:providers
元素与运行时注册。
jaxrs:providers
元素是 jaxrs:server
元素的子级,包含 bean
元素的列表。每个 bean
元素定义一个异常映射器。
例 50.7 “将异常映射器注册到运行时” 显示 JAX-RS 服务器,配置为使用自定义例外映射器 SecurityExceptionMapper
。
例 50.7. 将异常映射器注册到运行时
<beans ...> <jaxrs:server id="customerService" address="/"> ... <jaxrs:providers> <bean id="securityException" class="com.bar.providers.SecurityExceptionMapper"/> </jaxrs:providers> </jaxrs:server> </beans>
为 WebApplicationException 注册异常映射器
为 WebApplicationException
异常注册例外映射程序是一个特殊情况,因为此异常类型由默认的 WebApplicationExceptionMapper
自动处理。通常,即使您注册了您要处理 WebApplicationException
的自定义映射程序,它仍将继续由默认的 WebApplicationExceptionMapper
处理。要更改此默认行为,您需要将 default.wae.mapper.least.specific
属性设为 true
。
例如,以下 XML 代码演示了如何在 JAX-RS 端点上启用 default.wae.mapper.least.specific
属性:
<beans ...> <jaxrs:server id="customerService" address="/"> ... <jaxrs:providers> <bean id="securityException" class="com.bar.providers.SecurityExceptionMapper"/> </jaxrs:providers> <jaxrs:properties> <entry key="default.wae.mapper.least.specific" value="true"/> </jaxrs:properties> </jaxrs:server> </beans>
您还可以在拦截器中设置 default.wae.mapper.least.specific
属性,如下例所示:
// Java public void handleMessage(Message message) { m.put("default.wae.mapper.least.specific", true); ...