成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Spring Boot 2.x(七):全局處理異常

ivyzhang / 1067人閱讀

摘要:全局異常處理類(lèi)用于全局返回,如需返回請(qǐng)使用繼承了,對(duì)于一些類(lèi)似于請(qǐng)求方式異常的異常進(jìn)行捕獲重寫(xiě),自定義處理過(guò)程這里將異常直接傳給方法進(jìn)行處理,返回值為保證友好的返回,而不是出現(xiàn)錯(cuò)誤碼。

前言

異常的處理在我們的日常開(kāi)發(fā)中是一個(gè)繞不過(guò)去的坎,在Spring Boot 項(xiàng)目中如何優(yōu)雅的去處理異常,正是我們這一節(jié)課需要研究的方向。

異常的分類(lèi)

在一個(gè)Spring Boot項(xiàng)目中,我們可以把異常分為兩種,第一種是請(qǐng)求到達(dá)Controller層之前,第二種是到達(dá)Controller層之后項(xiàng)目代碼中發(fā)生的錯(cuò)誤。而第一種又可以分為兩種錯(cuò)誤類(lèi)型:1. 路徑錯(cuò)誤 2. 類(lèi)似于請(qǐng)求方式錯(cuò)誤,參數(shù)類(lèi)型不對(duì)等類(lèi)似錯(cuò)誤。

定義ReturnVO和ReturnCode

為了保持返回值的統(tǒng)一,我們這里定義了統(tǒng)一返回的類(lèi)ReturnVO,以及一個(gè)記錄錯(cuò)誤返回碼和錯(cuò)誤信息的枚舉類(lèi)ReturnCode,而具體的錯(cuò)誤信息和錯(cuò)誤代碼保存到了response.properties中,使用流進(jìn)行讀取。

ReturnVO
public class ReturnVO {

    private static Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + CommonUrl.RESPONSE_PROP_URL);

    /**
     * 返回代碼
     */
    private String code;

    /**
     * 返回信息
     */
    private String message;

    /**
     * 返回?cái)?shù)據(jù)
     */
    private Object data;


    public Object getData() {
        return data;
    }

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

    public String getMessage() {
        return message;
    }

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

    public String getCode() {
        return code;
    }

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

    /**
     * 默認(rèn)構(gòu)造,返回操作正確的返回代碼和信息
     */
    public ReturnVO() {
        this.setCode(properties.getProperty(ReturnCode.SUCCESS.val()));
        this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg()));
    }

    /**
     * 返回代碼,這里需要在枚舉中去定義
     * @param code
     */
    public ReturnVO(ReturnCode code) {
        this.setCode(properties.getProperty(code.val()));
        this.setMessage(properties.getProperty(code.msg()));
    }

    /**
     * 返回?cái)?shù)據(jù),默認(rèn)返回正確的code和message
     * @param data
     */
    public ReturnVO(Object data) {
        this.setCode(properties.getProperty(ReturnCode.SUCCESS.val()));
        this.setMessage(properties.getProperty(ReturnCode.SUCCESS.msg()));
        this.setData(data);
    }

    /**
     * 返回錯(cuò)誤的代碼,以及自定義的錯(cuò)誤信息
     * @param code
     * @param message
     */
    public ReturnVO(ReturnCode code, String message) {
        this.setCode(properties.getProperty(code.val()));
        this.setMessage(message);
    }

    /**
     * 返回自定義的code,message,以及data
     * @param code
     * @param message
     * @param data
     */
    public ReturnVO(ReturnCode code, String message, Object data) {
        this.setCode(code.val());
        this.setMessage(message);
        this.setData(data);
    }

    @Override
    public String toString() {
        return "ReturnVO{" +
                "code="" + code + """ +
                ", message="" + message + """ +
                ", data=" + data +
                "}";
    }
}
ReturnCode

其他的錯(cuò)誤處理只需要在枚舉類(lèi)中添加對(duì)應(yīng)的異常即可,枚舉的名稱(chēng)要定義為異常的名稱(chēng),這樣可以直接不用對(duì)其他的代碼進(jìn)行修改,添加一個(gè)新的異常時(shí),僅僅添加枚舉類(lèi)中的字段和properties文件中的屬性。

public enum ReturnCode {

    /** 操作成功 */
    SUCCESS("SUCCESS_CODE", "SUCCESS_MSG"),

    /** 操作失敗 */
    FAIL("FAIL_CODE", "FAIL_MSG"),

