日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python切面异常处理_Spring项目中优雅的异常处理

發(fā)布時(shí)間:2024/9/27 python 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python切面异常处理_Spring项目中优雅的异常处理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Spring項(xiàng)目中優(yōu)雅的異常處理

前言

如今的Java Web項(xiàng)目多是以 MVC 模式構(gòu)建的,通常我們都是將 Service 層的異常統(tǒng)一的拋出,包括自定義異常和一些意外出現(xiàn)的異常,以便進(jìn)行事務(wù)回滾,而 Service 的調(diào)用者 Controller 則承擔(dān)著異常處理的責(zé)任,因?yàn)樗桥c Web 前端交互的最后一道防線,如果此時(shí)還不進(jìn)行處理則用戶會在網(wǎng)頁上看到一臉懵逼的

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4

at cn.keats.TestAdd.main(TestAdd.java:20)

這樣做有以下幾點(diǎn)壞處:

用戶體驗(yàn)很不友好,可能用戶會吐槽一句:這是什么XX網(wǎng)站。然后不再訪問了

如果這個(gè)用戶是同行,他不僅看到了項(xiàng)目代碼的結(jié)構(gòu),而且看到拋出的是這么低級的索引越界異常,會被人家看不起

用戶看到網(wǎng)站有問題,打電話給客服,客服找到產(chǎn)品,產(chǎn)品叫醒正在熟睡/打游戲的你。你不僅睡不好游戲打不了還得挨批評完事改代碼

哎,真慘。因此一般我們采用的方法會是像這樣:

異常處理

一般的Controller處理

Service代碼如下:

@Service

public class DemoService{

public String respException(String param){

if(StringUtils.isEmpty(param)){

throw new MyException(ExceptionEnum.PARAM_EXCEPTION);

}

int i = 1/0;

return "你看不見我!";

}

}

Controller代碼如下:

@RestController

public class DemoController{

@Autowired

private DemoService demoService;

@PostMapping("respException")

public Result respException(){

try {

return Result.OK(demoService.respException(null));

} catch (MyException e){

return Result.Exception(e, null);

}

catch (Exception e) {

return Result.Error();

}

}

}

如果此時(shí)發(fā)送如下的請求:

http://localhost/respException

服務(wù)器捕捉到自定義的異常 MyException,而返回參數(shù)異常的Json串:

{

"code": 1,

"msg": "參數(shù)異常",

"data": null

}

而當(dāng)我們補(bǔ)上參數(shù):

http://localhost/respException?param=zhangsan

則服務(wù)器捕捉到 by zero 異常,會返回未知錯(cuò)誤到前端頁面

{

"code": -1,

"msg": "未知錯(cuò)誤",

"data": null

}

這樣就會在一定程度上規(guī)避一些問題,例如參數(shù)錯(cuò)誤就可以讓用戶去修改其參數(shù),當(dāng)然這一般需要前端同學(xué)配合做頁面的參數(shù)校驗(yàn),必傳參數(shù)都有的時(shí)候再向服務(wù)器發(fā)送請求,一方面減輕服務(wù)器壓力,一方面將問題前置節(jié)省雙方的時(shí)間。但是這樣寫有一個(gè)壞處就是所有的Controller方法中關(guān)于異常的部分都是一樣的,代碼非常冗余。且不利于維護(hù),而且一些不太熟悉異常機(jī)制的同學(xué)可能會像踢皮球一樣將異常抓了拋,拋完又抓回來,鬧著玩呢。。。(筆者就曾經(jīng)接手過一個(gè)跑路同學(xué)的代碼這樣處理異常,那簡直是跟異常捉迷藏呢!可恨)我們在Service有全局事務(wù)處理,在系統(tǒng)中可以有全局的日志處理,這些都是基于Spring 的一大殺器:AOP(面向切面編程) 實(shí)現(xiàn)的,AOP是什么呢?

AOP

