系统异常邮件推送

直接上代码

1.请求信息实体

import lombok.Data;

/**
 * @className: AppInfo
 * @description: 请求信息
 * @author: sun
 * @date: 2021/12/2
 */
@Data
public class AppInfo {
  private String version;
  private String platform;
  private String requestURI;
  private String requestParameters;
}


2.邮箱地址集合

import lombok.Data;

import java.util.List;

@Data
public class MailObject {
  List<String> mailList;
}


3.获取请求头中参数


import com.alibaba.fastjson.JSON;
import com.xcb.fun.entity.AppInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.*;

@Slf4j
public class HandlerInfoGet {

  /**
   * @param: mapKey
   * @description: 获取请求头 AppInfo 对象的方法
   * @return: com.xcb.fun.entity.AppInfo
   */
  public static AppInfo getHeader() {
    RequestAttributes ra = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes sra = (ServletRequestAttributes) ra;
    HttpServletRequest request = sra.getRequest();

    String appInfo = request.getHeader("appInfo");
    AppInfo app = new AppInfo();
    if (Objects.nonNull(appInfo)) {
      try {
        app = JSON.parseObject(appInfo, AppInfo.class);
        String method = request.getMethod();
        app.setRequestURI(method + request.getRequestURI());
        app.setRequestParameters(getMapToString(request.getParameterMap()));
      } catch (Exception e) {
        log.error(e.getMessage());
        app = new AppInfo();
      }
    }
    return app;
  }

  public static String getMapToString(Map<String, String[]> map) {
    Set<String> keySet = map.keySet();
    // 将set集合转换为数组
    String[] keyArray = keySet.toArray(new String[keySet.size()]);
    // 给数组排序(升序)
    Arrays.sort(keyArray);
    // 因为String拼接效率会很低的,所以转用StringBuilder
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < keyArray.length; i++) {
      // 参数值为空,则不参与签名 这个方法trim()是去空格
      if ((String.valueOf(map.get(keyArray[i]))).trim().length() > 0) {
        sb.append(keyArray[i]).append("=").append(String.join("@", map.get(keyArray[i])));
      }
      if (i != keyArray.length - 1) {
        sb.append("&");
      }
    }
    return sb.toString();
  }
  
}


4.邮件发送处理工具

import com.sun.mail.util.MailSSLSocketFactory;
import com.xcb.fun.aop.HandlerInfoGet;
import com.xcb.fun.entity.AppInfo;
import com.xcb.fun.entity.MailObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.text.SimpleDateFormat;
import java.util.*;

/** 邮件处理工具类 */
public class MailUtil {

  private static final Logger logger = LoggerFactory.getLogger(MailUtil.class);

  public static boolean sendMail(String title, String msgs, Address[] array) {
    return sendMail(title, msgs, array, false);
  }

  public static boolean sendMail(String title, String msgs, Address[] array, boolean isHtml) {
    try {
      Properties props = new Properties();

      logger.info("发送邮件--start");
      // 关闭debug调试
      props.setProperty("mail.debug", "false");
      // 发送服务器需要身份验证
      props.setProperty("mail.smtp.auth", "true");
      // 设置邮件服务器主机名(我这用的是腾讯企业邮箱)
      props.setProperty("mail.host", "smtp.exmail.qq.com");
      // 设置邮件服务器端口
      props.setProperty("mail.smtp.port", "465");
      // 发送邮件协议名称
      props.setProperty("mail.transport.protocol", "smtp");

      MailSSLSocketFactory sf = new MailSSLSocketFactory();

      sf.setTrustAllHosts(true);
      props.put("mail.smtp.ssl.enable", "true");
      props.put("mail.smtp.ssl.socketFactory", sf);

      Session session = Session.getInstance(props);

      Message msg = new MimeMessage(session);
      msg.setSubject(title);
      StringBuilder builder = new StringBuilder();
      builder.append(msgs);
      builder.append("\n");
      builder.append("\n时间 " + formatTime(new Date()));
      if (isHtml) {
        msg.setContent(builder.toString(), "text/html;charset = utf-8");
      } else {
        msg.setText(builder.toString());
      }
      // 此处设置发件人邮箱
      msg.setFrom(new InternetAddress("发件人邮箱@qq.com"));

      Transport transport = session.getTransport();
      // (邮件服务器主机名、发件人邮箱、发件人邮箱密码)
      transport.connect("smtp.exmail.qq.com", "发件人邮箱@qq.com", "发件邮箱密码/或者授权码");
      transport.sendMessage(msg, array);
      transport.close();
      logger.info("发送邮件--end");
      return true;

    } catch (Exception e) {
      logger.error(e.getMessage(), e);
      return false;
    }
  }

  public static String formatTime(Date date) {
    if (date == null) {
      return "";
    }
    Calendar c1 = Calendar.getInstance();
    c1.setTime(new Date());
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return format.format(date);
  }

