基于jdk11和基于apache-httpclient的http请求工具类

1.基于apache-httpclient

需要引入依赖
  <dependency>
      <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpclient</artifactId>
       <version>4.3.5</version>
 </dependency>

工具类如下:

package com.bw.edgeagent.common.util;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.bw.edgeagent.uitl.JSONUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.shaded.okhttp3.OkHttpClient;
import org.testcontainers.shaded.okhttp3.Request;
import org.testcontainers.shaded.okhttp3.RequestBody;
import org.testcontainers.shaded.okhttp3.Response;

import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * @Author MXF
 * @Description Htpp请求工具类
 * @Date 2023/12/21 10:59
 */
public class IotHttpClientUtil {

    private static Logger log = LoggerFactory.getLogger(IotHttpClientUtilbak.class);

    private final static String DEFAULT_ENCODE = "UTF-8";

    /**
     * 服务端返回的cookie,有更新则覆盖
     */
    private static String COOKIE_VALUE = "";

    /**
     * 默认 10s 超时
     */
    private static final int TIME_OUT = 10 * 1000;

    private IotHttpClientUtilbak() {
    }


    /**
     * 忽略 ssl
     *
     * @return
     */
    private static SSLContext buildIgnoreContext() {
        SSLContext sslContext = null;
        try {
            sslContext = SSLContexts.custom().setProtocol("TLSv1.2").build();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            log.error(e.getMessage(), e);
        }

        return sslContext;
    }

