由于经常需要通过后台服务端发起接口请求,在联调过程中借助HttpClientUtil工具类进行发送两位常见的网络请求,并且对返回的json结果集进行解析。作此文以方便后续查阅和学习,留个档。备注:后续可以直接使用hutool的HttpUtil工具类进行统一调用处理更为方便,详见第三章节的推荐。
一、HttpClientUtil
<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": "浙江省 杭州市 浙江大学",
}
]
<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格式的数据传输变得越来越普遍。
参考资料: