ke
2024-07-19 08a962d2925baa255207fdf979e6fee794f1773b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package cn.gistack.sm.sjztmd.service.impl;
 
import cn.gistack.sm.sjztmd.constant.RainfallConstant;
import cn.gistack.sm.sjztmd.entity.StBdData;
import cn.gistack.sm.sjztmd.mapper.StBdDataMapper;
import cn.gistack.sm.sjztmd.service.IStBdDataService;
import cn.gistack.sm.sjztmd.vo.BdParsedContentVO;
import cn.gistack.sm.sjztmd.vo.StBdDataVO;
import cn.gistack.sm.sjztmd.vo.StBdVO;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springframework.stereotype.Service;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
 
@Slf4j
@Service
@DS("zt")
public class StBdDataServiceImpl extends ServiceImpl<StBdDataMapper, StBdData> implements IStBdDataService {
 
    private final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
 
    @Override
    public Boolean insertData(StBdDataVO stBdDataVO) throws Exception {
        List<StBdDataVO.CommInfo> commInfos = stBdDataVO.getCommInfos();
        if (null == commInfos || commInfos.isEmpty()) {
            throw new ServiceException("获取北斗平台数据失败,无效的commInfos");
        }
        List<StBdData> stBdDataList = new ArrayList<>();
        for (StBdDataVO.CommInfo commInfo : commInfos) {
            StBdData stBdData = new StBdData();
            stBdData.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            stBdData.setTm(formatter.parse(commInfo.getTime()));
            stBdData.setCreateTime(new Date());
            stBdData.setFromAddr(commInfo.getFromAddr());
            stBdData.setToAddr(commInfo.getToAddr());
            String content = commInfo.getContent();
            stBdData.setContent(content);
            BdParsedContentVO parsedContentVO = parseContent(content);
            if (!parsedContentVO.getSuccess()) {
                log.warn("解析content失败, parsedContentVO : {}", parsedContentVO);
            }
            stBdData.setParsedContent(parsedContentVO.getParsedContent());
            stBdData.setLongitude(parsedContentVO.getLongitude());
            stBdData.setLatitude(parsedContentVO.getLatitude());
            stBdData.setAltitude(parsedContentVO.getAltitude());
            boolean containsChinese = parsedContentVO.isContainChinese();
            stBdData.setCodeType(containsChinese? RainfallConstant.CONTAINS_CHINESE : RainfallConstant.NOT_CONTAINS_CHINESE);
            stBdDataList.add(stBdData);
        }
        this.saveBatch(stBdDataList);
        return true;
    }
 
    private BdParsedContentVO parseContent(String content) {
        BdParsedContentVO bdParsedContentVO = new BdParsedContentVO();
        bdParsedContentVO.setContainChinese(false);
        bdParsedContentVO.setSuccess(false);
        if (StrUtil.isEmpty(content)) {
            bdParsedContentVO.setErrorMessage("无效的content");
            return bdParsedContentVO;
        }
 
        // 信息类型
        StringBuilder contentSb = new StringBuilder(content);
        String infoType = contentSb.substring(0, 2);
 
        if (!"91".equals(infoType)) {
            bdParsedContentVO.setErrorMessage("报文信息类型不是91,无法解析");
            return bdParsedContentVO;
        }
 
        // 接受者手机号
        Long phoneNumber = Long.parseLong(contentSb.substring(2, 12), 16);
 
        String formattedDate = formatter.format(new Date(1000L * Long.parseLong(contentSb.substring(12, 20), 16)));
 
        // 经度
        String longitude = new BigDecimal(Long.parseLong(contentSb.substring(20, 28), 16))
            .divide(new BigDecimal(1000000), 6, RoundingMode.HALF_UP).toString();
 
        // 纬度
        String latitude = new BigDecimal(Long.parseLong(contentSb.substring(28, 36), 16))
            .divide(new BigDecimal(1000000), 6 ,RoundingMode.HALF_UP).toString();
 
        // 海拔
        String altitude = String.valueOf(Integer.parseInt(contentSb.substring(36, 40), 16));
 
        // 短信内容解析
        String textMessage = hexStr2Str(contentSb.substring(40, content.length()));
 
        // 是否包含中文
        bdParsedContentVO.setContainChinese(contentIsContainChinese(textMessage));
 
        JSONObject dataObject = new JSONObject();
        dataObject.put("phone", phoneNumber);
        dataObject.put("time", formattedDate);
        dataObject.put("longitude", longitude);
        dataObject.put("latitude", latitude);
        dataObject.put("altitude", altitude);
        dataObject.put("message", textMessage);
        bdParsedContentVO.setParsedContent(dataObject.toString());
        bdParsedContentVO.setLongitude(longitude);
        bdParsedContentVO.setLatitude(latitude);
        bdParsedContentVO.setAltitude(altitude);
        bdParsedContentVO.setSuccess(true);
        return bdParsedContentVO;
    }
 
    @Override
    public IPage<StBdData> selectAlarmRecordPage(Query query, StBdVO stBdVO) {
        LambdaQueryWrapper<StBdData> queryWrapper = Wrappers.<StBdData>query().lambda()
            .eq(StrUtil.isNotEmpty(stBdVO.getCodeType()), StBdData::getCodeType, stBdVO.getCodeType())
            .eq(StrUtil.isNotEmpty(stBdVO.getFromAddr()), StBdData::getFromAddr, stBdVO.getFromAddr())
            .eq(StrUtil.isNotEmpty(stBdVO.getToAddr()), StBdData::getToAddr, stBdVO.getToAddr())
            .ge(stBdVO.getStartTime() != null, StBdData::getTm, stBdVO.getStartTime())
            .le(stBdVO.getEndTime() != null, StBdData::getTm, stBdVO.getEndTime());
        return page(Condition.getPage(query), queryWrapper);
    }
 
    private boolean contentIsContainChinese(String content) {
        if (content == null || content.isEmpty()) {
            return false;
        }
        String chinesePattern = "[\u4e00-\u9fa5]";
        Pattern pattern = Pattern.compile(chinesePattern);
        Matcher matcher = pattern.matcher(content);
        return matcher.find();
    }
 
    public static String hexStr2Str(String hexStr) {
        String str = "0123456789ABCDEF";  // 16进制能用到的所有字符 0-15
        char[] hexs = hexStr.toCharArray(); // toCharArray() 方法将字符串转换为字符数组。
        int length = (hexStr.length() / 2); // 1个byte数值 -> 两个16进制字符
        byte[] bytes = new byte[length];
        int n;
        for (int i = 0; i < bytes.length; i++) {
            int position = i * 2; //两个16进制字符 -> 1个byte数值
            n = str.indexOf(hexs[position]) * 16;
            n += str.indexOf(hexs[position + 1]);
            // 保持二进制补码的一致性 因为byte类型字符是8bit的  而int为32bit 会自动补齐高位1  所以与上0xFF之后可以保持高位一致性
            // 当byte要转化为int的时候,高的24位必然会补1,这样,其二进制补码其实已经不一致了,&0xff可以将高的24位置为0,低8位保持原样,
            // 这样做的目的就是为了保证二进制数据的一致性。
            bytes[i] = (byte) (n & 0xff);
        }
        return new String(bytes, Charset.forName("GB18030"));
    }
}