    private static CloseableHttpClient getClient(int timeOut) {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(timeOut)
                .setConnectTimeout(timeOut)
                .setSocketTimeout(timeOut)
                .build();

        SSLContext sslContext = buildIgnoreContext();
        // 注册
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslContext))
                .build();
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
        return HttpClients.custom()
                .setConnectionManager(connManager)
                .setDefaultRequestConfig(requestConfig)
                .build();
    }

    /**
     * POST application/json请求
     *
     * @param url     请求地址
     * @param jsonStr 请求数据json字符串
     * @param headers 请求头
     * @param timeOut 超时时间
     * @return
     */
    public static String sendPostJson(String url, String jsonStr, Map<String, String> headers, int timeOut) {
        HttpPost post = new HttpPost(url);
        if (headers != null && headers.size() > 0) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                post.setHeader(entry.getKey(), entry.getValue());
            }
        }
        StringEntity entity = new StringEntity(jsonStr, DEFAULT_ENCODE);
        entity.setContentEncoding(DEFAULT_ENCODE);
        entity.setContentType("application/json;charset=" + DEFAULT_ENCODE);
        post.setEntity(entity);
        return execute(post, timeOut);
    }

    public static String sendDelete(String url, Map<String, String> headers, int timeOut) {

        HttpDelete httpDelete = new HttpDelete(url);
        if (headers != null && headers.size() > 0) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                httpDelete.setHeader(entry.getKey(), entry.getValue());
            }
        }
        return execute(httpDelete, timeOut);
    }

    public static String sendDelete(String url, Map<String, String> headers) {

        return sendDelete(url, headers, TIME_OUT);

    }

    /**
     * POST application/json请求
     *
     * @param url     请求地址
     * @param jsonStr 请求数据json字符串
     * @param headers 请求头
     * @return
     */
    public static String sendPostJson(String url, String jsonStr, Map<String, String> headers) {
        return sendPostJson(url, jsonStr, headers, TIME_OUT);
    }

    /**
     * POST application/json请求
     *
     * @param url     请求地址
     * @param jsonStr 请求数据json字符串
     * @param timeOut 超时时间
     * @return
     */
    public static String sendPostJson(String url, String jsonStr, int timeOut) {
        return sendPostJson(url, jsonStr, new HashMap<>(0), timeOut);
    }

    /**
     * POST application/json请求
     *
     * @param url     请求地址
     * @param jsonStr 请求数据json字符串
     * @return
     */
    public static String sendPostJson(String url, String jsonStr) {
        return sendPostJson(url, jsonStr, TIME_OUT);
    }

    /**
     * POST application/json请求
     *
     * @param url  请求地址
     * @param data 请求数据
     * @return
     */
    public static String sendPostJson(String url, Object data) {
        if (data == null) {
            data = new HashMap(0);
        }
        return sendPostJson(url, JSONUtil.toJsonStr(data));
    }

    /**
     * POST application/json请求
     *
     * @param url          请求地址
     * @param jsonStr      请求数据json字符串
     * @param responseType 返回值类型
     * @return
     * @author lizhenjiang
     * @date 2020/05/30
     */
    public static <T> T postJsonForObject(String url, String jsonStr, Class<T> responseType) {
        String result = sendPostJson(url, jsonStr);
        if (StringUtils.isNotBlank(result)) {
            return JSONUtil.toBean(result, responseType);
        } else {
            return null;
        }
    }

    /**
     * POST application/json请求
     *
     * @param url          请求地址
     * @param jsonStr      请求数据json字符串
     * @param responseType 返回值类型
     * @return
     * @author lizhenjiang
     * @date 2020/05/30
     */
       /* public static <T> T postJsonForObject(String url, String jsonStr, TypeReference<T> responseType) {
            String result = sendPostJson(url, jsonStr);
            if (StringUtils.isNotBlank(result)) {
                return JSONUtil.toBean(result, responseType);
            } else {
                return null;
            }
        }*/

    /**
     * POST application/json请求
     *
     * @param url          请求地址
     * @param data         请求数据
     * @param responseType 返回值类型
     * @return
     * @author lizhenjiang
     * @date 2020/05/30
     */
    public static <T> T postJsonForObject(String url, Object data, Class<T> responseType) {
        if (data == null) {
            data = new HashMap(0);
        }
        return postJsonForObject(url, JSONUtil.toJsonStr(data), responseType);
    }

    /**
     * POST application/json请求
     *
     * @param url          请求地址
     * @param data         请求数据
     * @param responseType 返回值类型
     * @return
     * @author lizhenjiang
     * @date 2020/05/30
     */
    public static <T> T postJsonForObject(String url, Object data, T responseType) {
        if (data == null) {
            data = new HashMap(0);
        }
        return postJsonForObject(url, JSONUtil.toJsonStr(data), responseType);
    }


    /**
     * POST application/x-www-form-urlencoded 请求
     *
     * @param url    请求地址
     * @param params 请求数据map
     * @return
     */
    public static String sendPostForm(String url, Map<String, Object> params) {
        // 手动添加Cookies
        Map<String, String> hearParams = new HashMap<>();
        if (ObjectUtil.isNotEmpty(COOKIE_VALUE)) {
            // 添加Cookie到请求头
            hearParams.put("Cookie", COOKIE_VALUE);
        }
        return sendPostForm(url, params, hearParams);
    }

    /**
     * POST application/x-www-form-urlencoded 请求
     *
     * @param url     请求地址
     * @param params  请求数据map
     * @param timeOut 超时时间
     * @return
     */
    public static String sendPostForm(String url, Map<String, Object> params, int timeOut) {
        Map<String, String> headers = new HashMap<>(1);
        return sendPostForm(url, params, headers, timeOut);
    }

    /**
     * POST application/x-www-form-urlencoded 请求
     *
     * @param url     请求地址
     * @param params  请求数据map
     * @param headers 请求头
     * @return
     */
    public static String sendPostForm(String url, Map<String, Object> params, Map<String, String> headers) {
        return sendPostForm(url, params, headers, TIME_OUT);
    }

    /**
     * POST application/x-www-form-urlencoded 请求
     *
     * @param url     请求地址
     * @param params  请求数据map
     * @param headers 请求头
     * @param timeOut 超时时间
     * @return
     */
    public static String sendPostForm(String url, Map<String, Object> params, Map<String, String> headers, int timeOut) {
        UrlEncodedFormEntity reqEntity = createFormEntity(params);
        HttpPost httppost = new HttpPost(url);
        httppost.addHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                if (StrUtil.equalsAnyIgnoreCase(entry.getKey(), HttpHeaders.CONTENT_LENGTH, HttpHeaders.CONTENT_TYPE)) {
                    continue;
                }
                httppost.addHeader(entry.getKey(), entry.getValue());
            }
        }
        httppost.setEntity(reqEntity);
        return execute(httppost, timeOut);
    }

    /**
     * POST application/x-www-form-urlencoded 请求
     *
     * @param url          请求地址
     * @param params       请求数据map
     * @param responseType 返回值类型
     * @return
     * @author lizhenjiang
     * @date 2020/05/30
     */