AOP是Spring框架面向切面的編程思想,AOP采用一種稱為“橫切”的技術(shù),將涉及多業(yè)務(wù)流程的通用功能抽取并單獨(dú)封裝,形成獨(dú)立的切面,在合適的時(shí)機(jī)將這些切面橫向切入到業(yè)務(wù)流程指定的位置中。如果說我們常用的OOP思想是從上到下執(zhí)行業(yè)務(wù)流程的話,AOP就相當(dāng)于在我們執(zhí)行業(yè)務(wù)的時(shí)候橫切一刀,如下圖所示:

而Advice(通知)是AOP思想中重要的一個(gè)術(shù)語,分為前置通知(Before)、后置通知(AfterReturning)、異常通知(AfterThrowing)、最終通知(After)和環(huán)繞通知(Around)五種。具體通知所表示的意義我這里不多贅述,網(wǎng)上關(guān)于Spring核心原理的講解都會提及。而我們熟知的 Service 事務(wù)處理其實(shí)就是基于AOP AfterThrowing 通知實(shí)現(xiàn)的事務(wù)回滾。我們自定義的日志處理也可以根據(jù)不同的需求定制不同的通知入口。那既然如此,我們?yōu)楹尾蛔远x一個(gè)全局異常處理的切面去簡化我們的代碼呢?別急,且繼續(xù)向下看。

優(yōu)雅的處理異常

Spring 在 3.2 版本已經(jīng)為我們提供了該功能: @ControllerAdvice 注解。此注解會捕捉Controller層拋出的異常,并根據(jù) @ExceptionHandler 注解配置的方法進(jìn)行異常處理。下面是一個(gè)示例工程,主要代碼如下:

Result類:

此 Result 采用泛型的方式,便于在 Swagger 中配置方法的出參。使用靜態(tài)工廠方法是的對象的初始化更加見名只意。對于不存在共享變量問題的 Error 對象,采用雙重校驗(yàn)鎖懶漢單例模式來節(jié)省服務(wù)器資源(當(dāng)然最好還是整個(gè)項(xiàng)目運(yùn)行中一直沒有初始化它讓人更加舒服。)

package cn.keats.util;

import cn.keats.exception.MyException;

import lombok.Data;

/**

* 功能:統(tǒng)一返回結(jié)果,直接調(diào)用對應(yīng)的工廠方法

*

* @author Keats

* @date 2019/11/29 18:20

*/

@Data

public class Result{

private Integer code;

private String msg;

private T data;

/**

* 功能:響應(yīng)成功

*

* @param data 響應(yīng)的數(shù)據(jù)

* @return woke.cloud.property.transformat.Result

* @author Keats

* @date 2019/11/30 8:54

*/

public static Result OK(T data){

return new Result<>(0, "響應(yīng)成功", data);

}

private static Result errorResult;

/**

* 功能:返回錯(cuò)誤,此錯(cuò)誤不可定制,全局唯一。一般是代碼出了問題,需要修改代碼

*

* @param

* @return Result

* @author Keats

* @date 2019/11/30 8:55

*/

public static Result Error(){

if(errorResult == null){

synchronized (Result.class){

if(errorResult == null){

synchronized (Result.class){

errorResult = new Result<>(-1, "未知錯(cuò)誤", null);

}

}

}

}

return errorResult;

}

/**

* 功能:返回異常,直接甩自定義異常類進(jìn)來

*

* @param e 自定義異常類

* @param data 數(shù)據(jù),如果沒有填入 null 即可

* @return woke.cloud.property.transformat.Result

* @author Keats

* @date 2019/11/30 8:55

*/

public static Result Exception(MyException e, T data){

return new Result<>(e.getCode(), e.getMsg(), data);

}

/**

* 功能:為了方便使用,使用靜態(tài)工廠方法創(chuàng)建對象。如需新的構(gòu)造方式,請?zhí)砑訉?yīng)的靜態(tài)工廠方法

*

* @author Keats

* @date 2019/11/30 8:56

*/

private Result(Integer code, String msg, T data){

this.code = code;

this.msg = msg;

this.data = data;

}

}

