单元返回类型为的Spring-Post方法返回200而不是204

单元返回类型为的Spring-Post方法返回200而不是204,spring,spring-boot,kotlin,Spring,Spring Boot,Kotlin,当执行一个返回类型为Unit的方法时,我希望spring不会在响应中的状态代码上添加任何内容,但是它总是返回200ok。有没有办法在全球范围内改变这种行为?我不想向每个单元方法添加ResponseStatus注释 @RestController() @RequestMapping("/{role:(?:veterinarian\\b|admin\\b)}") class EmployeeController( private val userService: UserServic

当执行一个返回类型为Unit的方法时,我希望spring不会在响应中的状态代码上添加任何内容,但是它总是返回200ok。有没有办法在全球范围内改变这种行为?我不想向每个单元方法添加ResponseStatus注释

@RestController()
@RequestMapping("/{role:(?:veterinarian\\b|admin\\b)}")
class EmployeeController(
        private val userService: UserService
) {

    @PostMapping(consumes = [MediaType.APPLICATION_JSON_UTF8_VALUE])
    fun hire(@RequestBody employeeDTO: EmployeeDTO, @PathVariable role: String): Unit {
        if (employeeDTO.user_role != role)
            throw ResponseStatusException(HttpStatus.BAD_REQUEST)
        else
            userService.addNewUser(EmployeeDAO.build(employeeDTO))
    }
}
更新:

最后我使用了一个过滤器来检查内容类型是否未定义,当状态响应为200 OK并且似乎正常时

这是过滤代码

@Component
public class NoContentFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(httpServletRequest, httpServletResponse);
        if (httpServletResponse.getContentType() == null ||
                httpServletResponse.getContentType().equals("")) {
            if ( httpServletResponse.getStatus() == 200 ) {
                httpServletResponse.setStatus(HttpStatus.NO_CONTENT.value());
            }
        }
    }
}

Spring允许通过@ControllerAdvice配置控制器的全局行为

用@ControllerAdvice注释的类可以包含@ExceptionHandler、@InitBinder和@ModelAttribute注释的方法,这些方法将应用于所有控制器层次结构中的@RequestMapping方法,而不是声明它们的控制器层次结构

通常,我们使用它通过
@ExceptionHandler
全局处理异常,但这不是您的情况。(
@InitBinder
@modeldattribute

responseDataAdvice
但没有
ResponseStatusAdvice

因此,似乎没有直接的解决方案

解决方法:

这是一个相当肮脏的黑客行为,我真的建议你每次只使用@ResponseStatus,但如果你真的想在全球范围内解决这个问题,那么:

您可以将错误处理和响应建议结合起来

您应该创建一个异常类

class NoContentException: RuntimeException()
为它创建一个处理程序。它应该在
@ControllerAdvice
之后调用,这将不会引发ContentException,因此它具有
@Order(1)

@ControllerAdvice
@订单(1)
类NoContentErrorHandler{
@ExceptionHandler(NoContentException::类)
fun handleNoContent()=ResponseEntity.noContent().build()
}
最后,创建一个响应主体建议,该建议引发实际异常:

@ControllerAdvice
@Order(0)
class ThrowingNoContentExceptionResponseBodyAdvice : ResponseBodyAdvice<Unit> {
    override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean {
        return returnType.parameterType == Void.TYPE
    }

    override fun beforeBodyWrite(
        body: Unit?,
        returnType: MethodParameter,
        selectedContentType: MediaType,
        selectedConverterType: Class<out HttpMessageConverter<*>>,
        request: ServerHttpRequest,
        response: ServerHttpResponse
    ): Unit? {
        throw NoContentException()
    }
}
@ControllerAdvice
@订单(0)
类ThrowingNoContentExceptionResponseBodyAdvice:ResponseBodyAdvice{
覆盖有趣的支持(returnType:MethodParameter,converterType:Class):布尔{
returnType.parameterType==Void.TYPE
}
在bodywrite之前覆盖乐趣(
主体:单位?,
returnType:MethodParameter,
selectedContentType:MediaType,
selectedConverterType:Class,
请求:ServerHttpRequest,
响应:ServerHttpResponse
):单位{
抛出NoContentException()
}
}
所以它的工作原理是:
请求->带有单元响应调用的方法->抛出异常的建议->处理异常并将其转换为无内容状态的建议

请参阅此帖子:有几条建议可能对您有帮助我将尝试使用过滤器调整答案。我添加了一个检查,以确保响应状态为200,这样它就不会干扰身体可能为空的其他响应(如错误)。我希望有一个使用
@ControllerAdvice
的解决方案。我会重新考虑使用
@ResponseStatus
,或者尝试使用
OncePerRequestFilter
,因为我同意你的观点,这是一种非常肮脏的解决方法。谢谢你的回答
@ControllerAdvice
@Order(0)
class ThrowingNoContentExceptionResponseBodyAdvice : ResponseBodyAdvice<Unit> {
    override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean {
        return returnType.parameterType == Void.TYPE
    }

    override fun beforeBodyWrite(
        body: Unit?,
        returnType: MethodParameter,
        selectedContentType: MediaType,
        selectedConverterType: Class<out HttpMessageConverter<*>>,
        request: ServerHttpRequest,
        response: ServerHttpResponse
    ): Unit? {
        throw NoContentException()
    }
}