03/29 使用 海康SDK 对接时使用的 MysqlUtils

news2025/2/11 9:49:54

前言

最近朋友的需求, 是需要使用 海康sdk 连接海康设备, 进行数据的获取, 比如 进出车辆, 进出人员 

这一部分是 资源比较贫瘠时的一个 Mysql 工具类 

 

 

测试用例

public class MysqlUtils {

    public static String MYSQL_HOST = "192.168.31.9";
    public static int MYSQL_PORT = 3306;
    public static String MYSQL_DB = "20240811_vehicle_stats";
    public static String MYSQL_USERNAME = "root";
    public static String MYSQL_PASSWORD = "postgres";

    public static String COLUMN_CATM = "catm";
    public static String COLUMN_UPTM = "uptm";
    public static String SQL_DUMMY_SQL = "select 1;";

    public static boolean DEFAULT_ADD_CATM_UPTM = false;

    public static SingleStringColumnExtractor SINGLE_STRING_COLUMN_EXTRACTOR = new SingleStringColumnExtractor();
    public static GenericMapExtractor GENERIC_MAP_EXTRACTOR = new GenericMapExtractor();
    public static MyStatsVehicleFlowLogExtractor MY_STATISTICS_VEHICLE_FLOW_LOG_EXTRACTOR = new MyStatsVehicleFlowLogExtractor();
    public static MyStatsPeopleFlowLogExtractor MY_STATISTICS_PEOPLE_FLOW_LOG_EXTRACTOR = new MyStatsPeopleFlowLogExtractor();

    // disable constructor
    private MysqlUtils() {
        System.err.println("can't instantiate !");
    }