/*        public static <T> T postFormForObject(String url, Map<String, String> params, Class<T> responseType) {
            String result = sendPostForm(url, params);
            if (StringUtils.isNotBlank(result)) {
                return JSONUtil.toBean(result, responseType);
            } else {
                return null;
            }
        }*/

    /**
     * POST application/x-www-form-urlencoded 请求
     *
     * @param url          请求地址
     * @param params       请求数据map
     * @param responseType 返回值类型
     * @return
     * @author lizhenjiang
     * @date 2020/05/30
     */
    public static <T> T postFormForObject(String url, Map<String, Object> params, Class<T> responseType) {
        String result = sendPostForm(url, params);
        if (StringUtils.isNotBlank(result)) {
            return JSONUtil.toBean(result, responseType);
        } else {
            return null;
        }
    }

    /**
     * GET 请求
     *
     * @param url     请求地址
     * @param params  请求参数
     * @param timeOut 超时时间
     * @return
     */
    public static String sendGet(String url, Map<String, Object> params, int timeOut) {
        return sendGet(url, params, new HashMap<>(1), timeOut);
    }

    /**
     * GET 请求
     *
     * @param url    请求地址
     * @param params 请求参数
     * @return
     */
    public static String sendGet(String url, Map<String, Object> params) {
        // 手动添加Cookies
        Map<String, String> hearParams = new HashMap<>();
        if (ObjectUtil.isNotEmpty(COOKIE_VALUE)) {
            // 添加Cookie到请求头
            hearParams.put("Cookie", COOKIE_VALUE);
        }
        return sendGet(url, params, hearParams);
    }

    /**
     * GET 请求
     *
     * @param url     url
     * @param params  请求参数
     * @param headers 请求头
     * @param timeOut 超时时间
     * @return
     */
    public static String sendGet(String url, Map<String, Object> params, Map<String, String> headers, int timeOut) {
        if (url == null) {
            return null;
        }
        try {
            URIBuilder uriBuilder = new URIBuilder(url);
            if (null != params) {
                uriBuilder.setParameters(getNameValuePairList(params));
            }
            URI uri = uriBuilder.build();
            String rawQueryString = uri.getRawQuery();
            //拼接url
            if (StringUtils.isNotBlank(rawQueryString)) {
                // 防止原本url里面就有参数
                if (!url.contains("?")) {
                    url = url + "?";
                }
                if (url.endsWith("?")) {
                    url = url + rawQueryString;
                } else {
                    url = url + "&" + rawQueryString;
                }
            }
            HttpGet httpGet = new HttpGet(url);
            if (headers != null) {
                Set<Map.Entry<String, String>> entrySet = headers.entrySet();
                for (Map.Entry<String, String> entry : entrySet) {
                    httpGet.setHeader(entry.getKey(), entry.getValue());
                }
            }
            return execute(httpGet, timeOut);
        } catch (URISyntaxException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * GET 请求
     *
     * @param url     请求地址
     * @param params  请求参数
     * @param headers 请求头
     * @return
     */
    public static String sendGet(String url, Map<String, Object> params, Map<String, String> headers) {
        return sendGet(url, params, headers, TIME_OUT);
    }


    /**
     * GET 请求
     *
     * @param url          请求地址
     * @param params       请求参数
     * @param responseType 返回值类型
     * @return
     * @author lizhenjiang
     * @date 2020/05/30
     */
    public static <T> T getForObject(String url, Map<String, Object> params, Class<T> responseType) {
        String result = sendGet(url, params);
        if (StringUtils.isNotBlank(result)) {
            return JSONUtil.toBean(result, responseType);
        } else {
            return null;
        }
    }

    private static List<NameValuePair> getNameValuePairList(Map<String, Object> params) {
        List<NameValuePair> list = new ArrayList<>();
        try {
            if (params != null && !params.isEmpty()) {
                for (String key : params.keySet()) {
                    String value = params.get(key).toString();
                    if (value != null) {
                        list.add(new BasicNameValuePair(key, value));
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return list;
    }

    private static UrlEncodedFormEntity createFormEntity(Map<String, Object> pram) {
        try {
            List<NameValuePair> formParams = getNameValuePairList(pram);
            return new UrlEncodedFormEntity(formParams, DEFAULT_ENCODE);
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    private static String execute(HttpRequestBase requestBase, int timeOut) {
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = getClient(timeOut);
        try {

            // 执行
            long start = System.currentTimeMillis();
            response = httpClient.execute(requestBase);
            //Header[] headers = response.getAllHeaders();
            //获取服务端返回的cookie并设置到全局变量,下一次发起请求使用,有更新则覆盖
            Header[] cookies = response.getHeaders("Set-Cookie");
            if (ObjectUtil.isNotEmpty(cookies)) {
                System.out.println(cookies);
                StringBuilder cookieValue = new StringBuilder();
                for (Header h : cookies) {
                    cookieValue.append(h.getValue());
                }
                COOKIE_VALUE = cookieValue.toString();
            }
            log.info("请求id: {} , url: {} , 耗时: {} ", requestBase.getURI().toString(), (System.currentTimeMillis() - start));
            HttpEntity entity = response.getEntity();
            reader = new BufferedReader(new InputStreamReader(entity.getContent(), DEFAULT_ENCODE));
            String line = reader.readLine();
            while (line != null) {
                sb.append(line);
                line = reader.readLine();
            }
            EntityUtils.consume(entity);

        } catch (Exception e) {
            log.error("远程调用异常", e);
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (response != null) {
                    response.close();
                }
                httpClient.close();
            } catch (IOException e) {
                log.error("", e);
            }

        }
        return sb.toString();
    }


    /**
     * POST   multipart/form-data  请求
     *
     * @param requestUrl
     * @param body
     * @return
     */
    public static String sendPostWithFile(String requestUrl, RequestBody body) {
        try {
            OkHttpClient client = new OkHttpClient().newBuilder().build();
            Request request = new Request.Builder()
                    .url(requestUrl)
                    .method("POST", body)
                    .addHeader("Content-Type", "multipart/form-data")
                    .build();
            Response response = client.newCall(request).execute();
            if (response.body() == null) {
                log.info("短信发送httpClent获取数据为空");
                return null;
            }
            log.info("from-data:" + response.body().toString());
            return response.body().string();
        } catch (Exception e) {
            log.info("******短信发送httpClent  请求出错****" + e.getMessage());
        } finally {

        }
        return null;
    }
}

2.基于jdk11

工具类代码如下:

package com.bw.edgeagent.common.util;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.List;
import java.util.Map;

/**
 * @Author MXF
 * @Description Htpp请求工具类
 * @Date 2023/12/21 10:59
 */
public class IotHttpUtil {


    private final static String DEFAULT_ENCODE = "UTF-8";

    /**
     * 服务端返回的cookie,有更新则覆盖
     */
    private static String COOKIE_VALUE = "";

    /**
     * 默认 10s 超时
     */
    private static final int TIME_OUT = 10 * 1000;

    private IotHttpUtil() {
    }

    /**
     * 发送GET请求
     *
     * @param url
     * @return
     */
    public static String get(String url) {
        return get(url, null);
    }

    /**
     * 发送GET请求
     *
     * @param url
     * @param params
     * @return
     */
    public static String get(String url, Map<String, String> params) {

        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(URI.create(buildUrlWithParams(url, params)));
        if (ObjectUtil.isNotEmpty(COOKIE_VALUE)) {
            //手动添加Cookies,添加Cookie到请求头
            requestBuilder.header("Cookie", COOKIE_VALUE);
        }
        HttpRequest request = requestBuilder.header("Content-Type", "application/x-www-form-urlencoded").GET().build();
        return send(request);
    }

    /**
     * 给访问路径拼接参数
     *
     * @param url
     * @param params
     * @return
     */
    private static String buildUrlWithParams(String url, Map<String, String> params) {
        if (params == null || params.isEmpty()) {
            return url;
        }

        StringBuilder sb = new StringBuilder(url);
        // 若已有参数则和之前的参数合并
        sb.append(url.indexOf('?') == -1 ? '?' : '&');

        // 循环拼接参数
        params.forEach((key, value) -> {
            if (StrUtil.isNotBlank(value)) {
                try {
                    value = URLEncoder.encode(value, Charset.defaultCharset());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                sb.append(key).append('=').append(value).append('&');
            }
        });

        // 去掉最后的&
        return sb.substring(0, sb.length() - 1);
    }

    /**
     * 发送POST请求
     *
     * @param url
     * @param data
     * @return
     */
    public static String post(String url, String data) {
        return post(url, data, null);
    }

    /**
     * 发送POST请求
     *
     * @param url
     * @param data
     * @param params
     * @return
     */
    public static String post(String url, String data, Map<String, String> params) {
        HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(URI.create(buildUrlWithParams(url, params)));
        if (ObjectUtil.isNotEmpty(COOKIE_VALUE)) {
            //手动添加Cookies,添加Cookie到请求头
            requestBuilder.header("Cookie", COOKIE_VALUE);
        }
        HttpRequest request = requestBuilder.header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(data, Charset.forName(Charset.defaultCharset().toString()))).build();
        return send(request);
    }

    /**
     * 发送带本地证书的POST请求
     *
     * @param url
     * @param data
     * @param certFile
     * @param certPwd
     * @return
     */
    public static String postWithCertificate(String url, String data, File certFile, char[] certPwd) {
        HttpRequest request = HttpRequest.newBuilder(URI.create(url))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(data, Charset.forName(Charset.defaultCharset().toString()))).build();

        try {
            // 实例化SSL上下文
            SSLContext sslContext = SSLContext.getInstance("TLS");
            // 实例化密钥管理工厂
            KeyManagerFactory keyManagerFactory = KeyManagerFactory
                    .getInstance(KeyManagerFactory.getDefaultAlgorithm());
            // 实例化密钥库
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            // 加载证书文件和密码
            keyStore.load(new FileInputStream(certFile), certPwd);
            // 初始化密钥管理工厂
            keyManagerFactory.init(keyStore, certPwd);
            // 初始化SSL上下文
            sslContext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
            // 构建HTTP客户端实例
            HttpClient client = HttpClient.newBuilder().sslContext(sslContext).build();
            return client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body).get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送http请求
     *
     * @param request
     * @return
     */
    private static String send(HttpRequest request) {
        HttpClient client = HttpClient.newHttpClient();

        try {

            HttpResponse<String> res = client.send(request, HttpResponse.BodyHandlers.ofString());
            HttpHeaders headers = res.headers();
            List<String> cookies = headers.allValues("set-cookie");
            //获取服务端返回的cookie并设置到全局变量,下一次发起请求使用,有更新则覆盖
            if (ObjectUtil.isNotEmpty(cookies)) {
                System.out.println(cookies);
                StringBuilder cookieValue = new StringBuilder();
                for (String c : cookies) {
                    cookieValue.append(c);
                }
                COOKIE_VALUE = cookieValue.toString();
            }
            return res.body();
        } catch (InterruptedException | IOException e) {
            throw new RuntimeException(e);
        }
    }

//    public static void main(String[] args) {
//        Map<String, String> loginParamMap = new HashMap<>();
//        loginParamMap.put("username", "admin");
//        //密码admin 密码MD5加密32位
//        String password = DigestUtil.md5Hex("admin");
//        loginParamMap.put("password", password);
//        //String res = HttpUtil.sendGet(WVP_URL + WvpVideoUrlEnums.登录.getUrl(), HttpUtil.asUrlParams(loginParamMap));
//        String res = get("http://10.1.7.33:38080" + WvpVideoUrlEnums.登录.getUrl(), loginParamMap);
//        System.out.println("登录结果----->" + res);
//    }

}

说明:写这两个工具类的起因是客户端发起请求登录服务端成功后,后续请求需要携带服务端返回的响应头cookie会话信息来鉴权,否则后续请求会报401

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值