HttpClientUtil发送Post/Get请求,使用fastjson解析json结果集

由于经常需要通过后台服务端发起接口请求,在联调过程中借助HttpClientUtil工具类进行发送两位常见的网络请求,并且对返回的json结果集进行解析。作此文以方便后续查阅和学习,留个档。备注:后续可以直接使用hutool的HttpUtil工具类进行统一调用处理更为方便,详见第三章节的推荐。

一、HttpClientUtil

  • pom依赖
<dependency>
	<groupId>org.wso2.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.3.1.wso2v1</version>
</dependency>
  • 工具类内容

由于该工具类来自于另一位开源贡献值,故保留原作者信息。

package com.vainycos.utils;

import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpClientUtil {

    /**
     * @Auther: gengshuai@cetiti.com
     * @Description: 带参数GET请求
     * @Param: [url, param]
     * @Return: java.lang.String
     * @Create: 2018-9-21 9:03
     */
    public static String doGet(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

    /**
     * @Auther: gengshuai@cetiti.com
     * @Description: 带参数和请求头的GET请求
     * @Param: [url, param, header]
     * @Return: java.lang.String
     * @Create: 2018-9-25 20:09
     */
    public static String doGet(String url, Map<String, String> param, Map<String, String> header) {
        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key).toString());
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);

            if (header != null) {
                for (String key : header.keySet()) {
                    httpGet.setHeader(key, header.get(key).toString());
                }
            }

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

    /**
     * @Auther: gengshuai@cetiti.com
     * @Description: 无参GET请求
     * @Param: [url]
     * @Return: java.lang.String
     * @Create: 2018-9-21 9:05
     */
    public static String doGet(String url) {
        return doGet(url, null);
    }

    /**
     * @Auther: gengshuai@cetiti.com
     * @Description: application/x-www-form-urlencoded编码方式带参POST请求
     * @Param: [url, param]
     * @Return: java.lang.String
     * @Create: 2018-9-21 9:05
     */
    public static String doPost(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"utf-8");
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return resultString;
    }

    /**
     * @Auther: gengshuai@cetiti.com
     * @Description: application/x-www-form-urlencoded编码方式带参数和请求头的POST请求
     * @Param: [url, param, header]
     * @Return: java.lang.String
     * @Create: 2018-9-27 14:54
     */
    public static String doPost(String url, Map<String, String> param, Map<String, String> header) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);

            //添加请求头信息
            if (header != null) {
                for (String key : header.keySet()) {
                    httpPost.setHeader(key, header.get(key).toString());
                }
            }
            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"utf-8");
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

    /**
     * @Auther: gengshuai@cetiti.com
     * @Description: application/x-www-form-urlencoded编码方式无参POST请求
     * @Param: [url]
     * @Return: java.lang.String
     * @Create: 2018-9-21 9:10
     */
    public static String doPost(String url) {
        return doPost(url, null);
    }

    /**
     * @Auther: gengshuai@cetiti.com
     * @Description: application/json编码方式POST请求
     * @Param: [url, json]
     * @Return: java.lang.String
     * @Create: 2018-9-21 9:11
     */
    public static String doPostJson(String url, String json) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return resultString;
    }

    /**
     * @Auther: gengshuai@cetiti.com
     * @Description: application/json编码方式带请求头POST请求
     * @Param: [url, json, header]
     * @Return: java.lang.String
     * @Create: 2018-9-27 15:19
     */
    public static String doPostJson(String url, String json, Map<String, String> header) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);

            //添加请求头信息
            if (header != null) {
                for (String key : header.keySet()) {
                    httpPost.setHeader(key, header.get(key).toString());
                }
            }

            // 创建请求内容
            StringEntity entity = new StringEntity(json, "utf-8");
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

}

二、fastjson解析Json结果集

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

我们在调用了HttpClientUtil发起请求后,一般被调用端会返回一个标准结果集,以前用的最多的是XML格式的结果集,但是现在使用Json作为返回结果是最普遍的。于是我们就需要对Json字符串进行解析。
例如解析如下Json字符串:

	"name": "Vainycos",
	"success": true,
	"detail": [
		{
			"age": 24,
			"phone": "13556789012",
			"school": "浙江省 杭州市 浙江大学",
		}
	]
  • pom依赖
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.58</version>
</dependency>
  • 解析过程
