CXF / JAX-RS:从拦截器返回自定义响应

在REST调用期间发生exception时,我们需要返回自定义错误代码和错误消息。 我们已经创建了一个exception映射器提供程序,它适用于应用程序代码中的exception。 但是,当从CXF代码发生exception时(例如,形成我编写的CustomValidationInterceptor),它不起作用。

例如,如果我请求无效路径参数(例如无效的phoneNumber)。 在这种情况下,我们需要以JSON格式返回自定义错误代码和错误消息,但即使我们创建了一个exception映射器提供程序来处理WebApplicationException,它也不起作用。

有没有办法处理来自cxf拦截器的exception并返回对用户的响应,如下所示?

{ "errorDetail": { "errorCode": "404", "errorMessage": "Bad Request" } } 

我的CustomValidationInterceptor的代码片段:

 public class CustomValidationInterceptor extends AbstractPhaseInterceptor{ public CustomValidationInterceptor() { super(Phase.PRE_INVOKE); // Put this interceptor in this phase } public void handleMessage(Message message) { MetadataMap metadataMap = (MetadataMap) message.get("jaxrs.template.parameters"); if(null != metadataMap) { List list = metadataMap.get("phoneNumber"); if(null != list) { String phoneNumber = list.get(0); boolean result = validatePhoneNumber(phoneNumber); if(!result){ throw new TelusServiceException(Response.status(Response.Status.BAD_REQUEST).build(), 400, "phone number not valid"); } } else { throw new TelusServiceException(Response.status(Response.Status.BAD_REQUEST).build(), 400, "phone number not valid"); } } else { throw new TelusServiceException(Response.status(Response.Status.BAD_REQUEST).build(), 400, "phone number not valid"); } } public boolean validatePhoneNumber(String phoneNumber) { Pattern pattern = Pattern.compile("^[1-9]\\d{9}$"); Matcher matcher = pattern.matcher(phoneNumber); if (!matcher.matches()) { return false; } return true; } } 

我的自定义exception映射器提供程序的代码片段

 public class TelusExceptionHandler implements ExceptionMapper { public Response toResponse(TelusServiceException exception) { return Response.status(exception.getErrorDetail().getErrorCode()).entity(exception.getErrorDetail()).build(); } } 

TelusServiceException的代码片段

 public class TelusServiceException extends WebApplicationException{ // constructors and other methods private ErrorDetail errorDetail = null; public ErrorDetail getErrorDetail() { return errorDetail; } public void setErrorDetail(ErrorDetail errorDetail) { this.errorDetail = errorDetail; } public TelusServiceException(Response response, int errorCode, String errorMessage) { super(response); errorDetail = new ErrorDetail(); errorDetail.setErrorCode(errorCode); errorDetail.setErrorMessage(errorMessage); } } 

ErrorDetail类的代码片段

 @XmlRootElement(name="errorDetail") public class ErrorDetail { private int errorCode; private String errorMessage; @XmlElement(name = "errorCode") public int getErrorCode() { return errorCode; } public void setErrorCode(int errorCode) { this.errorCode = errorCode; } @XmlElement(name = "errorMessage") public String getErrorMessage() { return errorMessage; } public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } } 

我找到了一种从拦截器发送自定义响应的方法,但仍无法找到从拦截器调用我的CustomExceptionHandler的方法

码:

 public void handleMessage(Message message) { MetadataMap metadataMap = (MetadataMap) message.get("jaxrs.template.parameters"); if(null != metadataMap) { List list = metadataMap.get("phoneNumber"); if(null != list) { String phoneNumber = list.get(0); boolean result = validatePhoneNumber(phoneNumber); if(!result){ // Create a response object and set it in the message. // calling getExchange() will not call your service Response response = Response .status(Response.Status.BAD_REQUEST) .entity(new ErrorDetail(Response.Status.BAD_REQUEST.getStatusCode(), Response.Status.BAD_REQUEST.toString())) .build(); message.getExchange().put(Response.class, response); // That's it } } else { Response response = Response .status(Response.Status.BAD_REQUEST) .entity(new ErrorDetail(Response.Status.BAD_REQUEST.getStatusCode(), Response.Status.BAD_REQUEST.toString())) .build(); message.getExchange().put(Response.class, response); } } else { Response response = Response .status(Response.Status.BAD_REQUEST) .entity(new ErrorDetail(Response.Status.BAD_REQUEST.getStatusCode(), Response.Status.BAD_REQUEST.toString())) .build(); message.getExchange().put(Response.class, response); } } 

我在cxf用户组上提出了类似的问题,请参阅:

http://cxf.547215.n5.nabble.com/Handling-exceptions-in-a-JAX-RS-fault-interceptor-when-using-Local-Transport-td5733958.html

我最终用ContainerRequestFilter和ContainerResponseFilter替换了我的拦截器,然后Exception Mapper愉快地处理了从Filter抛出的应用程序exception和exception。

希望这可以帮助。