json

 

JSON

作为JSON处理(JSON-P)的Java API,JSR-353已经到达了最终的批准投票阶段。JSON-P(类似于JAXP)由一个流API(类似于StAX)和一个对象模型API(类似于DOM)组成。它的参考实现是jsonp,目前正处在测试阶段,它基于CDDL v1.1 GPL v2 协议开放源码。JSON-P将作为即将发布的Java EE 7的一部分,同时JAX-RS会使用它作为默认的JSON实现。请注意,该API并没有包含JSON数据绑定(类似于JAXB),同时它和更流行的JSONP(JSON with padding)并没有关系。

JSON(JavaScript对象标记)是一个轻量级数据交换格式,被广泛用于Web应用程序、REST服务和NoSQL数据库。随着JSON的流行以及Java平台上诸多JSON类库(org.json、Jackson及google-gson等)的出现,现在已经到了需要对开发者创建并使用JSON的方式进行标准化的阶段。JSON-P就是即将到来的标准,它能够被独立地使用,或者作为Java EE 7容器的一部分。

JSON-P分为两个API,流API(javax.json.stream)和对象模型API(javax.json)。流API是一种底层且高效的解析和生成JSON的方式。它由两个主要的抽象构成——JsonParser和JsonGenerator。JsonParser是一个拉模式解析器,允许以向前、只读的方式访问JSON输入源。JsonGenerator则提供了向流中写入JSON的方法,并且允许使用方法链。Generator输出JSON对象中的名/值对以及JSON数组中的值。

下面是JsonParser和JsonGenerator的代码示例。首先是我们将会读取或者创建的JSON数据。

[

{ "type" : "home", "number" : "(800)111-1111" },

{ "type" : "cell","number" : "(800) 222-2222" }

]

下面是JsonParser示例,示例的底部是它的输出。

JsonParserFactory factory =Json.createParserFactory(null);

JsonParser parser = factory.createParser(newStringReader(json));

while (parser.hasNext()) {

  Eventevent = parser.next();

 switch (event) {

   case KEY_NAME: {

     System.out.print(parser.getString() + "="); break;

    }

   case VALUE_STRING: {

     System.out.println(parser.getString()); break;

    }

  }

}

type=home

number=(800) 111-1111

type=cell

number=(800) 222-2222

下面是JsonGenerator的示例,它向System.out中打印JSON。

JsonGeneratorFactory factory =Json.createGeneratorFactory(null);

JsonGenerator generator =factory.createGenerator(System.out);

generator.writeStartArray().

 writeStartObject().

   write("type", "home").

   write("number", "(800) 111-1111").writeEnd().

 writeStartObject().

    write("type","cell").

   write("number", "(800) 222-2222").writeEnd().

 writeEnd().close();

 

第二部分是对象模型API,一个简单易用的高层API,它基于流API实现。它创建了一个类似于树的结构代表内存中的JSON数据,能够非常容易地进行操纵和查询。对象模型API中最主要的抽象是JsonObject和JsonArray,这两部分都是不可变的。JsonObject提供了一个Map视图,用于访问模型中未被排序的名/值对集合。JsonArray提供了一个列表视图访问排序的值序列。为了创建这些对象模型,你可以使用构建者模式(JsonObjectBuilder和JsonArrayBuilder)或者使用JsonReader从一个输入源(InputStream或者Reader)中读取它们。然后你可以使用JsonWriter将这些对象模型写入一个输出源(OutputStream或者Writer)。

下面是使用JsonArrayBuilder创建JsonArray的示例。需要再次提醒的是,我们使用的依然是上面的JSON数据。

JsonBuilderFactory factory =Json.createBuilderFactory(null);

JsonArray jsonArray =factory.createArrayBuilder()

   .add(factory.createObjectBuilder().

       add("type", "home").

       add("number", "(800) 111-1111"))

   .add(factory.createObjectBuilder().

       add("type", "cell").

       add("number", "(800) 222-2222")).build();

下面是JSONReader示例。

try (JsonReader jsonReader =Json.createReader(new StringReader(json))) {

 JsonArray array = jsonReader.readArray();

 System.out.println(array);

}

下面是JsonWriter示例。