    /** 空指針異常 */
    NullPointerException("NPE_CODE", "NPE_MSG"),

    /** 自定義異常之返回值為空 */
    NullResponseException("NRE_CODE", "NRE_MSG"),

    /** 運(yùn)行時(shí)異常 */
    RuntimeException("RTE_CODE","RTE_MSG"),

    /** 請(qǐng)求方式錯(cuò)誤異常 */
    HttpRequestMethodNotSupportedException("REQUEST_METHOD_UNSUPPORTED_CODE","REQUEST_METHOD_UNSUPPORTED_MSG"),

    /** INTERNAL_ERROR */
    BindException("BIND_EXCEPTION_CODE","BIND_EXCEPTION_MSG"),

    /** 頁(yè)面路徑不對(duì) */
    UrlError("UE_CODE","UE_MSG");

    private ReturnCode(String value, String msg){
        this.val = value;
        this.msg = msg;
    }

    public String val() {
        return val;
    }

    public String msg() {
        return msg;
    }

    private String val;
    private String msg;
}
response.properties

這里我自定義了一些異常用于后面的測(cè)試,在我們實(shí)際的項(xiàng)目中需要定義很多的異常去完善。

SUCCESS_CODE=2000
SUCCESS_MSG=操作成功

FAIL_CODE=5000
FAIL_MSG=操作失敗

NPE_CODE=5001
NPE_MSG=空指針異常

NRE_CODE=5002
NRE_MSG=返回值為空

RTE_CODE=5001
RTE_MSG=運(yùn)行時(shí)異常

UE_CODE=404
UE_MSG=頁(yè)面路徑有誤

REQUEST_METHOD_UNSUPPORTED_CODE=4000
REQUEST_METHOD_UNSUPPORTED_MSG=請(qǐng)求方式異常

BIND_EXCEPTION_CODE=4001
BIND_EXCEPTION_MSG=請(qǐng)求參數(shù)綁定失敗
路徑錯(cuò)誤處理

這里的路徑錯(cuò)誤處理方式是采用了實(shí)現(xiàn)ErrorController接口,然后實(shí)現(xiàn)了getErrorPath()方法:

/**
 * 請(qǐng)求路徑有誤
 * @author yangwei
 * @since 2019-01-02 18:13
 */
@RestController
public class RequestExceptionHandler implements ErrorController {

    @Override
    public String getErrorPath() {
        return "/error";
    }

    @RequestMapping("/error")
    public ReturnVO errorPage(){
        return new ReturnVO(ReturnCode.UrlError);
    }
}

這里可以進(jìn)行測(cè)試一下:

使用ControllerAdvice對(duì)其他類(lèi)型的異常進(jìn)行處理

類(lèi)似于到達(dá)Controller之前的請(qǐng)求參數(shù)錯(cuò)誤,請(qǐng)求方式錯(cuò)誤,數(shù)據(jù)格式不對(duì)等等錯(cuò)誤都?xì)w類(lèi)為一種,這里僅僅展示請(qǐng)求方式錯(cuò)誤的處理方式。

/**
 * 全局異常處理類(lèi)
 * @author yangwei
 *
 * 用于全局返回json,如需返回ModelAndView請(qǐng)使用ControllerAdvice
 * 繼承了ResponseEntityExceptionHandler,對(duì)于一些類(lèi)似于請(qǐng)求方式異常的異常進(jìn)行捕獲
 */
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    private static Properties properties = ReadPropertiesUtil.getProperties(System.getProperty("user.dir") + CommonUrl.RESPONSE_PROP_URL);

    /**
     * 重寫(xiě)handleExceptionInternal,自定義處理過(guò)程
     **/
    @Override
    protected ResponseEntity handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
        //這里將異常直接傳給handlerException()方法進(jìn)行處理,返回值為OK保證友好的返回,而不是出現(xiàn)500錯(cuò)誤碼。
        return new ResponseEntity<>(handlerException(ex), HttpStatus.OK);
    }

    /**
     * 異常捕獲
     * @param e 捕獲的異常
     * @return 封裝的返回對(duì)象
     **/
    @ExceptionHandler(Exception.class)
    public ReturnVO handlerException(Throwable e) {
        ReturnVO returnVO = new ReturnVO();
        String errorName = e.getClass().getName();
        errorName = errorName.substring(errorName.lastIndexOf(".") + 1);
        //如果沒(méi)有定義異常,而是直接拋出一個(gè)運(yùn)行時(shí)異常,需要進(jìn)入以下分支
        if (e.getClass() == RuntimeException.class) {
            returnVO.setMessage(properties.getProperty(valueOf("RuntimeException").msg()) +": "+ e.getMessage());
            returnVO.setCode(properties.getProperty(valueOf("RuntimeException").val()));
        } else {
            returnVO.setMessage(properties.getProperty(valueOf(errorName).msg()));
            returnVO.setCode(properties.getProperty(valueOf(errorName).val()));
        }
        return returnVO;
    }
}

