41

这将返回 200 OK,内容长度:0

@RestController
public class RepoController {
    @RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
    public Object getDocument(@PathVariable long id) {
       return null;
    }

}

简单地说,我希望它在 null 上返回 204 No Content。

有没有办法强制 spring-mvc/rest 在 null 而不是 200 时返回 204?我不想更改每个休息方法以返回 ResponseEntity 或类似的东西,只将 null 映射到 204

4

7 回答 7

80

您可以使用@ResponseStatus注释。这样您就可以拥有一个 void 方法,而不必构建一个 ResponseEntity。

@DeleteMapping(value = HERO_MAPPING)
@ResponseStatus(value = HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long heroId) {
    heroService.delete(heroId);
}

顺便说一句,当对象存在时返回 200,否则返回 204,否则对于 API REST 设计来说有点不寻常。当未找到请求的对象时,通常会返回 404(未找到)。这可以使用 ControllerAdvice 来实现。

在 Spring REST 中,最好使用异常处理程序来处理异常,而不是使用逻辑来决定响应状态等。这是使用 @ControllerAdvice 注释的示例:http ://www.jcombat.com/spring/exception-handling- in-spring-restful-web 服务

于 2016-11-10T08:11:37.997 回答
36

当然是的。

选项1 :

@RestController
public class RepoController {
    @RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
    public Object getDocument(@PathVariable long id, HttpServletResponse response) {
       Object object = getObject();
       if( null == object ){
          response.setStatus( HttpStatus.SC_NO_CONTENT);
       }
       return object ;
    }
}

选项 2:

@RestController
public class RepoController {
    @RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
    public Object getDocument(@PathVariable long id) {
       Object object = getObject();
       if ( null == object ){
          return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
       }

       return object ;
    }
}

可能有错别字,但你明白了这个概念。

于 2015-09-04T11:34:28.003 回答
14

我用过滤器解决了这个问题。它是全球性的和简单的。

package your.package.filter;

import org.springframework.http.HttpStatus;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

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("")) {
            httpServletResponse.setStatus(HttpStatus.NO_CONTENT.value());
        }
    }
}

并在您的 web.xml 中添加以下内容

<filter>
    <filter-name>restNoContentFilter</filter-name>
    <filter-class>your.package.filter.NoContentFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>restNoContentFilter</filter-name>
    <url-pattern>/rest/*</url-pattern>
</filter-mapping>
于 2017-02-24T23:10:22.350 回答
5

你可以试试这个:

@RestController
public class RepoController {

    @RequestMapping(value = "/document/{id}", method = RequestMethod.GET)
    public ResponseEntity<String> getDocument(@PathVariable long id) {

       if(noError) {
           ............
           return new ResponseEntity<String>(HttpStatus.OK); 
       }
       else {
           return new ResponseEntity<String>(HttpStatus.BAD_REQUEST);
       }
   }
}

您需要将 HttpStatus.BAD_REQUEST 更改为 204 代码状态的等效项

于 2015-09-04T11:34:36.617 回答
2

问题很旧,但对于那些需要全局答案并拥有 Spring 4+ 的人,您可以创建一个 ResponseBodyAdvice 来根据控制器响应更改响应代码。以下示例适用于所有 @RestController 类:

@ControllerAdvice(annotations = { RestController.class })
public class NullToNoContentResponseBodyAdvice
    implements ResponseBodyAdvice<Object>
{
    /**
     * {@inheritDoc}
     */
    @Override
    public Object beforeBodyWrite(final Object p_responseBodyObject, final MethodParameter p_methodParameter,
                                  final MediaType p_mediaType, final Class<? extends HttpMessageConverter<?>> p_class,
                                  final ServerHttpRequest p_serverHttpRequest,
                                  final ServerHttpResponse p_serverHttpResponse)
    {
        // ------------------------- DECLARE -------------------------- //

        if (p_responseBodyObject == null)
        {
            p_serverHttpResponse.setStatusCode(HttpStatus.NO_CONTENT);
        }

        // Always return object unchanged or it will break response
        return p_responseBodyObject;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean supports(final MethodParameter p_methodParameter, final Class<? extends HttpMessageConverter<?>> p_class)
    {
        return AbstractGenericHttpMessageConverter.class.isAssignableFrom(p_class);
    }
}
于 2020-01-24T10:50:14.820 回答
1

相同的答案,但由 AOP 解决:

@Aspect
public class NoContent204HandlerAspect {

  @Pointcut("execution(public * xx.xxxx.controllers.*.*(..))")
  private void anyControllerMethod() {
  }

  @Around("anyControllerMethod()")
  public Object handleException(ProceedingJoinPoint joinPoint) throws Throwable {

    Object[] args = joinPoint.getArgs();

    Optional<HttpServletResponse> response = Arrays.asList(args).stream().filter(x -> x instanceof HttpServletResponse).map(x -> (HttpServletResponse)x).findFirst();

    if (!response.isPresent())
      return joinPoint.proceed();

    Object retVal = joinPoint.proceed();
    if (retVal == null)
      response.get().setStatus(HttpStatus.NO_CONTENT.value());

    return retVal;
  }
}
于 2017-02-03T11:45:44.123 回答
0

您可以自定义自己HttpMessageConverter来支持这一点,就像我这样做,添加spring.http.converters.preferred-json-mapper=gsonapplication.properties配置文件中,结果建议如下:

@ControllerAdvice
public class CommonResultAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
    return true;
}

@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {

    if (null == o) {
    //set http code
        serverHttpResponse.setStatusCode(HttpStatus.NO_CONTENT);
        return BaseResult.success();
    }

    if (o instanceof String) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writeValueAsString(BaseResult.success(o));
        } catch (JsonProcessingException ignore) {
        }
    }

    if (o instanceof BaseResult) {
        return o;
    }
    return BaseResult.success(o);
}

}

或自定义HttpMessageConverter这样的:

@Configuration
public class BeanConfiguration {
@Bean
public HttpMessageConverter resultToJsonConverter() {
    return new GsonHttpMessageConverter();
}
}

希望能帮到你。:)

于 2020-08-24T08:37:17.437 回答