public class HttpTest {
	public static JSONObject search(){
        Map<String,String> params = new HashMap<>();
        // 请求参数
        params.put("name","Vainycos");
        // 发送查找用户请求,假设返回的字符串result即是上述的json字符串
        String result = HttpClientUtil.doGet("http://www.vainycos/searchUser",params);
        //进行解析 将字符串转化为JSONObject,即json对象
        JSONObject jsonObject = JSON.parseObject(result);
        // name节点的值
        String name = jsonObject.get("name");
        // success节点的值
        String success= jsonObject.get("success");
        // 除了普通节点之外,还有一个detail属性,这其实是一个数组,我们进行转义成JSONArray对象
        JSONArray jsonArray = (JSONArray)jsonObject.get("detail");
        // 由于我们这个数组只有一个 所以直接取第一个即可
        JSONObject detail = (JSONObject)jsonArray.get(0);
        // 这个时候我们就可以取到detail节点中的值,例如detail中的school节点
        String school = detail.get("school");
        return jsonObject;
    }
}

以上就是基本的借助fastjson解析json字符串的方法。我们接下来再介绍将json字符串解析到我们的java对象中的方法。
首先我们要知道返回的json内容,假设返回的json内容还是:

	"name": "Vainycos",
	"success": true,
	"detail": [
		{
			"age": 24,
			"phone": "13556789012",
			"school": "浙江省 杭州市 浙江大学",
		}
	]

通过观察该json字符串,可以发现该json分成两部分,name、success这两个节点为一个部分,detail节点为一个部分。这时候我们就明确了,用一个User对象承载基本信息,并且在User对象中有一个List列表承载的是UserDetail对象,即用户详细信息。并且通过观察各个节点的值可以发现,success节点对应的java变量值应该为boolean,detail中的age节点应该是int,其他都为String。接下来我们开始塑造对应该json字符串的java对象:

package com.vainycos.domin;

import lombok.Data;
import java.util.List;

/**
 * @author imvainycos
 * @data 2019/6/25 10:10
 **/
@Data
public class User {

    private String name;

    private boolean success;

    private List<UserDetail> detail;
}
package com.vainycos.domin;

import lombok.Data;
import java.util.List;

/**
 * @author imvainycos
 * @data 2019/6/25 10:10
 **/
@Data
public class User {
	private int age;
	private String phone;
	private String school;
}

@Data注解是lombok依赖提供的,方便我们不用在每个java对象中写get/set方法,是非常实用的一个注解,能够使得对象类看上去简洁明了。lombok的maven依赖如下:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>provided</scope>
</dependency>

正式开始json字符串解析成java对象:

public class HttpTest {
	public static User search(){
        Map<String,String> params = new HashMap<>();
        // 请求参数
        params.put("name","Vainycos");
        // 发送查找用户请求,假设返回的字符串result即是上述的json字符串
        String result = HttpClientUtil.doGet("http://www.vainycos/searchUser",params);
        // 使用parseObject的重载方法,将json字符串解析成对应的java对象
        User user= JSON.parseObject(result, User.class);
        return User;
    }
}

三、推荐

推荐使用hutool工具类的HttpUtil工具类。

<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-http -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-http</artifactId>
    <version>5.8.18</version>
</dependency>

简单使用:

HttpResponse execute = HttpUtil.createGet("http://localhost:8080/test")
                .form(paramMap)
                .header(Header.AUTHORIZATION, "token")
                .timeout(3000)
                .execute();
// 通常返回json结果,进行解析该json字符串作为返回结果
String result = execute.body();
HttpResponse execute = HttpUtil.createPost("http://localhost:8080/test")
                .body(body)
                .header(Header.AUTHORIZATION, "token")
                .timeout(3000)
                .execute();
// 通常返回json结果,进行解析该json字符串作为返回结果
String result = execute.body();

四、总结

使用HttpClientUtil工具类进行简单的发送post/get请求,并能够对返回的json结果集进行正确解析。需要明确json字符串的各个节点属性之后再开始解析,并创建合适的java对象进行装载。熟练解析json字符串是必不可少的一项技能,尤其是现在json格式的数据传输变得越来越普遍。