    // mysql jdbcDriver
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.err.println("can't found jdbcDriver !");
        }
    }

    public static void init() {
        MYSQL_HOST = ConfigUtils.getString("MYSQL_HOST", MYSQL_HOST);
        MYSQL_PORT = ConfigUtils.getInt("MYSQL_PORT", MYSQL_PORT);
        MYSQL_DB = ConfigUtils.getString("MYSQL_DB", MYSQL_DB);
        MYSQL_USERNAME = ConfigUtils.getString("MYSQL_USERNAME", MYSQL_USERNAME);
        MYSQL_PASSWORD = ConfigUtils.getString("MYSQL_PASSWORD", MYSQL_PASSWORD);

        DEFAULT_ADD_CATM_UPTM = ConfigUtils.getString("DEFAULT_ADD_CATM_UPTM", String.valueOf(DEFAULT_ADD_CATM_UPTM)).equalsIgnoreCase("true");
    }

    // 获取 jdbc 链接
    public static Connection getConnection(String ip, int port, String dbName, String userName, String password) {
        Connection con = null;
        try {
            con = DriverManager.getConnection(String.format("jdbc:mysql://%s:%d/%s?useUnicode=true&characterEncoding=UTF8", ip, port, dbName), userName, password);
        } catch (SQLException se) {
            se.printStackTrace();
            System.err.println("error while try to get an connection !");
        }

        return con;
    }

    public static Connection getConnection() {
        return MysqlUtils.getConnection(MYSQL_HOST, MYSQL_PORT, MYSQL_DB, MYSQL_USERNAME, MYSQL_PASSWORD);
    }

    // 执行 jdbc 查询
    public static <T> List<T> executeQuery(String sql, Function<ResultSet, T> recordExtractor) {
        Connection con = MysqlUtils.getConnection(MYSQL_HOST, MYSQL_PORT, MYSQL_DB, MYSQL_USERNAME, MYSQL_PASSWORD);
        PreparedStatement stat = null;
        ResultSet rs = null;
        List<T> result = new ArrayList<>();
        try {
            stat = con.prepareStatement(sql);
            rs = stat.executeQuery();
            while (rs.next()) {
                result.add(recordExtractor.apply(rs));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if(stat != null) {
                    stat.close();
                }
                if(rs != null) {
                    rs.close();
                }
                if (con != null) {
                    con.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public static List<Map<String, Object>> executeQuery(String sql) {
        return executeQuery(sql, GENERIC_MAP_EXTRACTOR);
    }

    // 执行 jdbc 更新
    public static int executeUpdate(String sql) {
        Connection con = MysqlUtils.getConnection(MYSQL_HOST, MYSQL_PORT, MYSQL_DB, MYSQL_USERNAME, MYSQL_PASSWORD);
        PreparedStatement stat = null;
        int updated = -1;
        try {
            stat = con.prepareStatement(sql);
            updated = stat.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if(stat != null) {
                    stat.close();
                }
                if (con != null) {
                    con.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return updated;
    }


    public static String assembleInsertSql(String tableName, Map<String, Object> entity, boolean addCommonFields) {
        String insertSqlTemplate = " insert into %s (%s) values (%s); ";
        List<String> fieldNames = new ArrayList<>(), fieldValues = new ArrayList<>();
        for (String fieldName : entity.keySet()) {
            Object originalFieldValue = entity.get(fieldName);
            String fieldValue = resolveFieldValue(entity, fieldName, originalFieldValue);
            fieldNames.add(String.format("`%s`", fieldName));
            fieldValues.add(transferFieldValueIfNecessary(fieldValue));
        }
        if (addCommonFields) {
            Long currentTs = System.currentTimeMillis();
            addFixedFieldNames(fieldNames, currentTs, true);
            addFixedFieldValues(fieldValues, currentTs, true);
        }

        String sql = String.format(insertSqlTemplate, tableName,
                join(fieldNames, ", "),
                join(fieldValues, ", ")
        );
        return sql;
    }

    public static String assembleInsertSql(String tableName, Map<String, Object> entity) {
        return assembleInsertSql(tableName, entity, DEFAULT_ADD_CATM_UPTM);
    }

    public static String assembleBatchInsertSql(String tableName, List<Map<String, Object>> entityList, boolean addCommonFields) {
        String insertSqlTemplate = " insert into %s (%s) values %s; ";
        List<String> insertFieldNames = new ArrayList<>(), outerFieldValues = new ArrayList<>();
        Set<String> fieldNames = new LinkedHashSet<>();
        Long currentTs = System.currentTimeMillis();

        for (Map<String, Object> entity : entityList) {
            fieldNames.addAll(entity.keySet());
        }
        for (String fieldName : fieldNames) {
            insertFieldNames.add(String.format("`%s`", fieldName));
        }
        if (addCommonFields) {
            addFixedFieldNames(insertFieldNames, currentTs, true);
        }

        for (Map<String, Object> entity : entityList) {
            List<String> fieldValues = new ArrayList<>();
            for (String fieldName : fieldNames) {
                Object originalFieldValue = entity.get(fieldName);
                String fieldValue = resolveFieldValue(entity, fieldName, originalFieldValue);
                fieldValues.add(transferFieldValueIfNecessary(fieldValue));
            }

            if (addCommonFields) {
                addFixedFieldValues(fieldValues, currentTs, true);
            }
            outerFieldValues.add(String.format("(%s)", join(fieldValues, ", ")));
        }

        String sql = String.format(insertSqlTemplate, tableName,
                join(insertFieldNames, ", "),
                join(outerFieldValues, ", ")
        );
        return sql;
    }

    public static String assembleBatchInsertSql(String tableName, List<Map<String, Object>> entityList) {
        return assembleBatchInsertSql(tableName, entityList, DEFAULT_ADD_CATM_UPTM);
    }

    public static String assembleUpdateSql(String tableName, String idFieldName, Map<String, Object> entity, boolean addCommonFields) {
        String updateSqlTemplate = " update %s set %s %s; ";
        List<String> fieldNames = new ArrayList<>(), fieldValues = new ArrayList<>();
        for (String fieldName : entity.keySet()) {
            Object originalFieldValue = entity.get(fieldName);
            String fieldValue = resolveFieldValue(entity, fieldName, originalFieldValue);
            fieldNames.add(String.format("`%s`", fieldName));
            fieldValues.add(transferFieldValueIfNecessary(fieldValue));
        }
        if (addCommonFields) {
            Long currentTs = System.currentTimeMillis();
            addFixedFieldNames(fieldNames, currentTs, false);
            addFixedFieldValues(fieldValues, currentTs, false);
        }

        List<String> setClauseList = new ArrayList<>();
        for (int i = 0; i < fieldNames.size(); i++) {
            setClauseList.add(String.format(" %s = %s ", fieldNames.get(i), fieldValues.get(i)));
        }
        String setClause = join(setClauseList, ", ");

        String idValue = String.valueOf(entity.get(idFieldName));
        String whereCond = String.format(" where %s = %s ", idFieldName, transferFieldValueIfNecessary(idValue));

        String sql = String.format(updateSqlTemplate, tableName, setClause, whereCond);
        return sql;
    }

    public static String assembleUpdateSql(String tableName, String idFieldName, Map<String, Object> entity) {
        return assembleUpdateSql(tableName, idFieldName, entity, DEFAULT_ADD_CATM_UPTM);
    }

    public static List<String> assembleBatchSaveSql(String tableName, String idFieldName,
                                                    List<Map<String, Object>> entityList, Function<ResultSet, String> idExtractor,
                                                    boolean addCommonFields) {
        List<String> idList = entityList.stream().map(ele -> String.valueOf(ele.get(idFieldName))).collect(Collectors.toList());
        List<String> existsIdList = selectExistsById(tableName, idFieldName, idList, idExtractor);
        Map<String, Map<String, Object>> toInsertById = new LinkedHashMap<>(), toUpdateById = new LinkedHashMap<>();
        for (Map<String, Object> entity : entityList) {
            String idValue = String.valueOf(entity.get(idFieldName));

            Map<String, Map<String, Object>> entityByIdTmp = toInsertById;
            if (existsIdList.contains(idValue)) {
                entityByIdTmp = toUpdateById;
            }
            entityByIdTmp.put(idValue, entity);
        }

        List<String> result = new ArrayList<>();
        String insertSql = SQL_DUMMY_SQL;
        List<Map<String, Object>> toInsertList = new ArrayList<>(toInsertById.values());
        if (!isEmpty(toInsertList)) {
            insertSql = assembleBatchInsertSql(tableName, toInsertList, addCommonFields);
        }
        result.add(insertSql);

        List<Map<String, Object>> toUpdateList = new ArrayList<>(toUpdateById.values());
        for (Map<String, Object> toUpdate : toUpdateList) {
            String updateSql = assembleUpdateSql(tableName, idFieldName, toUpdate, addCommonFields);
            result.add(updateSql);
        }
        return result;
    }

    public static <T> List<String> assembleBatchSaveSql(String tableName, String idFieldName,
                                                        List<Map<String, Object>> entityList, Function<ResultSet, String> recordExtractor) {
        return assembleBatchSaveSql(tableName, idFieldName, entityList, recordExtractor, true);
    }

    public static List<String> selectExistsById(String tableName, String idFieldName, List<String> idList, Function<ResultSet, String> recordExtractor) {
        if (isEmpty(idList)) {
            return Collections.emptyList();
        }

        String querySqlTemplate = " select %s as id from %s %s; ";
        String idInSnippet = join(idList.stream().map(MysqlUtils::transferFieldValueIfNecessary).collect(Collectors.toList()), ", ");
        String whereCond = String.format(" where %s in (%s) ", idFieldName, idInSnippet);
        String querySql = String.format(querySqlTemplate, idFieldName, tableName, whereCond);

        return executeQuery(querySql, recordExtractor);
    }

    public static String generateQuerySql(String tableName, String whereCond) {
        String querySql = String.format(" select * from %s ", tableName);
        if (isNotBlank(whereCond)) {
            querySql = String.format(" %s where %s ", querySql, whereCond);
        }
        return querySql;
    }

    public static String generateDeleteSql(String tableName, String whereCond) {
        String querySql = String.format(" delete from %s ", tableName);
        if (isNotBlank(whereCond)) {
            querySql = String.format(" %s where %s ", querySql, whereCond);
        }
        return querySql;
    }

    public static String resolveFieldValue(Map<String, Object> entity, String fieldName, Object fieldValue) {
        if (fieldValue == null) {
            return null;
        }

        if (fieldValue instanceof Date) {
            return DateFormatUtils.format((Date) fieldValue);
        }
        if (fieldValue instanceof LocalDateTime) {
            LocalDateTime dateTime = ((LocalDateTime) fieldValue);
            return String.format("%s-%s-%s %s:%s:%s",
                    String.format("%04d", dateTime.getYear()),
                    String.format("%02d", dateTime.getMonthValue()),
                    String.format("%02d", dateTime.getDayOfMonth()),
                    String.format("%02d", dateTime.getHour()),
                    String.format("%02d", dateTime.getMinute()),
                    String.format("%02d", dateTime.getSecond())
            );
        }

        return String.valueOf(fieldValue);
    }

    public static void addFixedFieldNames(List<String> fieldNames, Long currentTs, boolean addCatm) {
        if (addCatm) {
            fieldNames.add(COLUMN_CATM);
        }
        fieldNames.add(COLUMN_UPTM);
    }

    public static void addFixedFieldValues(List<String> fieldValues, Long currentTs, boolean addCatm) {
        if (addCatm) {
            fieldValues.add(transferFieldValueIfNecessary(String.valueOf(currentTs)));
        }
        fieldValues.add(transferFieldValueIfNecessary(String.valueOf(currentTs)));
    }

    public static String transferFieldValueIfNecessary(String fieldValue) {
        if (fieldValue == null) {
            return "NULL";
        }

        if (fieldValue.contains("\"")) {
            fieldValue = fieldValue.replace("\"", "\\\"");
        }
        return String.format("\"%s\"", fieldValue);
    }

    public static String transferSingleQuoteFieldValueIfNecessary(String fieldValue) {
        if (fieldValue == null) {
            return "NULL";
        }

        if (fieldValue.contains("'")) {
            fieldValue = fieldValue.replace("'", "\\'");
        }
        return String.format("'%s'", fieldValue);
    }

    public static void fillOrTrimToFieldNames(Map<String, Object> entity, List<String> fieldNames, String defaultValue) {
        List<String> field2Remove = new ArrayList<>();
        for (Map.Entry<String, Object> entry : entity.entrySet()) {
            String fieldName = entry.getKey();
            if (!fieldNames.contains(fieldName)) {
                field2Remove.add(fieldName);
            }
        }
        for (String fieldName : field2Remove) {
            entity.remove(fieldName);
        }

        for (String fieldName : fieldNames) {
            if (!entity.containsKey(fieldName)) {
                entity.put(fieldName, defaultValue);
            }
        }
    }

    public static void fillOrTrimToFieldNames(Map<String, Object> entity, List<String> fieldNames) {
        fillOrTrimToFieldNames(entity, fieldNames, "");
    }

    public static String wrapSqlIn(List<String> list) {
        if (isEmpty(list)) {
            return "";
        }

        return String.format("\"%s\"", join(list, "\", \""));
    }

    public static boolean isBlank(String str) {
        return str == null || str.trim().length() == 0;
    }

    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }

    public static <T> boolean isEmpty(Collection<T> list) {
        return list == null || (list.size() == 0);
    }

    public static <T> String join(Collection<T> list, String seprator) {
        StringBuffer result = new StringBuffer();
        for (Iterator ite = list.iterator(); ite.hasNext(); result.append((String) ite.next())) {
            if (result.length() != 0) {
                result.append(seprator);
            }
        }
        return result.toString();
    }

}

 

 

GenericMapExtractor
public class GenericMapExtractor implements Function<ResultSet, Map<String, Object>> {

    @Override
    public Map<String, Object> apply(ResultSet resultSet) {
        try {
            Map<String, Object> result = new LinkedHashMap<>();
            int columnCount = resultSet.getMetaData().getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                String columnName = resultSet.getMetaData().getColumnName(i);
                result.put(columnName, resultSet.getObject(columnName));
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}

 

 

MyStatsPeopleFlowLogExtractor
public class MyStatsPeopleFlowLogExtractor implements Function<ResultSet, StatsPeopleFlowLog> {

    @Override
    public StatsPeopleFlowLog apply(ResultSet resultSet) {
        try {
            Map<String, Object> entityMap = MysqlUtils.GENERIC_MAP_EXTRACTOR.apply(resultSet);
            JSONObject entityJson = (JSONObject) JSON.toJSON(entityMap);
            return StatsPeopleFlowLog.fromJSON(entityJson);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

 

 

部分截图

 

 

完 

 

 

 

 

 

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

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

相关文章

IDEA编写SpringBoot项目时使用Lombok报错“找不到符号”的原因和解决

目录 概述|背景 报错解析 解决方法 IDEA配置解决 Pom配置插件解决 概述|背景 报错发生背景&#xff1a;在SpringBoot项目中引入Lombok依赖并使用后出现"找不到符号"的问题。 本文讨论在上述背景下发生的报错原因和解决办法&#xff0c;如果仅为了解决BUG不论原…

将仓库A分支同步到仓库B分支,并且同步commit提交

一、 问题 有一仓库A 和 一仓库B&#xff0c; 需要将仓库A分支a1所有提交同步推送到仓库B分支b1上 二、 解决 2.1、 首先需要仓库A、仓库B的权限&#xff0c; 2.2、将仓库A clone到本地&#xff0c; 进入A目录&#xff0c;并且切换到a1分支 cd A ## A 为A仓库clone到本地代…

Windows Docker笔记-Docker拉取镜像

通过在前面的章节《安装docker》中&#xff0c;了解并安装成功了Docker&#xff0c;本章讲述如何使用Docker拉取镜像。 使用Docker&#xff0c;主要是想要创建并运行Docker容器&#xff0c;而容器又要根据Docker镜像来创建&#xff0c;那么首当其冲&#xff0c;必须要先有一个…

穷举vs暴搜vs深搜vs回溯vs剪枝系列一>黄金矿工

目录 决策树&#xff1a;代码设计代码&#xff1a; 决策树&#xff1a; 代码设计 代码&#xff1a; class Solution {boolean[][] vis;int ret,m,n;public int getMaximumGold(int[][] grid) {m grid.length;n grid[0].length;vis new boolean[m][n]; for(int i 0; i <…

07苍穹外卖之redis缓存商品、购物车(redis案例缓存实现)

课程内容 缓存菜品 缓存套餐 添加购物车 查看购物车 清空购物车 功能实现&#xff1a;缓存商品、购物车 效果图&#xff1a; 1. 缓存菜品 1.1 问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压…

使用DeepSeek的技巧笔记

来源&#xff1a;新年逼自己一把&#xff0c;学会使用DeepSeek R1_哔哩哔哩_bilibili 前言 对于DeepSeek而言&#xff0c;我们不再需要那么多的提示词技巧&#xff0c;但还是要有两个注意点&#xff1a;你需要理解大语言模型的工作原理与局限,这能帮助你更好的知道AI可完成任务…

Unity-Mirror网络框架-从入门到精通之CouchCoop示例

文章目录 前言示例NetworkManagerCouchPlayerManagerCouchPlayerPlatformMovementMovingPlatformCameraViewForAllCanvasScript前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。本系列文章将为读者提供对Mirror网络框架的深入了解,涵盖从基础到高级的多…

Spring Boot Web 入门

目录 Spring Boot Web 是 Spring Boot 框架的一个重要模块&#xff0c;它简化了基于 Spring 的 Web 应用程序的开发过程。以下是一个 Spring Boot Web 项目的入门指南&#xff0c;涵盖了项目创建、代码编写、运行等关键步骤。 1. 项目创建 使用 Spring Initializr 使用 IDE …

DeepSeek图解10页PDF

以前一直在关注国内外的一些AI工具&#xff0c;包括文本型、图像类的一些AI实践&#xff0c;最近DeepSeek突然爆火&#xff0c;从互联网收集一些资料与大家一起分享学习。 本章节分享的文件为网上流传的DeepSeek图解10页PDF&#xff0c;免费附件链接给出。 1 本地 1 本地部…

【Golang学习之旅】Go + MySQL 数据库操作详解

文章目录 前言1. GORM简介2. 安装GORM并连接MySQL2.1 安装GORM和MySQL驱动2.2 连接MySQL 3. GORM数据模型&#xff08;Model&#xff09;3.1 定义User结构体3.2 自动迁移&#xff08;AutoMigrate&#xff09; 4. GORM CRUD 操作4.1 插入数据&#xff08;Create&#xff09;4.2 …

ArgoCD实战指南:GitOps驱动下的Kubernetes自动化部署与Helm/Kustomize集成

摘要 ArgoCD 是一种 GitOps 持续交付工具,专为 Kubernetes 设计。它能够自动同步 Git 仓库中的声明性配置,并将其应用到 Kubernetes 集群中。本文将介绍 ArgoCD 的架构、安装步骤,以及如何结合 Helm 和 Kustomize 进行 Kubernetes 自动化部署。 引言 为什么选择 ArgoCD?…

每日Attention学习22——Inverted Residual RWKV

模块出处 [arXiv 25] [link] [code] RWKV-UNet: Improving UNet with Long-Range Cooperation for Effective Medical Image Segmentation 模块名称 Inverted Residual RWKV (IR-RWKV) 模块作用 用于vision的RWKV结构 模块结构 模块代码 注&#xff1a;cpp扩展请参考作者原…

机器学习之数学基础:线性代数、微积分、概率论 | PyTorch 深度学习实战

前一篇文章&#xff0c;使用线性回归模型逼近目标模型 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 本篇文章内容来自于 强化学习必修课&#xff1a;引领人工智能新时代【梗直哥瞿炜】 线性代数、微积分、概率论 …

UNI-MOL: A UNIVERSAL 3D MOLECULAR REPRESENTATION LEARNING FRAMEWORK

UNI-MOL: A UNIVERSAL 3D MOLECULAR REPRESENTATION LEARNING FRAMEWORK Neurips23 推荐指数&#xff1a;#paper/⭐⭐⭐#​&#xff08;工作量不小) 动机 在大多数分子表征学习方法中&#xff0c;分子被视为 1D 顺序标记或2D 拓扑图&#xff0c;这限制了它们为下游任务整合…

SQL Server查询计划操作符(7.3)——查询计划相关操作符(6)

7.3. 查询计划相关操作符 48)Key Lookup:该操作符对一个有簇索引的表进行书签查找。参数列包含簇索引的名字和用于查找簇索引中数据行的簇键。该操作符总是伴随一个Nested Loops操作符。如果其参数列中出现WITH PREFETCH子句,则查询处理器已决定使用异步预取(预读,read-ah…

C语言【基础篇】之数组——解锁多维与动态数组的编程奥秘

数组 &#x1f680;前言&#x1f99c;数组的由来与用途&#x1f31f;一维数组详解&#x1f58a;️二维数组进阶&#x1f4af;动态数组原理&#x1f914;常见误区扫盲&#x1f4bb;学习路径建议✍️总结 &#x1f680;前言 大家好&#xff01;我是 EnigmaCoder。本文收录于我的专…

掌握API和控制点(从Java到JNI接口)_38 JNI从C调用Java函数 01

1. Why? 将控制点下移到下C/C层 对古典视角的反思 App接近User&#xff0c;所以App在整体架构里&#xff0c;是主导者&#xff0c;拥有控制权。所以&#xff0c; App是架构的控制点所在。Java函数调用C/C层函数&#xff0c;是合理的。 但是EIT造形告诉我们&#xff1a; App…

windows蓝牙驱动开发-蓝牙 LE 邻近感应配置文件

邻近感应检测是蓝牙低功耗 (LE) 的常见用途。 本部分提供了创建可用于开发 UWP 设备应用的邻近感应配置文件的设备实现的指南。 在开发此应用之前&#xff0c;应熟悉蓝牙 LE 函数和蓝牙 LE 邻近感应配置文件规范。 示例服务声明 蓝牙低功耗引入了一个新的物理层&#xff0c;…

免费windows pdf编辑工具Epdf

Epdf&#xff08;完全免费&#xff09; 作者&#xff1a;不染心 时间&#xff1a;2025/2/6 Github: https://github.com/dog-tired/Epdf Epdf Epdf 是一款使用 Rust 编写的 PDF 编辑器&#xff0c;目前仍在开发中。它提供了一系列实用的命令行选项&#xff0c;方便用户对 PDF …

C++:类和对象初识

C&#xff1a;类和对象初识 前言类的引入与定义引入定义类的两种定义方法1. 声明和定义全部放在类体中2. 声明和定义分离式 类的成员变量命名规则 类的访问限定符及封装访问限定符封装 类的作用域与实例化类的作用域类实例化实例化方式&#xff1a; 类对象模型类对象的大小存储…