系統(tǒng)異常了,發(fā)個(gè)郵件

描述
在我們的項(xiàng)目中,總是有一些我們不可控制的異常,比如數(shù)據(jù)庫(kù)連接不上,redis掛掉,以及一些代碼上未可知的異常爆發(fā),不能在項(xiàng)目上線時(shí)就可以統(tǒng)計(jì)出來(lái),并且修復(fù),所以當(dāng)我們這些bug拋出異常時(shí),或者在某些可控的嚴(yán)重異常需要推送郵件或者短信或者其他的通訊工具比如 釘釘或者飛書(shū)等,我們就需要這樣的功能,這里提供一個(gè)郵件通知方法,當(dāng)有未知異常或者被定義為嚴(yán)重異常的,就會(huì)給運(yùn)維人員發(fā)送一個(gè)郵件進(jìn)行通知,方便計(jì)時(shí)應(yīng)對(duì)和問(wèn)題定位。

解決方案
在springboot中的全局異常捕獲處,對(duì)不可控異常拿到異常棧信息,進(jìn)行異常msg的組裝和通過(guò)freemarker模板進(jìn)行渲染html文本,然后再把這個(gè)異常msg的html進(jìn)行qq模式的email的發(fā)送

,freemarker模板可以支撐字符串模板渲染,即渲染的模板字符串可以保存到數(shù)據(jù)庫(kù),也可以直接定義好xxx.ftl模板,都行,這里需要強(qiáng)調(diào)的是 渲染的模板字符串可以保存到數(shù)據(jù)庫(kù)

就更加靈活,可以設(shè)計(jì)一套freemarker模板的管理系統(tǒng),比如,對(duì)自定義的freemarker模板配置后,保存到數(shù)據(jù)庫(kù),然后根據(jù)不同的用戶或者企業(yè)或者業(yè)務(wù),就可以從庫(kù)中獲取對(duì)應(yīng)的freemarker模板,進(jìn)行數(shù)據(jù)渲染html,再通過(guò)短信或者郵件或者釘釘,這樣就實(shí)現(xiàn)了類(lèi)似阿里或者騰訊等第三方的模板配置后進(jìn)行消息推送的功能。

代碼
代碼組成包含有自定義的模板的工具jar包和郵件的springboot-starter,以及在微服務(wù)中對(duì)異常的處理,和調(diào)用郵件的消息封裝以及模板的創(chuàng)建

模板自定springboot-starter


詳細(xì)代碼

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>wlc-spring-boot-tools</artifactId>
        <groupId>com.wlc</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>wlc-template</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
    <--freemarker依賴(lài) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
    <--spring-webmvc依賴(lài),這里可以換成spring的ioc包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.9</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>

</project>
BeanUtils,處理bean轉(zhuǎn)map
import org.springframework.cglib.beans.BeanMap;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Map;


/**
 * 描述 實(shí)體工具類(lèi)  <br>
 * 作者:IT學(xué)習(xí)道場(chǎng) <br>
 * 時(shí)間:2018/10/26 13:37
 */
public class BeanUtils extends org.springframework.beans.BeanUtils {
    public BeanUtils() {
    }

    /**
     * 實(shí)例化對(duì)象:傳入類(lèi)對(duì)類(lèi)進(jìn)行實(shí)例化對(duì)象
     *
     * @param clazz 類(lèi)
     * @return 對(duì)象
     * @author Lius
     * @date 2018/10/26 13:49
     */
    public static <T> T newInstance(Class<?> clazz) {
        return (T) instantiateClass(clazz);
    }

    /**
     * 實(shí)例化對(duì)象,傳入類(lèi)名對(duì)該類(lèi)進(jìn)行實(shí)例化對(duì)象
     *
     * @param clazzStr 類(lèi)名,傳入是必須傳入全路徑,com...
     * @return 對(duì)象
     * @author Lius
     * @date 2018/10/26 13:54
     */
    public static <T> T newInstance(String clazzStr) {
        try {
            Class<?> clazz = Class.forName(clazzStr);
            return newInstance(clazz);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException();
        }
    }

