Java网络编程
1. 协议与URL
这个可以参考我在python写的相关文档。
2. maven
Maven 是一个项目管理和构建自动化工具。但是对于我们程序员来说,我们最关心的是它的项目构建功能。所以这里我们介绍的就是怎样用 Maven 来满足我们项目的日常需要。
Maven 提供了一个命令行工具可以把工程打包成 Java 支持的格式(比如 jar),并且支持部署到中央仓库里,这样使用者只需要通过工具就可以很快捷的运用其他人写的代码,只需要你添加依赖即可
想要使用 Maven 这个工具,是要在命令行(终端软件)里输入指令的方式来执行的,我们需要大家了解几个常用的命令,注意命令要在工程的根目录下执行哦
mvn clean compile
编译命令,Maven 会自动扫描 src/main/java 下的代码并完成编译工作,执行完,会在根目录下生成 target/classes 目录(存放所有的 class)
mvn clean package
编译并打包命令,这个命令是 compile 和 package 的集合,也就是说会先执行 compile 命令,然后在执行 jar 打包命令,这个的结果会把所有的 java 文件和资源打包成一个jar,jar 是 java 的一个压缩格式,方便我们灵活的运用多个代码
mvn clean install
执行安装命令,这个命令是 compile 和 package、install 的集合,也就是说会先执行 compile 命令,然后在执行 jar 打包命令,然后执行 install 命令安装到本地的 Maven 仓库目录里。
这五个概念都会运用在 Maven 的配置文件中。Maven 的配置文件是一个强约定的XML格式文件。
初学者可能会记不住这么多属性,没有关系,可以随时开启编程的无敌模式:拷贝、粘贴,照葫芦画瓢即可。
我们来看一些相关:
一个 Java 项目所有的配置都放置在 POM 文件中,大概有如下的行为:
定义项目类型与名字;
管理依赖关系;
定制插件;
我们简单看看。
我们发现有这样的东西:
maven坐标
maven工程属性
maven依赖
maven插件
补充介绍一下,XML 格式可能是我们第一次接触,其实 HTML 语言也是 XML 格式,不过 XML 格式会严格遵守标记语言的要求,那就是有开始标签和结束标签,比如 <version>1.0</version>,我们在自定义 pom.xml 时候,如果没有写完整的开始、结束标签,那就会出错,这里我们就不详细展开了,大家多看几次也就了解啦。
maven坐标
<groupId>com.youkeda.course</groupId>
<artifactId>app</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
这四个标签组成了 Maven 的坐标,所谓坐标就是一种位置信息,Maven 的坐标决定了这个 Maven 工程部署后存在 Maven 仓库的文件位置,所以这个坐标信息是必须要指定的。
这个再我们搭建maven时就已经确定了。
groupId
groupId 就像一个文件夹一样,它的命名和 Java 的包比较一致,这里一般只用小写的英文字母和字符.,比如这里的com.youkeda.course。一般来说一个公司会设置自己的 groupId,避免和其他公司重合,个人开发者也一样。
artifactId
artifactId 有点像文件名一样,在一个 groupId 内,它应该是唯一的,你不能使用中文或者特殊字符,从规范上来说只能使用小写的英文字母、.、-、_。比如:app、member.shared 这些都可以
packaging
Maven 工程执行完后会把整个工程打包成packaging指定的文件格式,默认情况下packaging的值是jar,所以如果pom.xml文件中没有声明这个标签,那就是 jar
packaging 有如下的几种格式
jar,war,ear,pom
大部分情况我们都是使用jar包
version
顾名思义,就是版本。在 Maven 的世界里,会把一个工程分为两个状态,这也是软件工程里最最常用的规范。
SNAPSHOT 这个单词翻译过来的意思是快照,实际上代表了当前程序还处于不稳定的阶段,随时可以再修改,所以在我们开发的时候我们会在版本号后面加上SNAPSHOT关键字
属性配置:
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
首先它的格式是在properties 标签内,这个是固定的格式。properties内的标签可以自定义,但是一般来说只能是小写英文字母+.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kUMQ5kyf-1599051627101)(D:\南京邮电大学文件\南京咪珠软件编辑部分\编程学习笔记\Java\image-20200831160330566.png)]
依赖管理:
dependency 就是用于指定当前工程依赖其他代码库的,Maven 会自动管理 jar 依赖
一旦我们在 pom.xml 里声明了 dependency 信息,会先去本地用户目录下的.m2文件夹内查找对应的文件,如果没有找到那么就会触发从中央仓库下载行为,下载完会存在本地的.m2文件夹内
请注意,一个 pom.xml 只能存在一个 dependencies 标签,可以有多个 dependency,因为我们很有可能依赖多个库
大家仔细观察这个dependency标签,你会发现dependency标签的内容其实就是 Maven 坐标,所以说只要有坐标我们就可以建立依赖
一般我们会把别人写的代码库称为三方库,自己、团队写的称为二方库,这个概念请大家记住,以后我们可能会这样描述内容的
中央仓库:我们很多jar包在中央仓库里,但是我们要通过阿里云来访问:
间接依赖:间接依赖是 mvn 成功的核心要素,简单的来说,如果一个remote工程依赖了 okhttp 库,而当前工程locale依赖了 remote工程,这个时候locale工程也会自动依赖了 okhttp
插件体系:
插件体系让 Maven 这个工具变得高度可定制,所以可以无缝的支撑工程化能力。现在只要了解插件的格式就可以啦,因为不同的插件有不同的作用。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
</plugins>
</build>
插件用于执行 maven compile 的,你会发现 maven 的插件其实也是存放在中央仓库的坐标,也就是一切都是 jar。
3. 网络编程相关请求
3.1 get请求
在进行写之前,我们需要进行依赖注入。
我们增加的是这样的一个库:okhttp3
我们这么添加依赖:
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.1.0</version>
</dependency>
使用 Okhttp3 完成页面请求,需要三大步骤:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fE9stgu9-1599051627104)(D:\南京邮电大学文件\南京咪珠软件编辑部分\编程学习笔记\Java\image-20200831161738833.png)]
固定写法,不用记。
输出结果:call.execute().body().string();可以取得服务器返回的具体内容。在下一章我们会详细学习,这里大家知道用法即可。
以我们学校的网络为例:
package html;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import java.io.IOException;
public class GetPage {
public String getContent(String url){
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
Call call = okHttpClient.newCall(request);
String result = null;
try{
result = call.execute().body().string();
}catch (IOException e){
System.out.println("Error");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
GetPage getPage = new GetPage();
String url = "http://www.njupt.edu.cn/mainm.htm";
String content = getPage.getContent(url);
System.out.println(content);
}
}
我们解析出来了相关的页面html文档。
包含参数的话就全部复制过来就可以了。
3.2 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();
数据的写法是不是很眼熟呢?整体步骤跟请求 API 相似,不同的是,在构建 Request 对象时,使用 .post(formBody) 语句放入表单对象,就表示执行 POST 操作啦。
我们看一个例子:
package html;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.FormBody;
import okhttp3.FormBody.Builder;
public class Phone {
public String postContent(String url, Map<String, String> formData) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
//post方式提交的数据
Builder builder = new FormBody.Builder();
// 放入表单数据
for (String key : formData.keySet()) {
builder.add(key, formData.get(key));
}
// 构建 FormBody 对象
FormBody formBody = builder.build();
// 指定 post 方式提交FormBody
Request request = new Request.Builder().url(url).post(formBody).build();
// 使用client去请求
Call call = okHttpClient.newCall(request);
// 返回结果字符串
String result = null;
try {
// 获得返回结果
result = call.execute().body().string();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String url = "http://tcc.taobao.com/cc/json/mobile_tel_segment.htm";
Map<String, String> formData = new HashMap();
formData.put("tel","15850558521");
Phone poster = new Phone();
String content = poster.postContent(url, formData);
System.out.println("API调用结果");
System.out.println(content);
}
}
3.3 post的json数据
我们仍然调用post方法,但是不是FormBody,而是RequestBody
将数据转换成 JSON 格式的字符串,调用 JSON.toJSONString() 方法即可。
创建 RequestBody 实例,注意需要指定提交的类型是 application/json; charset=utf-8 。这里的 utf-8 是 API 规定的编码格式。
构建 Request 实例对象时,调用 .post(requestBody) 即表示使用 JSON 的方式提交数据。
基本上是固定写法。
我们又要注入依赖了。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
我解析了小阿七,源码在这里:
package html;
import com.alibaba.fastjson.JSON;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
public class JsonPoster {
public static final MediaType Json_type = MediaType.parse("application/json; charset=utf-8");
public String postContent(String url,Map<String,String> data){
String result = null;
OkHttpClient okHttpClient = new OkHttpClient();
String param = JSON.toJSONString(data);
RequestBody requestBody = RequestBody.create(Json_type,param);
Request request = new Request.Builder().url(url).post(requestBody).build();
Call call = okHttpClient.newCall(request);
try{
result = call.execute().body().string();
}catch(IOException e){
System.out.println(url + "Error!");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
Map<String,String> data = new HashMap<>();
String url ="http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key=%E5%B0%8F%E9%98%BF%E4%B8%83&pn=1&rn=30&httpsStatus=1&reqId=f61e3dd1-ec4f-11ea-bbb1-e3764df2dd13";
data.put("key","小阿七");
data.put("pn","1");
data.put("httpsStatus","1");
data.put("reqId","f61e3dd1-ec4f-11ea-bbb1-e3764df2dd13");
JsonPoster poster = new JsonPoster();
String result = poster.postContent(url,data);
System.out.println(result);
}
}
我们发现有问题,具体什么问题,我们后面慢慢说。
4. response
4.1 response解析文本文件
上一章我们学习了 Java 中使用 Okhttp3 库请求网页或调用 API 的知识,
call.execute().body().string()来返回我们所要的字符串
实际上,除了具体的返回结果,我们通常还关心的数据是:http 状态码
状态码是用一个数字直观反映了本次请求的状况,例如常见的 200 表示请求成功了,404 表示出错了,服务端没有被请求的内容。我们访问小阿七就出问题了。
为了取得响应状态码,可以使用语句:
call.execute().code()
具体操作如下:
import okhttp3.Response;
// 执行请求
Response rep = call.execute();
// 获取响应状态码
int code = rep.code();
// 获取响应内容
String content = rep.body().string();
4.2 response解析非文本文件
我们只要把string改成byte就可以了
response.body().bytes();
这个可以用于图片,视频等非文本文件。
4.3 json
前两节,我们学习了 Java 中使用 Okhttp3 库获取请求返回的内容。无论是文本文件,还是二进制文件,都能够熟练使用了。
而在工作中,经常会调用 API ,而很多 API 返回的文本内容是 JSON 格式的。
json是一段文本,也就是 Java 的字符串,是难以进行解析具体内容的。必须转换成 Java 的对象。
前一节我们已经学习过使用 fastjson 库把参数对象转换为 JSON 格式字符串,当然也可以把 JSON 结果转换为对象,方便程序今后一步分析。
JSON.parseObject()
package com.youkeda.test.http;
import com.alibaba.fastjson.JSON;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ApiAsker {
/**
* 根据输入的url,读取页面内容并返回
*/
public String getContent(String url) {
// okHttpClient 实例
OkHttpClient okHttpClient = new OkHttpClient();
// 定义一个request
Request request = new Request.Builder().url(url).build();
// 使用client去请求
Call call = okHttpClient.newCall(request);
// 返回结果字符串
String result = null;
try {
// 执行请求
Response response = call.execute();
// 获取响应内容
result = response.body().string();
} catch (IOException e) {
// 抓取异常
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String url = "http://ip-api.com/json/";
ApiAsker asker = new ApiAsker();
String content = asker.getContent(url);
System.out.println("查询结果文本:" + content);
Map contentObj = JSON.parseObject(content, Map.class);
System.out.println("JSON 格式字符串转换为 Map 对象");
}
}
4.4 解析json
我们上面解析了我现在的地址,在江苏南京,
{“status”:“success”,“country”:“China”,“countryCode”:“CN”,“region”:“JS”,“regionName”:“Jiangsu”,“city”:“Nanjing”,“zip”:"",“lat”:32.0617,“lon”:118.7778,“timezone”:“Asia/Shanghai”,“isp”:“China Mobile Communications Corporation”,“org”:“China Mobile Communications Corporation”,“as”:“AS56046 China Mobile communications corporation”,“query”:“36.152.115.125”}
我们怎么得到我们想要的东西呢?
我们就使用get方法,在里面输入键值就可以了
System.out.println("查询结果文本:" + content);
Map contentObj = JSON.parseObject(content, Map.class);
System.out.println("当前 IP 为:" + contentObj.get("query"));
如果嵌套复杂怎么办,我们一层层剥开就可以了。
Map contentObj = JSON.parseObject(content, Map.class);
Map dataObj = (Map)contentObj.get("data");
String city = (String)dataObj.get("city");
5. headers
5.1 user-agent
由于有一些网站有防抓取机制,就像小阿七一样所以我们没有办法访问到,因为浏览器判断请求是否真的来自于一个真实的浏览器。如果不是来自浏览器,例如 Java 程序请求,API 服务器认为不是真实的浏览器访问,就直接拒绝掉了。
判断请求是否真的来自于一个真实的浏览器,需要从 HTTP 消息头(Headers)中取得 User-Agent 信息后,才能判断。
调取方法:进去浏览器里面查看在开发者工具里面可以看到相关的问题与操作。
headers是HTTP协议的一项比较重要的内容,作用是在发起请求的时候,除了请求参数外,可以附加更多的信息。可以参看python文档里面的内容。
这里只要记住,Headers 信息并不是写在 URL 中的,属于隐藏的数据,不能直观看到。
User-Agent:是存放在 Headers 中的一种数据信息。作用是,在指定 URL 发送请求的时候,告诉服务端当前用户的浏览器类型、版本,甚至操作系统、CPU等非隐私的技术信息。
服务器从 Headers 中的 User-Agent 信息获取到浏览器类型、版本等数据后,就认为是一个浏览器请求的环境了,就会给出响应。
我们使用这个,就可以让浏览器认为是本浏览器进行工作的,就可以进行爬取了。
所以,我们只要在程序代码中,附加上 User-Agent 信息,就能允许成功了。当然,这里的 User-Agent 是模拟的。
代码如下:
Request request = new Request.Builder()
.url(url)
.addHeader("User-Agent", "")
.build();
addHeader的方法:第一个是参数名,第二个是参数值。
5.2 referer
有一些网页,我们加了user-agent还是打不开,因为有防盗处理机制,我们现在加一个方法:
但浏览器在请求网页中的图片(或其它任何文件)时,会自动在 HTTP 消息头 Headers 中,加一个 Referer 信息,表示请求的来源。
即浏览器自动告诉图片服务器,从当前 youkeda.com 请求此图片,这时图片服务器拒绝了访问,因为图片服务器的规则是不允许其它网站(非nlark.com)访问图片。
加referer的方法:
Request request = new Request.Builder()
.url(url)
.addHeader("Referer", "https://ham.youkeda.com/course/j14/0")
.build();
贴到浏览器能访问是因为此图片服务器允许无 Referer 信息时访问。但也不是所有图片服务器都允许呢,况且即使同一个图片服务器,也可能修改规则,某一天突然改为必须本站内才能也未可知。
所以,为了一劳永逸的解决问题,需要把 Referer 信息设置为图片原始使用的网站。
5.3 host
前两节我们学习了如何使用 Okhttp3 库设置 HTTP 协议的 Headers,以此解决在调用网址、API 过程中可能出现的各种问题。
这节课学习 Host,也是 Headers 中非常重要的信息之一。
表示当前请求的域名。虽然这个域名已经存在于 URL 中,但遇到复杂的场景,例如使用代理服务器、或者 URL 中不写域名而是写 IP 地址进行请求等,设置 Host 就非常有用了。
Request request = new Request.Builder()
.url(url)
.addHeader("Host", "www.douban.com")
.build();
6. 相关东西的下载
6.1 下载文件
在第3章第2节我们学习了如何请求图片、excel等文件,此类二进制文件无法把内容输出在 console 进行查看的,所以请求结果必须写入文件。
Java写文件要分为三个步骤
创建文件对象
↓
写入内容
↓
关闭写入操作
文本文件的写入:
import java.io.File;
import java.io.FileWriter;
// 文件对象
File file = new File("foo.txt");
String content = "Hello world"
// 写入内容
FileWriter fileWritter = new FileWriter(file.getName());
fileWritter.write(content);
// 关闭
fileWritter.close();
此时就生成了一个文本文件。
二进制文件的写入:
假设文件数据的变量是 byte[] data,那么写入本地文件的代码如下
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();
图片下载与二进制文件下载一模一样
6.2 解析excel
我们需要注入依赖。
大家都知道,excel 文件是多 sheet 模式的,每个 sheet 实际上是一个表格,表格又分为行和列。
解析方法:
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);
}
}
解析文件的第一个步骤是读取文件内容,调用 EasyExcel.read() 方法,传入文件名称。然后这里解析的 第一个 工作表,所以调用 sheet() 方法,传入参数 0 。最后的 doReadSync() 表示同步方式读取文件内容,返回一个读取到的内容集合 List 。这是一个连贯的写法。
我们知道,excel里面我们不知道类是什么,所以我们要自动转化成类来进行使用。
在不能提前确定 excel 文件每一列的含义时,或者复杂场景下 excel 文件的列经常变化,用 Map 表示每一列的数据比较好。
但是如果知道 excel 文件每一列的含义,用自定义类来表示,会更加直观。
import com.alibaba.excel.EasyExcel;
import java.util.List;
// 读取第一个sheet
List<DemoData> sheetDatas = EasyExcel.read("xzq_201907.xlsx").head(DemoData.class).sheet(0).doReadSync();
注意这里多调用了一个方法:.head(DemoData.class),DemoData 就是自定义的类,表示一行数据,类的每个属性都表示一列的值。
返回值为 List 就表示把每一行都转换为一个 DemoData 的实例对象,放入 List 集合中。
code1 是第一个属性,映射 excel 文件第一列的值。这是为了让大家易懂,在属性名上加了数字,实际上,即使属性名是 code10000 ,只要放在最前面,就映射第一列的值。
无论转换为自定义的类还是 Map,EasyExcel.XXXXXX.doReadSync() 最终返回的都是一个集合 List 。大家一定要理解的是,集合中的每一个元素,即每一个实例对象(无论是自定义类还是 Map),都表示一行数据。
7. cookie & session
7.1 cookie
前面我们学习 Okhttp3 库可以调用API、抓取网页、下载文件。但是这些操作都是不要求登录的,如果 API、网页、文件等内容要求登录才能访问,就需要学习新的 cookie 相关的知识了。
所谓 cookie ,是存储在客户端浏览器中的一段文本内容。以 key=value (数据名称、数据值)的格式存储一条数据;多条数据之间用分号 ; (英文半角)分开。由于各种浏览器都对 cookie 大小和数量有限制,所以 cookie 目前的核心功能是存储登录数据;额外可以存储一些小数据。
cookie的寻找方法:谷歌浏览器里面的开发者模式下进行查找即可。
由于cookie比较长,我们要把它解析成map
我们使用ReadFileTool.readContent方法进行把长长的字符串解析成map键值对。
7.2 session
但 cookie 的弊端是,cookie 是存放在客户端浏览器的,而且是临时的,登录后还想以登录状态与服务器通讯,就比较麻烦。
这就需要在程序中使用 Session 对象来解决这个问题。
代码如下:
package com.youkeda.test.http;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.FormBody.Builder;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class PageLoginer {
// 用 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();
public String postContent(String url, Map<String, String> formData) {
//post方式提交的数据
Builder builder = new FormBody.Builder();
// 放入表单数据
for (String key : formData.keySet()) {
builder.add(key, formData.get(key));
}
// 构建 FormBody 对象
FormBody formBody = builder.build();
// 指定 post 方式提交FormBody
Request request = new Request.Builder()
.url(url)
.post(formBody)
.addHeader("User-Agent",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36")
.addHeader("Referer",
"https://passport.mtime.com/member/signin/?redirectUrl=http%3A%2F%2Fwww.mtime.com%2F")
.addHeader("Host", "passport.mtime.com")
.build();
// 返回结果字符串
String result = null;
try {
result = okHttpClient.newCall(request).execute().body().string();
} catch (IOException e) {
System.out.println("request " + url + " error . ");
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
// 登录页面 url
String url = "https://passport.mtime.com/member/signinLogin";
// 登录表单数据
Map<String, String> formData = new HashMap();
formData.put("loginEmailText", "13777467803");
formData.put("loginPasswordText", "aa787bc9cc97ba5d27cc042ecffe1489");
formData.put("isvcode", "true");
formData.put("isAutoSign", "false");
PageLoginer asker = new PageLoginer();
String content = asker.postContent(url, formData);
System.out.println(content);
}
}
这里面new CookieJar() {…}是匿名内部类
我们使用时看看就可以了
8. 发邮件
在 Java 中我们可以调用 JavaMail 调用发送和接收邮件,我们首先配置 maven 依赖,如 pom 文件中加入
<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;
import com.sun.net.ssl.internal.ssl.Provider;
public class MailClient {
public static void main(String[] args) {
try {
//设置SSL连接、邮件环境
Security.addProvider(new Provider());
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();
}
}
}
“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();
}
}
}
授权码自己看吧。