天天看點

spring-boot統一包裝傳回體版本方案參考:

版本

Spring-boot:2.3.1

方案

使用攔截器

常量類

定義一個統一的辨別

public class Constant {
    public static final String RESPONSE_RESULT_ANNOTATION = "RESPONSE_RESULT_ANNOTATION";
}
           

傳回體

import org.springframework.http.HttpStatus;

import java.io.Serializable;

/**
 * 接口傳回對象
 */
public class Result<T> implements Serializable {
   private static final long serialVersionUID = 1L;
   private static Result<Object> result = new Result<>();

   /**
    * 失敗消息
    */
   private String message;

   /**
    * 傳回代碼  
    */
   private Integer code;

   /**
    * 時間戳
    */
   private long timestamp = System.currentTimeMillis();

   /**
    * 結果對象
    */
   private T data;

   public Integer getCode() {
      return code;
   }

   public void setCode(Integer code) {
      this.code = code;
   }

   public long getTimestamp() {
      return timestamp;
   }

   public void setTimestamp(long timestamp) {
      this.timestamp = timestamp;
   }

   public String getMessage() {
      return message;
   }

   public void setMessage(String message) {
      this.message = message;
   }

   public T getData() {
      return data;
   }

   public void setData(T data) {
      this.data = data;
   }

   private Result() {}

   public static Result success() {
      Result result = new Result();
      result.setCode(HttpStatus.OK.value());
      return result;
   }

   public static Result<Object> success(Object data) {
      result.setCode(HttpStatus.OK.value());
      result.setData(data);
      return result;
   }

    public static Result<Object> success(Object data, String message) {
        result.setCode(HttpStatus.OK.value());
        result.setData(data);
        result.setMessage(message);
        return result;
    }

   public static Result<Object> failure(String message) {
      result.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
      result.setMessage(message);
      return result;
   }

   public static Result<Object> failure(Integer code, String message) {
      result.setCode(code);
      result.setMessage(message);
      return result;
   }
}
           

注解類

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
public @interface ResponseResult {
}
           

Retention指明可以通過反射讀取

Target指明注解類可以注解到類,接口,枚舉,方法

controller統一注解封裝(可有可無)

import com.maintenance.response.ResponseResult;
import org.springframework.web.bind.annotation.RestController;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@RestController
@ResponseResult
public @interface BaseControllerAnnotation {
}
           

此注解的作用就是在Controller中隻需要寫BaseControllerAnnotation就行了,不需要在寫@RestController和@ResponseResult,是以隻是用來簡化代碼的

配置類

import com.maintenance.response.ResponseResultInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebAppConfig implements WebMvcConfigurer {
    /**
     * 添加攔截器規則
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(new ResponseResultInterceptor()).addPathPatterns("/**");
    }
}
           

Configuration注解指明配置類,springboot自動掃描

addInterceptors中添加攔截器,可以添加多個,這裡我們攔截了所有的請求

攔截器

import com.maintenance.pojo.BaseControllerAnnotation;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

public class ResponseResultInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(handler instanceof HandlerMethod) {
            /* 反射擷取類和方法 */
            final HandlerMethod handlerMethod = (HandlerMethod) handler;
            final Class<?> clazz = handlerMethod.getBeanType();
            final Method method = handlerMethod.getMethod();
            /* 校驗類的注解和方法的注解,滿足條件後,添加到attribute */
            if(clazz.isAnnotationPresent(ResponseResult.class)) {
                request.setAttribute(Constant.RESPONSE_RESULT_ANNOTATION, clazz.getAnnotation(ResponseResult.class));
            } else if(method.isAnnotationPresent(ResponseResult.class)) {
                request.setAttribute(Constant.RESPONSE_RESULT_ANNOTATION, method.getAnnotation(ResponseResult.class));
            } else if(clazz.isAnnotationPresent(BaseControllerAnnotation.class)) {
                request.setAttribute(Constant.RESPONSE_RESULT_ANNOTATION, clazz.getAnnotation(BaseControllerAnnotation.class));
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}
           

增強器(處理傳回)

import com.maintenance.excepion.RoleManagerException;
import com.maintenance.pojo.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
    private Logger logger = LoggerFactory.getLogger(ResponseResultHandler.class);

    /**
     * 判斷元件支援的類型
     * @param returnType
     * @param converterType
     * @return
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        /* 判斷是否需要統一包裝,如果attribute中有,則表示需要處理,傳回true */
        Object annotation = request.getAttribute(Constant.RESPONSE_RESULT_ANNOTATION);
        return !(annotation == null);
    }

    /**
     * 處理傳回體
     * @param body
     * @param returnType
     * @param selectedContentType
     * @param selectedConverterType
     * @param request
     * @param response
     * @return
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if(!(body instanceof Result)) {
            // 包裝傳回體
            return Result.success(body);
        }
        return body;
    }

    /**
     * 自定義異常
     * @param e
     * @return
     */
    @ExceptionHandler(RoleManagerException.class)
    @ResponseBody
    public Result<?> exceptionHandler(RoleManagerException e) {
        logger.error(e.getMessage(), e);
        return Result.failure(e.getMessage());
    }

    /**
     * 系統異常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result<?> exceptionHandler(Exception e) {
        logger.error(e.getMessage(), e);
        return Result.failure(HttpStatus.INTERNAL_SERVER_ERROR.value(), "系統異常,請聯系管理者");
    }
}
           

使用方法

在controller類上使用@ResponseResult或@BaseControllerAnnotation

在controller方法上使用@ResponseResult

參考:

https://www.toutiao.com/i6694404645827117572