最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot中如何統(tǒng)一接口返回與全局異常處理詳解

 更新時間:2021年09月02日 12:51:15   作者:l拉不拉米  
全局異常處理是個比較重要的功能,一般在項目里都會用到,這篇文章主要給大家介紹了關(guān)于SpringBoot中如何統(tǒng)一接口返回與全局異常處理的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

背景

在分布式、微服務(wù)盛行的今天,絕大部分項目都采用的微服務(wù)框架,前后端分離方式。前端和后端進(jìn)行交互,前端按照約定請求URL路徑,并傳入相關(guān)參數(shù),后端服務(wù)器接收請求,進(jìn)行業(yè)務(wù)處理,返回數(shù)據(jù)給前端。維護(hù)一套完善且規(guī)范的接口是非常有必要的, 這樣不僅能夠提高對接效率,也可以讓我的代碼看起來更加簡潔優(yōu)雅。

使用統(tǒng)一返回結(jié)果時,還有一種情況,就是程序的報錯是由于運行時異常導(dǎo)致的結(jié)果,有些異常是我們在業(yè)務(wù)中拋出的,有些是無法提前預(yù)知。

因此,我們需要定義一個統(tǒng)一的全局異常,在Controller捕獲所有異常,并且做適當(dāng)處理,并作為一種結(jié)果返回。

統(tǒng)一接口返回

定義API返回碼枚舉類

public enum ResultCode {
    /* 成功狀態(tài)碼 */
    SUCCESS(200, "成功"),
    
    /* 錯誤狀態(tài)碼 */
    NOT_FOUND(404, "請求的資源不存在"),
    INTERNAL_ERROR(500, "服務(wù)器內(nèi)部錯誤"),
    PARAMETER_EXCEPTION(501, "請求參數(shù)校驗異常"),
    
    /* 業(yè)務(wù)狀態(tài)碼 */
    USER_NOT_EXIST_ERROR(10001, "用戶不存在"),
    ;

    private Integer code;
    private String message;

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

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

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

定義正常響應(yīng)的API統(tǒng)一返回體

@Data
public class Result<T> implements Serializable {
private Integer code;
    private String message;
    private boolean success = true;
    private T data;
    @JsonIgnore
    private ResultCode resultCode;

    private Result() {
    }

    public void setResultCode(ResultCode resultCode) {
        this.resultCode = resultCode;
        this.code = resultCode.code();
        this.message = resultCode.message();
    }

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

    public static <T> Result<T> success() {
        Result<T> result = new Result<>();
        result.setResultCode(ResultCode.SUCCESS);
        return result;
    }

    public static <T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setResultCode(ResultCode.SUCCESS);
        result.setData(data);
            return result;
    }
}

定義異常響應(yīng)的API統(tǒng)一返回體

@Data
public class ErrorResult implements Serializable {
    private Integer code;
    private String message;
    private boolean success = false;
    @JsonIgnore
    private ResultCode resultCode;

    public static ErrorResult error() {
        ErrorResult result = new ErrorResult();
        result.setResultCode(ResultCode.INTERNAL_ERROR);
        return result;
    }

    public static ErrorResult error(String message) {
        ErrorResult result = new ErrorResult();
        result.setCode(ResultCode.INTERNAL_ERROR.code());
        result.setMessage(message);
        return result;
    }

    public static ErrorResult error(Integer code, String message) {
        ErrorResult result = new ErrorResult();
        result.setCode(code);
        result.setMessage(message);
        return result;
    }
    
    public static ErrorResult error(ResultCode resultCode, String message) {
        ErrorResult result = new ErrorResult();
        result.setResultCode(resultCode);
        result.setMessage(message)
        return result;
    }
}

編寫包裝返回結(jié)果的自定義注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})  //作用于方法和類(接口)上
@Documented
public @interface ResponseResult {
}

定義返回結(jié)果攔截器

