feiyu02
2024-02-02 83455446544f89b0663a3f520744331ad8259289
1. 新增导入静安监测数据功能模块
已修改12个文件
已添加1个文件
199 ■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/common/utils/ExcelUtil.kt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/utils/FileExchange.kt 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/MissionService.kt 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/RealTimeDataService.kt 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/MissionServiceImpl.kt 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/RealTimeDataServiceImpl.kt 101 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/web/MissionController.kt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/lightshare/web/RealTimeDataController.kt 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-pro.yml 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-test.yml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/templates/JinAn-Template.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/utils/ExcelUtil.kt
@@ -1,6 +1,7 @@
package com.flightfeather.uav.common.utils
import com.flightfeather.uav.common.exception.ResponseErrorException
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.ss.usermodel.Row
import org.apache.poi.ss.util.CellRangeAddress
import org.apache.poi.xssf.streaming.SXSSFWorkbook
src/main/kotlin/com/flightfeather/uav/common/utils/FileExchange.kt
@@ -3,6 +3,7 @@
import com.alibaba.fastjson.JSONObject
import com.flightfeather.uav.common.exception.ResponseErrorException
import com.flightfeather.uav.domain.entity.RealTimeData
import com.flightfeather.uav.domain.entity.RealTimeDataVehicle
import com.flightfeather.uav.socket.bean.AirData
import org.apache.poi.hssf.usermodel.HSSFWorkbook
import org.apache.poi.xssf.streaming.SXSSFWorkbook
@@ -28,11 +29,11 @@
        private val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    }
    fun exchangeJinanData(file: File) {
    fun exchangeJinanData(deviceCode: String, file: InputStream): List<RealTimeDataVehicle> {
        val headers = listOf(
            "data_time",
            "longitude",
            "latitude",
            "data_time",
            "NO2",
            "CO",
            "H2S",
@@ -48,6 +49,7 @@
            "wind_speed",
            "wind_direction"
        )
        val result = mutableListOf<RealTimeDataVehicle>()
        try {
            ExcelUtil.read(file, headerCheck = {
                val cellIterator = it.cellIterator()
@@ -65,13 +67,33 @@
                }
                true
            }, onRow = {
                it.cellIterator().forEach {
                    it.numericCellValue
                val data = RealTimeDataVehicle().apply {
                    this.deviceCode = deviceCode
                    dataTime = it.getCell(0).dateCellValue
                    longitude = it.getCell(1).numericCellValue.toBigDecimal()
                    latitude = it.getCell(2).numericCellValue.toBigDecimal()
                    no2 = it.getCell(3).numericCellValue.toFloat()
                    co = it.getCell(4).numericCellValue.toFloat()
                    h2s = it.getCell(5).numericCellValue.toFloat()
                    so2 = it.getCell(6).numericCellValue.toFloat()
                    o3 = it.getCell(7).numericCellValue.toFloat()
                    pm25 = it.getCell(8).numericCellValue.toFloat()
                    pm10 = it.getCell(9).numericCellValue.toFloat()
                    temperature = it.getCell(10).numericCellValue.toFloat()
                    humidity = it.getCell(11).numericCellValue.toFloat()
                    voc = it.getCell(12).numericCellValue.toFloat()
                    noi = it.getCell(13).numericCellValue.toFloat()
                    velocity = it.getCell(14).numericCellValue.toFloat()
                    windSpeed = it.getCell(15).numericCellValue.toFloat()
                    windDirection = it.getCell(16).numericCellValue.toFloat()
                }
                result.add(data)
            })
        } catch (e: Exception) {
            e.printStackTrace()
            throw ResponseErrorException("excel文件内容错误,数据转换失败!", e)
        }
        return result
    }
    /**
src/main/kotlin/com/flightfeather/uav/lightshare/service/MissionService.kt
@@ -10,4 +10,6 @@
    fun createMission(mission: Mission): BaseResponse<Boolean>
    fun deleteMission(missionCode: String): BaseResponse<Boolean>
    fun deleteMissionAndData(missionCode: String): Boolean
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/RealTimeDataService.kt
@@ -16,7 +16,9 @@
    fun importData(file: MultipartFile): BaseResponse<DataImportResult>
    fun importJinanData(file: MultipartFile): BaseResponse<DataImportResult>
    fun importJinanData(code:String, file: MultipartFile): DataImportResult
    fun downloadTemplate(response: HttpServletResponse): Boolean
    fun outToWorkbook(deviceCode: String, startTime: String, endTime: String): SXSSFWorkbook
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/MissionServiceImpl.kt
@@ -1,7 +1,10 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.common.exception.ResponseErrorException
import com.flightfeather.uav.domain.entity.Mission
import com.flightfeather.uav.domain.entity.RealTimeDataVehicle
import com.flightfeather.uav.domain.mapper.MissionMapper
import com.flightfeather.uav.domain.mapper.RealTimeDataVehicleMapper
import com.flightfeather.uav.lightshare.bean.BaseResponse
import com.flightfeather.uav.lightshare.bean.DataHead
import com.flightfeather.uav.lightshare.service.MissionService
@@ -10,7 +13,10 @@
import tk.mybatis.mapper.entity.Example
@Service
class MissionServiceImpl(private val missionMapper: MissionMapper) : MissionService {
class MissionServiceImpl(
    private val missionMapper: MissionMapper,
    private val realTimeDataVehicleMapper: RealTimeDataVehicleMapper,
) : MissionService {
    override fun getMission(type: String?, page: Int?, perPage: Int?): BaseResponse<List<Mission>> {
        val _perPage = perPage ?: 60
        val _page = page ?: 1
@@ -39,4 +45,14 @@
            return BaseResponse(it == 1)
        }
    }
    override fun deleteMissionAndData(missionCode: String): Boolean {
        val mission = missionMapper.selectByPrimaryKey(missionCode) ?: throw ResponseErrorException("任务不存在")
        missionMapper.deleteByPrimaryKey(missionCode)
        realTimeDataVehicleMapper.deleteByExample(Example(RealTimeDataVehicle::class.java).apply {
            createCriteria().andEqualTo("deviceCode", mission.deviceCode)
                .andBetween("dataTime", mission.startTime, mission.endTime)
        })
        return true
    }
}
src/main/kotlin/com/flightfeather/uav/lightshare/service/impl/RealTimeDataServiceImpl.kt
@@ -1,5 +1,6 @@
package com.flightfeather.uav.lightshare.service.impl
import com.flightfeather.uav.common.exception.ResponseErrorException
import com.flightfeather.uav.common.scaleMap
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.common.utils.ExcelUtil
@@ -17,10 +18,12 @@
import com.github.pagehelper.PageHelper
import org.apache.poi.xssf.streaming.SXSSFWorkbook
import org.springframework.beans.BeanUtils
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.web.multipart.MultipartFile
import tk.mybatis.mapper.entity.Example
import java.io.ByteArrayInputStream
import java.io.File
import java.text.SimpleDateFormat
import java.time.LocalDateTime
import java.time.ZoneId
@@ -38,14 +41,25 @@
    private val realTimeDataUavMapper: RealTimeDataUavMapper,
    private val realTimeDataGridMapper: RealTimeDataGridMapper,
    private val realTimeDataGridOptMapper: RealTimeDataGridOptMapper,
    private val realTimeDataGridMinMapper: RealTimeDataGridMinMapper
    private val realTimeDataGridMinMapper: RealTimeDataGridMinMapper,
    private val missionMapper: MissionMapper,
) : RealTimeDataService {
    @Value("\${filePath}")
    lateinit var filePath: String
    private var dateFormatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    private var dateFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
    private val fileExchange = FileExchange()
    override fun getSecondData(deviceCode: String?, startTime: String?, endTime: String?, type: Int?, page: Int?, perPage: Int?): BaseResponse<List<DataVo>> {
    override fun getSecondData(
        deviceCode: String?,
        startTime: String?,
        endTime: String?,
        type: Int?,
        page: Int?,
        perPage: Int?,
    ): BaseResponse<List<DataVo>> {
        val _perPage = perPage ?: 60
        val _page = page ?: 1
        val sTime = startTime?.let { dateFormatter.parse(it) }
@@ -128,7 +142,12 @@
        }
    }
    override fun getNextData(deviceCode: String, updateTime: String, page: Int?, perPage: Int?): BaseResponse<List<DataVo>> {
    override fun getNextData(
        deviceCode: String,
        updateTime: String,
        page: Int?,
        perPage: Int?,
    ): BaseResponse<List<DataVo>> {
        val _perPage = perPage ?: 60
        val _page = page ?: 1
        val pageInfo = PageHelper.startPage<RealTimeData>(_page, _perPage)
@@ -170,11 +189,52 @@
        fileExchange.exchangeBoatData("0c0000000001", f).forEach {
            realTimeDataMapper.insert(it)
        }
        return BaseResponse(true, data = DataImportResult(""))
        return BaseResponse(true, data = DataImportResult("成功"))
    }
    override fun importJinanData(file: MultipartFile): BaseResponse<DataImportResult> {
        TODO("Not yet implemented")
    override fun importJinanData(code: String, file: MultipartFile): DataImportResult {
        val f = ByteArrayInputStream(file.bytes)
        val result = fileExchange.exchangeJinanData(code, f)
        if (result.isNotEmpty()) {
            val first = result.first()
            val t = DateUtil.instance.dateToString(first.dataTime, DateUtil.DateStyle.YYYY_MM_DD)
            val last = result.last()
            val mission = Mission().apply {
                val tag = code.substring(0, 2) + "-" + code.substring(code.length - 2, code.length)
                missionCode = "SH-JA-${tag}-${t}"
                deviceType = UWDeviceType.getType(code)?.value
                deviceCode = code
            }
            missionMapper.selectOne(mission)?.run { throw ResponseErrorException("该设备该时段任务已存在,无法重复导入") }
            mission.apply {
                startTime = first.dataTime
                endTime = last.dataTime
            }
            missionMapper.insert(mission)
            realTimeDataVehicleMapper.insertList(result)
        }
        return DataImportResult("成功")
    }
    override fun downloadTemplate(response: HttpServletResponse): Boolean {
        val fileName = "JinAn-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 outToWorkbook(deviceCode: String, startTime: String, endTime: String): SXSSFWorkbook {
@@ -196,13 +256,19 @@
            })
            if (r.isNotEmpty()) {
                val heads = if (page == 1) {
                    println("[${DateUtil.instance.dateToString(Date(), DateUtil.DateStyle.YYYY_MM_DD_HH_MM_SS)}] totalPage: ${pageInfo.pages}")
                    println("[${
                        DateUtil.instance.dateToString(Date(),
                            DateUtil.DateStyle.YYYY_MM_DD_HH_MM_SS)
                    }] totalPage: ${pageInfo.pages}")
                    getTableTitle(r[0])
                } else {
                    emptyList()
                }
                val contents = getTableContents(r)
                print("[${DateUtil.instance.dateToString(Date(), DateUtil.DateStyle.YYYY_MM_DD_HH_MM_SS)}] currentPage: ${pageInfo.pageNum}......")
                print("[${
                    DateUtil.instance.dateToString(Date(),
                        DateUtil.DateStyle.YYYY_MM_DD_HH_MM_SS)
                }] currentPage: ${pageInfo.pageNum}......")
                rowIndex = ExcelUtil.write(heads, contents, workbook, row = rowIndex)
                println("output done")
            }
@@ -212,7 +278,12 @@
        return workbook
    }
    override fun outToExcel(deviceCode: String, startTime: String, endTime: String, response: HttpServletResponse): HttpServletResponse {
    override fun outToExcel(
        deviceCode: String,
        startTime: String,
        endTime: String,
        response: HttpServletResponse,
    ): HttpServletResponse {
        val workbook = outToWorkbook(deviceCode, startTime, endTime)
        val out = response.outputStream
@@ -236,7 +307,13 @@
        return contents
    }
    override fun getOriginData(deviceCode: String?, startTime: String?, endTime: String?, page: Int?, perPage: Int?): BaseResponse<List<DataVo>> {
    override fun getOriginData(
        deviceCode: String?,
        startTime: String?,
        endTime: String?,
        page: Int?,
        perPage: Int?,
    ): BaseResponse<List<DataVo>> {
        val _perPage = perPage ?: 60
        val _page = page ?: 1
        val sTime = startTime?.let { dateFormatter.parse(it) }
@@ -296,9 +373,9 @@
        var count = 0
        val minFormatter = SimpleDateFormat("yyyy-MM-dd HH:mm")
        val averageUtil = AverageUtil<RealTimeDataGridOpt, RealTimeDataGridMin>({d ->
        val averageUtil = AverageUtil<RealTimeDataGridOpt, RealTimeDataGridMin>({ d ->
            minFormatter.format(d.dataTime)
        },{list ->
        }, { list ->
            list.avg()
        })
src/main/kotlin/com/flightfeather/uav/lightshare/web/MissionController.kt
@@ -26,4 +26,9 @@
    fun deleteMission(
        @RequestParam("missionCode") missionCode: String
    ) = missionService.deleteMission(missionCode)
    @PostMapping("/delete/data/vehicle")
    fun deleteMissionAndData(
        @RequestParam("missionCode") missionCode: String
    ) = resPack { missionService.deleteMissionAndData(missionCode) }
}
src/main/kotlin/com/flightfeather/uav/lightshare/web/RealTimeDataController.kt
@@ -6,6 +6,8 @@
import io.swagger.annotations.ApiParam
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import springfox.documentation.annotations.ApiIgnore
import javax.servlet.http.HttpServletResponse
@Api(tags = ["走航监测数据API接口"])
@RestController
@@ -17,9 +19,10 @@
        @RequestParam(value = "deviceCode", required = false) deviceCode: String?,
        @RequestParam(value = "startTime", required = false) startTime: String?,
        @RequestParam(value = "endTime", required = false) endTime: String?,
        @ApiParam(value = "0: 秒级值; 1:分钟值", defaultValue = "0") @RequestParam(value = "type", required = false) type: Int?,
        @ApiParam(value = "0: 秒级值; 1:分钟值", defaultValue = "0") @RequestParam(value = "type",
            required = false) type: Int?,
        @RequestParam(value = "page", required = false) page: Int?,
        @RequestParam(value = "perPage", required = false) perPage: Int?
        @RequestParam(value = "perPage", required = false) perPage: Int?,
    ) = realTimeDataService.getSecondData(deviceCode, startTime, endTime, type, page, perPage)
    @GetMapping("/sec/next")
@@ -27,17 +30,22 @@
        @RequestParam(value = "deviceCode") deviceCode: String,
        @RequestParam(value = "updateTime") updateTime: String,
        @RequestParam(value = "page", required = false) page: Int?,
        @RequestParam(value = "perPage", required = false) perPage: Int?
        @RequestParam(value = "perPage", required = false) perPage: Int?,
    ) = realTimeDataService.getNextData(deviceCode, updateTime, page, perPage)
    @PostMapping("/import")
    fun importData(
        @RequestPart("excel") file: MultipartFile
        @RequestPart("excel") file: MultipartFile,
    ) = realTimeDataService.importData(file)
    @ApiOperation(value = "导入静安区生态环境监测站的走行数据")
    @PostMapping("/import/jinan")
    fun importJinanData(
        @RequestPart("excel") file: MultipartFile
    ) = realTimeDataService.importJinanData(file)
        @ApiParam("设备id") @RequestParam("code") code: String,
        @RequestPart("excel") file: MultipartFile,
    ) = resPack { realTimeDataService.importJinanData(code, file) }
    @ApiOperation(value = "下载静安区生态环境监测站走行数据导入模板")
    @PostMapping("/import/jinan/download/template")
    fun downloadTemplate(@ApiIgnore response: HttpServletResponse) = realTimeDataService.downloadTemplate(response)
}
src/main/resources/application-dev.yml
@@ -11,4 +11,5 @@
      v2:
        enabled: true
imgPath: target/
filePath: target/
src/main/resources/application-pro.yml
@@ -1,6 +1,11 @@
spring:
  datasource:
    #    线上服务器
    #    线上服务器 47
#    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
#    username: dronemonitor
#    password: dronemonitor_hackxrnomxm
    #    线上服务器 114
    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
    username: dronemonitor
    password: dronemonitor_hackxrnomxm
@@ -11,4 +16,5 @@
      v2:
        enabled: false
imgPath: D:/02product/10underway/images/
filePath: D:/02product/10underway/files/
src/main/resources/application-test.yml
@@ -17,4 +17,5 @@
      v2:
        enabled: true
imgPath: D:/02product/10underway/images/
filePath: D:/02product/10underway/files/
src/main/resources/application.yml
@@ -6,6 +6,8 @@
      minimum-idle: 20
      idle-timeout: 60000
      connection-timeout: 60000
  profiles:
    active: @profileActive@
  jmx:
    enabled: false
src/main/resources/templates/JinAn-Template.xlsx
Binary files differ