XNMS项目-业务数据按周分表的自动化生成与管理系统设计

文章目录

一、背景

XNMS(Extended Network Management System,增强型网络管理系统)是一款远程监控和管理常规中转台的软件。

中转台是系统的核心设备,所有业务都通过其进行中转。因此,只要对中转台进行监控,就能全面掌握系统的运行状况。而中转台通常部署室外,容易受到日晒雨淋等自然条件影响,造成设备损坏。为保证通讯系统正常运行,工作人员需要对中转台进行实时监控,发现中转台的异常问题,从而采取相关措施进行补救。

通过XNMS软件,工作人员可实时监控常规中转台的各项参数和告警情况,对异常问题进行排查;还可以查询或统计某时间段内中转台或终端的业务,从而全面了解常规系统的运行状况。

系统在初始化时,会自动为未来一年的业务数据按周创建独立的存储表。

二、页面


三、代码

ScheduledTaskController

java 复制代码
package com.xnms.client.service.controller.config;

import com.xnms.data.service.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import java.util.Calendar;
import java.util.Date;

@Controller
public class ScheduledTaskController {

    @Autowired
    private DateUtil dateUtil;

    // 定义任务,每年12月31日23:58执行
    @Scheduled(cron = "0 58 23 31 12 ?")
    public void executeTask() {

        Date nextYearFirstMoment = getNextYearFirstMoment();
        // 获取动态表名
        String tempTableName = DateUtil.convertStartTimeToTableName(nextYearFirstMoment);
        // 确保表已经存在,如果没有则创建
        dateUtil.createTableOrNot(tempTableName, nextYearFirstMoment);
    }

    // 获取明年1月1日0点0分10秒的时间
    public Date getNextYearFirstMoment() {
        // 获取当前时间
        Calendar calendar = Calendar.getInstance();

        // 获取明年年份
        int nextYear = calendar.get(Calendar.YEAR) + 1;

        // 设置为明年1月1日0点0分0秒
        calendar.set(nextYear, Calendar.JANUARY, 1, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        // 加10秒
        calendar.add(Calendar.SECOND, 10);

        // 返回计算后的时间
        return calendar.getTime();
    }
}

DateUtil

java 复制代码
package com.xnms.data.service.util;


import com.xnms.data.service.dao.SystemDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;


@Component
public class DateUtil {


    private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);

    private static final SimpleDateFormat YMDHMS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // Adjust format as needed

    // 假设你有 SystemDao 的实现
    @Autowired
    private SystemDao systemDao;

    /**
     * 计算业务表名
     * rptbizyearweek
     *
     * @param startTime 开始时间
     * @return 计算得到的表名
     */
    public static String convertStartTimeToTableName(Date startTime) {
        String tableName = "";
        try {
            // 使用 Calendar 获取年份和日历信息
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startTime);

            int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
            int num1 = dayOfYear / 7;
            int num2 = dayOfYear % 7;

            int week;
            if (num2 != 0) {
                week = num1 + 1;
            } else {
                week = num1;
            }

            // 获取年份
            int year = calendar.get(Calendar.YEAR);
            if (String.valueOf(week).length() == 1) {
                tableName = "rptbiz" + year + "0" + week;
            } else {
                tableName = "rptbiz" + year + week;
            }
        } catch (Exception ex) {
            logger.error("<convertStartTimeToTableName> " + ex.getMessage(), ex);
        }