try (JsonWriter jsonWriter =Json.createWriter(System.out)) {

 jsonWriter.writeArray(jsonArray);

}

如果你想尝试这个测试版本,那么可以下载jsonp,或者使用javax.json:javax.json-api:1.0-b06 和org.glassfish:javax.json:1.0-b06Maven 产品。你需要使用Java SE 6或者更高版本。如果想要获取更多信息,可以访问官方网站提供的JSON处理的Java API ,或者阅读JSON处理的Javadocs。你还可以通过YouTube观看JavaOne提供的JSON处理的Java API呈现

 

 

 

 

使用JSON的方法

 

JSON 即 JavaScript Object Natation,它是一种轻量级的数据交换格式,非常适合于服务器与 JavaScript 的交互。本文将快速讲解 JSON 格式,并通过代码示例演示如何分别在客户端和服务器端进行 JSON 格式数据的处理。

 

Json必需的包

commons-httpclient-3.1.jar
commons-lang-2.4.jar
commons-logging-1.1.1.jar
json-lib-2.2.3-jdk13.jar
ezmorph-1.0.6.jar
commons-collections-3.2.1.jar

 

出现java.lang.NoClassDefFoundError: net/sf/ezmorph/Morpher错误是因为没有导入ezmorph.jar文件或版本不对。

出现java.lang.NoClassDefFoundError:org/apache/commons/collections/map/ListOrderedMap错误是因为没有导入commons-collections.jar文件或版本不对。

 

Java代码转换成json代码

 

1.      List集合转换成json代码

List list = new ArrayList();

list.add( "first" );

list.add( "second" );

JSONArray jsonArray2 = JSONArray.fromObject( list );

 

2.      Map集合转换成json代码

Map map = new HashMap();

map.put("name", "json");

map.put("bool", Boolean.TRUE);

map.put("int", new Integer(1));

map.put("arr", new String[] { "a", "b" });

map.put("func", "function(i){ return this.arr[i]; }");

JSONObject json = JSONObject.fromObject(map);

 

3.      Bean转换成json代码

JSONObject jsonObject = JSONObject.fromObject(new JsonBean());

 

4.      数组转换成json代码

boolean[] boolArray = new boolean[] { true, false, true };

JSONArray jsonArray1 = JSONArray.fromObject(boolArray);

 

 

 

5. 一般数据转换成json代码

JSONArray jsonArray3 = JSONArray.fromObject("['json','is','easy']" );

 

6.      beans转换成json代码

List list = new ArrayList();

JsonBean2 jb1 = new JsonBean2();

jb1.setCol(1);

jb1.setRow(1);

jb1.setValue("xx");

JsonBean2 jb2 = new JsonBean2();

jb2.setCol(2);

jb2.setRow(2);

jb2.setValue("");

list.add(jb1);

list.add(jb2);

JSONArray ja = JSONArray.fromObject(list);

 

 

看了JSON的处理,对应存在特殊字符比如""的,怎么处理的?


用 \ 转义

关于 JSON 的Java库, Nutz 的 Json 解析器就非常好:

Java转换成Json:

Java代码

1.    Map<String,Object> map = new HashMap<String, Object>();  

2.    map.put("name", "Peter");  

3.    map.put("age", 21);   

4.    map.put("friends", null);  

5.    String result = Json.toJson(map);  

Map<String,Object> map = new HashMap<String, Object>();

map.put("name", "Peter");

map.put("age", 21);

map.put("friends", null);

String result = Json.toJson(map);


这个时候会输出成:

Json代码

1.    {   

2.      age :21,   

3.      name :"Peter"  

4.    }  

{

  age :21,

  name :"Peter"

}


会自动忽略掉值为空的字段.

Json转换成Java:

Java代码

1.    String json = "{age :21,name :\"Peter\"}";  

2.    map = Json.fromJson(HashMap.class, Lang.inr(json));  

String json = "{age :21,name :\"Peter\"}";

map = Json.fromJson(HashMap.class, Lang.inr(json));



可以支持行注释,块注释, Json.fromJson(Class<T> type, Reader) 可以直接生成一个 Java 对象

