[RestTemplate] 配置 及 调用POST GET请求 demo

13 篇文章 0 订阅

目录

01. RestTemplate简介

A). 简要说明

B). RestTemplate有两个构造方法

C). ClientHttpRequestFactory的两种实现

02. Spring的RestTemplate对Post/Get的常用接口

A). Post请求API

B). Get请求API

03. 配置及使用

A). 配置文件

B). 测试使用

附录及示例: 

A). pom.xml

B). RestClient.java  /  spring-restTemplate.xml

C). TestGetMain.java

D). TestPostMain.java

附录二, httpClient参考网址


01. RestTemplate简介

A). 简要说明

RestTemplate是Spring提供的用于访问Rest服务的客户端, RestTemplate提供了多种便捷访问远程Http服务的方法, 能够大大提高客户端的编写效率.

B). RestTemplate有两个构造方法

    分别是:
        a). 第一个构造方法为默认初始化, 无法控制超时时间;

        b). 第二个构造方法可以传入ClientHttpRequestFactory参数, 设置该工厂类的timeout属性可以控制超时时间;

    结论: 由于我们经常需要对请求超时进行设置并进行后续处理, 因此选用第二个构造方法.

C). ClientHttpRequestFactory的两种实现

        a). SimpleClientHttpRequestFactory: 使用J2SE提供的方式(java.net包提供的方式)创建底层的Http请求连接;
        b). HttpComponentsClientHttpRequestFactory: 使用HttpClient访问远程的Http服务, 使用HttpClient可以配置连接池证书等信息. 
    注意: RestTemplate默认是使用SimpleClientHttpRequestFactory,内部是调用jdk的HttpConnection, 默认超时为-1

02. Spring的RestTemplate对Post/Get的常用接口

A). Post请求API

public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables) throws RestClientException
public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException
public <T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException

B). Get请求API

public <T> T getForObject(String url, Class<T> responseType, Object... urlVariables) throws RestClientException 
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> urlVariables) throws RestClientException
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException
例如: 
String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", String.class,"42", "21");

String message = restTemplate.getForObject("http://localhost:8080/yongbarservice/appstore/appgoods/restTemplate?name=zhaoshijie&id=80", String.class);

Map<String, String> vars = Collections.singletonMap("hotel", "42");
String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);

03. 配置及使用

A). 配置文件

        pom.xml
        RestClient.java
        spring-restTemplate.xml

B). 测试使用

        TestGetMain.java
        TestPostMain.java

附录及示例

A). pom.xml

主要关注需要引入的jar包, jar包版本过低会出现很多问题,  什么版本合适请自行处理; 懒人请按如下或更高版本操作...

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cntv.learn</groupId>
    <artifactId>restTemplate_v3.0</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <junit.version>4.12</junit.version>
        <slf4j.version>1.7.25</slf4j.version>
        <spring.version>4.3.18.RELEASE</spring.version>
        <jackson.version>2.9.4</jackson.version>
        <fastjson.version>1.2.47</fastjson.version>
        <httpclient.version>4.5.2</httpclient.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
        <!-- 映入JSON -->
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>${httpclient.version}</version>
        </dependency>
    </dependencies>

</project>

B). RestClient.java  /  spring-restTemplate.xml

根据使用工厂类的不同(SimpleClientHttpRequestFactory, 或者 HttpComponentsClientHttpRequestFactory), 配置 

restTemplate分为两种, 具体配置如下: 

01-01. spring-restTemplate.xml 使用 SimpleClientHttpRequestFactory 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd"
       default-autowire="byName" default-lazy-init="true">

    <!--方式一、使用jdk的实现-->
    <bean id="ky.requestFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory">
        <property name="readTimeout" value="10000"/>
        <property name="connectTimeout" value="5000"/>
    </bean>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <constructor-arg ref="ky.requestFactory"/>
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <value>text/plain;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
            </list>
        </property>
    </bean>

</beans>

01-02. RestClient.java 使用 SimpleClientHttpRequestFactory  

package com.cntv.learn.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * @author LiuDong
 * @msg 第一种以类的方式获取restTemplate
 */
@Component
@Lazy(false)
public class RestClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(RestClient.class);

    private static RestTemplate restTemplate;

    static {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setReadTimeout(5000);
        requestFactory.setConnectTimeout(5000);

        // 添加转换器
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        messageConverters.add(new FormHttpMessageConverter());
        messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
        messageConverters.add(new MappingJackson2HttpMessageConverter());
        messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));

        restTemplate = new RestTemplate(messageConverters);
        restTemplate.setRequestFactory(requestFactory);
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());

        LOGGER.info("SimpleRestClient初始化完成");
    }

    private RestClient() {

    }

    @PostConstruct
    public static RestTemplate getClient() {
        return restTemplate;
    }

}

