buildJSONPacketBody数组形式封装json、JsonReader解析服务器返回值、封装对象、https协议(app提交建议)

以前都是网上各种练习服务器上传json数据,然后解析返回的数据,这次就总结下,我公司的代码,不过这个代码是简化的代码,公司的封装嵌套还是蛮深的

点击打开链接,免积分下载


在MainActivity中进行网络请求,后台线程,将对象传递过去,需要解析返回数据时候,封装对象实体类

	 private final class FeedbackTast implements Runnable{

	        public FeedbackTast(){

	        }

	        @Override
	        public void run() {
	            String app_type = "3";
	            DownLoad downLoad = new DownLoad();
	            downLoad.setApp_type(app_type);
	            SubmitFeedback rquest = new SubmitFeedback(MainActivity.this, downLoad, "反馈");
	            rquest.start();
	        }
	    }

然后封装我公司要求的数据格式:

requestJson = ProtocolUtil.buildJSONPacketBody(new String[] {
				"app_type", "os_type", "osversion", "appversion",
				"devicefactory", "devicemodel" },
				new Object[] { downLoad.getApp_type(), "android",
						GLauncherApplication.getInstance().getOsVersion(),
						GLauncherApplication.getInstance().getVersion(),
						GLauncherApplication.getInstance().getVendor(),
						GLauncherApplication.getInstance().getDevice() },
				new String[] { "phoneimei", "context" },
				new Object[] { GLauncherApplication.getInstance().getImei(),
						feedback });

在我的这篇博客中,是另外一种通过map的方式进行封装的,map封装json(公司需求)

下面是封装好的数据格式:

</pre><pre name="code" class="java">{
	"Request": {
 		"head": {
 			"app_type": "3",
 			"os_type": "android",
 			"osversion": "5.1.1",
 			"appversion": "1.0",
 			"devicefactory": "LGE",
 			"devicemodel": "AOSP on HammerHead"
 		},
 		"body": {
 			"phoneimei": "353490061934846",
 			"context": "反馈"
 		}
 	}
 }


然后服务器就返回200,然后就解析返回的相应,我公司的返回相应格式如下:

{"Response":{"head":{"statuscode":"000000","statusmsg":"sucess"}}}

然后就利用JsonReader进行解析json,封装对象(这个是系统自带滴)


基本上就是这个流程--万变不离其宗旨


#################################以下是代码区#########################

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
<uses-permission android:name="android.permission.INTERNET"/> 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> 
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> 
<uses-permission android:name="android.permission.READ_PHONE_STATE"/> 

activity_main.xml

<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"
    tools:context="com.example.feedback.MainActivity" >

    <TextView
        android:id="@+id/tv"
        android:background="#ccc"
        android:layout_width="60dp"
        android:gravity="center"
        android:text="反馈"
        android:layout_height="60dp"/>

</RelativeLayout>

MainActivity

package com.example.feedback;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {

	private TextView feekBack;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		feekBack = (TextView) findViewById(R.id.tv);
		feekBack.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				 new Thread(new FeedbackTast()).start();
			}
		});
	}

	
	
	 private final class FeedbackTast implements Runnable{

	        public FeedbackTast(){

	        }

	        @Override
	        public void run() {
	            String app_type = "3";
	            DownLoad downLoad = new DownLoad();
	            downLoad.setApp_type(app_type);
	            SubmitFeedback rquest = new SubmitFeedback(MainActivity.this, downLoad, "反馈");
	            rquest.start();
	        }
	    }
}

GLauncherApplication

package com.example.feedback;

import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.telephony.TelephonyManager;

public class GLauncherApplication extends Application {
	private static GLauncherApplication instance;
	private TelephonyManager telephonyManager;

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		this.instance = this;
	}

	public static GLauncherApplication getInstance() {

		return instance;
	}

	public String getImei() {
		return getTelephonyManager().getDeviceId();
	}

	public String getOsVersion() {
		return Build.VERSION.RELEASE;
	}

	public String getDevice() {
		return Build.MODEL;
	}

	public String getVendor() {
		return Build.MANUFACTURER;
	}

	public String getOSVersion() {
		return Build.VERSION.RELEASE;
	}
	public String getVersion() {
		String version = "0.0.0";
		try {

			PackageInfo packageInfo = instance.getPackageManager()
					.getPackageInfo(instance.getPackageName(), 0);
			version = packageInfo.versionName;
		} catch (NameNotFoundException e) {
			e.printStackTrace();
		}

		return version;
	}
	
	public TelephonyManager getTelephonyManager() {
		if (telephonyManager == null) {
			telephonyManager = (TelephonyManager) getApplicationContext()
					.getSystemService(Context.TELEPHONY_SERVICE);
		}
		return telephonyManager;
	}

}

