mybatis源码学习-3-解析器模块
写在前面,这里会有很多借鉴的内容,有以下三个原因
- 本博客只是作为本人学习记录并用以分享,并不是专业的技术型博客
- 笔者是位刚刚开始尝试阅读源码的人,对源码的阅读流程乃至整体架构并不熟悉,观看他人博客可以帮助我快速入门
- 如果只是笔者自己观看,难免会有很多弄不懂乃至理解错误的地方,观看他人的体会能有效改善这个问题
1. 目录结构
-
XNode类:
- 作用:
XNode
类表示XML文档中的一个节点(Element或Node),它用于封装XML节点的信息,例如标签名、属性和子节点等。 - 使用场景:MyBatis使用
XNode
来解析XML配置文件中的各种元素,如<select>
,<update>
,<insert>
,<delete>
等,并提供了一种方便的方式来访问这些元素的属性和子元素。
- 作用:
-
PropertyParser类:
- 作用:
PropertyParser
类是MyBatis用于解析属性表达式的工具类。属性表达式是在XML配置文件中引用JavaBean属性的方式,通常用于动态SQL。 - 使用场景:MyBatis在解析动态SQL语句或属性表达式时,会使用
PropertyParser
来解析${}
和#{}
中的属性表达式,并将其替换为实际的属性值或SQL参数。
- 作用:
-
GenericTokenParser类:
- 作用:
GenericTokenParser
类是MyBatis用于解析通用占位符(例如${}
和#{}
)的工具类。它允许你指定一个TokenHandler
接口的实现,用于处理占位符内的内容。 - 使用场景:MyBatis在解析SQL语句中的占位符时,会使用
GenericTokenParser
来查找和替换占位符内的内容,然后将处理后的SQL语句返回。
- 作用:
-
ParsingException类:
- 作用:
ParsingException
类是MyBatis中的自定义异常类,用于表示解析过程中的异常情况。它通常用于捕获和处理解析XML配置文件或SQL语句时可能发生的错误。 - 使用场景:当MyBatis在解析配置文件或SQL语句时遇到不合法的语法或结构时,会抛出
ParsingException
异常,以便开发者识别和处理问题。
- 作用:
-
TokenHandler接口:
- 作用:
TokenHandler
接口是一个回调接口,定义了如何处理占位符内的内容。它用于与GenericTokenParser
类一起工作,允许开发者自定义处理占位符内部内容的逻辑。 - 使用场景:当MyBatis使用
GenericTokenParser
解析占位符时,它会调用TokenHandler
接口的实现来处理占位符内的内容。开发者可以实现自定义的TokenHandler
来定义处理逻辑,例如从配置文件或参数中获取属性值。
- 作用:
-
XPathParser类:
- 作用:
XPathParser
类是MyBatis中的XML解析工具,用于解析XML配置文件和映射文件。它提供了一种方便的方式来处理XML文档,包括节点遍历、属性获取、XPath表达式解析等。 - 使用场景:
XPathParser
类通常用于加载和解析MyBatis的XML配置文件,例如mybatis-config.xml和映射文件。它允许MyBatis以一种结构化的方式访问和操作XML配置文件中的内容。
- 作用:
2. XPathParser类
- 参数
XPathParser
类通常用于加载和解析MyBatis的XML配置文件,例如mybatis-config.xml和映射文件。它允许MyBatis以一种结构化的方式访问和操作XML配置文件中的内容。
public class XPathParser {private final Document document;private boolean validation;private EntityResolver entityResolver;private Properties variables;private XPath xpath;//省略
}
-
document
属性,XML 被解析后,生成的org.w3c.dom.Document
对象。 -
validation
属性,是否校验 XML 。一般情况下,值为true
。 -
entityResolver
属性,org.xml.sax.EntityResolver
对象,XML 实体解析器。默认情况下,对 XML 进行校验时,会基于 XML 文档开始位置指定的 DTD 文件或 XSD 文件。例如说,解析mybatis-config.xml
配置文件时,会加载http://mybatis.org/dtd/mybatis-3-config.dtd
这个 DTD 文件。但是,如果每个应用启动都从网络加载该 DTD 文件,势必在弱网络下体验非常下,甚至说应用部署在无网络的环境下,还会导致下载不下来,那么就会出现 XML 校验失败的情况。所以,在实际场景下,MyBatis 自定义了 [EntityResolver](# 3. XMLMapperEntityResolver) 的实现,达到使用本地DTD 文件,从而避免下载网络DTD 文件的效果. -
xpath
属性,javax.xml.xpath.XPath
对象,用于查询 XML 中的节点和元素。如果对 XPath 的使用不了解的胖友,请先跳转 《Java XPath 解析器 - 解析 XML 文档》 中,进行简单学习,灰常简单。 -
variables
属性,变量 Properties 对象,用来替换需要动态配置的属性值。例如:<dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/> </dataSource>
-
variables
的来源,即可以在常用的 Java 配置文件中配置,也可以使用 MyBatis<property />
标签进行配置。例如:<properties resource="org/mybatis/example/config.properties"><property name="username" value="dev_user"/><property name="password" value="F2Fa3!33TYyg"/> </properties>
- 这里配置的
username
和password
属性,就可以替换上面的${username}
和${password}
这两个动态属性。 - 具体如何实现的,可以看下面的
PropertyParser#parse(String string, Properties variables)
方法。
- 这里配置的
-
- 构造方法
解释完属性后,我们可以看见后面有一长串的构造方法,挑选其中一个
/*** 构造 XPathParser 对象** @param xml XML 文件地址* @param validation 是否校验 XML* @param variables 变量 Properties 对象* @param entityResolver XML 实体解析器*/
public XPathParser(String xml, boolean validation, Properties variables, EntityResolver entityResolver) {//1. 公共构造方法commonConstructor(validation, variables, entityResolver);//2. 创建document对象,将xml文件解析成一个document对象this.document = createDocument(new InputSource(new StringReader(xml)));
}
private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {this.validation = validation;this.entityResolver = entityResolver;this.variables = variables;// 创建 XPathFactory 对象XPathFactory factory = XPathFactory.newInstance();this.xpath = factory.newXPath();
}
/*** 创建 Document 对象,这里就是简单的调用别人提供的java xml api,就像我们调用netty提供的api那样** @param inputSource XML 的 InputSource 对象* @return Document 对象*/
private Document createDocument(InputSource inputSource) {// important: this must only be called AFTER common constructortry {// 1. 创建 DocumentBuilderFactory 对象DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();// 设置是否验证 XMLfactory.setValidating(validation); factory.setNamespaceAware(false);factory.setIgnoringComments(true);factory.setIgnoringElementContentWhitespace(false);factory.setCoalescing(false);factory.setExpandEntityReferences(true);// 2. 创建 DocumentBuilder 对象DocumentBuilder builder = factory.newDocumentBuilder();// 设置实体解析器builder.setEntityResolver(entityResolver); // 实现都空的builder.setErrorHandler(new ErrorHandler() { @Overridepublic void error(SAXParseException exception) throws SAXException {throw exception;}@Overridepublic void fatalError(SAXParseException exception) throws SAXException {throw exception;}@Overridepublic void warning(SAXParseException exception) throws SAXException {}});// 3. 解析 XML 文件return builder.parse(inputSource);} catch (Exception e) {throw new BuilderException("Error creating document instance. Cause: " + e, e);}
}
至此,我们可以通过构造方法创建一个对象对xml文件进行解析
例如,在org.apache.ibatis.parsing.XPathParserTest#shouldTestXPathParserMethods
方法中,我们可以通过测试代码解析nodelet_test.xml
中的元素,通过构造方法后获得的XPathParser
对象已经对xml文件进行解析,如下
- eval元素
eval 元素的方法,用于获得 Boolean、Short、Integer、Long、Float、Double、String 类型的元素的值。我们以
#evalString(Object root, String expression)
方法为例子,代码如下:
public String evalString(Object root, String expression) {// 1. 获得指定元素或节点的值String result = (String) evaluate(expression, root, XPathConstants.STRING);// 2. 基于 variables 替换动态值,如果 result 为动态值,还记得variables是什么吗?Properties 对象,用来替换需要动态配置的属性值。result = PropertyParser.parse(result, variables);return result;
}
/*** 获得指定元素或节点的值,例如在上例中箭头所指表达式为"/employee/@id" , 节点为"[#document:null]" , 返回类型为String,那么返回的结果就是result = "${id_var}"** @param expression 表达式* @param root 指定节点* @param returnType 返回类型* @return 值*/
private Object evaluate(String expression, Object root, QName returnType) {try {return xpath.evaluate(expression, root, returnType);} catch (Exception e) {throw new BuilderException("Error evaluating XPath. Cause: " + e, e);}
}
在这里没有使用动态替换,因此即便result = “${id_var}”,在经过PropertyParser#parse(String string, Properties variables)
进行动态解析后,结果依然保持不变.
除了上面的vealString之类的方法,还有一个evalNode()方法,用户获得Node类型的节点的值,代码如下
//返回 Node 数组
public List<XNode> evalNodes(String expression) { return evalNodes(document, expression);
}public List<XNode> evalNodes(Object root, String expression) {// 1. 封装成 XNode 数组List<XNode> xnodes = new ArrayList<>();// 2. 获得 Node 数组NodeList nodes = (NodeList) evaluate(expression, root, XPathConstants.NODESET);for (int i = 0; i < nodes.getLength(); i++) {xnodes.add(new XNode(this, nodes.item(i), variables));}return xnodes;
}//返回 Node 对象
public XNode evalNode(String expression) { return evalNode(document, expression);
}public XNode evalNode(Object root, String expression) {//1. 获得 Node 对象Node node = (Node) evaluate(expression, root, XPathConstants.NODE);if (node == null) {return null;}//2. 封装成 XNode 对象return new XNode(this, node, variables);
}
1处,返回结果有 Node 对象和数组两种情况,根据方法参数 expression
需要获取的节点不同。
2处,会将结果Node封装为org.apache.ibatis.parsing.XNode
对象,主要为了动态值的替换,例如测试方法org.apache.ibatis.parsing.XPathParserTest#shouldTestXPathParserMethods
调用parser.evalNode("/employee/@id").toString().trim()
这条语句时,会产生下面的一个XNode对象,也就是获取xml文件中id节点的值了
3. XMLMapperEntityResolver
MyBatis 自定义 EntityResolver 实现类,用于加载本地的
mybatis-3-config.dtd
和mybatis-3-mapper.dtd
这两个 DTD 文件。简单介绍一下DTD文件的作用,菜🐤教程
- DTD文件用于验证和定义相应的XML文件的结构和规则,以确保XML文件的正确性和一致性。解析器会根据
publicId
和systemId
来决定使用哪个DTD文件进行验证。
mybatis-config.dtd
定义了MyBatis配置文件中允许的元素和属性,包括数据源配置、事务管理器配置、映射器配置等。mybatis-mapper.dtd
定义了映射文件中允许的元素和属性,包括SQL语句、参数映射、结果映射等。
public class XMLMapperEntityResolver implements EntityResolver {private static final String IBATIS_CONFIG_SYSTEM = "ibatis-3-config.dtd";private static final String IBATIS_MAPPER_SYSTEM = "ibatis-3-mapper.dtd";private static final String MYBATIS_CONFIG_SYSTEM = "mybatis-3-config.dtd";private static final String MYBATIS_MAPPER_SYSTEM = "mybatis-3-mapper.dtd";/*** 本地 mybatis-config.dtd 文件*/private static final String MYBATIS_CONFIG_DTD = "org/apache/ibatis/builder/xml/mybatis-3-config.dtd";/*** 本地 mybatis-mapper.dtd 文件*/private static final String MYBATIS_MAPPER_DTD = "org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd";/*** 将公共DTD转换为本地DTD** @param publicId publicId 是DTD声明中的 PUBLIC 标识符。它用于指定一个公共标准的标识符,通常用于引用在公共资源中定义的DTD。* @param systemId 是DTD声明中的 SYSTEM 标识符。它用于指定一个系统标准的标识符,通常用于引用本地文件系统或远程资源中的DTD。* @return The InputSource for the DTD** @throws org.xml.sax.SAXException If anything goes wrong*/@Overridepublic InputSource resolveEntity(String publicId, String systemId) throws SAXException {try {if (systemId != null) {String lowerCaseSystemId = systemId.toLowerCase(Locale.ENGLISH);// 本地 mybatis-config.dtd 文件if (lowerCaseSystemId.contains(MYBATIS_CONFIG_SYSTEM) || lowerCaseSystemId.contains(IBATIS_CONFIG_SYSTEM)) {return getInputSource(MYBATIS_CONFIG_DTD, publicId, systemId);// 本地 mybatis-mapper.dtd 文件} else if (lowerCaseSystemId.contains(MYBATIS_MAPPER_SYSTEM) || lowerCaseSystemId.contains(IBATIS_MAPPER_SYSTEM)) {return getInputSource(MYBATIS_MAPPER_DTD, publicId, systemId);}}return null;} catch (Exception e) {throw new SAXException(e.toString());}}private InputSource getInputSource(String path, String publicId, String systemId) {InputSource source = null;if (path != null) {try {// 创建 InputSource 对象InputStream in = Resources.getResourceAsStream(path);source = new InputSource(in);// 设置 publicId、systemId 属性source.setPublicId(publicId);source.setSystemId(systemId);} catch (IOException e) {// ignore, null is ok}}return source;}}
4. GenericTokenParser
在初识mybatis源码时,我会产生这样的疑惑,这里的
Token
指的是什么,与SpringSecurity
中的Token
的区别是什么?在GPT之后😂,给出如下解释
- 在 MyBatis 中,“token” 通常指的是通用标记解析器(GenericTokenParser)中的占位符标记,用于解析 SQL 语句或其他文本中的占位符,例如
${variable}
或#{parameter}
。这些占位符标记允许你在 SQL 语句中插入变量或参数值,以动态生成 SQL 查询语句。通用标记解析器会将这些标记替换为实际的值,从而生成最终的 SQL 语句。MyBatis 使用这种机制来支持参数化查询和动态 SQL。- 在 Spring Security 中,“token” 通常指的是认证令牌(Authentication Token)或访问令牌(Access Token)的概念。这些令牌用于身份验证和授权,用于验证用户的身份并控制用户对资源的访问。Spring Security 使用这种机制来保护应用程序的安全性,实现认证和授权功能。
public class GenericTokenParser {// 开放令牌,例如 "${"private final String openToken;// 关闭令牌,例如 "}"private final String closeToken;// 用于处理找到的令牌的处理器private final TokenHandler handler;// 构造函数,接收开放令牌,关闭令牌和令牌处理器作为参数public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {this.openToken = openToken;this.closeToken = closeToken;this.handler = handler;}// 解析文本的方法public String parse(String text) {// 如果文本为空,直接返回空字符串if (text == null || text.isEmpty()) {return "";}// 搜索开放令牌的位置int start = text.indexOf(openToken);// 如果没有找到开放令牌,直接返回原文本if (start == -1) {return text;}// 把文本转换为字符数组char[] src = text.toCharArray();int offset = 0;// 用于构建结果的字符串构建器final StringBuilder builder = new StringBuilder();// 用于构建找到的令牌的字符串构建器StringBuilder expression = null;// 当还能找到开放令牌时,执行循环while (start > -1) {// 如果开放令牌前面是反斜杠,那么这个开放令牌是转义的,需要忽略if (start > 0 && src[start - 1] == '\\') {// 添加转义的开放令牌builder.append(src, offset, start - offset - 1).append(openToken);offset = start + openToken.length();} else {// 找到开放令牌,开始搜索关闭令牌if (expression == null) {expression = new StringBuilder();} else {expression.setLength(0);}// 添加开放令牌前面的文本builder.append(src, offset, start - offset);offset = start + openToken.length();int end = text.indexOf(closeToken, offset);// 当还能找到关闭令牌时,执行循环while (end > -1) {// 如果关闭令牌前面是反斜杠,那么这个关闭令牌是转义的,需要忽略if (end > offset && src[end - 1] == '\\') {// 添加转义的关闭令牌expression.append(src, offset, end - offset - 1).append(closeToken);offset = end + closeToken.length();end = text.indexOf(closeToken, offset);} else {// 添加关闭令牌前面的令牌文本expression.append(src, offset, end - offset);offset = end + closeToken.length();break;}}if (end == -1) {// 如果没有找到关闭令牌,添加剩余的文本builder.append(src, start, src.length - start);offset = src.length;} else {// 添加处理后的令牌builder.append(handler.handleToken(expression.toString()));offset = end + closeToken.length();}}// 搜索下一个开放令牌start = text.indexOf(openToken, offset);}// 添加剩余的文本if (offset < src.length) {builder.append(src, offset, src.length - offset);}// 返回构建的字符串return builder.toString();}
}
测试案例org.apache.ibatis.parsing.GenericTokenParserTest
像上面两幅图那样,就可以把我们xml文件中诸如#{id}
通过反射去转换为具体的id内容了,再去看看带有转义字符的
5. PropertyParser
public class PropertyParser {private static final String KEY_PREFIX = "org.apache.ibatis.parsing.PropertyParser.";/*** 特殊属性键,指示是否在占位符上启用默认值。* <p>* 默认值为false (表示禁用占位符上的默认值)如果指定true ,则可以在占位符上指定键和默认值(例如${db.username:postgres} )。* </p>** @since 3.4.2*/public static final String KEY_ENABLE_DEFAULT_VALUE = KEY_PREFIX + "enable-default-value";/*** 特殊属性键,用于指定占位符上键和默认值的分隔符。* <p>* 默认分隔符是":" 。* </p>** @since 3.4.2*/public static final String KEY_DEFAULT_VALUE_SEPARATOR = KEY_PREFIX + "default-value-separator";private static final String ENABLE_DEFAULT_VALUE = "false";private static final String DEFAULT_VALUE_SEPARATOR = ":";private PropertyParser() {// Prevent Instantiation}//1.public static String parse(String string, Properties variables) {VariableTokenHandler handler = new VariableTokenHandler(variables);GenericTokenParser parser = new GenericTokenParser("${", "}", handler);return parser.parse(string);}//2.private static class VariableTokenHandler implements TokenHandler {private final Properties variables; // 存储变量的属性private final boolean enableDefaultValue; // 是否启用默认值private final String defaultValueSeparator; // 默认值分隔符private VariableTokenHandler(Properties variables) {this.variables = variables;// 解析属性值,获取是否启用默认值和默认值分隔符this.enableDefaultValue = Boolean.parseBoolean(getPropertyValue(KEY_ENABLE_DEFAULT_VALUE, ENABLE_DEFAULT_VALUE));this.defaultValueSeparator = getPropertyValue(KEY_DEFAULT_VALUE_SEPARATOR, DEFAULT_VALUE_SEPARATOR);}private String getPropertyValue(String key, String defaultValue) {// 获取属性值,如果属性为空则使用默认值return (variables == null) ? defaultValue : variables.getProperty(key, defaultValue);}@Overridepublic String handleToken(String content) {if (variables != null) {String key = content;if (enableDefaultValue) {final int separatorIndex = content.indexOf(defaultValueSeparator);String defaultValue = null;if (separatorIndex >= 0) {key = content.substring(0, separatorIndex);defaultValue = content.substring(separatorIndex + defaultValueSeparator.length());}if (defaultValue != null) {// 如果启用了默认值,并且默认值存在,则返回属性值或默认值return variables.getProperty(key, defaultValue);}}if (variables.containsKey(key)) {// 如果属性中包含该键,则返回属性值return variables.getProperty(key);}}// 如果属性为空或属性中不包含该键,则返回原始的标记内容return "${" + content + "}";}}}
先看看1处的代码,它主要是
-
创建一个VariableTokenHandler对象
-
创建一个[GenericTokenParser](# 4. GenericTokenParser)
-
调用
org.apache.ibatis.parsing.GenericTokenParser#parse
方法对对象进行动态替换,从而完成动态映射的功能
再来看看2处的代码,它是org.apache.ibatis.parsing.TokenHandler
的实现类,主要用于定义一些动态字符串的映射规则,例如将id->123456
.
测试代码org.apache.ibatis.parsing.PropertyParserTest
这个模块基本看完了,下一模块映射模块,今天就到这里了,记录一下
------------------------2023/9/4 未完待续------------------------
相关文章:

mybatis源码学习-3-解析器模块
写在前面,这里会有很多借鉴的内容,有以下三个原因 本博客只是作为本人学习记录并用以分享,并不是专业的技术型博客笔者是位刚刚开始尝试阅读源码的人,对源码的阅读流程乃至整体架构并不熟悉,观看他人博客可以帮助我快速入门如果只是笔者自己观看,难免会有很多弄不懂乃至理解错误…...

解决微信小程序recycle-view使用百分比单位控制宽高时出现的内容溢出问题
recycle-view是微信小程序官方推出的一个经过优化的长列表组件,但是在使用百分比单位控制高宽时有个内容溢出问题,虽然它提供了height和width的参数可以设置宽高,但每次写列表都需要去js里获取宽高并设置是较为麻烦的,所以现在来着…...

如何使用蚂蚁集团自动化混沌工程 ChaosMeta 做 OceanBase 攻防演练?
当前,业界主流的混沌工程项目基本只关注如何制造故障的问题,而经常做演练相关工作的工程师应该明白,每次演练时还会遇到以下痛点: 检测当前环境是否符合演练预设条件(演练准入); 业务流量是否满…...

在 Node.js 中使用 MongoDB 事务
MongoDB事务 事务介绍 在 MongoDB 中,对单个文档的操作是原子的。由于您可以使用嵌入的文档和数组来捕获单个文档结构中的数据之间的关系,而不是跨多个文档和集合进行规范化,因此这种单一文档的原子性消除了对多文档的需求许多实际用例的事务…...

IntelliJ IDEA的远程开发(Remote Development)
DEA的远程开发功能,可以将本地的编译、构建、调试、运行等工作都放在远程服务器上执行,而本地仅运行客户端软件进行常规的开发操作即可,官方给出的逻辑图如下,可见通过本地的IDE和服务器上的IDE backend将本地电脑和服务器打通&am…...

网络安全-信息收集简介
本文为作者学习文章,按作者习惯写成,如有错误或需要追加内容请留言(不喜勿喷) 本文为追加文章,后期慢慢追加 什么是信息收集 信息收集是指通过各种方式获取所需要的信息,以便我们在后续的渗透过程更好的…...

页面页脚部分CSS分享
先看效果: CSS部分:(查看更多) <style>body {display: grid;grid-template-rows: 1fr 10rem auto;grid-template-areas: "main" "." "footer";overflow-x: hidden;background: #F5F7FA;min…...

微信小程序slot插槽的介绍,以及如何通过uniapp使用动态插槽
微信小程序文档 - slots介绍 由上述文档看俩来,微信小程序官方并没有提及动态插槽内容。 uniapp文档 - slots介绍 uni官方也未提及关于动态插槽的内容 在实际使用中,直接通过 <<slot :name"item.xxx" /> 这种形式会报错ÿ…...

l8-d6 socket套接字及TCP的实现框架
一、socket套接字 /*创建套接字*/ int socket(int domain, int type, int protocol); /*绑定通信结构体*/ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); /*监听套接字*/ int listen(int sockfd, int backlog); /*处理客户端发起的连接࿰…...

ChatGPT AIGC 完成动态堆积面积图实例
先使用ChatGPT AIGC描述一下堆积面积图的功能与作用。 接下来一起看一下ChatGPT做出的动态可视化效果图: 这样的动态图案例代码使用ChatGPT AIGC完成。 将完整代码复制如下: <!DOCTYPE html> <html> <head><meta charset="utf-8"><tit…...

虹科产线实时数采检测方案——高速采集助力智能化升级
01 产线数采检测相关技术背景 1.1 典型场景 对于产线数采检测,让我们从典型的工厂场景开始介绍。 每个工位都有上位机监控下方的PLC控制器。指令、执行单元和作用对象的状态通过内置传感器进行采集和测量,反馈给PLC实现闭环控制。 工业4.0和智能制…...

用迅为RK3568开发板使用OpenCV处理图像颜色通道提取ROI
本小节代码在配套资料“iTOP-3568 开发板\03_【iTOP-RK3568 开发板】指南教程 \04_OpenCV 开发配套资料\07”目录下,如下图所示: 在计算机的色彩图像中存有三个通道,即 BGR 通道,根据三个颜色通道的亮度值来显示出不同的颜色&…...

低压配电室电力安全解决方案
低压电气安全监控运维系统是力安科技基于物联网核心技术自主开发的高可靠性安全监测系统。其工作原理是利用物联网、云计算、大数据、数字传感技术及RFID无线射频识别技术来获取低压配电回路电压、电流、温度、有功、无功、功率因数等全电量的采集及配电线路的漏电、温度的实时…...

【Windows 常用工具系列 11 -- 笔记本F5亮度调节关闭】
文章目录 笔记本 F 按键功能恢复 笔记本 F 按键功能恢复 使用笔记本在进行网页浏览时,本想使用F5刷新下网页,结果出现了亮度调节,如下图所示: 所以就在网上查询是否有解决这个问题的帖子,结果还真找到了:…...

Python小知识 - 【Python】如何使用Pytorch构建机器学习模型
【Python】如何使用Pytorch构建机器学习模型 机器学习是人工智能的一个分支,它的任务是在已有的数据集上学习,最终得到一个能够解决新问题的模型。Pytorch是一个开源的机器学习框架,它可以让我们用更少的代码构建模型,并且可以让模…...

使用Akka的Actor模拟Spark的Master和Worker工作机制
使用Akka的Actor模拟Spark的Master和Worker工作机制 Spark的Master和Worker协调工作原理 在 Apache Spark 中,Master 和 Worker 之间通过心跳机制进行通信和保持活动状态。下面是 Master 和 Worker 之间心跳机制的工作流程: Worker 启动后,…...

文心一言api接入如何在你的项目里使用文心一言
文心一言api接入在项目里接入文心一言 一、百度文心一言API二、使用步骤1、接口2、请求参数3、请求参数示例4、接口 返回示例 三、 如何获取appKey和uid1、申请appKey:2、获取appKey和uid 四、重要说明 一、百度文心一言API 基于百度文心一言语言大模型的智能文本对话AI机器人…...

Python匿名函数lambda(R与Python第五篇)
目录 一、为什么要引入“lambda函数”? 二、匿名函数的两种用法 参考: 本文来源:《Python全案例学习与实践》(2019年9月出版,电子工业出版社) Python允许使用一种无名的函数,称其为匿名函数…...

【2023校园招聘】 钉钉AI应用开发平台开始校招拉~
【岗位职责】 负责钉钉AI Paas 产品化研发落地,包含但不限于: 1. 用户意图理解、任务规划、服务推荐等算法的设计和开发 2. 基于大模型落地各种落地应用,缩短大模型与真实应用场景的距离 3. 负责算法的工程化落地,包括算法的代…...

Linux系统gdb调试常用命令
GDB(GNU调试器)是一款常用的调试工具,用于调试C、C等编程语言的程序。以下是一些常用的GDB命令: 1. 启动程序: - gdb <executable>:启动GDB调试器,并加载可执行文件。 2. 设置断点&a…...

Sumo中Traci.trafficlight详解(上)
Sumo中Traci.trafficlight详解(上) 记录慢慢学习traci的每一天,希望也能帮到你 文章目录 Sumo中Traci.trafficlight详解(上)Traci.trafficlight信号灯参数讲解1.getAllProgramLogics(self,tlsID)2.getBlockingVehicle…...

手写Mybatis:第13章-通过注解配置执行SQL语句
文章目录 一、目标:注解配置执行SQL二、设计:注解配置执行SQL三、实现:注解配置执行SQL3.1 工程结构3.2 注解配置执行SQL类图3.3 脚本语言驱动器3.3.1 脚本语言驱动器接口3.3.2 XML语言驱动器 3.4 注解配置构建器3.4.1 定义增删改查注解3.4.2…...

spring security - 快速整合 springboot
1.引入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spr…...

NPM 常用命令(二)
目录 1、npm bugs 1.1 配置 browser registry 2、npm cache 2.1 概要 2.2 详情 2.3 关于缓存设计的说明 2.4 配置 cache 3、 npm ci 3.1 描述 3.2 配置 install-strategy legacy-bundling global-style omit strict-peer-deps foreground-scripts ignore-s…...

ctfhub ssrf(3关)
文章目录 内网访问伪协议读取文件扫描端口 内网访问 根据该题目,是让我们访问127.0.0.1/falg.php,访问给出的链接后用bp抓包,修改URL,发送后得到flag: 伪协议读取文件 这题的让我们用伪协议,而网站的目录…...

跨源资源共享(CORS)Access-Control-Allow-Origin
1、浏览器的同源安全策略 没错,就是这家伙干的,浏览器只允许请求当前域的资源,而对其他域的资源表示不信任。那怎么才算跨域呢? 请求协议http,https的不同域domain的不同端口port的不同 好好好,大概就是这么回事啦&…...

【嵌入式软件开发 】学习笔记
本文主要记录 【嵌入式软件开发】 学习笔记,参考相关大佬的文章 1.RTOS 内功修炼笔记 RTOS内功修炼记(一)—— 任务到底应该怎么写? RTOS内功修炼记(二)—— 优先级抢占式调度到底是怎么回事?…...

CentOS 7上安装Python 3.11.5,支持Django
CentOS 7上安装Python 3.11.5,支持Django 今天安装django,报了“Django - deterministicTrue requires SQLite 3.8.3 or higher upon running python manage.py runserver”。查了一番资料,记录下来。 参考链接: 参考链接: Django的web项目…...

COMPFEST 15H「组合数学+容斥」
Problem - H - Codeforces 题意: 定义一个集合S为T的孩子是,对于S中的每一个元素x,在T中都能找到x1。 给定n,k,每一个集合中的元素x必须满足 1 < x < k 1<x<k 1<x<k且 c n t [ x ] < 1 cnt[x…...

react快速开始(三)-create-react-app脚手架项目启动;使用VScode调试react
文章目录 react快速开始(三)-create-react-app脚手架项目启动;使用VScode调试react一、create-react-app脚手架项目启动1. react-scripts2. 关于better-npm-runbetter-npm-run安装 二、使用VScode调试react1. 浏览器插件React Developer Tools2. 【重点】用 VSCode …...