传智播客PHP笔记06-thinkphp框架--模型、实例化模型对象,crud操作,where,自增减,单多条数据查询,数据删除,字段缓存,数据表字段定义,数据创建,字段映射,自动验证及完成,统计查询

1、创建模型
  • 1、存储位置

/应用/模块/Model目录

  • 2、模型文件命名规则

名称+model+.class.php
首字母大写,驼峰写法

模型的作用是实现与数据库中的数据表进行具体的数据交互,一般要求模型名称跟对应的数据表的名称保持一致。也可不一致,但不推荐,应为模型本身就是用来操作数据表的。

  • 2、模型代码创建规则
    先设置命名空间
    引入tp模型基类
    创建自定义的模型类并且要继承tp的模型基类
<?php
//设置命名空间
namespace Admin\Model;
//引入model基类
use Think\Model;
//创建自定义基类
class GoodsModel extends Model{

}
?>
2、配置tp与数据库的连接信息
  • 1、数据库配置项在tp的惯例配置文件/ThinkPHP/Conf/convention.php

以下配置信息是关于数据库的

/* 数据库设置 */
    'DB_TYPE'               =>  '',     // 数据库类型
    'DB_HOST'               =>  '', // 服务器地址
    'DB_NAME'               =>  '',          // 数据库名
    'DB_USER'               =>  '',      // 用户名
    'DB_PWD'                =>  '',          // 密码
    'DB_PORT'               =>  '',        // 端口
    'DB_PREFIX'             =>  '',    // 数据库表前缀
    'DB_PARAMS'          	=>  array(), // 数据库连接参数    
    'DB_DEBUG'  			=>  TRUE, // 数据库调试模式 开启后可以记录SQL日志
    'DB_FIELDS_CACHE'       =>  true,        // 启用字段缓存
    'DB_CHARSET'            =>  'utf8',      // 数据库编码默认采用utf8
    'DB_DEPLOY_TYPE'        =>  0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
    'DB_RW_SEPARATE'        =>  false,       // 数据库读写是否分离 主从式有效
    'DB_MASTER_NUM'         =>  1, // 读写分离后 主服务器数量
    'DB_SLAVE_NO'           =>  '', // 指定从服务器序号

2、修改自己模块下的config文件
修改配置文件在/Application/Common/Conf/config.php的相应选项

<?php
return array(
	//'配置项'=>'配置值'
/* 数据库设置 */
		'DB_TYPE' =>  'mysql',     // 数据库类型
		'DB_HOST' =>  '127.0.0.1', // 服务器地址
		'DB_NAME' =>  'shop',          // 数据库名
		'DB_USER' =>  'root',      // 用户名
		'DB_PWD'  =>  '********',          // 密码
		'DB_PORT'  =>  '3306',        // 端口
		'DB_PREFIX'=>  'shop_',    // 数据库表前缀
);

3、具体数据信息如下
数据库名:shop
数据表名:shop_goods
表结构
在这里插入图片描述

3、实例化模型对象
  • 1、常规的实例化方式

使用new关键字
Controller文件夹下IndexController.class.php文件

<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{
	public function test1(){
		//实例化的过程中要使用命名命名空间
		$model=new \Admin\Model\GoodsModel();
		//dump是tp内置的一个函数。作用就是查看某一个变量的数据,等价于echo var_dump($model)
		dump($model);

	}

}
?>
  • 2、使用tp内置的M函数实例化对象
    一般使用在需要直接使用原生sql语句的时候
    M函数有三个参数,可都传递或都不传递
    第一个参数:指定具体的某一个数据表,默认没有前缀
    第二个参数:指定具体的表前缀
    第三个参数,指定具体的mysql连接信息
public function test2(){
		//M函数有三个参数,可都传递或都不传递
		//第一个参数:指定具体的某一个数据表,默认没有前缀
		//第二个参数:指定具体的表前缀
		//第三个参数,指定具体的mysql连接信息
		$model=M();
		dump($model);

	}
  • 3、使用tp内置的D函数实例化对象
    使用D函数传递参数是,需要指定具体的自定义的模型的名称
    D函数可以跨模块执行,只需要指定具体的参数就可以,参数为“模块名称/模型名称”

当实例化某一个不存在的自定义模型,就会使用tp的模型积累进行实例化操作

public function test3(){

		$model=D('Goods');//参数是模型名称
		dump($model);

	}
  • 4、D函数和M函数的区别
    M永远实例化TP的模型的基类
    D会优先实例化自定义的模型类,如果自定义模型类不存在就会实例化tp模型基类

建议使用D函数实例化模型类