DownLoad

package com.example.feedback;

public class DownLoad {
    private String os_type;
    private String app_type;
    private String version_code;
    private String app_url;
    private String statuscode;
    private String statusmsg;
    private String version;

    private String pkgName;
    private String appName;
    private String whitelist_code;

    public String getUpdateMsg() {
        return updateMsg;
    }

    public void setUpdateMsg(String updateMsg) {
        this.updateMsg = updateMsg;
    }

    private String updateMsg;

    public String getPkgName() {
        return pkgName;
    }

    public void setPkgName(String pkgName) {
        this.pkgName = pkgName;
    }

    public String getAppName() {
        return appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }


    public String getWhitelistCode() {
        return whitelist_code;
    }

    public void setWhitelistCode(String whitelist_code) {
        this.whitelist_code = whitelist_code;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }
    public String getOs_type() {
        return os_type;
    }

    public void setOs_type(String os_type) {
        this.os_type = os_type;
    }

    public String getApp_type() {
        return app_type;
    }

    public void setApp_type(String app_type) {
        this.app_type = app_type;
    }

    public String getVersion_code() {
        return version_code;
    }

    public void setVersion_code(String version_code) {
        this.version_code = version_code;
    }

    public String getApp_url() {
        return app_url;
    }

    public void setApp_url(String app_url) {
        this.app_url = app_url;
    }

    public String getStatuscode() {
        return statuscode;
    }

    public void setStatuscode(String statuscode) {
        this.statuscode = statuscode;
    }

    public String getStatusmsg() {
        return statusmsg;
    }

    public void setStatusmsg(String statusmsg) {
        this.statusmsg = statusmsg;
    }
}

ProtocolUtil

package com.example.feedback;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

/**
 * simple tools to handle protocol for apps.
 */
public class ProtocolUtil {

	public static final String COLON = ": ";
	public static final String LEFT_ANGLE_BRACKET = "{";
	public static final String RIGHT_ANGLE_BRACKET = "}";

	
	public static String buildJSONPacketBody(String[] headKey, Object[] headValue,
			String[] bodyKey, Object[] bodyValue) {
		
		if (((headKey == null || headKey.length == 0) && (headValue == null || headValue.length == 0) 
				&& (bodyKey == null || bodyKey.length == 0) && (bodyValue == null || bodyValue.length == 0))) {
			throw new IllegalArgumentException();
		}
		
		StringBuffer sb = new StringBuffer(LEFT_ANGLE_BRACKET + "\r\n");
		sb.append("\t\"Request\"" + COLON + LEFT_ANGLE_BRACKET + "\r\n");
		if (headKey != null) {
			sb.append("\t\t\"head\"" + COLON + LEFT_ANGLE_BRACKET + "\r\n");
			for (int i = 0; i < headKey.length; i++) {
				
				sb.append("\t\t\t\"" + headKey[i].toLowerCase() + "\"" + COLON)
					.append(JSONUtil.object2json(headValue[i]));
				if(i != headKey.length -1) {
					sb.append(",");
				}
				sb.append("\r\n");
			}
			sb.append("\t\t" + RIGHT_ANGLE_BRACKET+ ",\r\n");
		}
		
		if (bodyKey != null) {
			sb.append("\t\t\"body\"" + COLON + LEFT_ANGLE_BRACKET + "\r\n");
			for (int i = 0; i < bodyKey.length; i++) {
				if (bodyKey[i] == null || bodyKey[i].equals("")) {
					continue;
				}
				
				sb.append("\t\t\t\"" + bodyKey[i].toLowerCase() + "\"" + COLON)
					.append(JSONUtil.object2json(bodyValue[i]));
				if(i != bodyKey.length -1) {
					sb.append(",");
				}
				sb.append("\r\n");
			}
			sb.append("\t\t" + RIGHT_ANGLE_BRACKET+ "\r\n");
		}
		
		sb.append("\t" + RIGHT_ANGLE_BRACKET + "\r\n");
		sb.append(RIGHT_ANGLE_BRACKET);
		clearObjectArray(headKey, headValue, bodyKey, bodyValue);
		return sb.toString();
	}
	
	
	
