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

news2025/1/16 8:05:03

序言:

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

1、定时任务

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

    AiHandlerTask.java 



import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ewaycloud.jw.ai.service.AiService;
import com.ewaycloud.jw.camera.entity.Camera;
import com.ewaycloud.jw.camera.mapper.CameraMapper;
import com.ewaycloud.jw.camera.service.CameraService;
import com.ewaycloud.jw.cases.dto.CaseDTO;
import com.ewaycloud.jw.cases.service.CaseService;
import com.ewaycloud.jw.channel.service.HikService;
import com.ewaycloud.jw.task.entity.Task;
import com.ewaycloud.jw.task.mapper.TaskMapper;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * AI分析 定时任务 处理类
 *
 * @author gwh
 * @date 2024-04-14 13:59:17
 */
@Component
@EnableScheduling
public class AiHandlerTask {

    @Resource
    AiService aiService;
    @Resource
    TaskService taskService;
    @Resource
    CameraService cameraService;
    @Resource
    private TaskMapper taskMapper;

    @Resource
    private CameraMapper cameraMapper;
    @Resource
    private HikService hkService;

    @Resource
    private CaseService caseService;

    /**
     *	注解中的Cron表达式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}
     *	注意:日和周其中的一个必须为"?"
     *	10/5 20 10 * * ? 每天10点20分第10秒以后,每3秒执行一次,到10点21分就不会执行了
     *
     * AI算法分析任务: 每5秒执行一次
     */
//   @Scheduled(cron = "0/5 * * * * ?")
    public void startTask(){
      // System.out.println("AI分析定时任务执行 每隔5秒执行一次:" + new Date());
       //查询要执行的任务
        List<Task> aiTasks = taskMapper.findAiTasks(null);
        if (null != aiTasks) {
            for(Task vo:aiTasks){
                if (null != vo.getDeptId()) {
                    //查询某谈话室下边的摄像头列表(flag是1 谈话人特写 和2 被谈话人特写 的)
                    List<Camera> cameraList = cameraMapper.findCamersByDeptId(vo.getDeptId());
                    if (null != cameraList && cameraList.size()>0) {
                        for(Camera camera:cameraList) {
                            //根据摄像头编码cameraCode,调用海康接口拉流
                            String cameraCode = camera.getCameraCode();
                            try {
                                //根据cameraCode、开始时间、结束时间 调用海康接口 拉回放流
                                //查询时间(IOS8601格式yyyy-MM-dd'T'HH:mm:ss.SSSzzz,和结束时间相差不超过三天
                                JSONObject data = hkService.playbackURLs( cameraCode, vo.getStartTime(),  vo.getEndTime());
                                //谈话人特写AI分析
                                if (null != data && null != data.getString("url")) {
                                    String rtspUrl = data.getString("url");
                                    //疑似肢体冲突
                                  //  startAiTask(rtspUrl, 1L, vo.getStartTime(), vo.getEndTime(), vo);
                                    //玩手机分析
                                  //  startAiTask(rtspUrl, 2L, vo.getStartTime(), vo.getEndTime(), vo);
                                    //倒地分析
                                  //  startAiTask(rtspUrl, 3L, vo.getStartTime(), vo.getEndTime(), vo);
                                    //人数异常
                                    startAiTask(rtspUrl, 5L, vo.getStartTime(), vo.getEndTime(), vo);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
      //  System.out.println("AI分析定时任务执行 每隔10秒执行一次:: " + new Date());
    }

    //执行拉流调用AI分析的方法
    public void startAiTask(String rtspUrl, Long aiId, String startTime, String endTime, Task vo) {
        //调用AI分析接口
        if (null != rtspUrl) {
            //调用海康AI算法分析
            String aiResponse = "";
            if (aiId == 1) {//疑似肢体冲突
                aiResponse = aiService.indoorPhysicalConfront(rtspUrl, startTime, endTime);
                vo.setBreakName("疑似肢体冲突");
                vo.setAiId(1L);
            } else if (aiId == 2) {//玩手机
                aiResponse = aiService.playCellphone(rtspUrl, startTime, endTime);
                vo.setBreakName("玩手机");
                vo.setAiId(2L);
            } else if (aiId == 3) {//倒地
                aiResponse = aiService.failDown(rtspUrl, startTime, endTime);
                vo.setBreakName("倒地");
                vo.setAiId(3L);
            } else if (aiId == 4) {//人员站立
                aiResponse = aiService.Standup(rtspUrl,startTime, endTime);
                vo.setBreakName("人员站立");
                vo.setAiId(4L);
            } else if (aiId == 5) {//人数异常
                aiResponse = aiService.PeopleNumChange(rtspUrl, startTime, endTime);
                vo.setBreakName("人数异常");
                vo.setAiId(5L);
            } else if (aiId == 6) {//声强突变
                aiResponse = aiService.audioAbnormal(rtspUrl, startTime, endTime);
                vo.setBreakName("声强突变");
                vo.setAiId(6L);
            } else if (aiId == 7) {//超时滞留
                aiResponse = aiService.overtimeTarry(rtspUrl, startTime, endTime);
                vo.setBreakName("超时滞留");
                vo.setAiId(7L);
            } else if (aiId == 8) {//攀高
                aiResponse = aiService.reachHeight(rtspUrl, startTime, endTime);
                vo.setBreakName("攀高");
                vo.setAiId(8L);
            }
            JSONObject aiResponseJSONObject = JSON.parseObject(aiResponse);
//            System.out.println("AI分析定时任务返回aiResponseJSONObject:" + aiResponseJSONObject);
            String taskId = "";
            String taskStatus = "";
            if (null != aiResponseJSONObject && null != aiResponseJSONObject.getString("taskID") ){
                taskId = aiResponseJSONObject.getString("taskID");
                //调用海康查询任务状态接口获取AI分析任务状态
                String result = aiService.queryTaskVideoStatus(taskId);
                JSONObject resultJSONObject = JSON.parseObject(result);
                JSONArray statusJSONArray = resultJSONObject.getJSONArray("status");
                JSONObject statusJSONObject = (JSONObject) statusJSONArray.get(0);
                 taskStatus = statusJSONObject.getString("taskStatus");
                //将AI分析结果taskStatus插入task表中,更新任务表,状态:1 未执行, 2等待, 3 正在执行 , 4 已完成
                vo.setTaskState(Integer.parseInt(taskStatus));
                vo.setTaskId(taskId); //保存 海康返回的 taskID
                //如果任务完成,关闭rtsp流
                if ("4".equals(taskStatus)) {
                    //根据caseId更新案件表的 task_state =1 , ai任务状态(0:未执行  1:已执行)
                    Long caseId = vo.getCaseId();
                    CaseDTO caseDTO = new CaseDTO();
                    caseDTO.setCaseId(caseId);
                    caseDTO.setCaseState(1);
                    caseService.updCaseInfo(caseDTO);
                    //关闭rtsp流
                    try {
                    hkService.clearPlayUrls(rtspUrl);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            System.out.println("AI分析定时任务返回 taskId:" + taskId +" breakName: "+ vo.getBreakName() +" taskStatus: "+ taskStatus);
            //更新任务表, 根据caseId 和taskId查询任务,如果有更新,没有插入
            Task dto = new Task();
               dto.setCaseId(vo.getCaseId());
               dto.setTaskId(vo.getTaskId());
            List<Task> tasks = taskMapper.findTasks(dto);
            if(null != tasks && tasks.size()>0){
                for(Task po : tasks){
                    vo.setId(po.getId());
                    vo.setUpdateTime(new Date());
                    taskService.updateById(po);
                }
            }else {
                vo.setCreateTime(new Date());
                vo.setUpdateTime(new Date());
                taskMapper.insert(vo);
            }
        }
    }

}

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

AiService.java



import com.baomidou.mybatisplus.extension.service.IService;
import com.ewaycloud.jw.ai.entity.Ai;
import com.ewaycloud.jw.task.entity.Task;

import java.util.List;

/**
 * AI对接
 *
 * @author gwh
 * @date 2024-03-13 13:49:09
 */
public interface AiService extends IService<Ai> {

    String getAiDeviceInfo();

    /**
     * 创建--疑似肢体冲突事件--分析视频分析任务
     *
     */
    String indoorPhysicalConfront(String streamUrl, String startTime, String endTime);

    /**
     * 创建--玩手机--分析视频分析任务
     *
     */
    String playCellphone(String streamUrl, String startTime, String endTime);

    /**
     * 创建--倒地检测--分析视频分析任务
     *
     */
    String failDown(String streamUrl, String startTime, String endTime);

    /**
     * 创建--人员站立--分析视频分析任务
     *
     */
    String Standup(String streamUrl, String startTime, String endTime);

    /**
     * 创建--人数异常--分析视频分析任务
     *
     */
    String PeopleNumChange(String streamUrl, String startTime, String endTime);


    /**
     * 创建--声强突变--分析视频分析任务
     *
     */
    String audioAbnormal(String streamUrl, String startTime, String endTime);


    /**
     * 创建--超时滞留--分析视频分析任务
     *
     */
     String overtimeTarry(String streamUrl, String startTime, String endTime);

    /**
     * 创建--攀高--分析视频分析任务
     *
     */
    String reachHeight(String streamUrl, String startTime, String endTime);


    /**
     * 查询分析视频分析任务状态
     *
     */
    String queryTaskVideoStatus(String taskId);



}

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

ListenThread.java



import com.ewaycloud.jw.ai.entity.AiResolveResult;
import com.ewaycloud.jw.ai.mapper.AiResolveResultMapper;
import com.ewaycloud.jw.task.entity.ContentTypeEnum;
import com.ewaycloud.jw.task.entity.Task;
import com.ewaycloud.jw.task.mapper.TaskMapper;
import com.mysql.cj.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.List;

/**
 * @author gwhui
 * @date 2024/1/18 17:38
 * @desc 监听处理线程
 */
@Slf4j
@Service
public class ListenThread implements Runnable {
    private final AlarmDataParser alarmDataParser = new AlarmDataParser();

    private static TaskMapper taskMapper;
    @Resource
    public void setVerificDao(TaskMapper taskMapper) {
        ListenThread.taskMapper = taskMapper;
    }
    private static AiResolveResultMapper aiResolveResultMapper;
    @Resource
    public void setVerificDao(AiResolveResultMapper aiResolveResultMapper) {
        ListenThread.aiResolveResultMapper = aiResolveResultMapper;
    }

    @Override
    public void run() {
//        int listenPort = propertiesUtil.getIntegerProperty("custom.isapi.listen.port", 9999);
        int listenPort =10006;
        try {
            ServerSocket serverSocket = new ServerSocket(listenPort);
            System.out.println("启动监听, 监听端口:" + listenPort);
            while (!Thread.currentThread().isInterrupted()) {
                Socket accept = serverSocket.accept();
                accept.setKeepAlive(true);
               System.out.println("设备(客户端)信息:" + accept.getInetAddress().getHostAddress());
                if (accept.isConnected()) {
                    handleData(accept);
                }
                accept.close();
            }
            serverSocket.close();
            System.out.println("停止监听完成");
        } catch (InterruptedException e) {
            // 线程被中断的处理逻辑
            System.out.println("停止监听完成: " + e.getMessage());
        } catch (Exception e) {
            System.out.println("监听创建异常: " + e.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public synchronized  void handleData(Socket accept) throws Exception {
        InputStream inputData = accept.getInputStream();
        OutputStream outputData = accept.getOutputStream();

        // 输出数据
        ByteArrayOutputStream byOutputData = new ByteArrayOutputStream();

        byte[] buffer = new byte[2 * 1024 * 1024];
        int length = 0;

        // 持续接收处理数据直到接收完毕
        String recvAlarmData = "";
        while ((length = inputData.read(buffer)) > 0) {
            byOutputData.write(buffer, 0, length);

            String recvData = byOutputData.toString();
            recvAlarmData = recvAlarmData + recvData;

            // 获取boundary
            String strBoundary = "boundary=";
            int beginIndex = recvData.indexOf(strBoundary);
            beginIndex += strBoundary.length();
            int lenIndex = recvData.indexOf("\r\n", beginIndex);
            String strBoundaryMark = recvData.substring(beginIndex, lenIndex);

            if (recvAlarmData.contains("--" + strBoundaryMark.trim() + "--")) {
                //表单结束符判断接收结束
                break;
            }
        }
//        System.out.println("==============recvAlarmData========>>  "+recvAlarmData);
        if(null != recvAlarmData){
            String taskId = null;
            int index = recvAlarmData.indexOf("<taskID>");
            if(index != -1){
                taskId = recvAlarmData.substring(index + 8, index + 40);
            }
            //获取服务器返回的图片
            String bkgUrl = null;
            int indexStartBkgUrl = recvAlarmData.indexOf("<bkgUrl>");
            int indexEndBkgUrl = recvAlarmData.indexOf("</bkgUrl>");
            if(indexStartBkgUrl != -1){
                bkgUrl = recvAlarmData.substring(indexStartBkgUrl+8, indexEndBkgUrl);
                bkgUrl =bkgUrl.replaceAll("&amp;","&");
            }
            System.out.println("===AIrecieveData===>>taskId:  "+taskId +" bkgUrl: "+ bkgUrl);
            //根据taskId查询 任务信息
            if(!StringUtils.isNullOrEmpty(taskId)){
                Task task = taskMapper.finTaskByTaskId(taskId);
                if(null != task){
                        AiResolveResult vo = new AiResolveResult();
                        vo.setCreateTime(new Date());
                        vo.setUpdateTime(new Date());
                        vo.setTaskId(taskId); //保存海康返回的 taskId
                        vo.setBreakName(task.getBreakName());
                        vo.setAiId(task.getAiId());
                        vo.setDeptId(task.getDeptId());
                        vo.setCameraId(task.getCameraId());
                        vo.setBreakTypeId(task.getAiId());
                        vo.setRiskTime(task.getTalkTime());
                        vo.setTalkAddress(task.getTalkAddress());
                        vo.setTalkAddressName(task.getTalkAddressName());
                        vo.setTalkUnit(task.getTalkUnit());
                        vo.setTalkUnitName(task.getTalkUnitName());
                        vo.setPhoto(bkgUrl); //保存海康返回的图片
                        vo.setCaseId(task.getCaseId());
                        vo.setCaseName(task.getCaseName());
                        vo.setInterviewerName(task.getInterviewerName());
                        //根据taskId查询任务结果表,如果有做更新操作,没有做插入操作
                        List<AiResolveResult>  aiResolveResults  =  aiResolveResultMapper.findAiResults(vo);
                        if(null != aiResolveResults && aiResolveResults.size()>0){
                            for(AiResolveResult aiResolveResult:aiResolveResults){
                                if(null != aiResolveResult){
                                    aiResolveResult.setPhoto(vo.getPhoto());
                                    aiResolveResultMapper.updateById(aiResolveResult);
                                }
                            }
                        }else {
                            aiResolveResultMapper.insert(vo);
                        }
                }

            }
        }
        String response = "HTTP/1.1 200 OK" +
                "\r\n" +
                "Connection: close" +
                "\r\n\r\n";
        outputData.write(response.getBytes());
        outputData.flush();
        outputData.close();
        inputData.close();
        //解析数据
        response = parseAlarmInfoByte(byOutputData);
        System.out.println("==============response========>>  "+response);
    }

    private String parseAlarmInfoByte(ByteArrayOutputStream byOutputData) throws Exception {
        // 事件报文字节
        byte[] byAlarmDataInfo = byOutputData.toByteArray();
        int iDataLen = byAlarmDataInfo.length;

        String szBoundaryMark = "boundary=";
        String szContentTypeMark = "Content-Type: ";
        int iTypeMarkLen = szContentTypeMark.getBytes("UTF-8").length;
        String szContentLenMark = "Content-Length: ";
        int iLenMarkLen = szContentLenMark.getBytes("UTF-8").length;
        String szContentLenMark2 = "content-length: ";
        int iLenMarkLen2 = szContentLenMark2.getBytes("UTF-8").length;
        int iContentLen = 0;
        String szEndMark = "\r\n";
        int iMarkLen = szEndMark.getBytes("UTF-8").length;
        String szEndMark2 = "\r\n\r\n";
        int iMarkLen2 = szEndMark2.getBytes("UTF-8").length;
        String szJson = "text/json";
        String szJpg = "image/jpeg";

        int iStartBoundary = doDataSearch(byAlarmDataInfo, szBoundaryMark.getBytes("UTF-8"), 0, byAlarmDataInfo.length);
        iStartBoundary += szBoundaryMark.getBytes("UTF-8").length;
        int iEndBoundary = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartBoundary, byAlarmDataInfo.length);
        byte[] byBoundary = new byte[iEndBoundary - iStartBoundary];
        System.arraycopy(byAlarmDataInfo, iStartBoundary, byBoundary, 0, iEndBoundary - iStartBoundary);

        String szBoundaryEndMark = "--" + new String(byBoundary).trim() + "--";
        int iDateEnd = doDataSearch(byAlarmDataInfo, szBoundaryEndMark.getBytes("UTF-8"), 0, byAlarmDataInfo.length);

        String szBoundaryMidMark = "--" + new String(byBoundary).trim();
        int iBoundaryMidLen = szBoundaryMidMark.getBytes("UTF-8").length;
        int startIndex = iEndBoundary;

        String szContentType = "";

        int[] iBoundaryPos = new int[11]; //boundary个数,这里最大解析10个
        int iBoundaryNum = 0;
        for (iBoundaryNum = 0; iBoundaryNum < 10; iBoundaryNum++) {
            startIndex = doDataSearch(byAlarmDataInfo, szBoundaryMidMark.getBytes("UTF-8"), startIndex, iDateEnd);
            if (startIndex < 0) {
                break;
            }
            startIndex += iBoundaryMidLen;
            iBoundaryPos[iBoundaryNum] = startIndex;
        }
        iBoundaryPos[iBoundaryNum] = iDateEnd;//最后一个是结束符

        for (int i = 0; i < iBoundaryNum; i++) {
            // Content-Type
            int iStartType = doDataSearch(byAlarmDataInfo, szContentTypeMark.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
            if (iStartType > 0) {
                iStartType += iTypeMarkLen;
                int iEndType = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartType, iBoundaryPos[i + 1]);
                if (iEndType > 0) {
                    byte[] byType = new byte[iEndType - iStartType];
                    System.arraycopy(byAlarmDataInfo, iStartType, byType, 0, iEndType - iStartType);
                    szContentType = new String(byType).trim();
                }
            }

            // Content-Length
            int iStartLength = doDataSearch(byAlarmDataInfo, szContentLenMark.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
            if (iStartLength > 0) {
                iStartLength += iLenMarkLen;
                int iEndLength = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartLength, iBoundaryPos[i + 1]);
                if (iEndLength > 0) {
                    byte[] byLength = new byte[iEndLength - iStartLength];
                    System.arraycopy(byAlarmDataInfo, iStartLength, byLength, 0, iEndLength - iStartLength);
                    iContentLen = Integer.parseInt(new String(byLength).trim());
                }
            }

            // Content-Length(兼容错误大小写)
            int iStartLength2 = doDataSearch(byAlarmDataInfo, szContentLenMark2.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
            if (iStartLength2 > 0) {
                iStartLength2 += iLenMarkLen2;
                int iEndLength2 = doDataSearch(byAlarmDataInfo, szEndMark.getBytes("UTF-8"), iStartLength2, iBoundaryPos[i + 1]);
                if (iEndLength2 > 0) {
                    byte[] byLength2 = new byte[iEndLength2 - iStartLength2];
                    System.arraycopy(byAlarmDataInfo, iStartLength2, byLength2, 0, iEndLength2 - iStartLength2);
                    iContentLen = Integer.parseInt(new String(byLength2).trim());
                }
            }

            // 通过\r\n\r\n判断报文数据起始位置
            int iStartData = doDataSearch(byAlarmDataInfo, szEndMark2.getBytes("UTF-8"), iBoundaryPos[i], iBoundaryPos[i + 1]);
            if (iStartData > 0) {
                iStartData += iMarkLen2;

                // 有的报文可能没有Content-Length
                if (iContentLen <= 0) {
                    iContentLen = iBoundaryPos[i + 1] - iStartData;
                }

                // 截取数据内容
                byte[] byData = new byte[iContentLen];
                System.arraycopy(byAlarmDataInfo, iStartData, byData, 0, iContentLen);

                // 根据类型处理数据
                int contentType = ContentTypeEnum.getEventType(szContentType);
                String storeFolder = System.getProperty("user.dir") + "\\output\\listen\\event\\";
                switch (contentType) {
                    case ContentTypeEnum.APPLICATION_JSON:
                    case ContentTypeEnum.APPLICATION_XML: {
                        String rawContent = new String(byData).trim();
                        alarmDataParser.parseAlarmInfo(contentType, storeFolder, rawContent, null);
                        break;
                    }
                    case ContentTypeEnum.IMAGE_JPEG:
                    case ContentTypeEnum.IMAGE_PNG:
                    case ContentTypeEnum.VIDEO_MPG:
                    case ContentTypeEnum.VIDEO_MPEG4:
                    case ContentTypeEnum.APPLICATION_ZIP: {
                        alarmDataParser.parseAlarmInfo(contentType, storeFolder, null, byData);
                        break;
                    }
                    default: {
                        System.out.println("未匹配到可以解析的content-type, 请自行补全处理!");
                    }
                }
            }
        }
        // 响应报文
        String response = "";

        // 消费交易事件 (实际如果没有消费机设备可以不需要消费机的处理代码)
        String eventType = "";
        String eventConfirm = "";
        if (eventType.equals("ConsumptionEvent") || eventType.equals("TransactionRecordEvent") || eventType.equals("HealthInfoSyncQuery")) {
            response = "HTTP/1.1 200 OK" +
                    "\r\n" +
                    "Content-Type: application/json; charset=\"UTF-8\"" +
                    "\r\n" +
                    "Content-Length: " + eventConfirm.length() +
                    "\r\n\r\n" + eventConfirm +
                    "\r\n";
        } else {
            response = "HTTP/1.1 200 OK" +
                    "\r\n" +
                    "Connection: close" +
                    "\r\n\r\n";
        }

        return response;
    }

    private int doDataSearch(byte[] bySrcData, byte[] keyData, int startIndex, int endIndex) {
        if (bySrcData == null || keyData == null || bySrcData.length <= startIndex || bySrcData.length < keyData.length) {
            return -1;
        }

        if (endIndex > bySrcData.length) {
            endIndex = bySrcData.length;
        }

        int iPos, jIndex;
        for (iPos = startIndex; iPos < endIndex; iPos++) {
            if (bySrcData.length < keyData.length + iPos) {
                break;
            }

            for (jIndex = 0; jIndex < keyData.length; jIndex++) {
                if (bySrcData[iPos + jIndex] != keyData[jIndex]) {
                    break;
                }
            }
            if (jIndex == keyData.length) {
                return iPos;
            }
        }
        return -1;
    }


}

4、数据库设计

瀚高国产数据库

        

5、前端页面设计

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1853677.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

物联网系统运维——数据库部署

一.MySQL 1.概要 MySQL是一种关联数据库管理系统&#xff0c;关联数据:而不是将所有数据放在一个大仓库内&#xff0c;这样就增加了速度并提高了灵活性库将数据保存在不同的表中。性能高、成本低、可靠性好&#xff0c;已经成为最流行的开源数据库。 二.MySQL安装与配置 1. …

赶论文不用愁:如何利用ChatGPT在3小时内完成论文

在这份指南里&#xff0c;我将详细介绍如何运用ChatGPT 4.0的高级功能来辅助学术研究与文章写作。从挖掘研究课题的初步想法开始&#xff0c;到撰写一篇内容深刻、结构完整的学术论文&#xff0c;我将逐步演示如何在研究的各个阶段中充分利用ChatGPT。值得一提的是&#xff0c;…

每日一题——Python代码实现PAT乙级1048 数字加密(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 初次尝试 再次尝试 代码点评 代码结构 时间复杂度 空间复杂度 优化建议 我要更强…

【python】python海底捞门店营业数据分析与可视化(数据集+源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

自2008年金融危机以来首次,欧洲AAA级CMBS投资者面临亏损

在欧洲预期损失之前&#xff0c;美国AAA级CMBS投资者已经遭受了打击。即便是最高信用等级的投资也不再安全&#xff0c;全球金融系统可能存在一些严重的问题。 历史罕见&#xff0c;最安全的AAA级债权人&#xff0c;在没有发生经济危机的情况下&#xff0c;出现了损失&#xff…

Pwn刷题记录(不停更新)

1、CTFshow-pwn04&#xff08;基础canary&#xff09; ​ 好久没碰过pwn了&#xff0c;今天临时做一道吧&#xff0c;毕竟刚联合了WSL和VSCode&#xff0c;想着试着做一道题看看&#xff0c;结果随手一点&#xff0c;就是一个很少接触的&#xff0c;拿来刷刷&#xff1a; ​ …

ClickHouse备份方案

ClickHouse备份方案主要包括以下几种方法&#xff1a; 一、使用clickhouse-backup工具&#xff1a; &#xff08;参考地址&#xff1a;https://blog.csdn.net/qq_43510111/article/details/136570850&#xff09; **安装与配置&#xff1a;**首先从GitHub获取clickhouse-bac…

apksigner jarsigner.md

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、apksigner3.2 为 APK 签名3.3 验证…

【深海王国】小学生都能玩的单片机?零基础入门单片机Arduino带你打开嵌入式的大门!(8)

Hi٩(๑o๑)۶, 各位深海王国的同志们&#xff0c;早上下午晚上凌晨好呀~辛勤工作的你今天也辛苦啦 (o゜▽゜)o☆ 今天大都督继续为大家带来系列——小学生都能玩的单片机&#xff01;带你一周内快速走进嵌入式的大门&#xff0c;let’s go&#xff01; &#xff08;8&#x…

系统安全设计规范(Word原件)

1.1安全建设原则 1.2 安全管理体系 1.3 安全管理规范 1.4 数据安全保障措施 1.4.1 数据库安全保障 1.4.2 操作系统安全保障 1.4.3 病毒防治 1.5安全保障措施 1.5.1实名认证保障 1.5.2 接口安全保障 1.5.3 加密传输保障 1.5.4终端安全保障 资料获取&#xff1a;私信或者进主页。…

PAT A1016. 最短路径

题意 有N个结点围成一个圈&#xff0c;相邻两个点之间的距离已知&#xff0c;且每次只能移动到相邻点。然后给出M个询问&#xff0c;每个询问给出两个数字A和B即结点编号(1≤A,B≤N)&#xff0c;求从A号结点到B号结点的最短距离。样例解释 如图3-2所示,共有5个结点&#xff0c;…

昇思25天学习打卡营第5天 | 网络构建

内容介绍&#xff1a;神经网络模型是由神经网络层和Tensor操作构成的&#xff0c;mindspore.nn提供了常见神经网络层的实现&#xff0c;在MindSpore中&#xff0c;Cell类是构建所有网络的基类&#xff0c;也是网络的基本单元。一个神经网络模型表示为一个Cell&#xff0c;它由不…

让你的Python代码更简洁:一篇文章带你了解Python列表推导式

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 列表推导式 📒📝 语法📝 条件筛选📝 多重循环📝 列表推导式的优点📝 使用场景📝 示例代码🎯 示例1🎯 示例2⚓️ 相关链接 ⚓️📖 介绍 📖 在Python编程中,列表推导式是一种强大且高效的语法,它允许你用…

2024-06-17 问AI: 在深度学习中,harmonic mean是什么?

文心一言 在深度学习中&#xff0c;**harmonic mean&#xff08;调和平均数&#xff09;**是一个用于评估模型性能的指标&#xff0c;特别是在处理不平衡的数据集或需要综合多个评估指标的场景中。以下是关于harmonic mean在深度学习中应用的详细解释&#xff1a; 定义&#…

6 PXE高效批量网络装机

6.1部署PXE远程安装服务 在大规模的Liunx应用环境中&#xff0c;如web群集&#xff0c;分布式计算等&#xff0c;服务器往往并不配备光驱设备&#xff0c;在这种情况下&#xff0c;如何为数十乃至上百台服务器裸机快速安装系统呢&#xff1f;传统的USB光驱&#xff0c;移动硬盘…

【数学】100332. 包含所有 1 的最小矩形面积 II

本文涉及知识点 数学 LeetCode100332. 包含所有 1 的最小矩形面积 II 给你一个二维 二进制 数组 grid。你需要找到 3 个 不重叠、面积 非零 、边在水平方向和竖直方向上的矩形&#xff0c;并且满足 grid 中所有的 1 都在这些矩形的内部。 返回这些矩形面积之和的 最小 可能值…

一个整数使用英文表达的字母计数

题目&#xff1a; 把1到5写成英文单词分别是&#xff1a;one、two、three、four、five。这些单词一共用了33544 19 个字母。 如果把1到1000都写成英文单词&#xff0c;一共要用多少个字母&#xff1f; 注&#xff1a;不计入空格和连字符&#xff0c;例如&#xff0c;342&am…

CentOS 7 内核 3.10 升级 6.5.2 (RPM 直装 + 源码编译)

方案一 直接基于 RPM 在线升级&#xff08;简单&#xff0c;速度快&#xff09; rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org yum install https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm -y # &#xff08;选项一&#xff09;升级最新版内…

linux系统cpu飙高如何排查

1.通过top命令查看cpu占比较高的进程ID 2.通过top -H -p <进程ID>命令查看该进程中具体线程&#xff0c;可以看到第一个线程 4311 占用了88.2%的cpu 3.通过 printf "%x\n" <线程ID> 把10进制的线程id转为16进制 4.通过jstack <进程ID> | grep &…

解决ArcGIS导出的svg格式的图片插入Word后的字体问题

背景 在ArcGIS中设置字体为Times New Roman&#xff0c;但导入Word后字体转为等线。 ArcGIS中的Layout 导入Word​​​​​​ 原因分析 Word无法识别嵌入进SVG格式文件中的字体。 解决方案 在Export Layer窗口中&#xff0c;将Embed fonts取消勾选&#xff0c;Convert cha…