        return tableName;
    }

    public static Date getPreviousWeekDate() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.WEEK_OF_YEAR, -1);
        return cal.getTime();
    }


    /**
     * 判断要写入数据的表是否存在,不存在则创建所在年份的所有的表
     *
     * @param tableName 要检查的表名
     * @param starttime 起始时间
     */
    public void createTableOrNot(String tableName, Date starttime) {
        // 判断要写入数据的表是否存在,不存在则创建所在年份的所有的表
        try {
            if (!systemDao.existTable(tableName)) {
                int year = getYear(starttime); // 获取年份

                List<String> tableNameList = new ArrayList<>();
                for (int j = 1; j <= 53; j++) { // 创建 1 到 53 周的表名
                    String week;
                    if (String.valueOf(j).length() == 1) {
                        week = "0" + j; // 如果周数是 1 位数,加一个前导零
                    } else {
                        week = String.valueOf(j); // 否则直接使用周数
                    }
                    String tempTableName = "rptbiz" + year + week; // 生成表名
                    tableNameList.add(tempTableName); // 将表名添加到列表中
                }
                systemDao.createTables(tableNameList); // 创建表
            }
        } catch (Exception ex) {
            logger.error("<createTableOrNot> " + ex.getMessage() +
                    (ex.getCause() != null ? "\r\n" + ex.getCause().getMessage() : ""), ex);
        }
    }

    // 获取年份的辅助方法
    private int getYear(Date date) {
        java.util.Calendar calendar = java.util.Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(java.util.Calendar.YEAR);
    }

    public static String addDaysToCurrentDate(int days) {
        return LocalDate.now().plusDays(days).toString(); // 返回 ISO 8601 格式的日期
    }

    public static String adjustEndTimeToLastMomentOfDay(Date endtime) {
        if (endtime == null) {
            return null;
        }

        // 将 endtime 转换为 Calendar 进行调整
        java.util.Calendar calendar = java.util.Calendar.getInstance();
        calendar.setTime(endtime);
        calendar.set(java.util.Calendar.HOUR_OF_DAY, 23);
        calendar.set(java.util.Calendar.MINUTE, 59);
        calendar.set(java.util.Calendar.SECOND, 59);
        calendar.set(java.util.Calendar.MILLISECOND, 999);
        return YMDHMS.format(calendar.getTime());
    }

    public static String adjustStartTimeToFirstMomentOfDay(Date starttime) {
        if (starttime == null) {
            return null;
        }

        // 将 starttime 转换为 Calendar 进行调整
        java.util.Calendar calendar = java.util.Calendar.getInstance();
        calendar.setTime(starttime);
        calendar.set(java.util.Calendar.HOUR_OF_DAY, 0);  // 设置为00小时
        calendar.set(java.util.Calendar.MINUTE, 0);      // 设置为00分钟
        calendar.set(java.util.Calendar.SECOND, 0);      // 设置为00秒
        calendar.set(java.util.Calendar.MILLISECOND, 0); // 设置为00毫秒
        return YMDHMS.format(calendar.getTime());
    }


//    public static void main(String[] args) {
//        Date startTime = new Date(); // 示例:当前日期
//        String tableName = convertStartTimeToTableName(startTime);
//        System.out.println("计算得到的表名: " + tableName);
//    }

}

SystemDaoImpl

java 复制代码
package com.xnms.data.service.dao.mysql.impl;

import com.xnms.data.contract.database.db.DbInfo;
import com.xnms.data.contract.database.db.InformationSchemaEntity;
import com.xnms.data.contract.database.db.QueryBackupDatabaseParams;
import com.xnms.data.contract.database.db.UserRoleData;
import com.xnms.data.service.dao.SystemDao;
import com.xnms.data.service.util.CommonUtil;
import com.xnms.data.service.util.DecryptionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;


@Repository
public class SystemDaoImpl implements SystemDao {

    private static final Logger logger = LoggerFactory.getLogger(SystemDaoImpl.class);

    @PersistenceContext
    private EntityManager entityManager;

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");

    //todo 获取数据名称的配置
    @Value("${xnms.data.service.DSDatabaseName}")
    private String databaseName;

@Override
    public boolean existTable(String tableName) {
        List<String> bizTableNameList = getBizTableNameList();
        return bizTableNameList.contains(tableName);
    }

