实现逻辑
首先要创建 不同类别的预警(数据中断,越限),以及不同严重级别(红,橙,黄,蓝)的预警的相关配置
越限报警
越限报警:监测数据,并调用接口判断是否满足报警
(数据在某个范围内是属于特别严重,严重,较重,一般)
1:当前监测点没有报警发生,则新增报警
2:当前监测点有其他类型的报警发生,则新增当前类型的报警
3:当前监测点有同类型的报警发生,判断是否级别一致,级别一致,更新报警信息的最新报警值。级别不一致,关闭上一条报警,新增一条报警
并根据情况判断发短信通知哪些人,把报警信息用websocket推送到前端,实时更新页面报警信息
//entity接收过来的水位数据
public boolean AccessSW(WaterLevel entity) {
try {
Yjxx yjxx=new Yjxx();
String content="";
String alevel= "";
Sensorinfo sensorinfo=SensorinfoService.GetBy(entity.deviceSn, entity.sensorCode);
String monitorPointCode=sensorinfo.getMonitorPointCode();//获取监测点编码
MonitorPointInfo monitorPoint =MonitorPointInfoService.GetByCode(monitorPointCode);//获取监测点
List<MonitorMxpzDto> monitorMxpzDtos=MonitorModelConfigService.GetDtoByMonitorCode(monitorPointCode);//获取监测点的预警配置
if(monitorMxpzDtos!=null&&monitorMxpzDtos.size()>0){
for (MonitorMxpzDto monitorMxpzDto:monitorMxpzDtos) {
if(monitorMxpzDto!=null&&monitorMxpzDto.mxpzDto!=null) {
if (monitorMxpzDto.mxpzDto.redConfig != null) {//红色配置
Map<String, List<Dlpz>> redConfig = monitorMxpzDto.mxpzDto.redConfig;
Map<Boolean, String> result = getSWContent(redConfig, entity, monitorPointCode);
if (result != null && result.get(true) != null) {
alevel = "red";
content = result.get(true) + "触发了红色预警,请网格员加强日常巡查!";
}
}
if (alevel.equals("") && monitorMxpzDto.mxpzDto.orangeConfig != null) {//橙色配置
Map<String, List<Dlpz>> orangeConfig = monitorMxpzDto.mxpzDto.orangeConfig;
Map<Boolean, String> result = getSWContent(orangeConfig, entity, monitorPointCode);
if (result != null && result.get(true) != null) {
alevel = "orange";
content = result.get(true) + "触发了橙色预警,请网格员加强日常巡查!";
}
}
if (alevel.equals("") && monitorMxpzDto.mxpzDto.yellowConfig != null) {//黄色配置
Map<String, List<Dlpz>> yellowConfig = monitorMxpzDto.mxpzDto.yellowConfig;
Map<Boolean, String> result = getSWContent(yellowConfig, entity, monitorPointCode);
if (result != null && result.get(true) != null) {
alevel = "yellow";
content = result.get(true) + "触发了黄色预警,请网格员加强日常巡查!";
}
}
if (alevel.equals("") && monitorMxpzDto.mxpzDto.blueConfig != null) {//蓝色配置
Map<String, List<Dlpz>> blueConfig = monitorMxpzDto.mxpzDto.blueConfig;
Map<Boolean, String> result = getSWContent(blueConfig, entity, monitorPointCode);
if (result != null && result.get(true) != null) {
alevel = "blue";
content = result.get(true) + "触发了蓝色预警,请网格员加强日常巡查!";
}
}
if(!alevel.equals("")&& !content.equals("")){
String contacts = wapConst.DEFAULT_CONTACT;
//获取通知人信息
if (monitorMxpzDto.gridPersonList != null && monitorMxpzDto.gridPersonList.size() > 0) {
contacts = monitorMxpzDto.gridPersonList.stream().map(a -> a.getContact()).collect(Collectors.joining(","));
}
//查询是否存在正在发生的报警
YjxxCondition yjxxCondition = new YjxxCondition();
yjxxCondition.DataIds.add(monitorPointCode);
yjxxCondition.WarningStates.add(0);
yjxxCondition.ConfigIds.add(monitorMxpzDto.getModelId());
List<Yjxx> yjxxlist = yjxxService.GetByCondition(yjxxCondition);
Boolean result = false;
String datastatus = "";
if (yjxxlist != null && yjxxlist.size() > 0) {
Yjxx oldYjxx = yjxxlist.get(0);
//判断是否同一级别
if (oldYjxx.getWarningLevel().equals(alevel)) {//更新报警记录
// yjxx.setWarningId(oldYjxx.getWarningId());
oldYjxx.setWarningContent(content);
oldYjxx.setLatestTime(new Date());//更新最新报警时间
result = yjxxService.ModifyById(oldYjxx);
yjxx = oldYjxx;
datastatus = "Modify";
} else {//新增高级别报警
oldYjxx.setWarningState(-1);
result = yjxxService.ModifyById(oldYjxx);
//预警信息
yjxx.setDataId(monitorPointCode);
yjxx.setWarningType("专业监测");
yjxx.setWarningSoure(monitorPoint.getMonitorPointName() + monitorPoint.getMonitorPointType());
yjxx.setWarningLocation(monitorPoint.getLocation());
yjxx.setWarningLevel(alevel);
yjxx.setWarningContent(content);
yjxx.setConfigId(monitorMxpzDto.getModelId());
yjxx.setWarningState(0);
yjxx.setProcessState(0);
yjxx.setWarningTime(new Date());
int flag = yjxxService.Add(yjxx);//新增预警
result = flag > 0;
datastatus = "Modify";
//发送短信通知
MsgService.saveSWDataMethod(content, contacts);
}
} else {//新增
//预警信息
yjxx.setDataId(monitorPointCode);
yjxx.setWarningType("专业监测");
yjxx.setWarningSoure(monitorPoint.getMonitorPointName() + monitorPoint.getMonitorPointType());
yjxx.setWarningLocation(monitorPoint.getLocation());
yjxx.setWarningLevel(alevel);
yjxx.setWarningContent(content);
yjxx.setConfigId(monitorMxpzDto.getModelId());
yjxx.setWarningState(0);
yjxx.setProcessState(0);
yjxx.setWarningTime(new Date());
int flag = yjxxService.Add(yjxx);//新增预警
result = flag > 0;
datastatus = "Add";
//发送短信通知
MsgService.saveSWDataMethod(content, contacts);
}
if (result) {
YjxxDto alarm = new YjxxDto(yjxx);
alarm.monitorPoint = monitorPoint;
//推送报警消息
SocketVO socket = new SocketVO();
socket.setData(alarm);
socket.setMessageName("预警信息");
socket.setTotal(1);
socket.setDataState(datastatus);
webSocket.sendMessage(socket);//前台推送消息
// emailUtil.sendMessage("*****@qq.com",alevel+"预警提醒",content);//发送邮件
return true;
}
}
}
}
}
return false;
} catch (Exception e) {
log.error(e.getMessage());
return false;
}
}
中断报警
中断报警:新增定时任务,判断数据是否中断
每隔一个小时循环中断配置配置,判断关联的监测点是否在配置的时间间隔内没有数据产生
满足条件则新增或更新中断报警,并发通知
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
/**
* 任务类
*/
@Component
public class WarningTask {
@Autowired
private WebSocket webSocket;
@Autowired
private MonitorModelConfigServiceImpl MonitorModelConfigService;
@Autowired
private MonitorPointInfoServiceImpl MonitorPointInfoService;
@Autowired
private AccessmonitorServiceImpl AccessmonitorService;
@Autowired
SwServiceImpl SwService;
@Autowired
SzServiceImpl SzService;
@Autowired
GnssServiceImpl GnssService;
@Autowired
YjxxServiceImpl yjxxService;
@Autowired
private MxpzServiceImpl MxpzService;
@Autowired
private CjswServiceImpl cjswService;
@Autowired
private MsgServiceImpl MsgService;
/**
* 每天凌晨执行一次
*/
// @Scheduled(fixedRate = 10000)
@Scheduled(cron = "0 0 6 * * ?")
public void saveSWDataMethod() throws InterruptedException {
Date date = new Date();
SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd");
// Calendar calendar = Calendar.getInstance(); //创建Calendar 的实例
// calendar.add(Calendar.DAY_OF_MONTH, -1); //当前时间减去一天,即一天前的时间
try {
RestTemplate restTemplate = new RestTemplate();
String url = "http:*****/GetRiverData?date="+dateFormat.format(date).toString(); //dateFormat.format(date); //设置url+当前时间
rowResponse responseData=restTemplate.getForObject(url, rowResponse.class); //通过getForObject请求调用接口
List<Hksw> list = responseData.getData();
Hksw hankou=list.stream().filter(h->h.STNM.equals("汉口")).findFirst().orElse(null);//过滤 只拿汉口的数据
String wsgc=hankou.Z;
Double z=Double.valueOf(wsgc);
//新增
Cjsw cjsw=new Cjsw();
cjsw.setSwDate(date);
cjsw.setWsgc(wsgc);
BigDecimal b1 = BigDecimal.valueOf(z);
BigDecimal b2 = BigDecimal.valueOf(1.953);
String hhgc=String.valueOf(b1.subtract(b2).doubleValue());
cjsw.setHhgc(hhgc);
cjswService.Add(cjsw);
} catch (RestClientException e) {
e.printStackTrace();
}
// System.out.println("fixedRateMethod:" + new Date());
// Thread.sleep(1000);
}
//根据时间差和单位获取其他时间
public static Date getBeforeDay(int day,String unit) {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
switch (unit) {
case "m":
calendar.add(Calendar.MINUTE, -day);
break;
case "h":
calendar.add(Calendar.HOUR, -day);
break;
case "d":
calendar.add(Calendar.DATE, -day);
break;
case "W":
calendar.add(Calendar.DAY_OF_WEEK, -day);
break;
case "M":
calendar.add(Calendar.MONTH, -day);
break;
}
date = calendar.getTime();
// String yesterday = sdf.format(date);
return date;
}
/**
* 每1小时验证是否有数据中断
*/
@Scheduled(cron = "0 0 0/1 * * ?")
// @Scheduled(fixedRate = 6000000)
public void DataInterruptWarning() throws InterruptedException {
try {
//获取所有中断报警的配置
List<MonitorMxpzDto> monitorMxpzList = MonitorModelConfigService.GetDtoByModelConfigTypes("interrupt");
if (monitorMxpzList != null && monitorMxpzList.size() > 0) {
//循环模型配置
monitorMxpzList.stream().forEach(monitorMxpzDto -> {
//获取中断的时间间隔
if (monitorMxpzDto.mxpzDto != null && monitorMxpzDto.mxpzDto.zdpz != null) {
Integer timeOut = monitorMxpzDto.mxpzDto.zdpz.getTimeOut();
//获取监测点编码
String monitorCode = monitorMxpzDto.getMonitorCode();
//获取监测点数据
MonitorPointInfo monitorPointInfo = MonitorPointInfoService.GetByCode(monitorCode);
if (monitorPointInfo != null) {
String monitorType = monitorPointInfo.getMonitorPointType();
//获取数据的类别
String[] monitorPointTypes = monitorType.split(",");
List<Accessmonitor> accessmonitors = AccessmonitorService.GetByMonitorPointTypes(monitorPointTypes);
if (accessmonitors != null && accessmonitors.size() > 0) {
//获取当前监测点的数据表
List<String> tableNames = accessmonitors.stream().map(a -> a.getTableName()).distinct().collect(Collectors.toList());
//数据查询条件
MonitorCondition monitorCondition = new MonitorCondition();
List<String> monitorCodes = new ArrayList<>();
monitorCodes.add(monitorCode);
monitorCondition.monitorCodes = monitorCodes;
monitorCondition.startTime = getBeforeDay(timeOut, "h");
monitorCondition.endTime = new Date();
// List<Object> dataList = new ArrayList<>();
boolean hasflag = false;
for (String tableName : tableNames) {
// 根据类型取对应表的数据
if (tableName.equals("sw")) {
List<Sw> dataList = SwService.GetByCondition(monitorCondition);
if (dataList != null && dataList.size() > 0) {
hasflag = false;
} else
hasflag = true;
} else if (tableName.equals("sz")) {
List<Sz> dataList = SzService.GetByCondition(monitorCondition);
if (dataList != null && dataList.size() > 0) {
hasflag = false;
} else
hasflag = true;
} else if (tableName.equals("gnss")) {
List<Gnss> dataList = GnssService.GetByCondition(monitorCondition);
if (dataList != null && dataList.size() > 0) {
hasflag = false;
} else
hasflag = true;
}
if (!hasflag)//如果有数据跳出循环
break;
}
if (hasflag) {//没有数据 触发数据中断
//查询是否存在正在发生的报警
YjxxCondition yjxxCondition = new YjxxCondition();
yjxxCondition.DataIds.add(monitorCode);
yjxxCondition.WarningStates.add(0);
yjxxCondition.ConfigIds.add(monitorMxpzDto.getModelId());
List<Yjxx> yjxxlist = yjxxService.GetByCondition(yjxxCondition);
Boolean result = false;
String datastatus = "";
Yjxx yjxx = new Yjxx();
String content = monitorCode + "监测点已连续" + timeOut + "小时未接收到监测数据,请工作人员进行核查。";
if (yjxxlist != null && yjxxlist.size() > 0) {
yjxx = yjxxlist.get(0);//获取最新一条记录
//更新报警记录
// yjxx.setWarningContent(content);
yjxx.setLatestTime(new Date());//更新最新报警时间
result = yjxxService.ModifyById(yjxx);
datastatus = "Modify";
} else {//新增预警信息
yjxx.setDataId(monitorCode);
yjxx.setWarningType("设备异常预警");
yjxx.setWarningSoure(monitorPointInfo.getMonitorPointName() + monitorPointInfo.getMonitorPointType());
yjxx.setWarningLocation(monitorPointInfo.getLocation());
yjxx.setWarningContent(content);
yjxx.setConfigId(monitorMxpzDto.getModelId());
yjxx.setWarningState(0);
yjxx.setProcessState(0);
yjxx.setWarningTime(new Date());
int flag = yjxxService.Add(yjxx);//新增预警
result = flag > 0;
datastatus = "Add";
//发送短信通知
String contacts = wapConst.DEFAULT_CONTACT;
//获取通知人信息
if (monitorMxpzDto.gridPersonList != null && monitorMxpzDto.gridPersonList.size() > 0) {
contacts = monitorMxpzDto.gridPersonList.stream().map(a -> a.getContact()).collect(Collectors.joining(","));
}
MsgService.saveSWDataMethod(content, contacts);
}
if (result) {
YjxxDto alarm = new YjxxDto(yjxx);
alarm.monitorPoint = monitorPointInfo;
//推送报警消息
SocketVO socket = new SocketVO();
socket.setData(alarm);
socket.setMessageName("预警信息");
socket.setTotal(1);
socket.setDataState(datastatus);
webSocket.sendMessage(socket);//前台推送消息
// emailUtil.sendMessage("*****@qq.com",alevel+"预警提醒",content);//发送邮件
}
}
}
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
webSocket的配置和工具类
@Data
public class SocketVO {
@ApiModelProperty("总计条数")
private Integer total;
@ApiModelProperty("消息名")
private String messageName;
@ApiModelProperty("数据")
private Object data;
@ApiModelProperty("数据状态")
private String dataState;
}
import com.alibaba.fastjson.JSON;
import com.dto.SocketVO;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
public class WebSocketCustomEncoding implements Encoder.Text<SocketVO>{
@Override
public String encode(SocketVO vo) {
assert vo!=null;
return JSON.toJSONString(vo);
}
@Override
public void init(EndpointConfig endpointConfig) {
}
@Override
public void destroy() {
}
}
import com.service.impl.WebSocketCustomEncoding;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint(value = "/websocket",encoders = WebSocketCustomEncoding.class)
@Component
@Slf4j
public class WebSocket {
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//concurrent包的线程安全Set,用来存放每个客户端对应的WebSocket对象。
private static CopyOnWriteArraySet<WebSocket> webSocketSet=new CopyOnWriteArraySet<>();
/**
* 建立连接成功
* @param session
*/
@OnOpen
public void onOpen(Session session){
this.session=session;
webSocketSet.add(this);
log.info("【websocket消息】 有新的连接,总数{}",webSocketSet.size());
}
/**
* 连接关闭
*/
@OnClose
public void onClose(){
this.session=session;
webSocketSet.remove(this);
log.info("【websocket消息】 连接断开,总数{}",webSocketSet.size());
}
/**
* 接收客户端消息
* @param message
*/
@OnMessage
public void onMessage(String message){
log.info("【websocket消息】 收到客户端发来的消息:{}",message);
}
/**
* 发送消息
* @param message
*/
public void sendMessage(String message){
log.info("【websocket消息】 发送消息:{}",message);
for (WebSocket webSocket:webSocketSet){
try {
webSocket.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发送消息
* @param message
*/
public void sendMessage(Object message){
log.info("【websocket消息】 发送消息:{}",message);
for (WebSocket webSocket:webSocketSet){
try {
webSocket.session.getBasicRemote().sendObject(message);
} catch (IOException | EncodeException e) {
e.printStackTrace();
}
}
}
}
消息通知服务,接公司的短信接口
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@Service
public class MsgServiceImpl {
public void saveSWDataMethod(String context,String phone) {
Date date = new Date();
SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd");
try {
RestTemplate restTemplate = new RestTemplate();
String url = "http://****:8080/httpapi.action"+context+"&mobile="+phone+"&textCode=123";
Object responseData=restTemplate.getForObject(url, Object.class); //通过getForObject请求调用接口
} catch (RestClientException e) {
e.printStackTrace();
}
}
}
发送邮箱服务
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
/**
* @ClassName EmailUtil
* @Description 邮件发送工具
* @Author
* @Date 2022/4/6 16:06
*/
@Component
public class EmailUtil {
@Value("${spring.mail.from}") // 从application.yml配置文件中获取
private String from; // 发送发邮箱地址
@Autowired
private JavaMailSender mailSender;
/**
* 发送纯文本邮件信息
*
* @param to 接收方
* @param subject 邮件主题
* @param content 邮件内容(发送内容)
*/
public void sendMessage(String to, String subject, String content) {
// 创建一个邮件对象
SimpleMailMessage msg = new SimpleMailMessage();
msg.setFrom(from); // 设置发送发
msg.setTo(to); // 设置接收方
msg.setSubject(subject); // 设置邮件主题
msg.setText(content); // 设置邮件内容
// 发送邮件
mailSender.send(msg);
}
/**
* 发送带附件的邮件信息
*
* @param to 接收方
* @param subject 邮件主题
* @param content 邮件内容(发送内容)
* @param files 文件数组 // 可发送多个附件
*/
public void sendMessageCarryFiles(String to, String subject, String content, File[] files) {
MimeMessage mimeMessage = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
helper.setFrom(from); // 设置发送发
helper.setTo(to); // 设置接收方
helper.setSubject(subject); // 设置邮件主题
helper.setText(content); // 设置邮件内容
if (files != null && files.length > 0) { // 添加附件(多个)
for (File file : files) {
helper.addAttachment(file.getName(), file);
}
}
} catch (MessagingException e) {
e.printStackTrace();
}
// 发送邮件
mailSender.send(mimeMessage);
}
/**
* 发送带附件的邮件信息
*
* @param to 接收方
* @param subject 邮件主题
* @param content 邮件内容(发送内容)
* @param file 单个文件
*/
public void sendMessageCarryFile(String to, String subject, String content, File file) {
MimeMessage mimeMessage = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);
helper.setFrom(from); // 设置发送发
helper.setTo(to); // 设置接收方
helper.setSubject(subject); // 设置邮件主题
helper.setText(content); // 设置邮件内容
helper.addAttachment(file.getName(), file); // 单个附件
} catch (MessagingException e) {
e.printStackTrace();
}
// 发送邮件
mailSender.send(mimeMessage);
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
}