riku
2021-06-17 81bd0388494d45463de42cd91bd8c33f10f0030a
1. 新增用电量数据的接收协议
2. 调整socket接收模块的代码结构
已修改10个文件
已删除2个文件
已添加14个文件
已重命名2个文件
2262 ■■■■ 文件已修改
src/main/kotlin/com/flightfeather/uav/UAVApplication.kt 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/utils/CommonUtil.kt 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt 765 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/entity/ElectricMinuteValue.java 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/domain/mapper/ElectricMinuteValueMapper.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/repository/ElectricRepository.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/repository/impl/ElectricDapImpl.kt 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/DeviceSession.kt 52 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt 65 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/UAVByteDataDecoder.kt 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/UnderwaySocketServer.kt 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/bean/BaseDataPackage.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/bean/BaseMessage.kt 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/bean/ElectricMessage.kt 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/AirDataDecoder.kt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/BaseDataDecoder.kt 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/DataPackageDecoder.kt 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/DataUnitDecoder.kt 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/ElectricDataDecoder.kt 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataPackageDecoderImpl.kt 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataUnitDecoderImpl.kt 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/processor/BaseProcessor.kt 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/processor/ElectricProcessor.kt 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/generator/generatorConfig.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ElectricMinuteValueMapper.xml 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/kotlin/com/flightfeather/uav/socket/UnderwayProcessorTest.kt 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/kotlin/com/flightfeather/uav/UAVApplication.kt
@@ -1,6 +1,9 @@
package com.flightfeather.uav
import com.flightfeather.uav.socket.UnderwaySocketServer
import com.flightfeather.uav.socket.processor.ElectricProcessor
import com.flightfeather.uav.socket.processor.UnderwayProcessor
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.ApplicationRunner
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@@ -9,9 +12,18 @@
@SpringBootApplication
class UAVApplication{
    @Autowired
    lateinit var underwayProcessor: UnderwayProcessor
    @Autowired
    lateinit var electricProcessor: ElectricProcessor
    private val socketServer = UnderwaySocketServer()
    @Bean
    fun runner() = ApplicationRunner{
        UnderwaySocketServer().startServer(9030)
        socketServer.startUnderwayServer(9030, underwayProcessor)
        socketServer.startElectricServer(9009, electricProcessor)
    }
}
src/main/kotlin/com/flightfeather/uav/common/utils/CommonUtil.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.flightfeather.uav.common.utils
/**
 * @author riku
 * Date: 2020/9/10
 */
