Java网络编程(自己在学习的一些路线)

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 仓库目录里。

img

这五个概念都会运用在 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();
}
}
}


授权码自己看吧。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值