Java Web|day5.MyBatis

MyBatis

定义

它是一款半自动的ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低

**ORM: **Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型,对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系,比如用一个Java的Student类,去对应数据库中的一张student表,类中的属性和表中的列一一对应。Student类就对应student表,一个Student对象就对应student表中的一行数据

半自动: 用mybatis进行开发,需要手动编写SQL语句。而全自动的ORM框架,如hibernate,则不需要编写SQL语句。

优点

  1. 灵活性高,自由地对sql进行定制

  2. 但相比JDBC,它提供了输入映射和输出映射,可以很方便地进行SQL参数设置,以及结果集封装。

  3. 还提供了关联查询和动态SQL等功能,极大地提升了开发的效率。

缺点

当要切换数据库时,SQL语句可能就要重写,因为不同的数据库有不同的方言(Dialect),所以mybatis的数据库无关性低。

占位符

#{}

  • #{}在mybatis中,最后会被解析为?,其实就是Jdbc的PreparedStatement中的?占位符,它有预编译的过程
  • 预编译
    • 它有预编译的过程,会对输入参数进行类型解析(如果入参是String类型,设置参数时会自动加上引号),可以防止SQL注入
  • 注意
    • 如果parameterType属性指定的入参类型是简单类型的话(简单类型指的是8种java原始类型再加一个String),#{}中的变量名可以任意
    • 如果入参类型是pojo,比如是Student类,那么#{name}表示取入参对象Student中的name属性,#{age}表示取age属性

${}

  • ${},一般会用在模糊查询的情景,比如SELECT * FROM student WHERE name like '%${name}%';
  • 处理阶段在#{}之前,它不会做参数类型解析,而仅仅是做了字符串的拼接,
  • 入参的Student对象的name属性为zhangsan,则上面那条SQL最终被解析为SELECT * FROM student WHERE name like ‘%zhangsan%’;
  • 模糊查询只能用${}
  • 对于简单类型(8种java原始类型再加一个String)的入参,${}中参数的名字必须是value

使用过程

原生流程

  1. 编写mapper.xml,书写SQL,并定义好SQL的输入参数,和输出参数
  2. 编写全局配置文件,配置数据源,以及要加载的mapper.xml文件
  3. 通过全局配置文件,创建SqlSessionFactory
  4. 每次进行CRUD时,通过SqlSessionFactory创建一个SqlSession
  5. 调用SqlSession上的selectOne,selectList,insert,delete,update等方法,传入mapper.xml中SQL标签的id,以及输入参数
  6. 提交sqlSession.commit()
  7. 关闭资源sqlSession.close()

基于Mapper代理

为了简化开发,mybatis提供了mapper接口代理的开发方式,不需要再编写dao类,只需要编写一个mapper接口,一个mapper的接口和一个mapper.xml相对应,只需要调用SqlSession对象上的getMapper(),传入mapper接口的class信息,即可获得一个mapper代理对象,直接调用mapper接口中的方法,即相当于调用mapper.xml中的各个SQL标签,此时就不需要指定SQL标签的id字符串了,mapper接口中的一个方法,就对应了mapper.xml中的一个SQL标签

注意
  • mapper接口的全限定名,要和mapper.xml的namespace属性一致
  • mapper接口中的方法名要和mapper.xml中的SQL标签的id一致
  • mapper接口中的方法入参类型,要和mapper.xml中SQL语句的入参类型一致
  • mapper接口中的方法出参类型,要和mapper.xml中SQL语句的返回值类型一致
使用方法
  1. 全局配置文件
<!-- 普通加载xml --> 
<mappers>    <mapper resource="StudentMapper.xml"/> 
</mappers>
  1. mapper.java
    在这里插入图片描述

  2. mapper.xml
    在这里插入图片描述

  3. 测试调用

请添加图片描述

基于注解的开发

还是得有一个全局配置的xml文件,不过mapper.xml就可以省掉了

注意

当使用注解开发时,若需要传入多个参数,可以结合@Param注解

  • @Param标签会被mybatis处理并封装成一个Map对象,比如上面的示例中,实际传入的参数是一个Map对象,@Param标签帮忙向Map中设置了值,即它做了

  • Map<String,Object> map = new HashMap<>(); map.put("name", name); 
    map.put("major",major);
    

步骤

  1. 创建一个Mapper接口
<!-- 在mapper接口中使用注解 --> 
<mappers>    <mapper class="com.yogurt.mapper.PureStudentMapper"/> 
</mappers>
  1. 在全局配置文件中修改标签,直接指定加载这个类

三种加载Mapper的方式

  1. <!-- 普通加载xml -->
    <mappers><mapper resource="StudentMapper.xml"/>
    </mappers>
    
  2. <!-- 在mapper接口中使用注解 -->
    <mappers><mapper class="com.yogurt.mapper.PureStudentMapper"/>
    </mappers>
    
  3. <!-- 使用<package>标签 -->
    <mappers><package name="com.yogurt.mapper"/>
    </mappers>
    
  1. 自动加载com.yogurt.mapper包下的所有mapper
  2. 这种方式需要将mapper接口文件和mapper.xml文件都放在com.yogurt.mapper包下,且接口文件和xml文件的文件名要一致。
  3. 若mapper接口采用注解方式,则不需要xml;若mapper接口没有采用注解方式,则mapper接口和xml文件的名称要相同,且在同一目录

注意

是因为,对于src/main/java 源码目录下的文件,maven打包时只会将该目录下的java文件打包,而其他类型的文件都不会被打包进去,去工程目录的target目录下看看maven构建后生成的文件

解决

需要在pom.xml中的 标签下 添加 标签,指定打包时要将xml文件打包进去

<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource></resources>
</build>

运行流程

流程

  1. 利用Xpath语法解析全局配置文件
  2. 解析全局配置,
    • 是否开启二级缓存
    • 是否开启延迟加载
    • 是否使用插件(plugin)
    • 是否设置类型别名(typeAlias)
    • 数据库连接信息
  3. 解析mapper映射文件,将每个CRUD标签,封装为一个MappedStatement
  4. 所有的信息封装到Configuration对象(这是一个重量级对象)
  5. 将Configuration封装到SqlSessionFactory中
  6. 每次调用SqlSessionFactory开启一个SqlSession
  7. 每个SqlSession,会持有一个私有的Executor对象,以及共享的Configuration对象
  8. 每次操作,选取一个MappedStatement,由Executor执行。包括SQL语句组装,参数解析,返回结果解析等操作

图示

请添加图片描述

关键类

  1. Configuration

    封装了所有的属性

  2. MappedStatement

    一个CRUD标签,对应一个MappedStatement

  3. Executor体系

    mybatis核心执行器,通过Executor来执行数据库操作

  4. SqlSource体系

    封装CRUD标签的一个SqlSource,用于组装SQL语句

  5. SqlNode体系

    以树状形式,存储动态SQL标签,一个SqlSource拥有一个rootSqlNode,每个SqlNode有一个apply方法,在Executor执行时用于拼接SQL语句,SqlNode的设计用到的是设计模式中的组合模式。

  6. StatementHandler

    生成Statement,设置参数,执行查询

  7. ParameterHandler

    设置参数时,进行参数解析,类型转换等

  8. ResultSetHandler

    获取结果集,并进行结果封装

MyBatis缓存

定义

mybatis缓存,将数据库的查询结果,保存到内存(或者硬盘),以便下次执行相同查询时,不经过数据库,直接从内存中取出结果

作用

对于重复的查询,它能够提高响应速度,并减轻数据库的访问压力。适用于对响应时间要求高,而数据实时性要求不高的情况下。

分类

一级缓存

作用范围

  • SqlSession(默认)

持有者

  • BaseExecutor

默认开启

  • 其实是无法关闭的,但可以通过一些方法来使一级缓存失效

清除缓存

  • 在同一个SqlSession里执行 增 删 改 操作时(不必提交),会清除一级缓存
  • SqlSession提交或关闭时(关闭时会自动提交),会清除一级缓存
  • 对mapper.xml中的某个CRUD标签设置属性flushCache=true (这样会导致该标签的一级缓存和二级缓存都失效)
  • 在全局配置文件中设置 ,这样会使一级缓存失效,二级缓存不受影响
