Android中解析JSON

JSON简介

JSON 语法规则

JSON 语法是 JavaScript 对象表示法语法的子集。

  • 数据在名称/值对中
  • 数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组

JSON 名称/值对

JSON 数据的书写格式是:名称/值对。

名称/值对包括字段名称(在双引号中),后面写一个冒号,然后是值:

"firstName" : "John"

这很容易理解,等价于这条 JavaScript 语句:

firstName = "John"

JSON 值

JSON 值可以是:

  • 数字(整数或浮点数)
  • 字符串(在双引号中)
  • 逻辑值(true 或 false)
  • 数组(在方括号中)
  • 对象(在花括号中)
  • null

JSON 对象

JSON 对象在花括号中书写:

对象可以包含多个名称/值对:

{ "firstName":"John" , "lastName":"Doe" }

这一点也容易理解,与这条 JavaScript 语句等价:

firstName = "John"
lastName = "Doe"

JSON 数组

JSON 数组在方括号中书写:

数组可包含多个对象:

{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }
]
}

在上面的例子中,对象 "employees" 是包含三个对象的数组。每个对象代表一条关于某人(有姓和名)的记录。

JSON 使用 JavaScript 语法

因为 JSON 使用 JavaScript 语法,所以无需额外的软件就能处理 JavaScript 中的 JSON。

通过 JavaScript,您可以创建一个对象数组,并像这样进行赋值:

例子

var employees = [
{ "firstName":"Bill" , "lastName":"Gates" },
{ "firstName":"George" , "lastName":"Bush" },
{ "firstName":"Thomas" , "lastName": "Carter" }
];

可以像这样访问 JavaScript 对象数组中的第一项:

employees[0].lastName;

返回的内容是:

Gates

可以像这样修改数据:

employees[0].lastName = "Jobs";
 
 

在下面的章节,您将学到如何把 JSON 文本转换为 JavaScript 对象。

JSON 文件

  • JSON 文件的文件类型是 ".json"
  • JSON 文本的 MIME 类型是 "application/json"

JSON解析常用类

1. Android JSON所有相关类,都在org.json包下

JSONObject、JSONArray、JSONException、JSONStringer、JSONTokener

2. 常见方法
使用get方法与使用opt方法的区别?
JsonObject 方法,opt* 与 get* 建议使用opt方法,因为get方法如果其内容为空会直接抛出异常。不过JsonArray.opt*(index)会有越界问题需要特别注意。
[java]  view plaincopyprint?在CODE上查看代码片派生到我的代码片

  1. opt、optBoolean、optDouble、optInt、optLong、optString、optJSONArray、optJSONObject  
  2. get、getBoolean、getDouble、getInt、getLong、getString、getJSONArray、getJSONObject  
3. Android创建JSON
[java]  view plaincopyprint?在CODE上查看代码片派生到我的代码片

  1. private String createJson() throws JSONException {  
  2.  JSONObject jsonObject = new JSONObject();  
  3.  jsonObject.put ("intKey" , 123);  
  4.  jsonObject.put ("doubleKey" , 10.1);  
  5.  jsonObject.put ("longKey" , 666666666);  
  6.  jsonObject.put ("stringKey" , "lalala" );  
  7.  jsonObject.put ("booleanKey" , true);  
  8.    
  9.  JSONArray jsonArray = new JSONArray();  
  10.  jsonArray.put (0111);  
  11.  jsonArray.put("second");  
  12.  jsonObject.put ("arrayKey" , jsonArray);  
  13.    
  14.  JSONObject innerJsonObject = new JSONObject();  
  15.  innerJsonObject.put ("innerStr" , "inner" );  
  16.  jsonObject.put ("innerObjectKey" , innerJsonObject);  
  17.    
  18.    
  19.  Log.e("Json" , jsonObject.toString());  
  20.    
  21.  return jsonObject.toString();  
  22.  }  