02-01. spring-restTemplate.xml 使用 HttpComponentsClientHttpRequestFactory

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd"
       default-autowire="byName" default-lazy-init="true">

    <!--方式二: 使用httpclient的实现,带连接池(在httpclient4.3版本后才有)-->
    <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
        <property name="connectionManager">
            <bean class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
                <!--整个连接池的并发-->
                <property name="maxTotal" value="50"/>
                <!--每个主机的并发-->
                <property name="defaultMaxPerRoute" value="50"/>
            </bean>
        </property>
        <!--开启重试-->
        <property name="retryHandler">
            <bean class="org.apache.http.impl.client.DefaultHttpRequestRetryHandler">
                <constructor-arg value="2"/>
                <constructor-arg value="true"/>
            </bean>
        </property>
        <property name="defaultHeaders">
            <list>
                <bean class="org.apache.http.message.BasicHeader">
                    <constructor-arg value="Content-Type"/>
                    <constructor-arg value="text/html;charset=UTF-8"/>
                </bean>
                <bean class="org.apache.http.message.BasicHeader">
                    <constructor-arg value="Accept-Encoding"/>
                    <constructor-arg value="gzip,deflate"/>
                </bean>
                <bean class="org.apache.http.message.BasicHeader">
                    <constructor-arg value="Accept-Language"/>
                    <constructor-arg value="zh-CN"/>
                </bean>
            </list>
        </property>
    </bean>

    <bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build"/>

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <property name="messageConverters">
            <list value-type="org.springframework.http.converter.HttpMessageConverter">
                <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                    <property name="supportedMediaTypes" value="application/json;charset=UTF-8" />
                </bean>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                    <!--<property name="supportedMediaTypes" value="text/html;charset=UTF-8" />-->
                    <property name="supportedMediaTypes">
                        <list>
                            <value>text/html;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
            </list>
        </property>
        <property name="requestFactory">
            <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
                <constructor-arg ref="httpClient"/>
                <!--连接时间(毫秒)-->
                <property name="connectTimeout" value="20000"/>
                <!--读取时间(毫秒)-->
                <property name="readTimeout" value="20000"/>
            </bean>
        </property>
    </bean>

</beans>

02-02. RestClient.java 使用 HttpComponentsClientHttpRequestFactory

package com.cntv.learn.client;

import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
@Lazy(false)
public class RestClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(RestClient.class);

    private static RestTemplate restTemplate;

    static {
        // 长连接保持30秒
        PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
        // 总连接数
        pollingConnectionManager.setMaxTotal(1000);
        // 同路由的并发数
        pollingConnectionManager.setDefaultMaxPerRoute(1000);

        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.setConnectionManager(pollingConnectionManager);
        // 重试次数,默认是3次,没有开启
        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));
        // 保持长连接配置,需要在头添加Keep-Alive
        httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());

        List<Header> headers = new ArrayList<>();
        headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
        headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
        headers.add(new BasicHeader("Accept-Language", "zh-CN"));
        headers.add(new BasicHeader("Connection", "Keep-Alive"));

        httpClientBuilder.setDefaultHeaders(headers);

        HttpClient httpClient = httpClientBuilder.build();

        // httpClient连接配置,底层是配置RequestConfig
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        // 连接超时
        clientHttpRequestFactory.setConnectTimeout(5000);
        // 数据读取超时时间,即SocketTimeout
        clientHttpRequestFactory.setReadTimeout(5000);
        // 连接不够用的等待时间,不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的
        clientHttpRequestFactory.setConnectionRequestTimeout(200);
        // 缓冲请求数据,默认值是true。通过POST或者PUT大量发送数据时,建议将此属性更改为false,以免耗尽内存。
//        clientHttpRequestFactory.setBufferRequestBody(false);

        // 添加内容转换器
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        messageConverters.add(new FormHttpMessageConverter());
        messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
        messageConverters.add(new MappingJackson2HttpMessageConverter());
        messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));

        restTemplate = new RestTemplate(messageConverters);
        restTemplate.setRequestFactory(clientHttpRequestFactory);
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());

        LOGGER.info("RestClient初始化完成");
    }

    private RestClient() {

    }

    @PostConstruct
    public static RestTemplate getClient() {
        return restTemplate;
    }

}

C). TestGetMain.java

参照 调用Get请求接口API , spring-restTemplate.xml的调用如下: 

package com.cntv.learn;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

/**
 * @author : LiuDong
 * @description : 莉莉
 * @date : Created in 2018/7/10 15:05
 */
