这个可以参考我在python写的相关文档。
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。
在进行写之前,我们需要进行依赖注入。
我们增加的是这样的一个库: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文档。
包含参数的话就全部复制过来就可以了。
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); } }我们仍然调用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); } }我们发现有问题,具体什么问题,我们后面慢慢说。
上一章我们学习了 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();我们只要把string改成byte就可以了
response.body().bytes();这个可以用于图片,视频等非文本文件。
前两节,我们学习了 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 对象"); } }我们上面解析了我现在的地址,在江苏南京,
{“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");由于有一些网站有防抓取机制,就像小阿七一样所以我们没有办法访问到,因为浏览器判断请求是否真的来自于一个真实的浏览器。如果不是来自浏览器,例如 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的方法:第一个是参数名,第二个是参数值。
有一些网页,我们加了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 信息设置为图片原始使用的网站。
前两节我们学习了如何使用 Okhttp3 库设置 HTTP 协议的 Headers,以此解决在调用网址、API 过程中可能出现的各种问题。
这节课学习 Host,也是 Headers 中非常重要的信息之一。
表示当前请求的域名。虽然这个域名已经存在于 URL 中,但遇到复杂的场景,例如使用代理服务器、或者 URL 中不写域名而是写 IP 地址进行请求等,设置 Host 就非常有用了。
Request request = new Request.Builder() .url(url) .addHeader("Host", "www.douban.com") .build();在第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();图片下载与二进制文件下载一模一样
我们需要注入依赖。
大家都知道,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),都表示一行数据。
前面我们学习 Okhttp3 库可以调用API、抓取网页、下载文件。但是这些操作都是不要求登录的,如果 API、网页、文件等内容要求登录才能访问,就需要学习新的 cookie 相关的知识了。
所谓 cookie ,是存储在客户端浏览器中的一段文本内容。以 key=value (数据名称、数据值)的格式存储一条数据;多条数据之间用分号 ; (英文半角)分开。由于各种浏览器都对 cookie 大小和数量有限制,所以 cookie 目前的核心功能是存储登录数据;额外可以存储一些小数据。
cookie的寻找方法:谷歌浏览器里面的开发者模式下进行查找即可。
由于cookie比较长,我们要把它解析成map
我们使用ReadFileTool.readContent方法进行把长长的字符串解析成map键值对。
但 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() {…}是匿名内部类
我们使用时看看就可以了
在 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(); } } }
授权码自己看吧。