我也是在用JSON,但不是像这样的动态生成js脚本,而是为了处理大批表格数据的读取问题,用struts(1.2)的action来生成json字符串,再用response.getWriter().write()输出到页面,ExtJS自然就是用Ext.data.JsonStore来读取了。这种方式的效率比较高,也达到了代码分离的目的,逻辑层和数据访问层根本无需暴露在web上,页面虽然是jsp,也无需使用<%%>或者struts标签。欢迎交流~

我先贴部分代码上来和大家交流一下,目前处于开发初期阶段,稍后我才做一个sample放上来。

Java代码

1.    /**  

2.     * 向浏览器输出JSON字符串  

3.     * @param response HttpServletResponse对象 

4.     * @param obj 任意对象,可以是List,也可以是单个对象  

5.     */  

6.    public void writeJsonString(HttpServletResponse response, Object obj) throws IOException {  

7.        if( obj == null ) {  

8.            this.exception = "obj参数为空";  

9.            logger.error(this.exception);  

10.         throw new NullPointerException(this.exception);  

11.     }  

12.       

13.     JSONArray array = JSONArray.fromObject(obj);  

14.       

15.     try {  

16.         String json = array.toString();  

17.         if( json.startsWith("[") ) {  

18.             json = json.substring(1);   

19.         }  

20.         if( json.endsWith("]") ) {  

21.             json = json.substring(0, json.length()-1);  

22.         }  

23.         response.setCharacterEncoding("utf-8");  

24.         response.getWriter().write(json);  

25.     } catch (IOException e) {  

26.         this.exception = "向浏览器输出JSON字符串时发生错误";   

27.         logger.error(this.exception);  

28.         logger.error(e);  

29.         throw new IOException(this.exception);  

30.     }  

31. }  

/**

 * 向浏览器输出JSON字符串

 * @param responseHttpServletResponse对象

 * @param obj 任意对象,可以是List,也可以是单个对象

 */

public void writeJsonString(HttpServletResponse response, Object obj)throws IOException {

  if( obj == null ) {

    this.exception= "obj参数为空";

    logger.error(this.exception);

    thrownew NullPointerException(this.exception);

  }

 

  JSONArray array = JSONArray.fromObject(obj);

 

  try {

    Stringjson = array.toString();

    if(json.startsWith("[") ) {

      json = json.substring(1);

    }

    if(json.endsWith("]") ) {

      json = json.substring(0, json.length()-1);

    }

    response.setCharacterEncoding("utf-8");

    response.getWriter().write(json);

  } catch (IOException e) {

    this.exception= "向浏览器输出JSON字符串时发生错误";

    logger.error(this.exception);

    logger.error(e);

    thrownew IOException(this.exception);

  }

}



这里是js部分

Java代码

1.    var store = new Ext.data.JsonStore({  

2.        url: '../demo.do', //请大家根据实际情况修改action路径   

3.        root: 'data', //传回来的JSON字符串是HashMap生成的,data对应具体的数据集,一般是List对象   

4.        totalProperty: 'totalCount', //总记录数,整型  

5.        id: 'id',  

6.        fields: ['title', 'state', {name:'createDate', type: 'date'}, 'author', {name:'id', type:'int'}]  

7.    });   

8.    store.setDefaultSort('id', 'asc');  

9.    store.load({params:{start:0, limit:25}}); //传两个URL参数做分页处理  

var store = new Ext.data.JsonStore({

  url: '../demo.do', //请大家根据实际情况修改action路径

  root: 'data', //传回来的JSON字符串是HashMap生成的,data对应具体的数据集,一般是List对象

  totalProperty: 'totalCount', //总记录数,整型

  id: 'id',

  fields: ['title', 'state',{name:'createDate', type: 'date'}, 'author', {name:'id', type:'int'}]

});

store.setDefaultSort('id', 'asc');

store.load({params:{start:0, limit:25}}); //传两个URL参数做分页处理



还需要说明的是:需要json-lib-2.1-jdk15.jar, ezmorph-1.0.3.jar,到附件中取。

 

 

