前提说明:在日常的项目中,由于数据量大,数据库隔几天就会自动宕机,独自运行的程序也会自行宕机,或者网络不稳当。产生的各种各样的问题,有时候没有及时发现会导致问题变得越来越大。于是写了一个监控系统,每隔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>