1. SpringBoot 如何進行全局異常捕獲和處理?

        共 24635字,需瀏覽 50分鐘

         ·

        2021-09-08 09:11

        不點藍字關注,我們哪來故事?




        正文如下

        來源:blog.csdn.net/songguopeng

        /article/details/98961787

        • 一,為什么要用全局異常處理?
        • 二,應用場景是什么?
        • 三、如何進行全局異常捕獲和處理?
        • 四、@ControllerAdvice和@ExceptionHandler怎么用?
        • 六、@Validated 校驗器注解的異常?
        • 七、自定義異常以及事務回滾


        一,為什么要用全局異常處理?

        在日常開發(fā)中,為了不拋出異常堆棧信息給前端頁面,每次編寫Controller層代碼都要盡可能的catch住所有service層、dao層等異常,代碼耦合性較高,且不美觀,不利于后期維護。

        為解決該問題,計劃將Controller層異常信息統(tǒng)一封裝處理,且能區(qū)分對待Controller層方法返回給前端的String、Map、JSONObject、ModelAndView等結果類型。

        推薦下自己做的 Spring Boot 的實戰(zhàn)項目:

        https://github.com/YunaiV/ruoyi-vue-pro

        二,應用場景是什么?

        • 非常方便的去掉了try catch這類冗雜難看的代碼,有利于代碼的整潔和優(yōu)雅
        • 自定義參數(shù)校驗時候全局異常處理會捕獲異常,將該異常統(tǒng)一返回給前端,省略很多if else代碼
        • 當后端出現(xiàn)異常時,需要返回給前端一個友好的界面的時候就需要全局異常處理
        • 因為異常時層層向上拋出的,為了避免控制臺打印一長串異常信息

        推薦下自己做的 Spring Cloud 的實戰(zhàn)項目:

        https://github.com/YunaiV/onemall

        三、如何進行全局異常捕獲和處理?

        一共有兩種方法:

        • Spring的AOP(較復雜)
        • @ControllerAdvice結合@ExceptionHandler(簡單)

        四、@ControllerAdvice和@ExceptionHandler怎么用?

        1、Controller Advice字面上意思是“控制器通知”,Advice除了“勸告”、“意見”之外,還有“通知”的意思。

        可以將@ExceptionHandler(標識異常類型對應的處理方法)標記的方法提取出來,放到一個類里,并將加上@ControllerAdvice,這樣,所有的控制器都可以用了

        @ControllerAdvice
        public class ControllerHandlers(){
         @ExceptionHandler
            public String errorHandler(Exception e){
                return "error";
            }
        }


        ??點擊關注,可添加我微信??

        我是 Socket,堅持分享編程,算法,Java 等干貨教程


        2、 因為@ControllerAdvice@Componen標記,所以他可以被組件掃描到并放入Spring容器

        3、 如果只想對一部分控制器通知,比如某個包下邊的控制器,就可以這樣寫:

        @ControllerAdvice("com.labor")
        public class ControllerHandlers(){}

        也可以直接寫類名

        @ControllerAdvice(basePackageClasses = ***.class)
        public class ControllerHandlers()
        {}

        也可以傳多個類

        @ControllerAdvice(assignableTypes = {***.class,***.class})
        public class ControllerHandlers()
        {}

        4、 控制器通知還有一個兄弟,@RestControllerAdvice,如果用了它,錯誤處理方法的返回值不會表示用的哪個視圖,而是會作為HTTP body處理,即相當于錯誤處理方法加了@ResponseBody注解。

        @RestControllerAdvice
        public class ControllerHandlers(){
         @ExceptionHandler
            public String errorHandler(Exception e){
                return "error";
            }
        }

        5、@ExceptionHandler注解的方法只能返回一種類型,在前后端分離開發(fā)中我們通常返回,統(tǒng)一返回類型和優(yōu)化錯誤的提示,我們可以封裝我們自己的返回Map

        public class AjaxResult extends HashMap<StringObject{

            private static final long serialVersionUID = 1L;

            public static final String CODE_TAG = "code";

            public static final String MSG_TAG = "msg";

            public static final String DATA_TAG = "data";

            /**
             * 狀態(tài)類型
             */

            public enum Type {
                /**
                 * 成功
                 */

                SUCCESS(1),
                /**
                 * 警告
                 */

                WARN(2),
                /**
                 * 錯誤
                 */

                ERROR(0),
                /**無權限*/
                UNAUTH(3),
                /**未登錄、登錄超時*/
                UNLOGIN(4);
                private final int value;

                Type(int value) {
                    this.value = value;
                }

                public int value() {
                    return this.value;
                }
            }

            /**
             * 狀態(tài)類型
             */

            private Type type;

            /**
             * 狀態(tài)碼
             */

            private int code;

            /**
             * 返回內容
             */

            private String msg;

            /**
             * 數(shù)據(jù)對象
             */

            private Object data;

            /**
             * 初始化一個新創(chuàng)建的 AjaxResult 對象,使其表示一個空消息。
             */

            public AjaxResult() {
            }

            /**
             * 初始化一個新創(chuàng)建的 AjaxResult 對象
             * @param type 狀態(tài)類型
             * @param msg  返回內容
             */

            public AjaxResult(Type type, String msg) {
                super.put(CODE_TAG, type.value);
                super.put(MSG_TAG, msg);
            }

            /**
             * 初始化一個新創(chuàng)建的 AjaxResult 對象
             * @param type 狀態(tài)類型
             * @param msg  返回內容
             * @param data 數(shù)據(jù)對象
             */

            public AjaxResult(Type type, String msg, Object data) {
                super.put(CODE_TAG, type.value);
                super.put(MSG_TAG, msg);
                /* 數(shù)據(jù)為空的時候,還是需要把參數(shù)傳給前臺   huangqr @2019.7.19
                if (StringUtils.isNotNull(data)) {
                    super.put(DATA_TAG, data);
                }*/

                super.put(DATA_TAG, data);
            }

            /**
             * 返回成功消息
             * @return 成功消息
             */

            public static AjaxResult success() {
                return AjaxResult.success("操作成功");
            }

            /**
             * 返回成功數(shù)據(jù)
             * @return 成功消息
             */

            public static AjaxResult success(Object data) {
                return AjaxResult.success("操作成功", data);
            }

            /**
             * 返回成功消息
             * @param msg 返回內容
             * @return 成功消息
             */

            public static AjaxResult success(String msg) {
                return AjaxResult.success(msg, null);
            }

            /**
             * 返回成功消息
             * @param msg  返回內容
             * @param data 數(shù)據(jù)對象
             * @return 成功消息
             */

            public static AjaxResult success(String msg, Object data) {
                return new AjaxResult(Type.SUCCESS, msg, data);
            }

            /**
             * 返回警告消息
             * @param msg 返回內容
             * @return 警告消息
             */

            public static AjaxResult warn(String msg) {
                return AjaxResult.warn(msg, null);
            }

            /**
             * 返回警告消息
             * @param msg  返回內容
             * @param data 數(shù)據(jù)對象
             * @return 警告消息
             */

            public static AjaxResult warn(String msg, Object data) {
                return new AjaxResult(Type.WARN, msg, data);
            }

            /**
             * 返回錯誤消息
             * @return
             */

            public static AjaxResult error() {
                return AjaxResult.error("操作失敗");
            }

            /**
             * 返回錯誤消息
             * @param msg 返回內容
             * @return 警告消息
             */

            public static AjaxResult error(String msg) {
                return AjaxResult.error(msg, null);
            }

            /**
             * 返回錯誤消息
             * @param msg  返回內容
             * @param data 數(shù)據(jù)對象
             * @return 警告消息
             */

            public static AjaxResult error(String msg, Object data) {
                return new AjaxResult(Type.ERROR, msg, data);
            }

            /**
             * 無權限返回
             * @return
             */

            public static AjaxResult unauth() {
                return new AjaxResult(Type.UNAUTH, "您沒有訪問權限!"null);
            }
            /**
             * 無權限
             *
             * @param msg
             * @return com.wanda.labor.framework.web.domain.AjaxResult
             * @exception
             */

            public static AjaxResult unauth(String msg) {
                return new AjaxResult(Type.UNAUTH, msg, null);
            }
            /**
             * 未登錄或登錄超時。請重新登錄
             *
             * @param
             * @return com.wanda.labor.framework.web.domain.AjaxResult
             * @exception
             */

            public static AjaxResult unlogin() {
                return new AjaxResult(Type.UNLOGIN, "未登錄或登錄超時。請重新登錄!"null);
            }

            public Type getType() {
                return type;
            }

            public void setType(Type type) {
                this.type = type;
            }

            public int getCode() {
                return code;
            }

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

            public String getMsg() {
                return msg;
            }

            public void setMsg(String msg) {
                this.msg = msg;
            }

            public Object getData() {
                return data;
            }

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


            public static class SUCCESS{

                public static AjaxResult data(Object data){
                    return new AjaxResult(Type.SUCCESS, "操作成功 Operation Successful", data);
                }

                public static AjaxResult iMessagesg(String msg){
                    return new AjaxResult(Type.SUCCESS, msg, null);
                }

                public static AjaxResult imsgAndData(String msg,Object data){
                    return new AjaxResult(Type.SUCCESS, msg, data);
                }
            }



            @Override
            public String toString() {
                return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("code", getCode())
                        .append("msg", getMsg()).append("data", getData()).toString();
            }
        }

        6、 完善全局異常處理器

        @RestControllerAdvice
        public class GlobalExceptionHandler {
            private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

            /**
             * 權限校驗失敗 如果請求為ajax返回json,普通請求跳轉頁面
             */

            @ExceptionHandler(AuthorizationException.class)
            public Object handleAuthorizationException(HttpServletRequest requestAuthorizationException e
        {
                //log.error(e.getMessage(), e);
                if (ServletUtils.isAjaxRequest(request)) {
                    return AjaxResult.unauth(PermissionUtils.getMsg(e.getMessage()));
                } else {
                    ModelAndView modelAndView = new ModelAndView();
                    modelAndView.setViewName("error/unauth");
                    return modelAndView;
                }
            }

            /**
             * 請求方式不支持
             */

            @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
            public AjaxResult handleException(HttpRequestMethodNotSupportedException e
        {
                log.error(e.getMessage(), e);
                return AjaxResult.error("不支持' " + e.getMethod() + "'請求");
            }

            /**
             * 攔截未知的運行時異常
             */

            @ExceptionHandler(RuntimeException.class)
            public AjaxResult notFount(RuntimeException e
        {
                log.error("運行時異常:", e);
                return AjaxResult.error("運行時異常:" + e.getMessage());
            }

            /**
             * 系統(tǒng)異常
             */

            @ExceptionHandler(Exception.class)
            public AjaxResult handleException(Exception e
        {
                log.error(e.getMessage(), e);
                return AjaxResult.error("服務器錯誤,請聯(lián)系管理員");
            }

            /**
             * 校驗異常
             */

            @ExceptionHandler(value = MethodArgumentNotValidException.class)
            public AjaxResult exceptionHandler(MethodArgumentNotValidException e
        {
                BindingResult bindingResult = e.getBindingResult();
                String errorMesssage = "";
                for (FieldError fieldError : bindingResult.getFieldErrors()) {
                    errorMesssage += fieldError.getDefaultMessage() + "!";
                }
                return AjaxResult.error(errorMesssage);
            }

            /**
             * 校驗異常
             */

            @ExceptionHandler(value = BindException.class)
            public AjaxResult validationExceptionHandler(BindException e
        {
                BindingResult bindingResult = e.getBindingResult();
                String errorMesssage = "";
                for (FieldError fieldError : bindingResult.getFieldErrors()) {
                    errorMesssage += fieldError.getDefaultMessage() + "!";
                }
                return AjaxResult.error(errorMesssage);
            }

            /**
             * 校驗異常
             */

            @ExceptionHandler(value = ConstraintViolationException.class)
            public AjaxResult ConstraintViolationExceptionHandler(ConstraintViolationException ex
        {
                Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
                Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
                List<String> msgList = new ArrayList<>();
                while (iterator.hasNext()) {
                    ConstraintViolation<?> cvl = iterator.next();
                    msgList.add(cvl.getMessageTemplate());
                }
                return AjaxResult.error(String.join(",",msgList));
            }

            /**
             * 業(yè)務異常
             */

            @ExceptionHandler(BusinessException.class)
            public AjaxResult businessException(BusinessException e
        {
                log.error(e.getMessage(), e);
                return AjaxResult.error(e.getMessage());
            }

            /**
             * 演示模式異常
             */

            @ExceptionHandler(DemoModeException.class)
            public AjaxResult demoModeException(DemoModeException e
        {
                return AjaxResult.error("演示模式,不允許操作");
            }

        }

        六、@Validated 校驗器注解的異常,也可以一起處理,無需手動判斷綁定校驗結果 BindingResult/Errors 了

        pom文件引入validation的jar包。

        <!-- 校驗-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

        等待校驗的object

        public class Person {
            /**
             * @PersonName(prefix = "song"):自定義注解
             */

            @NotNull
            @PersonName(prefix = "song")
            private String name;
            @Min(value = 18)
            @Max(value = 30, message = "超過30歲的不要!")
            private Integer age;
        }

        使用

        /**
         * 開啟校驗注解:@Valid
         */

        @RestController
        public class PersonController {
            @PostMapping("/person")
            public Person savePerson(@Valid @RequestBody Person person){
                return person;
            }
        }

        全局異常處理里有相應的處理方法

        /**
         * 校驗異常
         */

        @ExceptionHandler(value = BindException.class)
        public AjaxResult validationExceptionHandler(BindException e
        {
            BindingResult bindingResult = e.getBindingResult();
            String errorMesssage = "";
            for (FieldError fieldError : bindingResult.getFieldErrors()) {
                errorMesssage += fieldError.getDefaultMessage() + "!";
            }
            return AjaxResult.error(errorMesssage);
        }

        @RequestBody@RequestParam注解的請求實體,校驗異常類是不同的

        七、自定義異常以及事務回滾

        public class MyException extends RuntimeException {
            //這個地方不要寫exception,因為Spring是只對運行時異常進行事務回滾,
            //如果拋出的是exception是不會進行事務回滾的。

        }

        如果是在service層里捕獲異常統(tǒng)一去處理,那為了保證事務的回滾,需要拋出RuntimeException

        try {
            } catch (Exception e) {
          e.printStackTrace();
          logger.error("發(fā)生異常");
          throw new RuntimeException();
         }

        關于try-catch-finally中,finally的作用,finally設計之初就是為了關閉資源,如果在finally中使用return語句,會覆蓋try或者catch的返回值,最常見的就是覆蓋異常,即便catch往上拋了異常,也會被覆蓋,返回finally中return語句的返回值。

        -END-

        ↑ 點擊上方關注我公號 ↑ 


        我是 Socket,堅持分享編程,算法,Java 等干貨教程


        一枚醫(yī)科大本科生,開源小作者,半吊子創(chuàng)業(yè)愛好者...

        半吊子的自己在試錯,不知道以后會干什么,但享受現(xiàn)在的試錯,試錯給我驚訝的生活


        喜歡公號的互動分享,感謝關注,路上遇見了你,同一小段時間之路,相伴 ~



        長按識別,加我微信



        點個在看結對編程一把


        瀏覽 41
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 极品女神无套呻吟啪啪 | 在线观看成人A片 | 乳情欲乱办公室主任 | 国产成本人视频在线观看 | 日日骚网站 |