当前位置 博文首页 > 阳阳的博客:【SpringBoot】全局异常处理与发生异常时的邮件通知

    阳阳的博客:【SpringBoot】全局异常处理与发生异常时的邮件通知

    作者:[db:作者] 时间:2021-08-14 21:04

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 全局异常处理与发生异常时的邮件通知

    一、前言

    在任何一个SpringBoot项目中,Controlle层遍布异常捕获的代码,是不是觉得特别的不舒服呢。其实SpringBoot给我们提供了全局异常处理机制,使用ControllerAdvice与ExceptionHandler这两个注解即可。

    我们现在的需求是,在任何Controller层出现代码,首先通过全局异常处理机制,捕获到该异常,然后用日志输出该异常出现的时间、异常种类、请求路径与参数等信息,最后通过邮件的方式通知开发者。


    二、全局异常处理

    ControllerAdvice:使用在全局异常处理类,当然也可以使用RestControllerAdvice,这样请求的响应是json类型的。

    ExceptionHandler:标记该方法处理的异常类型,当发生的异常种类与ExceptionHandler中的值匹配时,便会进入处理方法中。

    先把异常处理类贴出来

    @Slf4j
    @RestControllerAdvice
    public class GlobalExceptionHandler {
    
        @Value("${spring.mail.username}")
        private String from;
    
        @Autowired
        JavaMailSender javaMailSender;
    
        @ExceptionHandler(Exception.class)
        public Result<String> handlerException(Exception e, HttpServletRequest request) {
            Result<String> result = Result.exception(e, request);
    
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            String time = sdf.format(new Date());
            String exceptionStr = result.getMsg();
            String requestStr = result.getData();
            log.error("Time:{} Exception:{} Request:{}", time, exceptionStr, requestStr);
    
            sendSimpleMail(time, result);
            return result;
        }
    
    
        /**
         * 出现异常则发送邮件通知
         *
         * @param time
         * @param result
         */
        public void sendSimpleMail(String time, Result<String> result) {
            SimpleMailMessage message = new SimpleMailMessage();
            message.setFrom(from);
            message.setTo("767638734@qq.com");
            message.setSubject("plm异常通知");
            StringBuffer text = new StringBuffer();
            text.append("发生时间: " + time);
            text.append("\n");
            text.append("异常种类: " + result.getMsg());
            text.append("\n");
            text.append("详细请求: " + result.getData());
            message.setText(text.toString());
            javaMailSender.send(message);
        }
    }

    用到的工具类Result

    @Data
    public class Result<T> {
        private int code;
        private String msg;
        private T data;
    
    
        public static <T> Result<T> success(String msg) {
            Integer code = ResultCodeEnum.SUCCESS.getCode();
            return result(code, msg, null);
        }
    
        public static <T> Result<T> success(String msg, T data) {
            Integer code = ResultCodeEnum.SUCCESS.getCode();
            return result(code, msg, data);
        }
    
        public static <T> Result<T> fail(String msg) {
            Integer code = ResultCodeEnum.FAILED.getCode();
            return result(code, msg, null);
        }
    
        public static <T> Result<T> fail(String msg, T data) {
            Integer code = ResultCodeEnum.FAILED.getCode();
            return result(code, msg, data);
        }
    
        public static Result<String> exception(Exception e, HttpServletRequest request) {
            Integer code = ResultCodeEnum.FAILED.getCode();
            String msg = e.toString();
            StringBuffer requestStr = new StringBuffer();
            //获取请求方法
            String requestMethod = request.getMethod();
            requestStr.append(requestMethod + " ");
    
            //请求路径
            StringBuffer requestURL = request.getRequestURL();
            requestStr.append(requestURL);
            if (requestMethod.equals("GET")) {
                //GET请求参数
                String queryString = request.getQueryString();
                if (null != queryString) {
                    requestStr.append("?");
                    requestStr.append(queryString);
                }
            } else {
                requestStr.append(" ");
                String parametersFromPost = RequestUtil.getParametersFromPost(request);
                requestStr.append(parametersFromPost);
            }
    
            return result(code, msg, requestStr.toString());
        }
    
    
        public static <T> Result<T> result(Integer code, String msg, T data) {
            Result<T> result = new Result<>();
            result.setCode(code);
            result.setMsg(msg);
            result.setData(data);
            return result;
        }
    }

    RequestUtil工具类

    public class RequestUtil {
    
        /**
         * 获取POST请求中Body参数
         *
         * @param request
         * @return 字符串
         */
        public static String getParametersFromPost(HttpServletRequest request) {
            BufferedReader br = null;
            try {
                br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            String line = "";
            StringBuilder sb = new StringBuilder();
            try {
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return sb.toString();
        }
    
    }

    编写一个Controller

    @RestController
    @RequestMapping("/category")
    public class CategoryController {
    
        @Autowired
        CategoryService categoryService;
    
        @GetMapping("/getAllCategory")
        public List<Category> getAllCategory() {
            return categoryService.getAllCategory();
        }
    
        @PostMapping("/add")
        public Result<Object> add(Category category) {
            throw new NullPointerException();
    //        int affect = categoryService.add(category);
    //        if (affect == 1) {
    //            return Result.success("类目插入成功");
    //        } else {
    //            return Result.fail("类目插入失败");
    //        }
        }
    
    }

    三、发送邮件

    (1)导入依赖

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-mail</artifactId>
            </dependency>

    (2)配置yaml

    spring:
      mail:
        host: smtp.qq.com
        username: 你的邮箱地址
        password: 从邮箱官网申请到的密码,不是登录邮箱的密码
        default-encoding: UTF-8

    我用的是qq邮箱,需要开启SMTP协议,然后生成授权码


    四、演示

    在第二部分中,我们已经在Controller埋了一个空指针异常,现在我们请求该路径。

    (1)请求

    (2)日志显示

    2019-09-04 16:15:55.339 ERROR 152984 --- [p-nio-80-exec-3] c.y.plm.handler.GlobalExceptionHandler   : 
    Time:2019/09/04 16:15:55 
    Exception:java.lang.NullPointerException 
    Request:POST http://localhost/food/add {"name":"红烧鲫鱼"}

    (3)邮件通知

    大功告成!

    ?

    ?

    cs