Search code examples
springspring-mvccontrollerhttp-status-codes

How to setup default success status codes for mapped HttpMethods Spring MVC @RestControllers?


Hi there Spring Gurus,

Currently we are annotating every mapped @RestController method with it's own success @ResponseStatus. I wonder, if there is a possibility for a global setup, based on the mapped @RequestMapping method. On Success we'd like to have:

  • GET -> HttpStatus.OK
  • POST -> HttpStatus.CREATED
  • PUT -> HttpStatus.OK
  • PATCH -> HttpStatus.OK
  • DELETE -> HttpStatus.NO_CONTENT

If possible at all, what do we have to do?

Best regards, Marius


Solution

  • You could do it using a Filter:

    public class ResponseStatusConverterFilter implements javax.servlet.Filter {
    
    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {
    
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
    
        chain.doFilter(request, response);
    
        switch (request.getMethod()) {
            case "GET": response.setStatus(200);
                        break;
            case "POST": response.setStatus(201);
                         break;
            ...
        }
    }
    

    And add filter in web.xml

    <filter>
        <filter-name>responseStatusConverterFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    
    <filter-mapping>
        <filter-name>responseStatusConverterFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    Just be careful with error handling because this could overwrite error response code. You should check response code before overwriting it (e.g check if it's some bad code like 500 or 404 and then do not set it to 200 or 201).

    Another solution:

    Create bean that extends HandlerInterceptorAdapter override

    void postHandle(HttpServletRequest request,
                    HttpServletResponse response,
                    Object handler,
                    ModelAndView modelAndView)
                    throws Exception
    

    and add logic similar to my first solution. Add bean definition to:

    <mvc:interceptors>
       <bean class="com.your.web.ResponseConverterInterceptor" />
    </mvc:interceptors>
    

    Addendum: You will need to wrap HttpServletResponse with your class that extends HttpServletResponseWrapper :

    public class StatusConvertingServletResponse extends HttpServletResponseWrapper {
    
        private int httpStatus;
    
        public StatusConvertingServletResponse(HttpServletResponse response) {
            super(response);
        }
    
        @Override
        public void setStatus(int sc) {
            httpStatus = sc;
            super.setStatus(sc);
        }
    
        @Override
        public int getStatus() {
            return httpStatus;
        }
    }
    

    And use it like:

    StatusConvertingServletResponse res = new StatusConvertingServletResponse((HttpServletResponse)response);
    chain.doFilter(request, res);
    if (res.getStatus() == 200) {
       res.setStatus(n);
    }