自定義異常類:

package cn.keats.exception;

import lombok.Getter;

/**

* 功能:系統(tǒng)自定義異常類。繼承自RuntimeException,方便Spring進(jìn)行事務(wù)回滾

*

* @author Keats

* @date 2019/11/29 18:50

*/

@Getter

public class MyException extends RuntimeException{

private Integer code;

private String msg;

public MyException(ExceptionEnum eEnum){

this.code = eEnum.getCode();

this.msg = eEnum.getMsg();

}

}

異常代碼枚舉類:

package cn.keats.exception;

import lombok.AllArgsConstructor;

import lombok.Getter;

/**

* 功能:異常枚舉

*

* @author Keats

* @date 2019/11/29 18:49

*/

@Getter

@AllArgsConstructor

public enum ExceptionEnum {

PARAM_EXCEPTION(1,"參數(shù)異常"),

USER_NOT_LOGIN(2,"用戶未登錄"),

FILE_NOT_FOUND(3,"文件不存在,請重新選擇");

private Integer code;

private String msg;

}

異常切面:

其中 @RestControllerAdvice 是spring 4.3 添加的新注解,是 @ControllerAdvice 和 @ResponseBody 的簡寫方式,類似與 @RestController 與 @Controller 的關(guān)系

package cn.keats.advice;

import cn.keats.exception.MyException;

import cn.keats.util.Result;

import lombok.extern.slf4j.Slf4j;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.RestControllerAdvice;

/**

* 功能:全局異常處理器,Controller異常直接拋出

*

* @return

* @author Keats

* @date 2019/11/30 10:28

*/

@Slf4j

@RestControllerAdvice

public class ExceptionAdvice{

/**

* 功能:其余非預(yù)先規(guī)避的異常返回錯(cuò)誤

*

* @param e

* @return woke.cloud.property.transformat.Result

* @author Keats

* @date 2019/11/30 10:08

*/

@ExceptionHandler(value = Exception.class)

@ResponseBody

public Result ResponseException(Exception e){

log.error("未知錯(cuò)誤,錯(cuò)誤信息:", e);

return Result.Error();

}

/**

* 功能:捕捉到 MyException 返回對應(yīng)的消息

*

* @param e

* @return woke.cloud.property.transformat.Result

* @author Keats

* @date 2019/11/30 10:07

*/

@ExceptionHandler(value = MyException.class)

@ResponseBody

public Result myException(MyException e){

log.info("返回自定義異常:異常代碼:" + e.getCode() + "異常信息:" + e.getMsg());

return Result.Exception(e, null);

}

}

此時(shí)的 Controller 方法可以這樣寫:

package cn.keats.controller;

import cn.keats.service.DemoService;

import cn.keats.util.Result;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

public class DemoController{

@Autowired

private DemoService demoService;

@PostMapping("respException")

public Result respException(String param) throws Exception{

return Result.OK(demoService.respException(param));

}

@PostMapping("respError")

public Result respError() throws Exception{

return Result.OK(demoService.respException(null));

}

}

省略的大部分的異常處理代碼,使得我們只需要關(guān)注業(yè)務(wù),一方面提高了代碼質(zhì)量,可閱讀性,另一方面也提高了我們的開發(fā)速度。美哉!

啟動項(xiàng)目,進(jìn)行測試沒有問題。

我是 Keats,一個(gè)熱愛技術(shù)的程序員,鑒于技術(shù)有限,如果本文有什么紕漏或者兄臺還有其他更好的建議/實(shí)現(xiàn)方式,歡迎留言評論,謝謝您!

總結(jié)

以上是生活随笔為你收集整理的python切面异常处理_Spring项目中优雅的异常处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。