项目发布成功、失败,Java项目来实现邮件通知相关人员,实时反馈提醒信息

场景说明

在开发的流程中必须涉及的项目的部署发布,这个过程也肯定会有成功、失败,作为开发能够实时的得到反馈是很有必要的,在不同的公司里采用的提醒方式不同。在说明下面的方案前,需要首先说明一下基本应用的场景。

  • 纯后台应用,现在项目基本都是前后端分离,因为一个前端服务可能会对应多个后端服务的支持,随着整个开发大环境的完善和技术的成熟,之前那种前后端耦合的应用很少,这里不在做具体的考虑。

  • 项目的基本架构是Spring+Spring MVC+Mybatis,其实主要是Spring+Spring MVC,因为下面的实现方式在这种模式下模拟,其他环境可以根据这个模式仿照,但是照搬可能存在问题,因为现在很多公司都开始使用SpringBoot相关的前沿技术。

  • 环境说明
    ①、本地测试环境,就是IDEA的启动测试,不多说;
    ②、开发测试环境,这个环境基本用来联调,开发人员发布项目使用的;
    ③、测试环境,这个是测试人员来用,将开发的代码拉到测试环境,进行各种姿势的测试;
    ④、演示环境,这个环境看各个公司的定义可能不同,也就是上线前的最后一个环境,基本模拟线上环境,最终验证项目的完整性,有时候所说的灰度、冒烟测试都会在这个环境执行;
    ⑤、线上环境,不解释。

  • 下面的内容数据自己歪歪,如果存在问题,欢迎提建议。

简单实现的几种方式

  • 在项目中添加一个主页(又称健康页),当发布完成后,访问该页面是OK就表示发布成功,反之就是失败,但是这样存在很多问题,比如在线上环境,这个页面可能就访问不到(纯后台应用可能不会提供这个访问功能)。在本地测试和开发环境可以凑合使用。
  • 定时任务请求项目,这个不仅能监控到项目启动是否成功,也可以监控服务器宕机问题,但是也存在问题,那就是要重新开一个项目,用于发送请求,另外当项目启动的时候,刚好定时任务发起,此时是请求不通的,系统会误报启动失败或者宕机,其实不是这样。
  • 日志扫描,通过对日志的分析查看日志中的异常,并做分析,给予开发或者维护人员一个通知,可以通过Python脚本等方式执行,设计到整体项目架构的问题,不做太多的讨论,也不是这个博客的主要讨论范畴,不做太多赘述。

项目中添加逻辑代码,用于捕获项目启动加载是否正常,从而判断项目是否启动成功。(主要讨论)

项目启动反馈提醒实现

web.xml文件中的配置
<servlet>
    <servlet-name>spring-dispatcher</servlet-name>
    <servlet-class>com.minuor.service.notice.LocalDispatcherServletDemo</servlet-class>
    <!-- 配置SpringMVC需要加载的配置文件 spring-xxx.xml -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-web.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>spring-dispatcher</servlet-name>
	<!--默认匹配所有的请求 -->
	<url-pattern>/</url-pattern>
</servlet-mapping>

正常应该配置spring默认的DispatcherServlet,这里需要改为加载重新后的LocalDispatcherServletDemo。

LocalDispatcherServletDemo类代码
package com.minuor.service.notice;

import com.minuor.common.utils.JavaMailSendUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * 重写DispatcherServlet,做系统启动成功失败监控并通知
 */
@Slf4j
public class LocalDispatcherServletDemo extends DispatcherServlet {

    public LocalDispatcherServletDemo() {
        super();
    }

    public LocalDispatcherServletDemo(WebApplicationContext webApplicationContext) {
        super(webApplicationContext);
    }

