• 中文
    • English
  • 注册
  • 查看作者
    • SpringBoot项目异常发送邮件报警

      一. 前言

      公司的一些项目部署到线上后,有时候会因为bug等其他原因触发异常信息,而且没有做相关的项目监控,虽然做了日志处理,但是还是需要每天打开日志检查,非常的麻烦。由于大多数SpringBoot项目都做了全局的统一异常处理,所以我们可以在每次异常被触发的时候,给我们发送一个邮件来捕获异常信息。

      二.  配置Mail

      Spring Boot2.x的版本默认集成了mail模块,所以只需要在pom.xml中添加相关依赖即可

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

      接下来在application.yml中添加相关配置,这里以163邮箱为例

      spring:
        mail:
          host: smtp.163.com  #SMTP服务器地址
          port:
          username: zhangjiaboke@163.com  # 发件的邮箱
          password: asdfdsfafaaxx #客户端授权密码,不是邮箱登录密码
          protocol: smtp  # SMTP服务器用到的协议
          default-encoding: UTF-8  # 消息包的编码
          #设置使用ssl连接时候才需要开启下面的内容配置TLS,安全起见,建议开启SSL,并添加以下配置
          properties:
            mail.smtp.auth: true
            mail.smtp.starttls.enable: true 
            mail.smtp.starttls.required: true
            mail.smtp.socketFactory.port: 465 
            mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory
            mail.smtp.socketFactory.fallback: false

      其中,host为你的发件邮件的SMTP服务器地址这里给出常用邮箱SMTP,port为端口号

      163邮箱:smtp.163.com , port不用写

      126邮箱:smtp.126.com, port不用写

      QQ邮箱:smtp.qq.com, port是587

      值得注意的是,password并不是邮箱的登录密码,而是客户端的授权密码,每种邮箱获取客户端授权密码的方式不同,可以自行查询,这里不再赘述。

      三. 编写发送邮箱工具类

      参考了Clement-Xu大佬的《spring boot发送邮件 》一文

      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.core.io.FileSystemResource;
      import org.springframework.mail.SimpleMailMessage;
      import org.springframework.mail.javamail.JavaMailSender;
      import org.springframework.mail.javamail.MimeMessageHelper;
      import org.springframework.stereotype.Component;
      import org.springframework.stereotype.Service;
      
      import javax.mail.MessagingException;
      import javax.mail.internet.MimeMessage;
      import java.io.File;
      
      /**
       * @Author : ZhangJia
       * @Date : 2020/4/1 14:47
       * @Description : 
       */
      @Component
      public class MailUtil {
      
      
          private final Logger logger = LoggerFactory.getLogger(this.getClass());
      
          @Autowired
          private JavaMailSender sender;
      
          @Value("${spring.mail.username}")
          private String from;
      
          /**
           * 发送纯文本的简单邮件
           * @param to
           * @param subject
           * @param content
           */
          public void sendSimpleMail(String to, String subject, String content) {
              SimpleMailMessage message = new SimpleMailMessage();
              String[] toRecive = to.split(",");
              message.setFrom(from);
              message.setTo(toRecive);
              message.setSubject(subject);
              message.setText(content);
              message.setCc(from); //添加抄送人,否则会报Failed messages: com.sun.mail.smtp.SMTPSendFailedException: 554 DT:SPM 163 smt
      
              try {
                  sender.send(message);
                  logger.info("简单邮件已经发送。");
              } catch (Exception e) {
                  logger.error("发送简单邮件时发生异常!", e);
              }
          }
      
          /**
           * 发送html格式的邮件
           * @param to
           * @param subject
           * @param content
           */
          public void sendHtmlMail(String to, String subject, String content) {
              MimeMessage message = sender.createMimeMessage();
      
              try {
                  String[] toRecive = to.split(",");
                  //true表示需要创建一个multipart message
                  MimeMessageHelper helper = new MimeMessageHelper(message, true);
                  helper.setFrom(from);
                  helper.setTo(toRecive);
                  helper.setSubject(subject);
                  helper.setText(content, true);
      
                  sender.send(message);
                  logger.info("html邮件已经发送。");
              } catch (MessagingException e) {
                  logger.error("发送html邮件时发生异常!", e);
              }
          }
      
          /**
           * 发送带附件的邮件
           * @param to
           * @param subject
           * @param content
           * @param filePath
           */
          public void sendAttachmentsMail(String to, String subject, String content, String filePath) {
              MimeMessage message = sender.createMimeMessage();
      
              try {
                  String[] toRecive = to.split(",");
                  //true表示需要创建一个multipart message
                  MimeMessageHelper helper = new MimeMessageHelper(message, true);
                  helper.setFrom(from);
                  helper.setTo(toRecive);
                  helper.setSubject(subject);
                  helper.setText(content, true);
      
                  FileSystemResource file = new FileSystemResource(new File(filePath));
                  String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
                  helper.addAttachment(fileName, file);
      
                  sender.send(message);
                  logger.info("带附件的邮件已经发送。");
              } catch (MessagingException e) {
                  logger.error("发送带附件的邮件时发生异常!", e);
              }
          }
      
          /**
           * 发送嵌入静态资源(一般是图片)的邮件
           * @param to
           * @param subject
           * @param content 邮件内容,需要包括一个静态资源的id,比如:<img src=\"cid:rscId01\" >
           * @param rscPath 静态资源路径和文件名
           * @param rscId 静态资源id
           */
          public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId) {
              MimeMessage message = sender.createMimeMessage();
      
              try {
                  String[] toRecive = to.split(",");
                  //true表示需要创建一个multipart message
                  MimeMessageHelper helper = new MimeMessageHelper(message, true);
                  helper.setFrom(from);
                  helper.setTo(toRecive);
                  helper.setSubject(subject);
                  helper.setText(content, true);
      
                  FileSystemResource res = new FileSystemResource(new File(rscPath));
                  helper.addInline(rscId, res);
      
                  sender.send(message);
                  logger.info("嵌入静态资源的邮件已经发送。");
              } catch (MessagingException e) {
                  logger.error("发送嵌入静态资源的邮件时发生异常!", e);
              }
          }
      
      }

      四.  在全局异常类中发送错误信息

      关于全局异常类的配置和使用,请查看本站《SpringBoot:统一异常处理》一文,在统一异常处理类中,将报错信息发送至邮箱即可。

      mport io.zhangjia.springbootmd5.exception.TestException;
      import io.zhangjia.springbootmd5.util.Result;
      import org.springframework.util.StringUtils;
      import org.springframework.web.bind.annotation.ControllerAdvice;
      import org.springframework.web.bind.annotation.ExceptionHandler;
      import org.springframework.web.bind.annotation.ResponseBody;
      @ControllerAdvice
      public class GlobalExceptionHandler {
          @Autowired
          private MailUtil mailUtil;
          @ExceptionHandler
          @ResponseBody
          public Result handle(Exception e) {
              if(e instanceof TestException) {
                  TestException testException =  (TestException) e;
                  int code = testException.getCode();
                  String message = testException.getMessage();
                  mailUtil.sendSimpleMail("zhangjia@188.com","自定义异常",message );
                  return new Result(code,message);
              }
              String message = e.getMessage();
              if(StringUtils.isEmpty(message)){
                  message = "未定义错误";
                  
              }
              return new Result(-1,message);
          }
      }

      此时,当有异常被触发的时候,邮箱便可以收到相关通知:

      SpringBoot项目异常发送邮件报警

      五.  美化邮件

      在上面的例子中,我们采用了纯文本的方式发送邮件,不太美观,我们可以写个网页美化一下,采用Thymeleaf交互数据

      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
      <head>
          <meta charset="UTF-8">
          <title>张甲博客:系统异常提示</title>
          <link rel='stylesheet' href='https://unpkg.com/ionicons@4.5.10-0/dist/css/ionicons.min.css'>
          <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Montserrat:1000,700&amp;display=swap'>
          <style>
              body {
                  background-color: #EBECF0;
              }
      
              #mail-body {
                  display: flex;
                  flex-direction: column;
                  justify-content: space-between;
                  align-items: center;
              }
      
              .mail-name {
                  display: inline-block;
                  width: 100px;
                  height: 50px;
                  line-height: 50px;
                  background-color: #EBECF0;
                  text-align: center;
                  box-shadow: -5px -5px 20px #FFF, 5px 5px 20px #BABECC;
                  border-radius: 8px;
              }
      
              .mail-value {
                  display: inline-block;
                  width: 400px;
                  height: 50px;
                  line-height: 50px;
                  background-color: #EBECF0;
                  margin-right: 8px;
                  box-shadow: inset 2px 2px 5px #BABECC, inset -5px -5px 10px #FFF;
                  box-sizing: border-box;
                  transition: all 0.2s ease-in-out;
                  appearance: none;
                  -webkit-appearance: none;
                  border-radius: 10px;
                  margin-left: 20px;
                  padding-left: 10px;
              }
      
              #mail-info {
                  width: 535px;
                  height: 100%;
                  background-color: #EBECF0;
                  margin-right: 8px;
                  box-shadow: inset 2px 2px 5px #BABECC, inset -5px -5px 10px #FFF;
                  box-sizing: border-box;
                  transition: all 0.2s ease-in-out;
                  appearance: none;
                  -webkit-appearance: none;
                  border-radius: 10px;
                  padding: 10px;
                  white-space: normal;
                  word-break: break-all;
                  overflow: hidden;
              }
      
              div {
                  margin-bottom: 20px;
              }
          </style>
      </head>
      <body>
      
      <div id="mail-body">
      
          <div class="segment">
              <h1>Vchain 异常信息</h1>
          </div>
      
          <div>
                  <span class="mail-name">
                      异常代码:
                  </span>
      
                   <span class="mail-value" th:text="${code}">
                  </span>
          </div>
      
          <div>
                  <span class="mail-name">
                      异常信息:
                  </span>
      
                   <span class="mail-value" th:text="${message}">
      
                  </span>
          </div>
      
          <div>
                  <span class="mail-name">
                      发生时间:
                  </span>
      
                 <span class="mail-value" th:text="${create}">
      
                </span>
          </div>
          <div id="mail-info" th:text="${info}">
      
          </div>
      </div>
      
      </div>
      </body>
      </html>

      此时将统一异常类修改为:

      package com.enjoysix.vchain.exception;
      
      import com.enjoysix.vchain.util.MailUtil;
      import com.enjoysix.vchain.util.Result;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.ControllerAdvice;
      import org.springframework.web.bind.annotation.ExceptionHandler;
      import org.springframework.web.bind.annotation.ResponseBody;
      import org.thymeleaf.TemplateEngine;
      import org.thymeleaf.context.Context;
      
      import java.io.ByteArrayOutputStream;
      import java.io.PrintStream;
      import java.util.Date;
      import java.util.HashMap;
      import java.util.Map;
      
      /**
       * @Author : ZhangJia
       * @Date : 2019/11/1 15:00
       * @Description : 统一异常处理类
       * 统一异常处理类思路:
       * 程序可能遇到的任何错误都在service层处理
       * (因为在Controller中调用了Service,所以Service发生的异常,也会被GlobalExceptionHandler统一处理)
       * 在service层可能发生错误的地方通过调用VchainException,传入异常类型,将异常抛出
       */
      @ControllerAdvice
      public class GlobalExceptionHandler {
          private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
          @Autowired
          private MailUtil mailUtil;
          @Autowired
          private TemplateEngine templateEngine;
      
      
          @ExceptionHandler
          @ResponseBody
          public Result handle(Exception e) {
              Result result;
              int code;
              String message;
              if (e instanceof VchainException) {  //如果是自定义异常
                  VchainException vchainException = (VchainException) e;
                  code = vchainException.getCode();
                  message = vchainException.getMessage(); //Throwable类中的message
                  result = new Result(code, message);  //设置code和result
              } else { //如果是其他异常,统一报未定义错误
                  code = ExceptionCode.UNDEFINED_ERROR.getCode();
                  message = ExceptionCode.UNDEFINED_ERROR.getMsg();
                  result = new Result(code, message);
              }
      
      
              ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
              e.printStackTrace(new PrintStream(byteArrayOutputStream));
              String exception = byteArrayOutputStream.toString();
      
              Map<String, Object> map = new HashMap<>();
              map.put("code", code);
              map.put("message", message);
              map.put("info", exception);
              map.put("create", new Date());
      
              Context context = new Context();
              context.setVariables(map);
              String emailContent = templateEngine.process("/mail", context);
              mailUtil.sendHtmlMail("zhangjia@188.com", "系统报警信息", emailContent);
              return result;
          }
      
      }

      当异常发生时,收到的邮件如下:

      SpringBoot项目异常发送邮件报警

    • 0
    • 1
    • 0
    • 2.8k
    • Tobehappyohzjmarina

      请登录之后再进行评论

      登录
    • 0
      L1
      111
    • 赞助本站

      • 支付宝
      • 微信
      • QQ

      感谢一直支持本站的所有人!

      单栏布局 侧栏位置: