package com.flightfeather.uav.lightshare.service.impl
|
|
import com.flightfeather.uav.biz.satellite.SatelliteDataMix
|
import com.flightfeather.uav.biz.satellite.SatelliteGridManage
|
import com.flightfeather.uav.common.exception.BizException
|
import com.flightfeather.uav.common.utils.FileExchange
|
import com.flightfeather.uav.domain.entity.GridAod
|
import com.flightfeather.uav.domain.entity.GridCell
|
import com.flightfeather.uav.domain.entity.GridData
|
import com.flightfeather.uav.domain.entity.GridDataDetail
|
import com.flightfeather.uav.domain.entity.GridGroup
|
import com.flightfeather.uav.domain.repository.SatelliteGridRep
|
import com.flightfeather.uav.lightshare.bean.AreaVo
|
import com.flightfeather.uav.lightshare.bean.DataHead
|
import com.flightfeather.uav.lightshare.bean.GridDataImportResult
|
import com.flightfeather.uav.lightshare.service.SatelliteTelemetryService
|
import com.github.pagehelper.PageHelper
|
import org.springframework.stereotype.Service
|
import org.springframework.transaction.annotation.Transactional
|
import org.springframework.web.multipart.MultipartFile
|
import java.io.ByteArrayInputStream
|
import java.io.File
|
import java.time.LocalDateTime
|
import java.time.ZoneId
|
import java.util.*
|
import javax.servlet.http.HttpServletResponse
|
import kotlin.math.round
|
|
/**
|
*
|
* @date 2024/12/5
|
* @author feiyu02
|
*/
|
@Service
|
class SatelliteTelemetryServiceImpl(
|
private val satelliteGridRep: SatelliteGridRep,
|
private val satelliteDataMix: SatelliteDataMix,
|
) : SatelliteTelemetryService {
|
|
private val fileExchange = FileExchange()
|
override fun fetchGridGroup(areaVo: AreaVo, page: Int?, perPage: Int?): Pair<DataHead, List<GridGroup?>> {
|
val pageInfo = PageHelper.startPage<GridGroup>(page ?: 1, perPage ?: 100)
|
val res = satelliteGridRep.fetchGridGroup(areaVo)
|
return DataHead(pageInfo.pageNum, pageInfo.pages) to res
|
}
|
|
override fun fetchGridCell(groupId: Int): List<GridCell?> {
|
return satelliteGridRep.fetchGridCell(groupId)
|
}
|
|
override fun fetchGridData(groupId: Int, dataTime: LocalDateTime?, type: Int?): List<GridData?> {
|
return satelliteGridRep.fetchGridData(groupId, dataTime, type)
|
}
|
|
override fun fetchGridAod(groupId: Int, dataTime: LocalDateTime?): List<GridAod?> {
|
return satelliteGridRep.fetchGridAod(groupId, dataTime)
|
}
|
|
override fun fetchGridDataDetail(dataId: Int, groupId: Int?, cellId: Int?): List<GridDataDetail?> {
|
val res = satelliteGridRep.fetchGridDataDetail(dataId, groupId, cellId)
|
res.forEach {
|
if (it?.pm25 != null) {
|
it.pm25 = round(it.pm25 * 100) / 100
|
}
|
}
|
return res
|
}
|
|
@Transactional
|
override fun mixGridData(dataIdList: List<Int>): List<GridData?> {
|
if (dataIdList.isEmpty()) throw BizException("融合所需数据id不能为空")
|
// 1. 根据数据主键id数组,查询该组合下是否已有数据融合记录
|
val exist = satelliteGridRep.fetchGridData(GridData().apply {
|
type = 1
|
mixDataId = dataIdList.sorted().joinToString(",")
|
})
|
// 2. 若融合数据已存在,直接返回
|
return exist.ifEmpty {
|
listOf(satelliteDataMix.mixData(dataIdList).first)
|
}
|
}
|
|
override fun importGridData(groupId: Int, dataTime: LocalDateTime?, update: Boolean, file: MultipartFile): GridDataImportResult? {
|
// 因为是导入卫星遥测数据 type始终为0
|
val type = 0
|
// 首先判断文件类型,文件类型不是xlsx直接报错
|
if (!file.contentType!!.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
|
throw BizException("文件类型错误,请上传xlsx类型文件")
|
}
|
// 校验 用户更新指令 和 数据库中网格数据存在与否 是否匹配,不匹配抛出错误
|
// 这个过程需要查询数据库中网格组数据
|
val gridData = satelliteGridRep.fetchGridData(groupId, dataTime, type)
|
// 将用户导入的文件转换为数据
|
// 转换的过程需要网格单元格数据 以判断网格单元格是否在正确的范围内
|
val gridCellsInDBSet = satelliteGridRep.fetchGridCell(groupId).asSequence().map { it?.id ?: -1 }.toSet()
|
val importData
|
= fileExchange.exchangeGridData(ByteArrayInputStream(file.bytes), gridCellsInDBSet)
|
if (update) {
|
// 用户需要执行更新
|
if (gridData.isEmpty()) {
|
throw BizException("指令错误,数据库对应网格组和日期下不存在遥测数据,请执行插入操作")
|
}
|
importData.forEach {
|
it.dataId = gridData[0]?.id
|
it.groupId = gridData[0]?.groupId
|
}
|
satelliteGridRep.updatePM25Batch(importData)
|
return GridDataImportResult(true, "覆盖成功")
|
}else {
|
// 用户需要执行插入
|
if (gridData.isNotEmpty()) {
|
throw BizException("指令错误,数据库对应网格组和日期下已存在遥测数据,请执行更新操作")
|
}
|
val gridDataEntity = GridData()
|
gridDataEntity.groupId = groupId
|
gridDataEntity.dataTime = dataTime?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli()
|
?.let { Date(it) }
|
gridDataEntity.type = type.toByte()
|
satelliteGridRep.insertGridDataAndDetail(gridDataEntity, importData)
|
return GridDataImportResult(true, "导入成功")
|
}
|
}
|
|
override fun downloadTemplate(response: HttpServletResponse): Boolean {
|
val fileName = "GridData-PM2.5-Template.xlsx"
|
val path = (Thread.currentThread().contextClassLoader?.getResource("/")?.path
|
?: "src/main/resources") + "/templates/" + fileName
|
val file = File(path)
|
if (file.exists()) {
|
val fName = Base64.getEncoder().encodeToString(fileName.toByteArray())
|
response.apply {
|
setHeader("Content-Disposition", "attachment;filename=$fName")
|
setHeader("fileName", fName)
|
addHeader("Access-Control-Expose-Headers", "fileName")
|
contentType = "application/vnd.ms-excel;charset=UTF-8"
|
setHeader("Pragma", "no-cache")
|
setHeader("Cache-Control", "no-cache")
|
setDateHeader("Expires", 0)
|
}
|
response.outputStream.write(file.readBytes())
|
}
|
return true
|
}
|
|
override fun importGridAOD(
|
groupId: Int,
|
dataTime: LocalDateTime?,
|
update: Boolean,
|
file: MultipartFile
|
): GridDataImportResult? {
|
// 首先判断文件类型,文件类型不是xlsx直接报错
|
if (!file.contentType!!.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
|
throw BizException("文件类型错误,请上传xlsx类型文件")
|
}
|
// 校验 用户更新指令 和 数据库中网格数据存在与否 是否匹配,不匹配抛出错误
|
// 这个过程需要查询数据库中网格组数据
|
val gridAod = satelliteGridRep.fetchGridAod(groupId, dataTime)
|
// 将用户导入的文件转换为数据
|
// 转换的过程需要网格单元格数据 以判断网格单元格是否在正确的范围内
|
val gridCellsInDBSet = satelliteGridRep.fetchGridCell(groupId).asSequence().map { it?.id ?: -1 }.toSet()
|
val importAod
|
= fileExchange.exchangeGridAod(ByteArrayInputStream(file.bytes), gridCellsInDBSet)
|
if (update) {
|
// 用户需要执行更新
|
if (gridAod.isEmpty()) {
|
throw BizException("指令错误,数据库对应网格组和日期下不存在AOD数据,请执行插入操作")
|
}
|
importAod.forEach {
|
it.aodId = gridAod[0]?.id
|
it.groupId = gridAod[0]?.groupId
|
}
|
satelliteGridRep.updateGridAodBatch(importAod)
|
return GridDataImportResult(true, "覆盖成功")
|
}else {
|
// 用户需要执行插入
|
if (gridAod.isNotEmpty()) {
|
throw BizException("指令错误,数据库对应网格组和日期下已存在AOD数据,请执行更新操作")
|
}
|
val gridAodEntity = GridAod()
|
gridAodEntity.groupId = groupId
|
gridAodEntity.dataTime = dataTime?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli()
|
?.let { Date(it) }
|
satelliteGridRep.insertGridAodAndDetail(gridAodEntity, importAod)
|
return GridDataImportResult(true, "导入成功")
|
}
|
}
|
|
override fun downloadAODTemplate(response: HttpServletResponse): Boolean {
|
val fileName = "GridData-AOD-Template.xlsx"
|
val path = (Thread.currentThread().contextClassLoader?.getResource("/")?.path
|
?: "src/main/resources") + "/templates/" + fileName
|
val file = File(path)
|
if (file.exists()) {
|
val fName = Base64.getEncoder().encodeToString(fileName.toByteArray())
|
response.apply {
|
setHeader("Content-Disposition", "attachment;filename=$fName")
|
setHeader("fileName", fName)
|
addHeader("Access-Control-Expose-Headers", "fileName")
|
contentType = "application/vnd.ms-excel;charset=UTF-8"
|
setHeader("Pragma", "no-cache")
|
setHeader("Cache-Control", "no-cache")
|
setDateHeader("Expires", 0)
|
}
|
response.outputStream.write(file.readBytes())
|
}
|
return true
|
}
|
|
override fun calGridVertex(groupId: Int): List<GridCell?> {
|
val cellList = satelliteGridRep.fetchGridCell(groupId)
|
val vertexList = SatelliteGridManage.calGridVertex(cellList.map {
|
if (it?.longitude == null || it.latitude == null) {
|
throw BizException("卫星遥测网格计算顶点坐标点失败,存在中心点坐标为空的情况")
|
}
|
it.longitude?.toDouble()!! to it.latitude?.toDouble()!!
|
})
|
|
cellList.forEachIndexed { i, c ->
|
val v = vertexList[i]
|
c?.point1Lon = v.point1Lon.toBigDecimal()
|
c?.point1Lat = v.point1Lat.toBigDecimal()
|
|
c?.point2Lon = v.point2Lon.toBigDecimal()
|
c?.point2Lat = v.point2Lat.toBigDecimal()
|
|
c?.point3Lon = v.point3Lon.toBigDecimal()
|
c?.point3Lat = v.point3Lat.toBigDecimal()
|
|
c?.point4Lon = v.point4Lon.toBigDecimal()
|
c?.point4Lat = v.point4Lat.toBigDecimal()
|
}
|
|
satelliteGridRep.updateGridCellBatch(cellList)
|
|
return cellList
|
}
|
}
|