    @Override
    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext webApplicationContext;
        try {
            webApplicationContext = super.initWebApplicationContext();
            sendMsg(Boolean.TRUE);
            log.info(">>>>>>>webApplicationContext初始化成功~");
        } catch (Exception e) {
            sendMsg(Boolean.FALSE);
            webApplicationContext = new XmlWebApplicationContext();//设置临时值,避免重复初始化
            log.info(">>>>>>>webApplicationContext初始化失败~");
        }
        return webApplicationContext;
    }

    /**
     * 发送邮件
     */
    private void sendMsg(boolean flag) {
        try {
            JavaMailSendUtil sender = new JavaMailSendUtil();
            //成功失败信息
            String result = "FAIL";
            if (flag) result = "SUCCESS";
            //模块名
            String ip = InetAddress.getLocalHost().getHostAddress();
            String userDir = System.getProperty("user.dir");
            String tempStr = userDir.substring(0, userDir.indexOf(File.separator + "bin"));
            String userDirModel = tempStr.substring(tempStr.lastIndexOf(File.separator) + 1);
            //组装并推送信息
            String mailTest = "发布系统:" + "Minuor个人博客系统" + "<br/>" +
                    "发布环境:" + ip + "<br/>" +
                    "模块名称:" + userDirModel + "<br/>" +
                    "发布时间:" + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date()) + "<br/>" +
                    "发布结果:" + result + "<br/>" +
                    "温馨提示:" + "此邮件仅为系统发布通知邮件,请勿回复!";
            sender.sendEmail("个人博客系统发布结果提醒", mailTest, "xxxx@163.com");
        } catch (Exception e) {
            log.info(">>>>>个人博客系统发布结果预警邮件推送失败!异常信息:{}", e);
        }
    }

    @Override
    public void setDetectAllHandlerMappings(boolean detectAllHandlerMappings) {
        super.setDetectAllHandlerMappings(detectAllHandlerMappings);
    }

    @Override
    protected void initFrameworkServlet() throws ServletException {
        super.initFrameworkServlet();
    }

    @Override
    public void setDetectAllHandlerAdapters(boolean detectAllHandlerAdapters) {
        super.setDetectAllHandlerAdapters(detectAllHandlerAdapters);
    }

    @Override
    public void setDetectAllHandlerExceptionResolvers(boolean detectAllHandlerExceptionResolvers) {
        super.setDetectAllHandlerExceptionResolvers(detectAllHandlerExceptionResolvers);
    }

    @Override
    public void setDetectAllViewResolvers(boolean detectAllViewResolvers) {
        super.setDetectAllViewResolvers(detectAllViewResolvers);
    }

    @Override
    public void setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound) {
        super.setThrowExceptionIfNoHandlerFound(throwExceptionIfNoHandlerFound);
    }

    @Override
    public void setCleanupAfterInclude(boolean cleanupAfterInclude) {
        super.setCleanupAfterInclude(cleanupAfterInclude);
    }

    @Override
    protected void onRefresh(ApplicationContext context) {
        super.onRefresh(context);
    }

    @Override
    protected void initStrategies(ApplicationContext context) {
        super.initStrategies(context);
    }

    @Override
    protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
        return super.getDefaultStrategy(context, strategyInterface);
    }

    @Override
    protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
        return super.getDefaultStrategies(context, strategyInterface);
    }

    @Override
    protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
        return super.createDefaultStrategy(context, clazz);
    }

    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        super.doService(request, response);
    }

    @Override
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        super.doDispatch(request, response);
    }

    @Override
    protected LocaleContext buildLocaleContext(HttpServletRequest request) {
        return super.buildLocaleContext(request);
    }

    @Override
    protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
        return super.checkMultipart(request);
    }

    @Override
    protected void cleanupMultipart(HttpServletRequest request) {
        super.cleanupMultipart(request);
    }

    @Override
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        return super.getHandler(request);
    }

    @Override
    protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
        super.noHandlerFound(request, response);
    }

    @Override
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        return super.getHandlerAdapter(handler);
    }

    @Override
    protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        return super.processHandlerException(request, response, handler, ex);
    }

    @Override
    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        super.render(mv, request, response);
    }

    @Override
    protected String getDefaultViewName(HttpServletRequest request) throws Exception {
        return super.getDefaultViewName(request);
    }

    @Override
    protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
        return super.resolveViewName(viewName, model, locale, request);
    }
}

重写所有的方法,直接调用父类DispatcherServlet内的逻辑,实际LocalDispatcherServletDemo中没有具体的逻辑,只有构造方法、initWebApplicationContext、sendMsg短信发送逻辑的修改和创建。

package com.minuor.common.mail;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

/**
 * 发送邮件服务
 */
@Slf4j
public class JavaMailSendUtil {
    /**
     * 发送邮件
     */
    public void sendEmail(String subject, String mailText, String rStr) {
        try {
            // 1.创建一个程序与邮件服务器会话对象 Session
            Properties props = new Properties();
            props.setProperty("mail.smtp.host", "smtp.163.com");
            props.setProperty("mail.smtp.port", "25");
            // 指定验证为true
            props.setProperty("mail.smtp.auth", "true");
            // 验证账号及密码,密码需要是第三方授权码
            Authenticator auth = new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(
                            "xxxx@163.com", "123456");
                }
            };
            Session session = Session.getInstance(props, auth);

            // 2.创建一个Message,它相当于是邮件内容
            Message message = new MimeMessage(session);
            // 设置发送者
            message.setFrom(new InternetAddress("xxxxx@163.com"));
            // 设置发送方式与接收者
            if (StringUtils.isBlank(rStr)) return;
            String[] rStrs = rStr.split(",");
            InternetAddress[] address = new InternetAddress[rStrs.length];
            int index = 0;
            for (String str : rStrs) {
                address[index] = new InternetAddress(str);
                index++;
            }
            message.setRecipients(MimeMessage.RecipientType.TO, address);
            // 设置主题
            message.setSubject(subject);
            // 设置内容
            message.setContent(mailText, "text/html;charset=utf-8");
            // 3.创建 Transport用于将邮件发送
            Transport.send(message);
            log.info(">>>>>>>发送邮件成功<<<<<<<");
        } catch (Exception e) {
            log.error(">>>>>>>发送邮件异常:{}", e);
        }
    }
}

封装的最简单的发送方式,只为实现简单的邮件推送功能。

具体说明
  • 在重写initWebApplicationContext方法内,对调用父类的initWebApplicationContext方法加了异常捕捉,在catch捕捉中添加了邮件处理逻辑,也将异常吃掉不打印出来;

  • 邮件推送分为两个部分,一个是项目启动成功,一个是项目启动失败,两个部分都会给开发或者维护人员提供相应的邮件提醒;

  • 最主要的一点,这里涉及到的邮件发送工具类,重写类LocalDispatcherServletDemo都不能交给spring管理,因为在spring加载失败的时候,这些类对应的bean是不能创建成功的,更不用说对象的注入以及具体逻辑的实现。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿洞晓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值