天天看點

SpringBoot背景資料格式統一規範

現在所在公司沒有大哥,是以格式全憑開發人員自己寫,一點開發規範都沒有,是以看到統一格式就立馬記錄一下。

SpringBoot 背景傳回給前台固定的資料格式:

{

    code:integer,        #傳回狀态碼

    message:string,   #傳回資訊描述

    data:object           #傳回值

}

 傳回碼ResultCode類

public enum ResultCode {

    //成功狀态碼
    SUCCESS(200,"成功"),
    //失敗 狀态碼
    FAIL(400,"失敗"),

    //參數錯誤 1001-1999
    PARAM_IS_INVALID(1001,"參數無效"),
    PARAM_IS_BLANK(1002,"參數為空"),
    PARAM_TYPE_BIND_ERROR(1003,"參數類型錯誤"),

    //使用者錯誤 2001-2999
    USER_NOT_LOGGED_IN(2001,"使用者未登陸,通路路徑需要驗證,請登陸"),
    USER_LOGIN_ERROR(2002,"賬号不存在");

    private Integer code;
    private String message;

    ResultCode(Integer code,String message){
        this.code=code;
        this.message=message;
    }

    public Integer code() {
        return this.code;
    }

    public String message() {
        return this.message;
    }
}
           

 傳回結果封裝Result

/**
 * 結果實體類
 */
public class Result {
    /**
     * 響應狀态碼
     */
    private int code;
    /**
     * 響應提示資訊
     */
    private String message;
    /**
     * 響應結果對象
     */
    private Object data;

    public Result(ResultCode resultCode, Object data) {
        this.code = resultCode.code();
        this.message = resultCode.message();
        this.data = data;
    }

    public Result(){

    }

    public Result(int code,String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public static Result success(){
        Result result=new Result();
        result.setMessage("success");
        result.setCode(ResultCode.SUCCESS.code());
        return result;
    }
    public static Result success(Object data){
        Result result=new Result();
        result.setCode(ResultCode.SUCCESS.code());
        result.setMessage("success");
        result.setData(data);
        return result;
    }

    public static Result failure(){
        Result result=new Result();
        result.setMessage("failure");
        result.setCode(ResultCode.FAIL.code());
        return result;
    }
    public static Result failure(Object data){
        Result result=new Result();
        result.setMessage("failure");
        result.setCode(ResultCode.FAIL.code());
        result.setData(data);
        return result;
    }

    public static Result getResult(ResultCode resultCode,Object data){
        Result result=new Result();
        result.setData(data);
        result.setCode(resultCode.USER_NOT_LOGGED_IN.code());
        result.setMessage(resultCode.USER_NOT_LOGGED_IN.message());
        return result;
    }

    public int getCode() {
        return code;
    }

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

    public String getMessage() {
        return message;
    }

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

    public Object getData() {
        return data;
    }

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

 Controller層編寫

/*
 *檔案名: TestResultCodeController
 *建立者: xiaozhan
 *建立時間:2020/10/31 16:23
 *描述: 這是一個示例
 */

import com.bigdata.bigdata.entity.result.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/testResultCode")
public class TestResultCodeController {

    @GetMapping("/{id}")
    public Result getResult(@PathVariable("id") Integer id){
        if(id==null){
            return null;
        }
        List<String> resultList=new ArrayList<>();
        resultList.add("肖戰");
        resultList.add("王一博");
        resultList.add("趙麗穎");
        resultList.add("李易峰");
        return Result.success(resultList);
    }

}
           

此時,若是已經開發好的背景接口,若是需要調整傳回結果格式,需要調整接口邏輯,不建議調整之前邏輯,因為會存在一些雷。

是以 這時需要 全局統一格式即可。

請求攔截器 标記是否類/方法上有@ResponseResult标記

package com.bigdata.bigdata.component;

import com.bigdata.bigdata.annotations.ResponseResult;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

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

/**
 * @Description:  請求攔截器 标記是否類/方法上有@ResponseResult标記
 */
@Component
public class ResponseResultInterceptor implements HandlerInterceptor {
    //标記名稱
    public static final String RESPONSE_RESULT_ANN="RESPONSE_RESULT_ANN";

    @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();
            //判斷是否在類對象上加注解
            if(clazz.isAnnotationPresent(ResponseResult.class)){
                request.setAttribute(RESPONSE_RESULT_ANN,clazz.getAnnotation(ResponseResult.class));
            }else if(method.isAnnotationPresent(ResponseResult.class)){ //方法上是否有注解
                request.setAttribute(RESPONSE_RESULT_ANN,method.getAnnotation(ResponseResult.class));
            }
        }
        return true;
    }
}
           