這里我們可以進(jìn)行測(cè)試:

@RestController
@RequestMapping(value = "/user")
public class UserController {

    @Autowired
    private IUserService userService;

    @PostMapping(value = "/findAll")
    public Object findAll() {
        throw new RuntimeException("ffffd");
    }

    @RequestMapping(value = "/findAll1")
    public ReturnVO findAll1(UserDO userDO) {
        System.out.println(userDO);
        return new ReturnVO(userService.findAll1());
    }

   @RequestMapping(value = "/test")
    public ReturnVO test() {
        throw new RuntimeException("測(cè)試非自定義運(yùn)行時(shí)異常");
    }
}

直接在瀏覽器訪問(wèn)findAll,默認(rèn)為get方法,這里按照我們期望會(huì)拋出請(qǐng)求方式異常的錯(cuò)誤:

訪問(wèn)findAll1?id=123ss,這里由于我們接受的UserDOid屬性是Integer類(lèi)型,所以這里報(bào)一個(gè)參數(shù)綁定異常:

訪問(wèn)test,測(cè)試非自定義運(yùn)行時(shí)異常:

結(jié)合AOP使用,放入公用模塊減少代碼的重復(fù)

我們上節(jié)課使用AOP對(duì)于全局異常處理進(jìn)行了一次簡(jiǎn)單的操作,這節(jié)課進(jìn)行了完善,并將其放入到我們的公用模塊,使用時(shí)只需導(dǎo)入jar包,然后在啟動(dòng)類(lèi)配置掃描包路徑即可

/**
 * 統(tǒng)一封裝返回值和異常處理
 *
 * @author vi
 * @since 2018/12/20 6:09 AM
 */
@Slf4j
@Aspect
@Order(5)
@Component
public class ResponseAop {

    @Autowired
    private GlobalExceptionHandler exceptionHandler;

    /**
     * 切點(diǎn)
     */
    @Pointcut("execution(public * indi.viyoung.viboot.*.controller..*(..))")
    public void httpResponse() {
    }

    /**
     * 環(huán)切
     */
    @Around("httpResponse()")
    public ReturnVO handlerController(ProceedingJoinPoint proceedingJoinPoint) {
        ReturnVO returnVO = new ReturnVO();
        try {
            Object proceed = proceedingJoinPoint.proceed();
            if (proceed instanceof ReturnVO) {
                returnVO = (ReturnVO) proceed;
            } else {
                returnVO.setData(proceed);
            }
        }  catch (Throwable throwable) {
            // 這里直接調(diào)用剛剛我們?cè)趆andler中編寫(xiě)的方法
            returnVO =  exceptionHandler.handlerException(throwable);
        }
        return returnVO;
    }
}

做完這些準(zhǔn)備工作,以后我們?cè)谶M(jìn)行異常處理的時(shí)候只需要進(jìn)行以下幾步操作:

引入公用模塊jar包

在啟動(dòng)類(lèi)上配置掃描包路徑

