Apache HttpClient
1.简单架构
前后分离/安全
开发维护方便
分布式系统的雏形形态
2.Apache HttpClient介绍
HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient。
HTMLUnit可以用来做爬虫的。Jsoup比他跟简洁。使用python语言进行爬虫.开箱即用。
HttpClient
相比传统 JDK
自带的 URLConnection
,增加了易用性和灵活性,它不仅是客户端发送 HTTP
请求变得容易,而且也方便了开发人员测试接口(基于HTTP
协议的),即提高了开发的效率,也方便提高代码的健壮性。因此熟练掌握 HttpClient
是很重要的必修内容,掌握 HttpClien
t 后,相信对于 HTTP
协议的了解会更加深入。
3.Apache HttpClient特点
- 基于标准、纯净的
Java
语言。实现了HTTP 1.0
和HTTP 1.1
- 以可扩展的面向对象的结构实现了
HTTP
全部的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)
。 - 支持
HTTPS
协议。 - 通过
HTTP
代理建立透明的连接。 - 利用
CONNECT
方法通过HTTP
代理建立隧道的HTTPS
连接。 - Basic, Digest, NTLMv1, NTLMv2, NTLM2 Session, SNPNEGO/Kerberos` 认证方案。
- 插件式的自定义认证方案。
- 便携可靠的套接字 (socket) 工厂使它更容易的使用第三方解决方案。
- 连接管理器支持多线程应用。支持设置最大连接数,同时支持设置每个主机的最大连接数,发现并关闭过期的连接(支持并发请求)。
- 自动处理
Set-Cookie
中的Cookie
。(可以管理cookie) - 插件式的自定义
Cookie
策略。 Request
的输出流可以避免流中内容直接缓冲到Socket
服务器。Response
的输入流可以有效的从Socket
服务器直接读取相应内容。- 在
HTTP 1.0
和HTTP 1.1
中利用KeepAlive
保持持久连接。 - 直接获取服务器发送的
response code
和headers
。(设置响应状态,http status 200) - 设置连接超时的能力。
- 实验性的支持
HTTP 1.1 response caching
。 - 源代码基于
Apache License
可免费获取。
httpClient可以理解成是一个模拟的虚拟的浏览器。
4. 使用流程
你是如何操作浏览器:
- 打开浏览器
- 输入URL
- 回车
- 展示 响应
Apache httpClient使用流程:
-
创建
HttpClient
对象。 -
创建请求方法的实例,并指定请求
URL
。如果需要发送GET
请求,创建HttpGet
对象;如果需要发送POST
请求,创建HttpPost
对象。 -
如果需要发送请求参数,可调用
HttpGet、HttpPost
共同的setParams(HttpParams params)
方法来添加请求参数;对于HttpPost
对象而言,也可调用setEntity(HttpEntity entity)
方法来设置请求参数。 -
调用
HttpClient
对象的execute(HttpUriRequest request)
发送请求,该方法返回一个HttpResponse
。 -
调用
HttpResponse
的getAllHeaders()、getHeaders(String name)
等方法可获取服务器的响应头;调用HttpResponse
的getEntity()
方法可获取HttpEntity
对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。 -
释放连接。无论执行方法是否成功,都必须释放连接
5.使用案例
5.1 导入pom
依赖
<!-- Apache Http Begin -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.5</version>
</dependency>
<!-- Apache Http End -->
5.2 创建HttpGet请求
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
public class MyTest {
public static void main(String[] args) {
get();
}
private static void get() {
// 创建 HttpClient 客户端
CloseableHttpClient httpClient = HttpClients.createDefault();
// 创建 HttpGet 请求
HttpGet httpGet = new HttpGet("http://localhost:8080/content/page?draw=1&start=0&length=10");
// 设置长连接
httpGet.setHeader("Connection", "keep-alive");
// 设置代理(模拟浏览器版本)
httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
// 设置 Cookie
httpGet.setHeader("Cookie", "UM_distinctid=16442706a09352-0376059833914f-3c604504-1fa400-16442706a0b345; CNZZDATA1262458286=1603637673-1530123020-%7C1530123020; JSESSIONID=805587506F1594AE02DC45845A7216A4");
CloseableHttpResponse httpResponse = null;
try {
// 请求并获得响应结果
httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
// 输出请求结果
System.out.println(EntityUtils.toString(httpEntity));
} catch (IOException e) {
e.printStackTrace();
}
// 无论如何必须关闭连接
finally {
if (httpResponse != null) {
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpClient != null) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
5.3 创建httpPost
请求
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
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.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
post();
}
private static void post() {
// 创建 HttpClient 客户端
CloseableHttpClient httpClient = HttpClients.createDefault();
// 创建 HttpPost 请求
HttpPost httpPost = new HttpPost("http://localhost:8080/content/page");
// 设置长连接
httpPost.setHeader("Connection", "keep-alive");
// 设置代理(模拟浏览器版本)
httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
// 设置 Cookie
httpPost.setHeader("Cookie", "UM_distinctid=16442706a09352-0376059833914f-3c604504-1fa400-16442706a0b345; CNZZDATA1262458286=1603637673-1530123020-%7C1530123020; JSESSIONID=805587506F1594AE02DC45845A7216A4");
// 创建 HttpPost 参数
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("draw", "1"));
params.add(new BasicNameValuePair("start", "0"));
params.add(new BasicNameValuePair("length", "10"));
CloseableHttpResponse httpResponse = null;
try {
// 设置 HttpPost 参数
httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
// 输出请求结果
System.out.println(EntityUtils.toString(httpEntity));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 无论如何必须关闭连接
finally {
try {
if (httpResponse != null) {
httpResponse.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (httpClient != null) {
httpClient.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
通信协议:http协议
http://www.baidu.com
HttpClientUtils工具类
public class HttpClientUtils {
private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class); // 日志记录
private static RequestConfig requestConfig = null;
static {
// 设置请求和传输超时时间
requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();
}
/**
* post请求传输json参数
*
* @param url
* url地址
* @param json
* 参数
* @return
*/
public static JSONObject httpPost(String url, JSONObject jsonParam) {
// post请求返回结果
CloseableHttpClient httpClient = HttpClients.createDefault();
JSONObject jsonResult = null;
HttpPost httpPost = new HttpPost(url);
// 设置请求和传输超时时间
httpPost.setConfig(requestConfig);
try {
if (null != jsonParam) {
// 解决中文乱码问题
StringEntity entity = new StringEntity(jsonParam.toString(), "utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
}
CloseableHttpResponse result = httpClient.execute(httpPost);
// 请求发送成功,并得到响应
if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String str = "";
try {
// 读取服务器返回过来的json字符串数据
str = EntityUtils.toString(result.getEntity(), "utf-8");
// 把json字符串转换成json对象
jsonResult = JSONObject.parseObject(str);
} catch (Exception e) {
logger.error("post请求提交失败:" + url, e);
}
}
} catch (IOException e) {
logger.error("post请求提交失败:" + url, e);
} finally {
httpPost.releaseConnection();
}
return jsonResult;
}
/**
* post请求传输String参数 例如:name=Jack&sex=1&type=2
* Content-type:application/x-www-form-urlencoded
*
* @param url
* url地址
* @param strParam
* 参数
* @return
*/
public static JSONObject httpPost(String url, String strParam) {
// post请求返回结果
CloseableHttpClient httpClient = HttpClients.createDefault();
JSONObject jsonResult = null;
HttpPost httpPost = new HttpPost(url);
httpPost.setConfig(requestConfig);
try {
if (null != strParam) {
// 解决中文乱码问题
StringEntity entity = new StringEntity(strParam, "utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/x-www-form-urlencoded");
httpPost.setEntity(entity);
}
CloseableHttpResponse result = httpClient.execute(httpPost);
// 请求发送成功,并得到响应
if (result.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String str = "";
try {
// 读取服务器返回过来的json字符串数据
str = EntityUtils.toString(result.getEntity(), "utf-8");
// 把json字符串转换成json对象
jsonResult = JSONObject.parseObject(str);
} catch (Exception e) {
logger.error("post请求提交失败:" + url, e);
}
}
} catch (IOException e) {
logger.error("post请求提交失败:" + url, e);
} finally {
httpPost.releaseConnection();
}
return jsonResult;
}
/**
* 发送get请求
*
* @param url
* 路径
* @return
*/
public static JSONObject httpGet(String url) {
// get请求返回结果
JSONObject jsonResult = null;
CloseableHttpClient client = HttpClients.createDefault();
// 发送get请求
HttpGet request = new HttpGet(url);
request.setConfig(requestConfig);
try {
CloseableHttpResponse response = client.execute(request);
// 请求发送成功,并得到响应
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
// 读取服务器返回过来的json字符串数据
HttpEntity entity = response.getEntity();
String strResult = EntityUtils.toString(entity, "utf-8");
// 把json字符串转换成json对象
jsonResult = JSONObject.parseObject(strResult);
} else {
logger.error("get请求提交失败:" + url);
}
} catch (IOException e) {
logger.error("get请求提交失败:" + url, e);
} finally {
request.releaseConnection();
}
return jsonResult;
}
}
Jackson
json字符串—>JSON对象;JSON对象—>json字符串
SpringMVC
的@ResponseBody
依赖jackJson
.
Jackson
是一个简单基于 Java 应用库;
Jackson
注解
@JsonProperty
@JsonProperty
注解指定一个属性用于 JSON
映射,默认情况下映射的 JSON
属性与注解的属性名称相同,不过可以使用该注解的 value
值修改 JSON
属性名,该注解还有一个 index
属性指定生成 JSON
属性的顺序,如果有必要的话
@JsonIgnore
@JsonIgnore
注解用于排除某个属性,这样该属性就不会被 Jackson 序列化和反序列化。
@JsonIgnoreProperties
@JsonIgnoreProperties
注解是类注解。在序列化为 JSON
的时候,@JsonIgnoreProperties({"prop1", "prop2"})
会忽略 pro1
和 pro2
两个属性。在从 JSON
反序列化为 Java
类的时候,@JsonIgnoreProperties(ignoreUnknown=true)
会忽略所有没有 Getter
和 Setter
的属性。该注解在 Java
类和 JSON
不完全匹配的时候很有用
@JsonIgnoreType
@JsonIgnoreType
也是类注解,会排除所有指定类型的属性。
@JsonPropertyOrder
@JsonPropertyOrder
和 @JsonProperty
的 index
属性类似,指定属性序列化时的顺序。
#@JsonRootName
@JsonRootName 注解用于指定 JSON 根属性的名称
Jackson
所需要的依赖
<!-- jackjson start -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.7.4</version>
</dependency>
<!-- jackjson end -->
对象的序列化与反序列化
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class JsonTester {
public static void main(String[] args) {
// 创建 ObjectMapper 对象
ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"name\":\"Mahesh\", \"age\":21}";
try {
// 反序列化 JSON 到对象
Student student = mapper.readValue(jsonString, Student.class);
System.out.println(student);
// 序列化对象到 JSON
String json = mapper.writeValueAsString(student);
System.out.println(json);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Student {
private String name;
private int age;
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student [ name: " + name + ", age: " + age + " ]";
}
}
集合的序列化与反序列化
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class JsonTester {
public static void main(String[] args) {
// 创建 ObjectMapper 对象
ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"draw\":1,\"recordsTotal\":1,\"recordsFiltered\":1,\"data\":[{\"id\":33,\"title\":\"ad1\",\"subTitle\":\"ad1\",\"titleDesc\":\"ad1\",\"url\":\"https://sale.jd.com/act/XkCzhoisOMSW.html\",\"pic\":\"https://m.360buyimg.com/babel/jfs/t20164/187/1771326168/92964/b42fade7/5b359ab2N93be3a65.jpg\",\"pic2\":\"\",\"content\":\"<p><br></p>\"}],\"error\":null}";
try {
// 反序列化 JSON 到树
JsonNode jsonNode = mapper.readTree(jsonString);
// 从树中读取 data 节点
JsonNode jsonData = jsonNode.findPath("data");
System.out.println(jsonData);
// 反序列化 JSON 到集合
JavaType javaType = mapper.getTypeFactory().constructParametricType(ArrayList.class, TbContent.class);
List<TbContent> tbContents = mapper.readValue(jsonData.toString(), javaType);
for (TbContent tbContent : tbContents) {
System.out.println(tbContent);
}
// 序列化集合到 JSON
String json = mapper.writeValueAsString(tbContents);
System.out.println(json);
} catch (IOException e) {
e.printStackTrace();
}
}
}
class TbContent {
private Long id;
private String title;
private String subTitle;
private String titleDesc;
private String url;
private String pic;
private String pic2;
private String content;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSubTitle() {
return subTitle;
}
public void setSubTitle(String subTitle) {
this.subTitle = subTitle;
}
public String getTitleDesc() {
return titleDesc;
}
public void setTitleDesc(String titleDesc) {
this.titleDesc = titleDesc;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public String getPic2() {
return pic2;
}
public void setPic2(String pic2) {
this.pic2 = pic2;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "TbContent{" +
"id=" + id +
", title='" + title + '\'' +
", subTitle='" + subTitle + '\'' +
", titleDesc='" + titleDesc + '\'' +
", url='" + url + '\'' +
", pic='" + pic + '\'' +
", pic2='" + pic2 + '\'' +
", content='" + content + '\'' +
'}';
}
}
JacksonUtils工具类
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonUtils {
private final static ObjectMapper objectMapper = new ObjectMapper();
private JacksonUtils() {
}
public static ObjectMapper getInstance() {
return objectMapper;
}
/**
* javaBean、列表数组转换为json字符串
*/
public static String obj2json(Object obj) throws Exception {
return objectMapper.writeValueAsString(obj);
}
/**
* javaBean、列表数组转换为json字符串,忽略空值
*/
public static String obj2jsonIgnoreNull(Object obj) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return mapper.writeValueAsString(obj);
}
/**
* json 转JavaBean
*/
public static <T> T json2pojo(String jsonString, Class<T> clazz) throws Exception {
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
return objectMapper.readValue(jsonString, clazz);
}
/**
* json字符串转换为map
*/
public static <T> Map<String, Object> json2map(String jsonString) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return mapper.readValue(jsonString, Map.class);
}
/**
* json字符串转换为map
*/
public static <T> Map<String, T> json2map(String jsonString, Class<T> clazz) throws Exception {
Map<String, Map<String, Object>> map = objectMapper.readValue(jsonString, new TypeReference<Map<String, T>>() {
});
Map<String, T> result = new HashMap<String, T>();
for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
result.put(entry.getKey(), map2pojo(entry.getValue(), clazz));
}
return result;
}
/**
* 深度转换json成map
*
* @param json
* @return
*/
public static Map<String, Object> json2mapDeeply(String json) throws Exception {
return json2MapRecursion(json, objectMapper);
}
/**
* 把json解析成list,如果list内部的元素存在jsonString,继续解析
*
* @param json
* @param mapper 解析工具
* @return
* @throws Exception
*/
private static List<Object> json2ListRecursion(String json, ObjectMapper mapper) throws Exception {
if (json == null) {
return null;
}
List<Object> list = mapper.readValue(json, List.class);
for (Object obj : list) {
if (obj != null && obj instanceof String) {
String str = (String) obj;
if (str.startsWith("[")) {
obj = json2ListRecursion(str, mapper);
} else if (obj.toString().startsWith("{")) {
obj = json2MapRecursion(str, mapper);
}
}
}
return list;
}
/**
* 把json解析成map,如果map内部的value存在jsonString,继续解析
*
* @param json
* @param mapper
* @return
* @throws Exception
*/
private static Map<String, Object> json2MapRecursion(String json, ObjectMapper mapper) throws Exception {
if (json == null) {
return null;
}
Map<String, Object> map = mapper.readValue(json, Map.class);
for (Map.Entry<String, Object> entry : map.entrySet()) {
Object obj = entry.getValue();
if (obj != null && obj instanceof String) {
String str = ((String) obj);
if (str.startsWith("[")) {
List<?> list = json2ListRecursion(str, mapper);
map.put(entry.getKey(), list);
} else if (str.startsWith("{")) {
Map<String, Object> mapRecursion = json2MapRecursion(str, mapper);
map.put(entry.getKey(), mapRecursion);
}
}
}
return map;
}
/**
* 与javaBean json数组字符串转换为列表
*/
public static <T> List<T> json2list(String jsonArrayStr, Class<T> clazz) throws Exception {
JavaType javaType = getCollectionType(ArrayList.class, clazz);
List<T> lst = (List<T>) objectMapper.readValue(jsonArrayStr, javaType);
return lst;
}
/**
* 获取泛型的Collection Type
*
* @param collectionClass 泛型的Collection
* @param elementClasses 元素类
* @return JavaType Java类型
* @since 1.0
*/
public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
return objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
}
/**
* map 转JavaBean
*/
public static <T> T map2pojo(Map map, Class<T> clazz) {
return objectMapper.convertValue(map, clazz);
}
/**
* map 转json
*
* @param map
* @return
*/
public static String mapToJson(Map map) {
try {
return objectMapper.writeValueAsString(map);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* map 转JavaBean
*/
public static <T> T obj2pojo(Object obj, Class<T> clazz) {
return objectMapper.convertValue(obj, clazz);
}
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/100783.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...