4、模型的curd(增删改查)操作

add,add(all)
delete
save
find,select

5、add数据的写入
  • 1、实例化模型对象

  • 2、拼接具体要写入的数据

    使用add数据写入,add是写入单条数据,所以需要使用一维数组格式(关联数组)。下标具体的字段名称

<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//拼接具体要写入的数据使用数组
		$data=array(
			'goods_name'=>'test4',
			'addtime'=>time(),
			'goods_body'=>'test44'
		);
		//具体实现添加
		$res=$model->add($data);
		dump($res);
	}
}
?>
6、addAll写入多条数据

创建一个二维数组,进行写入

<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//写入多条数据则使用二维数组,第一位下标要从0开始
		$data=array(
				array('goods_name'=>'test5',
						'addtime'=>time(),
						'goods_body'=>'test55'),
				array('goods_name'=>'test6',
						'addtime'=>time(),
						'goods_body'=>'test66')

		);
		//具体实现添加
		$res=$model->addAll($data);
		dump($res);
	}
}
?>
7、save修改所有数据
  • 1、首先需要一个模型对象
  • 2、指定需要修改的内容
    只需要需要修改内容的一维数组即可,需要指定条件进行更新
<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//写入多条数据则使用二维数组,第一位下标要从0开始
		$data=array(
			'id'=>'2',//执行修改id为6的数据
			'goods_name'=>'test666'

		);
		//具体实现添加
		$res=$model->save($data);
		dump($res);
	}
}
?>

当需要判断是否更新成功,需要使用返回值与false进行全等判断,如果全等判断成立说明目前修改失败,因为save返回一个逻辑值

8、setField只更新个别字段

setField()实现更新具体某一些字段对应的内容
两种使用方式

  • 1、第一种方法修改多个字段,直接个setField传递一个参数,需要一个一维数组,下标为字段名称,具体的值就是每一个字段对应要修改的内容
<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//执行查询
		$res=$model->where("id=3")->setField(array('goods_name'=>test999,'goods_body'=>'body666'));
		dump($res);
	}
}
?>
  • 2、第二种方法修改单个字段,对第一个参数指定具体的某一个字段名称,第二个字段对应字段所需要修改的内容
<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//执行查询
		$res=$model->where("id=1")->setField('goods_name','tp999');
		dump($res);
	}
}
?>
9、setInc,setDec字段值增减操作

setInc:指定将某一个字段的值进行增加操作
setDec:指定将某一个字段的值进行减少操作

两个参数,
第一个参数是指定具体的字段名称
第二个参数指定增减的具体值,如果不指定则增减1

  • 1、实例化模型对象
  • 2、通过模型来操作修改
<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//执行查询
		$model->where("id=6")->setInc('addtime');
		//第二个参数指定了减少的具体值
		$model->where("id=4")->setDec('addtime',100);

	}
}
?>
10、连贯操作(链式)修改操作中的where方法

当模型调用where方法,tp会根据where中的具体内容设置条件,返回具体的模型对象,再去调用save方法
where方法可以配合查询、删除等操作
对于where指定具体的条件使用方式比较多,经常使用的是数组格式来指定具体的条件,第二种方式是使用原生sql语句来指定

<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//写入多条数据则使用二维数组,第一位下标要从0开始
		$data=array(
			'goods_name'=>'test88888'

		);
		//具体实现添加
		$res=$model->where("goods_name='test4'")->save($data);
		dump($res);
	}
}
?>
11、单条数据查询-find

find:作用实现获取一条数据,返回的数据格式是一维数组
select:作用实现获取多条数据,返回的数据格式是二维数组
1、先获取模型对象
2、通过模型对象来执行查找

<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//执行查询
		$data=$model->where("id=6")->find();
		dump($data);
	}
}
?>

返回
array(5) {
[“id”] => string(1) “6”
[“goods_name”] => string(6) “test55”
[“goods_img”] => string(8) "default "
[“addtime”] => string(10) “1609226494”
[“goods_body”] => string(6) “test66”
}

12、多条数据查询-select

select:作用实现获取多条数据,返回的数据格式是二维数组

  • 1、先获取模型对象
  • 2、通过模型对象来执行查找
<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//执行查询
		$data=$model->where("goods_name='test5'")->select();
		dump($data);
	}
}
?>

结果:
array(2) {
[0] => array(5) {
[“id”] => string(1) “2”
[“goods_name”] => string(5) “test5”
[“goods_img”] => string(8) "default "
[“addtime”] => string(10) “1609226203”
[“goods_body”] => NULL
}
[1] => array(5) {
[“id”] => string(1) “6”
[“goods_name”] => string(5) “test5”
[“goods_img”] => string(8) "default "
[“addtime”] => string(10) “1609226494”
[“goods_body”] => string(6) “test66”
}
}

