MyBatis(一)Mybatis入门 ゞ 浴缸里的玫瑰 2021-06-22 15:37 547阅读 0赞 ### 目录 ### * 一、概述 * 二、JDBC编程的分析 * * jdbc问题分析: * 三、mybatis环境搭建 * * 1. 前期准备 * * ① 创建一个maven工程 * ② 创建一个数据库,供我们实验使用: * 2. 搭建mybatis开发环境 * * ① 导入依赖 * ② 创建User类: * ③ 编写持久层接口\`IUserDao\`: * ④ 编写sqlMapConfig.xml配置文件: * ⑤ 编写持久层接口的映射文件 \`IUserDao.xml:\` * 总结 * 3. 测试我们的demo * * ①log4j的配置文件 * ② 测试入口: * ③ 运行结果 * 总结 * 四、使用注解 * 五、写Dao实现类 * 六、分析 * * 1. mybatis入门案例中设计模式的分析 * 2. 自定义mybatis的分析 * 3. 创建代理对象的分析 # 一、概述 # mybatis是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql语句本身, 而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。 mybatis通过xml 或注解的方式将要执行的各种statement配置起来,并通过java对象和statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并 返回。 采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc进行了封装,屏蔽了 jdbc api 底层访问细节,使我 们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。 了我们能够更好掌握框架运行的内部过程,并且有更好的体验,下面我们将从自定义 Mybatis 框架开始来 学习框架。此时我们将会体验框架从无到有的过程体验,也能够很好的综合前面阶段所学的基础。 -------------------- # 二、JDBC编程的分析 # 我们回顾一下以前的JDBC编程方式: public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { // 加载数据库驱动 Class.forName("com.mysql.jdbc.Driver"); // 通过驱动管理类获取数据库链接 connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "0000"); // 定义 sql 语句 ?表示占位符 String sql = "select * from user where username = ?"; // 获取预处理 statement preparedStatement = connection.prepareStatement(sql); // 设置参数,第一个参数为 sql 语句中参数的序号(从 1 开始),第二个参数为设置的 参数值 preparedStatement.setString(1, "王五"); // 向数据库发出 sql 执行查询,查询出结果集 resultSet = preparedStatement.executeQuery(); // 遍历查询结果集 while (resultSet.next()) { System.out.println(resultSet.getString("id") + "," + resultSet.getString("username")); } } catch (Exception e) { e.printStackTrace(); } finally { // 释放资源 if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } } 上边使用 jdbc 的原始方法(未经封装)实现了查询数据库表记录的操作。 ## jdbc问题分析: ## 1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。 2. Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。 3. 使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能 多也可能少,修改 sql 还要修改代码,系统不易维护。 4. 对结果集解析存在硬编码(查询列名),sql 变化导致解析代码变化,系统不易维护,如果能将数据库记 录封装成 pojo 对象解析比较方便。 -------------------- # 三、mybatis环境搭建 # 接下来,我们做一个mybatis的小demo,整体上感受一下mybatis的使用过程。 ## 1. 前期准备 ## ### ① 创建一个maven工程 ### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 1] ### ② 创建一个数据库,供我们实验使用: ### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 2] **新建一张表:** CREATE TABLE `user` ( `id` INT ( 11 ) NOT NULL auto_increment, `username` VARCHAR ( 32 ) NOT NULL COMMENT '用户名称', `birthday` datetime DEFAULT NULL COMMENT '生日', `sex` CHAR ( 1 ) DEFAULT NULL COMMENT '性别', `address` VARCHAR ( 256 ) DEFAULT NULL COMMENT '地址', PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8; **插入一些内容:** INSERT INTO `user` ( `id`, `username`, `birthday`, `sex`, `address` ) VALUES ( 41, '刘帅帅', '2018-02-27 17:47:08', '男', '菏泽' ), ( 42, '刘伟佳', '2018-03-02 15:09:37', '男', '青岛' ), ( 43, '李萌萌', '2018-03-04 11:34:34', '女', '济南' ), ( 45, '李美美', '2018-03-04 12:04:06', '女', '滨州' ), ( 46, '外星人', '2018-03-07 17:37:26', '男', '火星' ), ( 48, '歪比巴卜', '2018-03-08 11:44:00', '女', '三体' ); ![在这里插入图片描述][20200330152404428.png] ## 2. 搭建mybatis开发环境 ## ### ① 导入依赖 ### **我们在maven工程中导入依赖,并把项目的打包方式改为jar:** <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.veeja</groupId> <artifactId>day01_01mybatis</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> </dependencies> </project> ### ② 创建User类: ### package com.veeja.domain; import java.io.Serializable; import java.util.Date; public class User implements Serializable { private Integer id; private String username; private Date birthday; private String sex; private String address; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + '}'; } } ### ③ 编写持久层接口`IUserDao`: ### package com.veeja; import com.veeja.domain.User; import java.util.List; /** * 用户的持久层接口 */ public interface IUserDao { /** * 查询所有的用户 * * @return */ List<User> findAll(); } ### ④ 编写sqlMapConfig.xml配置文件: ### ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 3] <?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"> <!--mybatis的主配置文件--> <configuration> <!--配置环境--> <environments default="mysql"> <!--配置mysql的环境--> <environment id="mysql"> <!--配置事务的类型--> <transactionManager type="JDBC"></transactionManager> <!--配置数据源(连接池)--> <dataSource type="POOLED"> <!--配置连接数据库的4个基本信息--> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatisdatabase"/> <property name="username" value="root"/> <property name="password" value="0000"/> </dataSource> </environment> </environments> <!--指定映射配置文件的位置,映射文件指的是每个dao独立的配置文件--> <mappers> <mapper resource="com/veeja/dao/IUserDao.xml"/> </mappers> </configuration> ### ⑤ 编写持久层接口的映射文件 `IUserDao.xml:` ### **注意:** 创建位置:必须和持久层接口在相同的包中。 名称:必须以持久层接口名称命名文件名,扩展名是.xml ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 4] <?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.veeja.dao.IUserDao"> <!-- 配置查询所有的操作 --> <select id="findAll" resultType="com.veeja.domain.User"> select * from user </select> </mapper> ### 总结 ### 接下来我们总结一下,搭建一个mybatis的环境需要做些什么? 1. 创建一个maven工程并且导入依赖; 2. 创建实体类和DAO接口 3. 创建mybatis的主配置文件,SqlMapConfig.xml 4. 创建映射配置文件,IUserDao.xml **这里面有几个注意事项:** 第一个:创建IUserDao.xml 和 IUserDao.java时名称是为了和我们之前的知识保持一致。 在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper 所以:IUserDao 和 IUserMapper是一样的 第二个:在idea中创建目录的时候,它和包是不一样的 包在创建时:com.itheima.dao它是三级结构 目录在创建时:com.itheima.dao是一级目录 第三个:mybatis的映射配置文件位置必须和dao接口的包结构相同 第四个:映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名 第五个:映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名 当我们遵从了第三,四,五点之后,我们在开发中就无须再写dao的实现类。 ## 3. 测试我们的demo ## ### ①log4j的配置文件 ### 首先导入log4j的配置文件,在resources文件夹下创建文件:**log4j.properties** ![在这里插入图片描述][20200410082942736.png] 内容如下: # Set root category priority to INFO and its only appender to CONSOLE. #log4j.rootCategory=INFO, CONSOLE debug info warn error fatal log4j.rootCategory=debug, CONSOLE, LOGFILE # Set the enterprise logger category to FATAL and its only appender to CONSOLE. log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE # CONSOLE is set to be a ConsoleAppender using a PatternLayout. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n # LOGFILE is set to be a File appender using a PatternLayout. log4j.appender.LOGFILE=org.apache.log4j.FileAppender log4j.appender.LOGFILE.File=d:\axis.log log4j.appender.LOGFILE.Append=true log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n ### ② 测试入口: ### package com.veeja.test; import com.veeja.dao.UserDaoImpl; import com.veeja.domain.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; import java.util.List; /** * mybatis的入门案例使用main函数执行 */ public class MybatisTest { /** * 入门案例 */ public static void main(String[] args) throws Exception { // 1. 读取配置文件 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); // 2. 创建一个SqlSessionFactory工厂 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); // 3. 使工厂生产SQLSession对象 SqlSession session = factory.openSession(); // 4. 使用SQLSession创建Dao接口的代理对象(动态代理) IUserDao userDao = session.getMapper(IUserDao.class); // 5. 使用代理对象执行方法 List<User> users = userDao.findAll(); for (User user : users) { System.out.println(user); } // 6. 释放资源 session.close(); in.close(); } } ### ③ 运行结果 ### 运行一下,结果符合我们预期。 ![在这里插入图片描述][20200407115848135.png] ### 总结 ### 我们再总结一下刚才在测试类里面我们都做了什么。 第一步:读取配置文件 第二步:创建SqlSessionFactory工厂 第三步:创建SqlSession 第四步:创建Dao接口的代理对象 第五步:执行dao中的方法 第六步:释放资源 -------------------- # 四、使用注解 # 我们发现,这样好像还是很麻烦,还要写xml文件,我们在上面的概述中提到,mybatis可以使用xml或者注解的方式来进行配置。接下来我们演示一下使用注解的配置方式。 **我们新建一个maven工程。** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 5] 为了方便,我们把上个项目中的**src下的main和test文件夹**以及**pom.xml文件**直接复制到新的项目中去。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 6] **我们到底怎么样使用注解呢?** 既然我们使用注解,那么上面的一些xml配置文件就没什么用了。 **IUserDao.xml文件我们就可以直接删除了。** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 7] **然后在我们的UserDaoImpl.java类的相应方法上,我们写上一些注解:** /** * 用户的持久层接口 */ public interface IUserDao { /** * 查询所有的用户 * * @return */ @Select("select * from user") List<User> findAll(); } 但是这样有一个问题,我们在SqlMapConfig.xml中有一个mapper,指定了配置文件的位置, ![在这里插入图片描述][20200410084613331.png] 那么现在这个配置文件没有了,我们该怎么办呢? **如果是注解的方式我们应该使用class属性,** 而不是resource属性,也就是: <mappers> <mapper class="com.veeja.dao.IUserDao"/> </mappers> **我们按照上面的测试类继续运行一遍,还是完全没有问题的。** ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 8] 我们可以发现,这样的方式会简单一些。 **我们稍微总结一下使用注解的方式:** 把`UserDaoImpl.xml`移除,在dao接口的方法上使用`@Select`注解,并且指定SQL语句。 同时需要在`SqlMapConfig.xml`中的mapper配置时,使用class属性指定dao接口的全限定类名。 -------------------- # 五、写Dao实现类 # 我们在实际开发中,都是越简便越好,所以都是采用不写dao实现类的方式,不管使用XML还是注解配置。 **但是Mybatis它是支持写dao实现类的。** 接下来我们演示一下。 首先创建一个新的工程: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 9] 我们还是把第一个工程中的**main和test直接复制到新的项目**中来。还要**复制pom.xml中的配置进来**。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 10] 接下来我们在dao文件夹下新建一个包`impl`,并且添加一个新的IUserDao的实现类`UserDaoImpl`: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 11] **我们要在Dao的实现类中添加一下代码:** public class UserDaoImpl implements IUserDao { private SqlSessionFactory factory; /** * 覆写构造参数 * @param factory */ public UserDaoImpl(SqlSessionFactory factory) { this.factory = factory; } public List<User> findAll() { //1.使用工厂创建SQLSession对象 SqlSession session = factory.openSession(); //2. 使用session执行查询方法 // 为了定位这个方法,使用了namespace.function的方式。 List<User> users = session.selectList("com.veeja.dao.IUserDao.findAll"); session.close(); //3.返回查询结果 return users; } } 我们在测试的时候需要作出一点改变,我们的dao是需要一个factory的,我们应该传给它,而且不需要session了: public class MybatisTest { /** * 入门案例 */ public static void main(String[] args) throws Exception { // 1. 读取配置文件 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); // 2. 创建一个SqlSessionFactory工厂 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); /******************************************************/ // 3. 使用工厂创建dao对象 IUserDao userDao = new UserDaoImpl(factory); /******************************************************/ // 4. 使用代理对象执行方法 List<User> users = userDao.findAll(); for (User user : users) { System.out.println(user); } // 5. 释放资源 in.close(); } } 运行结果完全符合预期: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 12] **但是这样的写法毫无意义,增加了我们开发的任务量,但是需要注意的上面就是在Dao的实现中为了定位相应 的方法,使用了namespace和方法名的方式。** -------------------- # 六、分析 # ## 1. mybatis入门案例中设计模式的分析 ## ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 13] ## 2. 自定义mybatis的分析 ## mybatis在使用代理Dao的方式实现增删改查时做什么事呢? 只有两件事,一个是创建代理对象,一个是在代理对象中调用`selectList()`方法,而里面是具体怎么执行的呢?看如下的图示: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 14] ## 3. 创建代理对象的分析 ## ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 15] -------------------- END. [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70]: /images/20210615/42e1ee35904c46a9b6e263f94891760a.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 1]: /images/20210615/cd3079b760c3474790fc71c73cb8763f.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 2]: /images/20210615/25cb7129d438452aad2c7717b76625f0.png [20200330152404428.png]: /images/20210615/7fc20ebeb4d045a69ac1e478f40df225.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 3]: /images/20210615/00ffa42ba54347318372ebabcbc815c2.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 4]: /images/20210615/a37117f3609c4563ba2814799de427e0.png [20200410082942736.png]: /images/20210615/7cba6b927c6e4f2f9bd585b74705210b.png [20200407115848135.png]: /images/20210615/208fd82dabd947e5b51216dd049c09ea.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 5]: /images/20210615/771ba91866c1491598cef7a41f4d822d.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 6]: /images/20210615/336f900d93d34991a54ccc4de30d6d68.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 7]: /images/20210615/1b67a99d608047f188cc8a7bae9fe9c8.png [20200410084613331.png]: /images/20210615/ea21fd0eb3504bb79439c17e783aec39.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 8]: /images/20210615/1d86aa3ce60a435b96475cd673de3e23.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 9]: /images/20210615/21831ceeeb9c489480e96b448384bf5d.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 10]: /images/20210615/6cafa9180ef347b888a5fe9c98eb3d8e.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 11]: /images/20210615/35a017f99e45466e810b5f1e348aa366.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 12]: /images/20210615/febcf49da99d446392e1c66e20e919c7.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 13]: /images/20210615/1980e0399ade44e0817a7f2d7dfab4ce.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 14]: /images/20210615/42ddc9c336c24652b2a94fcdcf965ea7.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTQ1NjUxMjc_size_16_color_FFFFFF_t_70 15]: /images/20210615/2c239d03a8b64bb9b1254179787b1317.png
还没有评论,来说两句吧...