	private static void clearObjectArray(String[] hk, Object[] hv, String[] bk, Object[] bv) {
		if (hk != null && hv != null) {
			for (int i = 0; i < hk.length; i++) {
				hk[i] = null;
				hv[i] = null;
			}
		}
		hk = null;
		hv = null;
		if (bk != null && bv != null) {
			for (int i = 0; i < bk.length; i++) {
				bk[i] = null;
				bv[i] = null;
			}
		}
		bk = null;
		bv = null;
	}
	
	
}

JSONUtil  在上一篇博客里有各种转json的格式

package com.example.feedback;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gson.Gson;
public class JSONUtil {

	
	/** 对象转换为json */
	public static String object2json(Object obj) {
		StringBuilder json = new StringBuilder();
		if (obj == null) {
			json.append("\"\"");
		} else if (obj instanceof String || obj instanceof Integer || obj instanceof Float || obj instanceof Boolean
				|| obj instanceof Short || obj instanceof Double || obj instanceof Long || obj instanceof BigDecimal
				|| obj instanceof BigInteger || obj instanceof Byte) {
			json.append("\"").append(string2json(obj.toString())).append("\"");
		} else if (obj instanceof Object[]) {
			json.append(array2json((Object[]) obj));
		} else if (obj instanceof List) {
			json.append(list2json((List<?>) obj));
		} else if (obj instanceof Map) {
			json.append(map2json((Map<?, ?>) obj));
		} else if (obj instanceof Set) {
			json.append(set2json((Set<?>) obj));
		} else {
			json.append(bean2json(obj));
		}
		return json.toString();
	}

	/** 对象转换为json */
	public static String bean2json(Object bean) {
		Gson gson = new Gson();
		return gson.toJson(bean);
	}

	/** List转换为json */
	public static String list2json(List<?> list) {
		StringBuilder json = new StringBuilder();
		json.append("[");
		if (list != null && list.size() > 0) {
			for (Object obj : list) {
				json.append(object2json(obj));
				json.append(",");
			}
			json.setCharAt(json.length() - 1, ']');
		} else {
			json.append("]");
		}
		return json.toString();
	}

	/** 数组转换为json */
	public static String array2json(Object[] array) {
		StringBuilder json = new StringBuilder();
		json.append("[");
		if (array != null && array.length > 0) {
			for (Object obj : array) {
				json.append(object2json(obj));
				json.append(",");
			}
			json.setCharAt(json.length() - 1, ']');
		} else {
			json.append("]");
		}
		return json.toString();
	}

	/** map转换为json */
	public static String map2json(Map<?, ?> map) {
		StringBuilder json = new StringBuilder();
		json.append("{");
		if (map != null && map.size() > 0) {
			for (Object key : map.keySet()) {
				json.append(object2json(key));
				json.append(":");
				json.append(object2json(map.get(key)));
				json.append(",");
			}
			json.setCharAt(json.length() - 1, '}');
		} else {
			json.append("}");
		}
		return json.toString();
	}

	/** set转换为json */
	public static String set2json(Set<?> set) {
		StringBuilder json = new StringBuilder();
		json.append("[");
		if (set != null && set.size() > 0) {
			for (Object obj : set) {
				json.append(object2json(obj));
				json.append(",");
			}
			json.setCharAt(json.length() - 1, ']');
		} else {
			json.append("]");
		}
		return json.toString();
	}

	public static String string2json(String s) {
		if (s == null)
			return "";
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++) {
			char ch = s.charAt(i);
			switch (ch) {
			case '"':
				sb.append("\\\"");
				break;
			case '\\':
				sb.append("\\\\");
				break;
			case '\b':
				sb.append("\\b");
				break;
			case '\f':
				sb.append("\\f");
				break;
			case '\n':
				sb.append("\\n");
				break;
			case '\r':
				sb.append("\\r");
				break;
			case '\t':
				sb.append("\\t");
				break;
			case '/':
				sb.append("\\/");
				break;
			default:
				if (ch >= '\u0000' && ch <= '\u001F') {
					String ss = Integer.toHexString(ch);
					sb.append("\\u");
					for (int k = 0; k < 4 - ss.length(); k++) {
						sb.append('0');
					}
					sb.append(ss.toUpperCase());
				} else {
					sb.append(ch);
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 对象转map
	 * 
	 * @param obj
	 * @return
	 */
	public static Map<String, Object> objToMap(Object obj) {

		Map<String, Object> map = new HashMap<String, Object>();
		try {
			/*
			 * BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
			 * PropertyDescriptor[] propertyDescriptors = beanInfo
			 * .getPropertyDescriptors(); for (PropertyDescriptor property :
			 * propertyDescriptors) { String key = property.getName(); //
			 * 过滤class属性 if (!key.equals("class")) { // 得到property对应的getter方法
			 * Method getter = property.getReadMethod(); Object value =
			 * getter.invoke(obj); map.put(key, value); } }
			 */
			Field[] fields = obj.getClass().getDeclaredFields();
			for (Field field : fields) {
				String key = field.getName();
				boolean accessFlag = field.isAccessible();
				field.setAccessible(true);
				Object val = field.get(obj);
				if (val == null) {
					val = "";
				}
				map.put(key, val);
				field.setAccessible(accessFlag);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

}

SubmitFeedback

package com.example.feedback;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ssl.SSLSocketFactory;

import android.content.Context;
import android.util.JsonReader;
import android.util.Log;

public class SubmitFeedback extends Thread {

	public static final String TAG = "SubmitFeedback";
	public static final String ROOT_RESPONSE = "Response";
	private String statuscode;
	private String statusmsg;

	private String path = "https://www.imlianxi.com:xxxx/AppFeedback";
	private String requestJson;
	private DownLoad downLoad;

	/**
	 * requestJson:{
	"Request": {
 		"head": {
 			"app_type": "3",
 			"os_type": "android",
 			"osversion": "5.1.1",
 			"appversion": "1.0",
 			"devicefactory": "LGE",
 			"devicemodel": "AOSP on HammerHead"
 		},
 		"body": {
 			"phoneimei": "353490061934846",
 			"context": "反馈"
 		}
 	}
 }

	 * 
	 */
	public SubmitFeedback(Context context, DownLoad downLoad, String feedback) {
		this.downLoad = downLoad;
		requestJson = ProtocolUtil.buildJSONPacketBody(new String[] {
				"app_type", "os_type", "osversion", "appversion",
				"devicefactory", "devicemodel" },
				new Object[] { downLoad.getApp_type(), "android",
						GLauncherApplication.getInstance().getOsVersion(),
						GLauncherApplication.getInstance().getVersion(),
						GLauncherApplication.getInstance().getVendor(),
						GLauncherApplication.getInstance().getDevice() },
				new String[] { "phoneimei", "context" },
				new Object[] { GLauncherApplication.getInstance().getImei(),
						feedback });
		Log.e(TAG, "requestJson:" + requestJson);
		
	}

	@Override
	public void run() {
		{
			super.run();
			try {
				// 得到byte[]字节数组
				byte[] requestStringBytes = requestJson.getBytes("UTF-8");
				URL url = new URL(path);
				HttpsURLConnection conn = null;
				initHttps();
				conn = (HttpsURLConnection) url.openConnection();
				conn.setConnectTimeout(5 * 1000);
				conn.setRequestMethod("POST");
				conn.setRequestProperty("Content-length", ""
						+ requestStringBytes.length);
				conn.setRequestProperty(
						"Accept",
						"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
				conn.setRequestProperty("Accept-Language", "zh-CN");
				conn.setRequestProperty("Referer", path);
				conn.setRequestProperty("Charset", "UTF-8");
				conn.setRequestProperty(
						"User-Agent",
						"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
				conn.setRequestProperty("Connection", "Keep-Alive");
				conn.connect();


				// 输出流
				OutputStream outputStream = conn.getOutputStream();
				outputStream.write(requestStringBytes);
				outputStream.close();
				int responseCode = conn.getResponseCode();

				Log.e(TAG, "responseCode   ..." + responseCode);
				if (responseCode == 200) {
					// 得到服务器返回的InputStream流
//					InputStream in = conn.getInputStream();
//					// 包装流
//					BufferedReader respondReader = new BufferedReader(
//							new InputStreamReader(in, "UTF-8"));
//
//					String temp = "";
//					String s = "";
//					while ((temp = respondReader.readLine()) != null) {
//						s = s + temp;
//					}
//
//					Log.e(TAG, "result:"+s);
					
					
					
					InputStream in = conn.getInputStream();
					
					 ByteArrayOutputStream baos = new ByteArrayOutputStream();  
					  int len = 0;  
                     byte[] buffer = new byte[1024];  
                     while ((len = in.read(buffer)) != -1) {  
                         baos.write(buffer, 0, len);  
                     }  
                     baos.close();  
                     in.close();  
                     //字节数组转为字符串  
                     final String result = baos.toString();  
					
					// 解析流
					jsonParse(result);
				}
			} catch (Exception e) {
				Log.e(TAG, "connect wrong :" + e);
			}

		}
	}
	/**服务器返回值:
	 * result:{"Response":{"head":{"statuscode":"000000","statusmsg":"sucess"}}}
	 */

	/**
	 * 解析从服务器返回的respondReader
	 */
//	public void jsonParse(BufferedReader respondReader) {
//		// 创建jsonReader对象--参数为Reader
//		JsonReader reader = new JsonReader(respondReader);
		public void jsonParse(String respondReader) {
			JsonReader reader = new JsonReader(new StringReader(respondReader));
		Log.e(TAG, "jsonParse");
		try {
			//整体是一个json对象 {"Response":{"head":{"statuscode":"000000","statusmsg":"sucess"}}}
			reader.beginObject();
			while (reader.hasNext()) {
				String nameTag = reader.nextName();
				//Response
				if (ROOT_RESPONSE.equals(nameTag)
						|| ROOT_RESPONSE.toLowerCase().equals(nameTag)) {
					//{"head":{"statuscode":"000000","statusmsg":"sucess"}}是个对象
					reader.beginObject();
					while (reader.hasNext()) {
						//head
						nameTag = reader.nextName();
						if ("head".equals(nameTag)) {
							//解析{"statuscode":"000000","statusmsg":"sucess"}
							handleReadJSONHead(reader);
						} else {
							reader.skipValue();
						}
					}
					reader.endObject();
				}
			}
			reader.endObject();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void handleReadJSONHead(JsonReader reader) throws IOException {
		//{"statuscode":"000000","statusmsg":"sucess"}是个对象
		reader.beginObject();
		while (reader.hasNext()) {
			String nextName = reader.nextName();
			if ("statuscode".equals(nextName)) {
				statuscode = reader.nextString();
				downLoad.setStatuscode(statuscode);
			} else if ("statusmsg".equals(nextName)) {
				statusmsg = reader.nextString();
				downLoad.setStatusmsg(statusmsg);
			} else {
				reader.skipValue();
			}
		}
		
		Log.i("Safly", "getStatuscode::"+downLoad.getStatuscode()+",getStatusmsg::"+downLoad.getStatusmsg());
		reader.endObject();
	}

	private void initHttps() {
		try {
			KeyStore trustStore = KeyStore.getInstance(KeyStore
					.getDefaultType());
			trustStore.load(null, null);

			SSLSocketFactoryEx sf = new SSLSocketFactoryEx(trustStore);
			HttpsURLConnection.setDefaultSSLSocketFactory(sf.getSSLContext()
					.getSocketFactory());

			HttpsURLConnection
					.setDefaultHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
		} catch (Exception e) {
		}
	}

	static class SSLSocketFactoryEx extends SSLSocketFactory {

		SSLContext sslContext = SSLContext.getInstance("TLS");

		public SSLSocketFactoryEx(KeyStore truststore)
				throws NoSuchAlgorithmException, KeyManagementException,
				KeyStoreException, UnrecoverableKeyException {
			super(truststore);

			TrustManager tm = new X509TrustManager() {

				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
					return null;
				}

				@Override
				public void checkClientTrusted(
						java.security.cert.X509Certificate[] chain,
						String authType)
						throws java.security.cert.CertificateException {
				}

				@Override
				public void checkServerTrusted(
						java.security.cert.X509Certificate[] chain,
						String authType)
						throws java.security.cert.CertificateException {

				}
			};
			sslContext.init(null, new TrustManager[] { tm }, null);
		}

		@Override
		public Socket createSocket(Socket socket, String host, int port,
				boolean autoClose) throws IOException, UnknownHostException {
			return sslContext.getSocketFactory().createSocket(socket, host,
					port, autoClose);
		}

		@Override
		public Socket createSocket() throws IOException {
			return sslContext.getSocketFactory().createSocket();
		}

		public SSLContext getSSLContext() {
			return sslContext;
		}
	}

}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值