    @Override
    public List<String> getBizTableNameList() {
        List<String> tableNameList = new ArrayList<>();
        // SQL 查询语句
        String sql = "SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_NAME LIKE :tableName AND TABLE_SCHEMA = :tableSchema ORDER BY TABLE_NAME";

        // 设置参数
        String tableNamePattern = String.format("rptbiz%s", "______");

        // 创建查询
        Query query = entityManager.createNativeQuery(sql);
        query.setParameter("tableName", tableNamePattern);
        query.setParameter("tableSchema", databaseName);

        try {
            tableNameList = query.getResultList();

        } catch (Exception ex) {
            // 日志记录错误
            logger.error("<SystemDao GetBizTableNameList> Error: {}, Sql: {}", ex.getMessage(), sql, ex);
        }

        return tableNameList;
    }

@Transactional
    @Override
    public void createTables(List<String> tableNameList) {
        try {

            // 遍历表名列表,为每个表构建 SQL
            for (String tableName : tableNameList) {
                String sql = String.format(
                        "CREATE TABLE %s (SERIAL_NO varchar(32), MODE INT(11), STATUS INT(11), TYPE INT(11), " +
                                "CALLTYPE INT(11), TARGETID INT(11), SENDERID INT(11), SLOT INT(11), RSSI INT(11), " +
                                "HANDSTATUS INT(11), STARTTIME DATETIME(3), ENDTIME DATETIME(3), DURATION BIGINT(20), " +
                                "EASTWEST varchar(10), NORTHSOUTH varchar(10), LAT DOUBLE DEFAULT 0, LNG DOUBLE DEFAULT 0, " +
                                "ELEVATION INT DEFAULT 0, CROSSSITE INT DEFAULT 1, RPTALIAS varchar(32)) " +
                                "ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;", tableName);

                // 执行创建表 SQL
                entityManager.createNativeQuery(sql).executeUpdate();

                // 创建索引
                String indexSql1 = String.format("CREATE INDEX INDEX_SN ON %s (SERIAL_NO);", tableName);
                String indexSql2 = String.format("CREATE INDEX INDEX_TARGETID ON %s (TARGETID);", tableName);
                String indexSql3 = String.format("CREATE INDEX INDEX_SENDERID ON %s (SENDERID);", tableName);
                String indexSql4 = String.format("CREATE INDEX INDEX_STARTTIME ON %s (STARTTIME);", tableName);
                String indexSql5 = String.format("CREATE INDEX INDEX_ENDTIME ON %s (ENDTIME);", tableName);
                String indexSql6 = String.format("CREATE INDEX IDX_SERIAL_START_END ON %s (SERIAL_NO, STARTTIME, ENDTIME);", tableName);
                String indexSql7 = String.format("CREATE INDEX INDEX_STARTTIME_LAT_LNG ON %s (STARTTIME,LAT,LNG);", tableName);
                String indexSql8 = String.format("CREATE INDEX INDEX_STARTTIME_SERIALNO_LAT_LNG ON %s (STARTTIME,SERIAL_NO,LAT,LNG);", tableName);

                // 执行创建索引的 SQL
                entityManager.createNativeQuery(indexSql1).executeUpdate();
                entityManager.createNativeQuery(indexSql2).executeUpdate();
                entityManager.createNativeQuery(indexSql3).executeUpdate();
                entityManager.createNativeQuery(indexSql4).executeUpdate();
                entityManager.createNativeQuery(indexSql5).executeUpdate();
                entityManager.createNativeQuery(indexSql6).executeUpdate();
                entityManager.createNativeQuery(indexSql7).executeUpdate();
                entityManager.createNativeQuery(indexSql8).executeUpdate();
            }

        } catch (Exception e) {

            e.printStackTrace();
        }
    }
}
java 复制代码
CREATE TABLE `rptbiz202604` (
  `SERIAL_NO` varchar(32) COLLATE utf8_bin DEFAULT NULL,
  `MODE` int(11) DEFAULT NULL,
  `STATUS` int(11) DEFAULT NULL,
  `TYPE` int(11) DEFAULT NULL,
  `CALLTYPE` int(11) DEFAULT NULL,
  `TARGETID` int(11) DEFAULT NULL,
  `SENDERID` int(11) DEFAULT NULL,
  `SLOT` int(11) DEFAULT NULL,
  `RSSI` int(11) DEFAULT NULL,
  `HANDSTATUS` int(11) DEFAULT NULL,
  `STARTTIME` datetime(3) DEFAULT NULL,
  `ENDTIME` datetime(3) DEFAULT NULL,
  `DURATION` bigint(20) DEFAULT NULL,
  `EASTWEST` varchar(10) COLLATE utf8_bin DEFAULT NULL,
  `NORTHSOUTH` varchar(10) COLLATE utf8_bin DEFAULT NULL,
  `LAT` double DEFAULT '0',
  `LNG` double DEFAULT '0',
  `ELEVATION` int(11) DEFAULT '0',
  `CROSSSITE` int(11) DEFAULT '1',
  `RPTALIAS` varchar(32) COLLATE utf8_bin DEFAULT NULL,
  KEY `INDEX_SN` (`SERIAL_NO`),
  KEY `INDEX_TARGETID` (`TARGETID`),
  KEY `INDEX_SENDERID` (`SENDERID`),
  KEY `INDEX_STARTTIME` (`STARTTIME`),
  KEY `INDEX_ENDTIME` (`ENDTIME`),
  KEY `IDX_SERIAL_START_END` (`SERIAL_NO`,`STARTTIME`,`ENDTIME`),
  KEY `INDEX_STARTTIME_LAT_LNG` (`STARTTIME`,`LAT`,`LNG`),
  KEY `INDEX_STARTTIME_SERIALNO_LAT_LNG` (`STARTTIME`,`SERIAL_NO`,`LAT`,`LNG`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

四、说明

说明点1:举例说明rptbiz202604表字段介绍

  • SERIAL_NO:序列号
  • MODE:分群或者全网【0:Normal: 全网模式、1:Selective: 分群模式】
  • STATUS:状态
    • 0x00:本地中转
    • 0x01:本地呼叫持续时间
    • 0x02:IP中转
    • 0x03:IP呼叫持续时间
    • 0x04:信道持续时间
    • 0x05:休眠
    • 0x06:远程PTT发射
    • 0x07:远程PTT持续时间
    • 0x08:远程PTT发射结束
    • 0x09:远程PTT等待回应
    • 0x0A:远程PTT TOT
    • 0x0B:本地PTT发射
    • 0x0C:本地PTT持续时间
    • 0x0D:本地PTT发射结束
    • 0x0E:本地PTT等待回应
    • 0x0F:本地 PTT TOT
    • 16:其他
  • TYPE:业务类型
    • 0: 'Query_HeaderTypeone', //None
    • 1: 'Query_HeaderTypeVoice', //语音
    • 2: 'Query_HeaderTypeTextMessage', //短消息
    • 3: 'Query_HeaderTypeGPS', //GPS(定位协议)
    • 4: 'Query_HeaderTypeRRS', //RRS(注册服务)
    • 5: 'Query_HeaderTypeTelemetry', //遥测
    • 6: 'Query_HeaderTypeSupplementary', //辅助业务
    • 7: 'Query_HeaderTypeE2E', //端到端数据
    • 31: 'Query_HeaderTypePhoneVoice', //电话语音业务
  • CALLTYPE:呼叫类型
    • 0: 'Query_HeaderPrivateCall', // 个呼
    • 1: 'Query_HeaderGroupCall', // 组呼
    • 2: 'Query_HeaderAllCall', // 全呼
    • 3: 'Query_HeaderEmergencyGroupCall', // 紧急组呼
    • 4: 'Query_HeaderRemoteMonitorCall', // 远程监听
    • 5: 'Query_HeaderEmergencyAlarmCall', // 紧急告警
    • 6: 'Query_HeaderPriorityPrivateCall', // 优先个呼
    • 7: 'Query_HeaderPriorityGroupCall', // 优先组合呼
    • 8: 'Query_HeaderPriorityAllCall', // 优先全呼
    • 11: 'Query_CallAlert', // 呼叫提示
    • 12: 'BusinessCallType_12', // 告警取消
    • 13: 'BusinessCallType_13', // 对讲机检查
    • 14: 'BusinessCallType_14', // 对讲机激活
    • 15: 'BusinessCallType_15', // 对讲机遥毙
    • 16: 'FULL_DUPLEX_CALL', // 双工呼叫
  • TARGETID:目的id
  • SENDERID:发送方id
  • SLOT:时隙信息
  • RSSI:场强值信息
  • HANDSTATUS:握手状态消息
  • STARTTIME:开始时间
  • ENDTIME:结束时间
  • DURATION:保持时间
  • EASTWEST:东西经
  • NORTHSOUTH:南北纬
  • LAT:纬度
  • LNG:经度
  • ELEVATION:海拔
  • CROSSSITE:跨域
  • RPTALIAS:别名

说明点2:业务表用于存储中转台和终端上报的所有业务数据,包括:语音、短消息、GPS(定位协议)、RRS(注册服务)、遥测、辅助业务、端到端数据、电话语音业务。

说明点3:OID协议文档定义



五、本人其他相关文章链接

相关推荐
奔跑吧邓邓子9 个月前
DeepSeek+Mermaid:轻松实现可视化图表自动化生成(附实战演练)
mermaid·可视化图表·自动化生成·deepseek
企鹅侠客1 年前
python实现自动化生成pdf报告
python·pdf·办公自动化·自动化生成·pdf教程