  public static void sendEmail(
      String serviceName,
      String resultMessage,
      StackTraceElement[] stackTraceElements,
      String[] activeProfiles) {
    String mailKey = "EXCEPTIONNOTIFICATION:EMAIL:" + String.join("@", activeProfiles);
    //    缓存中获取邮箱地址
    MailObject mailObject = RedisUtils.getBean(mailKey, MailObject.class);
    if (Objects.nonNull(mailObject)) {
      AppInfo appInfo = HandlerInfoGet.getHeader();
      StringBuffer stringBuffer = new StringBuffer();
      if (Objects.nonNull(appInfo)) {
        stringBuffer.append("请求端:");
        stringBuffer.append(appInfo.getPlatform());
        stringBuffer.append("\n请求端版本:");
        stringBuffer.append(appInfo.getVersion());
        stringBuffer.append("\n请求接口:");
        stringBuffer.append(appInfo.getRequestURI());
        stringBuffer.append("\n请求头参数:");
        stringBuffer.append(appInfo.getRequestParameters());
        stringBuffer.append("\n");
      }
      stringBuffer.append(serviceName);
      stringBuffer.append("服务出问题了快处理,原因:\n");
      stringBuffer.append(StringUtils.isBlank(resultMessage) ? "未知异常" : resultMessage);
      if (Objects.nonNull(stackTraceElements)) {
        stringBuffer.append("\n报错信息:");
        Arrays.asList(stackTraceElements)
            .forEach(
                e -> {
                  stringBuffer.append(e.toString());
                  stringBuffer.append("\n");
                });
      }
      try {
        List<String> mailList = mailObject.getMailList();
        // 添加收件人地址 多个收件人存放list中
        List<Address> list = new ArrayList<Address>();
        for (String mail : mailList) {
          list.add(new InternetAddress(mail));
        }
        Address[] senderList = list.toArray(new Address[list.size()]);
        MailUtil.sendMail(
            formatTime(new Date()) + " " + serviceName + "接口异常及时处理",
            stringBuffer.toString(),
            senderList);
      } catch (AddressException e) {
        logger.error(e.getMessage(), e);
      }
    }
  }

  public static MailObject getMailObject(String activeProfile) {
    String mailKey = "EXCEPTIONNOTIFICATION:EMAIL:" + activeProfile;
    return RedisUtils.getBean(mailKey, MailObject.class);
  }

  public static MailObject saveMailObject(MailObject mailObject, String activeProfile) {
    String mailKey = "EXCEPTIONNOTIFICATION:EMAIL:" + activeProfile;
    RedisUtils.saveBean(mailKey, mailObject);

    return RedisUtils.getBean(mailKey, MailObject.class);
  }
}

5.拦截所有异常处理


import com.fasterxml.jackson.databind.ObjectMapper;
import com.xcb.basics.domain.enums.MicroServiceErrorCode;
import com.xcb.fun.util.MailUtil;
import feign.FeignException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.nio.file.AccessDeniedException;
import java.util.stream.Collectors;

/** 统一异常处理 */
@RestControllerAdvice
public class ExceptionTranslator {
  private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionTranslator.class);
  @Autowired ObjectMapper objectMapper;
  /** 参数校验失败异常 */
  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.OK)
  @ResponseBody
  public MicroServiceErrorCode processValidationError(MethodArgumentNotValidException ex) {
    LOGGER.error("Exception with cause = {} and exception {}", ex.getCause(), ex.getMessage());
    String description =
        ex.getBindingResult().getFieldErrors().stream()
            .map(t -> t.getDefaultMessage())
            .collect(Collectors.joining(" "));
    return new MicroServiceErrorCode("400", description);
  }
  /** 无权限异常 */
  @ExceptionHandler(AccessDeniedException.class)
  @ResponseStatus(HttpStatus.FORBIDDEN)
  @ResponseBody
  public MicroServiceErrorCode processAccessDeniedException(AccessDeniedException ex) {
    LOGGER.error("Exception with cause = {} and exception {}", ex.getCause(), ex.getMessage());
    return new MicroServiceErrorCode(String.valueOf(HttpStatus.FORBIDDEN.value()), ex.getMessage());
  }
  /** feign异常 */
  @ExceptionHandler(FeignException.class)
  @ResponseStatus(HttpStatus.OK)
  public ResponseEntity<MicroServiceErrorCode> processFeignException(FeignException ex) {
    LOGGER.error("Exception with cause = {} and exception {}", ex.getCause(), ex.getMessage());
    String contentStr = "content:";
    MicroServiceErrorCode microServiceErrorCode = null;
    if (StringUtils.contains(ex.getMessage(), contentStr)) {
      String str =
          ex.getMessage()
              .substring(StringUtils.indexOf(ex.getMessage(), contentStr) + contentStr.length());
      try {
        microServiceErrorCode = objectMapper.readValue(str, MicroServiceErrorCode.class);
      } catch (Exception e) {
        LOGGER.error("Exception with cause = {} and exception {}", ex.getCause(), ex.getMessage());
        microServiceErrorCode.setCode(String.valueOf(ex.status()));
        microServiceErrorCode.setMessage(ex.getMessage());
      }
    } else {
      microServiceErrorCode.setCode(String.valueOf(ex.status()));
      microServiceErrorCode.setMessage(ex.getMessage());
    }
    return new ResponseEntity<>(microServiceErrorCode, HttpStatus.valueOf(ex.status()));
  }

  /** 统一server异常 200 */
  @ExceptionHandler(XcbServerException.class)
  @ResponseStatus(HttpStatus.OK)
  public MicroServiceErrorCode processServerException(XcbServerException ex) {
    LOGGER.error(
        "XcbServerException with cause = {} and exception {}", ex.getCause(), ex.getMessage());
    return new MicroServiceErrorCode(ex.getCode(), ex.getMessage());
  }
  // 注入对象
  @Autowired private Environment env;
  /** 其他异常 */
  @ExceptionHandler(Exception.class)
  @ResponseStatus(HttpStatus.OK)
  public MicroServiceErrorCode processRuntimeException(Exception ex) throws Exception {
    LOGGER.error("Exception with cause = {} and exception {}", ex.getCause(), ex.getMessage());

    MailUtil.sendEmail(
        env.getProperty("spring.application.name"),
        ex.getMessage(),
        ex.getStackTrace(),
        env.getActiveProfiles());
    return new MicroServiceErrorCode("400", ex.getMessage());
  }
}


6.所需依赖

<dependency>
            <groupId>com.sun.mail</groupId>
            <artifactId>javax.mail</artifactId>
            <version>1.5.3</version>
        </dependency>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值