public class TestGetMain {
    private static final Logger LOGGER = LoggerFactory.getLogger(TestGetMain.class);

    public static void main(String[] args) {
        // 获取app上下文
        String configLocation = "config/spring-restTemplate.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
        // 获取userService对象
        RestTemplate restTemplate = (RestTemplate) context.getBean("restTemplate");

        testRestTemplateForPostV2(restTemplate);
    }

    /**
     * 方式一: 调用Get请求
     *         text请求, json响应
     * @param restTemplate 调用http请求
     */
    private static void testRestTemplateForPostV2(RestTemplate restTemplate) {
        // 1-1. . 请求参数
//        Map<String, String> urlVariables = new HashMap<>();
//        urlVariables.put("host", ""www.lala.com");
        String urlVariables = "www.lala.com";
        // 1-2. 请求地址
        String url = "http://{host}/projectName/saveSxPolicy?username=ss&age=18";

        // 2-0. 调用
        JSONObject exchange;
        try {
            exchange = restTemplate.getForObject(url, JSONObject.class, urlVariables);
            LOGGER.info(exchange.toString());
            System.out.println(exchange.toString());
        } catch (RestClientException e) {
            LOGGER.info("请求失败...");
            System.out.println("请求失败: " + e.getMessage());
        }
    }
}

D). TestPostMain.java

参照 调用Post请求接口API , spring-restTemplate.xml的调用如下: 

package com.cntv.learn;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

/**
 * @author : LiuDong
 * @description : 莉莉
 * @date : Created in 2018/7/10 15:05
 */
public class TestPostMain {
    private static final String TOKEN = "3ffe8a64-10cf-4d0e-b7f3-0efc05824376";
    private static final Logger LOGGER = LoggerFactory.getLogger(TestPostMain.class);

    public static void main(String[] args) {
        // 获取app上下文
        String configLocation = "config/spring-restTemplate.xml";
        ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
        // 获取userService对象
        RestTemplate restTemplate = (RestTemplate) context.getBean("restTemplate");

        testRestTemplateForPostV1(restTemplate);
        testRestTemplateForPostV2(restTemplate);
    }

    /**
     * 方式一: 调用JSON的Post请求
     * @param restTemplate 调用http请求
     */
    private static void testRestTemplateForPostV1(RestTemplate restTemplate) {
        // 1-1. 请求头信息
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        // 1-2. . 请求参数
        JSONObject postParameters = new JSONObject();
//        ParameterRo postParameters = new ParameterRo();
//        Map<String, String> postParameters = new HashMap<>(3);
        postParameters.put("openid", "opentid_test");
        HttpEntity<JSONObject> requestEntity = new HttpEntity<>(postParameters, headers);
        // 1-3. 请求地址
        String url = "http://www.lala.com/projectPoth/saveIPAndAddress";

        // 2-0. 调用
        JSONObject exchange;
        try {
            exchange = restTemplate.postForObject(url, requestEntity, JSONObject.class);
            LOGGER.info(exchange.toString());
            System.out.println(exchange.toString());
        } catch (RestClientException e) {
            LOGGER.info("请求失败...");
            System.out.println("请求失败: " + e.getMessage());
        }
    }

    /**
     * 方式二: 调用普通Post请求(简单版)
     *         text请求, json响应
     * @param restTemplate 调用http请求
     */
    private static void testRestTemplateForPostV2(RestTemplate restTemplate) {
        // 1-1. . 请求参数
        MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
        requestEntity.set("token", TOKEN);
        // 1-2. 请求地址
        String url = "http://www.lala.com/project/searchGroupOrgList";

        // 2-0. 调用
        JSONArray exchange;
        try {
            exchange = restTemplate.postForObject(url, requestEntity, JSONArray.class);
            LOGGER.info(exchange.toString());
            System.out.println(exchange.toString());
        } catch (RestClientException e) {
            LOGGER.info("请求失败...");
            System.out.println("请求失败: " + e.getMessage());
        }
    }


    /**
     * 模拟请求参数
     */
    static private class ResponseVo {
        private String code = "0";
        private String errMsg = "请求失败...";
        private Object data;

        public String getCode() {
            return code;
        }
        public void setCode(String code) {
            this.code = code;
        }
        public String getErrMsg() {
            return errMsg;
        }
        public void setErrMsg(String errMsg) {
            this.errMsg = errMsg;
        }
        public Object getData() {
            return data;
        }
        public void setData(Object data) {
            this.data = data;
        }
    }
}

附录二, httpClient参考网址

httpclient调用http请求学习: https://www.cnblogs.com/fengli9998/p/8028250.html 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值