前提说明:在日常的项目中,由于数据量大,数据库隔几天就会自动宕机,独自运行的程序也会自行宕机,或者网络不稳当。产生的各种各样的问题,有时候没有及时发现会导致问题变得越来越大。于是写了一个监控系统,每隔1分钟对程序进行监测,如有离线状态的消息,每隔5分钟会发送邮件,方便正常维护处置。

源代码:码云

1.Demo 

服务器开源监控工具_服务器开源监控工具

2.建表

总共建两张表即可

CREATE TABLE `socket` (
  `id` varchar(255) NOT NULL,
  `mc` varchar(255) DEFAULT NULL,
  `ip` varchar(255) DEFAULT NULL,
  `prot` varchar(255) DEFAULT NULL,
  `status` varchar(255) DEFAULT NULL,
  `time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `ifsocket` int(11) DEFAULT NULL,
  `ifdelte` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `email` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

3.后端代码

  3.1 实体类

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Date;
@Data
@Accessors(chain = true)
public class Socket {

    private String id;
    private String mc;
    private String ip;
    private String prot;
    private String status;
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date time;
    private int ifsocket;
    private int ifdelte;

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getMc() {
        return mc;
    }

    public void setMc(String mc) {
        this.mc = mc;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getProt() {
        return prot;
    }

    public void setProt(String prot) {
        this.prot = prot;
    }

    public Date getTime() {
        return time;
    }

    public void setTime(Date time) {
        this.time = time;
    }

    public int getIfsocket() {
        return ifsocket;
    }

    public void setIfsocket(int ifsocket) {
        this.ifsocket = ifsocket;
    }

    public int getIfdelte() {
        return ifdelte;
    }

    public void setIfdelte(int ifdelte) {
        this.ifdelte = ifdelte;
    }
}

  3.2  xml

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.sws.course.dao.SocketDao">

    <!--查询所有要监听的ip和端口号-->
    <select id="findAll" resultType="com.sws.course.dto.Socket">
--       SELECT * FROM `socket` where ifdelte=1 and ifsocket=1;
      SELECT * FROM `socket` where ifdelte=1 ;
    </select>
    <!--插入要监听的ip和端口号-->
    <insert id="insertSocket" parameterType="com.sws.course.dto.Socket">
        insert into socket (id,mc,ip,prot,status,ifsocket,ifdelte)  values(#{id},#{mc},#{ip},#{prot},#{status},#{ifsocket},#{ifdelte})
    </insert>

    <!--插入要监听的ip和端口号-->
    <update id="updateSocket" parameterType="com.sws.course.dto.Socket">
         update socket SET status=#{status},time=#{time} where id=#{id} ;
    </update>

    <!--查询表中是离线的服务-->
    <select id="findbyStatus"  resultType="com.sws.course.dto.Socket">
      SELECT mc,ip,prot FROM `socket` where status='离线'
    </select>

    <!--查询要发送的邮箱-->
    <select id="findEmail"  resultType="String">
     SELECT email from email
    </select>

    <!--删除数据-->
    <delete id="deleteById">
     delete FROM `socket` where id=#{id}
    </delete>
</mapper>

  3.3  Dao

import com.sws.course.dto.Socket;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;

@Mapper
public interface SocketDao {

    //查询所有需要监控的ip端口
    List<Socket> findAll();

    //插入所有需要监控的ip端口
    int insertSocket(@Param("id") String id,
                     @Param("mc") String mc,
                     @Param("ip") String ip,
                     @Param("prot") String prot,
                     @Param("status") String status,
                     @Param("ifsocket") int ifsocket,
                     @Param("ifdelte") int ifdelte);


    //修改服务端口的状态
    int updateSocket(@Param("id") String id,
                     @Param("mc") String mc,
                     @Param("ip") String ip,
                     @Param("prot") String prot,
                     @Param("status") String status,
                     @Param("time") Date time);


   //查询表中是离线的服务
    List<Socket> findbyStatus();

  //查询要发送的邮箱
    List<String> findEmail();

    //根据id删除相关数据
    int deleteById(String id);

}

3.4Controller

package com.sws.course.controller;


import com.fasterxml.jackson.annotation.JsonFormat;
import com.sws.course.dao.SocketDao;
import com.sws.course.dto.Socket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@RestController
@RequestMapping("/Socket")
@CrossOrigin
@Slf4j
public class SocketController {
    @Autowired
    private SocketDao dao;

    @PostMapping("add")
    public Map<String,Object> add(String mc,String ip,String prot) {
        UUID uuid= UUID.randomUUID();
        String uuidString=uuid.toString();
        dao.insertSocket(uuidString,mc,ip,prot,"待定",1,1);
        Map<String, Object> map =  new HashMap<>();
        map.put("success","保存成功");
        map.put("ip",ip);
        map.put("prot",prot);
        return map;
    }

    @PostMapping("findAll")
    public List<Socket> findAll() {

        List<Socket> list=dao.findAll();

        return list;
    }

    @PostMapping("deleteById")
    public Map<String,Object> delete(String id) {
        Map<String, Object> map =  new HashMap<>();
        int num=dao.deleteById(id);
        map.put("success","删除成功");
        return map;
    }



}

3.5 定时任务(两个)

import com.sws.course.dao.SocketDao;
import com.sws.course.dto.Socket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.ConnectException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Component
public class crontabSocket {
    @Autowired
    SocketDao dao;

    @Scheduled(cron="0 0/1 * * * ? ")   //每1分钟执行一次
    public  void AnimalAechartsMapper() throws IOException, ParseException {
        java.net.Socket client = null;
        List<Socket> list=dao.findAll();
        for (int j=0;j<list.size();j++){

            String id=list.get(j).getId();
            String ip=list.get(j).getIp();
            String mc=list.get(j).getMc();
            String prot=list.get(j).getProt();
            int protInt=Integer.parseInt(prot);
            try{
                client = new java.net.Socket(ip, protInt);
                System.out.println("连接已建立...");

                Date time=getDate();
                dao.updateSocket(id,mc,ip,prot,"在线",time);

            }  catch(ConnectException e) {
                System.out.println("未建立连接!!!");

                Date time=getDate();
                dao.updateSocket(id,mc,ip,prot,"离线",time);


            }


        }

    }

    public Date getDate() throws ParseException {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        String dateName = df.format(calendar.getTime());
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sf.parse(dateName);
        return  date;
    }

}
import com.sws.course.dao.SocketDao;
import com.sws.course.dto.Socket;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.ParseException;
import java.util.List;


@Component
public class crontabEmail {

    @Autowired
    SocketDao socketdao;

    @Scheduled(cron="0/5 * * * * ?")   //每10分钟执行一次
    public  void SendEamil() throws IOException, ParseException, EmailException {

        List<Socket> list=socketdao.findbyStatus();
        List<String>  emailList =socketdao.findEmail();

        int num=list.size();
        if (num>0) {
            HtmlEmail email=new HtmlEmail();//创建一个HtmlEmail实例对象
            email.setHostName("smtp.163.com");//邮箱的SMTP服务器,一般123邮箱的是smtp.123.com,qq邮箱为smtp.qq.com
            email.setCharset("utf-8");//设置发送的字符类型

            for (int i=0;i<emailList.size();i++){
                email.addTo(emailList.get(i));//设置收件人
            }

            email.setFrom("18629461220@163.com","服务端口监测系统");//发送人的邮箱为自己的,用户名可以随便填
            email.setAuthentication("18629461220@163.com","xxxxxIBSVPURHA");//设置发送人到的邮箱和用户名和授权码(授权码是自己设置的)
            email.setSubject("服务端口监测系统-离线通知");//设置发送主题email.setMsg("1234");//设置发送内容email.send();//进行发送
            StringBuffer bodyBf = new StringBuffer();
            bodyBf.append("<!DOCTYPE html>");
            bodyBf.append("<HTML>");
            bodyBf.append("<HEAD>");
            bodyBf.append("<TITLE> 管理员你好</TITLE>");
            bodyBf.append("<meta http-equiv=Content-Type content=text/html; charset=utf-8>");
            bodyBf.append("</HEAD>");
            bodyBf.append("<BODY>");
            bodyBf.append("<h1 align=center style='color:rgb(5,112,255)'>服务端口监测系统 </h1>");
            bodyBf.append("<table border='1'  align=center>");
            bodyBf.append("<thead><tr>");
            bodyBf.append("<tr><th>名称</th><th>地址</th><th>端口</th></tr></thead><tbody>");
            for (int j=0;j<list.size();j++){
                String ip=list.get(j).getIp();
                String mc=list.get(j).getMc();
                String prot=list.get(j).getProt();
                bodyBf.append("<tr><th>"+mc+"</th><th>"+ip+"</th><th>"+prot+"</th></tr>");
            }
            bodyBf.append("</tbody></table>");
            bodyBf.append("</BODY>");
            bodyBf.append("</HTML>");
            //email.setMsg("您的验证码是:123456");
            email.setHtmlMsg(bodyBf.toString());
            email.send();
            System.out.println("发送成功");
        }else{

        }

    }
}

4.前段代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>服务端口监测系统</title>

    <link rel="icon" href="./img/favicon.ico" type="image/x-icon">
    <link rel="stylesheet" href="./css/bootstrap.min.css">
    <script src="./js/jquery-3.4.1.min.js"></script>
    <script src="./js/bootstrap.min.js"></script>

    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>

    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.css">
    <!-- Latest compiled and minified JavaScript -->
    <script src="https://unpkg.com/bootstrap-table@1.15.3/dist/bootstrap-table.min.js"></script>
    <!-- Latest compiled and minified Locales -->
    <script src="https://unpkg.com/bootstrap-table@1.15.3/dist/locale/bootstrap-table-zh-CN.min.js"></script>

    <script src="https://cdn.bootcdn.net/ajax/libs/layer/3.1.1/layer.js"></script>

</head>
<style>
  /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
  ::-webkit-scrollbar {
            width: 10px;
            height: 10px;
            background-color: #F5F5F5;
        }

        /*定义滚动条轨道 内阴影+圆角*/
        ::-webkit-scrollbar-track {
            -webkit-box-shadow: inset 0 0 6px rgba(217, 223, 233);
            border-radius: 5px;
            background-color: #F5F5F5;
        }

        /*定义滑块 内阴影+圆角*/
        ::-webkit-scrollbar-thumb {
            border-radius: 5px;
            -webkit-box-shadow: inset 0 0 6px rgba(217, 223, 233);
            background-color: rgba(217, 223, 233);
        }

    body {
        margin: 0;
        padding: 0;
    }
   #LoadTable{
        width: 800px;
  }

   .page-header{
       display: flex;
       justify-content:center;
       color: cornflowerblue;
   }
  #pagebody{
      display: flex;
      justify-content:  center;
  }
  #离线{
     color: red;
  }
  #在线{
      color: green;
  }
    #add{
        position: absolute;
        right: 20px;
        bottom: 20px;
    }

</style>

<body>
<div class="page-header">
    <h1>欢迎来到服务端口监测系统</h1>
</div>
<div id="pagebody">


    <div id="toolbar" class="btn-group">
        <button id="btn_add" type="button" onclick="btn_add()" class="btn btn-primary">
            <span class="glyphicon glyphicon-plus" aria-hidden="true" ></span>新增
        </button>

    </div>

    <table id="LoadTable"></table>


</div>


    <script>
        $(function () {

            //1.初始化Table
            TableInit();


        });


       var TableInit = function () {
           var oTableInit = new Object();
           //初始化Table
           $('#LoadTable').bootstrapTable({
               url: "/Socket/findAll",
                columns: [{
                   field: 'mc',
                   title: '名称'
               }, {
                   field: 'ip',
                   title: '地址'
               }, {
                   field: 'prot',
                   title: '端口'
               }, {
                   field: 'status',
                   title: '状态',
                    align: 'center',
                    valign: 'middle',
                    formatter: function(status){
                        if(status=="离线"){
                            return '<text type="text"   style="color:#D9534F">'+status+'</text>';
                        }else if(status=="在线"){
                            return '<text type="text"  style="color:#228B22" >'+status+'</text>';
                        }else if(status=="待定"){
                            return '<text type="text" style="color:#A9A9A9" >'+status+'</text>';
                        }

                    }
               },{
                    field: 'time',
                    title: '时间',
                    align: 'center',
                    valign: 'middle',
                },{
                   field: 'id',
                   title: '操作',
                   align: 'center',
                   valign: 'middle',
                   formatter: function(id){
                       return '<button type="button" class="btn btn-danger" onclick="deleteById(\''+id+'\')">删除</button>';
                   }
               }],
               method: 'post',                      //请求方式(*)
               toolbar: '#toolbar',                //工具按钮用哪个容器
               striped: true,                      //是否显示行间隔色
               cache: false,                       //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
               pagination: true,                   //是否显示分页(*)
               sortable: false,                     //是否启用排序
               sortOrder: "asc",                   //排序方式
               pageSize: 25,                       //每页的记录行数(*)
               clickToSelect: true,                //是否启用点击选中行
               //height: 500,                        //行高,如果没有设置height属性,表格自动根据记录条数觉得表格高度
               uniqueId: "id",                     //每一行的唯一标识,一般为主键列

           });
       }

var html='<form id="form_data" style="padding: 10px">\n' +
    '                    <div class="modal-body">\n' +
    '                        <div class="form-group">\n' +
    '                            <label for="mc">名称</label>\n' +
    '                            <input type="text" class="form-control" id="mc" placeholder="某某数据库">\n' +
    '                        </div>\n' +
    '                        <div class="form-group">\n' +
    '                            <label for="ip">地址/ip</label>\n' +
    '                            <input type="text" class="form-control" id="ip" placeholder="127.0.0.1">\n' +
    '                        </div>\n' +
    '                        <div class="form-group">\n' +
    '                            <label for="prot">端口/prot</label>\n' +
    '                            <input type="text" class="form-control" id="prot" placeholder="3306">\n' +
    '                        </div>\n' +
    '                    </div>\n' +
    '                    <div class="modal-footer">\n' +
    '                        <button type="button"  onclick="add()" class="btn btn-primary">\n' +
    '                            提交更改\n' +
    '                        </button>\n' +
    '                    </div>\n' +
    '                </form>'

        function  btn_add(){
            layer.open({
                type: 1,
                skin: 'layui-layer-rim', //加上边框
                area: ['600px' ], //宽高
                content: html
            });
        }

        function  deleteById(id){
            layer.confirm('你确认要进行删除操作?', {
                btn: ['取消','确认'] //按钮
            }, function(){
                layer.msg('取消成功', {icon: 1});
            }, function(){
                $.ajax({
                    type: "post",
                    async:false,
                    url: "/Socket/deleteById",
                    data:{"id":id,},
                    dataType: "json",
                    success: function (response) {
                        layer.msg('删除成功', {
                            time: 2000, //2s后自动关闭
                        });
                        location.reload();
                    },
                    error: function (e) {
                        alert("请求异常。");
                    }
                });
            });



        }


        function add() {

            var mc = $.trim($('#mc').val());
            var ip = $.trim($('#ip').val());
            var prot = $.trim($('#prot').val());

            $.ajax({
                type: "post",
                async:false,
                url: "/Socket/add",
                data:{"mc":mc,"ip":ip,"prot":prot},
                dataType: "json",
                success: function (response) {
                    layer.msg('添加成功', {
                        time: 2000, //2s后自动关闭
                    });

                    location.reload();
                },
                error: function (e) {
                    alert("请求异常。");
                }
            });
        }

    </script>
</body>

</html>