@Component
public class ResponseResultInterceptor implements HandlerInterceptor {
    /* 使用統(tǒng)一返回體的標(biāo)識 */
    private static final String RESPONSE_RESULT_ANNOTATION = "RESPONSE-RESULT-ANNOTATION";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 正在處理請求的方法bean
        if (handler instanceof HandlerMethod) {
            final HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 獲取當(dāng)前類
            final Class<?> clazz = handlerMethod.getBeanType();
            // 獲取當(dāng)前方法
            final Method method = handlerMethod.getMethod();
            // 判斷是否在類對象上加了注解
            if (clazz.isAnnotationPresent(ResponseResult.class)) {
                // 設(shè)置該請求返回體,需要包裝,往下傳遞,在ResponseBodyAdvice接口進(jìn)行判斷
                request.setAttribute(RESPONSE_RESULT_ANNOTATION, clazz.getAnnotation(ResponseResult.class));
            }
            // 判斷是否在方法上加了注解
            else if (method.isAnnotationPresent(ResponseResult.class)) {
                // 設(shè)置該請求返回體,需要包裝,往下傳遞,在ResponseBodyAdvice接口進(jìn)行判斷
                request.setAttribute(RESPONSE_RESULT_ANNOTATION, method.getAnnotation(ResponseResult.class));
            }
        }
        return true;
    }
}

WebMvc配置類攔截器注冊者添加返回結(jié)果攔截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    /**
     * 添加自定義攔截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new ResponseResultInterceptor()).addPathPatterns("/**");
    }
}

編寫響應(yīng)體處理器

/**
 * 統(tǒng)一處理響應(yīng)體,用Result.success靜態(tài)方法包裝,
 * 在API接口使用時就可以直接返回原始類型
 */
@RestControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
    /* 使用統(tǒng)一返回體的標(biāo)識 */
    private static final String RESPONSE_RESULT_ANNOTATION = "RESPONSE-RESULT-ANNOTATION";

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(sra).getRequest();
        ResponseResult responseResult = (ResponseResult) request.getAttribute(RESPONSE_RESULT_ANNOTATION);
        // 判斷返回體是否需要處理
        return responseResult != null;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 異常響應(yīng)體則直接返回code+message的消息體
        if (body instanceof ErrorResult) {
            return body;
        }
        // 正常響應(yīng)體則返回Result包裝的code+message+data的消息體
        return Result.success(body);
    }
}

接口調(diào)用

@Api("用戶管理")
@RestController
@RequestMapping("user")
@ResponseResult  // 作用于類上,對所有接口有效
public class UserController {

    @Autowired
    private UserService userService;

    @ResponseResult  // 作用于方法上
    @ApiOperation("根據(jù)ID查詢用戶")
    @GetMapping("one")
    public User selectOne(Long id) {
        // 由于在ResponseResultHandler中已經(jīng)統(tǒng)一將返回數(shù)據(jù)用Result.success包裝了,
        // 直接返回原始類型即可,代碼更簡潔
        return this.userService.queryById(id);
    }

    @ResponseResult
    @ApiOperation("查詢所有用戶")
    @GetMapping("all")
    public List<User> selectAll(Page page) {
        // 由于在ResponseResultHandler中已經(jīng)統(tǒng)一將返回數(shù)據(jù)用Result.success包裝了,
        // 直接返回原始類型即可,代碼更簡潔
        return this.userService.queryAllByLimit(page);
    }
}

測試結(jié)果

全局異常處理

編寫自定義異常基類

@Data
public class BaseException extends RuntimeException {

    private static final int BASE_EXCEPTION_CODE = ResultCode.INTERNAL_ERROR.code();
    private static final String BASE_EXCEPTION_MESSAGE = ResultCode.INTERNAL_ERROR.message();

    private Integer code;
    private String message;

    public BaseException() {
        super(BASE_EXCEPTION_MESSAGE);
        this.code = BASE_EXCEPTION_CODE;
        this.message = BASE_EXCEPTION_MESSAGE;
    }