在学习JSON之前,当我在写大量JSP页面的时候,产生动态数据一般采用两种途径:
1.直接在页面中写java代码
2 采用各种标签代替
   这两种用法的支持者都很多,但是我发现就算是采用标签也好,对于页面的重用还是无能为力,比如有几个页面都需要用到一个item数据,一个是管理用户页面,一个是订单页面。我们既要在管理用户的servlet写上setAttribute('item',item),也要在管理订单的servlet写上setAttribute('item',item);然后在页面上通过getAttribute()获得数据:

Java代码

1.    <%for(int i=0;i<item.length;++i){%>   

2.        html tag ...  

3.    <%}%>  

  <%for(inti=0;i<item.length;++i){%>

      html tag ...

  <%}%>


或者采用标签的形式:

Java代码

1.    <ww:iterator value="item">  

2.        html tag...  

3.    <ww:iterator>  

  <ww:iterator value="item">

      html tag...

  <ww:iterator>


   很多时候我们会采用 <jsp:inclue page="common.jsp"/>来重用这样的页面,但这里有个问题,如果多个的页面样式不一样呢?如果数据不是很多呢,这样会产生很多页面碎片,实践已经证明,重用页面并不是一个好办法.

   有时候我想,如果我能单独用一个action来提供输出数据,每个需要这些数据的页面页面都去获取这些数据,关于这些数据在页面如何渲染是页面的问题,这个action只提供数据,这样我们重用数据不是比重用页面好很多么?

   但是之前的技术并不能支撑这样的实现,一个页面如何自己主动去访问它需要的数据呢?

   答案是当然是通过AJAX技术.但今天我介绍的是另外一种技术JSON.

   先简单的介绍一下JSON(虽然很多人已经知道),JSON JavaScirp Object Notion 可以看成一段javascript对象树,比如 user.id 表示的是user对象的id,如果对webwork或则是srtus2.0熟悉的朋友应该对此并不陌生,对象树可以嵌套对象,比如user.cat.age 表示user对象的成员cat的年龄。除了对象还可以嵌套数组方法user.cat[0].sayHello();
  我们这样声明一个JSON:

Java代码

1.    var user = { id:’1’, name:’sanyun’};      

2.    alert(user.id)  //输出1  

3.    user = { id:’1’, cat:{age:2,color:’white’ }};   

4.    alert(user.cat.age) //输出2  

var user = { id:’1’,name:’sanyun’}; 

alert(user.id)  //输出1

user = { id:’1’,cat:{age:2,color:’white’ }};

alert(user.cat.age)  //输出2



  但是JSON本身是不能和后端通信的,不过我们可以通过

Java代码

1.    <script type="text/javascript" src="后端资源"> </script>  

<script type="text/javascript" src="后端资源"> </script>


来和服务器后端通信.
我们可以把它封装成一个方法:

Java代码

1.    function CallBack(model) {  

2.        this.model = model;  

3.    }   

4.    CallBack.init = function (url) {  

5.        var headElement = document.getElementsByTagName("head").item(0);   

6.        var scriptTag = document.createElement("script");  

7.        scriptTag.setAttribute("type", "text/javascript");  

8.        scriptTag.setAttribute("src", url);  

9.        headElement.appendChild(scriptTag);  

10. };  

function CallBack(model) {

    this.model = model;

}

CallBack.init = function (url) {

    var headElement =document.getElementsByTagName("head").item(0);

    var scriptTag =document.createElement("script");

   scriptTag.setAttribute("type", "text/javascript");

   scriptTag.setAttribute("src", url);

   headElement.appendChild(scriptTag);

};


   不过需要注意的是采用这种方式后台MIME必须要设置为 html/Javascritp,当然你也可以轻松把这种方式替换成Ajax.
解析
  通信之后我们需要做的是解析数据,一般来说,我们可以通过for in 简单的遍列JSON

Java代码

1.       //model表示后端产生的JSON  

2.    CallBack.update(model){  

3.      for(i in model){  

4.         var node =document.getElementByID(i);  

5.         if(node){  

6.           node.value = model[i];  

7.         }  

8.      }  

9.    }  

   //model表示后端产生的JSON

CallBack.update(model){

  for(i in model){

     var node=document.getElementByID(i);

     if(node){

       node.value = model[i];

     }

  }

}