    /**
     * 把對(duì)象封裝成Map形式
     *
     * @param src 需要封裝的實(shí)體對(duì)象
     * @author Lius
     * @date 2018/10/26 14:08
     */
    public static Map toMap(Object src) {
        return BeanMap.create(src);
    }

    /**
     * 把Map轉(zhuǎn)換成bean對(duì)象
     *
     * @author Lius
     * @date 2018/10/26 14:09
     */
    public static <T> T toBean(Map<String, Object> beanMap, Class<T> valueType) {
        // 對(duì)象實(shí)例化
        T bean = BeanUtils.newInstance(valueType);
        PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(valueType);
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            String properName = propertyDescriptor.getName();
            // 過(guò)濾class屬性
            if ("class".equals(properName)) {
                continue;
            }
            if (beanMap.containsKey(properName)) {
                Method writeMethod = propertyDescriptor.getWriteMethod();
                if (null == writeMethod) {
                    continue;
                }
                Object value = beanMap.get(properName);
                if (!writeMethod.isAccessible()) {
                    writeMethod.setAccessible(true);
                }
                try {
                    writeMethod.invoke(bean, value);
                } catch (Throwable throwable) {
                    throw new RuntimeException("Could not set property '" + properName + " ' to bean" + throwable);
                }
            }
        }
        return bean;
    }
}
FreemarkerUtil,來(lái)處理模板的封裝
import com.wlc.template.util.BeanUtils;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import java.io.IOException;
import java.util.Map;

/**
 * 描述: FreemarkerUtil輔助類(lèi) <br>
 * 時(shí)間: 2022-07-01 9:44  <br>
 * 作者:IT學(xué)習(xí)道場(chǎng)
 */
@Component
public class FreemarkerUtil {
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;


    /**
     * bean轉(zhuǎn)map
     * @param bean 轉(zhuǎn)換bean
     * @return Map<String, Object> - map對(duì)象
     */
    public Map<String, Object> beanToMap(Object bean){
        Map<String, Object> map = BeanUtils.toMap(bean);
        return map;
    }

