• 视频AI分析定时任务思路解析


    序言:

         最近项目中用到视频ai分析,由于sdk涉及保密,不便透露,仅对定时任务分析的思路作出分享,仅供参考。

    1、定时任务

         由于ai服务器的性能上限,只能同时对64个rtsp流分析一种算法,或者对8个rtsp流分析8种算法。因此定时任务,做如下设计。   

        AiHandlerTask.java 

    1. import com.alibaba.fastjson.JSON;
    2. import com.alibaba.fastjson.JSONArray;
    3. import com.alibaba.fastjson.JSONObject;
    4. import com.ewaycloud.jw.ai.service.AiService;
    5. import com.ewaycloud.jw.camera.entity.Camera;
    6. import com.ewaycloud.jw.camera.mapper.CameraMapper;
    7. import com.ewaycloud.jw.camera.service.CameraService;
    8. import com.ewaycloud.jw.cases.dto.CaseDTO;
    9. import com.ewaycloud.jw.cases.service.CaseService;
    10. import com.ewaycloud.jw.channel.service.HikService;
    11. import com.ewaycloud.jw.task.entity.Task;
    12. import com.ewaycloud.jw.task.mapper.TaskMapper;
    13. import org.springframework.scheduling.annotation.EnableScheduling;
    14. import org.springframework.stereotype.Component;
    15. import javax.annotation.Resource;
    16. import java.util.Date;
    17. import java.util.List;
    18. /**
    19. * AI分析 定时任务 处理类
    20. *
    21. * @author gwh
    22. * @date 2024-04-14 13:59:17
    23. */
    24. @Component
    25. @EnableScheduling
    26. public class AiHandlerTask {
    27. @Resource
    28. AiService aiService;
    29. @Resource
    30. TaskService taskService;
    31. @Resource
    32. CameraService cameraService;
    33. @Resource
    34. private TaskMapper taskMapper;
    35. @Resource
    36. private CameraMapper cameraMapper;
    37. @Resource
    38. private HikService hkService;
    39. @Resource
    40. private CaseService caseService;
    41. /**
    42. * 注解中的Cron表达式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}
    43. * 注意:日和周其中的一个必须为"?"
    44. * 10/5 20 10 * * ? 每天10点20分第10秒以后,每3秒执行一次,到10点21分就不会执行了
    45. *
    46. * AI算法分析任务: 每5秒执行一次
    47. */
    48. // @Scheduled(cron = "0/5 * * * * ?")
    49. public void startTask(){
    50. // System.out.println("AI分析定时任务执行 每隔5秒执行一次:" + new Date());
    51. //查询要执行的任务
    52. List aiTasks = taskMapper.findAiTasks(null);
    53. if (null != aiTasks) {
    54. for(Task vo:aiTasks){
    55. if (null != vo.getDeptId()) {
    56. //查询某谈话室下边的摄像头列表(flag是1 谈话人特写 和2 被谈话人特写 的)
    57. List cameraList = cameraMapper.findCamersByDeptId(vo.getDeptId());
    58. if (null != cameraList && cameraList.size()>0) {
    59. for(Camera camera:cameraList) {
    60. //根据摄像头编码cameraCode,调用海康接口拉流
    61. String cameraCode = camera.getCameraCode();
    62. try {
    63. //根据cameraCode、开始时间、结束时间 调用海康接口 拉回放流
    64. //查询时间(IOS8601格式yyyy-MM-dd'T'HH:mm:ss.SSSzzz,和结束时间相差不超过三天
    65. JSONObject data = hkService.playbackURLs( cameraCode, vo.getStartTime(), vo.getEndTime());
    66. //谈话人特写AI分析
    67. if (null != data && null != data.getString("url")) {
    68. String rtspUrl = data.getString("url");
    69. //疑似肢体冲突
    70. // startAiTask(rtspUrl, 1L, vo.getStartTime(), vo.getEndTime(), vo);
    71. //玩手机分析
    72. // startAiTask(rtspUrl, 2L, vo.getStartTime(), vo.getEndTime(), vo);
    73. //倒地分析
    74. // startAiTask(rtspUrl, 3L, vo.getStartTime(), vo.getEndTime(), vo);
    75. //人数异常
    76. startAiTask(rtspUrl, 5L, vo.getStartTime(), vo.getEndTime(), vo);
    77. }
    78. } catch (Exception e) {
    79. e.printStackTrace();
    80. }
    81. }
    82. }
    83. }
    84. }
    85. }
    86. // System.out.println("AI分析定时任务执行 每隔10秒执行一次:: " + new Date());
    87. }
    88. //执行拉流调用AI分析的方法
    89. public void startAiTask(String rtspUrl, Long aiId, String startTime, String endTime, Task vo) {
    90. //调用AI分析接口
    91. if (null != rtspUrl) {
    92. //调用海康AI算法分析
    93. String aiResponse = "";
    94. if (aiId == 1) {//疑似肢体冲突
    95. aiResponse = aiService.indoorPhysicalConfront(rtspUrl, startTime, endTime);
    96. vo.setBreakName("疑似肢体冲突");
    97. vo.setAiId(1L);
    98. } else if (aiId == 2) {//玩手机
    99. aiResponse = aiService.playCellphone(rtspUrl, startTime, endTime);
    100. vo.setBreakName("玩手机");
    101. vo.setAiId(2L);
    102. } else if (aiId == 3) {//倒地
    103. aiResponse = aiService.failDown(rtspUrl, startTime, endTime);
    104. vo.setBreakName("倒地");
    105. vo.setAiId(3L);
    106. } else if (aiId == 4) {//人员站立
    107. aiResponse = aiService.Standup(rtspUrl,startTime, endTime);
    108. vo.setBreakName("人员站立");
    109. vo.setAiId(4L);
    110. } else if (aiId == 5) {//人数异常
    111. aiResponse = aiService.PeopleNumChange(rtspUrl, startTime, endTime);
    112. vo.setBreakName("人数异常");
    113. vo.setAiId(5L);
    114. } else if (aiId == 6) {//声强突变
    115. aiResponse = aiService.audioAbnormal(rtspUrl, startTime, endTime);
    116. vo.setBreakName("声强突变");
    117. vo.setAiId(6L);
    118. } else if (aiId == 7) {//超时滞留
    119. aiResponse = aiService.overtimeTarry(rtspUrl, startTime, endTime);
    120. vo.setBreakName("超时滞留");
    121. vo.setAiId(7L);
    122. } else if (aiId == 8) {//攀高
    123. aiResponse = aiService.reachHeight(rtspUrl, startTime, endTime);
    124. vo.setBreakName("攀高");
    125. vo.setAiId(8L);
    126. }
    127. JSONObject aiResponseJSONObject = JSON.parseObject(aiResponse);
    128. // System.out.println("AI分析定时任务返回aiResponseJSONObject:" + aiResponseJSONObject);
    129. String taskId = "";
    130. String taskStatus = "";
    131. if (null != aiResponseJSONObject && null != aiResponseJSONObject.getString("taskID") ){
    132. taskId = aiResponseJSONObject.getString("taskID");
    133. //调用海康查询任务状态接口获取AI分析任务状态
    134. String result = aiService.queryTaskVideoStatus(taskId);
    135. JSONObject resultJSONObject = JSON.parseObject(result);
    136. JSONArray statusJSONArray = resultJSONObject.getJSONArray("status");
    137. JSONObject statusJSONObject = (JSONObject) statusJSONArray.get(0);
    138. taskStatus = statusJSONObject.getString("taskStatus");
    139. //将AI分析结果taskStatus插入task表中,更新任务表,状态:1 未执行, 2等待, 3 正在执行 , 4 已完成
    140. vo.setTaskState(Integer.parseInt(taskStatus));
    141. vo.setTaskId(taskId); //保存 海康返回的 taskID
    142. //如果任务完成,关闭rtsp流
    143. if ("4".equals(taskStatus)) {
    144. //根据caseId更新案件表的 task_state =1 , ai任务状态(0:未执行 1:已执行)
    145. Long caseId = vo.getCaseId();
    146. CaseDTO caseDTO = new CaseDTO();
    147. caseDTO.setCaseId(caseId);
    148. caseDTO.setCaseState(1);
    149. caseService.updCaseInfo(caseDTO);
    150. //关闭rtsp流
    151. try {
    152. hkService.clearPlayUrls(rtspUrl);
    153. } catch (Exception e) {
    154. e.printStackTrace();
    155. }
    156. }
    157. }
    158. System.out.println("AI分析定时任务返回 taskId:" + taskId +" breakName: "+ vo.getBreakName() +" taskStatus: "+ taskStatus);
    159. //更新任务表, 根据caseId 和taskId查询任务,如果有更新,没有插入
    160. Task dto = new Task();
    161. dto.setCaseId(vo.getCaseId());
    162. dto.setTaskId(vo.getTaskId());
    163. List tasks = taskMapper.findTasks(dto);
    164. if(null != tasks && tasks.size()>0){
    165. for(Task po : tasks){
    166. vo.setId(po.getId());
    167. vo.setUpdateTime(new Date());
    168. taskService.updateById(po);
    169. }
    170. }else {
    171. vo.setCreateTime(new Date());
    172. vo.setUpdateTime(new Date());
    173. taskMapper.insert(vo);
    174. }
    175. }
    176. }
    177. }

    2、算法实现,由于涉密,只贴出接口

    AiService.java

    1. import com.baomidou.mybatisplus.extension.service.IService;
    2. import com.ewaycloud.jw.ai.entity.Ai;
    3. import com.ewaycloud.jw.task.entity.Task;
    4. import java.util.List;
    5. /**
    6. * AI对接
    7. *
    8. * @author gwh
    9. * @date 2024-03-13 13:49:09
    10. */
    11. public interface AiService extends IService {
    12. String getAiDeviceInfo();
    13. /**
    14. * 创建--疑似肢体冲突事件--分析视频分析任务
    15. *
    16. */
    17. String indoorPhysicalConfront(String streamUrl, String startTime, String endTime);
    18. /**
    19. * 创建--玩手机--分析视频分析任务
    20. *
    21. */
    22. String playCellphone(String streamUrl, String startTime, String endTime);
    23. /**
    24. * 创建--倒地检测--分析视频分析任务
    25. *
    26. */
    27. String failDown(String streamUrl, String startTime, String endTime);
    28. /**
    29. * 创建--人员站立--分析视频分析任务
    30. *
    31. */
    32. String Standup(String streamUrl, String startTime, String endTime);
    33. /**
    34. * 创建--人数异常--分析视频分析任务
    35. *
    36. */
    37. String PeopleNumChange(String streamUrl, String startTime, String endTime);
    38. /**
    39. * 创建--声强突变--分析视频分析任务
    40. *
    41. */
    42. String audioAbnormal(String streamUrl, String startTime, String endTime);
    43. /**
    44. * 创建--超时滞留--分析视频分析任务
    45. *
    46. */
    47. String overtimeTarry(String streamUrl, String startTime, String endTime);
    48. /**
    49. * 创建--攀高--分析视频分析任务
    50. *
    51. */
    52. String reachHeight(String streamUrl, String startTime, String endTime);
    53. /**
    54. * 查询分析视频分析任务状态
    55. *
    56. */
    57. String queryTaskVideoStatus(String taskId);
    58. }

    3、启动一个线程,Socket监听10006端口,接收ai服务器返回的结果

    ListenThread.java

    1. import com.ewaycloud.jw.ai.entity.AiResolveResult;
    2. import com.ewaycloud.jw.ai.mapper.AiResolveResultMapper;
    3. import com.ewaycloud.jw.task.entity.ContentTypeEnum;
    4. import com.ewaycloud.jw.task.entity.Task;
    5. import com.ewaycloud.jw.task.mapper.TaskMapper;
    6. import com.mysql.cj.util.StringUtils;
    7. import lombok.extern.slf4j.Slf4j;
    8. import org.springframework.stereotype.Service;
    9. import org.springframework.transaction.annotation.Transactional;
    10. import javax.annotation.Resource;
    11. import java.io.ByteArrayOutputStream;
    12. import java.io.InputStream;
    13. import java.io.OutputStream;
    14. import java.net.ServerSocket;
    15. import java.net.Socket;
    16. import java.util.Date;
    17. import java.util.List;
    18. /**
    19. * @author gwhui
    20. * @date 2024/1/18 17:38
    21. * @desc 监听处理线程
    22. */
    23. @Slf4j
    24. @Service
    25. public class ListenThread implements Runnable {
    26. private final AlarmDataParser alarmDataParser = new AlarmDataParser();
    27. private static TaskMapper taskMapper;
    28. @Resource
    29. public void setVerificDao(TaskMapper taskMapper) {
    30. ListenThread.taskMapper = taskMapper;
    31. }
    32. private static AiResolveResultMapper aiResolveResultMapper;
    33. @Resource
    34. public void setVerificDao(AiResolveResultMapper aiResolveResultMapper) {
    35. ListenThread.aiResolveResultMapper = aiResolveResultMapper;
    36. }
    37. @Override
    38. public void run() {
    39. // int listenPort = propertiesUtil.getIntegerProperty("custom.isapi.listen.port", 9999);
    40. int listenPort =10006;
    41. try {
    42. ServerSocket serverSocket = new ServerSocket(listenPort);
    43. System.out.println("启动监听, 监听端口:" + listenPort);
    44. while (!Thread.currentThread().isInterrupted()) {
    45. Socket accept = serverSocket.accept();
    46. accept.setKeepAlive(true);
    47. System.out.println("设备(客户端)信息:" + accept.getInetAddress().getHostAddress());
    48. if (accept.isConnected()) {
    49. handleData(accept);
    50. }
    51. accept.close();
    52. }
    53. serverSocket.close();
    54. System.out.println("停止监听完成");
    55. } catch (InterruptedException e) {
    56. // 线程被中断的处理逻辑
    57. System.out.println("停止监听完成: " + e.getMessage());
    58. } catch (Exception e) {
    59. System.out.println("监听创建异常: " + e.getMessage());
    60. }
    61. }
    62. @Transactional(rollbackFor = Exception.class)
    63. public synchronized void handleData(Socket accept) throws Exception {
    64. InputStream inputData = accept.getInputStream();
    65. OutputStream outputData = accept.getOutputStream();
    66. // 输出数据
    67. ByteArrayOutputStream byOutputData = new ByteArrayOutputStream();
    68. byte[] buffer = new byte[2 * 1024 * 1024];
    69. int length = 0;
    70. // 持续接收处理数据直到接收完毕
    71. String recvAlarmData = "";
    72. while ((length = inputData.read(buffer)) > 0) {
    73. byOutputData.write(buffer, 0, length);
    74. String recvData = byOutputData.toString();
    75. recvAlarmData = recvAlarmData + recvData;
    76. // 获取boundary
    77. String strBoundary = "boundary=";
    78. int beginIndex = recvData.indexOf(strBoundary);
    79. beginIndex += strBoundary.length();
    80. int lenIndex = recvData.indexOf("\r\n", beginIndex);
    81. String strBoundaryMark = recvData.substring(beginIndex, lenIndex);
    82. if (recvAlarmData.contains("--" + strBoundaryMark.trim() + "--")) {
    83. //表单结束符判断接收结束
    84. break;
    85. }
    86. }
    87. // System.out.println("==============recvAlarmData========>> "+recvAlarmData);
    88. if(null != recvAlarmData){
    89. String taskId = null;
    90. int index = recvAlarmData.indexOf("");
    91. if(index != -1){
    92. taskId = recvAlarmData.substring(index + 8, index + 40);
    93. }
    94. //获取服务器返回的图片
    95. String bkgUrl = null;
    96. int indexStartBkgUrl = recvAlarmData.indexOf("");
    97. int indexEndBkgUrl = recvAlarmData.indexOf("");
    98. if(indexStartBkgUrl != -1){
    99. bkgUrl = recvAlarmData.substring(indexStartBkgUrl+8, indexEndBkgUrl);
    100. bkgUrl =bkgUrl.replaceAll("&","&");
    101. }
    102. System.out.println("===AIrecieveData===>>taskId: "+taskId +" bkgUrl: "+ bkgUrl);
    103. //根据taskId查询 任务信息
    104. if(!StringUtils.isNullOrEmpty(taskId)){
    105. Task task = taskMapper.finTaskByTaskId(taskId);
    106. if(null != task){
    107. AiResolveResult vo = new AiResolveResult();
    108. vo.setCreateTime(new Date());
    109. vo.setUpdateTime(new Date());
    110. vo.setTaskId(taskId); //保存海康返回的 taskId
    111. vo.setBreakName(task.getBreakName());
    112. vo.setAiId(task.getAiId());
    113. vo.setDeptId(task.getDeptId());
    114. vo.setCameraId(task.getCameraId());
    115. vo.setBreakTypeId(task.getAiId());
    116. vo.setRiskTime(task.getTalkTime());
    117. vo.setTalkAddress(task.getTalkAddress());
    118. vo.setTalkAddressName(task.getTalkAddressName());
    119. vo.setTalkUnit(task.getTalkUnit());
    120. vo.setTalkUnitName(task.getTalkUnitName());
    121. vo.setPhoto(bkgUrl); //保存海康返回的图片
    122. vo.setCaseId(task.getCaseId());
    123. vo.setCaseName(task.getCaseName());
    124. vo.setInterviewerName(task.getInterviewerName());
    125. //根据taskId查询任务结果表,如果有做更新操作,没有做插入操作
    126. List aiResolveResults = aiResolveResultMapper.findAiResults(vo);
    127. if(null != aiResolveResults && aiResolveResults.size()>0){
    128. for(AiResolveResult aiResolveResult:aiResolveResults){
    129. if(null != aiResolveResult){
    130. aiResolveResult.setPhoto(vo.getPhoto());
    131. aiResolveResultMapper.updateById(aiResolveResult);
    132. }
    133. }
    134. }else {
    135. aiResolveResultMapper.insert(vo);
    136. }
    137. }
    138. }
    139. }
    140. String response = "HTTP/1.1 200 OK" +
    141. "\r\n" +
    142. "Connection: close" +
    143. "\r\n\r\n";
    144. outputData.write(response.getBytes());
    145. outputData.flush();
    146. outputData.close();
    147. inputData.close();
    148. //解析数据
    149. response = parseAlarmInfoByte(byOutputData);
    150. System.out.println("==============response========>> "+response);
    151. }
    152. private String parseAlarmInfoByte(ByteArrayOutputStream byOutputData) throws Exception {
    153. // 事件报文字节
    154. byte[] byAlarmDataInfo = byOutputData.toByteArray();
    155. int iDataLen = byAlarmDataInfo.length;
    156. String szBoundaryMark = "boundary=";
    157. String szContentTypeMark = "Content-Type: ";
    158. int iTypeMarkLen = szContentTypeMark.getBytes("UTF-8").length;
    159. String szContentLenMark = "Content-Length: ";
    160. int iLenMarkLen = szContentLenMark.getBytes("UTF-8").length;
    161. String szContentLenMark2 = "content-length: ";
    162. int iLenMarkLen2 = szContentLenMark2.getBytes("UTF-8").length;
    163. int iContentLen = 0;
    164. String szEndMark = "\r\n";
    165. int iMarkLen = szEndMark.getBytes("UTF-8").length;
    166. String szEndMark2 = "\r\n\r\n";
    167. int iMarkLen2 = szEndMark2.getBytes("UTF-8").length;
    168. String szJson = "text/json";
    169. String szJpg = "image/jpeg";
    170. int iStartBoundary = doDataSearch(byAlarmDataInfo, szBoundaryMark.getBytes("UTF-8"), 0, byAlarmDataInfo.length);
    171. iStartBoundary += szBoundaryMark.getBytes("UTF-8").length;
    172. int iEndBoundary = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartBoundary, byAlarmDataInfo.length);
    173. byte[] byBoundary = new byte[iEndBoundary - iStartBoundary];
    174. System.arraycopy(byAlarmDataInfo, iStartBoundary, byBoundary, 0, iEndBoundary - iStartBoundary);
    175. String szBoundaryEndMark = "--" + new String(byBoundary).trim() + "--";
    176. int iDateEnd = doDataSearch(byAlarmDataInfo, szBoundaryEndMark.getBytes("UTF-8"), 0, byAlarmDataInfo.length);
    177. String szBoundaryMidMark = "--" + new String(byBoundary).trim();
    178. int iBoundaryMidLen = szBoundaryMidMark.getBytes("UTF-8").length;
    179. int startIndex = iEndBoundary;
    180. String szContentType = "";
    181. int[] iBoundaryPos = new int[11]; //boundary个数,这里最大解析10个
    182. int iBoundaryNum = 0;
    183. for (iBoundaryNum = 0; iBoundaryNum < 10; iBoundaryNum++) {
    184. startIndex = doDataSearch(byAlarmDataInfo, szBoundaryMidMark.getBytes("UTF-8"), startIndex, iDateEnd);
    185. if (startIndex < 0) {
    186. break;
    187. }
    188. startIndex += iBoundaryMidLen;
    189. iBoundaryPos[iBoundaryNum] = startIndex;
    190. }
    191. iBoundaryPos[iBoundaryNum] = iDateEnd;//最后一个是结束符
    192. for (int i = 0; i < iBoundaryNum; i++) {
    193. // Content-Type
    194. int iStartType = doDataSearch(byAlarmDataInfo, szContentTypeMark.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
    195. if (iStartType > 0) {
    196. iStartType += iTypeMarkLen;
    197. int iEndType = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartType, iBoundaryPos[i + 1]);
    198. if (iEndType > 0) {
    199. byte[] byType = new byte[iEndType - iStartType];
    200. System.arraycopy(byAlarmDataInfo, iStartType, byType, 0, iEndType - iStartType);
    201. szContentType = new String(byType).trim();
    202. }
    203. }
    204. // Content-Length
    205. int iStartLength = doDataSearch(byAlarmDataInfo, szContentLenMark.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
    206. if (iStartLength > 0) {
    207. iStartLength += iLenMarkLen;
    208. int iEndLength = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartLength, iBoundaryPos[i + 1]);
    209. if (iEndLength > 0) {
    210. byte[] byLength = new byte[iEndLength - iStartLength];
    211. System.arraycopy(byAlarmDataInfo, iStartLength, byLength, 0, iEndLength - iStartLength);
    212. iContentLen = Integer.parseInt(new String(byLength).trim());
    213. }
    214. }
    215. // Content-Length(兼容错误大小写)
    216. int iStartLength2 = doDataSearch(byAlarmDataInfo, szContentLenMark2.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
    217. if (iStartLength2 > 0) {
    218. iStartLength2 += iLenMarkLen2;
    219. int iEndLength2 = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartLength2, iBoundaryPos[i + 1]);
    220. if (iEndLength2 > 0) {
    221. byte[] byLength2 = new byte[iEndLength2 - iStartLength2];
    222. System.arraycopy(byAlarmDataInfo, iStartLength2, byLength2, 0, iEndLength2 - iStartLength2);
    223. iContentLen = Integer.parseInt(new String(byLength2).trim());
    224. }
    225. }
    226. // 通过\r\n\r\n判断报文数据起始位置
    227. int iStartData = doDataSearch(byAlarmDataInfo, szEndMark2.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
    228. if (iStartData > 0) {
    229. iStartData += iMarkLen2;
    230. // 有的报文可能没有Content-Length
    231. if (iContentLen <= 0) {
    232. iContentLen = iBoundaryPos[i + 1] - iStartData;
    233. }
    234. // 截取数据内容
    235. byte[] byData = new byte[iContentLen];
    236. System.arraycopy(byAlarmDataInfo, iStartData, byData, 0, iContentLen);
    237. // 根据类型处理数据
    238. int contentType = ContentTypeEnum.getEventType(szContentType);
    239. String storeFolder = System.getProperty("user.dir") + "\\output\\listen\\event\\";
    240. switch (contentType) {
    241. case ContentTypeEnum.APPLICATION_JSON:
    242. case ContentTypeEnum.APPLICATION_XML: {
    243. String rawContent = new String(byData).trim();
    244. alarmDataParser.parseAlarmInfo(contentType, storeFolder, rawContent, null);
    245. break;
    246. }
    247. case ContentTypeEnum.IMAGE_JPEG:
    248. case ContentTypeEnum.IMAGE_PNG:
    249. case ContentTypeEnum.VIDEO_MPG:
    250. case ContentTypeEnum.VIDEO_MPEG4:
    251. case ContentTypeEnum.APPLICATION_ZIP: {
    252. alarmDataParser.parseAlarmInfo(contentType, storeFolder, null, byData);
    253. break;
    254. }
    255. default: {
    256. System.out.println("未匹配到可以解析的content-type, 请自行补全处理!");
    257. }
    258. }
    259. }
    260. }
    261. // 响应报文
    262. String response = "";
    263. // 消费交易事件 (实际如果没有消费机设备可以不需要消费机的处理代码)
    264. String eventType = "";
    265. String eventConfirm = "";
    266. if (eventType.equals("ConsumptionEvent") || eventType.equals("TransactionRecordEvent") || eventType.equals("HealthInfoSyncQuery")) {
    267. response = "HTTP/1.1 200 OK" +
    268. "\r\n" +
    269. "Content-Type: application/json; charset=\"UTF-8\"" +
    270. "\r\n" +
    271. "Content-Length: " + eventConfirm.length() +
    272. "\r\n\r\n" + eventConfirm +
    273. "\r\n";
    274. } else {
    275. response = "HTTP/1.1 200 OK" +
    276. "\r\n" +
    277. "Connection: close" +
    278. "\r\n\r\n";
    279. }
    280. return response;
    281. }
    282. private int doDataSearch(byte[] bySrcData, byte[] keyData, int startIndex, int endIndex) {
    283. if (bySrcData == null || keyData == null || bySrcData.length <= startIndex || bySrcData.length < keyData.length) {
    284. return -1;
    285. }
    286. if (endIndex > bySrcData.length) {
    287. endIndex = bySrcData.length;
    288. }
    289. int iPos, jIndex;
    290. for (iPos = startIndex; iPos < endIndex; iPos++) {
    291. if (bySrcData.length < keyData.length + iPos) {
    292. break;
    293. }
    294. for (jIndex = 0; jIndex < keyData.length; jIndex++) {
    295. if (bySrcData[iPos + jIndex] != keyData[jIndex]) {
    296. break;
    297. }
    298. }
    299. if (jIndex == keyData.length) {
    300. return iPos;
    301. }
    302. }
    303. return -1;
    304. }
    305. }

    4、数据库设计

    瀚高国产数据库

            

    5、前端页面设计

  • 相关阅读:
    SPI在Java中的实现与应用 | 京东物流技术团队
    逻辑回归——线性二分类(机器学习)
    嵌入式Linux应用开发-第十三章APP怎么读取按键值
    Java刷题day28
    计算摄影——图像超分
    CDGA|做数据安全治理,先考个DAMA证书吧!
    docker部署最新版nacos(2.2.3)设置登录密码
    c语言实现数据结构中的带头双向循环链表
    【解决方案】如何使用 Http API 代替 OpenFeign 进行远程服务调用
    CompletableFuture理解与应用
  • 原文地址:https://blog.csdn.net/gaowenhui2008/article/details/139832836