网络协议的简称,计算机遵守这个协议才能交流,主要有http和https两种
地址栏输入的地址就叫做url,英文全称Uniform Resource Locator
多个参数之间用&分隔,参数用键值对表示key=value
和Windows文件路径\分割符不一样
因为http默认端口号为80,https默认端口号443,默认的端口号可以省略,其他的要写
不是以/开头的路径表示相对路径,以/开头的为绝对路径
不输入路径打开的是默认路径
安装依赖库okhttp3
安装方式,在pom.xml增加依赖
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp --> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.1.0</version> </dependency>
实例化
OkHttpClient okHttpClient = new OkHttpClient();
执行调用
调用之前先实例化一个request
Request request = new Request.Builder().url(url).build();
构建调用对象
Call call = okHttpClient.newCall(request);
最后执行调用
call.execute()返回的是一个执行的结果的对象,需要转换成字符串
call.execute().body().string();
api是应用程序接口,是预先定义的函数
url本质上就是api
只需把有参数的url直接传入方法中即可
提交数据至服务器进行增加,删除,修改操作都是post
post操作数据放在表单中,不是url
创建表单对象FormBody
Builder builder = new FormBody.Builder(); // 设置数据,第一个参数是数据名,第二个参数是数据值 builder.add("", ""); FormBody formBody = builder.build(); Request request = new Request.Builder().url(url).post(formBody).build();
构建Request对象时用.post(formbody),与api不同
用for循环添加表单数据
for(String key:formData.keySet()) {builder.add(key,formDate.get(key));}
post的参数不是formbody,改为requestbody
json
FastJson依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency>
先定义一个最终提交的常量数据
pravite static final MediaType JSON_TYPE = MediaType.parse("application/json;charset=utf-8");
utf-8是码表,查询
完整代码
除了返回值,还经常关注http状态码
常见状态码200表示成功,404表示出错
更多状态码
取得状态码的代码
call.execute().code()
但是即要读取相应内容,又要读取状态,而且不是再次请求,那么代码应该优化为
import okhttp3.Response; // 执行请求 Response rep = call.execute(); // 获取响应状态码 int code = rep.code(); // 获取响应内容 String content = rep.body().string();
就是将原本的call.excute()保存为一次结果,再获取其中的内容
非文本文件获取不是用string()方法,而是用
response.body().bytes();
返回二进制编码,再用软件解析
json是一段文本,也就是java的字符串,要解析内容需转换为java对象
JSON.parseObject()
普通的直接转换,遇到多次嵌套的
{ "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" } }
就转换后取出内部的再转换
Map contentObj = JSON.parseObject(content, Map.class); Map dataObj = (Map)contentObj.get("data"); String city = (String)dataObj.get("city");
json格式化工具
有时网站的会未成功,因为网站会校验是否是真实的浏览器发出的请求,api服务器认为不是真实的浏览器
判断是否是真实的浏览器,需要从HTTP消息头(Headers)中取得(User-Agent)
HTTP Headers文档
模拟win7 + chrome:
Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1
加入header信息
Request request = new Request.Builder() .url(url) .addHeader("User-Agent", "") .build();
addheader第一个参数是名称,第二个参数是值
图片防盗链
在headers中加入referer信息
在浏览器能访问是因为没有了“来源”
加入referer
Request request = new Request.Builder() .url(url) .addHeader("Referer", "https://ham.youkeda.com/course/j14/0") .build();
可把referer的信息设置为本站的信息(相同的域名)
有时图片请求的相应码为200,表示请求成功,但是最终相应地址却不一样,是因为服务器判断没有权限访问,做了特殊处理
host也是headers的信息之一
host表示当前请求的域名,虽然域名有时已经存在于url中,但是使用代理服务器或者url中不写域名而是写ip地址请求时,设置host就很有用
具体的host文档
设置Host
Request request = new Request.Builder() .url(url) .addHeader("Host", "www.douban.com") .build();
host的值是不带协议的域名
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();
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();
需要用FileOutputStream类,必须执行刷新,关闭
data 是byte[]类型
easyexecl是能快速操作excel文件的库
要先添加依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.1.6</version> </dependency>
excel是多sheet的模式,所以数据的位置是sheet->行->列
电脑中第一个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("xzq_201907.xlsx").sheet(0).doReadSync(); // List 中每个元素表示一行 for (Map<Integer, String> rowData : sheetDatas) { // Map 中用序号指代每一列 for (Integer index : rowData.keySet()) { // 列值 String columnValue = rowData.get(index); } }
但是如果知道每一行的含义,用自定义类比较好
import com.alibaba.excel.EasyExcel; import java.util.List; // 读取第一个sheet List<DemoData> sheetDatas = EasyExcel.read("xzq_201907.xlsx").head(DemoData.class).sheet(0).doReadSync();
// 属性定义的顺序必须与列顺序保持一致 public class DemoData { private String code1; private String city1; private String code2; private String city2; private String code3; private String city3; }
EasyExcel.XXXXXX.doReadSync()无论是什么类型,返回的都是list类型
如果文件或者网站要求登录才能访问,就要学习cookie的知识
cookie是储存在浏览器网站的一段文本文件,以key=value形式存放,多条数据之间用;隔开
准备 先找到登录后的cookie
谷歌开发者工具
复制cookie的值,然后用addHeader赋值给cookie
如果返回值404,是因为cookie是有有效期的
cookie的弊端是cookie是临时的,要登录再获取相关信息,可以用session来解决这个问题
// 用 CookieJar 实现 cookie 的存储,便于登录后请求其它 URL 可以复用 private static final OkHttpClient okHttpClient = new OkHttpClient.Builder() .cookieJar(new CookieJar() { private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>(); @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { cookieStore.put("mtime.com", cookies); System.out.println("[saveFromResponse]url.host()=" + url.host()); } @Override public List<Cookie> loadForRequest(HttpUrl url) { System.out.println("[loadForRequest]url.host()=" + url.host()); List<Cookie> cookies = cookieStore.get("mtime.com"); return cookies != null ? cookies : new ArrayList<>(); } }) .build();
匿名类
在login.api中找信息,有name和password
讲okHttpClient进行重构,不再定义为变量,改为类变量
private static final OkHttpClient okHttpClient
SMPT是一个简单的基于文本的文件传输协议,在这个协议可以指定一条消息和一个或多个邮件接收者,然后进行邮件传输。
和HTTP协议类似,
协议+服务器地址 就组成一个邮件访问方式,比如:
qq邮箱: smtp.qq.com
163邮箱: smtp.163.com
JavaMail依赖
<dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4</version> </dependency>
邮箱发送代码
import java.security.Security; import java.util.Properties; import javax.mail.Authenticator; import javax.mail.Message; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; public class MailClient { public static void main(String[] args) { try { final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; //配置邮箱信息 Properties props = System.getProperties(); //邮件服务器 props.setProperty("mail.smtp.host", "smtp.qq.com"); props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY); props.setProperty("mail.smtp.socketFactory.fallback", "false"); //邮件服务器端口 props.setProperty("mail.smtp.port", "465"); props.setProperty("mail.smtp.socketFactory.port", "465"); //鉴权信息 props.setProperty("mail.smtp.auth", "true"); //建立邮件会话 Session session = Session.getDefaultInstance(props, new Authenticator() { //身份认证 protected PasswordAuthentication getPasswordAuthentication() { //1.账户 授权码 return new PasswordAuthentication("xxxxxxx@qq.com", "xxxx"); } }); //建立邮件对象 MimeMessage message = new MimeMessage(session); //设置邮件的发件人 message.setFrom(new InternetAddress("xxxxxxx@qq.com")); //2.设置邮件的收件人,可多个,用逗号隔开 message.setRecipients(Message.RecipientType.TO, "xxxxxxx@qq.com"); //设置邮件的主题 message.setSubject("通过javamail发出!!!"); //文本部分 message.setContent("文本邮件测试", "text/html;charset=UTF-8"); message.saveChanges(); //发送邮件 Transport.send(message); } catch (Exception e) { e.printStackTrace(); } } }
固定用法,只需修改邮箱配置