object CommonUtil {
    fun getSubStr(strData: String, startIndexStr: String, endIndexStr: String): String? {
        try {
            val startIndex = strData.indexOf(startIndexStr)
            val endIndex = strData.indexOf(endIndexStr, startIndex + startIndexStr.length)
            return strData.substring(startIndex, endIndex)
        } catch (e: Exception) {
//            println("字段[$startIndexStr]无法获取")
        }
        return null
    }
}
src/main/kotlin/com/flightfeather/uav/common/utils/DateUtil.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,765 @@
package com.flightfeather.uav.common.utils
import java.sql.Timestamp
import java.text.ParsePosition
import java.text.SimpleDateFormat
import java.util.*
class DateUtil {
    private val threadLocal = ThreadLocal<SimpleDateFormat>()
    private val `object` = Any()
    /**
     * èŽ·å–SimpleDateFormat
     * @param pattern æ—¥æœŸæ ¼å¼
     * @return SimpleDateFormat对象
     * @throws RuntimeException å¼‚常:非法日期格式
     */
    @Throws(RuntimeException::class)
    private fun getDateFormat(pattern: String): SimpleDateFormat {
        var dateFormat: SimpleDateFormat? = threadLocal.get()
        if (dateFormat == null) {
            synchronized(`object`) {
                if (dateFormat == null) {
                    dateFormat = SimpleDateFormat(pattern)
                    dateFormat!!.isLenient = false
                    threadLocal.set(dateFormat)
                }
            }
        }
        dateFormat!!.applyPattern(pattern)
        return dateFormat as SimpleDateFormat
    }
    /**
     * èŽ·å–æ—¥æœŸä¸­çš„æŸæ•°å€¼ã€‚å¦‚èŽ·å–æœˆä»½
     * @param date æ—¥æœŸ
     * @param dateType æ—¥æœŸæ ¼å¼
     * @return æ•°å€¼
     */
    private fun getInteger(date: Date?, dateType: Int): Int {
        var num = 0
        val calendar = Calendar.getInstance()
        if (date != null) {
            calendar.time = date
            num = calendar.get(dateType)
        }
        return num
    }
    /**
     * å¢žåŠ æ—¥æœŸä¸­æŸç±»åž‹çš„æŸæ•°å€¼ã€‚å¦‚å¢žåŠ æ—¥æœŸ
     * @param date æ—¥æœŸå­—符串
     * @param dateType ç±»åž‹
     * @param amount æ•°å€¼
     * @return è®¡ç®—后日期字符串
     */
    private fun addInteger(date: String, dateType: Int, amount: Int): String? {
        var dateString: String? = null
        val dateStyle = getDateStyle(date)
        if (dateStyle != null) {
            var myDate = StringToDate(date, dateStyle)
            myDate = addInteger(myDate, dateType, amount)
            dateString = DateToString(myDate, dateStyle)
        }
        return dateString
    }
    /**
     * å¢žåŠ æ—¥æœŸä¸­æŸç±»åž‹çš„æŸæ•°å€¼ã€‚å¦‚å¢žåŠ æ—¥æœŸ
     * @param date æ—¥æœŸ
     * @param dateType ç±»åž‹
     * @param amount æ•°å€¼
     * @return è®¡ç®—后日期
     */
    private fun addInteger(date: Date?, dateType: Int, amount: Int): Date? {
        var myDate: Date? = null
        if (date != null) {
            val calendar = Calendar.getInstance()
            calendar.time = date
            calendar.add(dateType, amount)
            myDate = calendar.time
        }
        return myDate
    }
    /**
     * èŽ·å–ç²¾ç¡®çš„æ—¥æœŸ
     * @param timestamps æ—¶é—´long集合
     * @return æ—¥æœŸ
     */
    private fun getAccurateDate(timestamps: List<Long>?): Date? {
        var date: Date? = null
        var timestamp: Long = 0
        val map = HashMap<Long, LongArray>()
        val absoluteValues = ArrayList<Long>()
        if (timestamps != null && timestamps.size > 0) {
            if (timestamps.size > 1) {
                for (i in timestamps.indices) {
                    for (j in i + 1 until timestamps.size) {
                        val absoluteValue = Math.abs(timestamps[i] - timestamps[j])
                        absoluteValues.add(absoluteValue)
                        val timestampTmp = longArrayOf(timestamps[i], timestamps[j])
                        map.put(absoluteValue, timestampTmp)
                    }
                }
                // æœ‰å¯èƒ½æœ‰ç›¸ç­‰çš„æƒ…况。如2012-11和2012-11-01。时间戳是相等的。此时minAbsoluteValue为0
                // å› æ­¤ä¸èƒ½å°†minAbsoluteValue取默认值0
                var minAbsoluteValue: Long = -1
                if (!absoluteValues.isEmpty()) {
                    minAbsoluteValue = absoluteValues[0]
                    for (i in 1 until absoluteValues.size) {
                        if (minAbsoluteValue > absoluteValues[i]) {
                            minAbsoluteValue = absoluteValues[i]
                        }
                    }
                }
                if (!minAbsoluteValue.equals(-1)) {
                    val timestampsLastTmp = map[minAbsoluteValue]
                    val dateOne = timestampsLastTmp?.get(0)
                    val dateTwo = timestampsLastTmp?.get(1)
                    if (absoluteValues.size > 1) {
                        timestamp = if (Math.abs(dateOne!!) > Math.abs(dateTwo!!)) dateOne else dateTwo
                    }
                }
            } else {
                timestamp = timestamps[0]
            }
        }
        if (timestamp != 0L) {
            date = Date(timestamp)
        }
        return date
    }
    /**
     * åˆ¤æ–­å­—符串是否为日期字符串
     * @param date æ—¥æœŸå­—符串
     * @return true or false
     */
    fun isDate(date: String?): Boolean {
        var isDate = false
        if (date != null) {
            if (getDateStyle(date) != null) {
                isDate = true
            }
        }
        return isDate
    }
    /**
     * èŽ·å–æ—¥æœŸå­—ç¬¦ä¸²çš„æ—¥æœŸé£Žæ ¼ã€‚å¤±æ•—è¿”å›žnull。
     * @param date æ—¥æœŸå­—符串
     * @return æ—¥æœŸé£Žæ ¼
     */
    fun getDateStyle(date: String?): DateStyle? {
        var dateStyle: DateStyle? = null
        val map = HashMap<Long, DateStyle>()
        val timestamps = ArrayList<Long>()
        for (style in DateStyle.values()) {
            if (style.isShowOnly) {
                continue
            }
            var dateTmp: Date? = null
            if (date != null) {
                try {
                    val pos = ParsePosition(0)
                    dateTmp = getDateFormat(style.value).parse(date, pos)
                    if (pos.index != date.length) {
                        dateTmp = null
                    }
                } catch (e: Exception) {
                }
            }
            if (dateTmp != null) {
                timestamps.add(dateTmp.time)
                map.put(dateTmp.time, style)
            }
        }
        val accurateDate = getAccurateDate(timestamps)
        if (accurateDate != null) {
            dateStyle = map[accurateDate.time]
        }
        return dateStyle
    }
    /**
     * Timestamp -> String
     *
     */
    fun timestampToString(ts: Timestamp, format: String): String {
        var tsStr = ""
        val sdf = SimpleDateFormat(format)
        try {
            //方法一
            tsStr = sdf.format(ts)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return tsStr
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为日期。失败返回null。
     * @param date æ—¥æœŸå­—符串
     * @return æ—¥æœŸ
     */
    fun StringToDate(date: String): Date? {
        val dateStyle = getDateStyle(date)
        return StringToDate(date, dateStyle)
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为日期。失败返回null。
     * @param date æ—¥æœŸå­—符串
     * @param pattern æ—¥æœŸæ ¼å¼
     * @return æ—¥æœŸ
     */
    fun StringToDate(date: String?, pattern: String): Date? {
        var myDate: Date? = null
        if (date != null) {
            try {
                myDate = getDateFormat(pattern).parse(date)
            } catch (e: Exception) {
            }
        }
        return myDate
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为日期。失败返回null。
     * @param date æ—¥æœŸå­—符串
     * @param dateStyle æ—¥æœŸé£Žæ ¼
     * @return æ—¥æœŸ
     */
    fun StringToDate(date: String?, dateStyle: DateStyle?): Date? {
        var myDate: Date? = null
        if (dateStyle != null) {
            myDate = StringToDate(date, dateStyle.value)
        }
        return myDate
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为日期。失败返回null。
     * @param millisecondStamp æ—¥æœŸæ—¶é—´æˆ³
     * @param dateStyle æ—¥æœŸé£Žæ ¼
     * @return æ—¥æœŸ
     */
    fun LongToString(millisecondStamp: Long?, dateStyle: DateStyle?): String? {
        var dateString: String? = null
        if (dateStyle != null) {
            dateString = DateToString(Date(millisecondStamp!!), dateStyle.value)
        }
        return dateString
    }
    /**
     * å°†æ—¥æœŸè½¬åŒ–为日期字符串。失败返回null。
     * @param date æ—¥æœŸ
     * @param pattern æ—¥æœŸæ ¼å¼
     * @return æ—¥æœŸå­—符串
     */
    fun DateToString(date: Date?, pattern: String): String? {
        var dateString: String? = null
        if (date != null) {
            try {
                dateString = getDateFormat(pattern).format(date)
            } catch (e: Exception) {
            }
        }
        return dateString
    }
    /**
     * å°†æ—¥æœŸè½¬åŒ–为日期字符串。失败返回null。
     * @param date æ—¥æœŸ
     * @param dateStyle æ—¥æœŸé£Žæ ¼
     * @return æ—¥æœŸå­—符串
     */
    fun DateToString(date: Date?, dateStyle: DateStyle?): String? {
        var dateString: String? = null
        if (dateStyle != null) {
            dateString = DateToString(date, dateStyle.value)
        }
        return dateString
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为另一日期字符串。失败返回null。
     * @param date æ—§æ—¥æœŸå­—符串
     * @param newPattern æ–°æ—¥æœŸæ ¼å¼
     * @return æ–°æ—¥æœŸå­—符串
     */
    fun StringToString(date: String, newPattern: String): String? {
        val oldDateStyle = getDateStyle(date)
        return StringToString(date, oldDateStyle, newPattern)
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为另一日期字符串。失败返回null。
     * @param date æ—§æ—¥æœŸå­—符串
     * @param newDateStyle æ–°æ—¥æœŸé£Žæ ¼
     * @return æ–°æ—¥æœŸå­—符串
     */
    fun StringToString(date: String, newDateStyle: DateStyle): String? {
        val oldDateStyle = getDateStyle(date)
        return StringToString(date, oldDateStyle, newDateStyle)
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为另一日期字符串。失败返回null。
     * @param date æ—§æ—¥æœŸå­—符串
     * @param olddPattern æ—§æ—¥æœŸæ ¼å¼
     * @param newPattern æ–°æ—¥æœŸæ ¼å¼
     * @return æ–°æ—¥æœŸå­—符串
     */
    fun StringToString(date: String, olddPattern: String, newPattern: String): String? {
        return DateToString(StringToDate(date, olddPattern), newPattern)
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为另一日期字符串。失败返回null。
     * @param date æ—§æ—¥æœŸå­—符串
     * @param olddDteStyle æ—§æ—¥æœŸé£Žæ ¼
     * @param newParttern æ–°æ—¥æœŸæ ¼å¼
     * @return æ–°æ—¥æœŸå­—符串
     */
    fun StringToString(date: String, olddDteStyle: DateStyle?, newParttern: String): String? {
        var dateString: String? = null
        if (olddDteStyle != null) {
            dateString = StringToString(date, olddDteStyle.value, newParttern)
        }
        return dateString
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为另一日期字符串。失败返回null。
     * @param date æ—§æ—¥æœŸå­—符串
     * @param olddPattern æ—§æ—¥æœŸæ ¼å¼
     * @param newDateStyle æ–°æ—¥æœŸé£Žæ ¼
     * @return æ–°æ—¥æœŸå­—符串
     */
    fun StringToString(date: String, olddPattern: String, newDateStyle: DateStyle?): String? {
        var dateString: String? = null
        if (newDateStyle != null) {
            dateString = StringToString(date, olddPattern, newDateStyle.value)
        }
        return dateString
    }
    /**
     * å°†æ—¥æœŸå­—符串转化为另一日期字符串。失败返回null。
     * @param date æ—§æ—¥æœŸå­—符串
     * @param olddDteStyle æ—§æ—¥æœŸé£Žæ ¼
     * @param newDateStyle æ–°æ—¥æœŸé£Žæ ¼
     * @return æ–°æ—¥æœŸå­—符串
     */
    fun StringToString(date: String, olddDteStyle: DateStyle?, newDateStyle: DateStyle?): String? {
        var dateString: String? = null
        if (olddDteStyle != null && newDateStyle != null) {
            dateString = StringToString(date, olddDteStyle.value, newDateStyle.value)
        }
        return dateString
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„å¹´ä»½ã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸ
     * @param yearAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ å¹´ä»½åŽçš„æ—¥æœŸå­—ç¬¦ä¸²
     */
    fun addYear(date: String, yearAmount: Int): String? {
        return addInteger(date, Calendar.YEAR, yearAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„å¹´ä»½ã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸ
     * @param yearAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ å¹´ä»½åŽçš„æ—¥æœŸ
     */
    fun addYear(date: Date, yearAmount: Int): Date? {
        return addInteger(date, Calendar.YEAR, yearAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„æœˆä»½ã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸ
     * @param monthAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ æœˆä»½åŽçš„æ—¥æœŸå­—ç¬¦ä¸²
     */
    fun addMonth(date: String, monthAmount: Int): String? {
        return addInteger(date, Calendar.MONTH, monthAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„æœˆä»½ã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸ
     * @param monthAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ æœˆä»½åŽçš„æ—¥æœŸ
     */
    fun addMonth(date: Date, monthAmount: Int): Date? {
        return addInteger(date, Calendar.MONTH, monthAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„å¤©æ•°ã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸå­—符串
     * @param dayAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ å¤©æ•°åŽçš„æ—¥æœŸå­—ç¬¦ä¸²
     */
    fun addDay(date: String, dayAmount: Int): String? {
        return addInteger(date, Calendar.DATE, dayAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„å¤©æ•°ã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸ
     * @param dayAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ å¤©æ•°åŽçš„æ—¥æœŸ
     */
    fun addDay(date: Date, dayAmount: Int): Date? {
        return addInteger(date, Calendar.DATE, dayAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„å°æ—¶ã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸå­—符串
     * @param hourAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ å°æ—¶åŽçš„æ—¥æœŸå­—ç¬¦ä¸²
     */
    fun addHour(date: String, hourAmount: Int): String? {
        return addInteger(date, Calendar.HOUR_OF_DAY, hourAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„å°æ—¶ã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸ
     * @param hourAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ å°æ—¶åŽçš„æ—¥æœŸ
     */
    fun addHour(date: Date, hourAmount: Int): Date? {
        return addInteger(date, Calendar.HOUR_OF_DAY, hourAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„åˆ†é’Ÿã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸå­—符串
     * @param minuteAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ åˆ†é’ŸåŽçš„æ—¥æœŸå­—ç¬¦ä¸²
     */
    fun addMinute(date: String, minuteAmount: Int): String? {
        return addInteger(date, Calendar.MINUTE, minuteAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„åˆ†é’Ÿã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸ
     * @param minuteAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ åˆ†é’ŸåŽçš„æ—¥æœŸ
     */
    fun addMinute(date: Date, minuteAmount: Int): Date? {
        return addInteger(date, Calendar.MINUTE, minuteAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„ç§’é’Ÿã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸå­—符串
     * @param secondAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ ç§’é’ŸåŽçš„æ—¥æœŸå­—ç¬¦ä¸²
     */
    fun addSecond(date: String, secondAmount: Int): String? {
        return addInteger(date, Calendar.SECOND, secondAmount)
    }
    /**
     * å¢žåŠ æ—¥æœŸçš„ç§’é’Ÿã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸ
     * @param secondAmount å¢žåŠ æ•°é‡ã€‚å¯ä¸ºè´Ÿæ•°
     * @return å¢žåŠ ç§’é’ŸåŽçš„æ—¥æœŸ
     */
    fun addSecond(date: Date, secondAmount: Int): Date? {
        return addInteger(date, Calendar.SECOND, secondAmount)
    }
    /**
     * èŽ·å–æ—¥æœŸçš„å¹´ä»½ã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸå­—符串
     * @return å¹´ä»½
     */
    fun getYear(date: String): Int {
        return getYear(StringToDate(date))
    }
    /**
     * èŽ·å–æ—¥æœŸçš„å¹´ä»½ã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸ
     * @return å¹´ä»½
     */
    fun getYear(date: Date?): Int {
        return getInteger(date, Calendar.YEAR)
    }
    /**
     * èŽ·å–æ—¥æœŸçš„æœˆä»½ã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸå­—符串
     * @return æœˆä»½
     */
    fun getMonth(date: String): Int {
        return getMonth(StringToDate(date))
    }
    /**
     * èŽ·å–æ—¥æœŸçš„æœˆä»½ã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸ
     * @return æœˆä»½
     */
    fun getMonth(date: Date?): Int {
        return getInteger(date, Calendar.MONTH) + 1
    }
    /**
     * èŽ·å–æ—¥æœŸçš„å¤©æ•°ã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸå­—符串
     * @return å¤©
     */
    fun getDay(date: String): Int {
        return getDay(StringToDate(date))
    }
    /**
     * èŽ·å–æ—¥æœŸçš„å¤©æ•°ã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸ
     * @return å¤©
     */
    fun getDay(date: Date?): Int {
        return getInteger(date, Calendar.DATE)
    }
    /**
     * èŽ·å–æ—¥æœŸçš„å°æ—¶ã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸå­—符串
     * @return å°æ—¶
     */
    fun getHour(date: String): Int {
        return getHour(StringToDate(date))
    }
    /**
     * èŽ·å–æ—¥æœŸçš„å°æ—¶ã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸ
     * @return å°æ—¶
     */
    fun getHour(date: Date?): Int {
        return getInteger(date, Calendar.HOUR_OF_DAY)
    }
    /**
     * èŽ·å–æ—¥æœŸçš„åˆ†é’Ÿã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸå­—符串
     * @return åˆ†é’Ÿ
     */
    fun getMinute(date: String): Int {
        return getMinute(StringToDate(date))
    }
    /**
     * èŽ·å–æ—¥æœŸçš„åˆ†é’Ÿã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸ
     * @return åˆ†é’Ÿ
     */
    fun getMinute(date: Date?): Int {
        return getInteger(date, Calendar.MINUTE)
    }
    /**
     * èŽ·å–æ—¥æœŸçš„ç§’é’Ÿã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸå­—符串
     * @return ç§’é’Ÿ
     */
    fun getSecond(date: String): Int {
        return getSecond(StringToDate(date))
    }
    /**
     * èŽ·å–æ—¥æœŸçš„ç§’é’Ÿã€‚å¤±è´¥è¿”å›ž0。
     * @param date æ—¥æœŸ
     * @return ç§’é’Ÿ
     */
    fun getSecond(date: Date?): Int {
        return getInteger(date, Calendar.SECOND)
    }
    /**
     * èŽ·å–æ—¥æœŸ ã€‚默认yyyy-MM-dd格式。失败返回null。
     * @param date æ—¥æœŸå­—符串
     * @return æ—¥æœŸ
     */
    fun getDate(date: String): String? {
        return StringToString(date, DateStyle.YYYY_MM_DD)
    }
    /**
     * èŽ·å–æ—¥æœŸã€‚é»˜è®¤yyyy-MM-dd格式。失败返回null。
     * @param date æ—¥æœŸ
     * @return æ—¥æœŸ
     */
    fun getDate(date: Date?): String? {
        return DateToString(date, DateStyle.YYYY_MM_DD)
    }
    /**
     * èŽ·å–æ—¥æœŸçš„æ—¶é—´ã€‚é»˜è®¤HH:mm:ss格式。失败返回null。
     * @param date æ—¥æœŸå­—符串
     * @return æ—¶é—´
     */
    fun getTime(date: String): String? {
        return StringToString(date, DateStyle.HH_MM_SS)
    }
    /**
     * èŽ·å–æ—¥æœŸçš„æ—¶é—´ã€‚é»˜è®¤HH:mm:ss格式。失败返回null。
     * @param date æ—¥æœŸ
     * @return æ—¶é—´
     */
    fun getTime(date: Date): String? {
        return DateToString(date, DateStyle.HH_MM_SS)
    }
    /**
     * èŽ·å–æ—¥æœŸçš„æ˜ŸæœŸã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸå­—符串
     * @return æ˜ŸæœŸ
     */
    fun getWeek(date: String): Week? {
        var week: Week? = null
        val dateStyle = getDateStyle(date)
        if (dateStyle != null) {
            val myDate = StringToDate(date, dateStyle)
            week = getWeek(myDate)
        }
        return week
    }
    /**
     * èŽ·å–æ—¥æœŸçš„æ˜ŸæœŸã€‚å¤±è´¥è¿”å›žnull。
     * @param date æ—¥æœŸ
     * @return æ˜ŸæœŸ
     */
    fun getWeek(date: Date?): Week? {
        var week: Week? = null
        val calendar = Calendar.getInstance()
        calendar.time = date!!
        val weekNumber = calendar.get(Calendar.DAY_OF_WEEK) - 1
        when (weekNumber) {
            0 -> week = Week.SUNDAY
            1 -> week = Week.MONDAY
            2 -> week = Week.TUESDAY
            3 -> week = Week.WEDNESDAY
            4 -> week = Week.THURSDAY
            5 -> week = Week.FRIDAY
            6 -> week = Week.SATURDAY
        }
        return week
    }
    /**
     * èŽ·å–ä¸¤ä¸ªæ—¥æœŸç›¸å·®çš„å¤©æ•°
     * @param date æ—¥æœŸå­—符串
     * @param otherDate å¦ä¸€ä¸ªæ—¥æœŸå­—符串
     * @return ç›¸å·®å¤©æ•°ã€‚如果失败则返回-1
     */
    fun getIntervalDays(date: String, otherDate: String): Int {
        return getIntervalDays(StringToDate(date), StringToDate(otherDate))
    }
    /**
     * @param date æ—¥æœŸ
     * @param otherDate å¦ä¸€ä¸ªæ—¥æœŸ
     * @return ç›¸å·®å¤©æ•°ã€‚如果失败则返回-1
     */
    fun getIntervalDays(date: Date?, otherDate: Date?): Int {
        var num = -1
        val dateTmp = StringToDate(getDate(date), DateStyle.YYYY_MM_DD)
        val otherDateTmp = StringToDate(getDate(otherDate), DateStyle.YYYY_MM_DD)
        if (dateTmp != null && otherDateTmp != null) {
            val time = Math.abs(dateTmp.time - otherDateTmp.time)
            num = (time / (24 * 60 * 60 * 1000)).toInt()
        }
        return num
    }
    enum class DateStyle private constructor(val value: String, val isShowOnly: Boolean) {
        YYYYMMDD("yyyyMMdd", false),
        YYYY_MM("yyyy-MM", false),
        YYYY_MM_DD("yyyy-MM-dd", false),
        YYYY_MM_DD_HH("yyyyMMddHH", false),
        YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm", false),
        YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss", false),
        YYYY_MM_EN("yyyy/MM", false),
        YYYY_MM_DD_EN("yyyy/MM/dd", false),
        YYYY_MM_DD_HH_MM_EN("yyyy/MM/dd HH:mm", false),
        YYYY_MM_DD_HH_MM_SS_EN("yyyy/MM/dd HH:mm:ss", false),
        YYYY_MM_CN("yyyyå¹´MM月", false),
        YYYY_MM_DD_CN("yyyyå¹´MM月dd日", false),
        YYYY_MM_DD_HH_MM_CN("yyyyå¹´MM月dd日 HH:mm", false),
        YYYY_MM_DD_HH_MM_SS_CN("yyyyå¹´MM月dd日 HH:mm:ss", false),
        HH_MM("HH:mm", true),
        HH_MM_SS("HH:mm:ss", true),
        MM_DD("MM-dd", true),
        MM_DD_HH_MM("MM-dd HH:mm", true),
        MM_DD_HH_MM_SS("MM-dd HH:mm:ss", true),
        MM_DD_EN("MM/dd", true),
        MM_DD_HH_MM_EN("MM/dd HH:mm", true),
        MM_DD_HH_MM_SS_EN("MM/dd HH:mm:ss", true),
        MM_DD_CN("MM月dd日", true),
        MM_DD_HH_MM_CN("MM月dd日 HH:mm", true),
        MM_DD_HH_MM_SS_CN("MM月dd日 HH:mm:ss", true)
    }
    enum class Week private constructor(name_cn: String, name_en: String, name_enShort: String, number: Int) {
        MONDAY("星期一", "Monday", "Mon.", 1),
        TUESDAY("星期二", "Tuesday", "Tues.", 2),
        WEDNESDAY("星期三", "Wednesday", "Wed.", 3),
        THURSDAY("星期四", "Thursday", "Thur.", 4),
        FRIDAY("星期五", "Friday", "Fri.", 5),
        SATURDAY("星期六", "Saturday", "Sat.", 6),
        SUNDAY("星期日", "Sunday", "Sun.", 7);
        var chineseName: String
            internal set
        var aname: String
            internal set
        var shortName: String
            internal set
        var number: Int = 0
            internal set
        init {
            this.chineseName = name_cn
            this.aname = name_en
            this.shortName = name_enShort
            this.number = number
        }
    }
}
src/main/kotlin/com/flightfeather/uav/domain/entity/ElectricMinuteValue.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,229 @@
package com.flightfeather.uav.domain.entity;
import java.util.Date;
import javax.persistence.*;
@Table(name = "el_minutevalue")
public class ElectricMinuteValue {
    @Id
    @Column(name = "MV_ID")
    private Integer mvId;
    @Column(name = "MV_Stat_Code")
    private String mvStatCode;
    @Column(name = "MV_Create_Time")
    private Date mvCreateTime;
    @Column(name = "MV_Data_Time")
    private Date mvDataTime;
    @Column(name = "MV_Electricity_A")
    private Double mvElectricityA;
    @Column(name = "MV_Electricity_B")
    private Double mvElectricityB;
    @Column(name = "MV_Electricity_C")
    private Double mvElectricityC;
    @Column(name = "MV_Voltage_A")
    private Double mvVoltageA;
    @Column(name = "MV_Voltage_B")
    private Double mvVoltageB;
    @Column(name = "MV_Voltage_C")
    private Double mvVoltageC;
    @Column(name = "MV_Power_A")
    private Double mvPowerA;
    @Column(name = "MV_Power_B")
    private Double mvPowerB;
    @Column(name = "MV_Power_C")
    private Double mvPowerC;
    /**
     * @return MV_ID
     */
    public Integer getMvId() {
        return mvId;
    }
    /**
     * @param mvId
     */
    public void setMvId(Integer mvId) {
        this.mvId = mvId;
    }
    /**
     * @return MV_Stat_Code
     */
    public String getMvStatCode() {
        return mvStatCode;
    }
    /**
     * @param mvStatCode
     */
    public void setMvStatCode(String mvStatCode) {
        this.mvStatCode = mvStatCode == null ? null : mvStatCode.trim();
    }
    /**
     * @return MV_Create_Time
     */
    public Date getMvCreateTime() {
        return mvCreateTime;
    }
    /**
     * @param mvCreateTime
     */
    public void setMvCreateTime(Date mvCreateTime) {
        this.mvCreateTime = mvCreateTime;
    }
    /**
     * @return MV_Data_Time
     */
    public Date getMvDataTime() {
        return mvDataTime;
    }
    /**
     * @param mvDataTime
     */
    public void setMvDataTime(Date mvDataTime) {
        this.mvDataTime = mvDataTime;
    }
    /**
     * @return MV_Electricity_A
     */
    public Double getMvElectricityA() {
        return mvElectricityA;
    }
    /**
     * @param mvElectricityA
     */
    public void setMvElectricityA(Double mvElectricityA) {
        this.mvElectricityA = mvElectricityA;
    }
    /**
     * @return MV_Electricity_B
     */
    public Double getMvElectricityB() {
        return mvElectricityB;
    }
    /**
     * @param mvElectricityB
     */
    public void setMvElectricityB(Double mvElectricityB) {
        this.mvElectricityB = mvElectricityB;
    }
    /**
     * @return MV_Electricity_C
     */
    public Double getMvElectricityC() {
        return mvElectricityC;
    }
    /**
     * @param mvElectricityC
     */
    public void setMvElectricityC(Double mvElectricityC) {
        this.mvElectricityC = mvElectricityC;
    }
    /**
     * @return MV_Voltage_A
     */
    public Double getMvVoltageA() {
        return mvVoltageA;
    }
    /**
     * @param mvVoltageA
     */
    public void setMvVoltageA(Double mvVoltageA) {
        this.mvVoltageA = mvVoltageA;
    }
    /**
     * @return MV_Voltage_B
     */
    public Double getMvVoltageB() {
        return mvVoltageB;
    }
    /**
     * @param mvVoltageB
     */
    public void setMvVoltageB(Double mvVoltageB) {
        this.mvVoltageB = mvVoltageB;
    }
    /**
     * @return MV_Voltage_C
     */
    public Double getMvVoltageC() {
        return mvVoltageC;
    }
    /**
     * @param mvVoltageC
     */
    public void setMvVoltageC(Double mvVoltageC) {
        this.mvVoltageC = mvVoltageC;
    }
    /**
     * @return MV_Power_A
     */
    public Double getMvPowerA() {
        return mvPowerA;
    }
    /**
     * @param mvPowerA
     */
    public void setMvPowerA(Double mvPowerA) {
        this.mvPowerA = mvPowerA;
    }
    /**
     * @return MV_Power_B
     */
    public Double getMvPowerB() {
        return mvPowerB;
    }
    /**
     * @param mvPowerB
     */
    public void setMvPowerB(Double mvPowerB) {
        this.mvPowerB = mvPowerB;
    }
    /**
     * @return MV_Power_C
     */
    public Double getMvPowerC() {
        return mvPowerC;
    }
    /**
     * @param mvPowerC
     */
    public void setMvPowerC(Double mvPowerC) {
        this.mvPowerC = mvPowerC;
    }
}
src/main/kotlin/com/flightfeather/uav/domain/mapper/ElectricMinuteValueMapper.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.flightfeather.uav.domain.mapper
import com.flightfeather.uav.domain.MyMapper
import com.flightfeather.uav.domain.entity.ElectricMinuteValue
import org.apache.ibatis.annotations.Mapper
@Mapper
interface ElectricMinuteValueMapper : MyMapper<ElectricMinuteValue?>
src/main/kotlin/com/flightfeather/uav/repository/ElectricRepository.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.flightfeather.uav.repository
import com.flightfeather.uav.socket.bean.ElectricMessage
interface ElectricRepository {
    fun saveData(electricMessage: ElectricMessage): Int
}
src/main/kotlin/com/flightfeather/uav/repository/impl/ElectricDapImpl.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package com.flightfeather.uav.repository.impl
import com.flightfeather.uav.domain.entity.ElectricMinuteValue
import com.flightfeather.uav.domain.mapper.ElectricMinuteValueMapper
import com.flightfeather.uav.repository.ElectricRepository
import com.flightfeather.uav.socket.bean.ElectricMessage
import org.springframework.stereotype.Repository
import java.util.*
@Repository
class ElectricDapImpl(val electricMinuteValueMapper: ElectricMinuteValueMapper) : ElectricRepository {
    override fun saveData(electricMessage: ElectricMessage): Int {
        val minuteValue = ElectricMinuteValue().apply {
            mvStatCode = electricMessage.mn
            mvCreateTime = Date()
            mvDataTime = electricMessage.dataTime
            mvElectricityA = electricMessage.electricityA
            mvElectricityB = electricMessage.electricityB
            mvElectricityC = electricMessage.electricityC
            mvVoltageA = electricMessage.voltageA
            mvVoltageB = electricMessage.voltageB
            mvVoltageC = electricMessage.voltageC
            mvPowerA = electricMessage.powerA
            mvPowerB = electricMessage.powerB
            mvPowerC = electricMessage.powerC
        }
        return electricMinuteValueMapper.insert(minuteValue)
    }
}
src/main/kotlin/com/flightfeather/uav/socket/DeviceSession.kt
@@ -11,38 +11,38 @@
 */
class DeviceSession {
    companion object{
        private val deviceMap = ConcurrentHashMap<String, ChannelHandlerContext?>()
        private val typeMap = ConcurrentHashMap<String, List<AirTypeData>>()
    companion object {
        private const val DEFAULT_DEVICE = "default_device"
    }
    private val deviceMap = ConcurrentHashMap<String, ChannelHandlerContext?>()
    private val typeMap = ConcurrentHashMap<String, List<AirTypeData>>()
        fun saveDevice(deviceCode: String?, channel: ChannelHandlerContext?) {
            deviceCode?.let {
                deviceMap.put(deviceCode, channel)
            }
    fun saveDevice(deviceCode: String?, channel: ChannelHandlerContext?) {
        deviceCode?.let {
            deviceMap.put(deviceCode, channel)
        }
    }
        fun getDevice(deviceCode: String?): ChannelHandlerContext? {
            return if (deviceMap.containsKey(deviceCode))
                deviceMap[deviceCode]
            else
                null
    fun getDevice(deviceCode: String?): ChannelHandlerContext? {
        return if (deviceMap.containsKey(deviceCode))
            deviceMap[deviceCode]
        else
            null
    }
    fun saveAirType(deviceCode: String?, types: List<AirTypeData>) {
        if (deviceCode == null) {
            typeMap[DEFAULT_DEVICE] = types
        } else {
            typeMap[deviceCode] = types
        }
    }
        fun saveAirType(deviceCode: String?, types: List<AirTypeData>) {
            if (deviceCode == null) {
                typeMap[DEFAULT_DEVICE] = types
            } else {
                typeMap[deviceCode] = types
            }
        }
        fun getAirType(deviceCode: String?): List<AirTypeData>? {
            return when {
                deviceCode == null -> typeMap[DEFAULT_DEVICE]
                typeMap.containsKey(deviceCode) -> typeMap[deviceCode]
                else -> null
            }
    fun getAirType(deviceCode: String?): List<AirTypeData>? {
        return when {
            deviceCode == null -> typeMap[DEFAULT_DEVICE]
            typeMap.containsKey(deviceCode) -> typeMap[deviceCode]
            else -> null
        }
    }
}
src/main/kotlin/com/flightfeather/uav/socket/ServerHandler.kt
@@ -1,5 +1,6 @@
package com.flightfeather.uav.socket
import com.flightfeather.uav.socket.processor.BaseProcessor
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInboundHandlerAdapter
import io.netty.util.AttributeKey
@@ -8,57 +9,57 @@
import java.util.*
class ServerHandler : ChannelInboundHandlerAdapter() {
    companion object {
        private const val TAG = "UAV"
    }
class ServerHandler(private val processor: BaseProcessor) : ChannelInboundHandlerAdapter() {
    val attributeKey = AttributeKey.valueOf<String>("deviceCode")
    val messageManager = MessageManager()
    override fun channelRegistered(ctx: ChannelHandlerContext?) {
        super.channelRegistered(ctx)
        println()
        println("------${TAG}端口有IP连接:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        println("------【${processor.tag}】IP连接:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
//        ctx?.fireChannelActive()
    }
    override fun channelActive(ctx: ChannelHandlerContext?) {
        println()
        println("------${TAG}端口有IP激活:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        println("------【${processor.tag}】IP激活:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        super.channelActive(ctx)
    }
    override fun channelRead(ctx: ChannelHandlerContext?, msg: Any?) {
        super.channelRead(ctx, msg)
        println("------【${processor.tag}】收到的原始数据:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        val sb = StringBuilder()
        var str = ""
        if (msg is ByteArray) {
            println()
            println("------${TAG}收到的原始数据:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
            msg.forEach {
                val a: Int = if (it < 0) {
                    it + 256
                } else {
                    it.toInt()
        when (msg) {
            is ByteArray -> {
                val sb = StringBuilder()
                msg.forEach {
                    var a = 0
                    a = if (it < 0) {
                        it + 256
                    } else {
                        it.toInt()
                    }
                    val s = if (a < 16) {
                        "0${a.toString(16)}"
                    } else {
                        a.toString(16)
                    }
                    sb.append(s).append(" ")
                }
                val s = if (a < 16) {
                    "0${a.toString(16)}"
                } else {
                    a.toString(16)
                }
                print("$s ")
                sb.append(s).append(" ")
                sb.deleteCharAt(sb.length - 1)
                str = sb.toString()
            }
            sb.deleteCharAt(sb.length - 1)
        }
        val str = sb.toString()
        if (str.isNotEmpty()) {
            messageManager.dealStringMsg(str, ctx)
            is String -> str = msg
        }
        println(str)
        if (str.isNotEmpty()) {
            processor.dealStringMsg(str, ctx)
        }
    }
    override fun channelReadComplete(ctx: ChannelHandlerContext?) {
@@ -66,7 +67,7 @@
    }
    override fun channelInactive(ctx: ChannelHandlerContext?) {
        println("------${TAG}端口有IP不活动:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        println("------【${processor.tag}】端口有IP不活动:[ip:${ctx?.channel()?.remoteAddress()}] ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}")
        super.channelInactive(ctx)
    }
src/main/kotlin/com/flightfeather/uav/socket/UAVByteDataDecoder.kt
@@ -1,10 +1,9 @@
package com.flightfeather.uav.socket
import com.flightfeather.uav.socket.decoder.impl.DataPackageDecoderImpl
import com.flightfeather.uav.socket.decoder.DataPackageDecoder
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.ByteToMessageDecoder
import java.lang.StringBuilder
/**
 * @author riku
@@ -14,13 +13,13 @@
class UAVByteDataDecoder : ByteToMessageDecoder() {
    companion object {
        const val BASE_LENGTH = DataPackageDecoderImpl.HEAD_BYTES + DataPackageDecoderImpl.COMMAND_UNIT_BYTES +
                DataPackageDecoderImpl.DEVICE_CODE_BYTES + DataPackageDecoderImpl.DATA_LENGTH + DataPackageDecoderImpl.BCC_BYTES
        const val BASE_LENGTH = DataPackageDecoder.HEAD_BYTES + DataPackageDecoder.COMMAND_UNIT_BYTES +
                DataPackageDecoder.DEVICE_CODE_BYTES + DataPackageDecoder.DATA_LENGTH + DataPackageDecoder.BCC_BYTES
        const val HEAD1 = 0x01.toByte()
        const val COMMAND_1 = 0x01.toByte()
        const val COMMAND_2 = 0x01.toByte()
        const val HEAD_LENGTH = DataPackageDecoderImpl.HEAD_BYTES + DataPackageDecoderImpl.COMMAND_UNIT_BYTES +
                DataPackageDecoderImpl.DEVICE_CODE_BYTES
        const val HEAD_LENGTH = DataPackageDecoder.HEAD_BYTES + DataPackageDecoder.COMMAND_UNIT_BYTES +
                DataPackageDecoder.DEVICE_CODE_BYTES
    }
    override fun decode(p0: ChannelHandlerContext?, p1: ByteBuf?, p2: MutableList<Any>?) {
@@ -74,14 +73,14 @@
                //数据单元的长度
                val length = getDataUnitLength(it, dataList)
                // åˆ¤æ–­è¯·æ±‚数据单元数据及[LENGTH_BYTES]个字节的校验码是否到齐
                if (it.readableBytes() < length + DataPackageDecoderImpl.BCC_BYTES) {
                if (it.readableBytes() < length + DataPackageDecoder.BCC_BYTES) {
                    // è¿˜åŽŸè¯»æŒ‡é’ˆ
                    it.readerIndex(beginReader)
                    return
                }
                //读取数据单元和校验码数据
                ByteArray(length + DataPackageDecoderImpl.BCC_BYTES).apply {
                ByteArray(length + DataPackageDecoder.BCC_BYTES).apply {
                    it.readBytes(this)
                }.forEach {b ->
                    dataList.add(b)
src/main/kotlin/com/flightfeather/uav/socket/UnderwaySocketServer.kt
@@ -1,11 +1,14 @@
package com.flightfeather.uav.socket
import com.flightfeather.uav.socket.processor.BaseProcessor
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.ChannelHandler
import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.handler.codec.LineBasedFrameDecoder
import io.netty.handler.codec.string.StringDecoder
import io.netty.handler.codec.string.StringEncoder
import java.nio.charset.Charset
@@ -19,8 +22,12 @@
    private val bossGroup = NioEventLoopGroup()
    private val workerGroup = NioEventLoopGroup()
    fun startServer(port: Int) {
        initialize()?.bind(port)?.sync()
    fun startUnderwayServer(port: Int, processor: BaseProcessor) {
        underwayServer(processor)?.bind(port)?.sync()
    }
    fun startElectricServer(port: Int, processor: BaseProcessor) {
        electricServer(processor)?.bind(port)?.sync()
    }
    fun stopServer() {
@@ -28,28 +35,44 @@
        workerGroup.shutdownGracefully()
    }
    private fun initialize(): ServerBootstrap? {
    private fun newServer(childHandler: ChannelHandler): ServerBootstrap? {
        try {
            return ServerBootstrap()
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel::class.java)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childHandler(object : ChannelInitializer<NioSocketChannel>() {
                        override fun initChannel(p0: NioSocketChannel?) {
                            p0?.pipeline()
//                                    ?.addLast("decoder", StringDecoder())
                                    ?.addLast(UAVByteDataDecoder())
                                    ?.addLast("encoder", StringEncoder(Charset.forName("UTF-8")))
                                    ?.addLast(ServerHandler())
                        }
                    })
                .group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel::class.java)
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childHandler(childHandler)
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return null
    }
    /**
     * ç”¨ç”µé‡æœåŠ¡ç«¯
     */
    private fun electricServer(processor: BaseProcessor): ServerBootstrap? = newServer(object : ChannelInitializer<NioSocketChannel>() {
        override fun initChannel(p0: NioSocketChannel?) {
            p0?.pipeline()
                ?.addLast("lineDecoder", LineBasedFrameDecoder(1024))
                ?.addLast("stringDecoder", StringDecoder())
                ?.addLast("encoder", StringEncoder(Charset.forName("UTF-8")))
                ?.addLast(ServerHandler(processor))
        }
    })
    /**
     * å¤šå‚数走航服务端
     */
    private fun underwayServer(processor: BaseProcessor):ServerBootstrap? = newServer(object : ChannelInitializer<NioSocketChannel>() {
        override fun initChannel(p0: NioSocketChannel?) {
            p0?.pipeline()
                ?.addLast(UAVByteDataDecoder())
                ?.addLast("encoder", StringEncoder(Charset.forName("UTF-8")))
                ?.addLast(ServerHandler(processor))
        }
    })
}
src/main/kotlin/com/flightfeather/uav/socket/bean/BaseDataPackage.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,4 @@
package com.flightfeather.uav.socket.bean
open class BaseDataPackage {
}
src/main/kotlin/com/flightfeather/uav/socket/bean/BaseMessage.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
package com.flightfeather.uav.socket.bean
import java.text.SimpleDateFormat
import java.util.*
/**
 * @author riku
 * Date: 2020/9/10
 */
open class BaseMessage {
    var head: String = ""
    var length: String = ""
    var qn: String = ""
    var st: String = ""
    var cn: String = ""
    var pw: String = ""
    var mn: String = ""
    var flag: String = ""
    var cp: String = ""
    var extra: String = ""
    var crc: String = ""
    open fun newMessage() {
        head = "##"
        qn = SimpleDateFormat("yyyyMMddHHmmssSSS", Locale.getDefault()).format(Date())
    }
    fun parse2Str():String {
        val str = "QN=$qn;ST=$st;CN=$cn;PW=$pw;MN=$mn;Flag=$flag;CP=&&${cp}&&$extra"
        return "$head${getLength(str.length)}$str${getCrc(str.toByteArray(), str.length)}\r\n"
    }
    /**
     * crc计算工具类
     * @param bufData æ•°æ®æ®µå­—符串转化的byte[],
     * @param bufLen çš„长度
     * @return CRC码:4字节
     */
    fun getCrc(bufData: ByteArray, bufLen: Int): String? {
        var crc = 0x0000ffff
        val polynomial = 0x0000a001
        var j: Int
        if (bufLen == 0) {
            return null
        }
        var i: Int = 0
        while (i < bufLen) {
            crc = crc xor (bufData[i].toInt() and 0x000000ff)
            j = 0
            while (j < 8) {
                if (crc and 0x00000001 != 0) {
                    crc = crc shr 1
                    crc = crc xor polynomial
                } else {
                    crc = crc shr 1
                }
                j++
            }
            i++
        }
        var strCRC = Integer.toHexString(crc).toString()
        if (strCRC.length < 4) {
            strCRC += "0"
        }
        return strCRC
    }
    fun getLength(length: Int): String {
        val size = StringBuilder()
        when {
            length >= 100 -> {
                size.append("0")
            }
            length >= 10 -> {
                size.append("00")
            }
            length >= 0 -> {
                size.append("000")
            }
        }
        size.append(length)
        return size.toString()
    }
}
src/main/kotlin/com/flightfeather/uav/socket/bean/ElectricMessage.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.flightfeather.uav.socket.bean
import java.util.*
class ElectricMessage : BaseMessage() {
    var dataTime: Date? = null
    var electricityA: Double = -1.0
    var electricityB: Double = -1.0
    var electricityC: Double = -1.0
    var voltageA: Double = -1.0
    var voltageB: Double = -1.0
    var voltageC: Double = -1.0
    var powerA: Double = -1.0
    var powerB: Double = -1.0
    var powerC: Double = -1.0
}
src/main/kotlin/com/flightfeather/uav/socket/decoder/AirDataDecoder.kt
@@ -1,7 +1,6 @@
package com.flightfeather.uav.socket.decoder
import com.flightfeather.uav.socket.bean.AirDataPackage
import com.flightfeather.uav.socket.decoder.impl.DataPackageDecoderImpl
/**
 * ç©ºæ°”质量多参数数据解码器
@@ -29,7 +28,7 @@
            }
    }
    private val dataPackageDecoder: DataPackageDecoder = DataPackageDecoderImpl()
    private val dataPackageDecoder: DataPackageDecoder = DataPackageDecoder()
    fun decode(msg: String): AirDataPackage {
        val list = dataPackageDecoder.toStringList(msg)
src/main/kotlin/com/flightfeather/uav/socket/decoder/BaseDataDecoder.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,109 @@
package com.flightfeather.uav.socket.decoder
import com.flightfeather.uav.common.utils.CommonUtil
import com.flightfeather.uav.socket.bean.BaseMessage
import java.text.SimpleDateFormat
import java.util.*
/**
 * @author riku
 * Date: 2020/9/10
 */
typealias Decode<T> = (m: T, s: String) -> Unit
abstract class BaseDataDecoder<T : BaseMessage> {
    companion object {
        const val INVALID_VALUE = -1.0
    }
    private var isInit = false
    private lateinit var message: T
    abstract fun messageClass(): Class<T>
    abstract fun getCpDecode(): List<Decode<T>>
    private val decodeList = mutableListOf<Decode<T>>()
    private val getHead: Decode<T> = {m, s ->
        m.head = s.substring(0, 2)
    }
    private val getLength: Decode<T> = {m, s ->
        m.length = s.substring(2, 6)
    }
    private val getQN: Decode<T> = {m, s ->
        m.qn = getData(s, "QN=", ";")
    }
    private val getST: Decode<T> = {m, s ->
        m.st = getData(s, "ST=", ";")
    }
    private val getCN: Decode<T> = {m, s ->
        m.cn = getData(s, "CN=", ";")
    }
    private val getPW: Decode<T> = {m, s ->
        m.pw = getData(s, "PW=", ";")
    }
    private val getMN: Decode<T> = {m, s ->
        m.mn = getData(s, "MN=", ";")
    }
    private val getCP: Decode<T> = {m, s ->
        m.cp = getData(s, "CP=&&", "&&")
    }
    private val getExtra:Decode<T> = {m, s ->
        val start = s.lastIndexOf("&&")
        val end = s.length - 4
        m.extra = s.substring(start, end).substring(2)
    }
    private val getCrc: Decode<T> = {m, s ->
        m.crc = s.substring(s.length - 4, s.length)
    }
    protected fun getData(msg: String, start: String, end: String) =
            CommonUtil.getSubStr(msg, start, end)?.substring(start.length) ?: ""
    private fun init() {
        if (!isInit) {
            decodeList.add(getHead)
            decodeList.add(getLength)
            decodeList.add(getQN)
            decodeList.add(getST)
            decodeList.add(getCN)
            decodeList.add(getPW)
            decodeList.add(getMN)
            decodeList.add(getCP)
            decodeList.add(getExtra)
            decodeList.add(getCrc)
            decodeList.addAll(this.getCpDecode())
            isInit = true
        }
        message = this.messageClass().newInstance()
    }
    fun decode(msg: String): T {
        init()
        decodeList.forEach {
            try {
                it.invoke(message, msg)
            } catch (e: Exception) {
                println("${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}: å‘½ä»¤æ— æ³•获取[${it.javaClass.name}]")
            }
        }
        return message
    }
}
src/main/kotlin/com/flightfeather/uav/socket/decoder/DataPackageDecoder.kt
@@ -16,22 +16,103 @@
 * 2                   æ•°æ®å•元长度
 * å€’数第2           æ ¡éªŒç 
 */
interface DataPackageDecoder {
class DataPackageDecoder {
    fun getHead(b: List<String>): String?
    companion object {
        //        æ•°æ®å¤´
        const val HEAD_BYTES = 1
        //        ç›‘测参数确认指令位
        const val COMMAND_UNIT_BYTES = 1
        //        è®¾å¤‡ç±»åž‹
        const val DEVICE_CODE_BYTES = 6
        //        æœ¬æ¬¡ç›‘测的空气因子数量
        const val DATA_LENGTH = 1
        //        æ ¡éªŒ
        const val BCC_BYTES = 2
    }
    fun getCommandUnit(b: List<String>): Int?
    private val dataUnitDecoder: DataUnitDecoder = DataUnitDecoder()
    fun getDeviceCode(b: List<String>): String?
    fun getDataTime(b: List<String>): Date
    fun getHead(b: List<String>): String? {
        return if (b.isNotEmpty()) {
            val s = StringBuilder()
            repeat(HEAD_BYTES) {
                s.append(b[it])
            }
            s.toString()
        } else {
            null
        }
    }
    fun getDataLength(b: List<String>): Int
    fun getCommandUnit(b: List<String>): Int? = if (b.size >= (HEAD_BYTES + COMMAND_UNIT_BYTES)) {
        val s = StringBuilder()
        repeat(COMMAND_UNIT_BYTES) {
            s.append(b[HEAD_BYTES + it])
        }
        s.toString().toIntOrNull(16)
    } else {
        null
    }
    fun getDataUnit(b: List<String>): List<DataUnit>
    fun getDeviceCode(b: List<String>): String? = if (b.size >= (HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES)) {
        //2021/1/7 '0A'代表车载设备,'0B'代表无人机设备,'0C'为网格化监测
        val s = StringBuilder()
        repeat(DEVICE_CODE_BYTES) {
            s.append(b[HEAD_BYTES + COMMAND_UNIT_BYTES + it])
        }
        s.toString()
    } else {
        null
    }
    fun getCheckCode(b: List<String>): Int?
    fun getDataTime(b: List<String>): Date {
        // FIXME: 2021/1/7 é‡‡æ ·æ—¶é—´å’Œç›‘测因子一同放在了数据部分,此处不再做解析
        return Date()
    }
    fun toStringList(msg: String): List<String>
    fun getDataLength(b: List<String>): Int {
        if (b.size <= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH) return 0
        val hexNum = b[HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES]
        return hexNum.toIntOrNull(16) ?: 0
    }
    fun getDataUnit(b: List<String>): List<DataUnit> {
        if (getDataLength(b) == 0 || b.size <= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH) {
            return emptyList()
        }
        val unit = mutableListOf<String>()
        val start = HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + DATA_LENGTH
        for (i in start..b.size - 1 - BCC_BYTES) {
            unit.add(b[i])
        }
        dataUnitDecoder.run {
            return when (getCommandUnit(b)) {
                AirCommandUnit.Confirm.value -> getAirConfirmData(unit, getDeviceCode(b))
                AirCommandUnit.AirData.value -> getAirData(unit, getDeviceCode(b))
                else -> emptyList()
            }
        }
    }
    fun getCheckCode(b: List<String>): Int? {
        return if (b.size >= HEAD_BYTES + COMMAND_UNIT_BYTES + DEVICE_CODE_BYTES + BCC_BYTES) {
            val hexNum = "${b[b.size - 2]}${b[b.size - 1]}"
            hexNum.toIntOrNull(16)
        } else {
            null
        }
    }
    fun toStringList(msg: String): List<String> {
        return msg.split(" ")
    }
}
src/main/kotlin/com/flightfeather/uav/socket/decoder/DataUnitDecoder.kt
@@ -2,6 +2,9 @@
import com.flightfeather.uav.socket.bean.*
import com.flightfeather.uav.socket.eunm.AirCommandUnit
import com.flightfeather.uav.socket.eunm.FactorType
import org.slf4j.LoggerFactory
import java.text.SimpleDateFormat
import java.util.*
/**
@@ -12,10 +15,160 @@
 * æ•°æ®å•元按照命令单元的类型共有以下几种类型:
 * å‘½ä»¤å•å…ƒ @see [AirCommandUnit]
 */
interface DataUnitDecoder {
class DataUnitDecoder {
    fun getAirConfirmData(b: List<String>, deviceCode: String?): List<AirTypeData>
    private val logger = LoggerFactory.getLogger(javaClass.name)
    fun getAirData(b: List<String>, deviceCode: String?): List<AirData>
    private val types = mutableMapOf<String?, MutableList<AirTypeData>>()
    fun getAirConfirmData(b: List<String>, deviceCode: String?): List<AirTypeData> {
        val resultList = mutableListOf<AirTypeData>()
        b.forEach {
            FactorType.getByIndex(it.toInt(16))?.let { f->
                resultList.add(AirTypeData(f))
            }
        }
        if (!types.containsKey(deviceCode)) {
            types[deviceCode] = mutableListOf()
        }
        types[deviceCode]?.clear()
        types[deviceCode]?.addAll(resultList)
        return resultList
    }
    fun getAirData(b: List<String>, deviceCode: String?): List<AirData> {
        val resultList = mutableListOf<AirData>()
        if (!types.containsKey(deviceCode)) {
            return resultList
        }
        var i = 0
        types[deviceCode]?.forEach {
            if (i > b.size - it.factorType.byteLength) {
                return@forEach
            }
            when (it.factorType) {
                FactorType.LNG -> {
                    val valid = b[i].toInt(16).toChar()//经纬度是否有效(有效: A; æ— æ•ˆ: V)
                    //经纬度原始值,例:121°30.0411′,其中 121 å¯¹åº”a1,30对应b1,04对应b2,11对应b3
                    val a1 = b[i + 1].toInt(16)//度
                    val b1 = b[i + 2].toInt(16)//分(整数)
                    var b2 = b[i + 3].toInt(16).toDouble()//分(小数部分前两位)
                    var b3 = b[i + 4].toInt(16).toDouble()//分(小数部分后两位)
//                    var b2 = "${b[i + 3]}${b[i + 4]}".toInt(16).toDouble()
                    b2 /= 100
                    b3 /= 10000
                    val lng = a1 + (b1 + b2 + b3) / 60
                    val s = b[i + 5].toInt(16).toChar()
                    resultList.add(AirData().apply {
                        factorId = it.factorType.value?.toString()
                        factorName = it.factorType.des
                        factorData = lng
                        statusList = listOf(valid.toString(), s.toString())
                    })
                }
                FactorType.LAT -> {
                    val a1 = b[i].toInt(16)
                    val b1 = b[i + 1].toInt(16)
                    var b2 = b[i + 2].toInt(16).toDouble()//分(小数部分前两位)
                    var b3 = b[i + 3].toInt(16).toDouble()//分(小数部分后两位)
                    b2 /= 100
                    b3 /= 10000
                    val lat = a1 + (b1 + b2 + b3) / 60
                    val s = b[i + 4].toInt(16).toChar()
                    resultList.add(AirData().apply {
                        factorId = it.factorType.value.toString()
                        factorName = it.factorType.des
                        factorData = lat
                        statusList = listOf(s.toString())
                    })
                }
                FactorType.TIME -> {
                    val year = b[i].toInt(16).toString().run { numberFormat(this) }
                    val month = b[i + 1].toInt(16).toString().run { numberFormat(this) }
                    val day = b[i + 2].toInt(16).toString().run { numberFormat(this) }
                    val hour = b[i + 3].toInt(16).toString().run { numberFormat(this) }
                    val minute = b[i + 4].toInt(16).toString().run { numberFormat(this) }
                    val second = b[i + 5].toInt(16).toString().run { numberFormat(this) }
                    val date = "20$year-$month-$day $hour:$minute:$second"
                    val time = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date).time
                    resultList.add(AirData().apply {
                        factorId = it.factorType.value.toString()
                        factorName = it.factorType.des
                        factorData = time.toDouble()
                        statusList = listOf(date)
                    })
                }
                else -> {
                    when (it.factorType.byteLength) {
                        AirDataPackage.FACTOR_BIT_LENGTH_2 -> {
                            val a1 = "${b[i]}${b[i + 1]}".toInt(16)
                            var b1 = b[i + 2].toInt(16).toDouble()
                            while (b1 >= 1) {
                                b1 /= 10
                            }
                            val data1 = a1 + b1
                            resultList.add(AirData().apply {
                                factorId = it.factorType.value?.toString()
                                factorName = it.factorType.des
                                factorData = data1
                            })
                        }
                        AirDataPackage.FACTOR_BIT_LENGTH_1 -> {
                            //数据实际值(3位字节表示)
                            val a1 = "${b[i]}${b[i + 1]}".toInt(16)
                            var b1 = b[i + 2].toInt(16).toDouble()
                            while (b1 >= 1) {
                                b1 /= 10
                            }
                            val data1 = a1 + b1
                            //数据物理量(3位字节表示)
                            val a2 = "${b[i+3]}${b[i + 4]}".toInt(16)
                            var b2 = b[i + 5].toInt(16).toDouble()
                            while (b2 >= 1) {
                                b2 /= 10
                            }
                            val data2 = a2 + b2
                            resultList.add(AirData().apply {
                                factorId = it.factorType.value?.toString()
                                factorName = it.factorType.des
                                factorData = data1
                                physicalQuantity = data2
                            })
                        }
                        AirDataPackage.FACTOR_BIT_LENGTH_3 -> {
                            val data = "${b[i]}${b[i + 1]}".toInt(16)
                            resultList.add(AirData().apply {
                                factorId = it.factorType.value.toString()
                                factorName = it.factorType.des
                                factorData = data.toDouble()
                            })
                        }
                    }
                }
            }
            i += it.factorType.byteLength
        }
        return resultList
    }
    private fun numberFormat(num: String) =
        if (num.length < 2) {
            "0$num"
        } else {
            num
        }
}
src/main/kotlin/com/flightfeather/uav/socket/decoder/ElectricDataDecoder.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
package com.flightfeather.uav.socket.decoder
import com.flightfeather.uav.common.utils.DateUtil
import com.flightfeather.uav.socket.bean.ElectricMessage
import org.springframework.stereotype.Component
@Component
class ElectricDataDecoder:BaseDataDecoder<ElectricMessage>() {
    private val dateUtil = DateUtil()
    override fun messageClass(): Class<ElectricMessage> = ElectricMessage::class.java
    override fun getCpDecode(): List<Decode<ElectricMessage>> = listOf(
        getDataTime,
        getElectricityA, getElectricityB, getElectricityC,
        getVoltageA, getVoltageB, getVoltageC,
        getPowerA, getPowerB, getPowerC
    )
    private val getDataTime: Decode<ElectricMessage> = { e, s ->
        val time = getData(s, "DataTime=", ";")
        time.let {
            val date = if (it.length > "yyyyMMddHHmmss".length) {
                dateUtil.StringToDate(it, "yyyyMMddHHmmssSSS")
            } else {
                dateUtil.StringToDate(it, "yyyyMMddHHmmss")
            }
            e.dataTime = date
        }
    }
    private val getElectricityA: Decode<ElectricMessage> = { e, s ->
        getData(s, "550-Rtd=", ";").let {
            e.electricityA = it.toDoubleOrNull() ?: INVALID_VALUE
        }
    }
    private val getElectricityB: Decode<ElectricMessage> = { e, s ->
        getData(s, "551-Rtd=", ";").let {
            e.electricityB = it.toDoubleOrNull() ?: INVALID_VALUE
        }
    }
    private val getElectricityC: Decode<ElectricMessage> = { e, s ->
        getData(s, "552-Rtd=", ";").let {
            e.electricityC = it.toDoubleOrNull() ?: INVALID_VALUE
        }
    }
    private val getVoltageA: Decode<ElectricMessage> = { e, s ->
        getData(s, "553-Rtd=", ";").let {
            e.voltageA = it.toDoubleOrNull() ?: INVALID_VALUE
        }
    }
    private val getVoltageB: Decode<ElectricMessage> = { e, s ->
        getData(s, "554-Rtd=", ";").let {
            e.voltageB = it.toDoubleOrNull() ?: INVALID_VALUE
        }
    }
    private val getVoltageC: Decode<ElectricMessage> = { e, s ->
        getData(s, "555-Rtd=", ";").let {
            e.voltageC = it.toDoubleOrNull() ?: INVALID_VALUE
        }
    }
    private val getPowerA: Decode<ElectricMessage> = { e, s ->
        getData(s, "556-Rtd=", ";").let {
            e.powerA = it.toDoubleOrNull() ?: INVALID_VALUE
        }
    }
    private val getPowerB: Decode<ElectricMessage> = { e, s ->
        getData(s, "557-Rtd=", ";").let {
            e.powerB = it.toDoubleOrNull() ?: INVALID_VALUE
        }
    }
    private val getPowerC: Decode<ElectricMessage> = { e, s ->
        getData(s, "558-Rtd=", ";").let {
            e.powerC = it.toDoubleOrNull() ?: INVALID_VALUE
        }
    }
}
src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataPackageDecoderImpl.kt
ÎļþÒÑɾ³ý
src/main/kotlin/com/flightfeather/uav/socket/decoder/impl/DataUnitDecoderImpl.kt
ÎļþÒÑɾ³ý
src/main/kotlin/com/flightfeather/uav/socket/processor/BaseProcessor.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.flightfeather.uav.socket.processor
import com.flightfeather.uav.common.utils.FileUtil
import com.flightfeather.uav.socket.DeviceSession
import io.netty.channel.ChannelHandlerContext
import java.text.SimpleDateFormat
import java.util.*
abstract class BaseProcessor {
    abstract var tag: String
    val deviceSession = DeviceSession()
    abstract fun dealStringMsg(msg: String, ctx: ChannelHandlerContext?)
    /**
     * ä¿å­˜è‡³txt文本
     */
    fun saveToTxt(msg: String) {
        val data = "[${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}]data=> $msg"
        FileUtil.instance?.saveObdData(data)
    }
}
src/main/kotlin/com/flightfeather/uav/socket/processor/ElectricProcessor.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
package com.flightfeather.uav.socket.processor
import com.flightfeather.uav.repository.ElectricRepository
import com.flightfeather.uav.socket.bean.BaseMessage
import com.flightfeather.uav.socket.bean.ElectricMessage
import com.flightfeather.uav.socket.decoder.ElectricDataDecoder
import io.netty.channel.ChannelHandlerContext
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import javax.annotation.PostConstruct
/**
 * å¤„理用电量socket接收的消息
 * @author riku
 */
@Component
class ElectricProcessor() : BaseProcessor() {
    companion object {
        private lateinit var instance: ElectricProcessor
    }
    @Autowired
    lateinit var electricRepository: ElectricRepository
    @Autowired
    lateinit var electricDataDecoder: ElectricDataDecoder
    @PostConstruct
    fun init() {
        instance = this
    }
    override var tag: String = "用电量"
    override fun dealStringMsg(msg: String, ctx: ChannelHandlerContext?) {
        //解包
        val packageData = electricDataDecoder.decode(msg)
        deviceSession.saveDevice(packageData.mn, ctx)
        saveToTxt(msg)
        saveToDataBase(packageData, msg)
    }
    private fun saveToDataBase(message: BaseMessage, msg: String) {
        if (message is ElectricMessage) {
            instance.electricRepository.saveData(message)
        }
    }
}
src/main/kotlin/com/flightfeather/uav/socket/processor/UnderwayProcessor.kt
ÎļþÃû´Ó src/main/kotlin/com/flightfeather/uav/socket/MessageManager.kt ÐÞ¸Ä
@@ -1,10 +1,9 @@
package com.flightfeather.uav.socket
package com.flightfeather.uav.socket.processor
import com.flightfeather.uav.common.utils.FileUtil
import com.flightfeather.uav.repository.*
import com.flightfeather.uav.socket.bean.*
import com.flightfeather.uav.repository.AirDataRepository
import com.flightfeather.uav.socket.bean.AirDataPackage
import com.flightfeather.uav.socket.decoder.AirDataDecoder
import com.flightfeather.uav.socket.decoder.impl.DataPackageDecoderImpl
import com.flightfeather.uav.socket.decoder.DataPackageDecoder
import com.flightfeather.uav.socket.eunm.AirCommandUnit
import io.netty.channel.ChannelHandlerContext
import org.springframework.beans.factory.annotation.Autowired
@@ -20,10 +19,10 @@
 */
@Component
class MessageManager{
class UnderwayProcessor : BaseProcessor() {
    companion object{
        private lateinit var instance: MessageManager
    companion object {
        private lateinit var instance: UnderwayProcessor
        private const val TAG = "UAV"
    }
@@ -32,35 +31,27 @@
    lateinit var airDataRepository: AirDataRepository
    val airDataDecoder = AirDataDecoder.instance
    val dataPackageDecoder = DataPackageDecoderImpl()
    val dataPackageDecoder = DataPackageDecoder()
    @PostConstruct
    fun init() {
        instance = this
        airDataRepository = this.airDataRepository
    }
    fun dealStringMsg(msg: String, ctx: ChannelHandlerContext?) {
    override var tag: String = "走航监测"
    override fun dealStringMsg(msg: String, ctx: ChannelHandlerContext?) {
        //解包
        val packageData = airDataDecoder.decode(msg)
        if (bccCheck(msg)) {
            //保存
            DeviceSession.saveDevice(packageData.deviceCode, ctx)
            deviceSession.saveDevice(packageData.deviceCode, ctx)
            saveToTxt(msg)
            saveToDataBase(packageData)
        } else {
            println("------${TAG}数据BCC校验失败,舍弃 [${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}]")
        }
    }
    /**
     * ä¿å­˜è‡³txt文本
     */
    fun saveToTxt(msg: String) {
        val data = "[${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())}]data=> $msg"
        FileUtil.instance?.saveObdData(data)
    }
    /**
@@ -75,7 +66,7 @@
    /**
     * BCC(异或校验)
     */
    fun bccCheck(msg: String):Boolean {
    fun bccCheck(msg: String): Boolean {
        val list = mutableListOf<String>().apply {
            addAll(dataPackageDecoder.toStringList(msg))
        }
@@ -97,11 +88,11 @@
    }
    fun encodeToBytes(msg:String): ByteArray {
    fun encodeToBytes(msg: String): ByteArray {
        val list = msg.split(" ")
        val bytes = ByteArray(list.size)
        for (i in 0 until list.size) {
            bytes[i]=list[i].toInt(16).toByte()
            bytes[i] = list[i].toInt(16).toByte()
        }
        return bytes
src/main/resources/application.yml
@@ -8,6 +8,10 @@
    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
#    url: jdbc:mysql://localhost:3306/dronemonitor?serverTimezone=Asia/Shanghai&prepStmtCacheSize=517&cachePrepStmts=true&autoReconnect=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
#    username: root
#    password: 123456
    hikari:
      maximum-pool-size: 500
      minimum-idle: 20
src/main/resources/generator/generatorConfig.xml
@@ -46,6 +46,7 @@
        </javaClientGenerator>
        <!-- è¦ç”Ÿæˆçš„表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
<!--        <table tableName="air_real_time_data" domainObjectName="RealTimeData" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
        <table tableName="mission" domainObjectName="Mission" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
<!--        <table tableName="mission" domainObjectName="Mission" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>-->
        <table tableName="el_minutevalue" domainObjectName="ElectricMinuteValue" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"/>
    </context>
</generatorConfiguration>
src/main/resources/mapper/ElectricMinuteValueMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.flightfeather.uav.domain.mapper.ElectricMinuteValueMapper">
  <resultMap id="BaseResultMap" type="com.flightfeather.uav.domain.entity.ElectricMinuteValue">
    <!--
      WARNING - @mbg.generated
    -->
    <id column="MV_ID" jdbcType="INTEGER" property="mvId" />
    <result column="MV_Stat_Code" jdbcType="VARCHAR" property="mvStatCode" />
    <result column="MV_Create_Time" jdbcType="TIMESTAMP" property="mvCreateTime" />
    <result column="MV_Data_Time" jdbcType="TIMESTAMP" property="mvDataTime" />
    <result column="MV_Electricity_A" jdbcType="DOUBLE" property="mvElectricityA" />
    <result column="MV_Electricity_B" jdbcType="DOUBLE" property="mvElectricityB" />
    <result column="MV_Electricity_C" jdbcType="DOUBLE" property="mvElectricityC" />
    <result column="MV_Voltage_A" jdbcType="DOUBLE" property="mvVoltageA" />
    <result column="MV_Voltage_B" jdbcType="DOUBLE" property="mvVoltageB" />
    <result column="MV_Voltage_C" jdbcType="DOUBLE" property="mvVoltageC" />
    <result column="MV_Power_A" jdbcType="DOUBLE" property="mvPowerA" />
    <result column="MV_Power_B" jdbcType="DOUBLE" property="mvPowerB" />
    <result column="MV_Power_C" jdbcType="DOUBLE" property="mvPowerC" />
  </resultMap>
  <sql id="Base_Column_List">
    <!--
      WARNING - @mbg.generated
    -->
    MV_ID, MV_Stat_Code, MV_Create_Time, MV_Data_Time, MV_Electricity_A, MV_Electricity_B,
    MV_Electricity_C, MV_Voltage_A, MV_Voltage_B, MV_Voltage_C, MV_Power_A, MV_Power_B,
    MV_Power_C
  </sql>
</mapper>
src/test/kotlin/com/flightfeather/uav/socket/UnderwayProcessorTest.kt
ÎļþÃû´Ó src/test/kotlin/com/flightfeather/uav/socket/MessageManagerTest.kt ÐÞ¸Ä
@@ -1,14 +1,15 @@
package com.flightfeather.uav.socket
import com.flightfeather.uav.socket.processor.UnderwayProcessor
import org.junit.Test
/**
 * @author riku
 * Date: 2019/9/16
 */
class MessageManagerTest {
class UnderwayProcessorTest {
    private val messageManager = MessageManager()
    private val messageManager = UnderwayProcessor()
    @Test
    fun bccCheck() {