简体   繁体   中英

Spring Boot equivalent to JAX-RS Interceptors

I would like to wrap the response of my @RestController method into different object structure before Jackson starts to serialize the response to JSON. Let's say I work with the following Spring controller.

@RestController
@RequestMapping("/api/susu")
public class SusuController {

    @RequestMapping(path = "/{id}", method = RequestMethod.GET)
    public Susu hello(String id) {
        Susu susu = new Susu();
        susu.setDate(LocalDate.now());
        susu.setName("Peter Pan");
        return susu;
    }
}

In JEE7 I used JAX-RS Interceptor the get access to the Susu instance and wrap it.

@Provider
@Priority(1)
public class JsonStructureInterceptor implements WriterInterceptor {

  private final JsonResponseBuilder jsonResponseBuilder = new JsonResponseBuilder();

  @Override
  public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {

    Susu s = (Susu) context.getEntity(); // read the JAX-RS response entity

    JsonObject jsonObjectWithStructure = jsonResponseBuilder.toResponse(s); // wrap it

    // add it back into the JAX-RS context
    context.setEntity(jsonObjectWithStructure);
    context.proceed();
  }
}

When using Spring Boot what is the preferred way to to something equivalent without using JAX-RS features?

Update 1: Using a HandlerInterceptorAdapter

I added the following HandlerInterceptorAdapter to my application context and the postHandle method gets called. Everything works fine so far but I cannot figure out how to get the Susu instance and how to pass the wrapped instance over for further processing.

@Component
public class SusuHandlerInterceptor extends HandlerInterceptorAdapter {

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        Susu s = ; // how to get access to my Susu instance?


        Wrapper w = new Wrapper(s);

        // how to pass Wrapper instance on?

    }
}

Update 2: Implementing a ResponseBodyAdvice

I found another approach that allows me to access the return value of my controller action. The problem here is that I cannot change the type of the return value. It seems it is not possible to wrap Susu instance in a Wrapper instance.

@ControllerAdvice
public class JsonFilter implements ResponseBodyAdvice<SusuController.Susu> {


    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public SusuController.Susu beforeBodyWrite(SusuController.Susu body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return body;
    }
}

Implementing a ResponseBodyAdvice lets you modify the object before it's converted.

If the return-type should be modified, one has to omit the Generic-types:

@ControllerAdvice
class JsonModifyingAdvice implements ResponseBodyAdvice {

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
        Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        return new WrappedResponse(body);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM