阶段三:项目开发---民航功能模块实现:任务24:航空实时监控
任务描述
内 容:地图展示、飞机飞行轨迹、扇区控制。航空实时监控,是飞机每秒发送坐标,经过终端转换实时发送给塔台,为了飞机位置的精准度,传输位置的密度很大,在地图位置显示不明显。本次为了案例展示效果,对飞机位置重新进行了规划,结合百度地图,和数据清洗,展示到前台。
学 时:6学时
知识点:后端文件处理
重 点:百度地图展示、飞机动态飞行、数据获取
任务指导
1、后台从文件名为part-xxxxx的文件中读取每行飞机坐标点传输到Kafka,Spark清洗任务拉取Kafka数据对数据进行清洗,对数据坐标进行判断转换成各扇区,发送到MySQL作为转换后的数据点,这一过程在前面的数据清洗和统计任务阶段已经完成,可参见:
- BigData-Etl-KongGuan/src/main/java/com/qrsoft/etl/spark/SparkUtil.java类
- BigData-Etl-KongGuan/src/main/java/com/qrsoft/etl/spark/SparkStreamingApplication.java类
2、前端经过读取后台MySQL的数据并结合百度地图,将飞机的实时飞行状态展示出来,可按以下步骤实现:
1)引入百度地图
2)地图上添加飞机
3)飞机动态修改
4)Vue中重新绑定值
3、后台逻辑实现(BigData-KongGuan)
1)编写后台逻辑,访问数据库,查询飞行实时数据
4、完成功能测试
下面图中是原企业项目的真实展示页面,在当前项目中由于数据集的特点,实际展示效果可能会有差异。
任务实现
1、从Kafka中读取飞机数据,并进行清洗
此步骤在前面的“使用Spark清洗统计业务数据并保存到数据库中”任务阶段应该已经完成。如果没有完成,请参考源代码自行完成。核心类主要有三个:SparkStreamingApplication类、SparkUtil类和MapManager类,以及一些辅助类。
- BigData-Etl-KongGuan/src/main/java/com/qrsoft/etl/spark/SparkStreamingApplication.java类的作用是实时读取Kafka中所有Topic的数据,然后进入到不同的处理分支程序中进行数据清洗和存储,处理“实时飞行的航迹数据”的分支的代码如下:
SparkUtil sparkUtil = new SparkUtil();
try {switch (topName) {case Constants.TASK_RADAR:sparkUtil.TaskRadarStr(taskRadar);break;
- 进入 Constants.TASK_RADAR 分支后,会调用SparkUtil类中的TaskRadarStr方法来处理数据,BigData-Etl-KongGuan/src/main/java/com/qrsoft/etl/spark/SparkUtil.java类中相关的核心代码如下:
/*** 业务处理* @param strs 航迹数据*/public void TaskRadarStr(String strs){System.out.println(strs);String[] str = strs.split(",");logger.info(str.toString());try {//判断是哪个扇区 sectionG sectionK sectionEString sectionVal = "";MapManager mapMan = new MapManager();double lat = Double.valueOf(str[8]);double lng = Double.valueOf(str[9]);if(mapMan.isInRectangleArea(lat,lng,sectionG[0],sectionG[1],sectionG[2],sectionG[3])){sectionVal = "G";}else if(mapMan.isInRectangleArea(lat,lng,sectionK[0],sectionK[1],sectionK[2],sectionK[3])){sectionVal = "K";}else if(mapMan.isInRectangleArea(lat,lng,sectionE[0],sectionE[1],sectionE[2],sectionE[3])){sectionVal = "E";};System.out.println("=========================================================");System.out.println("========================"+sectionVal+"=================================");System.out.println("=========================================================");MultiRadar mr = new MultiRadar();//MultiRadar mr = new MultiRadar(str[1],str[12],str[11],str[0],str[17],str[15],str[18],str[19],str[9],str[8],str[7],str[13],str[14],str[10],str[3],str[6],str[4],str[16],str[5],str[2],sectionVal);mr.setAcid(str[0]);mr.setAreaSource(str[1]);mr.setClimbordownSpeed(str[2]);mr.setDirection(str[3]);mr.setFcu(str[4]);mr.setFlyStatus(str[5]);mr.setRadarCFL(str[6]);mr.setRadarHeight(str[7]);mr.setRadarLatitude(str[8]);mr.setRadarLongTitude(str[9]);mr.setRadarSpeed(str[10]);mr.setRadarType(str[11]);mr.setSendRadarTime(str[12]);mr.setSpeedX(str[13]);mr.setSpeedY(str[14]);mr.setSsrCode(str[15]);mr.setTime(str[16]);mr.setTrackNumber(str[17]);mr.setZhiJiaoX(str[18]);mr.setZhiJiaoY(str[19]);mr.setSection(sectionVal);//根据航班号,查询是否已经开始对该航迹进行统计MultiRadarDao dao = new MultiRadarDao();boolean bool = dao.isExistThisRadar(mr.getAcid());if(bool) {//存在,修改数据库中该航迹dao.updateAnRadarMsg(mr);}else{//尚未进行统计 创建一个统计信息dao.createAnRadarMsg(mr);}}catch (Exception e){e.printStackTrace();logger.info(" MultiRadar错误数据: [{}]", strs);}}
- 在处理“实时飞行的航迹数据”时,会使用到一个辅助类MapManager,该类的功能包括:判断飞机是否在指定的矩形区域内、判断飞机是否在指定的经纬度范围内,核心代码如下:
public class MapManager {/*** 是否在矩形区域内* * @param lat 测试点经度* @param lng 测试点纬度* @param minLat 纬度范围限制1* @param maxLat 纬度范围限制2* @param minLng 经度限制范围1* @param maxLng 经度范围限制2*/public boolean isInRectangleArea(double lat,double lng,double minLat, double maxLat,double minLng,double maxLng){if(this.isInRange(lat, minLat, maxLat)){//如果在纬度的范围内if(minLng*maxLng>0){if(this.isInRange(lng, minLng, maxLng)){return true;}else {return false;}}else {if(Math.abs(minLng)+Math.abs(maxLng)<180){if(this.isInRange(lng, minLng, maxLng)){return true;}else {return false;}}else{double left = Math.max(minLng, maxLng);double right = Math.min(minLng, maxLng);if(this.isInRange(lng, left, 180)||this.isInRange(lng, right,-180)){return true;}else {return false;}}}}else{return false;}}/*** 判断是否在经纬度范围内* * @param point* @param left* @param right*/public boolean isInRange(double point, double left,double right){if(point>=Math.min(left, right)&&point<=Math.max(left, right)){return true;}else {return false;}}
}
- 其他辅助类,请参考源代码。
2、打开前端Vue项目kongguan_web,完成前端Vue页面(src/views/Home/Map.vue)设计
- 在Vue页面 src/views/Home/Map.vue 中引入百度地图,首先添加百度地图背景图,并在地图上飞机,飞机相当于在地图上添加mark点
其中bm-marker是飞机,bm-label是飞机旁边显示的标签,通过v-for标签循环绑定数据, 例如:v-for="item in caseList",caseList是在下边的数据获取步骤中赋值的。
<template><div style="height: 100%"><baidu-map :center="center" :zoom="zoom" style="height:100%" @click="getClickInfo":scroll-wheel-zoom='true' :map-style="mapStyle"><bm-marker v-for="item in caseList" :key="item.id":position="{lng: item.radarLongtitude, lat: item.radarLatitude}" :rotation="Number(item.direction)":icon="{url: urlz(item.id), size: {width: 100, height: 75}}"><bm-label :position="{lng: item.radarLongtitude, lat: item.radarLatitude}":content="item.acid":labelStyle="{color: 'gray', fontSize : '8px',backgroundColor: 'rgba(0,0,0,0)',border:0}"title="Hover me"/></bm-marker><!-- 缩放控件,注册此组件才会显示拖放进度 --><bm-navigation anchor="BMAP_ANCHOR_TOP_LEFT"></bm-navigation></baidu-map>
... 接下文 ...
- 在Vue页面中添加扇区管理的页面设计:
页面中包含"G"、"K"、"E"三个扇区的按钮,并绑定了click事件,当点击其中任意一个扇区对应的按钮时会触发click事件,执行clickData方法,clickData方法在后面的步骤中定义,主要是根据传入的不同的参数("G"、"K"、"E"),获取不同扇区的数据。
... 接上文 ...<div class="allStatistics box"><img src="../../assets/images/nl.png" width="45px" height="45px" style="position: absolute;right: 90px;top: 75px"><img src="../../assets/images/gj.png" width="45px" height="45px"style="position: absolute ;right: 290px;top: 70px"><div style=" margin-left: 70px;margin-top: 12px"><div>当前时间:{{new Date().getFullYear()}}-{{new Date().getMonth()}}-{{new Date().getDate()}}  {{newDate().getHours()}}:{{new Date().getMinutes()}}:{{new Date().getSeconds()}}</div><div style="margin-left: -17px">当前位置:{{this.center.lng}} {{this.center.lat}}</div></div><div style=" font-weight: bold;position: absolute;top: 145px;left: 45px"><span style="color: #2a58f4">轨迹数:</span><span style="color: #2a58f4">{{count}}</span><span style="color: #f17140;margin-left: 52px">告警数:</span><span style="color: #f17140">{{count1}}</span></div></div><div class="sectors1 box"><div class="title">当前用户: <span class="npc">管理员 G</span></div><div ><el-button :type="isActive==='G'?'success':'primary'" style="margin-left: 16px" @click="clickData('G')">G</el-button><el-button :type="isActive==='K'?'success':'primary'" :class="isActive === 2?'active':''"@click="clickData('K')">k</el-button><el-button :type="isActive==='E'?'success':'primary'" :class="isActive === 3?'active':''"@click="clickData('E')">E</el-button></div></div><div class="sectors2 box"><div class="title">扇区状态栏</div><div><el-button :type="isActive==='G'?'success':'primary'" style="margin-left: 16px" @click="clickData('G')">G</el-button><el-button :type="isActive==='K'?'success':'primary'" :class="isActive === 2?'active':''"@click="clickData('K')">k</el-button><el-button :type="isActive==='E'?'success':'primary'" :class="isActive === 3?'active':''"@click="clickData('E')">E</el-button></div></div><div class="simi_box box"><div class="similarity"><el-tag effect="dark"><span class="tag-group__title" style="">相似航班数提醒</span></el-tag><div v-for="(it,index) in atcList" :key="index" style="height: 45px; font-weight: bold;"><spanstyle="margin-left: 25px">{{it.gjSector}}</span><spanstyle="margin-left: 45px">{{it.gj}}</span></div></div><div class="similarity"><el-tag effect="dark"><span class="tag-group__title" style="">管制指令纠错</span></el-tag><div v-for="(it,index) in warnList" :key="index"><div style="height: 45px;text-align: center"><spanstyle="width: 100%; font-weight: bold;">{{it.gj_acids}}</span></div><div style="height: 45px;text-align: center;"><table style="height: 45px"><tr><td style="width: 150px; border: #2a58f4 3px solid; border-left: none">{{it.gj_name}}</td><td style="width: 83px; border: #2a58f4 3px solid">{{it.gj_track_num1}}</td><td style="width: 83px; border: #2a58f4 3px solid">{{it.gj_track_num2}}</td><td style="width: 83px; border: #2a58f4 3px solid; border-right: none">{{it.gj_distinct}}</td></tr></table></div></div></div></div></div>
</template>
- 导入访问服务端的api路由
<script>import {findLocusCount,findMultRadar,findWarnSimilarOfATC,findWarnSimilarOfATCCount,findWarnTp} from "@/api/map/map";
... 接下文 ...
- 初始化数据,在地图上设置一个初始点,并设置样式
... 接上文 ...export default {name: 'TestBaiDu',data() {return {center: {lng: 118.78995, lat: 36.62934},zoom: 8,url1: require("../../assets/images/fj.png"),url2: require("../../assets/images/hfj.png"),markerPoint: {lng: 116.404, lat: 39.915},caseList: [],warnList: [],atcList: [],count: 1,count1: 1,isActive: 'G',mapStyle: {styleJson: [{"featureType": "water","elementType": "all","stylers": {"color": "#285ea5"}},{"featureType": "land","elementType": "all","stylers": {"color": "#0c3c7f"}},{"featureType": "road","elementType": "all","stylers": {"visibility": "off"}},{"featureType": "point","elementType": "all","stylers": {"visibility": "off"}},{"featureType": "all","elementType": "labels.text.fill","stylers": {"color": "#2da0c6","visibility": "off"}}]},timer: null,}},
... 接下文 ...
- 获取数据
其中loadData方法是用来获取实时飞行数据,loadWarn方法是获取告警信息,clickData方法是响应扇区按钮的点击事件,查询不同扇区对应的数据。
... 接上文 ...mounted() {this.loadWarn();this.loadData();this.clickData();this.timeOut();},beforeDestroy() { //页面关闭时清除定时器 window.clearInterval(this.timer);this.timer = null;},destroyed() {window.clearInterval(this.timer);this.timer = null; },methods: {urlz(data){for(let i=0;i<this.warnList.length;i++){var value1 = this.warnList[i].gj_track_num1;var value2 = this.warnList[i].gj_track_num2;if(value1 == data || value2 == data){return this.url2;}}return this.url1;},getClickInfo(e) {this.center.lng = e.point.lngthis.center.lat = e.point.lat},loadData() {findMultRadar().then(data => {if (data.isSuccess) {this.caseList = data.result;this.caseList.forEach(it => {it.count = it.areaSource + "," + it.trackNumber})} else {this.$message.error("数据获取失败");}})},loadWarn(){findWarnTp().then(data => {if (data.isSuccess) {this.warnList = data.result;} else {this.warnList.error("数据获取失败");}})},clickData(data) {if (data == null) {this.isActive = 'G'data = 'G'} else {this.isActive = data}findLocusCount(data).then(data => {if (data.isSuccess) {this.count = data.result;} else {this.warnList.error("数据获取失败");}}),findWarnSimilarOfATC(data).then(data => {if (data.isSuccess) {this.atcList = data.result;} else {this.atcList.error("数据获取失败");}}),findWarnSimilarOfATCCount(data).then(data => {if (data.isSuccess) {this.count1 = data.result;} else {this.count1.error("数据获取失败");}})},
... 接下文 ...
- 创建一个定时器,定时获取数据,以更新飞机的位置
... 接上文 ...timeOut(){// 需要在一开始就先调用一遍该方法,否则在开始的5s内是没有数据的 if (this.timer) {window.clearInterval(this.timer)} else {this.timer = window.setInterval(() => {this.loadData();}, 9000)}},}}
</script>
... 接下文 ...
- 页面样式
... 接上文 ...
<style>.sectors1 { top: 20px; right: 450px; background: #fff; width: 220px; height: 80px; margin-top: 30px; }.sectors2 { top: 20px; right: 690px; background: #fff; width: 220px; height: 80px; margin-top: 30px; }.box { position: absolute; margin-top: 70px; }.allStatistics { background: #fff; width: 400px; height: 200px; top: 60px; right: 20px; margin-top: 30px; }.similarity { background: #fff; overflow: hidden; border-radius: 5px 5px 0 0; margin-bottom: 20px; }.simi_box { top: 300px; right: 20px; width: 400px; height: 400px; margin-top: 18px; }.npc { color: #2a58f4; }.title { color: #575757; text-align: center; font-weight: bold; }.active { background-color: #00b700; }.el-button { height: 25px; }.el-tag { width: 400px; border-radius: 0px; }.common-right{ padding-top: 60px; padding-right: 0; padding-left: 0; }
</style>
- 在src/api/目录下创建map目录,然后创建api路由文件 src/api/map/map.js,用于访问服务端相应的Controller(主要是通过findMultRadar()方法“查询综合航迹数据”并显示航迹图,还会涉及到“管制指令纠错”、“根据扇区名称获取该扇区航班数”、“根据扇区号查询相似航班”、“根据扇区号查询相似航班告警总数”等数据的展示)
import request from "../../utils/request";//综合航迹数据查询相关的服务器端请求的根路径
const baseUrl="/api/multiRadar"
//年度统计查询相关的服务器端请求的根路径
const warUrl ="/api/warnFlightHistory"
//航班告警查询相关的服务器端请求的根路径
const warSimUrl = "/api/warnSimilarHistory"
//扇区操作查询相关的服务器端请求的根路径
const atcUrl = "/api/atc"//查询综合航迹数据
export function findMultRadar(){return request({url:baseUrl+"/findMultRadar",method: "get",})
}
//管制指令纠错
export function findWarnTp(){return request({url:warUrl+"/findWarnTp",method: "get",})
}
//根据扇区名称获取该扇区航班数
export function findLocusCount(data){return request({url:atcUrl+"/findLocusCount?planSectorName="+data,method: "get",})
}
//根据扇区号查询相似航班
export function findWarnSimilarOfATC(data){return request({url:warSimUrl+"/findWarnSimilarOfATC?sectorName="+data,method: "get",})
}
//根据扇区号查询相似航班告警总数
export function findWarnSimilarOfATCCount(data){return request({url:warSimUrl+"/findWarnSimilarOfATCCount?sectorName="+data,method: "get",})
}
- 修改 src/router/index.js 路由文件,添加Map.vue页面的路由跳转
... 略 ...{path: '/',component: Layout,redirect: '/map',children: [{path: 'map',component: resolve => require(['@/views/Home/Map'], resolve),name: 'map',meta: { title: 'map' }}]},
... 略 ...
- src/router/index.js文件的完整内容如下:
import Vue from 'vue'
import Router from 'vue-router'const originalPush = Router.prototype.push;
Router.prototype.push = function push(location) {return originalPush.call(this, location).catch(err => err)
}Vue.use(Router)
/* Layout */
import Layout from '@/views/Layout/Layout'
const router = new Router({base: process.env.BASE_URL,mode: 'history',routes: [{path: "/login",component: resolve => require(['@/views/Login/Login'], resolve),hidden: true,meta: {auth: true}},{path: '/',component: Layout,redirect: '/home',children: [{path: 'home',component: resolve => require(['@/views/Home/Index'], resolve),name: 'home',meta: { title: 'home' }}]},{path: '/',component: Layout,redirect: '/map',children: [{path: 'map',component: resolve => require(['@/views/Home/Map'], resolve),name: 'map',meta: { title: 'map' }}]},]
})// 导航守卫
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
router.beforeEach((to, from, next) => {if (to.path === '/login') {next();} else {let token = localStorage.getItem('Authorization');if (token === null || token === '') {next('/login');} else {next();}}
});
export default router
- 确保 src/App.vue 文件的内容如下:
<template><div id="app"><router-view/></div>
</template><script>
export default {name: 'App',
}
</script><style>
html,body,#app{height: 100%;
}
</style>
3、打开后端项目BigData-KongGuan,完成后台逻辑实现
- 编写以下Controller类,来处理客户端发送过来的请求,涉及以下几个类:
类/接口 | 作用 |
---|---|
com.qrsoft.controller.AtcController | 扇区操作类:处理客户端的 /api/atc 相关的扇区操作请求 |
com.qrsoft.controller.MultiRadarController | 综合航迹数据:处理客户端的 /api/multiRadar 相关的综合航迹数据查询请求 |
com.qrsoft.controller.WarnFlightHistoryController | 年度告警统计:处理客户端的 /api/warnFlightHistory 相关的年度统计查询请求 |
com.qrsoft.controller.WarnSimilarHistoryController | 航班告警:处理客户端的 /api/warnSimilarHistory 相关的航班告警查询请求 |
1)在com.qrsoft.controller.AtcController类中主要调用其中的 findLocusCount() 方法,用于根据扇区名称获取该扇区航班数。
/**
* 根据扇区名称获取该扇区航班数
*/
@ApiOperation(value = "根据扇区名称获取该扇区航班数")
@GetMapping("/findLocusCount")
public Result findLocusCount(@RequestParam String planSectorName){return service.findLocusCount(planSectorName);
}
AtcController类的完整内容如下:
@Api(tags = "扇区操作类")
@RestController
@RequestMapping("/api/atc")
public class AtcController {@Autowiredprivate AtcService service;/*** 获取各扇区航班数*/@ApiOperation(value = "获取各扇区航班数")@GetMapping("/findSectorSortie")public Result findSectorSortie(){return service.findSectorSortie();}/*** 根据扇区名称获取该扇区航班数*/@ApiOperation(value = "根据扇区名称获取该扇区航班数")@GetMapping("/findLocusCount")public Result findLocusCount(@RequestParam String planSectorName){return service.findLocusCount(planSectorName);}/*** 扇区架次数动态统计(饼状图)*/@ApiOperation(value = "扇区架次数动态统计(饼状图)")@GetMapping("/findATCTime")public Result findATCTime(){return service.findATCTime();}
}
2)在com.qrsoft.controller.MultiRadarController类中主要调用findMultRadar()方法,用于综合航迹数据查询,MultiRadarController类的内容如下:
@Api(tags = "综合航迹数据")
@RestController
@RequestMapping("/api/multiRadar")
public class MultiRadarController {@Autowiredprivate MultiRadarService service;/*** 查询综合航迹数据*/@GetMapping("/findMultRadar")public Result findMultRadar(){return service.findMultRadar();}
}
3)在com.qrsoft.controller.WarnFlightHistoryController类中主要调用 findWarnTp() 方法,用于查询“管制指令纠错”的数据。
/*** 管制指令纠错*/
@ApiOperation(value = "管制指令纠错")
@GetMapping("/findWarnTp")
public Result findWarnTp(){return service.findWarnTp();
}
WarnFlightHistoryController类的完整内容如下:
@Api(tags = "年度统计")
@RestController
@RequestMapping("/api/warnFlightHistory")
public class WarnFlightHistoryController {@Autowiredprivate WarnFlightHistoryService service;/*** 年度警告分类统计*/@ApiOperation(value = "年度警告分类统计")@GetMapping("/annualWarningStatisticsByCategory")public Result annualWarningStatisticsByCategory(){return service.annualWarningStatisticsByCategory();}/*** 年度警告区域统计*/@ApiOperation(value = "年度警告区域统计")@GetMapping("/annualWarningAreaStatistics")public Result annualWarningAreaStatistics(){return service.annualWarningAreaStatistics();}/*** 管制指令纠错*/@ApiOperation(value = "管制指令纠错")@GetMapping("/findWarnTp")public Result findWarnTp(){return service.findWarnTp();}
}
4)创建com.qrsoft.controller.WarnSimilarHistoryController类,在类中主要调用findWarnSimilarOfATC()和findWarnSimilarOfATCCount()方法,用于“根据扇区号查询相似航班告警”和“根据扇区号查询相似航班告警总数”。
/**
* 根据扇区号查询相似航班告警
*/
@ApiOperation(value = "根据扇区号查询相似航班")
@GetMapping("/findWarnSimilarOfATC")
public Result findWarnSimilarOfATC(@RequestParam String sectorName){return service.findWarnSimilarOfATC(sectorName);
}
/**
* 根据扇区号查询相似航班告警总数
*/
@ApiOperation(value = "根据扇区号查询相似航班告警总数")
@GetMapping("/findWarnSimilarOfATCCount")
public Result findWarnSimilarOfATCCount(@RequestParam String sectorName){return service.findWarnSimilarOfATCCount(sectorName);
}
WarnSimilarHistoryController类的完整代码如下:
package com.qrsoft.controller;import com.qrsoft.common.Result;
import com.qrsoft.service.WarnSimilarHistoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@Api(tags = "航班告警")
@RestController
@RequestMapping("/api/warnSimilarHistory")
public class WarnSimilarHistoryController {@Autowiredprivate WarnSimilarHistoryService service;/*** 查询相似航班告警*/@ApiOperation(value = "查询相似航班告警")@GetMapping("/findWarnSimilarHistory")public Result findWarnSimilarHistory(){return service.findWarnSimilarHistory();}/*** 根据扇区号查询相似航班告警*/@ApiOperation(value = "根据扇区号查询相似航班")@GetMapping("/findWarnSimilarOfATC")public Result findWarnSimilarOfATC(@RequestParam String sectorName){return service.findWarnSimilarOfATC(sectorName);}/*** 根据扇区号查询相似航班告警总数*/@ApiOperation(value = "根据扇区号查询相似航班告警总数")@GetMapping("/findWarnSimilarOfATCCount")public Result findWarnSimilarOfATCCount(@RequestParam String sectorName){return service.findWarnSimilarOfATCCount(sectorName);}
}
- 编写以下Controller对应的Service类,包括以下几个类:
类/接口 | 作用 |
---|---|
com.qrsoft.service.AtcService | 扇区操作的业务模块处理类 |
com.qrsoft.service.MultiRadarService | 综合航迹数据查询的业务模块处理类 |
com.qrsoft.service.WarnFlightHistoryService | 年度告警数据查询的业务模块处理类 |
com.qrsoft.service.WarnSimilarHistoryService | 航班告警数据查询的业务模块处理类 |
1)com.qrsoft.service.AtcService类的内容如下:
@Service
public class AtcService extends ServiceImpl<AtcMapper, Atc> {@Autowiredprivate MultiRadarService multiRadarService;/*** 查询所有扇区航班架次*/public Result findSectorSortie() {List<Atc> sectorSortie = baseMapper.findSectorSortie();return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS, sectorSortie);}/*** 根据扇区号查询架次*/public Result findLocusCount(String planSectorName) {QueryWrapper<MultiRadar> queryWrapper = new QueryWrapper<>();queryWrapper.eq("section",planSectorName);int count = multiRadarService.count(queryWrapper);return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS, count);}/*** 扇区架次数动态统计(饼状图)*/public Result findATCTime() {List<String> sectorName = new ArrayList<>();sectorName.add("K");sectorName.add("S");sectorName.add("E");sectorName.add("P");sectorName.add("G");List<String> executeTime = baseMapper.findATCTime();List list = new ArrayList();for (int i = 0; executeTime.size() > i; i++) {ArrayList<Object> objects = new ArrayList<>();for (int j = 0; sectorName.size() > j; j++) {Atc atcTime2 = baseMapper.findATCTime2(executeTime.get(i), sectorName.get(j));HashMap<String, Object> map = new HashMap<>();if (atcTime2.getPlanSectorName() != null) {map.put(atcTime2.getPlanSectorName(), atcTime2.getCount());}else {map.put(sectorName.get(j),0);}objects.add(map);}list.add(objects);}return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS, list);}
}
2)创建com.qrsoft.service.MultiRadarService类,类中包含一个findMultRadar()方法,用于查询综合航迹数据,内容如下:
package com.qrsoft.service;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qrsoft.common.Result;
import com.qrsoft.common.ResultConstants;
import com.qrsoft.entity.MultiRadar;
import com.qrsoft.mapper.MultiRadarMapper;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class MultiRadarService extends ServiceImpl<MultiRadarMapper, MultiRadar> {/*** 查询综合航迹数据*/public Result findMultRadar(){List<MultiRadar> multiRadars = baseMapper.selectList(null);return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS,multiRadars);}
}
3)com.qrsoft.service.WarnFlightHistoryService类的内容如下:
@Service
public class WarnFlightHistoryService extends ServiceImpl<WarnFlightHistoryMapper, WarnFlightHistory> {/*** 年度警告区域统计*/public Result annualWarningAreaStatistics(){List<WarnFlightHistory> warnFlightHistories = baseMapper.annualWarningAreaStatistics();return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS,warnFlightHistories);}/*** 年度警告分类统计*/public Result annualWarningStatisticsByCategory(){List<WarnFlightHistory> warnFlightHistories = baseMapper.annualWarningStatisticsByCategory();return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS,warnFlightHistories);}/*** 管制指令纠错*/public Result findWarnTp(){List<HashMap<String, Object>> result = new ArrayList<>();List<HashMap<String, Object>> warnTp = baseMapper.findWarnTp();for (HashMap<String,Object> hm :warnTp){String gj_acids = (String)hm.get("gj_acids");String[] split = gj_acids.split("-");System.out.println(split.length);if(split.length>=2) {Integer warn = baseMapper.getWarn(split[0], split[1]);if(warn >=2){result.add(hm);}}}return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS,result);}
}
4)创建com.qrsoft.service.WarnSimilarHistoryService类,内容如下:
package com.qrsoft.service;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qrsoft.common.Result;
import com.qrsoft.common.ResultConstants;
import com.qrsoft.entity.MultiRadar;
import com.qrsoft.entity.WarnSimilarHistory;
import com.qrsoft.mapper.MultiRadarMapper;
import com.qrsoft.mapper.WarnSimilarHistoryMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Service
public class WarnSimilarHistoryService extends ServiceImpl<WarnSimilarHistoryMapper, WarnSimilarHistory> {@Autowiredprivate MultiRadarMapper multiRadarMapper;/*** 查询相似航班告警*/public Result findWarnSimilarHistory(){List<WarnSimilarHistory> warnSimilarHistory = baseMapper.findWarnSimilarHistory();return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS,warnSimilarHistory);}/*** 根据扇区号查询相似航班*/public Result findWarnSimilarOfATC(String sectorName){QueryWrapper<MultiRadar> queryWrapper = new QueryWrapper<>();queryWrapper.eq("section",sectorName);List<MultiRadar> list = multiRadarMapper.selectList(queryWrapper);List<Map<String,String>> result = new ArrayList<>();System.out.println(list);for(MultiRadar m1 :list){for(MultiRadar m2:list){String acid1 = m1.getAcid();String substring = acid1.substring(0,3);String acid2 = m2.getAcid();if(acid2.startsWith(substring)){if(acid1.equals(acid2)){break;}HashMap<String, String> res = new HashMap<>();res.put("gj", acid1 + "-" + acid2);res.put("gjSector",sectorName);result.add(res);break;}}}return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS,result);}/*** 查询航班数量*/public Result findWarnSimilarOfATCCount(String sectorName){Result warnSimilarOfATC = this.findWarnSimilarOfATC(sectorName);Object result = warnSimilarOfATC.getResult();List<?> result1 = (List<?>) result;int size = result1.size();return new Result(ResultConstants.SUCCESS, ResultConstants.C_SUCCESS,size);}
}
- 编写对应的Mapper数据访问类,包括以下几个类:
类/接口 | 作用 |
---|---|
com.qrsoft.mapper.AtcMapper | 扇区操作的数据访问类 |
com.qrsoft.mapper.MultiRadarMapper | 综合航迹数据查询的数据访问类 |
com.qrsoft.mapper.WarnFlightHistoryMapper | 年度告警数据查询的数据访问类 |
com.qrsoft.mapper.WarnSimilarHistoryMapper | 航班告警数据查询的数据访问类 |
1)com.qrsoft.mapper.AtcMapper类的内容如下:
@Mapper
public interface AtcMapper extends BaseMapper<Atc> {@Select("select PLAN_SECTOR_NAME,COUNT(*) as count from atc_number GROUP BY PLAN_SECTOR_NAME;")List<Atc> findSectorSortie();@Select("select EXECUTE_DATE from atc_number group by EXECUTE_DATE order by EXECUTE_DATE desc limit 19;")List<String> findATCTime();@Select("select PLAN_SECTOR_NAME,count(*) as count from atc_number where EXECUTE_DATE = #{executeTime} and PLAN_SECTOR_NAME = #{sectorName}")Atc findATCTime2(String executeTime,String sectorName);
}
2)com.qrsoft.mapper.MultiRadarMapper类的内容如下:
@Mapper
public interface MultiRadarMapper extends BaseMapper<MultiRadar> {}
3)com.qrsoft.mapper.WarnFlightHistoryMapper类的内容如下:
@Mapper
public interface WarnFlightHistoryMapper extends BaseMapper<WarnFlightHistory> {@Select("SELECT gj_sector,COUNT(*) as gjCount FROM warnflighthistory_number GROUP BY gj_sector ORDER BY sum(count) desc LIMIT 11;")List<WarnFlightHistory> annualWarningAreaStatistics();@Select("select gj_name,count(*) as gjCount from warnflighthistory_number group by gj_name;")List<WarnFlightHistory> annualWarningStatisticsByCategory();@Select("select gj_type,gj_id,gj_msg_type,gj_track_num1,gj_track_num2,gj_distinct,gj_radian,gj_name,gj_distinct_bz,gj_city,gj_date,gj_acids,gj_num1_long,gj_num1_lat,gj_num2_long,gj_num2_lat from warntp_number;")List<HashMap<String,Object>> findWarnTp();@Select("select count(*) from multiradar_number where `ACID` IN (#{acid},#{bcid});")Integer getWarn(@Param("acid") String acid, @Param("bcid") String bcid);
}
4)创建com.qrsoft.mapper.WarnSimilarHistoryMapper类,内容如下:
package com.qrsoft.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qrsoft.entity.WarnSimilarHistory;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface WarnSimilarHistoryMapper extends BaseMapper<WarnSimilarHistory> {@Select("SELECT gj_sector,gj_acid FROM warnsimilarhistory_number ORDER BY id DESC LIMIT 4;")List<WarnSimilarHistory> findWarnSimilarHistory();@Select("SELECT gj_sector,gj_acid FROM warnsimilarhistory_number where gj_sector = #{sectorName} ORDER BY id DESC LIMIT 4;")List<WarnSimilarHistory> findWarnSimilarOfATC(@Param("sectorName") String sectorName);
}
- 涉及的数据实体类包括(在前面的任务中已经创建过,此处只需确认一下是否存在):
类/接口 | 作用 |
---|---|
com.qrsoft.entity.Atc | 扇区对应的实体类 |
com.qrsoft.entity.MultiRadar | 雷达对应的实体类 |
com.qrsoft.entity.WarnFlightHistory | 年度告警飞行历史记录对应的实体类 |
com.qrsoft.entity.WarnSimilarHistory | 航班告警历史记录对应的实体类 |
com.qrsoft.entity.Company | 航空公司信息表对应的实体类 |
com.qrsoft.common.Result | 返回结果类 |
com.qrsoft.common.ResultConstants | 返回常量结果类 |
1)需要创建com.qrsoft.entity.WarnSimilarHistory类,用于航班告警历史记录对应的实体类,内容如下:
package com.qrsoft.entity;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("warnsimilarhistory_number")
public class WarnSimilarHistory implements Serializable {private Integer id;@TableField(value = "gj_type")private String gjType;@TableField(value = "gj_id")private String gjDd;@TableField(value = "gj_msg_type")private String gjMsgType;@TableField(value = "gj_num")private String gjNum;@TableField(value = "gj_track_num")private String gjTrackNum;@TableField(value = "gj_sector")private String gjSector;@TableField(value = "gj_acid")private String gjAcid;@TableField(value = "gj_status")private String gjStatus;@TableField(value = "gj_city")private String gjCity;@TableField(value = "gj_date")private String gjDate;@TableField(value = "count")private Integer count;}
2)其他实体类在前面的任务中已经创建,这里不需要重复创建。
4、功能测试
- 启动后端程序:BigData-KongGuan
- 启动后端程序:BigData-Etl-KongGuan
- 启动前端程序
- 页面显示效果(下面图中是原企业项目的真实展示页面,在当前项目中由于数据集的特点,实际展示效果可能会有差异)
相关文章:
阶段三:项目开发---民航功能模块实现:任务24:航空实时监控
任务描述 内 容:地图展示、飞机飞行轨迹、扇区控制。航空实时监控,是飞机每秒发送坐标,经过终端转换实时发送给塔台,为了飞机位置的精准度,传输位置的密度很大,在地图位置显示不明显。本次为了案例展示效…...
手机容器化 安装docker
旧手机-基于Termux容器化 1、安装app 在手机上安装Termux或ZeroTermux(Termux扩展) 1.1 切换源 注:可以将termux进行换源,最好采用国内源,例如:清华源等 更新包列表和升级包(可选࿰…...
科普文:深入理解Mybatis
概叙 (1) JDBC JDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成.JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。 优点…...
称重传感器有哪些种类
有关称重传感器的知识,称重传感器是众多传感器产品中的一种,也是很常用的传感器之一,那么称重传感器有哪些种类,称重传感器的分类方式是什么样的,一起来了解下。 称重传感器的分类 主要有六种称重传感器类型…...
程序员鱼皮的保姆级写简历指南第四弹,优秀简历参考
大家好,我是程序员鱼皮。做知识分享这些年来,我看过太多简历、也帮忙修改过很多的简历,发现很多同学是完全不会写简历的、会犯很多常见的问题,不能把自己的优势充分展示出来,导致措施了很多面试机会,实在是…...
UML建模案例分析-时序图和类图的对应关系
概念 简单地说,类图定义了系统中的对象,时序图定义了对象之间的交互。 例子 一个电子商务系统,会员可通过电子商务系统购买零件。具体功能需求如下: 会员请求结账时,系统验证会员的账户是否处于登录状态࿱…...
Java版Flink使用指南——从RabbitMQ中队列中接入消息流
大纲 创建RabbitMQ队列新建工程新增依赖编码设置数据源配置读取、处理数据完整代码 打包、上传和运行任务测试 工程代码 在《Java版Flink使用指南——安装Flink和使用IntelliJ制作任务包》一文中,我们完成了第一个小型Demo的编写。例子中的数据是代码预先指定的。而…...
Python酷库之旅-第三方库Pandas(013)
目录 一、用法精讲 31、pandas.read_feather函数 31-1、语法 31-2、参数 31-3、功能 31-4、返回值 31-5、说明 31-6、用法 31-6-1、数据准备 31-6-2、代码示例 31-6-3、结果输出 32、pandas.DataFrame.to_feather函数 32-1、语法 32-2、参数 32-3、功能 32-4、…...
Linux 高级 Shell 脚本编程:掌握 Shell 脚本精髓,提升工作效率
【Linux】 高级 Shell 脚本编程:掌握 Shell 脚本精髓,提升工作效率 Shell 脚本编程是 Linux 系统管理员和开发人员的必备技能。通过学习高级 Shell 脚本编程,你可以编写更高效、更灵活和更易于维护的脚本。本文将介绍 Shell 脚本编程中的函数…...
【ARMv8/v9 GIC 系列 1.5 -- Enabling the distribution of interrupts】
请阅读【ARM GICv3/v4 实战学习 】 文章目录 Enabling the distribution of interruptsGIC Distributor 中断组分发控制CPU Interface 中断组分发控制Physical LPIs 的启用Summary Enabling the distribution of interrupts 在ARM GICv3和GICv4体系结构中,中断分发…...
《mysql篇》--索引事务
索引 索引的介绍 索引是帮助MySQL高效获取数据的数据结构,是一种特殊的文件,包含着对数据表里所有记录的引用指针,因为索引本身也比较大,所以索引一般是存储在磁盘上的,索引的种类有很多,不过如果没有特殊…...
科研绘图系列:R语言STAMP图(STAMP Plot)
介绍 STAMP图(STAMP plot)并非一个广泛认知的、具有特定名称的图表类型,而是可能指在STAMP(Statistical Analysis of Metagenomic Profiles:“STAMP: statistical analysis of taxonomic and functional profiles”)软件使用过程中生成的各种统计和可视化图表的总称。ST…...
运维团队如何应对动环监控与IT监控分离的挑战
IT与机房动环监控的一体化是当下及未来的必然趋势,这一模式显著节省了运维过程中的时间与成本。一体化平台不仅消除了频繁切换系统的繁琐,更在一个统一界面上实现了多元化的管理运维功能,极大地提升了工作效率。 在机房升级或新建项目中&…...
深入解析大数据核心概念:数据平台、数据中台、数据湖与数据仓库的异同与应用
大数据领域内的诸多概念常常让人困惑,其中数据平台、数据中台、数据湖和数据仓库是最为关键的几个。 1. 数据平台 定义: 数据平台是一个综合性的技术框架,旨在支持整个数据生命周期的管理和使用。它包含数据采集、存储、处理、分析和可视化…...
开发指南040-业务操作日志
平台所有业务操作都存储在核心库,以便统一分析处理。各业务微服务通过feign调用核心日志服务。底层提供了API: <dependency><groupId>org.qlm</groupId><artifactId>qlm-api</artifactId><version>1.0-SNAPSHOT<…...
如何构建数据驱动的企业?爬虫管理平台是关键桥梁吗?
一、数据驱动时代:为何选择爬虫管理平台? 在信息爆炸的今天,数据驱动已成为企业发展的核心战略之一。爬虫管理平台,作为数据采集的第一站,它的重要性不言而喻。这类平台通过自动化手段,从互联网的各个角落…...
多线程Thread
线程Thread简介 任务、线程、金城、多线程 多任务:短时间切换不同得任务 多线程:通过同一条道路,增加道多条道路,提高使用率,解决堵塞问题 普通方法调多线程只有主线一台执行路径是主线程调run()方法,方…...
计算机网络之WPAN 和 WLAN
上一篇文章内容:无线局域网 1.WPAN(无线个人区域网) WPAN 是以个人为中心来使用的无线个人区域网,它实际上就是一个低功率、小范围、低速率和低价格的电缆替代技术。 (1) 蓝牙系统(Bluetooth) &#…...
TikTok海外运营,云手机多种变现方法
从现阶段来看,TikTok 的用户基数不断增长,已然成为全球创业者和品牌的全新竞争舞台。其用户数量近乎 20 亿,年轻用户占据主导,市场渗透率也逐年提高。不管是大型企业、著名品牌,还是个体创业者,都绝不能小觑…...
kubekey在ubuntu24实现kubernetes快速安装
基于Ubunut24.04安装 设置主机名 hostnamectl set-hostname kkmain hostnamectl set-hostname kknode1 hostnamectl set-hostname kknode2关闭swap sudo swapoff -a sudo sed -i s/.*swap.*/#&/ /etc/fstab安装kubekey export KKZONEcn curl -sfL https://get-kk.kubes…...
根据关键词query获取google_img(api方式)
文章目录 说明代码第一部分:链接保存为Json第二部分:链接转换为img 说明 根据关键词query获取google_img USERNAME “xxx” PASSWORD “xxx” 官网申请。 代码 首先获取图片链接,保存为json之后下载。 第一部分:链接保存为…...
西安明德理工学院师生莅临泰迪智能科技开展参观见习活动
为进一步深化校企合作,落实高校应用型人才培养。7月8日,西安明德理工学院与广东泰迪智能科技股份有限公司联合开展学生企业见习活动。西安明德理工学院金融产业学院副院长刘敏、金融学专业负责人张莉萍、金融学专业教师曹艳飞、赵浚妤、泰迪智能科技董事…...
通用机器人里程碑!MIT提出策略组合框架PoCo,解决数据源异构难题,实现机器人多任务灵活执行
18 位人形机器人充当「迎宾」人员,整齐划一向嘉宾挥手,这是 2024 世界人工智能大会上的一个震撼场景,让人们直观感受到了今年机器人的飞速发展。 图源:甲子光年 1954 年,世界上第一台可编程机器人「尤尼梅特」在通用汽…...
基于Java中的SSM框架实现疫情冷链追溯系统项目【项目源码+论文说明】
基于Java中的SSM框架实现疫情冷链追溯系统演示 摘要 近几年随着城镇化发展和居民消费水平的不断提升,人们对健康生活方式的追求意识逐渐加强,生鲜食品逐渐受到大众青睐,诸如盒马鲜生、7-fresh等品牌生鲜超市,一时间如雨后春笋般迅…...
想在vue中预览doxc,excel,pdf文件? vue-office提供包支持
在浩瀚的Vue生态中,vue-office犹如一颗璀璨的星辰,以其独特的魅力照亮了开发者处理多种文件格式的预览之路。这款精心打造的Vue组件库,不仅拥抱了Vue2的经典,也紧密跟随Vue3的步伐,展现了卓越的技术前瞻性和兼容性。它…...
PostgreSQL16安装Mac(brew)
问题 最近需要从MySQL切换到PostgreSQL。我得在本地准备一个PostgreSQL。 步骤 使用brew安装postgresql16: arch -arm64 brew install postgresql16启动postgresql16: brew services start postgresql16配置postgresql环境变量,打开环境变量文件: …...
【语音识别算法】深度学习语音识别算法与传统语音识别算法的区别、对比及联系
深度学习语音识别算法与传统语音识别算法在理论基础、实现方式、性能表现等方面存在显著区别,同时也有一些联系。下面将从几个方面详细比较这两种方法,并给出应用实例和代码示例。 一、理论基础与实现方式 1.传统语音识别算法: 特征提取&a…...
图片批量重命名bat,一个脚本快速搞定图片批量重命名
BAT 批处理 是一种在 Microsoft Windows 操作系统中使用的脚本语言,用于自动执行一系列预定义的命令或任务。这些命令集合通常存储在一个文本文件中,文件扩展名为 .bat 或 .cmd。批处理脚本可以包含简单的命令,如文件复制、移动、删除&#x…...
基于stm32单片机的智能手环的设计
摘 要 随着科技的飞速发展和人们生活水平的提高,健康与科技日益融合,智能可穿戴设备已成为现代人生活中不可或缺的一部分。智能手环,作为一种便携、实用且功能丰富的可穿戴设备,受到越来越多用户的喜爱。它不仅能够实时监测用户的…...
雷池WAF动态防护功能初体验
一、 介绍 大名鼎鼎的雷池WAF最近新上了个名为 动态防护 的功能 所谓动态防护,是在用户浏览到的网页内容不变的情况下,将网页赋予动态特性,即使是静态页面,也会具有动态的随机性。 说白了就是给你网站的 html 和 js 代码加上加密…...
宁夏电力建设工程公司外部网站/青岛seo排名收费
[ 中关村在线 原创 ] 有很多的朋友们在问我:“交换机和路由器到底有什么区别”,其实这个不是什么很难理解的事情,这两个设备的区别主要在功能上区别大了些,那么我们最好先了解一下什么是交换机和什么是路由器的最基本的常识。现在…...
网站制作步骤是什么/青岛关键词排名哪家好
前言 在这一章中,实现光线与对象表面之间的相互作用。目的是在渲染流水线中增加着色功能,所以这里只讨论最基础的局部光照模型。与全局光照不同,在局部光照模型中,着色点的颜色值只取决于着色点表面的材质属性、表面的局部几何性质…...
dede网站移动端怎么做/如何做企业产品推广
deque概述 vector是单向开口的连续线性空间,deque是双向开口的连续线性空间。 双向开口,意思是可以在首尾两端分别做元素的插入和删除操作。 deque允许常数时间内对首尾两端进行元素的插入或删除,且deque没有容量capacity的概念,因…...
在线做春节网站/如何快速优化网站排名
redis–18–集群–理论 1、集群简介 1.1、主从架构 优点 读写分离,通过增加Slaver可以提高并发读的能力。 缺点 Master写能力是瓶颈。 1.2、哈希Slot 对象保存到Redis之前先经过CRC16哈希到一个指定的Node上,例如Object4最终Hash到了Node1上。将整…...
做企业网站需要的人/软文代写费用
1.id: 代表select 语句的编号, 如果是连接查询,表之间是平等关系, select 编号都是1,从1开始. 如果某select中有子查询,则编号递增.如下一条语句2个结果 mysql> explain select goods_id,goods_name from goods where goods_id in (sele ct goods_id from goods where ca…...
sem对seo的影响有哪些/全网seo是什么意思
2019年10月1日,在北京天安门广场,举行了庆祝中华人民共和国成立70周年的阅兵式,先进的军备、英姿飒爽的军人们,各自从广场前缓缓经过,回顾我国以前的艰难岁月,不禁让人百感交集。阅兵式,是对武装…...