如果新增異常的話,在枚舉類(lèi)中新增后,再去properties中進(jìn)行返回代碼和返回信息的編輯即可(注意:枚舉類(lèi)的變量名一定要和異常名保持一致

公眾號(hào)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75701.html

相關(guān)文章

  • Spring Boot 2.x 系列教程:WebFlux REST API 全局異常處理 Error

    摘要:挺多人咨詢(xún)的,異常處理用切面注解去實(shí)現(xiàn)去全局異常處理。全局異常處理類(lèi),代碼如下代碼解析如下抽象類(lèi)是用來(lái)處理全局錯(cuò)誤時(shí)進(jìn)行擴(kuò)展和實(shí)現(xiàn)注解標(biāo)記的切面排序,值越小擁有越高的優(yōu)先級(jí),這里設(shè)置優(yōu)先級(jí)偏高。 本文內(nèi)容 為什么要全局異常處理? WebFlux REST 全局異常處理實(shí)戰(zhàn) 小結(jié) 摘錄:只有不斷培養(yǎng)好習(xí)慣,同時(shí)不斷打破壞習(xí)慣,我們的行為舉止才能夠自始至終都是正確的。 一、為什么要全局...

    BicycleWarrior 評(píng)論0 收藏0
  • Spring Boot 2.x(十一):AOP實(shí)戰(zhàn)--打印接口日志

    摘要:接口日志有啥用在我們?nèi)粘5拈_(kāi)發(fā)過(guò)程中,我們可以通過(guò)接口日志去查看這個(gè)接口的一些詳細(xì)信息。在切入點(diǎn)返回內(nèi)容之后切入內(nèi)容可以用來(lái)對(duì)處理返回值做一些加工處理。 接口日志有啥用 在我們?nèi)粘5拈_(kāi)發(fā)過(guò)程中,我們可以通過(guò)接口日志去查看這個(gè)接口的一些詳細(xì)信息。比如客戶(hù)端的IP,客戶(hù)端的類(lèi)型,響應(yīng)的時(shí)間,請(qǐng)求的類(lèi)型,請(qǐng)求的接口方法等等,我們可以對(duì)這些數(shù)據(jù)進(jìn)行統(tǒng)計(jì)分析,提取出我們想要的信息。 怎么拿到接口...

    Youngdze 評(píng)論0 收藏0
  • 一個(gè)比Spring Boot快44倍的Java框架!

    摘要:最近棧長(zhǎng)看到一個(gè)框架,官方號(hào)稱(chēng)可以比快倍,居然這么牛逼,有這么神奇嗎今天帶大家來(lái)認(rèn)識(shí)一下。官網(wǎng)簡(jiǎn)介很簡(jiǎn)單,翻譯過(guò)來(lái)就是一個(gè)快速輕量級(jí)和更高效的微服務(wù)框架。 最近棧長(zhǎng)看到一個(gè)框架,官方號(hào)稱(chēng)可以比 Spring Boot 快 44 倍,居然這么牛逼,有這么神奇嗎?今天帶大家來(lái)認(rèn)識(shí)一下。 這個(gè)框架名叫:light-4j。 官網(wǎng)簡(jiǎn)介:A fast, lightweight and more p...

    amc 評(píng)論0 收藏0
  • 手把手0基礎(chǔ)項(xiàng)目實(shí)戰(zhàn)(三)——教你開(kāi)發(fā)一套電商平臺(tái)的安全框架

    摘要:在領(lǐng)域,有兩大主流的安全框架,和。角色角色是一組權(quán)限的集合。安全框架的實(shí)現(xiàn)注解的實(shí)現(xiàn)本套安全框架一共定義了四個(gè)注解。該注解用來(lái)告訴安全框架,本項(xiàng)目中所有類(lèi)所在的包,從而能夠幫助安全框架快速找到類(lèi),避免了所有類(lèi)的掃描。 寫(xiě)在最前 本文是《手把手項(xiàng)目實(shí)戰(zhàn)系列》的第三篇文章,預(yù)告一下,整個(gè)系列會(huì)介紹如下內(nèi)容: 《手把手0基礎(chǔ)項(xiàng)目實(shí)戰(zhàn)(一)——教你搭建一套可自動(dòng)化構(gòu)建的微服務(wù)框架(Sprin...

    RaoMeng 評(píng)論0 收藏0
  • Spring Boot 2.x(六):優(yōu)雅的統(tǒng)一返回值

    摘要:下面我們來(lái)測(cè)試一下,訪問(wèn)我們經(jīng)過(guò)修改后的編寫(xiě)的接口這里我將返回值統(tǒng)一為,以便數(shù)據(jù)存入,實(shí)際類(lèi)型應(yīng)是接口的返回類(lèi)型。如果沒(méi)有返回值的話,那就可以一個(gè)對(duì)象直接通過(guò)構(gòu)造方法賦值即可。 為什么要統(tǒng)一返回值 在我們做后端應(yīng)用的時(shí)候,前后端分離的情況下,我們經(jīng)常會(huì)定義一個(gè)數(shù)據(jù)格式,通常會(huì)包含code,message,data這三個(gè)必不可少的信息來(lái)方便我們的交流,下面我們直接來(lái)看代碼 ReturnV...

    shaonbean 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<