03/29 使用 海康SDK 对接时使用的 MysqlUtils
前言
最近朋友的需求, 是需要使用 海康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 constructorprivate MysqlUtils() {System.err.println("can't instantiate !");}// mysql jdbcDriverstatic {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>> {@Overridepublic 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> {@Overridepublic 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;}}
}
部分截图

完
相关文章:
03/29 使用 海康SDK 对接时使用的 MysqlUtils
前言 最近朋友的需求, 是需要使用 海康sdk 连接海康设备, 进行数据的获取, 比如 进出车辆, 进出人员 这一部分是 资源比较贫瘠时的一个 Mysql 工具类 测试用例 public class MysqlUtils {public static String MYSQL_HOST "192.168.31.9";public static int MY…...
2025.2.7 Python开发岗面试复盘
2025.2.7 Python开发岗面试复盘 问题: 是否了解过其他语言? 了解过Java、JavaScript、C等语言,但主要技术栈是Python。 Python跟Java的区别? Python是解释型语言,Java是编译型语言 Python动态类型,Java静态类型 Python简洁易读,Java相对严谨复杂 Python GIL限制并发,Java并…...
一个sql只能有一个order by
ORDER BY 子句在 SQL 中只能出现一次,静态部分和动态部分只能写一个 ORDER BY...
Windows Docker笔记-在容器中运行项目
在文章《Windows Docker笔记-Docker容器操作》中,已经成功创建了容器,也就是建好了工厂,接下来就应该要安装流水线设备,即运行项目达到生产的目的。 在Ubuntu容器中新建项目 这里要新建一个简单的C项目,步骤如下&…...
postgreSQL16.6源码安装
1.获取源码 从PostgreSQL: File Browser获取tar.bz2或者tar.gz源码 2.解压 tar xf postgresql-version.tar.bz2 roothwz-VMware-Virtual-Platform:/usr/local# tar xf postgresql-16.6.tar.bz2 roothwz-VMware-Virtual-Platform:/usr/local# ll 总计 24324 drwxr-xr-x 12 ro…...
寒假2.5
题解 web:[网鼎杯 2020 朱雀组]phpweb 打开网址,一直在刷新,并有一段警告 翻译一下 查看源码 每隔五秒钟将会提交一次form1,index.php用post方式提交了两个参数func和p,func的值为date,p的值为Y-m-d h:i:s a 执行fu…...
定期删除一周前的数据,日志表的表空间会增长吗?
即使定期删除一周前的数据,日志表的表空间仍可能持续增长。原因如下: 删除操作不释放空间:DELETE 操作只会标记数据为删除状态,并不会立即释放空间。这些空间可以被后续的 INSERT 操作重用,但不会自动缩减表的总大小。…...
yum 安装mysql
sudo yum install mysql-server sudo systemctl start mysqld sudo systemctl enable mysqld 获取临时 root 密码并登录 MySQL 安装完成后,MySQL 会生成一个临时的 root 密码。你可以通过查看日志文件来找到这个密码: sudo grep ‘temporary password’…...
Servlet笔记(下)
HttpServletRequest对象相关API 获取请求行信息相关(方式,请求的url,协议及版本) | API | 功能解释 | | ----------------------------- | ------------------------------ | | StringBuffer getRequestURL(); | 获取客户端…...
Windows 中学习Docker环境准备3、在Ubuntu中安装Docker
Windows 中学习Docker环境准备1、Win11安装Docker Desktop Windows 中学习Docker环境准备2、Docker Desktop中安装ubuntu Windows 中学习Docker环境准备3、在Ubuntu中安装Docker 需要更多Docker学习视频和资料,请文末联系 步骤 1:更新系统并安装依赖…...
【centOS】搭建公司内网git环境-GitLab 社区版(GitLab CE)
1. 安装必要的依赖 以 CentOS 7 系统为例,安装必要的依赖包: sudo yum install -y curl policycoreutils openssh-server openssh-clients postfix sudo systemctl start postfix sudo systemctl enable postfix2. 添加 GitLab 仓库 curl -sS https:/…...
Unity DoTween使用文档
DoTween 使用文档 DoTween 是 Unity 中非常流行的动画补间插件。它通过链式调用方式,让开发者可以快速创建平滑、自然的动画效果。本文将介绍 DoTween 的基础用法、缓动曲线原理(包含常见缓动曲线的数学公式与参数说明)、案例演示以及一些常…...
【办公类-99-01】20250201学具PDF打印会缩小一圈——解决办法:换一个PDF阅读器
背景需求: 2024年1月13日,快要放寒假了,组长拿着我们班的打印好的一叠教案来调整。 “前面周计划下面的家园共育有调整,你自己看批注。” “还有你这个教案部分的模版有问题,太小(窄)了。考虑…...
组合总和II(力扣40)
这道题的难点就在于题目所给的集合中有重复的数字,我们需要进行去重操作。首先明确去重指的是去重哪一部分。注意并不是对递归的集合去重,而是对当前集合的遍历进行去重。这么说可能有点抽象,举个例子:假设集合为1,1,2,3,4&#x…...
基于HTML生成网页有什么优势
在互联网时代,网页是人们获取信息、交流互动的重要窗口,而基于HTML生成网页,是搭建网络大厦的关键。HTML语法简洁直观,标签和属性语义明确,新手也能迅速上手,创建包含基础元素的网页,极大降低了…...
php 接入扣子的 token获取
本身逻辑只是个api,但是官方不提供php的sdk 扎心了老铁,这下php 狗都不用了,主要麻烦的是如何获取access_token,代码如下 protected function get_jwt(): string{$header [alg > RS256,typ > JWT,kid > $this->kid];…...
Redis02 - 持久化
Redis持久化 文章目录 Redis持久化一:持久化简介1:Redis为什么要进行持久化2:Redis持久化的方式 二:RDB持久化介绍1:手动触发RDB2:自动触发RDB3:redis.conf中进行RDB的配置4:RDB优缺…...
【力扣】240.搜索二维矩阵 II
题目 我的代码 class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {for(int i0;i<matrix.size();i){for(int j0;j<matrix[0].size();j){if(targetmatrix[i][j]){return true;}else if(target<matrix[i][j]){brea…...
RabbitMQ 从入门到精通:从工作模式到集群部署实战(二)
接上篇:《RabbitMQ 从入门到精通:从工作模式到集群部署实战(一)》 链接 文章目录 4.安装RabbitMQ Messaging Topology Operator 裸金属环境部署RabbitMQ部署单实例部署集群 4.安装RabbitMQ Messaging Topology Operator 使用 cer…...
编程AI深度实战:大模型哪个好? Mistral vs Qwen vs Deepseek vs Llama
随着开源 LLM 的发展,越来越多的模型变得专业化,“代码”LLM 变得非常流行。这些 LLM 旨在比其 “常识” 对应物更小,但旨在超越更大的通用模型的编码性能。 这些模型以极低的成本提供大型模型的功能,进一步使本地 LLM 空间民主化…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...
ZYNQ学习记录FPGA(二)Verilog语言
一、Verilog简介 1.1 HDL(Hardware Description language) 在解释HDL之前,先来了解一下数字系统设计的流程:逻辑设计 -> 电路实现 -> 系统验证。 逻辑设计又称前端,在这个过程中就需要用到HDL,正文…...