13、delete数据删除
  • 1、先获取模型对象
  • 2、通过模型对象来执行删除
    使用delete进行删除非常危险,tp为了安全不会正常地执行删除操作
 <?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//执行查询
		$res=$model->where("id=5")->delete();
		dump($res);
	}
}
?>

PS:可以通过对象调用getlastSql()方法到最后所执行的sql语句

<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//执行查询
		$res=$model->where("id=5")->delete();
		$str=$model->getLastSql();
		echo $str;
		dump($res);
	}
}
?>
14、数据表字段的缓存

当直接使用$model->sage( $data)时必须要指定修改数据的主键才可以修改,tp为什么能知道具体哪一个字段是主键呢,因为:
每次实例化模型对象,tp都会分析对应数据表的字段信息,因此就可以知道具体哪一个才是主键字段

字段缓存就是将字段信息存储到某个文件中,下次实例化会直接读取文件的信息,不会再去分析具体的数据表的结果

15、开启字段缓存功能
  • 1、关闭调试模式
define(‘APP_DEBUG’,false);
  • 2、查看第一次访问的效果
  • 3、再次访问

具体缓存文件在哪呢

Application\Runtime\Data\_fields\shop.shop_goods.php
16、数据表字段定义

在自定义的模型中将具体的字段信息保存到某一个具体的属性中(固定的属性名称)。本质也是将具体的字段信息保存到变量中。变量会载入到内存。对于内存的速度比磁盘的速度要更加快,因此使用字段定义功能比字段缓存效果更加高。

  • 1、修改模型

·实现字段的定义,需要将每一个字段都写入到对应的数组中,每一个字段就是一个具体的元素
·注意每一个字段都需要写入进去,如果缺少某一个字段,在进行数据交互时,缺少的对应字段就不能正常的进行交互

<?php
//设置命名空间
namespace Admin\Model;
//引入model基类
use Think\Model;
//创建自定义基类
class GoodsModel extends Model{
	//通过属性指定具体的主键字段信息
	protected $pk='id';//默认为id,如果主键是id,则可以不写

	//实现字段的定义,需要将每一个字段都写入到对应的数组中,每一个字段就是一个具体的元素
	//注意每一个字段都需要写入进去,如果缺少某一个字段,在进行数据交互时,缺少的对应字段就不能正常的进行交互
	protected $field=array('id','goods_name','goods_img','addtime','goods_body');
}
?>
17、数据创建

就是使用模型对象调用create方法来自动的接受提交的数据内容,并且对内容进行过滤操作(根据数据表的结构信息)
create的功能非常多,如自动验证等

  • 1、修改商品的添加模板

Application\Admin\View\Goods\add.html
下面的pic图片地址命名故意命名错,为了将来使用字段映射,实际应该为goods_img

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
</head>

<body>
	<form action="" method="post">
		<div><label>商品名称</label><input name="goods_name" type="text"/></div>
		<div><label>图片地址</label><input name="pic" type="text" value="http://www.mycodes.net"/></div>
		<div><label>内容</label><textarea name="goods_body"  cols="" rows=""></textarea></div>
		<div><input name="" type="submit" value="提交"/></div>
	</form>
</body>
</html>

页面效果
在这里插入图片描述

  • 2、同时设置了Admin模块下的Goods控制器
    可以根据不同的请求方式进行反应
    IS_GET:判断当前请求是否是get方式。如果get,值为真
    IS_POST:判断当前请求是否是post方式。如果post,值为真
    IS_AJAX:判断当前请求是否是ajaxt方式。如果是ajax,值为真
<?php
namespace Admin\Controller;
use Think\Controller;

class GoodsController extends Controller{

	public function test1(){
		//需要add能够实现显示具体的表单及实现处理表单的提交
		//可以根据不同的请求方式进行反应
		if (IS_GET) {
			$this->display('add');
		}else{
			//post表单的提交
			//创建模型对象
			$model=D("Goods");
			$data=$model->create();
			dump($data);
		}
	}

}
?>

这里由于pic不是数据库对应的字段自然地被过滤掉了

  • 3、目录结构是

在这里插入图片描述

18、字段映射

为了在表单中隐藏真实字段名称,可以使用假名,但是为了确保使用假名后也能够使用数据的创建功能,可以在自定义的模型中通过某一个属性(有固定的名称)指定具体的假名与真名的对应关系。这就是字段映射。

  • 1、修改模型编辑映射