    /**
     * 根據(jù)模板路徑獲取模板渲染數(shù)據(jù)
     * @param templatePath 模板路徑 ,ex:templatePath = "notice.ftl",意思是 resources/templates/下的notice.ftl文件
     * @param data 渲染數(shù)據(jù)對(duì)象
     * @return String- 渲染后的html文本
     */
    public String freeMarkerRenderHtml(String templatePath, Map<String, Object> data ){
        //獲取模板信息
        Template template = null;
        String html= "";
        try {
            template = freeMarkerConfigurer.getConfiguration().getTemplate(templatePath);
            html = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
        return html;

    }

    /**
     * 字符文本渲染成html文本
     * @param templateName 模板名
     * @param templateText 模板文本
     * @param data         渲染數(shù)據(jù)map
     * @return String - 渲染后的html文本
     */
    public String textRenderFreemarkerHtml(String templateName, String templateText, Map<String, Object> data){
        String html = textRenderFreemarkerHtml(templateName, templateText, "utf-8", data);
        return html;
    }

    /**
     * 字符文本渲染成html文本
     * @param templateName 模板名
     * @param templateText 模板文本
     * @param charEncode   模板編碼
     * @param data         渲染數(shù)據(jù)map
     * @return String - 渲染后的html文本
     */
    public String textRenderFreemarkerHtml(String templateName, String templateText, String charEncode, Map<String, Object> data){
        Template template = textToFreemarkerTemplate(templateName, templateText, charEncode);
        String html = freemarkerTemplateRenderHtml(template, data);
        return html;
    }

    /**
     * 根據(jù)模板對(duì)象和數(shù)據(jù)map渲染html文本
     * @param template 模板對(duì)象
     * @param data 渲染數(shù)據(jù)map
     * @return String - html文本
     */
    public String freemarkerTemplateRenderHtml(Template template, Map<String, Object> data){
        String html = "";
        try {
            //渲染data數(shù)據(jù)到模板中
            html = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
        return html;
    }

    /**
     * 文本轉(zhuǎn)freemarker模板
     * @param templateName 模板名字
     * @param templateText 模板文本
     * @param charEncode 模板編碼
     * @return Template- 返回freemarkerTemplate對(duì)象
     */
    public Template textToFreemarkerTemplate(String templateName, String templateText, String charEncode){
        //獲取配置文件
        Configuration cfg = freeMarkerConfigurer.getConfiguration();
        //創(chuàng)建freeMarker字符串模板加載器
        StringTemplateLoader stringLoader = new StringTemplateLoader();
        //加載模板名字和模板文本
        stringLoader.putTemplate(templateName, templateText);
        //配置文件設(shè)置模板加載器
        cfg.setTemplateLoader(stringLoader);
        freemarker.template.Template template = null;
        try {
            //從配置文件中獲取模板對(duì)象
            template = cfg.getTemplate(templateName, charEncode);

        } catch (IOException e) {
            e.printStackTrace();
        }
        return template;
    }

}
這樣,模板的渲染jar就封裝好了



pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>wlc-spring-boot-tools</artifactId>
        <groupId>com.wlc</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>wlc-email-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!-- 郵件發(fā)送的核心依賴(lài) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <!-- 模板jar -->
        <dependency>
            <groupId>com.wlc</groupId>
            <artifactId>wlc-template</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>
EmailUtil-> 郵件發(fā)送工具類(lèi)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailProperties;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Date;

/**
 * 描述: email輔助類(lèi) <br>
 * 時(shí)間: 2022-07-01 10:20  <br>
 * 作者:IT學(xué)習(xí)道場(chǎng)
 */
public class EmailUtil {

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private MailProperties mailProperties;

    /**
     * 發(fā)送普通郵件
     * @param subject 主題
     * @param simpleText 內(nèi)容
     * @param toEamils 郵件接受郵箱數(shù)組
     */
    public void simpleEmailSend(String subject, String simpleText, String... toEamils) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setSentDate(new Date());
        message.setFrom(mailProperties.getUsername());
        message.setTo(toEamils);
        message.setSubject(subject);
        message.setText(simpleText);
        //發(fā)送郵件
        javaMailSender.send(message);
    }

    /**
     * 發(fā)送html郵件
     * @param subject 發(fā)送主題
     * @param html 發(fā)送的html
     * @param toEamils 郵件接收人數(shù)組
     */
    public void emailSendHtml(String subject, String html, String... toEamils) {
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper message = null;
        try {
            message = new MimeMessageHelper(mimeMessage, true);
            message.setSentDate(new Date());
            message.setFrom(mailProperties.getUsername());
            message.setTo(toEamils);
            message.setSubject(subject);
            message.setText(html, true);
            //發(fā)送郵件
            javaMailSender.send(mimeMessage);
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }
}






EmailService -> email服務(wù)類(lèi)的輔助類(lèi)
import com.wlc.email.util.EmailUtil;
import com.wlc.template.freemarker.FreemarkerUtil;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Map;

/**
 * 描述: email服務(wù)類(lèi) <br>
 * 時(shí)間: 2022-07-01 10:33  <br>
 * 作者:IT學(xué)習(xí)道場(chǎng)
 */
public class EmailService {

    @Autowired
    private EmailUtil emailUtil;
    @Autowired
    private FreemarkerUtil freemarkerUtil;

    /**
     * 根據(jù)模板路徑給郵件發(fā)送html模板
     * @param subject       郵件主題
     * @param templatePath  html模板路徑
     * @param data          渲染html模板里的數(shù)據(jù)map
     * @param toEamils      郵件接受者數(shù)組
     */
    public void emailSendHtmlByTemplatePath(String subject, String templatePath, Map<String, Object> data, String... toEamils) {
        String html = freemarkerUtil.freeMarkerRenderHtml(templatePath, data);
        emailUtil.emailSendHtml(subject, html, toEamils);
    }

    /**
     * 根據(jù)字符模板文本給郵件發(fā)送html模板
     * @param subject       郵件主題
     * @param templateName  html模板名字
     * @param templateText  html模板text文本(就是html的模板字符串,使用html模板易字符串的形式保存到數(shù)據(jù)庫(kù),
     *                      然后從數(shù)據(jù)庫(kù)中讀取模板字符串,在轉(zhuǎn)換成模板對(duì)象,把data進(jìn)行渲染成html,來(lái)發(fā)送郵件)
     * @param data          渲染html模板里的數(shù)據(jù)map
     * @param toEamils      郵件接受者數(shù)組
     */
    public void emailSendHtmlByTemplateText(String subject, String templateName, String templateText, Map<String, Object> data, String... toEamils) {
        String html = freemarkerUtil.textRenderFreemarkerHtml(templateName, templateText, data);
        emailUtil.emailSendHtml(subject, html, toEamils);
    }

    /**
     * 根據(jù)字符模板文本給郵件發(fā)送html模板
     * @param subject       郵件主題
     * @param templateName  html模板名字
     * @param templateText  html模板text文本(就是html的模板字符串,使用html模板易字符串的形式保存到數(shù)據(jù)庫(kù),
     *                      然后從數(shù)據(jù)庫(kù)中讀取模板字符串,在轉(zhuǎn)換成模板對(duì)象,把data進(jìn)行渲染成html,來(lái)發(fā)送郵件)
     * @param data          渲染html模板里的數(shù)據(jù)map
     * @param charEncode    編碼格式 ex: "utf-8"
     * @param toEamils      郵件接受者數(shù)組
     */
    public void emailSendHtmlByTemplateText(String subject, String templateName, String templateText, String charEncode, Map<String, Object> data, String... toEamils) {
        String html = freemarkerUtil.textRenderFreemarkerHtml(templateName, templateText, charEncode, data);
        emailUtil.emailSendHtml(subject, html, toEamils);
    }

}
EmailAutoConfiguration --> 自定義郵件自動(dòng)化配置類(lèi)
import com.wlc.email.service.EmailService;
import com.wlc.email.util.EmailUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 描述: 自定義郵件自動(dòng)化配置類(lèi) <br>
 * 時(shí)間: 2022-07-01 11:00  <br>
 * 作者:IT學(xué)習(xí)道場(chǎng)
 */
@Configuration
public class EmailAutoConfiguration {
    
    @Bean
    public EmailService emailService(){
        EmailService emailService = new EmailService();
        return emailService;
    }

    @Bean
    EmailUtil emailUtil(){
        EmailUtil emailUtil = new EmailUtil();
        return emailUtil;
    }
}
resources/META-INF下的spring.factories文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.wlc.email.config.EmailAutoConfiguration
這樣一個(gè)郵件的自定義springboot-starter就封裝好了

下面就是在各個(gè)微服務(wù)中的全局異常捕獲中進(jìn)行msg的freemarker的組裝和郵件的發(fā)送

演示的服務(wù)代碼,全局異常處理





ftl代碼,有類(lèi)似需求可以copy

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"></meta>
    <title>郵件內(nèi)容</title>
</head>
<body>
    <p style="text-align:center "><img width="400px" height="200px" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimgsa.baidu.com%2Fexp%2Fw%3D500%2Fsign%3Da5c70c27a1efce1bea2bc8ca9f50f3e8%2Fa9d3fd1f4134970a05665ffe93cad1c8a6865dcd.jpg&refer=http%3A%2F%2Fimgsa.baidu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659171243&t=17d3f0b344e9cb402e8ec4311207fa5a"></p>
    <h4>系統(tǒng)管理員</h4>
    <h4>   您好!</h4>
    <p>系統(tǒng)異常了!日志如下:</p>
    <p>服務(wù)名:<span style="color:red">${appName}</span></p>
    <p>服務(wù)ip:<span style="color:red">${ipAddr}</span></p>
    <p>類(lèi)路徑:<span style="color:red">${className}</span></p>
    <p>方法名字:<span style="color:red">${methodName}</span></p>
    <p>異常發(fā)生行號(hào):<span style="color:red">${lineNumber}</span></p>
    <p style="color:red">${content}</p>
    <p style="width: 100%;text-align: right">IT學(xué)習(xí)道場(chǎng)系統(tǒng)</p>
</body>
</html>


EmailExtendContent -> email的異常郵件信息組裝類(lèi),這里是給郵件哪個(gè)模板里需要的數(shù)據(jù)組裝

import com.utils.IPUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.servlet.http.HttpServletRequest;

/**
 * 描述: email的異常郵件信息組裝類(lèi) <br>
 * 時(shí)間: 2022-06-30 17:03  <br>
 * 作者:IT學(xué)習(xí)道場(chǎng)
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class EmailExtendContent {
    //異常
    public Exception e;
    //請(qǐng)求request
    public HttpServletRequest request;
    //ip地址
    public String ipAddr;
    //類(lèi)命
    public String className;
    //方法名
    public String methodName;
    //發(fā)生異常的行號(hào)
    public int lineNumber;

    public EmailExtendContent(Exception e, HttpServletRequest request) {
        this.e = e;
        this.request = request;
        handler();

    }


    void handler(){
        StackTraceElement stackTraceElement = e.getStackTrace()[0];
        // 獲取類(lèi)名
        ipAddr = IPUtil.getIpAddr(request);
        className = stackTraceElement.getClassName();
        methodName = stackTraceElement.getMethodName();
        lineNumber = stackTraceElement.getLineNumber();
    }
}
EmailHandler --> 微服務(wù)中email處理類(lèi)定制化處理類(lèi)
import com.wlc.email.service.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 描述: email處理類(lèi) <br>
 * 時(shí)間: 2022-07-01 11:11  <br>
 * 作者:IT學(xué)習(xí)道場(chǎng)
 */
@Component
public class EmailHandler {

    @Autowired
    private EmailService emailService; // 自定義郵件starter里的 EmailService
    @Value("${spring.application.name:no-service}") //服務(wù)應(yīng)用沒(méi)名字
    private String appName;
    @Value("#{'${spring.mail.toEamils:}'.split(',')}") //郵件接收者的郵箱數(shù)組
    private String[] toEamils;

    /**
     * 異步發(fā)送郵件
     * @param stackExceptionMsg 棧異常信息 str
     * @param e                 異常對(duì)象
     * @param request           request
     */
    @Async
    public void sendExceptionEmail(String stackExceptionMsg,Exception e, HttpServletRequest request){
        //根據(jù)異常對(duì)象和request組裝EmailExtendContent
        EmailExtendContent emailExtendContent = new EmailExtendContent(e, request);
        //組裝渲染數(shù)據(jù)data
        Map<String, Object> data = builderData(appName, emailExtendContent, stackExceptionMsg);
        //發(fā)送郵件
        emailService.emailSendHtmlByTemplatePath("美術(shù)傳媒系統(tǒng)異常報(bào)告", "notice.ftl", data, toEamils);
    }

    private Map builderData(String appName, EmailExtendContent extendContent, String content){
        Map<String, Object> data = new HashMap<>();
        data.put("appName", appName);
        data.put("ipAddr", extendContent.ipAddr);
        data.put("className", extendContent.className);
        data.put("methodName", extendContent.methodName);
        data.put("lineNumber", extendContent.lineNumber);
        data.put("content", content);
        return data;
    }
}

然后就可以在全局異常里調(diào)用一下 EmailHandler.sendExceptionEmail即可

import cn.hutool.core.exceptions.ExceptionUtil;
import com.email.EmailHandler;
import com.http.constant.HttpCode;
import com.http.exception.BusinessException;
import com.utils.JsonUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import javax.servlet.http.HttpServletRequest;

/**
 * 全局結(jié)果響應(yīng)處理,全局異常處理 <br>
 * 作者:IT學(xué)習(xí)道場(chǎng)             <br>
 * 時(shí)間:2019-01-24 10:33
 */
@Slf4j
@RestControllerAdvice
public class ResultAdvice implements ResponseBodyAdvice<Object> {

    @Autowired
    private EmailHandler emailHandler;

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }
    /**
     * 先捕獲異常 然后再把數(shù)據(jù)返回到ResponseBody中,
     * 然后在Body中要返回?cái)?shù)據(jù)的時(shí)候調(diào)用上面的攔截方法beforeBodyWrite()
     */
    @ExceptionHandler(value = Exception.class)
    public Object handleException(Object o, Exception e, HttpServletRequest request) {
        //此處返回json數(shù)據(jù)
        //捕捉到的異常如果是自定義異常類(lèi),那么就返回自定義異常類(lèi)中的錯(cuò)誤碼和錯(cuò)誤信息
        String stackExceptionMsg = ExceptionUtil.stacktraceToString(e);
        //異常輸出到日志
        log.error(stackExceptionMsg);
        //自定義基礎(chǔ)異常
        if (e instanceof BusinessException) {
            return new ResultException(((BusinessException) e).getCode(), false, ((BusinessException) e).getMessage(), request.getRequestURL().toString());
            //非法參數(shù)異常
        } else if (e instanceof IllegalArgumentException) {
            return new ResultException(HttpCode.BAD_REQUEST.code, false, "參數(shù)異常,請(qǐng)稍候再試", request.getRequestURL().toString());
            //綁定異常
        } else if (e instanceof BindException) {
            return new ResultException(HttpCode.BAD_REQUEST.code, false, ((BindException) e).getBindingResult().getFieldError().getDefaultMessage(), request.getRequestURL().toString());
            //方法參數(shù)異常驗(yàn)證異常
        } else if (e instanceof MethodArgumentNotValidException) {
            return new ResultException(HttpCode.BAD_REQUEST.code, false, ((MethodArgumentNotValidException) e).getBindingResult().getFieldError().getDefaultMessage(), request.getRequestURL().toString());
        }

        //這里是除了自定義異常的其他異常信息
        else {
       // 這里是未知不可控異常,發(fā)送異常郵件即可
            emailHandler.sendExceptionEmail(stackExceptionMsg, e, request);
            return new ResultException(HttpCode.SERVER_ERROR.code, false, "系統(tǒng)異常請(qǐng)聯(lián)系管理員", request.getRequestURL().toString());
        }
    }
}

下面是

application.yml的郵件配置

erver:
  port: 8080
  #啟用undertow
  undertow:
    # CPU有幾核,就填寫(xiě)幾。
    io-threads: 4
    #阻塞任務(wù)線程池, 當(dāng)執(zhí)行類(lèi)似servlet請(qǐng)求阻塞IO操作, undertow會(huì)從這個(gè)線程池中取得線程
    # 它的值設(shè)置取決于系統(tǒng)線程執(zhí)行任務(wù)的阻塞系數(shù),默認(rèn)值是IO線程數(shù)*8
    worker-threads: 32
    # 以下的配置會(huì)影響buffer,這些buffer會(huì)用于服務(wù)器連接的IO操作,有點(diǎn)類(lèi)似netty的池化內(nèi)存管理
    # 每塊buffer的空間大小,越小的空間被利用越充分,不要設(shè)置太大,以免影響其他應(yīng)用,合適即可
    buffer-size: 1024
    # 是否分配的直接內(nèi)存(NIO直接分配的堆外內(nèi)存)
    direct-buffers: true
  servlet:
    context-path: /


spring:
  application:
    name: wlc
  redis:
    host: localhost
    port: 6379
    password:
    lettuce:
      pool:
        # 連接池中的最大空閑連接 默認(rèn)8
        max-idle: 8
        # 連接池中的最小空閑連接 默認(rèn)0
        min-idle: 0
        # 連接池最大連接數(shù) 默認(rèn)8 ,負(fù)數(shù)表示沒(méi)有限制
        max-active: 8
        # 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制) 默認(rèn)-1
        max-wait: -1

  #, 1603610130@qq.com
  mail:
    host: smtp.qq.com
  #你開(kāi)通smtp的郵箱地址
    username: xxxxx@qq.com
  #你的郵箱開(kāi)通smtp時(shí)的授權(quán)碼
    password: xxxxxxxxxx
    port: 465
    toEamils: xxxx@qq.com,yyyy@qq.com
    properties:
      mail:
        smtp:
          auth: true
          ssl:
            enable: true
          starttls:
            enable: true
            required: true
驗(yàn)證,已通知找個(gè)接口,搞個(gè)異常測(cè)試,我的是 int i= 1/0,簡(jiǎn)單測(cè)試



到此結(jié)束,覺(jué)得有用就關(guān)注下,全是原創(chuàng)干貨,你可以看下我的合集,希望能對(duì)你有所幫助





作者:IT學(xué)習(xí)道場(chǎng)

歡迎關(guān)注微信公眾號(hào) : IT學(xué)習(xí)道場(chǎng)