输出结果:
{"intKey":123, "doubleKey":10.1, "longKey":666666666, "stringKey":"lalala", "booleanKey":true, "arrayKey":[111,"second"], "innerObjectKey":{"innerStr":"inner"}}
4. 解析上面创建的JSON
[java]  view plaincopyprint?在CODE上查看代码片派生到我的代码片

  1. private void pareJson(String jsonStr) throws JSONException {  
  2.  JSONObject jsonObject = new JSONObject(jsonStr);  
  3.  int intValue       = jsonObject.optInt( "intKey");  
  4.  double doubleValue = jsonObject.optDouble( "doubleKey");  
  5.  long longValue     = jsonObject.optLong( "longKey");  
  6.  String strValue    = jsonObject.optString( "stringKey");  
  7.  boolean boolValue  = jsonObject.optBoolean( "booleanKey");  
  8.    
  9.  JSONArray array    = jsonObject.optJSONArray( "arrayKey");  
  10.  int arrIntValue    = array.optInt(0);  
  11.  String arrStrValue = array.optString(1);  
  12.    
  13.  JSONObject innerJson = jsonObject.optJSONObject("innerObjectKey" );  
  14.  String innerStr      = innerJson.optString( "innerStr");  
  15.    
  16.  Log.e("Json" , "intValue = " + intValue + " , doubleValue = " + doubleValue  
  17.             + " , longValue = " + longValue + " , strValue = " + strValue  
  18.             + " , booleanValue = " + boolValue + " , arrIntValue = " + arrIntValue  
  19.             + " , arrStrValue = " + arrStrValue + " , innerStr = " + innerStr);  
  20. }  
输出结果:
intValue = 123 , doubleValue = 10.1 , longValue = 666666666 , strValue = lalala , booleanValue = true , arrIntValue = 111 , arrStrValue = second , innerStr = inner
更加详细的解析请参考 《android json解析及简单例子》:http://blog.csdn.net/lwwgtm/article/details/8990019

android的json解析部分都在包org.json下,主要有以下几个类: 

JSONObject:可以看作是一个json对象,这是系统中有关JSON定义的基本单元,其包含一对儿(Key/Value)数值。它对外部(External:   应用toString()方法输出的数值)调用的响应体现为一个标准的字符串(例如:{"JSON": "Hello, World"},最外被大括号包裹,其中的KeyValue被冒号":"分隔)。其对于内部(Internal)行为的操作格式略微,例如:初始化一个JSONObject实例,引用内部的put()方法添加数值:new JSONObject().put("JSON", "Hello, World!"),在KeyValue之间是以逗号","分隔。Value的类型包括:BooleanJSONArrayJSONObjectNumberString或者默认值JSONObject.NULL object 。

JSONStringer:json文本构建类 ,根据官方的解释,这个类可以帮助快速和便捷的创建JSON text。其最大的优点在于可以减少由于 格式的错误导致程序异常,引用这个类可以自动严格按照JSON语法规则(syntax rules)创建JSON text。每个JSONStringer实体只能对应创建一个JSON text。。其最大的优点在于可以减少由于格式的错误导致程序异常,引用这个类可以自动严格按照JSON语法规则(syntax rules)创建JSON text。每个JSONStringer实体只能对应创建一个JSON text。

JSONArray它代表一组有序的数值。将其转换为String输出(toString)所表现的形式是用方括号包裹,数值以逗号”,”分隔(例如:     [value1,value2,value3],大家可以亲自利用简短的代码更加直观的了解其格式)。这个类的内部同样具有查询行为,     get()和opt()两种方法都可以通过index索引返回指定的数值,put()方法用来添加或者替换数值。同样这个类的value类型可以包括:Boolean、JSONArray、JSONObject、Number、String或者默认值JSONObject.NULL object。

JSONTokener:json解析类 
JSONException:json中用到的异常 

除了上面的JSONObject和JSONArray,还可以使用JSONStringer来构建json文本  

