目录
1、简介
1.1、背景
1.2、概念
1.3、驱动程序
2、JDBC的优点
3、使用步骤
3.1、操作流程
3.2、代码步骤
3.3、实例演示
3.3.1、创建空工程
3.3.2、指定项目的名称以及存放路径
3.3.3、设置项目的JDK版本和编译版本
3.3.4、创建模块
3.3.5、⭐导入MySQL驱动包
3.3.6、⭐创建Java类
4、API详解
4.1、DriverManager
4.1.1、注册方式
4.1.2、源码分析
4.1.3、🔺🔺MySQL5
4.2、Connection
4.2.1、DriverManager.getConnection
4.2.2、connection.createStaterment()
4.2.3、事务管理
4.3、⭐Statement
4.4、ResultSet
4.4.1、⭐⭐内部方法
5、数据库连接池
5.1、简介
5.2、连接池的实现
5.2.1、⭐常见的数据库连接池
5.3、🔺Druid的使用->IDEA
5.3.1、导jar包
5.3.2、定义配置文件
5.3.3、使用Druid
1、简介
1.1、背景
开发中,同一套Java代码是无法操作不同的关系型数据库,因为每一个关系型数据库的底层实现细节都不一样。如果这样,假如在业务开发阶段使用的是MySQL数据库,而上线时公司最终选用oracle数据库,则需要对代码进行大批量修改,这显然行不通。
因此Java开发人员更希望做到的是同一套Java代码操作不同的关系型数据库。sun公司就指定了一套标准接口(JDBC),JDBC中定义了所有操作关系型数据库的规则。
接口是无法直接使用的,我们需要使用接口的实现类,而这套实现类(称之为:驱动)就由各自的数据库厂商给出。
简单来说:在开发中我们使用的是java语言,那么势必要通过java语言操作数据库中的数据,势必要用Java操作不同的数据库管理系统,所以需要JDBC!
1.2、概念
JDBC(Java Database Connectivity)是Java程序用于访问关系数据库的API。通过标准的接口和类来管理数据库连接和执行SQL语句,可以用于连接不同类型的数据库管理系统(DBMS),如MySQL、Oracle、SQL Server等。这使得Java程序员可以快速、方便地与各种关系数据库进行交互。
1.3、驱动程序
JDBC驱动程序分为四种类型:
- JDBC-ODBC桥驱动
- Native-API驱动(部分)
- Network-Protocol驱动(三层驱动)
- Thin驱动(纯Java驱动)
通过使用JDBC驱动程序,Java程序员可以方便地访问关系型数据库,而不必关心数据库的具体实现方式。
2、JDBC的优点
各数据库厂商使用相同的接口,Java代码不需要针对不同数据库分别开发,可随时替换底层数据库,访问数据库的Java代码基本不变 。
以后编写操作数据库的代码只需要面向JDBC(接口),操作哪个关系型数据库就需要导入该数据库的驱动包,如需要操作MySQL数据库,就需要在项目中导入MySQL数据库的驱动包。
3、使用步骤
3.1、操作流程
①编写Java代码
②Java代码将SQL发送到MySQL服务端
③MySQL服务端接收到SQL语句并执行该SQL语句
④将SQL语句执行的结果返回给Java代码
3.2、代码步骤
①创建工程,导入驱动jar包
②注册驱动->Class.forName("com.mysql.jdbc.Driver");
③获取连接->Connection connection = DriverManager.getConnection(url, username, password);
Java代码需要发送SQL给MySQL服务端,就需要先建立连接
(如果是连接本地root数据库,要记得开启本地的MySQL服务)
(在后面的技术中,主要使用的是连接池的方式获取Connection连接)
④定义SQL语句->String sql = "update…" ;
⑤获取执行SQL对象(执行SQL语句需要SQL执行对象,而这个执行对象就是Statement对象) ->
->Statement statement = connection.createStatement();
⑥执行SQL->statement.executeUpdate(sql);
ResultSet resultSet = statement.executeQuery(sql);
⑦处理返回结果 while (resultSet.next()) {...}
⑧释放资源connection.close();
3.3、实例演示
3.3.1、创建空工程
3.3.2、指定项目的名称以及存放路径
3.3.3、设置项目的JDK版本和编译版本
编译版本一般默认即可
3.3.4、创建模块
3.3.5、⭐导入MySQL驱动包
将mysql的驱动包放在模块下的lib目录(随意命名,但是一般命名为lib或library)下,
并将该jar包添加为库文件
添加到项目依赖中,MySQL驱动jar包才能使用。
3.3.5.1、判断
如何判断添加是否成功:
①未添加:
②已添加成功
添加依赖成功后,jar包可以下拉看见其中的各种代码
3.3.6、⭐创建Java类
url : 连接路径
语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…
示例:jdbc:mysql://127.0.0.1:3306/db1
如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对
package com.xzl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class jdbc {
public static void main(String[] args) throws Exception {
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取连接
String url = "jdbc:mysql://127.0.0.1:3306/student";
String username = "root";
String password_P = "";
Connection connection = DriverManager.getConnection(url,username,password);
//3、定义sql
String sql = "insert into stu(name,math,gender) values('张三',85,'男')";
//4. 获取执行sql的对象Statement
Statement statement = connection.createStatement();
//5、执行SQL
int count = statement.executeUpdate(sql);
//6、处理结果(此处demo展现受影响的函数)
System.out.println(count);
//7、释放资源
statement.close();
connection.close();
}
}
结果:
在执行Java代码前:
执行Java代码后:
4、API详解
4.1、DriverManager
JDBC步骤二:注册驱动->DriverManager
4.1.1、注册方式
注册驱动的两种方式:
①静态注册:Class.forName("com.mysql.jdbc.Driver");
②动态注册:DriverManager.registerDriver(new Driver());
实际注册方式为方式二,但实际代码编写为方式一。
理由:
两种注册方式都可以,但是静态注册方式更稳定,因为它在程序启动前就注册了驱动,没有因为网络问题等导致无法加载驱动的风险,所以推荐使用静态注册方法。
4.1.2、源码分析
DriverManager.registerDriver(new Driver());
--->
Class.forName("com.mysql.jdbc.Driver");
--->
可以看出,静态注册方式采用的是反射机制,获取了MySQL驱动包中的Driver对象
重温反射知识:
查看com.mysql.jdbc.Driver源码,可以看到在Driver中静态加载了DriverManager.registerDriver(new Driver());,所以两种注册方式在源码上本质并无区别。只是静态注册更安全更稳固,且只会随着类加载一次,不会出现重复注册或者因网络问题进而出现注册问题的情况出现。
4.1.3、🔺🔺MySQL5
MySQL 5之后的驱动包,可以省略注册驱动的步骤,
自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
4.2、Connection
Connection(数据库连接对象)作用:
获取执行 SQL 的对象
管理事务
4.2.1、DriverManager.getConnection
JDBC步骤三:获取连接->Connection connection = DriverManager.getConnection(url, username, password);
参数说明:
①url : 连接路径
语法:jdbc:mysql://ip地址(域名):端口号/数据库名称[?参数键值对1&参数键值对2… ]
示例:jdbc:mysql://127.0.0.1:3306/student
②user :用户名
③poassword :密码
4.2.2.1、⭐注意事项:useSSL
如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,
则url可以简写为:jdbc:mysql:///数据库名称?参数键值对
配置 useSSL=false 参数,禁用安全连接方式,解决警告提示
Ex: jdbc:mysql://127.0.0.1:3306/student?useSSL=false
false前:
false后:
警告内容为:
Tue Jan 31 20:57:02 CST 2023 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
简单来说就是:
不建议在没有服务器身份验证的情况下建立 SSL 连接。
需要设置 useSSL=false 来显式禁用 SSL,或设置 useSSL=true 并为服务器证书验证提供信任库。
4.2.2、connection.createStaterment()
JDBC步骤五:获取执行SQL对象->Statement statement = connection.createStatement();
三种获取方式:
①普通执行SQL对象:Statement createStatement()
②预编译SQL的执行SQL对象:PreparedStatement prepareStatement(sql)->防止SQL注入
③执行存储过程的对象:CallableStatement prepareCall(sql)
通过方式③获取的 CallableStatement 执行对象是用来执行存储过程的,而存储过程在MySQL中不常用
4.2.2.1、 🔺🔺PreparedStatement
PreparedStatement作用: 预编译SQL语句并执行:预防SQL注入问题
sql语句中参数使用"?"进行占位,在执行SQL之前要设置这些"?"的值。
PreparedStatement对象方法:setXxx(参数1,参数2)->给SQL中的"?"赋值
Xxx:数据类型 ; 如 setInt (参数1,参数2)
参数:
参数1: ?的位置编号,从1 开始
参数2: ?的值
注意:
调用执行SQL语句的方法时不需要传递SQL语句,
因为获取SQL语句执行对象时已经对SQL语句进行预编译了。
代码改进如下:
改前:
package com.xzl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class jdbc {
public static void main(String[] args) throws Exception {
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取连接
String url = "jdbc:mysql://127.0.0.1:3306/student?useSSL=false";
String username = "root";
String password_P = "xzlXZGK680";
Connection connection = DriverManager.getConnection(url,username,password);
String sql = "update stu set gender='女' where name='李四' and gender='男'";
//4. 获取执行sql的对象Statement
Statement statement = connection.createStatement();
//此时需要开启事务之后再执行
try {
//禁用自动提交模式:false
connection.setAutoCommit(false);
//5、执行SQL->此处需要开启事务之后再执行
int count = statement.executeUpdate(sql);
System.out.println(count);
//6、处理结果
// ============提交事务==========
//程序运行到此处,说明没有出现任何问题,则需提交事务
connection.commit();
}catch (Exception e){
//事务程序出错,回滚事务
connection.rollback();
e.printStackTrace();
}finally {
//7、释放资源
statement.close();
connection.close();
}
}
}
改后:
package com.xzl;
import java.sql.*;
public class jdbc {
public static void main(String[] args) throws Exception {
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取连接
String url = "jdbc:mysql://127.0.0.1:3306/student?useSSL=false";
String username = "root";
String password_P = "xzlXZGK680";
Connection connection = DriverManager.getConnection(url,username,password);
//3、定义sql
String sql = "update stu set gender='女' where name=? and gender=?";
//4、获取预编译SQL的执行SQL对象:PreparedStatement
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//设置参数值
preparedStatement.setString(1,"李四");
preparedStatement.setString(2,"男");
//此时需要开启事务之后再执行
try {
//禁用自动提交模式:false
connection.setAutoCommit(false);
//5、执行SQL->此处需要开启事务之后再执行
int count = preparedStatement.executeUpdate();
System.out.println(count);
//6、处理结果
// ============提交事务==========
//程序运行到此处,说明没有出现任何问题,则需提交事务
connection.commit();
}catch (Exception e){
//事务程序出错,回滚事务
connection.rollback();
e.printStackTrace();
}finally {
//7、释放资源
preparedStatement.close();
connection.close();
}
}
}
4.2.3、事务管理
4.2.3.1、MySQL事务管理
回顾MySQL事务管理的操作:
①开启事务 : BEGIN; 或者 START TRANSACTION;
②提交事务 : COMMIT;
③回滚事务 : ROLLBACK;
MySQL默认是自动提交事务
4.2.3.2、⭐JDBC事务管理信息
JDBC事务管理的方法:Connection接口中定义了3个对应的方法:
方法 |
说明 |
|
开启事务 |
void setAutoCommit (boolean autoCommit) |
将次连接的自动提交模式设置为给定状态 |
提交事务 |
void commit() |
使自上次提交/回滚以来所做的所有更改成为永久更改,并释放此Connection对象当前特有的所有数据库锁 |
回滚事务 |
void rollback() |
撤销当前事务中所做的所有更改,并释放此Connection对象当前特有的所有数据库锁 |
代码如下:
4.3、⭐Statement
Statement对象的作用就是用来执行SQL语句。而针对不同类型的SQL语句使用的方法也不一样。
(excute执行 quary查询)
方法 |
说明 |
|
执行DDL、DML语句 |
int executeUpdate(String sql) |
执行给定的SQL语句,这可能是INSERT, UPDATE,或 DELETE语句,或者不返回任何内容,如SQL中的DDL语句 |
执行DQL语句 |
ResultSet excuteQuery(String sql) |
执行给定的SQL语句,该语句返回单个 Resultset对象。 |
在开发中很少使用java代码操作DDL语句,原因如下:
- 数据库结构定义通常由数据库管理员负责,而不是开发人员。
- Java代码不是操作DDL语句最方便的方式,使用数据库管理工具(如MySQL Workbench)通常更方便。
- DDL语句很少需要在运行时进行更改,因此不太需要通过Java代码来操作。
- Java代码主要用于查询和更新数据,而不是定义数据结构。
4.4、ResultSet
JDBC步骤六:执行SQL:
方式一:->int executeUpdate(String sql)
方式二:->ResultSet excuteQuery(String sql)
ResultSet(结果集对象)作用: 封装了SQL查询语句的结果,执行了DQL语句后就会返回该对象
4.4.1、⭐⭐内部方法
ResultSet 对象提供了操作查询结果数据的方法:
①boolean next()
②xxx getXxx(参数):获取数据
4.4.1.1、boolean next()
作用:将光标从当前位置向前移动一行,判断当前行是否为有效行
方法返回值说明:
true : 有效行,当前行有数据
false : 无效行,当前行没有数据
一开始光标指定于第一行前,指向于表头行。
当我们调用了 next() 方法后,光标就下移到第一行数据,并且方法返回true
4.4.1.2、xxx getXxx(参数):获取数据
xxx : 数据类型;如: int getInt(参数) ;String getString(参数)
两种参数 :
①int类型的参数:列的编号,从1开始,第一列为1,第二列为2…
String name = resultSet.getString("1");
②String类型的参数: 列的名称
String name = resultSet.getString("name");
4.4.1.3、⭐代码实现
需求:遍历得到数据库表单stu中的数据
stu:
package com.xzl;
public class stu {
private String name;
private Integer math;
private String gender;
public stu() { }
public stu(String name, Integer math, String gender) {
this.name = name;
this.math = math;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getMath() {
return math;
}
public void setMath(Integer math) {
this.math = math;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "stu{" +
"name='" + name + '\'' +
", math=" + math +
", gender='" + gender + '\'' +
'}';
}
}
jbdc:
package com.xzl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class jdbc {
public static void main(String[] args) throws Exception {
//1、注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获取连接
String url = "jdbc:mysql://127.0.0.1:3306/student?useSSL=false";
String username = "root";
String password_P = "xzlXZGK680";
Connection connection = DriverManager.getConnection(url,username,password);
//3、定义sql
// String sql1 = "insert into stu(name,math,gender) values('张三',85,'男')";
// String sql2 = "insert into stu(name,math,gender) values('李四',75,'男')";
// String sql3 = "insert into stu(name,math,gender) values('王五',90,'男')";
String sql_dql = "select * from stu";
//4. 获取执行sql的对象Statement
Statement statement = connection.createStatement();
//创建集合存放接下来得到的表单数据
List<stu> list = new ArrayList<>();
//此时需要开启事务之后再执行
try {
//禁用自动提交模式:false
connection.setAutoCommit(false);
//5、执行SQL->此处需要开启事务之后再执行
// int count1 = statement.executeUpdate(sql1);
// int count2 = statement.executeUpdate(sql2);
// int count3 = statement.executeUpdate(sql3);
ResultSet resultSet = statement.executeQuery(sql_dql);
//6、处理结果(此处demo遍历得到stu中的所有数据并存放于集合)
while (resultSet.next()){
//创建stu对象
stu student = new stu();
String name = resultSet.getString("1");
Integer math = resultSet.getInt(2);
String gender = resultSet.getString(3);
student.setName(name);
student.setMath(math);
student.setGender(gender);
//存入list集合
list.add(student);
}
// ============提交事务==========
//程序运行到此处,说明没有出现任何问题,则需提交事务
connection.commit();
}catch (Exception e){
//事务程序出错,回滚事务
connection.rollback();
e.printStackTrace();
}finally {
//7、释放资源
statement.close();
connection.close();
}
System.out.println(Arrays.toString(list.toArray()));
}
}
5、数据库连接池
5.1、简介
数据库连接池是个容器,负责分配、管理数据库连接(Connection)。
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
优点:
①资源重用
②提升系统响应速度
③避免数据库连接遗漏
之前的代码中使用连接是不管有没有使用都创建一个Connection对象,使用完毕就会将其销毁。
这样重复创建销毁的过程是特别耗费计算机的性能的及消耗时间。
而数据库使用了数据库连接池后,就能达到Connection对象的复用!
连接池是在一开始就创建好了一些连接(Connection)对象存储起来。
用户需要连接数据库时,不需要自己创建连接,而只需要从连接池中获取一个连接进行使用,使用完毕后再将连接对象归还给连接池;这样就可以起到资源重用,也节省了频繁创建连接销毁连接所花费的时间,从而提升了系统响应的速度
5.2、连接池的实现
标准接口:DataSource-> 官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口。
该接口提供了获取连接的功能,以后就不需要通过 DriverManager 对象获取Connection对象,而是通过连接池(DataSource)获取Connection对象。
5.2.1、⭐常见的数据库连接池
- DBCP:Apache基金会提供的数据库连接池实现,具有简单易用、性能稳定等优点。
- C3P0:开源的数据库连接池实现,支持自动回收空闲连接、自动重新获取失效连接等功能。
- Druid
- HikariCP:一款高性能的数据库连接池实现,支持多种数据库,具有轻量级、高效率、可靠稳定等特点。
- BoneCP:一款高性能的数据库连接池实现,支持多种数据库,具有高并发能力、可靠稳定等特点。
现在使用更多的是Druid.
Druid是阿里巴巴开源的一款高性能、稳定、安全的数据库连接池实现。
它支持多种数据库,具有以下特点:
- 高性能:采用高效的缓存机制,提高数据库连接的利用率,提升数据库性能。
- 稳定可靠:支持连接池、防止攻击、SQL监控等功能,保证数据库的安全性和稳定性。
- 实时监控:提供实时的数据监控、性能分析和数据统计功能,方便用户对数据库性能进行诊断和优化。
- 易用易扩展:提供丰富的API和扩展接口,方便用户定制和扩展功能,同时易于集成到各种应用系统中。
Druid是一款优秀的数据库连接池实现,适用于各种数据库应用场景,推荐使用。
5.3、🔺Druid的使用->IDEA
步骤:
①导入jar包 druid-1.1.12.jar
②定义配置文件
③加载配置文件
④获取数据库连接池对象
⑤获取连接
5.3.1、导jar包
放在lib目录下,并添加到项目依赖:
5.3.2、定义配置文件
配置文件可以从外部导入,也可以自己新建编写,此处是自己编写。
配置文件要放在src目录下
5.3.2.1、 🔺⭐druid.properties
Druid的配置文件druid.properties是Druid数据库连接池的主要配置文件,它包含了Druid数据库连接池的各项配置参数,控制Druid运行的行为。
下面是druid.properties文件的常见配置项:
- 驱动相关配置:
- driverClassName:指定数据库驱动类名;
- url:指定数据库连接地址;
- username:指定数据库用户名;
- password:指定数据库密码。
- 连接池相关配置:
- initialSize:初始连接数;
- maxActive:最大连接数;
- minIdle:最小空闲连接数;
- maxWait:获取连接的最大等待时间。
- 监控相关配置(后面再详细学习):
- filters:指定Druid监控的拦截器;
- connectionProperties:指定连接的其他属性;
- stat:是否开启Druid监控。
示例:
#驱动相关配置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
username=root
password=root
#连接池相关配置
initialSize=10
maxActive=20
minIdle=5
maxWait=60000
#监控相关配置
filters=stat,wall
connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
stat=true
5.3.2.1.1、监控相关配置
druid的监控相关配置一般是写在properties文件中,也就是druid.properties文件中。这样做的好处是可以随时修改配置文件来更改druid的配置,而不需要重新编译客户端代码。
当然,也可以通过客户端代码的方式来配置druid的监控相关配置。具体的方法是使用DruidDataSource类来配置监控相关配置。
以下是常用的监控配置的Java代码示例:
DruidDataSource dataSource = new DruidDataSource();
// 设置是否合并SQL
dataSource.setConnectionProperties("druid.stat.mergeSql=true");
// 设置统计慢SQL的时间
dataSource.setConnectionProperties("druid.stat.slowSqlMillis=5000");
// 设置是否打印慢SQL日志
dataSource.setConnectionProperties("druid.stat.logSlowSql=true");
// 设置是否开启Web统计页面
dataSource.setConnectionProperties("druid.web.stat.enabled=true");
// 设置访问监控页面的用户名
dataSource.setConnectionProperties("druid.web.stat.loginUsername=druid");
// 设置访问监控页面的密码
dataSource.setConnectionProperties("druid.web.stat.loginPassword=druid");
下面是druid.properties中常见的监控相关配置项:
- 配置监控控制台:
druid.stat.mergeSql=true druid.stat.logSlowSql=true druid.web.stat.enabled=true druid.web.stat.urlPattern=/* druid.web.stat.resetEnable=false druid.web.stat.sessionStatEnable=false druid.web.stat.sessionStatMaxCount=1000 druid.web.stat.principalSessionName=user druid.web.stat.principalCookieName=user druid.web.stat.profileEnable=false
- 配置监控数据源:
druid.monitor.log.enabled=false druid.monitor.log.intervalSeconds=30
注意:上面的配置仅仅是druid.properties监控相关配置的常见配置项,详细配置请参考druid官方文档。文章来源:https://www.toymoban.com/news/detail-768011.html
5.3.2.2、简单demo代码文章来源地址https://www.toymoban.com/news/detail-768011.html
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/student?useSSL=false&useServePrepStmts=true
username=root
password=xzlXZGK680
initialSize=5
maxActive=15
minIdle=5
maxWait=3000
5.3.3、使用Druid
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
public class DruidDemo {
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.定义配置文件
//3. 加载配置文件
Properties properties = new Properties();
properties.load(new FileInputStream("src/druid.properties"));
//4、获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
//5、获取数据库连接Connection
Connection connection = dataSource.getConnection();
System.out.println(connection);
//获取到数据库连接之后就可以继续进行其他操作了
}
}
到了这里,关于[Java Web]JDBC->Java操作MySQL数据库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!