    public BaseException(String message) {
        super(message);
        this.code = BASE_EXCEPTION_CODE;
        this.message = message;
    }

    public BaseException(ResultCode resultCode) {
        super(resultCode.message());
        this.code = resultCode.code();
        this.message = resultCode.message();
    }

    public BaseException(Throwable cause) {
        super(cause);
        this.code = BASE_EXCEPTION_CODE;
        this.message = BASE_EXCEPTION_MESSAGE;
    }

    public BaseException(String message, Throwable cause) {
        super(message, cause);
        this.code = BASE_EXCEPTION_CODE;
        this.message = message;
    }

    public BaseException(Integer code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }

    public BaseException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
        this.message = message;
    }
}

編寫自定義業(yè)務(wù)異常類

public class BizException extends BaseException {
    public BizException(ResultCode resultCode) {
        super(resultCode);
    }
}

定義全局異常處理類

通過@ExceptionHandler注解來統(tǒng)一處理某一類異常

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 統(tǒng)一處理自定義基礎(chǔ)異常
     */
    @ExceptionHandler(BaseException.class)
    public ErrorResult baseException(BaseException e) {
        if (StringUtils.isEmpty(e.getCode())) {
            return ErrorResult.error(e.getMessage());
        }
        return ErrorResult.error(e.getCode(), e.getMessage());
    }

    /**
     * 統(tǒng)一處理自定義業(yè)務(wù)異常
     */
    @ExceptionHandler(BizException.class)
    public ErrorResult bizException(BizException e) {
        if (StringUtils.isEmpty(e.getCode())) {
            return ErrorResult.error(e.getMessage());
        }
        return ErrorResult.error(e.getCode(), e.getMessage());
    }

    /**
     * 統(tǒng)一處理非自定義異常外的所有異常
     */
    @ExceptionHandler(Exception.class)
    public ErrorResult handleException(Exception e) {
        log.error(e.getMessage(), e);
        return ErrorResult.error(e.getMessage());
    }
    
    /**
     * 兼容Validation校驗框架:忽略參數(shù)異常處理器
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ApiResult<String> parameterMissingExceptionHandler(MissingServletRequestParameterException e) {
        log.error(e.getMessage(), e);
        return ErrorResult.error(PARAMETER_EXCEPTION, "請求參數(shù) " + e.getParameterName() + " 不能為空");
    }
    
    /**
     * 兼容Validation校驗框架:缺少請求體異常處理器
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ErrorResult parameterBodyMissingExceptionHandler(HttpMessageNotReadableException e) {
        log.error(e.getMessage(), e);
        return ErrorResult.error(PARAMETER_EXCEPTION, "參數(shù)體不能為空");
    }

    /**
     * 兼容Validation校驗框架:參數(shù)效驗異常處理器
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ErrorResult parameterExceptionHandler(MethodArgumentNotValidException e) {
        log.error(e.getMessage(), e);
        // 獲取異常信息
        BindingResult exceptions = e.getBindingResult();
        // 判斷異常中是否有錯誤信息,如果存在就使用異常中的消息,否則使用默認(rèn)消息
        if (exceptions.hasErrors()) {
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                // 這里列出了全部錯誤參數(shù),按正常邏輯,只需要第一條錯誤即可
                FieldError fieldError = (FieldError) errors.get(0);
                return ErrorResult.error(PARAMETER_EXCEPTION, fieldError.getDefaultMessage());
            }
        }
        return ErrorResult.error(PARAMETER_EXCEPTION, "請求參數(shù)校驗異常");
    }
}

接口調(diào)用

    @ResponseResult
    @GetMapping
    public User update() {
        // 非自定義的運行時異常
        long id = 10 / 0;
        return userService.queryById(id);
    }

    @ResponseResult
    @PostMapping
    public User insert() {
        // 拋出自定義的基礎(chǔ)異常
        throw new BaseException();
    }

    @ResponseResult
    @DeleteMapping
    public boolean delete() {
        // 拋出自定義的業(yè)務(wù)異常
        throw new BizException(USER_NOT_EXIST_ERROR);
    }

測試結(jié)果

總結(jié)

到此這篇關(guān)于SpringBoot中如何統(tǒng)一接口返回與全局異常處理的文章就介紹到這了,更多相關(guān)SpringBoot統(tǒng)一接口返回內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java this關(guān)鍵字的引用詳解

    Java this關(guān)鍵字的引用詳解

    每個類中都有一個本類的this引用,類似:類名 this;實例對象時,this引用指向?qū)ο蟊旧恚渥钪饕淖饔檬亲岊愔械姆椒梢栽L問本類中的另外一個方法或?qū)傩?,因為調(diào)用一個方法或?qū)傩?非類方法/屬性)必須要有實例
    2022-03-03
  • 常用json與javabean互轉(zhuǎn)的方法實現(xiàn)

    常用json與javabean互轉(zhuǎn)的方法實現(xiàn)

    這篇文章主要介紹了常用json與javabean互轉(zhuǎn)的方法實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • springboot中如何去整合shrio實例分享

    springboot中如何去整合shrio實例分享

    這篇文章主要介紹了springboot中如何去整合shrio實例分享的相關(guān)資料,需要的朋友可以參考下
    2023-08-08
  • java 垃圾回收機(jī)制以及經(jīng)典垃圾回收器詳解

    java 垃圾回收機(jī)制以及經(jīng)典垃圾回收器詳解

    這篇文章主要介紹了java 垃圾回收機(jī)制以及經(jīng)典垃圾回收器詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • JAVA隨機(jī)數(shù)隨機(jī)字母的實現(xiàn)(微信搶紅包小練習(xí))

    JAVA隨機(jī)數(shù)隨機(jī)字母的實現(xiàn)(微信搶紅包小練習(xí))

    這篇文章主要介紹了JAVA隨機(jī)數(shù)隨機(jī)字母的實現(xiàn)(微信搶紅包小練習(xí)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • java中ThreadLocal取不到值的兩種原因

    java中ThreadLocal取不到值的兩種原因

    這篇文章主要介紹了java中ThreadLocal取不到值的兩種原因,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 輕松掌握J(rèn)ava單例模式

    輕松掌握J(rèn)ava單例模式

    這篇文章主要幫助大家輕松掌握J(rèn)ava單例模式 ,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • SpringMVC域?qū)ο蠊蚕頂?shù)據(jù)示例詳解

    SpringMVC域?qū)ο蠊蚕頂?shù)據(jù)示例詳解

    這篇文章主要為大家介紹了SpringMVC域?qū)ο蠊蚕頂?shù)據(jù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Spring Boot入門(web+freemarker)

    Spring Boot入門(web+freemarker)

    這篇文章主要介紹了Spring Boot入門(web+freemarker)的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • SpringBoot整合 Quartz實現(xiàn)定時推送實戰(zhàn)指南

    SpringBoot整合 Quartz實現(xiàn)定時推送實戰(zhàn)指南

    文章介紹了Spring Boot中使用Quartz動態(tài)定時任務(wù)和任務(wù)持久化實現(xiàn)多條不確定結(jié)束時間并提前N分鐘推送的方案,本文結(jié)合實例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2025-12-12

最新評論

新竹市| 永定县| 林西县| 定安县| 九江县| 金溪县| 响水县| 辽阳县| 辽阳市| 虹口区| 凉城县| 泾源县| 珠海市| 缙云县| 双柏县| 新余市| 高阳县| 兴山县| 古丈县| 永福县| 平舆县| 锦州市| 家居| 西丰县| 荣昌县| 拜泉县| 定日县| 波密县| 芜湖市| 藁城市| 山西省| 邢台县| 苏尼特右旗| 临沂市| 阜城县| 新郑市| 阿坝| 汕尾市| 新竹市| 章丘市| 吉安市|