1 General Description

The last blog post, “Building a Common service for a unified back End interface return data format,” described how to build a common service to complete a unified back end interface return data format and introduce and use common services in business services. After a public service is introduced and configured to take effect, it takes effect on all Rest interfaces by default. In order to provide more flexibility, we modified the public service to provide custom annotations instead of @RestController. Only the Controller interface that references custom annotations encapsulates the returned data format. The Controller interface identified by the @restController annotation is not handled.

In the previous article we mentioned intercepting all @RestControllerAdvice via @RestControllerAdvice. The @RestControllerAdvice annotation and ResponseBodyAdvice interface enable the return data to be wrapped when the interface call is normal. The beforeBodyWrite method of ResponseBodyAdvice determines whether to apply the beforeBodyWrite method of ResponseBodyAdvice to the current controller interface. The ‘ResponseBodyAdvice interface is also where we encapsulate the logic of the returned data format.

In order to implement the controller interface that intercepts and encapsulates only custom annotations, we can check whether the current controller has custom annotations in ResponseBodyAdvice#support and return true if so. Otherwise return false no longer encapsulated by ResponseBodyAdvice#beforeBodyWrite method.

Now the question becomes how to know the controller interface annotation information in responseBodyAdvance #support, A search on the net to find through WebMvcConfigurer and HandlerInterceptorAdapter interface can get annotation information of the controller. Requst = responseBodyAdvice@responseBodyAdvice@responseBodyQuest ();

Basic logic sorted out, dry. WebMvcConfigurer and HandlerInterceptorAdapter, of course, the working principle of the interface, it’s life cycle need further comb, but does not affect currently in use.

References:

Get the Controller method name and annotation information in the SpringMVC interceptor (used to verify permissions)

Master SpringBoot — Part 3: A detailed description of the WebMvcConfigurer interface

2. Reform of public services

2.1 Definition of Annotations

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited @Documented @RestController @RequestMapping public @interface ComRestController { @AliasFor(annotation = RequestMapping.class) String[] value() default {}; @AliasFor(annotation = RequestMapping.class) String[] path() default {}; @AliasFor(annotation = RequestMapping.class) String[] produces() default {"application/json; charset=UTF-8"}; @AliasFor(annotation = RequestMapping.class) String[] consumes() default {}; }Copy the code

2.2 WebMvcConfigurer interface implementation

@configuration // Must add this annotation, Spring to the unified management of the current interceptor instance public class ComRestControllerConfigure implements WebMvcConfigurer {/ * is executed in application startup phase * / @ Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new ComRestControllerInterceptor());  }}Copy the code

2.3 HandlerInterceptor interface implementation

public class ComRestControllerInterceptor implements HandlerInterceptor { public static final String REST_CONTROLLER_ANNO = "REST_CONTROLLER_ANNO"; /* Override public Boolean preHandle(HttpServletRequest Request, HttpServletResponse Response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod)  handler; Class<? > clazz = handlerMethod.getBeanType(); request.setAttribute(REST_CONTROLLER_ANNO, clazz.isAnnotationPresent(ComRestController.class)); } // When true is returned, the next interceptor in the interceptor chain is executed until all interceptors' preHandle methods are completed, and the intercepted request is executed when false is returned. The preHandle method following the interceptor chain and the intercepted request return true are no longer executed. }}Copy the code

2.4 Returned Result of Abnormal Encapsulation Interface

You only need to modify the support method to indirectly check whether the current controller has the ComRestController annotation.

@restControllerAdvice // Intercept the return value of the Controller method, process the return value/response body uniformly, Public class RestResponseAdvice implements ResponseBodyAdvice<Object> {@autoWired private ObjectMapper objectMapper; */ @override public Boolean supports(MethodParameter, Class<? extends HttpMessageConverter<? >> aClass) { RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); // With custom ComRestController annotations enable encapsulating return data, If (requestAttributes Instanceof ServletRequestAttributes) {ServletRequestAttributes ServletRequestAttributes = (ServletRequestAttributes) requestAttributes; return Boolean.parseBoolean(String.valueOf(servletRequestAttributes.getRequest(). getAttribute(ComRestControllerInterceptor.REST_CONTROLLER_ANNO))); } return true; */ @sneakythrows @Override public Object beforeBodyWrite(Object O, MethodParameter MethodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<? >> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { if(o instanceof String){ return objectMapper.writeValueAsString(ResultData.success(o)); } if (o instanceof ResultData) { return o; } return ResultData.success(o); }}Copy the code

2.5 Project Structure

3 Service service reference

Installation of public services, introduction of business services Public services and configuration refer to the previous blog and will not be covered here.

3.1 Interface Verification

(1) Use the @RestController annotation of SpringBoot

@RestController
@RequestMapping("/api/original")
public class RestOriginal {
​
    @GetMapping("/success")
    public String GetSuccess() {
        return "hello, don!";
    }
​
    @GetMapping("/error")
    public int GetError() {
        return 6/0;
    }
}
Copy the code

The result of the interface call returns a string without wrapping.

(2) Use custom @comrestController annotations

@comrestController // Custom annotation @requestMapping ("/ API /anno") public class RestAnno {@getMapping ("/success") public String GetSuccess() { return "hello, don!" ; } @GetMapping("/error") public int GetError() { return 6/0; }}Copy the code

Interface call results are uniformly encapsulated