Kotlin + Spring Boot请求编组

Jas*_*ues 3 java spring jackson kotlin spring-boot

鉴于以下有效负载:

data public class CandidateDetailDTO(val id: String,
                                     val stageName: String,
                                     val artists: Iterable<ArtistDTO>,
                                     val instruments: Iterable<InstrumentDTO>,
                                     val genres: Iterable<GenreDTO>,
                                     val discoverable: Boolean,
                                     val gender: Gender,
                                     val involvement: Involvement,
                                     val biography: String,
                                     var photoURLs: List<URL>,
                                     var birthday: Date? = null,
                                     var customGenre: String? = null)
Run Code Online (Sandbox Code Playgroud)

..如图所示,某些字段允许为空,其他字段不允许.

使用Spring Boot调用请求时,如果缺少预期字段,则返回400 - Bad Request.这是不太令人期待的,我期望相关的控制器建议适用:

@ControllerAdvice
public class SomeExceptionHandler : ResponseEntityExceptionHandler()
{
    @ExceptionHandler(Throwable::class)
    @ResponseBody
    public fun onException(ex: Throwable): ResponseEntity<ErrorResponse>
    {
        val responseCode = ex.responseCode()
        val errorResponse = ErrorResponse(response = ResponseHeader(responseCode, ex.message))
        return ResponseEntity(errorResponse, responseCode.httpStatus());
    }

}
Run Code Online (Sandbox Code Playgroud)

..如果它有,它也会返回400,以及一些关于出了什么问题的额外信息.

是否可以将Spring Boot配置为如上所述?

Jay*_*ard 11

默认情况下,如果不干扰异常处理,Spring Boot将在响应正文中以JSON形式返回完整的错误信息.但它不允许您reasonString在HTTP标头中设置状态代码.

问题:

@ControllerAdvice
public class BadExceptionHandler: ResponseEntityExceptionHandler()
{
    @ExceptionHandler(Throwable::class)
    @ResponseBody
    public fun onException(ex: Throwable): ResponseEntity<ErrorResponse>
    {
        val responseCode = ex.responseCode()
        val errorResponse = ErrorResponse(response = ResponseHeader(responseCode, ex.message))
        return ResponseEntity(errorResponse, responseCode.httpStatus());
    }
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,您是子类,ResponseEntityExceptionHandler但不要覆盖其任何方法.相反,你添加一个@ExceptionHandler用于Throwable将不会执行.更明确的基类注册@ExceptionHandler将赢得,因为它按具有优先级的特定类型注册每个异常类.

并且意外地让它ResponseEntityExceptionHandler做默认行为(将主体设置为null),您也丢失了自定义错误消息JSON响应.正确使用ResponseEntityExceptionHandler是将其子类化然后覆盖其中一个错误方法:

  • handleBindException
  • handleMissingServletRequestParameter
  • handleServletRequestBindingException
  • handleTypeMismatch
  • handleMethodArgumentNotValid
  • ...

当覆盖这些方法时,您更难设置HTTP状态,reasonString因为响应实体会收到一个HttpStatusCode永远不允许您更改reasonString其中一个预定义值的响应实体.您可以使用完整的错误信息返回一个正文,并让状态代码保持通用.

解决方案:

第一个选项是完全删除自定义错误处理程序,它干扰了您已经想要的默认行为.

第二个选项,如果你使用ResponseEntityExceptionHandler那么你需要覆盖正确的方法,你可以在响应的主体中返回一个带有你的消息的实体(参见:Spring Boot REST服务异常处理)...这篇文章涵盖了很多你的无论如何问题.一定要设置一个身体,而不是将null身体传递给身体handleExceptionInternal().

第三个选项是删除ResponseEntityExceptionHandler和保留与您的问题类似的代码:

data class ErrorResponse(val statusCode: Int,  val statusMessage: String, val message: String)

@ControllerAdvice
public class SomeExceptionHandler
{
    @ExceptionHandler(Throwable::class)
    @ResponseBody
    public fun onException(ex: Throwable): ResponseEntity<ErrorResponse>
    {
        val httpError = HttpStatus.BAD_REQUEST
        val errorResponse = ErrorResponse(httpError.value(), httpError.reasonPhrase, ex.message ?: "Bad Thing")
        return ResponseEntity(errorResponse, httpError);
    }
}
Run Code Online (Sandbox Code Playgroud)

这会产生类似于:

{
    "response": {
        "code": "VAMPServiceError",
        "message": "Could not read document: No suitable constructor found for type [simple type, class vampr.api.service.profile.payload.CandidateUpdateDTO]"
    }
}
Run Code Online (Sandbox Code Playgroud)

第四个选项是创建一个不同形式的异常处理程序,该异常处理程序调用response.sendError()发回JSON错误,这是Spring Boot的正常默认值,但允许您执行其他逻辑.这看起来像:

@ControllerAdvice
public class UniversalExceptionHandler
{
    @ExceptionHandler(SomeException::class)
    fun handleBadRequests(ex: Throwable, response: HttpServletResponse){
        // .. some logic
        response.sendError(HttpStatus.BAD_REQUEST.value(), ex.message)
    }
}
Run Code Online (Sandbox Code Playgroud)

这会产生:

{
    "timestamp": 1452730838233,
    "status": 400,
    "error": "Bad Request",
    "exception": "org.springframework.web.bind.MissingServletRequestParameterException",
    "message": "Required String parameter 'name' is not present",
    "path": "/greeting"
}
Run Code Online (Sandbox Code Playgroud)

也可以看看:


归档时间:

查看次数:

4302 次

最近记录:

6 年,8 月 前