二级缓存

作用范围

  • mapper级别(可以跨SqlSession),一个mapper.xml即对应一个二级缓存,每个二级缓存,以mapper文件的namespace作为唯一标识

持有者

  • MappedStatement

默认关闭

  • (其实全局配置文件中的cacheEnabled默认是true,这个是二级缓存总开关,默认是已经打开了的,然而必须要在mapper.xml中配置 标签,才能开启该mapper.xml的二级缓存)

开启效果

  • 映射语句文件中的所有SELECT 语句将会被缓存。
  • 映射语句文件中的所有时INSERT 、UPDATE 、DELETE 语句会刷新缓存。
  • 缓存会使用Least Rece ntly U sed ( LRU ,最近最少使用的)算法来收回。
  • 根据时间表(如no Flush Int erv al ,没有刷新间隔),缓存不会以任何时间顺序来刷新。
  • 缓存会存储集合或对象(无论查询方法返回什么类型的值)的1024 个引用。
  • 缓存会被视为read/write(可读/可写)的,意味着对象检索不是共享的,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

注意

  • 对于SELECT节点对应的MappedStatement,默认是开启二级缓存,对其他节点(INSERT/DELETE/UPDATE),默认是关闭(这是由MappedStatement里的useCache属性控制的)
  • 放入二级缓存的数据,默认要实现Serializable接口,因为二级缓存的存储介质除了内存,还可能存在硬盘,所以存储的对象需要可序列化。
    • readOnly=false:通过序列化,返回缓存对象的一份拷贝,速度上会慢一些,但是更加安全。用户取得数据后,执行修改,并不会影响到二级缓存中的对象
    • 这些对象可以随意修改,不会影响后续相同查询条件的结果。这会慢一些,但是安全,因此默认是false。
  • 当然,若把二级缓存的readOnly属性设为true,则对象数据可以不用实现Serializable接口
    • readOnly=true:返回缓存对象的引用。
    • 因此返回的这些缓存对象自己没事不要去修改。一旦修改,就会影响下一个相同查询条件的查询结果。这提供了很重要的性能优势。
    • readOnly=true意在告诉用户,从缓存中取出数据后,不要对数据进行修改,而不是保证缓存的只读性(cache中存的是对象引用,取出数据后若执行修改,则会改变真正的对象,另外的用户再从cache中取对象,则会发现对象已经被修改)
  • 执行一次查询后,需要进行提交,该次查询结果才会保存到二级缓存中

存在问题

  • 由于是每个namespace对应一个二级缓存(一个namespace就是一个mapper.xml)
  • 若mapperA.xml中全是对user表的操作,而在另一个mapperB.xml中也有少许对user表的操作,这2个mapper的二级缓存是互相独立的,然而mapperB若对user表执行了增删改,并提交,却不会刷新到mapperA的二级缓存,此时用mapperA去做查询,则可能取到脏数据。

应用场景

主键返回

在插入一条记录时,我们不设置其主键id,而让数据库自动生成该条记录的主键id,那么在插入一条记录后,如何得到数据库自动生成的这条记录的主键id呢

两种方式

  1. 使用useGeneratedKeys和keyProperty属性
<insert id="insert" parameterType="com.yogurt.po.Student" useGeneratedKeys="true" keyProperty="id">INSERT INTO student (name,score,age,gender) VALUES (#{name},#{score},#{age},#{gender});
</insert>
  1. 使用子标签
<insert id="insert" parameterType="com.yogurt.po.Student">INSERT INTO student (name,score,age,gender) VALUES (#{name},#{score},#{age},#{gender});<selectKey keyProperty="id" order="AFTER" resultType="int" >SELECT LAST_INSERT_ID();</selectKey>
</insert>

标签其实就是一条SQL,这条SQL的执行,可以放在主SQL执行之前或之后,并且会将其执行得到的结果封装到入参的Java对象的指定属性上。

注意子标签只能用在和标签中。上面的LAST_INSERT_ID()实际上是MySQL提供的一个函数,可以用来获取最近插入或更新的记录的主键id。

批量查询

主要是动态SQL标签的使用,注意如果parameterType是List的话,则在标签体内引用这个List,只能用变量名list,如果parameterType是数组,则只能用变量名array

mapper定义

<select id="batchFind" resultType="student" parameterType="java.util.List">SELECT * FROM student<where><if test="list != null and list.size() > 0">AND id in<foreach collection="list" item="id" open="(" separator="," close=")">#{id}</foreach></if></where>
</select>

传参

List<Student> students = mapper.batchFind(Arrays.asList(1, 2, 3, 7, 9));

动态sql

可以根据具体的参数条件,来对SQL语句进行动态拼接。

注意

由于不确定查询参数是否存在,许多人会使用类似于where 1 = 1 来作为前缀,然后后面用AND 拼接要查询的参数,这样,就算要查询的参数为空,也能够正确执行查询,如果不加1 = 1,则如果查询参数为空,SQL语句就会变成SELECT * FROM student where ,SQL不合法。

  1. if
<select id="find" resultType="student" parameterType="student">SELECT * FROM student WHERE age >= 18<if test="name != null and name != ''">AND name like '%${name}%'</if>
</select>
  1. choose
<select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG WHERE state = ‘ACTIVE’<choose><when test="title != null">AND title like #{title}</when><when test="author != null and author.name != null">AND author_name like #{author.name}</when><otherwise>AND featured = 1</otherwise></choose>
</select> 
  1. where

    标签只会在至少有一个子元素返回了SQL语句时,才会向SQL语句中添加WHERE,并且如果WHERE之后是以AND或OR开头,会自动将其删掉

<select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG<where><if test="state != null">state = #{state}</if><if test="title != null">AND title like #{title}</if><if test="author != null and author.name != null">AND author_name like #{author.name}</if></where>
</select>
  1. trim

    标签可以用标签代替

<trim prefix="WHERE" prefixOverrides="AND | OR">...
</trim>
  1. foreach

    用来做迭代拼接的,通常会与SQL语句中的IN查询条件结合使用,注意,到parameterType为List(链表)或者Array(数组),后面在引用时,参数名必须为list或者array。如在foreach标签中,collection属性则为需要迭代的集合,由于入参是个List,所以参数名必须为list

<select id="batchFind" resultType="student" parameterType="list">SELECT * FROM student WHERE id in<foreach collection="list" item="item" open="(" separator="," close=")">#{item}</foreach>
</select>
  1. sql

    可将重复的SQL片段提取出来,然后在需要的地方,使用标签进行引用

<select id="findUser" parameterType="user" resultType="user">SELECT * FROM user<include refid="whereClause"/>
</select><sql id="whereClause"><where><if test="user != null">AND username like '%${user.name}%'</if></where>
</sql>
  1. bind

    mybatis的动态SQL都是用OGNL表达式进行解析的,如果需要创建OGNL表达式以外的变量,可以用bind标签

<select id="selectBlogsLike" resultType="Blog"><bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />SELECT * FROM BLOGWHERE title LIKE #{pattern}
</select>

关联查询

使用 标签以及和 子标签,进行关联查询,

延迟加载

定义

在关联查询时,利用延迟加载,先加载主信息。需要关联信息时再去按需加载关联信息

优点

这样会大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。

用法

在mybatis中,resultMap标签 的association标签和collection标签具有延迟加载的功能。

原理

开启前

  • 第一种方法:我们直接关联查询出所有订单和用户的信息
  • select * from orders o ,user u where o.user_id = u.id;

开启后

  • 第二种方法:分步查询,首先查询出所有的订单信息,然后如果需要用户的信息,我们在根据查询的订单信息去关联用户信息
  • select * from orders;
  • select * from user where id=user_id

逆向工程

mybatis官方提供了mapper自动生成工具mybatis-generator-core来针对单表,生成PO类,以及Mapper接口和mapper.xml映射文件。针对单表,可以不需要再手动编写xml配置文件和mapper接口文件了,非常方便。美中不足的是它不支持生成关联查询。一般做关联查询,就自己单独写SQL就好了。

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

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

相关文章

培训学校课程管理系统-计算机毕设Java|springboot实战项目

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

Java面试--框架--Spring MVC

Spring MVC 目录 Spring MVC1.spring mvc简介2.spring mvc实现原理2.1核心组件2.2工作流程 3.RESTful 风格4.Cookie&#xff0c;Session4.1 会话4.2 保存会话的两种技术 5.拦截器5.1过滤器、监听器、拦截器的对比5.2 过滤器的实现5.3 拦截器基本概念5.4 拦截器的实现 1.spring …

如何使用unittest和pytest进行python脚本的单元测试

1. 关于unittest和pytest unittest是python内置的支持单元测试的模块&#xff0c;他提供了核心类&#xff0c;TestCase&#xff0c;让单元测试 代码的编写不再是从0开始&#xff0c;不再是作坊式&#xff0c;而是标准化&#xff0c;模板化&#xff0c;工厂化。 pytest是第三方…

【深度解析】WRF-LES与PALM微尺度气象大涡模拟

查看原文>>>【深度解析】WRF-LES与PALM微尺度气象大涡模拟 针对微尺度气象的复杂性&#xff0c;大涡模拟&#xff08;LES&#xff09;提供了一种无可比拟的解决方案。微尺度气象学涉及对小范围内的大气过程进行精确模拟&#xff0c;这些过程往往与天气模式、地形影响和…

Linux - 模拟实现 shell 命令行解释器

目录 简介 shell 的重要性 解释为什么学习 shell 的工作原理很重要 模拟实现一个简单的 shell 循环过程 1. 获取命令行 2. 解析命令行 3. 建立一个子进程&#xff08;fork&#xff09; 4. 替换子进程&#xff08;execvp&#xff09; 5. 父进程等待子进程退出&#xff08;wai…

合宙LuatOS AIR700 IPV6 TCP 客户端向NodeRed发送数据

为了验证 AIR700 IPV6 &#xff0c;特别新建向NodeRed Tcp发送的工程。 Air700发送TCP数据源码如下&#xff1a; --[[ IPv6客户端演示, 仅EC618系列支持, 例如Air780E/Air600E/Air780UG/Air700E ]]-- LuaTools需要PROJECT和VERSION这两个信息 PROJECT "IPV6_SendDate_N…

Jupyter安装指南:最简便最详细的步骤

一.介绍 JupyterNotebook 是一个款以网页为基础的交互计算环境&#xff0c;可以创建Jupyter的文档&#xff0c;支持多种语言&#xff0c;包括Python, Julia, R等等。一般来说&#xff0c;如果是使用R语言的话&#xff0c;使用Rstudio居多&#xff0c;使用Python的话&#xff0…

开源的数据库增量订阅和消费的中间件——Cancl

目录 工作原理 MySQL主备复制原理 Canal 工作原理 主要功能和特点 应用场景 实验准备 安装JDK11 下载MySQL8.0 配置canal.admin 配置canal-deployer 测试数据读取 新增一台主机用做被同步的目标机器测试 官方地址&#xff1a;https://github.com/alibaba/canal?ta…

【gitlab】gitlab-ce:17.3.0-ce.0 1:使用docker engine安装

ce版本必须配置代理。 极狐版本可以直接pull 社区版GitLab不支持Alibaba Cloud Linux 3,本操作以Ubuntu/Debian系统为例进行说明,其他操作系统安装说明,请参见安装社区版GitLab。 docker 环境重启 sudo systemctl daemon-reload sudo systemctl restart docker脚本安装 安裝…

宝塔面板实现定时任务删除 logs文件 加条件删除 只删除一个月前的日志

我们在开发中难免用到了日志功能&#xff0c;随着日志越来越多导致占用我们的内存 下面是一个简单的 使用宝塔面板里面的定时任务来实现删除日志案例 第一步 首先我的日志文件目录 都在log文件夹里面&#xff0c; 每个月生成一个日志文件夹 文件夹命名是年月来命名的 第二…

探索深度学习的力量:从人工智能到计算机视觉的未来科技革命

目录 1. 引言 2. 人工智能的历史背景 3. 深度学习的崛起 3.1 深度神经网络的基本原理 4. 计算机视觉的发展现状 4.1 传统计算机视觉与深度学习的结合 5. 深度学习在计算机视觉中的应用 5.1 图像分类 5.2 目标检测 6. 深度学习引领的未来科技创新与变革 7. 结论 引言…

【vue3+Typescript】手撸了一个轻量uniapp导航条

最近公共组件写到导航条&#xff0c;本来打算拿已有的改。看了下uniapp市场上已有的组件&#xff0c;一是不支持vue3typescript&#xff0c;二是包装过重。索性自己手撸了一个导航条&#xff0c;不到100行代码全部搞定&#xff0c;因为自己的需求很简单&#xff1a; 1&#xf…

pycharm2023.1破解

下载解压文件&#xff0c;文件夹 /jetbra 复制电脑某个位置 注意&#xff1a; 补丁所属文件夹需单独存放&#xff0c;且放置的路径不要有中文与空格&#xff0c;以免 Pycharm 读取补丁错误。 点击进入 /jetbra 补丁目录&#xff0c;再点击进入 /scripts 文件夹&#xff0c;双…

javaer快速入门 goweb框架 gin

gin 入门 前置条件 安装环境 配置代理 # 配置 GOPROXY 环境变量&#xff0c;以下三选一# 1. 七牛 CDN go env -w GOPROXYhttps://goproxy.cn,direct# 2. 阿里云 go env -w GOPROXYhttps://mirrors.aliyun.com/goproxy/,direct# 3. 官方 go env -w GOPROXYhttps://goproxy.…

鸿蒙内核源码分析——(自旋锁篇)

本篇说清楚自旋锁 读本篇之前建议先读系列篇 进程/线程篇. 内核中哪些地方会用到自旋锁?看图: 概述 自旋锁顾名思义&#xff0c;是一把自动旋转的锁&#xff0c;这很像厕所里的锁&#xff0c;进入前标记是绿色可用的&#xff0c;进入格子间后&#xff0c;手一带&#xff0c…

10分钟学会LVM逻辑卷

华子目录 前言认识LVMLVM基本概念LVM整体流程LVM管理命令pvs&#xff0c;vgs&#xff0c;lvs命令pvs基本用法选项示例 vgs基本用法选项示例 lvs基本用法 pvcreate&#xff0c;vgcreate&#xff0c;lvcreate命令pvcreate示例 vgcreate基本用法示例选项 lvcreate基本用法示例 pvr…

Python爬虫入门教程(非常详细)适合零基础小白

一、什么是爬虫&#xff1f; 1.简单介绍爬虫 爬虫的全称为网络爬虫&#xff0c;简称爬虫&#xff0c;别名有网络机器人&#xff0c;网络蜘蛛等等。 网络爬虫是一种自动获取网页内容的程序&#xff0c;为搜索引擎提供了重要的数据支撑。搜索引擎通过网络爬虫技术&#xff0c;将…

【电路笔记】-无源衰减器总结

无源衰减器总结 文章目录 无源衰减器总结1、概述2、L-型无源衰减器设计3、T-型无源衰减器设计4、桥接 T 型衰减器设计5、π型无源衰减器设计无源衰减器是一个纯电阻网络,可用于控制输出信号的电平。 1、概述 无源衰减器是一种纯电阻网络,用于削弱或“衰减”传输线的信号电平…

Element UI中报dateObject.getTime is not a function解决方法~

1、错误信息。 2、该报错原因是Element UI中日期组件的校验规则是type: "date",而一般我们从后台拿到的数据是字符串型的&#xff0c;不满足预期&#xff0c;就会报错。 3、解决方法。 去掉日子组件中的type: "date"校验规则即可。 rules: {newName: [{…

EasyCVR视频汇聚平台:深度解析GB/T 28181协议下的视频资源整合与应用

随着安防技术的快速发展和智慧城市建设的推进&#xff0c;视频监控系统作为公共安全、城市管理、企业运营等领域的重要基础设施&#xff0c;其重要性和应用范围不断扩大。在这一过程中&#xff0c;GB/T 28181作为国家标准中关于视频监控设备通信协议的规范&#xff0c;正逐渐受…