如何在异常处理程序

时间:2020-05-15 06:14:01

标签: java spring-boot

我们有一个spring boot应用程序,我们的控制器希望在我们的端点之一中使用XML Document元素:

@PostMapping(value = "/api/v1/do-stuff",
        consumes = APPLICATION_XML_VALUE,
        produces = APPLICATION_XML_VALUE)
public ResponseEntity<JAXBElement<my.company.stuff.resposnse.Document>> doStuff(
        @RequestBody JAXBElement<my.company.stuff.request.Document> requestBody,
        Principal principal) throws Exception {

    // Doing some suff here and returning the result
    return stuffService.doStuff(...);
}

我们有自己的Jaxb2Marshaller实例,我们在其中设置了请求文档和响应文档的架构,以用于在请求和响应主体与我们的域对象之间进行编组和解组。当请求到来时,Spring Boot框架将在请求主体与域请求文档之间进行转换。有时,请求主体没有通过XSD模式验证,因此甚至没有到达我们的控制器。

引发的异常将传递到我们的自定义扩展org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler中,在该扩展中,我们希望为我们的应用程序客户端创建最有意义的错误响应:

    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
            HttpHeaders headers, HttpStatus status, WebRequest request) {
        // Getting access to the request body would be very beneficial here
    }

我们的问题是,有时传递给我们的处理程序的异常没有足够的详细信息,我们希望能够访问请求正文,以便能够自定义对客户端的响应。但是,该请求的输入流不再可访问,因为已经从模式验证(转换)处理的一部分中读取了该请求,因此以这种方式进行访问的任何尝试都会失败。

另一方面,我们试图实现的目标是非常常识,只是想知道我们是否采用了错误的方法,以及哪种方法可以更好地实现同一目标。更改控制器以期望使用纯文本并进行验证并将其转换为控制器内部的请求文档并不是真正的选择。

预先感谢您或您的投入。

3 个答案:

答案 0 :(得分:0)

您可以创建一个请求范围实体,以保留请求主体,

@Component
@RequestScope
public class RequestDetails {
    private JAXBElement<my.company.stuff.request.Document> requestBody;
    //getter setter
}

在控制器中使用它来设置请求正文,

@Inject
RequestDetails requestDetails;

public ResponseEntity<JAXBElement<my.company.stuff.resposnse.Document>> doStuff(
        @RequestBody JAXBElement<my.company.stuff.request.Document> requestBody,
        Principal principal) throws Exception {
    requestDetails.setRequestBody(requestBody); //set request body
    // Doing some suff here and returning the result
    return stuffService.doStuff(...);
}

然后将RequestDetails注入ExceptionHandler并使用,

Document requestBody = requestDetails.getRequestBody();

答案 1 :(得分:0)

您应该使用ControllerAdvice

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    protected void handleHttpMessageNotReadableException(HttpMessageNotReadableException ex,
                                                              HttpServletResponse response,HttpServletRequest request {
      // you have full access to both request and response
    }

如果这不适合您的情况,我认为您可以:

@Autowired
private HttpServletRequest request;

答案 2 :(得分:0)

您可以再添加一个参数HttpServletRequest,然后您将收到请求。 示例:

@RestControllerAdvice
@Slf4j
public class InvalidRequestExceptionHandler {

    @ExceptionHandler(InvalidRequestException.class)
    public ResponseEntity<BusinessLogicValidationError> handle(InvalidRequestException exception, HttpServletRequest request) {

    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("some text");
    }
}
相关问题