Java代码  
  1. try {  
  2.     JSONStringer jsonText = new JSONStringer();  
  3.     // 首先是{,对象开始。object和endObject必须配对使用  
  4.     jsonText.object();  
  5.       
  6.     jsonText.key("phone");  
  7.     // 键phone的值是数组。array和endArray必须配对使用  
  8.     jsonText.array();  
  9.     jsonText.value("12345678").value("87654321");  
  10.     jsonText.endArray();  
  11.       
  12.     jsonText.key("name");  
  13.     jsonText.value("yuanzhifei89");  
  14.     jsonText.key("age");  
  15.     jsonText.value(100);  
  16.       
  17.     jsonText.key("address");  
  18.     // 键address的值是对象  
  19.     jsonText.object();  
  20.     jsonText.key("country");  
  21.     jsonText.value("china");  
  22.     jsonText.key("province");  
  23.     jsonText.value("jiangsu");  
  24.     jsonText.endObject();  
  25.       
  26.     jsonText.key("married");  
  27.     jsonText.value(false);  
  28.       
  29.     // },对象结束  
  30.     jsonText.endObject();  
  31. catch (JSONException ex) {  
  32.     throw new RuntimeException(ex);  
  33. }  


json文本解析类JSONTokener  
按照RFC4627规范将json文本解析为相应的对象。  


对于将json文本解析为对象,只需要用到该类的两个api:  
构造函数 
public Object nextValue(); 

代码  
  1. //  {  
  2. //      "phone" : ["12345678", "87654321"], // 数组  
  3. //      "name" : "yuanzhifei89", // 字符串  
  4. //      "age" : 100, // 数值  
  5. //      "address" : { "country" : "china", "province" : "jiangsu" }, // 对象  
  6. //      "married" : false // 布尔值  
  7. //  }  
  8.   
  9.   final String JSON = "{'phone':['12345678','87654321']," +    "'name':'yuanzhifei89'," +    "'age':100," +    "'address':{'country':'china','province':'jiangsu'}," +    "'married': false}";

  1.   
  2. try {  
  3.     JSONTokener jsonParser = new JSONTokener(JSON);  
  4.     // 此时还未读取任何json文本,直接读取就是一个JSONObject对象。  
  5.     // 如果此时的读取位置在"name" : 了,那么nextValue就是"yuanzhifei89"(String)  
  6.     JSONObject person = (JSONObject) jsonParser.nextValue();  
  7.     // 接下来的就是JSON对象的操作了  
  8.     person.getJSONArray("phone");  
  9.     person.getString("name");  
  10.     person.getInt("age");  
  11.     person.getJSONObject("address");  
  12.     person.getBoolean("married");  
  13. catch (JSONException ex) {  
  14.     // 异常处理代码  
  15. }  

 

其它的api基本就是用来查看json文本中的文本的 

代码  
  1. try {  
  2.     JSONTokener jsonParser = new JSONTokener(JSON);  
  3.     // 继续向下读8个json文本中的字符。此时刚开始,即在{处  
  4.     jsonParser.next(8); //{    "phone。tab算一个字符  
  5.       
  6.     // 继续向下读1个json文本中的字符  
  7.     jsonParser.next(); //"  
  8.       
  9.     // 继续向下读取一个json文本中的字符。该字符不是空白、同时也不是注视中的字符  
  10.     jsonParser.nextClean(); //:  
  11.       
  12.     // 返回当前的读取位置到第一次遇到'a'之间的字符串(不包括a)。  
  13.     jsonParser.nextString('a'); //  ["12345678", "87654321"],    "n(前面有两个空格)  
  14.       
  15.     // 返回当前读取位置到第一次遇到字符串中(如"0089")任意字符之间的字符串,同时该字符是trimmed的。(此处就是第一次遇到了89)  
  16.     jsonParser.nextTo("0089"); //me" : "yuanzhifei  
  17.       
  18.     // 读取位置撤销一个  
  19.     jsonParser.back();  
  20.     jsonParser.next(); //i  
  21.       
  22.     // 读取位置前进到指定字符串处(包括字符串)  
  23.     jsonParser.skipPast("address");  
  24.     jsonParser.next(8); //" : { "c  
  25.       
  26.     // 读取位置前进到执行字符处(不包括字符)  
  27.     jsonParser.skipTo('m');  
  28.     jsonParser.next(8); //married"  
  29. catch (JSONException ex) {  
  30.     // 异常处理代码  
  31. }  

例子:

gson(http://code.google.com/p/google-gson/)

下面我们来看看Google提供的gson这个json解析库,同样我们需要去下载gson这个jar包,导入到我们的项目中

使用gson,我们可以非常轻松的实现数据对象和json对象的相互转化,其中我们最常用的就是两个方法,一个是fromJSON(),将json对象转换成我们需要的数据对象,另一个是toJSON(),这个就是将我们的数据对象转换成json对象。下面我们也通过一个综合的例子来看看gson的使用方法:

复制代码
public class JsonService
{
    public Person getPerson()
    {
        Person person = new Person(1, "xiaoluo", "广州");
        return person;
    }
    
    public List<Person> getPersons()
    {
        List<Person> persons = new ArrayList<Person>();
        Person person = new Person(1, "xiaoluo", "广州");
        Person person2 = new Person(2, "android", "上海");
        persons.add(person);
        persons.add(person2);
        return persons;
    }
    
    public List<String> getString()
    {
        List<String> list = new ArrayList<String>();
        list.add("广州");
        list.add("上海");
        list.add("北京");
        return list;
    }
    
    public List<Map<String, String>> getMapList()
    {
        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
        Map<String, String> map1 = new HashMap<String, String>();
        map1.put("id", "001");
        map1.put("name", "xiaoluo");
        map1.put("age", "20");
        Map<String, String> map2 = new HashMap<String, String>();
        map2.put("id", "002");
        map2.put("name", "android");
        map2.put("age", "33");
        list.add(map1);
        list.add(map2);
        return list;
    }
}
复制代码
复制代码
public static void main(String[] args)
    {
        Gson gson = new Gson();
        JsonService jsonService = new JsonService();
        Person person = jsonService.getPerson();
        System.out.println("person: " + gson.toJson(person));
        //    对于Object类型,使用 fromJson(String, Class)方法来将Json对象转换成Java对象
        Person person2 = gson.fromJson(gson.toJson(person), Person.class);
        System.out.println(person2);
        System.out.println("------------------------------------------------");
        
        List<Person> persons = jsonService.getPersons();
        System.out.println("persons: " + gson.toJson(persons));
        /*
         * 对于泛型对象,使用fromJson(String, Type)方法来将Json对象转换成对应的泛型对象
         * new TypeToken<>(){}.getType()方法
         */
        List<Person> persons2 = gson.fromJson(gson.toJson(persons), new TypeToken<List<Person>>(){}.getType());
        System.out.println(persons2);
        System.out.println("------------------------------------------------");
        
        List<String> list = jsonService.getString();
        System.out.println("String---->" + gson.toJson(list));
        List<String> list2 = gson.fromJson(gson.toJson(list), new TypeToken<List<String>>(){}.getType());
        System.out.println("list2---->" + list2);
        System.out.println("------------------------------------------------");
        
        List<Map<String, String>> listMap = jsonService.getMapList();
        System.out.println("Map---->" + gson.toJson(listMap));
        List<Map<String, String>> listMap2 = gson.fromJson(gson.toJson(listMap), new TypeToken<List<Map<String, String>>>(){}.getType());
        System.out.println("listMap2---->" + listMap2);
        System.out.println("------------------------------------------------");
    }
复制代码

看看控制台的输出:

复制代码
person: {"id":1,"name":"xiaoluo","address":"广州"}
Person [id=1, name=xiaoluo, address=广州]
------------------------------------------------
persons: [{"id":1,"name":"xiaoluo","address":"广州"},{"id":2,"name":"android","address":"上海"}]
[Person [id=1, name=xiaoluo, address=广州], Person [id=2, name=android, address=上海]]
------------------------------------------------
String---->["广州","上海","北京"]
list2---->[广州, 上海, 北京]
------------------------------------------------
Map---->[{"id":"001","age":"20","name":"xiaoluo"},{"id":"002","age":"33","name":"android"}]
listMap2---->[{id=001, age=20, name=xiaoluo}, {id=002, age=33, name=android}]
------------------------------------------------
复制代码

三、在Android客户端解析服务器端的json数据

下面我们来完成一个综合的例子,Android客户端通过一个AsyncTask异步任务请求服务器端的某些数据,然后在解析完这些数据后,将得到的数据内容更新到我们的Spinner这个UI控件当中。

我们首先来看下服务器端的代码:

复制代码
@WebServlet("/CityServlet")
public class CityServlet extends HttpServlet
{
    private static final long serialVersionUID = 1L;

    public CityServlet()
    {
        super();
    }

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException
    {
        this.doPost(request, response);
    }

    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException
    {
        response.setContentType("text/html;charset=utf-8");
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter writer = response.getWriter();
        
        String type = request.getParameter("type");
        if("json".equals(type))
        {
            List<String> cities = new ArrayList<String>();
            cities.add("广州");
            cities.add("上海");
            cities.add("北京");
            cities.add("湖南");
            Map<String, List<String>> map = new HashMap<String, List<String>>();
            map.put("cities", cities);
            String citiesString = JSON.toJSONString(map);
            writer.println(citiesString);
        }
        
        writer.flush();
        writer.close();
    }

}
复制代码

如果客户端请求的参数是type=json,则响应给客户端一个json数据格式

接着来看看客户端的代码,首先看看客户端的布局文件,其实就是一个按钮和一个Spinner控件,当点击按钮后,通过http协议请求服务器端的数据,然后在接收到后再更新我们的Spinner控件的数据

复制代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="64dp"
        android:layout_marginTop="64dp"
        android:textSize="20sp"
        android:text="城市" />
    
    <Spinner 
        android:id="@+id/spinner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/textView1"
        android:layout_toRightOf="@id/textView1"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_below="@+id/spinner"
        android:layout_marginLeft="22dp"
        android:layout_marginTop="130dp"
        android:text="加载数据" />

</RelativeLayout>
复制代码

在Android客户端写一个解析json数据格式的类:

复制代码
public class JsonUtils
{
    /**
     * @param citiesString    从服务器端得到的JSON字符串数据
     * @return    解析JSON字符串数据,放入List当中
     */
    public static List<String> parseCities(String citiesString)
    {
        List<String> cities = new ArrayList<String>();
        
        try
        {
            JSONObject jsonObject = new JSONObject(citiesString);
            JSONArray jsonArray = jsonObject.getJSONArray("cities");
            for(int i = 0; i < jsonArray.length(); i++)
            {
                cities.add(jsonArray.getString(i));
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        
        return cities;
    }
}
复制代码

当然我们的HttpUtils类也不可少:

复制代码
public class HttpUtils
{
    /**
     * @param path    请求的服务器URL地址
     * @param encode    编码格式
     * @return    将服务器端返回的数据转换成String
     */
    public static String sendPostMessage(String path, String encode)
    {
        String result = "";
        HttpClient httpClient = new DefaultHttpClient();
        try
        {
            HttpPost httpPost = new HttpPost(path);
            HttpResponse httpResponse = httpClient.execute(httpPost);
            if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
            {
                HttpEntity httpEntity = httpResponse.getEntity();
                if(httpEntity != null)
                {
                    result = EntityUtils.toString(httpEntity, encode);
                }
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            httpClient.getConnectionManager().shutdown();
        }
        
        return result;
    }
}
复制代码

最后来看看我们的MainActivity类:

复制代码
public class MainActivity extends Activity
{
    private Spinner spinner;
    private Button button;
    private ArrayAdapter<String> adapter;
    private ProgressDialog dialog;
    private final String CITY_PATH_JSON = "http://172.25.152.34:8080/httptest/CityServlet?type=json";
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        spinner = (Spinner)findViewById(R.id.spinner);
        button = (Button)findViewById(R.id.button);
        dialog = new ProgressDialog(MainActivity.this);
        button.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                dialog.setTitle("提示信息");
                dialog.setMessage("loading......");
                dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                dialog.setCancelable(false);
                
                new MyAsyncTask().execute(CITY_PATH_JSON);
            }
        });
    }

    public class MyAsyncTask extends AsyncTask<String, Void, List<String>>
    {
        @Override
        protected void onPreExecute()
        {
            dialog.show();
        }
        @Override
        protected List<String> doInBackground(String... params)
        {
            List<String> cities = new ArrayList<String>();
            String citiesString = HttpUtils.sendPostMessage(params[0], "utf-8");
            //    解析服务器端的json数据
            cities = JsonUtils.parseCities(citiesString);return cities;
        }
        @Override
        protected void onPostExecute(List<String> result)
        {
            adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_spinner_item, result);
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            spinner.setAdapter(adapter);
            dialog.dismiss();
        }
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}
复制代码

当然别往了开启我们的网络授权

<uses-permission android:name="android.permission.INTERNET"/>

最后我们来看看效果图:

这样我们就完成了客户端与服务器端通过json来进行数据的交换

 

总结:本篇随笔主要讲解了JSON这种轻量级的数据交换格式的概念,以及讲解了两种解析json数据的解析类(json-lib以及gson),最后通过一个小例子实现了在Android客户端和服务器端使用json这种数据格式来进行数据的交换。


Android 读取app内json配置文件


public class AppJsonFileReader {
public static String getJson(Context context, String fileName) {

StringBuilder stringBuilder = new StringBuilder();
try {
AssetManager assetManager = context.getAssets();
BufferedReader bf = new BufferedReader(new InputStreamReader(
assetManager.open(fileName)));
String line;
while ((line = bf.readLine()) != null) {
stringBuilder.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}
return stringBuilder.toString();
}

public static List<Map<String, String>> setData(String str) {
try {
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
JSONArray array = new JSONArray(str);
int len = array.length();
Map<String, String> map;
for (int i = 0; i < len; i++) {
JSONObject object = array.getJSONObject(i);
map = new HashMap<String, String>();
map.put("operator", object.getString("operator"));
map.put("loginDate", object.getString("loginDate"));
map.put("logoutDate", object.getString("logoutDate"));
data.add(map);
}
return data;
} catch (JSONException e) {
e.printStackTrace();
return null;
}

}

public static List<Map<String, String>> setListData(String str) {
List<Map<String, String>> data = new ArrayList<Map<String, String>>();
try {

JSONArray array = new JSONArray(str);
int len = array.length();
Map<String, String> map;
for (int i = 0; i < len; i++) {
JSONObject object = array.getJSONObject(i);
map = new HashMap<String, String>();
map.put("imageId", object.getString("imageId"));
map.put("title", object.getString("title"));
map.put("subTitle", object.getString("subTitle"));
map.put("type", object.getString("type"));
data.add(map);
}

} catch (JSONException e) {
e.printStackTrace();
}
return data;

}
}






评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值