一、简单的API调用
1.Get请求
在程序中也可以发送请求,获取结果。
为了具体实现这个功能我们需要先安装一个Okhttp3库,可以快速实现HTTP的调用。为了安装Okhttp3库我们需要在pom.xml文件中添加依赖。
那么如何使用OkHttpClient库来实现请求功能呢?
1.实例化OkHttpClient类
OkHttpClient okHttpClient = new OkHttpClient();
2.执行调用
在执行调用之前,需要实例化一个Request对象,作用是定义请求的各种参数,比如url。
Request request = new Request.Builder().url(url).build();
然后构建调用对象
Call call = okHttpClient.newCall(request);
最后执行调用,这里必须用try/catch环绕,因为如果调用失败就可能抛异常。
我们用call.execute().body().string() 来获取返回的字符串结果。
call.execute().body().string()
整个过程可以类比于打电话:拿出手机,相当于实例化Request对象;拨号,相当于newCall()方法;每说一句话,相当于执行execute()方法;听到对方说的话,相当于body().string()。
由于上述过程的代码基本比较固定,所以我们可以将其封装在一个getContent()方法当中。可以记在电脑上,当需要的时候把它copy出来,就可以完成功能。
2.POST
提交数据至服务器进行修改、增加、删除等操作,都是POST操作。与GET操作不同的是,POST操作的数据不存放在URL当中,而是存放在表单当中。
所以说,我们需要先构建一个表单对象FormBody,用于放置表单数据。
Builder builder = new FormBody.Builder();
// 设置数据,第一个参数是数据名,第二个参数是数据值
builder.add("", "");
FormBody formBody = builder.build();
Request request = new Request.Builder().url(url).post(formBody).build();
除了提交表单数据之外,也经常提交JSON数据。与表单数据一样,我们调用post()方法,只是不再使用FormBody对象,而是使用RequestBody对象提交JSON数据。
RequestBody用于处理HTTP请求体中的数据,将其转化为java对象。
二、Response
状态码
之前讲到了使用Get请求网页返回字符串结果的操作,事实上,除了具体的返回结果,我们还关心的数据是:http状态码。
http状态码反映的是请求的状态。例如:200表示请求成功了,而404表示出错等等。
为了在一次请求中得到请求的状态码以及返回的结果,我们可以这么敲:
import okhttp3.Response;
// 执行请求
Response rep = call.execute();
// 获取响应状态码
int code = rep.code();
// 获取响应内容
String content = rep.body().string();
其中call.execute()是真正执行请求的程序。
非文本文件
除了网页、API,对于一些非文本文件,例如图片、excel等文件,它们的内容不是可以直接阅读的字符文本,而是二进制编码,需要软件解析图片的二进制编码数据。所以在请求非文本文件时,我们不使用response.body().string()返回字符内容,而使用:
response.body().bytes();
获取返回的二进制编码内容。其中,bytes[] bytes 的length就是图片或者excel文件的大小。
解析JSON对象
很多API返回的结果都是JSON格式的。JSON是一段文本,是JAVA字符串,不方便操作,需要将它转化为Java对象,方便后续解析。
我们可以使用FastJson库对JSON进行操作,完成对象的序列化以及反序列化。
下面给出JSON对象的实例:
{
"code": 0,
"data": {
"ip": "117.89.35.58",
"country": "中国",
"area": "",
"region": "江苏",
"city": "南京",
"county": "XX",
"isp": "电信",
"country_id": "CN",
"area_id": "",
"region_id": "320000",
"city_id": "320100",
"county_id": "xx",
"isp_id": "100017"
}
}
对于这种多层嵌套的JSON对象,我们需要多次取出嵌套的Map对象:
Map contentObj = JSON.parseObject(content, Map.class);
Map dataObj = (Map)contentObj.get("data");
String city = (String)dataObj.get("city");
由于Map可以存储各种对象,所以从Map当中get()到的对象必须指定其类型。
三、Headers
Headers:HTTP消息头,是HTTP协议的一项重要内容。作用是,在发送请求的时候,除了请求参数之外,附加更多信息。
User-Agent
对于一些大型网站,出于安全等各种因素的考虑,会对请求进行比较严格的检验,其中一项就是判断这个请求是否来自一个真实的浏览器。比如如果不是来自浏览器,而是java程序请求,就会拒绝请求。
而判断请求是否来自一个真实浏览器,需要在Headers中提取User-Agent信息。
User-Agent:存放在Headers中的一种数据信息。作用是,在发送请求的时候,告诉服务端当前用户的浏览器类型、版本甚至操作系统、CPU等非隐私的技术信息。
所以,我们只需要在发送请求的时候,附带上模拟的User-Agent信息就行了。
Request request = new Request.Builder()
.url(url)
.addHeader("User-Agent", "")
.build();
Referer
我们从一个网页当中访问其他网页的图片时,有时候会遇到图片无法正常显示的情况。
这是因为浏览器在请求网页中的图片时,会自动在HTTP消息头Headers中,加一个Referer信息,表示请求的来源,表示请求的来源(即当前网址)。也就是说,浏览器自动告诉图片服务器,从当前网址访问图片,而图片服务器会拒绝该访问,因为图片服务器的规则是不允许其他网站访问图片。
为了解决这个问题,我们通常会在Headers中添加值为图片网站的Referer信息,模拟从图片所在网站访问图片。附加Referer的程序与附加User-Agent的程序类似。
四、下载文件&图片
写文件
在3.Response中,我们提到了请求非文本文件,此类二进制文件不能将内容输入在console进行查看,所以必须将结果写入文件。
也就是说,要想下载文件内容,就要将请求返回文件内容写入另一个文件中。
在java中,写文件必须经过三个步骤:
1.创建文件对象
2.写入内容
3.关闭写入操作
打开和关闭的步骤,是为了保证一个文件只能同时被一个程序写,否则内容会错乱。
File是文件类,FileWriter是用来给文件写入内容的类。
import java.io.File;
import java.io.FileWriter;
// 文件对象
File file = new File("foo.txt");
// 写入内容
FileWriter fileWritter = new FileWriter(file.getName());
fileWritter.write(content);
// 关闭
fileWritter.close();
当我们需要写二进制文件时,使用FileOutputStream类,并且必须额外执行刷新操作。
import java.io.File;
import java.io.FileOutputStream;
// 文件对象
File file = new File("china-city-list.xlsx");
// 写文件
FileOutputStream fos = new FileOutputStream(file);
fos.write(data);
// 必须刷新并关闭
fos.flush();
fos.close();
解析excel
想操作excel文件,我们可以借助java中的easyexcel库。
excel文件是多sheet模式的,每一个sheet就相当于一个表格,表格又分为行和列。
所以,我们解析excel文件的路径是:sheet->行->列。
注意:在计算机中,第一个单元格的位置是0。第一个sheet、第一行、第一列的位置是0,0,0。
import com.alibaba.excel.EasyExcel;
import java.util.Map;
import java.util.List;
// 读取第一个sheet
List<Map<Integer, String>> sheetDatas = EasyExcel.read("文件名").sheet(0).doReadSync();
// List 中每个元素表示一行
for (Map<Integer, String> rowData : sheetDatas) {
// Map 中用序号指代每一列
for (Integer index : rowData.keySet()) {
// 列值
String columnValue = rowData.get(index);
}
}
重点在于,返回的集合List的每一个元素,即每一个实例对象,都代表一行数据。然后再取每一列的数据。
五、cookie
cookie
所谓cookie,是存储在客户端浏览器中的一段文本内容。
1.以key=value的形式存储一条数据。
2.多条数据之间用;隔开。
3.核心功能为存储登录数据。
可以使用谷歌的开发者工具拷贝cookie数据,放入文件当中,再在Headers中添加cookie数据,从而实现登录操作。
addHeader("Cookie",ReadFileTool.readContent("文件名"));