参考资料:

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先,需要在 `pom.xml` 文件中添加以下依赖: ```xml <dependencies> <!-- Spring Boot Web Starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Boot Test Starter --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Apache HttpClient 5 --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient5</artifactId> <version>5.1.2</version> </dependency> <!-- Fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.78</version> </dependency> </dependencies> ``` 然后,创建一个 `RestTemplate` 的 Bean: ```java import org.apache.hc.client5.http.async.methods.SimpleHttpRequests; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer; import org.apache.hc.core5.concurrent.FutureCallback; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.Method; import org.apache.hc.core5.http.nio.support.BasicRequestProducer; import org.apache.hc.core5.http.nio.support.BasicResponseConsumer; import org.apache.hc.core5.http.protocol.HttpContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.client.HttpComponentsAsyncClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.client.AsyncRestTemplate; import org.springframework.web.client.RestTemplate; import java.util.Arrays; import java.util.Collections; import java.util.concurrent.Future; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); headers.setContentType(MediaType.APPLICATION_JSON); restTemplate.setInterceptors(Collections.singletonList(new RestTemplateHeaderModifierInterceptor(headers))); // 设置请求和响应的消息转换器 MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)); restTemplate.setMessageConverters(Collections.singletonList(converter)); // 设置请求工厂 HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setConnectTimeout(10000); requestFactory.setReadTimeout(10000); restTemplate.setRequestFactory(requestFactory); return restTemplate; } @Bean public AsyncRestTemplate asyncRestTemplate() { AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(); // 设置请求头 HttpHeaders headers = new HttpHeaders(); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); headers.setContentType(MediaType.APPLICATION_JSON); asyncRestTemplate.setInterceptors(Collections.singletonList(new RestTemplateHeaderModifierInterceptor(headers))); // 设置请求和响应的消息转换器 MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN)); asyncRestTemplate.setMessageConverters(Collections.singletonList(converter)); // 设置请求工厂 HttpComponentsAsyncClientHttpRequestFactory requestFactory = new HttpComponentsAsyncClientHttpRequestFactory(); requestFactory.setConnectTimeout(10000); requestFactory.setReadTimeout(10000); asyncRestTemplate.setAsyncRequestFactory(requestFactory); return asyncRestTemplate; } private static class RestTemplateHeaderModifierInterceptor implements org.springframework.http.client.ClientHttpRequestInterceptor { private final HttpHeaders headers; public RestTemplateHeaderModifierInterceptor(HttpHeaders headers) { this.headers = headers; } @Override public org.springframework.http.client.ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { headers.forEach((key, value) -> request.getHeaders().put(key, value)); return execution.execute(request, body); } } } ``` 其中,`RestTemplateHeaderModifierInterceptor` 是用来设置请求头的拦截器,`MappingJackson2HttpMessageConverter` 是用来转换请求和响应消息的消息转换器,`HttpComponentsClientHttpRequestFactory` 和 `HttpComponentsAsyncClientHttpRequestFactory` 是用来配置请求工厂的。 在上面的代码中,我同时定义了同步和异步的 `RestTemplate`,你可以根据需要选择其中一个。 使用示例: ```java import com.alibaba.fastjson.JSONObject; import org.apache.http.entity.ContentType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.*; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.client.RestTemplate; import java.util.HashMap; import java.util.Map; @Controller @RequestMapping("/test") public class TestController { @Autowired private RestTemplate restTemplate; @GetMapping("/sync") @ResponseBody public String testSync() { String url = "https://jsonplaceholder.typicode.com/todos/1"; ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class); return responseEntity.getBody(); } @GetMapping("/async") @ResponseBody public String testAsync() throws Exception { String url = "https://jsonplaceholder.typicode.com/todos/1"; Future<ResponseEntity<String>> future = restTemplate.exchange(url, HttpMethod.GET, null, String.class); ResponseEntity<String> responseEntity = future.get(); return responseEntity.getBody(); } } ``` 上面的示例中,我使用 `RestTemplate` 发送了一个 GET 请求,请求的 URL 是 `https://jsonplaceholder.typicode.com/todos/1`,并且指定了响应消息的类型为 `String`。如果你需要发送 POST 请求,只需要将 `HttpMethod.GET` 改为 `HttpMethod.POST`,并且设置请求体即可。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值