后台

Java代码

1.    public class ShowType extends HttpServlet {  

2.          

3.       protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  

4.          

5.       response.addHeader("Cache-Control", "no-cache");  //(1)  

6.       response.setContentType("HTML/JavaScript;charset=GBK");//(2)  

7.       PrintWriter out = response.getWriter();  

8.       String json = ” {name:'jiangyunpeng', status:'1',sex:'female'}  ”//(3)   

9.       out.print("CallBack.update("+json+")"); //(4)  

10.   }       

11. }  

public class ShowType extends HttpServlet {

   

   protected voiddoGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException {

 

  response.addHeader("Cache-Control","no-cache");  //(1)

  response.setContentType("HTML/JavaScript;charset=GBK");//(2)

   PrintWriter out =response.getWriter();

   String json = ” {name:'jiangyunpeng', status:'1',sex:'female'}  ”//(3)

  out.print("CallBack.update("+json+")"); //(4)

  }  

}


(1)首先需要设置缓存为空
(2)然后MIME必须要设置为 html/Javascritp
(3)产生一段JSON,这里我们是手动产生的,可以采用JSON开源框架
(4)调用我们前面页面定义的JS函数
通过这样处理了之后我们的页面再也没有任何JAVA代码或者自定义标签了,他完全是一个HTML页面(当然这里为了演示,把解析JSON过程过于简单化了),他具有这些好处:
1.它是一个HTML,响应速度比JSP快
2.对于一些表单元素,比如checkbox,select,如果采用java代码会很繁琐,

Java代码

1.     function initCheckbox(){  

2.       if('<%=status%>'==1){  //这里有JAVA代码  

3.          document.getElementById('checkbox').checked = true;  

4.       }else{  

5.          document.getElementById('checkbox').checked = fasle;  

6.        }  

7.    }  

   function initCheckbox(){

    if('<%=status%>'==1){  //这里有JAVA代码

       document.getElementById('checkbox').checked = true;

     }else{

       document.getElementById('checkbox').checked = fasle;

      }

  }


但是如果采用JSON的话

Java代码

1.    function initCheckbox(){  

2.       if(status==1){      //这里只有JSON  

3.          document.getElementById('checkbox').checked = true;  

4.       }else{  

5.          document.getElementById('checkbox').checked = fasle;  

6.        }  

7.    }  

  function initCheckbox(){

     if(status==1){      //这里只有JSON

       document.getElementById('checkbox').checked = true;

     }else{

        document.getElementById('checkbox').checked= fasle;

      }

  }


  我们可以把这段代码放在解析方法里面,判断查询的对象如果是checkbox,就像上面这样处理,这样我们就可以更本不用关心它是否是checkbox
3.重用了数据.多个页面可以通过JSON访问相同的数据,这里没有setAttribute(),也不用考虑生命周期。
4.降低了服务器端的负载。因为我们把解析的数据任务放在客户端里面进行,服务器只需要产生一些JSON字符串。
5.分离了JAVA代码和JS,诸如验证,判断,很多时候在javascript里面嵌套java,可读性很差。
JQURY JSON

JQuery处理json与ajax返回JSON实例

 

[导读] json数据是一种经型的实时数据交互的数据存储方法,使用到最多的应该是ajax与json配合使用了,下面我来给大家介绍jquery处理json数据方法。 一、JSON的一些基础知识。JSON中对象通过{}来标识,一个{}代表一个对象

json数据是一种经型的实时数据交互的数据存储方法,使用到最多的应该是ajax与json配合使用了,下面我来给大家介绍jquery处理json数据方法。

一、JSON的一些基础知识。

JSON中对象通过“{}”来标识,一个“{}”代表一个对象,如{“AreaId”:”123”},对象的值是键值对的形式(key:value)。

 “[]”,标识数组,数组内部各个数据之间通过“,”分割,如[“AreaId”:”123”,”AreaId”:”345”]。

很多情况下是对象数组,那就是这样:

 代码如下

复制代码

[{“AreaId”:”123”},{“AreaId”:”345”}]

 其实数组也是一个对象,上面的格式也可以写成这样:

 代码如下

复制代码

