Mybatis TypeHandler 介绍及使用
Mybatis TypeHandler类型转换器是负责Java类和jdbc类型之间的转换
主要涉及到下面这几个类:
TypeHandler类型转换器的顶层接口BaseTypeHandler抽象类继承自TypeHandler,Mybatis中所有的类型转换器实现均继承他。TypeHandlerRegistry类型转换器注册器,负责存储类型转换器。TypeAliasRegistry类型别名转换器,用来存储类型与别名的对应关系。
1 TypeHandler
TypeHandler是类型转换器的顶层接口,其定义了类型转换器应该具有的功能,
TypeHandler主要解决了两个问题:
- 可以指定我们在Java实体类所包含的自定义类型存入数据库后的类型是什么
- 从数据库中取出该数据后自动转换为我们自定义的Java类型
其源码如下:
public interface TypeHandler<T> { /** * 用于定义在Mybatis设置参数时该如何把Java类型的参数转换为对应的数据库类型 * @param ps 当前的PreparedStatement对象 * @param i 当前参数的位置 * @param parameter 当前参数的Java对象 * @param jdbcType 当前参数的数据库类型 * @throws SQLException */ void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; /** * 用于在Mybatis获取数据结果集时如何把数据库类型转换为对应的Java类型 * @param rs 当前的结果集 * @param columnName 当前的字段名称 * @return 转换后的Java对象 * @throws SQLException */ T getResult(ResultSet rs, String columnName) throws SQLException; /** * 用于在Mybatis通过字段位置获取字段数据时把数据库类型转换为对应的Java类型 * @param rs 当前的结果集 * @param columnIndex 当前字段的位置 * @return 转换后的Java对象 * @throws SQLException */ T getResult(ResultSet rs, int columnIndex) throws SQLException; /** * 用于Mybatis在调用存储过程后把数据库类型的数据转换为对应的Java类型 * @param cs 当前的CallableStatement执行后的CallableStatement * @param columnIndex 当前输出参数的位置 * @return * @throws SQLException */ T getResult(CallableStatement cs, int columnIndex) throws SQLException; }
2 BaseTypeHandler
BaseTypeHandler是一个抽象类,改类实现了TypeHandler中的方法并实现了异常捕获。继承改类我们可以很容易的实现一个自定义类型转换器,其源码如下:
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> { protected Configuration configuration; public void setConfiguration(Configuration c) { this.configuration = c; } public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { if (parameter == null) { if (jdbcType == null) { throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters."); } try { ps.setNull(i, jdbcType.TYPE_CODE); } catch (SQLException e) { throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " + "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " + "Cause: " + e, e); } } else { setNonNullParameter(ps, i, parameter, jdbcType); } } public T getResult(ResultSet rs, String columnName) throws SQLException { T result = getNullableResult(rs, columnName); if (rs.wasNull()) { return null; } else { return result; } } public T getResult(ResultSet rs, int columnIndex) throws SQLException { T result = getNullableResult(rs, columnIndex); if (rs.wasNull()) { return null; } else { return result; } } public T getResult(CallableStatement cs, int columnIndex) throws SQLException { T result = getNullableResult(cs, columnIndex); if (cs.wasNull()) { return null; } else { return result; } } public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException; public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException; public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException; }
我们可以看到BaseTypeHandler对TypeHandler接口的四个方法做了一个简单的选择,把null值的情况都做了一个过滤,核心的取值和设值的方法还是抽象出来了供子类来实现。使用BaseTypeHandler还有一个好处是它继承了另外一个叫做TypeReference的抽象类,通过TypeReference的getRawType()方法可以获取到当前TypeHandler所使用泛型的原始类型。这对Mybatis在注册TypeHandler的时候是非常有好处的。在没有指定javaType的情况下,Mybatis在注册TypeHandler时可以通过它来获取当前TypeHandler所使用泛型的原始类型作为要注册的TypeHandler的javaType类型,这个在讲到Mybatis注册TypeHandler的方式时将讲到。
3 注册TypeHandler
为什么Java自带的类型在存取的时候不会出错,我们自定义的类型就会出错?那是因为mybatis已经将这些类型的TypeHandler提前写好了,并且注册好了
具体注册了哪些,我们可以看TypeHandlerRegistry这个类:
public TypeHandlerRegistry(Configuration configuration) {this.unknownTypeHandler = new UnknownTypeHandler(configuration);register(Boolean.class, new BooleanTypeHandler());register(boolean.class, new BooleanTypeHandler());register(JdbcType.BOOLEAN, new BooleanTypeHandler());register(JdbcType.BIT, new BooleanTypeHandler());register(Byte.class, new ByteTypeHandler());register(byte.class, new ByteTypeHandler());register(JdbcType.TINYINT, new ByteTypeHandler());register(Short.class, new ShortTypeHandler());register(short.class, new ShortTypeHandler());register(JdbcType.SMALLINT, new ShortTypeHandler());register(Integer.class, new IntegerTypeHandler());register(int.class, new IntegerTypeHandler());register(JdbcType.INTEGER, new IntegerTypeHandler());register(Long.class, new LongTypeHandler());register(long.class, new LongTypeHandler());register(Float.class, new FloatTypeHandler());register(float.class, new FloatTypeHandler());register(JdbcType.FLOAT, new FloatTypeHandler());register(Double.class, new DoubleTypeHandler());register(double.class, new DoubleTypeHandler());register(JdbcType.DOUBLE, new DoubleTypeHandler());register(Reader.class, new ClobReaderTypeHandler());register(String.class, new StringTypeHandler());register(String.class, JdbcType.CHAR, new StringTypeHandler());register(String.class, JdbcType.CLOB, new ClobTypeHandler());register(String.class, JdbcType.VARCHAR, new StringTypeHandler());register(String.class, JdbcType.LONGVARCHAR, new StringTypeHandler());register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());register(String.class, JdbcType.NCHAR, new NStringTypeHandler());register(String.class, JdbcType.NCLOB, new NClobTypeHandler());register(JdbcType.CHAR, new StringTypeHandler());register(JdbcType.VARCHAR, new StringTypeHandler());register(JdbcType.CLOB, new ClobTypeHandler());register(JdbcType.LONGVARCHAR, new StringTypeHandler());register(JdbcType.NVARCHAR, new NStringTypeHandler());register(JdbcType.NCHAR, new NStringTypeHandler());register(JdbcType.NCLOB, new NClobTypeHandler());register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());register(JdbcType.ARRAY, new ArrayTypeHandler());register(BigInteger.class, new BigIntegerTypeHandler());register(JdbcType.BIGINT, new LongTypeHandler());register(BigDecimal.class, new BigDecimalTypeHandler());register(JdbcType.REAL, new BigDecimalTypeHandler());register(JdbcType.DECIMAL, new BigDecimalTypeHandler());register(JdbcType.NUMERIC, new BigDecimalTypeHandler());register(InputStream.class, new BlobInputStreamTypeHandler());register(Byte[].class, new ByteObjectArrayTypeHandler());register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());register(byte[].class, new ByteArrayTypeHandler());register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());register(JdbcType.LONGVARBINARY, new BlobTypeHandler());register(JdbcType.BLOB, new BlobTypeHandler());register(Object.class, unknownTypeHandler);register(Object.class, JdbcType.OTHER, unknownTypeHandler);register(JdbcType.OTHER, unknownTypeHandler);register(Date.class, new DateTypeHandler());register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());register(JdbcType.TIMESTAMP, new DateTypeHandler());register(JdbcType.DATE, new DateOnlyTypeHandler());register(JdbcType.TIME, new TimeOnlyTypeHandler());register(java.sql.Date.class, new SqlDateTypeHandler());register(java.sql.Time.class, new SqlTimeTypeHandler());register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());register(String.class, JdbcType.SQLXML, new SqlxmlTypeHandler());register(Instant.class, new InstantTypeHandler());register(LocalDateTime.class, new LocalDateTimeTypeHandler());register(LocalDate.class, new LocalDateTypeHandler());register(LocalTime.class, new LocalTimeTypeHandler());register(OffsetDateTime.class, new OffsetDateTimeTypeHandler());register(OffsetTime.class, new OffsetTimeTypeHandler());register(ZonedDateTime.class, new ZonedDateTimeTypeHandler());register(Month.class, new MonthTypeHandler());register(Year.class, new YearTypeHandler());register(YearMonth.class, new YearMonthTypeHandler());register(JapaneseDate.class, new JapaneseDateTypeHandler());// issue #273register(Character.class, new CharacterTypeHandler());register(char.class, new CharacterTypeHandler());}
4. 实现自定义的TypeHandler
我们可以直接继承BaseTypeHandler来实现我们自己的类型转换器
我们要实现把json字符串转换成为我们的对象,可以这么实现:
public class JsonTypeHandler<T> extends BaseTypeHandler<T> {private final Class<T> type;public JsonTypeHandler(Class<T> type) {if (type == null) {throw new IllegalArgumentException("输入参数不能为空");}this.type = type;}@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType)throws SQLException {try {String json = JsonUtil.toJson(parameter);ps.setString(i, json);} catch (Exception e) {throw new RuntimeException("Json对象转换成String失败", e);}}@Overridepublic T getNullableResult(ResultSet rs, String columnName) throws SQLException {String json = rs.getString(columnName);return convertJsonToObject(json);}@Overridepublic T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String json = rs.getString(columnIndex);return convertJsonToObject(json);}@Overridepublic T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String json = cs.getString(columnIndex);return convertJsonToObject(json);}private T convertJsonToObject(String json) {try {return JsonUtil.fromJson(json, type);} catch (Exception e) {throw new RuntimeException("json转换成Java对象失败", e);}}
}
因为我们使用的是Spring boot工程,只需要把JsonTypeHandler放到Spring boot可以扫描的目录下即可。
在XML中使用:
<resultMap id="BaseResultMap" type="com.db.model.SettlementBill"><id column="id" jdbcType="INTEGER" property="id" /><result column="receipts_code" jdbcType="VARCHAR" property="receiptsCode" /><result column="finance_info" jdbcType="VARCHAR" property="financeDetailVO1" javaType="com.db.model.SettlementBill"typeHandler="com.mybatis.handler.JsonArrayTypeHandler" /></resultMap><select id="test" parameterType="java.lang.Integer" resultMap="BaseResultMap">select id, receipts_code, finance_info from settlement_bill where id = #{id,jdbcType=INTEGER}</select>
Mybatis Plus中的使用方式:
@TableName(value = "settlement_bill", autoResultMap = true)
@Data
public class SettlementBill extends CxmBaseModel implements Serializable {@TableId(value = "id", type = IdType.AUTO)private Integer id;@TableField(value = "finance_info",typeHandler = JsonTypeHandler.class)private BatchFinanceDetailVO1 financeDetailVO1;
}
5. Mybatis自动获取TypeHandle
在介绍了Mybatis是如何注册TypeHandler之后就介绍一下Mybatis是如何获取对应的TypeHandler进行类型转换的。
如果我们在Mapper.xml文件中配置某一个属性或变量的映射关系时指定了该属性对应的javaType和jdbcType,则Mybatis会从注册好的TypeHandler中寻找对应的javaType和jdbcType组合的TypeHandler进行处理,这也是Mybatis最基本的获取TypeHandler进行类型转换的方式。
1.javaType和jdbcType都指定
假设Mybatis配置文件中有这么一段TypeHandler的注册信息:
<typeHandlers> <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>
</typeHandlers>
看这样一个UserMapper.xml定义:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.tiantian.mybatis.mapper.UserMapper"> <resultMap id="UserResult" type="User"> <id column="id" property="id"/> <result column="interests" property="interests" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/> </resultMap> <insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyColumn="id"> insert into t_user(name, age, interests) values(#{name}, #{age}, #{interests, javaType=[Ljava.lang.String;, jdbcType=VARCHAR}) </insert> <update id="updateUser" parameterType="User"> update t_user set name=#{name}, age=#{age}, interests=#{interests} where id=#{id} </update> <select id="findById" parameterType="int" resultMap="UserResult"> select * from t_user where id=#{id} </select> <delete id="deleteUser" parameterType="int"> delete from t_user where id=#{id} </delete>
</mapper>
我们可以看到在id为UserResult的resultMap中,我们定义了一个对应字段interests的映射关系,并且定义了其javaType为“[Ljava.lang.String;”,jdbcType为VARCHAR,这个时候Mybatis就会到已经注册了的TypeHandler中寻找到能处理javaType和jdbcType对应的类型转换的TypeHandler来进行处理。在这里就会找到我们注册的StringArrayTypeHandler。在上面id为insertUser的insert语句中,我们也为变量interests指定了它的javaType和jdbcType属性,这时候Mybatis也会寻找javaType和jdbcType对应的TypeHandler。上面这样定义是Mybatis最基本也是最完整地获取到对应的TypeHandler的方法。
2. 只指定变量对应的javaType类型。
这个时候Mybatis会拿着这个javaType和jdbcType为null的组合到注册的TypeHandler中寻找对应的TypeHandler。
(1)不动StringArrayTypeHandler的注册信息,把我们的UserMapper.xml改为如下形式:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tiantian.mybatis.mapper.UserMapper"> <resultMap id="UserResult" type="User"> <id column="id" property="id"/> <result column="interests" property="interests" javaType="[Ljava.lang.String;"/> </resultMap> <select id="findById" parameterType="int" resultMap="UserResult"> select * from t_user where id=#{id} </select>
</mapper>
此时我们发现最终执行的结果interests为null,这说明Mybatis没有使用我们定义的StringArrayTypeHandler来转换interests。
(2)UserMapper.xml还像上面那样定义,但是也只指定javaType属性来注册我们的StringArrayTypeHandler,代码如下:
<typeHandlers> <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;"/> </typeHandlers>
这个时候再运行上面的测试代码,输出结果发现interests转换为User类字符串数组类型的interests属性。
这是因为我们是以javaType和null注册的StringArrayTypeHandler,然后在需要转换interests时又是以相同的javaType和null来寻找的,所以就会找到我们注册的StringArrayTypeHandler来进行类型转换。
3. 只指定变量对应的jdbcType类型
这个时候Mybatis会利用我们指定的返回类型和对应的属性取该属性在返回类型中对应的javaType,之后再拿着该javaType和我们指定的jdbcType到注册的TypeHandler中获取对应的TypeHandler。
保持之前指定javaType和jdbcType的方式注册StringArrayTypeHandler,然后在定义interests变量的时候不指定javaType,只指定jdbcType,这个时候UserMapper.xml如下所示:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tiantian.mybatis.mapper.UserMapper"> <resultMap id="UserResult" type="User"> <id column="id" property="id"/> <result column="interests" property="interests" jdbcType="VARCHAR"/> </resultMap> <select id="findById" parameterType="int" resultMap="UserResult"> select * from t_user where id=#{id} </select>
</mapper>
这个时候Mybatis是这样获取TypeHandler的:首先它发现我们的interests没有指定javaType,这个时候它就会通过我们指定的类型User和属性interests获取User类的interests属性对应的java类型,即String数组,再拿着获取到的javaType和我们指定的jdbcType即VARCHAR去寻找对应的TypeHandler,这个时候就找到了我们之前以String数组和VARCHAR注册好的StringArrayTypeHandler来处理interests的类型转换。
4. javaType类型和jdbcType类型都不指定
这个时候Mybatis会以方式2中的方式获取到对应的javaType类型,然后再以方式1获取到对应的TypeHandler。
首先,注册一个javaType为String数组,jdbcType不指定即为null的TypeHandler—StringArrayTypeHandler,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration> <properties resource="config/jdbc.properties"></properties> <typeAliases> <package name="com.tiantian.mybatis.model"/> </typeAliases> <typeHandlers> <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;"/> </typeHandlers> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="com/tiantian/mybatis/mapper/UserMapper.xml"/> </mappers>
</configuration>
然后,定义我们的interests字段的映射关系时既不指定javaType,又不指定jdbcType,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tiantian.mybatis.mapper.UserMapper"> <resultMap id="UserResult" type="User"> <id column="id" property="id"/> <result column="interests" property="interests"/> </resultMap> <select id="findById" parameterType="int" resultMap="UserResult"> select * from t_user where id=#{id} </select>
</mapper>
此时我们以javaType为String数组和jdbcType为null注册了一个StringArrayTypeHandler,然后在定义interests字段的映射关系时我们没有指明其对应的javaType和jdbcType,这个时候Mybatis会利用我们指定的User类型和interests属性获取到User类的interests属性对应的java类型,即String数组,然后结合jdbcType为null去寻找注册的TypeHandler,这样就找到了StringArrayTypeHandler。经StringArrayTypeHandler的处理就把jdbcType为VARCHAR的数据转换为javaType为String数组的数据。
5. 直接通过变量的typeHandler属性指定其对应的TypeHandler
还有一种形式是我们直接通过变量的typeHandler属性指定其对应的TypeHandler,这个时候Mybatis就会使用该用户自己指定的TypeHandler来进行类型转换,而不再以javaType和jdbcType组合的方式获取对应的TypeHandler。
首先在Mybatis的配置文件中以javaType和jdbcType配套的方式注册一个StringArrayTypeHandler,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration> <properties resource="config/jdbc.properties"></properties> <typeAliases> <package name="com.tiantian.mybatis.model"/> </typeAliases> <typeHandlers> <typeHandler handler="com.tiantian.mybatis.handler.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/> </typeHandlers> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="com/tiantian/mybatis/mapper/UserMapper.xml"/> </mappers>
</configuration>
按照前面说的Mybatis按照变量的javaType和jdbcType来取对应的TypeHandler的话,这里注册的StringArrayTypeHandler只有在指定变量的javaType为字符串数组而jdbcType为VARCHAR的情况下才能被获取到。
然后我们在UserMapper.xml文件中不指定interests字段对应的javaType和jdbcType,但是通过typeHandler属性指定将以StringArrayTypeHandler来进行类型转换,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tiantian.mybatis.mapper.UserMapper"> <resultMap id="UserResult" type="User"> <id column="id" property="id"/> <result column="interests" property="interests"
typeHandler="com.tiantian.mybatis.handler.StringArrayTypeHandler"/> </resultMap> <select id="findById" parameterType="int" resultMap="UserResult"> select * from t_user where id=#{id} </select>
</mapper>
这是因为我们指定了进行interests字段的映射关系时使用StringArrayTypeHandler来进行类型转换。当指定了某一个字段或变量进行映射关系时所使用的TypeHandler时,Mybatis在需要进行类型转换时就使用给定的TypeHandler进行类型转换,而不会再通过javaType和jdbcType的组合去注册好的TypeHandler中寻找对应的TypeHandler。
相关文章:
Mybatis TypeHandler 介绍及使用
Mybatis TypeHandler类型转换器是负责Java类和jdbc类型之间的转换 主要涉及到下面这几个类: TypeHandler 类型转换器的顶层接口BaseTypeHandler 抽象类继承自TypeHandler,Mybatis中所有的类型转换器实现均继承他。TypeHandlerRegistry 类型转换器注册器…...
Linux SVN 命令详解
1、将文件 checkout 到本地目录 svn checkout path(path是服务器上的目录) 例如:svn checkout svn://192.168.1.1/pro/domain 简写:svn co 2、往版本库中添加新的文件 svn add file 例如:svn add test.php(添加test.…...
Maven依赖引入的优先机制
xxxx待持续更新...
全开源无加密跨境电商购物网站系统源码(无货源模式+多语言+多货币)
在全球化的时代背景下,跨境电商成为了越来越受欢迎的消费方式,而建立一个源码无加密多语言跨境购物网站系统是一个具有挑战性的任务,但完全可行。以下是这个过程的一些主要步骤: 1. 确定需求和功能规划:先确定网站需要…...
Python常用视频编辑操作——读取与保存视频、更改帧数、拼接视频、视频语音合并、视频与图像互转等
1.更改视频帧数 降低视频帧数,简单的操作只能降低视频帧数,如果要增加视频帧数,那就要使用深度学习进行插帧处理: import cv2 from moviepy.editor import * def change_fps(inpt_path,output_path,fps):# 加载视频video Video…...
从javascript到vue再到react的演变
当提到前端开发中的框架时,JavaScript、Vue.js和React.js是三个最常见的名词。它们代表了Web开发中不同的技术选择和演变过程。本文将探讨JavaScript从原生到Vue.js再到React.js的演变,以及每个阶段的特点和优势。 JavaScript: 动态语言的基础 JavaScr…...
50个渗透(黑客)常用名词及解释
目录 前言一、渗透测试1. 渗透测试:2. 黑盒测试:3. 白盒测试:4. 社会工程学:5. 缓冲区溢出:6. 拒绝服务攻击:7. DDoS攻击:8. XSS攻击:9. CSRF攻击:10. SQL注入࿱…...
开源游戏引擎和模拟器的项目合集 | 开源专题 No.38
yuzu-emu/yuzu Stars: 26.2k License: GPL-3.0 yuzu是一款全球最受欢迎的开源Nintendo Switch模拟器,由Citra创建者编写。它采用C语言编写,并具有可移植性,在Windows和Linux上进行积极维护。该模拟器能够全速运行大多数商业游戏,…...
ELK + Filebeat 分布式日志管理平台部署
ELK Filebeat 分布式日志管理平台部署 1、前言1.1日志分析的作用1.2需要收集的日志1.3完整日志系统的基本特征 2、ELK概述2.1ELK简介2.2为什么要用ELK?2.3ELK的组件 3、ELK组件详解3.1Logstash3.1.1简介3.1.2Logstash命令常用选项3.1.3Logstash 的输入和输出流3.1.4Logstash配…...
Stable Diffusion原理
一、Diffusion扩散理论 1.1、 Diffusion Model(扩散模型) Diffusion扩散模型分为两个阶段:前向过程 反向过程 前向过程:不断往输入图片中添加高斯噪声来破坏图像反向过程:使用一系列马尔可夫链逐步将噪声还原为原始…...
2022年亚太杯APMCM数学建模大赛A题结晶器熔剂熔融结晶过程序列图像特征提取及建模分析求解全过程文档及程序
2022年亚太杯APMCM数学建模大赛 A题 结晶器熔剂熔融结晶过程序列图像特征提取及建模分析 原题再现: 连铸过程中的保护渣使钢水弯液面隔热,防止钢水在连铸过程中再次氧化,控制传热,为铸坯提供润滑,并吸收非金属夹杂物…...
金融网站如何做好安全防护措施?
联网的发展为当代很多行业的发展提供了一个更为广阔的平台,而对于中国的金融业来说,互联网金融这一新兴理念已经为 人们所接受,且发展迅速。我们也都知道金融行业对互联网技术是非常严格的,这对互联网的稳定性和可靠性提出了较高的…...
2023年中国恋爱社区未来发展趋势分析:多元化盈利模式实现可持续发展[图]
恋爱社区指满足情侣之间互动、记录及娱乐需求,以维护情侣恋爱关系的虚拟社区。恋爱社区行业主要以线上APP的虚拟形式为用户提供相关服务,其业务包括情侣记录、情侣互动、情侣娱乐、公共社区、线上购物、增值服务。 恋爱社区主要业务 资料来源࿱…...
Elasticsearch:生成式人工智能带来的社会转变
作者:JEFF VESTAL 了解 Elastic 如何走在大型语言模型革命的最前沿 – 通过提供实时信息并将 LLM 集成到数据分析的搜索、可观察性和安全系统中,帮助用户将 LLM 提升到新的高度。 iPhone 社会转变:新时代的黎明 曾几何时,不久前…...
服务器数据恢复-RAID5中磁盘被踢导致阵列崩溃的服务器数据恢复案例
服务器数据恢复环境: 一台3U的某品牌机架式服务器,Windows server操作系统,100块SAS硬盘组建RAID5阵列。 服务器故障: 服务器有一块硬盘盘的指示灯亮黄灯,这块盘被raid卡踢出后,raid阵列崩溃。 服务器数据…...
负荷不均衡问题分析处理流程
一、负荷不均衡分析 负荷不均衡判断标准:4G同覆盖扇区内存在无线利用率大于50%的小区,且两两小区间无线利用率差值大于30%,判定为4G负荷不均衡扇区;5G同覆盖扇区内存在无线利用率大于50%的小区,且两两小区间无线利用率…...
Spring篇---第四篇
系列文章目录 文章目录 系列文章目录一、说说你对Spring的IOC是怎么理解的?二、解释一下spring bean的生命周期三、解释Spring支持的几种bean的作用域?一、说说你对Spring的IOC是怎么理解的? (1)IOC就是控制反转,是指创建对象的控制权的转移。以前创建对象的主动权和时机…...
算法通过村第十五关-超大规模|白银笔记|经典问题
文章目录 前言从40个亿中产生一个不存在的整数位图存储数据的原理使用10MB来存储如何确定分块的区间 用2GB内存在20亿的整数中找到出现次数最多的数从100亿个URL中查找的问题40亿个非负整数中找出两次的数。总结 前言 提示:人生之中总有空白,但有时&…...
Mini小主机All-in-one搭建教程6-安装苹果MacOS系统
笔者使用的ESXI7.0 Update 3 抱着试试的态度想安装一下苹果的MacOS系统 主要步骤有2个 1.解锁unlocker虚拟机系统 2.安装苹果MacOS系统 需要下载的文件 unlocker 这一步是最耗时间的,要找到匹配自己系统的unlocker文件。 https://github.com/THDCOM/ESXiUnloc…...
Android中使用Glide加载圆形图像或给图片设置指定圆角
一、Glide加载圆形头像 效果 R.mipmap.head_icon是默认圆形头像 ImageView mImage findViewById(R.id.image);RequestOptions options new RequestOptions().placeholder(R.mipmap.head_icon).circleCropTransform(); Glide.with(this).load("图像Uri").apply(o…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