实现字段的映射功能,对应的是数组格式(关联数组),在数组格式中体现出假名与真名的对应关系。
要求对每个元素的下标表示假名,具体的内容就是真实名称
Application\Admin\Model\GoodsModel.class.php

<?php
//设置命名空间
namespace Admin\Model;
//引入model基类
use Think\Model;
//创建自定义基类
class GoodsModel extends Model{

	//实现字段的映射功能,对应的是数组格式,在数组格式中体现出假名与真名的对应关系
	protected $_map=array(
		'name'=>'goods_name',
		'pic'=>'goods_img',
		'body'=>'goods_body'
	);
}
?>
  • 2、修改模型增加属性(假名)
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
</head>

<body>
	<form action="" method="post">
		<div><label>商品名称</label><input name="name" type="text"/></div>
		<div><label>图片地址</label><input name="pic" type="text" value="http://www.mycodes.net"/></div>
		<div><label>内容</label><textarea name="body"  cols="" rows=""></textarea></div>
		<div><input name="" type="submit" value="提交"/></div>
	</form>
</body>
</html>
  • 3、查看效果
    array(3) {
    [“goods_name”] => string(9) “张三丰”
    [“goods_img”] => string(22) “http://www.mycodes.net”
    [“goods_body”] => string(12) “武当奇侠”
    }
19、自动验证

在使用create创建数据时自动对提交的具体内容进行合法性校验操作
数据校验有两种方式
1、静态方式:在模型类里面通过 $validate属性 定义验证规则
2、动态方式:使用模型类的validate方法动态创建自动验证规则。

无论什么方式,验证规则的定义的统一规则,定义格式为:

arrayarray(验证字段1,验证规则,错误提示[验证条件,附加规则,验证时间],
	array(验证字段1,验证规则,错误提示[验证条件,附加规则,验证时间],

验证字段:需要在表单验证的字段名称,可以是数据表中的字段名称,也可以使是表单中的辅助字段名称,如验证码(作为辅助字段)

验证规则:当附加规则指定使用哪一种方式方式进行验证,验证规则会在附加规则的基础上再次指定具体使用的规则,
·当使用附加规则为regex时,验证规则可以写上具体的正则表达式。
·当使用附加规则为function时,验证规则可以写上具体的函数名称(php内置函数名称、tp公共的函数名称,自定义的公共函数名称。)
·当附加规则为callback,验证规则可以协商具体当前模型类下的具体某一个方法的名称

错误提示:验证不通过时,给用户的提示语

验证条件:控制当前的验证规则是否执行,self::EXISTS_VALIDATE的取值为0,1,2

附加规则:指定当前的验证规则使用哪一种方式进行验证。

验证时间:控制当前的验证规则具体什么时间生效:
self:MODEL_INSERT或1:新增数据时验证
self:MODEL_UPDATE或2:编辑数据时验证
self:MODEL_BOTH或3:全部情况下验证

20、自动验证案例
  • 1、修改商品添加模板

增加了商品价格输入框

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
</head>

<body>
	<form action="" method="post">
		<div><label>商品名称</label><input name="name" type="text"/></div>
		<div><label>商品价格</label><input name="goods_price" type="text"/></div>
		<div><label>图片地址</label><input name="pic" type="text" value="http://www.mycodes.net"/></div>
		<div><label>内容</label><textarea name="body"  cols="" rows=""></textarea></div>
		<div><input name="" type="submit" value="提交"/></div>
	</form>
</body>
</html>
  • 2、修改商品模型(因为增加了商品价格字段)
<?php
//设置命名空间
namespace Admin\Model;
//引入model基类
use Think\Model;
//创建自定义基类
class GoodsModel extends Model{
	//实现字段的映射功能,对应的是数组格式,在数组格式中体现出假名与真名的对应关系
	protected $_map=array(
		'name'=>'goods_name',
		'pic'=>'goods_img',
		'body'=>'goods_body'
	);
	//增加属性,指定具体的自动验证规则
	protected $_validate=array(
		array('goods_name','checkName','goods_name error',1,'callback',3),
		array('goods_price','check_Price','goods_price error',1,'function',3),
		array('goods_body','check_Price','goods_body error',1,'regex',3),
	);
}
?>
  • 3、修改商品模型在,增加验证方法
<?php
//设置命名空间
namespace Admin\Model;
//引入model基类
use Think\Model;
//创建自定义基类
class GoodsModel extends Model{

	//实现字段的映射功能,对应的是数组格式,在数组格式中体现出假名与真名的对应关系
	protected $_map=array(
		'name'=>'goods_name',
		'pic'=>'goods_img',
		'body'=>'goods_body'
	);
	//增加属性,指定具体的自动验证规则
	protected $_validate=array(
		array('goods_name','check_Name','goods_name error',1,'callback',3),
		array('goods_price','check_Price','goods_price error',1,'function',3),
		array('goods_body','require','goods_body error',1,'regex',3),
	);

	//检查商品名称是否满足格式要求
	public function check_Name($goods_name){
		//根据商品名称的长度判断,大于3就不满足格式要求
		if(mb_strlen($goods_name,'utf-8')>3){
			return false;
		}
		return true;

	}
}
?>
  • 4、增加项目的公共函数
    需要在Application\Common\Common\创建一个function.php
    定义项目使用的公共函数,对于此文件下的函数会自动载入到项目
<?php
//定义项目使用的公共函数,对于此文件下的函数会自动载入到项目
//检查当前提交的商品价格是否满足格式要求
function check_Price($goods_price){
    if($goods_price<=0){
        return false;
    }
    return true;
}

?>
  • 5、在入口文件中开启调试模式
  • 6、修改控制器的test方法进行显示
 <?php
namespace Admin\Controller;
use Think\Controller;

class GoodsController extends Controller{

	public function test1(){
		//需要add能够实现显示具体的表单及实现处理表单的提交
		//可以根据不同的请求方式进行反应
		if (IS_GET) {
			$this->display('add');
		}else{
			//post表单的提交
			//创建模型对象
			$model=D("Goods");
			$data=$model->create();
			if(!$data){
				//说明目前有数据格式不满足要求
				//$model->getError能够获取具体的错误信息
				dump($model->getError());
			}
			dump($data);
		}
	}

}
?>

最终
在这里插入图片描述
在这里插入图片描述

21、自动完成

在使用create创建数据是tp会自动对接受的内容进行增加或者修改的操作
自动完成的使用场景

  • 1、部分字段在表单中没有体现出来(不需要用户进行录入操作,),但是对于这些字段在数据的添加或者是修改时,又需要将具体对应的内容写入到数据库中
  • 2、使用create方法创建数据后,可能部分数据在格式上不满足要求,就需要将具体的内容转换格式之后再写入到数据库

自动完成的使用方式

  • 1、静态方式:在模型类里通过 $_auto属性定义处理规则
  • 2、动态方式:使用模型类的auto方法动态创建自动处理规则
    array(
    array(完成字段1,完成规则,[完成条件,附加规则]),
    array(完成字段2,完成规则,[完成条件,附加规则]),

完成字段:
完成规则:

完成条件:
self:MODEL_INSERT或1:新增数据时验证
self:MODEL_UPDATE或2:编辑数据时验证
self:MODEL_BOTH或3:全部情况下验证

附加规则:主要是function和callback

22、自动完成案例

修改GoodsController.class.php文件

<?php
namespace Admin\Controller;
use Think\Controller;

class GoodsController extends Controller{

	public function test1(){
		//需要add能够实现显示具体的表单及实现处理表单的提交
		//可以根据不同的请求方式进行反应
		if (IS_GET) {
			$this->display('add');
		}else{
			//post表单的提交
			//创建模型对象
			$model=D("Goods");
			//使用动态方式完成表单,定义具体自动完成规则
			$auto=array(
				array('addtime','time',1,'function')
			);

			$data=$model->auto($auto)->create();
			if(!$data){
				//说明目前有数据格式不满足要求
				//$model->getError能够获取具体的错误信息
				dump($model->getError());
			}
			dump($data);

			
		}
	}

}
?>

添加数据时显示:
在这里插入图片描述

23、统计查询方法
  • 1、查看统计查询的方法
    Count:
    Max:
    Min:
    Avg:
    Sum:
24、统计查询方法-Count

1、创建一个控制器方法
修改呢Application\Admin\Controller\IndexController.class.php

<?php
namespace  Admin\Controller;
use Think\Controller;

class IndexController extends Controller{

	public function test1(){
		//实例化模型对象
		$model=D('Goods');
		//计算当前数据的总行数
		echo $model->count();
		echo '<hr>';
		//计算id中的最大值
		echo $model->max('id');
		echo '<hr>';
		//计算所有数据id的总和
		echo $model->sum('id');
		echo '<hr>';
		//使用where指定具体的条件进行统计查询
		echo $model->where("goods_name='test999'")->sum('id');

		$this->display(news);

	}
}
?>

结果为:
在这里插入图片描述

25、开启tp开发者工具

修改Application\common\config\config.php

//开启tp的开发者工具
		'SHOW_PAGE_TRACE'=>true,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值