{“Area”:[{“AreaId”:”123”},{“AreaId”:”345”}]}

这表示一个Area对象,他有两个子数据,每个子数据也是一个对象,每个子对象都是AreaId。

 JSON中字符串和字符的定义格式和一般的类C语言定义是类似的,双引号定义字符串,单引号定义字符。

JSON的键(Key)用双引号括起来,比如上面的“Area“和”AreaId“,都是用双引号括起来的,在一些语言中构造JSON字符串的时候,可以使用转义字符转义双引号。

 二、javascript操作JSON字符

1、先要区分JSON字符串和JSON对象

JSON字符串:

 代码如下

复制代码

Var strJSON = “{“Area”:[{“AreaId”:”123”},{“AreaId”:”345”}]}”,

其实也可以写成这样:

 代码如下

复制代码

Var strJSON = ‘{“Area”:[{“AreaId”:”123”},{“AreaId”:”345”}]}’,

这表示一个JSON字符串,由于在Js中单引号和双引号都可以表示一个字符串,所以上面第一个使用双引号和第二个使用单引号的都表示一个JSON字符串。

下面看看JSON对象

 代码如下

复制代码

Var JSON = {“Area”:[{“AreaId”:”123”},{“AreaId”:”345”}]},

看到了吧,JSON对象最外面是没有单引号或者双引号的,这就表示一个JSON对象。


在服务器断的脚本:

 代码如下

复制代码

<?php
$data['id'] = 1;
$dat['name'] = "mary";
$da['red']= array_merge($data,$dat);
$data1['id'] = 2;
$dat1['name'] = "燕子";
$da['blue']= array_merge($data1,$dat1);
print_r($da);///打印出来是一个二维数组(如下)

/*
Array
(
    [red] => Array
        (
            [id] => 1
            [name] => mary
        )
    [blue] => Array
        (
            [id] => 2
            [name] => 燕子
        )
)
*/

echo json_encode($da);//输出的是一个转化成json格式的字符串,可以直接在js中用(如下)
/*
{"red":{"id":1,"name":"mary"},"blue":{"id":2,"name":"u71d5u5b50"}}
*/
?>

jquery脚本:

返回到js后的处理:
第一种要用到varl转化的:是字符串的时候就要用eval转化成jquery对象(如下)

 代码如下

复制代码

var arr = '{"red":{"id":1,"name":"mary"},"blue":{"id":2,"name":"u71d5u5b50"}}';//u71d5u5b50这个是php中自动转换的
var dataObj = eval("("+arr+")");//这里要加上加好括号和双引号的原因我也不知道,就当是json语法,只能死记硬背了
  $.each(dataObj,function(idx,item){  
   //输出 
   alert(item.id+"哈哈"+item.name);  
})

第二种:不需要转化的:

 代码如下

复制代码

var arr = {"red":{"id":1,"name":"mary"},"blue":{"id":2,"name":"u71d5u5b50"}};
  $.each(arr,function(idx,item){    
   //输出
   alert(item.id+"哈哈"+item.name);
})

循环也有两种方法:
//方法一:

 代码如下

复制代码

$.each(arr,function(idx,item){    
   //输出
   alert(item.id+"哈哈"+item.name);
})

//方法二:

 代码如下

复制代码

for(var key in arr){
  alert(key);
  alert(arr[key].status);
 }

大家可以试试效果。

ajax返回JSON时的处理方式

 1,使用普通的aspx页面来处理
       本人觉得这种方式处理起来是最简单的了,看下面的代码吧

 代码如下

复制代码

$.ajax({
           type: "post",
           url: "Default.aspx",
           dataType: "json",
           success: function (data) {
                      $("input#showTime").val(data[0].demoData);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                   alert(errorThrown);
            }
});

     
         这里是后台传递数据的代码

 代码如下

复制代码

Response.Clear();
Response.Write("[{"demoData":"This Is The JSON Data"}]");
Response.Flush();
Response.End();

         这种处理的方式将传递过来的数据直接解析为json数据,也就是说这里的前台js代码可能直接把这些数据解析成json对象数据,而并非字符串数据,如data[0].demoData,这里就直接使用了这个json对象数据

 



 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值