對資料格式統一處理
           
package com.bigdata.bigdata.component;

import com.bigdata.bigdata.annotations.ResponseResult;
import com.bigdata.bigdata.entity.result.ErrorResult;
import com.bigdata.bigdata.entity.result.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
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.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * @Description: 對資料格式統一
 */
@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {

    private final static Logger logger= LoggerFactory.getLogger(ResponseResultHandler.class);

    //标記名稱
    public static final String RESPONSE_RESULT_ANN="RESPONSE_RESULT_ANN";

    //是否請求包含了 包裝注解标記 沒有 直接傳回,不需要重寫傳回體
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        ServletRequestAttributes requestAttributes =(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //判斷請求中是否包含 包裝标記
        ResponseResult responseResultAnn = (ResponseResult)request.getAttribute(RESPONSE_RESULT_ANN);
        return responseResultAnn==null?false:true;
    }

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

        logger.info("進入傳回體 重寫格式進行中");
        //方法體報異常 判斷body是否為異常類
        if(body instanceof ErrorResult){
            logger.info("傳回值異常 做包裝 進行中");
            ErrorResult errorResult=(ErrorResult)body;
            return Result.failure(errorResult.getCode(),errorResult.getMessage(),errorResult.getData());
        }
        return Result.success(body);
    }
}
           

攔截器的配置

package com.bigdata.bigdata.config;

import com.bigdata.bigdata.component.ResponseResultInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Description: 請求攔截器 攔截路徑 配置
 */
@Configuration
public class HandlerInterceptorConfig implements WebMvcConfigurer {

    @Autowired
    private ResponseResultInterceptor interceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor).addPathPatterns("/testResultAnnotation/**")
                .excludePathPatterns("/test");
    }

}
           

controller測試

package com.bigdata.bigdata.controller;

import com.bigdata.bigdata.annotations.ResponseResult;
import com.bigdata.bigdata.entity.result.ErrorResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description: 測試使用注解的傳回值 格式統一化
 */
@RestController
@RequestMapping("/testResultAnnotation")
@ResponseResult
public class TestResultAnnotationController {

    @GetMapping("/{id}")
    public List<String> getResult(@PathVariable("id") Integer id){
        if(id==null){
            return null;
        }
        List<String> resultList=new ArrayList<>();
        resultList.add("肖戰");
        resultList.add("王一博");
        resultList.add("趙麗穎");
        resultList.add("李易峰");
        return resultList;
    }



    @GetMapping("getResultError")
    public ErrorResult getResultError(){
        return new ErrorResult(500,"網絡逾時",null);
    }

}
           

 ErrorResult類

package com.bigdata.bigdata.entity.result;

/**
 * @Description: 錯誤傳回結果實體類
 */
public class ErrorResult{

    /**
     * 響應狀态碼
     */
    private int code;
    /**
     * 響應提示資訊
     */
    private String message;
    /**
     * 響應結果對象
     */
    private Object data;

    public ErrorResult(int code, String message, Object data) {
        this.code=code;
        this.message=message;
        this.data=data;
    }

    public String getMessage() {
        return message;
    }

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

    public Object getData() {
        return data;
    }

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

    public int getCode() {
        return code;
    }

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