HTTP请求协议包
http服务器
HTTP Server 也是我们常说的Web服务器
在网络中传递的信息都是以【二进制】形式存在的,接收方在接收信息后需要把二进制数据编译为原数据。
弊端:HTTP协议无法实现服务器主动向客户端发起消息。
http服务器需要
1、可以接收来自浏览器发送的Http请求协议包,并自动对Http请求协议包内容解析
2、并将定位的文件内容给写入到Http写入到HTTP响应协议包
请求协议包
在基于B/S结构下,互联网通信过程中,所有在网络中传递信息都是保存在HTTP网络协议包
浏览器 向 WEB服务器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
HTTP请求协议包自上而下划分为4个空间
请求行
请求行主要提供:请求地址和请求方式
get方式参数存放在请求数据包的请求行的URI字段中,以?开始以param=value¶me2=value2的形式附加在URI字段之后
请求头
请求头的作用有以下几个方面:
-
进行身份验证:请求头中的Authorization字段常用于传递身份验证凭证,如基本认证(Basic Authentication)或令牌(Token)。服务器可以根据这些凭证对请求进行身份验证,以确定是否允许访问受保护的资源。
-
控制请求体的格式:Content-Type字段指定了请求体中数据的格式类型,如JSON、表单数据等。服务器可以根据Content-Type来正确解析请求体中的数据。
-
提供跳转来源信息:Referer字段指示了当前请求是从哪个URL页面发起的,可以帮助服务器识别请求的来源。
-
User-Agent:标识客户端使用的浏览器和操作系统信息
如果请求方式是get,那么请求参数信息会保存到请求头中
x-forwarded-for:是一个 HTTP 扩展头部,主要是为了让 Web 服务器获取访问用户的真实 IP 地址
X-Forwarded-For 请求头格式
X-Forwarded-For: client, proxy1, proxy2
可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP(用户真实 IP),然后是每一级代理设备的 IP。
public static String getIpAddr(HttpServletRequest request) { if (request == null) { return "unknown"; } String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("X-Forwarded-For"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("X-Real-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; }
CONTENT_TYPE
空白行
没有任何内容。是用来区分"请求头"和"请求体"的
请求体
如果请求方式是post,那么请求参数信息会保存到请求体中
HTTP响应协议包
响应协议包
WEB服务器 向 浏览器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
状态行
HTTP状态码
响应头
Content-Type:指定浏览器采用对应编译器对响应体二进制数据进行解析
空白行
区分"响应头"和"响应体"
响应体
可能是被访问静态资源文件内容,可能是动态资源文件的运行结果
HttpClient
多种请求方法
HTTP 请求可以使用多种请求方法。
HTTP1.0 定义了三种请求方法: GET, POST 和 HEAD 方法。
HTTP1.1 新增了六种请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法。
1 | GET | 请求指定的页面信息,并返回实体主体。 |
2 | HEAD | 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头 |
3 | POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。 |
4 | PUT | 从客户端向服务器传送的数据取代指定的文档的内容。 |
5 | DELETE | 请求服务器删除指定的页面。 |
6 | CONNECT | HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。 |
7 | OPTIONS | 允许客户端查看服务器的性能。 |
8 | TRACE | 回显服务器收到的请求,主要用于测试或诊断。 |
9 | PATCH | 是对 PUT 方法的补充,用来对已知资源进行局部更新 。 |
HttpClient
HttpClient 是Apache HttpComponents 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。
创建HttpClient对象。
创建请求方式的实例。创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
添加请求参数。如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。
发送Http请求。调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。
获取返回的内容。调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
释放资源。无论执行方法是否成功,都必须释放资源;
spring boot集成HttpClient
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
如果是maven工程,引入如下maven依赖
<!-- 此处使用的是 5.x 版本,可以根据自身情况引入版本 -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.1.1</version>
</dependency>
HttpClient 响应处理
在 HttpClient 中把响应封装成了 CloseableHttpResponse
对象,在此对象中可以获取如下数据:
- getCode() 获取响应状态
- getEntity() 获取响应数据
HttpClient 提供了 EntityUtils
工具类,可以很好的把 响应的 HttpEntity 转换为 字节数组或者字符串
// 转换为字符串
EntityUtils.toString(response.getEntity());
// 转换为字节数组
EntityUtils.toByteArray(response.getEntity());
1
GET请求
GET请求的所有参数是直接拼接在 URL 后面的,在浏览器地址栏中可见。
GET请求url编码
使用GET请求时会将参数附加到URL的查询字符串中,以便将其发送给服务器。但是GET请求只接受ASCII字符作为参数值。
解决办法:
GET请求会把参数进行URL编码(也称为百分号编码或URL转义),以确保特殊字符不会干扰URL结构。
public static void main(String[] args) throws Exception {
//获取默认配置的 HttpClient
CloseableHttpClient httpclient = HttpClients.createDefault();
//设置单个请求的配置信息
RequestConfig requestConfig = RequestConfig.custom()
// 设置连接超时时间
.setConnectTimeout(Timeout.of(3000, TimeUnit.MILLISECONDS))
// 设置响应超时时间
.setResponseTimeout(3000, TimeUnit.MILLISECONDS)
// 设置从连接池获取链接的超时时间
.setConnectionRequestTimeout(3000, TimeUnit.MILLISECONDS)
.build();
// 请求路径及参数
String name = URLEncoder.encode("张三", "utf-8");
String url = "http://localhost:10010/user/params?age=20&name=" + name;
HttpGet httpget = new HttpGet(url);
httpget.setConfig(requestConfig);
// 调用 HttpClient 的 execute 方法执行请求
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
EntityUtils.consume(entity);
System.out.println(result);
} finally {
response.close();
}
}
通过 URIBuilder 构建请求路径
POST 请求
使用POST请求时,参数通过HTTP消息体进行传输,并不会直接显示在URL上。
POST支持多种编码方式。
熟悉常见的 Content-Type 类型对于处理 POST 请求至关重要,它可以帮助我们更好地使用和解决问题。
请求头字段有
Content-Type
具体的数据格式和编码方式由
Content-Type
字段确定。服务端会根据 Content-Type 字段使用不同的方式对请求体进行解析。1、最常用的POST数据编码方式是 application/x-www-form-urlencoded ,它与GET相似,也会对非ASCII字符和特殊字符进行URL编码。
这种方式下,参数按照键值对形式出现在消息正文中,并用&符号连接起来,同时以 = 分隔键和值,
public static void main(String[] args) throws Exception { // 创建 ContentType 对象为 form 表单模式 ContentType contentType = ContentType.create("application/x-www-form-urlencoded", StandardCharsets.UTF_8); String url = "http://localhost:10010/user/body"; HttpPost httpPost = new HttpPost(url); //设置请求头,添加到 HttpPost 头中 httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType); //HttpPost请求 要传的参数 这里先将参数封装起来 List<BasicNameValuePair> params = new ArrayList<>(); params.add(new BasicNameValuePair("name", "张三")); params.add(new BasicNameValuePair("age", "20")); //这一步才是 为post 请求设置参数 这是创建表单的实体对象 设置当前参数的编码格式 //设置请求数据,把HttpEntity 设置到 HttpPost 中 httpPost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8)); //获取默认配置的 HttpClient CloseableHttpClient httpclient = HttpClients.createDefault(); //调用 HttpClient 的 execute 方法执行请求 CloseableHttpResponse response = httpclient.execute(httpPost); try { HttpEntity entity = response.getEntity(); String result = EntityUtils.toString(entity); EntityUtils.consume(entity); System.out.println(result); } finally { response.close(); } }
最主要的就是consume()这个方法,其功能就是关闭HttpEntity是的流,
2、使用
application/json
编码方式,可以将数据序列化成一个 JSON 字符串作为请求主体。application/json 是一种常用的HTTP请求头,用于指定请求的内容类型为JSON格式
public static void main(String[] args) throws Exception { // 创建 ContentType 对象为 form 表单模式 ContentType contentType = ContentType.create("application/json", StandardCharsets.UTF_8); String url = "http://localhost:10010/user/body"; HttpPost httpPost = new HttpPost(url); //设置请求头,添加到 HttpPost 头中 httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType); //设置报文和通讯格式 String jsonParam = "{\"name\":\"John\", \"age\":30}"; StringEntity stringEntity = new StringEntity(jsonParam, StandardCharsets.UTF_8); httpPost.setEntity(stringEntity); //获取默认配置的 HttpClient CloseableHttpClient httpclient = HttpClients.createDefault(); //调用 HttpClient 的 execute 方法执行请求 CloseableHttpResponse response = httpclient.execute(httpPost); try { HttpEntity entity = response.getEntity(); String result = EntityUtils.toString(entity); EntityUtils.consume(entity); System.out.println(result); } finally { response.close(); } }
3、multipart/form-data
这种编码方式主要用于文件上传,可以有效地传输二进制(非字母数字)数据,同时还可以携带其他信息
最常见的 POST 提交数据的方式,也是典型的key-val键值对,无需转化,在request中直接获取,框架也会将同名属性封装到接收对象中,支持文件流上传
如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。
但是如果有type=file的话,就要用到multipart/form-data了。
4、 application/octet-stream
二进制流数据(如常见的文件下载)
HTTP 中的 POST 请求的数据是包含在请求体中的。在 HttpClient 中 POST 请求发送数据是通过,调用 HttpPost
类的 setEntity(HttpEntity entity)
方法设置消息内容的
发送 JSON 数据
java 发邮件
SMTP
SMTP是一种提供可靠且有效的电子邮件传输的协议(只负责发送,不负责接收)
POP3协议,读取邮件的协议
用户必须首先设置 SMTP 服务器,然后才能配置电子邮件客户端与其连接。完成此操作后,用户按下电子邮件上的“发送”按钮,并在客户端和服务器之间建立 SMTP 连接以允许发送电子邮件。SMTP 连接建立在传输控制协议 (TCP)连接之上。
SMTP (Simple Mail Transfer Protocol),即简单邮件传输协议,默认端口是25,通过SSL协议加密之后的默认端口是465
465端口(SMTP SSL):465端口是为SMTP SSL(SMTP-over-SSL)协议服务开放的,这是SMTP协议基于SSL安全协议之上的一种变种协议,它继承了SSL安全协议的非对称加密的高度安全可靠性,可防止邮件泄露。
SMTPS和SMTP协议一样,也是用来发送邮件的,只是更安全些,防止邮件被黑客截取泄露,还可实现邮件发送者抗抵赖功能。防止发送者发送之后删除已发邮件,拒不承认发送过这样一份邮件。
SMTP 服务器,如smtp.163.com、smtp.qq.com
25端口(SMTP):25端口为SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)服务所开放的,是用于发送邮件。
如今绝大多数邮件服务器都使用该协议。当你给别人发送邮件时,你的机器的某个动态端口(大于1024)就会与邮件服务器的25端口建立一个连接,你发送的邮件就会通过这个连接传送到邮件服务器上,保存起来。
POP3
POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,是TCP/IP协议族中的一员,默认端口是110,通过SSL协议加密之后的默认端口是995。
POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,但是对邮件的操作并不会反馈到邮箱服务器上。
IMAP
IMAP (Internet Mail Access Protocol),即交互式邮件存取协议,是一个应用层协议,默认端口是143,通过SSL协议加密之后的默认端口是993。
开启了IMAP后,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。
IMAP协议:即Internet Message Access Protocol(互联网邮件访问协议),您可以通过这种协议从邮件服务器上获取邮件的信息、下载邮件等
邮箱授权码
现在邮箱大多为邮箱客户端设置了独立密码或授权码(即通过Smtp方式发送邮件密码处不是填邮箱登录密码,而是要填授权码)
如下:
进去后,点击开启。开启完成后状态变为”已开启“
javax.mail
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
1
commons-email
commons-email它构建在Java Mail API 之上,主要是为了简化它。
pom文件依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.5</version>
</dependency>
Commons-Email的核心是Email类,它是一个抽象类,提供了发送邮件的核心功能。具体有以下几个实现类
SimpleEmail:发送简单邮件,即纯文本邮件
public static void main(String[] args) throws EmailException {
Email email = new SimpleEmail();
//设置邮箱服务器,在这里我使用的163邮箱
email.setHostName("smtp.163.com");
//填写邮件服务器端口:465和25选填
email.setSmtpPort(25);
//开启debug日志
//email.setDebug(true);
//设置用户名(邮箱)和授权码(授权码是用于登录第三方邮件客户端的专用密码)
//邮箱开启授权只需要登陆邮件,在里边设置一下就行了.
email.setAuthenticator(new DefaultAuthenticator("your_email@163.com", "your_auth_password"));
//开启ssl连接
email.setSSLOnConnect(true);
//填写发送者的邮箱
email.setFrom("your_email@163.com");
//填写发送日期
email.setSentDate(new Date());
//填写邮件标题
email.setSubject("TestMail");
//邮件内容
email.setMsg("你好这是测试邮件");
//填写发送人,我用发给的是新浪邮箱,除了发送给QQ邮箱不行之外,你随意
//注:发给QQ邮箱被退回了(腾讯邮箱服务对邮件检查比较严格导致)
email.addTo("target_email_address@sina.com");
//发送
email.send();
}
MultiPartEmail
MultiPartEmail类通常用来发送流媒体类型的邮件,允许附件和文本类型数据一起发送。
public static void main(String[] args) throws EmailException {
//创建附件
EmailAttachment attachment = new EmailAttachment();
//填写附件位置
attachment.setPath("path_to_your_attachment/attachment.txt");
attachment.setDisposition(EmailAttachment.ATTACHMENT);
//填写附件描述
attachment.setDescription("附件描述");
//填写附件名称,要与上面一致填写路径中的附件名称一致
//要不然收到附件的时候会有问题
attachment.setName("attachment.txt");
//创建邮件信息
MultiPartEmail email = new MultiPartEmail();
email.setHostName("smtp.163.com");
email.setSmtpPort(465);
email.setDebug(true);
//填写授权码和用户名
email.setAuthenticator(new DefaultAuthenticator("your_email@163.com", "your_auth_password"));
email.setSSLOnConnect(true);
email.setFrom("your_email@163.com");
email.addTo("target_email_address@sina.com");
email.setSubject("附件");
email.setMsg("我的附件发给你了.");
// 添加附件
email.attach(attachment);
//发送邮件
email.send();
}
email.addCc("抄送人");
HtmlEmail
HtmlEmail类通常用来发送html格式的邮件,他也支持邮件携带普通文本、附件和内嵌图片。
ImageHtmlEmail
ImageHtmlEmail类通常是用来发送Html格式并内嵌图片的邮件,它拥有所有HtmlEmail的功能,但是图片主要是以html内嵌的为主。
POP3接收邮件
接收邮件常用的协议有pop3,imap和exchange。exchange是微软的邮箱协议,Jakarta Mail暂不支持。
JavaMail API中定义了一个java.mail.Store类,应用程序调用这个类的方法就可以获得用户邮箱中的各个邮件夹的信息。
javaMail中的使用Folder对象表示邮件夹,通过Folder对象的方法应用程序进而又可以获得该邮件夹中的所有邮件信息。
而每封邮件信息JavaMail又分别使用了一个Message对象进行封装
用于返回指定名称的邮件夹(Folder)对象
Folder folder = store.getFolder("inbox");
- 通过POP3协议获得的Store对象调用这个方法时,邮件夹名称只能指定为"INBOX"。
public class StoreMail {
final static String USER = "robot"; // 用户名
final static String PASSWORD = "password520"; // 密码
public final static String MAIL_SERVER_HOST = "mail.***.com"; // 邮箱服务器
public final static String TYPE_HTML = "text/html;charset=UTF-8"; // 文本内容类型
public final static String MAIL_FROM = "[email protected]"; // 发件人
public final static String MAIL_TO = "[email protected]"; // 收件人
public final static String MAIL_CC = "[email protected]"; // 抄送人
public final static String MAIL_BCC = "[email protected]"; // 密送人
public static void main(String[] args) throws Exception {
// 创建一个有具体连接信息的Properties对象
Properties prop = new Properties();
prop.setProperty("mail.debug", "true");
prop.setProperty("mail.store.protocol", "pop3");
prop.setProperty("mail.pop3.host", MAIL_SERVER_HOST);
// 1、创建session
Session session = Session.getInstance(prop);
// 2、通过session得到Store对象
Store store = session.getStore();
// 3、连上邮件服务器
store.connect(MAIL_SERVER_HOST, USER, PASSWORD);
// 4、获得邮箱内的邮件夹
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
// 获得邮件夹Folder内的所有邮件Message对象
Message[] messages = folder.getMessages();
for (int i = 0; i < messages.length; i++) {
String subject = messages[i].getSubject();
String from = (messages[i].getFrom()[0]).toString();
System.out.println("第 " + (i + 1) + "封邮件的主题:" + subject);
System.out.println("第 " + (i + 1) + "封邮件的发件人地址:" + from);
}
// 5、关闭
folder.close(false);
store.close();
}
}
-
//由于POP3协议无法获知邮件的状态,所以getUnreadMessageCount()得到的是收件箱的邮件总数
-
System.out.println("未读邮件数:" + folder.getUnreadMessageCount());
文件夹上的getPermanentFlags
方法返回一个Flags对象,该对象包含该文件夹实现支持的所有标志。
mail.pop3.host
Flags.Flag.SEEN | 邮件阅读标记,标识邮件是否已被阅读。 |
imap接收邮件
同样需要先开启授权码
public final static String MAIL_SERVER_HOST = "imap.163.com"; // 邮箱服务器
public static void main(String[] args) throws Exception {
// 创建一个有具体连接信息的Properties对象
Properties prop = new Properties();
prop.setProperty("mail.debug", "true");
//指定接收的邮件协议
prop.setProperty("mail.store.protocol", "imap");
prop.setProperty("mail.imap.host", MAIL_SERVER_HOST);
prop.setProperty("mail.imap.port", "143");
// 1、创建session
Session session = Session.getInstance(prop);
// 2、通过session得到Store对象
Store store = session.getStore("imaps");
// 3、连上邮件服务器
store.connect(MAIL_SERVER_HOST, USER, PASSWORD);
// 4、获得邮箱内的邮件夹 POP协议的话,这里只能是INBOX
Folder folder = store.getFolder("INBOX");
System.out.println("INBOX exist:" + folder.exists());
//
Folder defaultFolder = store.getDefaultFolder();
Folder[] folders = defaultFolder.list("*");
for (Folder folder1 : folders) {
IMAPFolder imapFolder = (IMAPFolder) folder1;
//javamail中使用id命令校验chekOpened,去掉
imapFolder.doCommand(new IMAPFolder.ProtocolCommand() {
@Override
public Object doCommand(IMAPProtocol p) throws ProtocolException {
p.id("FUTONG");
return null;
}
});
}
//以只读方式打开收件箱
folder.open(Folder.READ_ONLY);
System.out.println("邮件总数:" + folder.getMessageCount());
//由于POP3协议无法获知邮件的状态,所以getUnreadMessageCount()得到的是收件箱的邮件总数
System.out.println("未读邮件数:" + folder.getUnreadMessageCount());
//由于POP3协议无法获知邮件的状态,所以下面得到的结果始终都是为0
System.out.println("删除邮件数:" + folder.getDeletedMessageCount());
System.out.println("新邮件数:" + folder.getNewMessageCount());
// 获得邮件夹Folder内的所有邮件Message对象
Message[] messages = folder.getMessages();
for (int i = 0; i < messages.length; i++) {
String subject = messages[i].getSubject();
String from = (messages[i].getFrom()[0]).toString();
System.out.println("第 " + (i + 1) + "封邮件的主题:" + subject);
System.out.println("第 " + (i + 1) + "封邮件的发件人地址:" + from);
System.out.println("第 " + (i + 1) + "读写标识:" + messages[i].getFlags().contains(Flags.Flag.SEEN));
}
// 5、关闭
folder.close(false);
store.close();
}
1
附件下载
// 获得邮件夹Folder内的所有邮件Message对象
Message[] messages = folder.getMessages();
for (int i = 0; i < messages.length; i++) {
String subject = messages[i].getSubject();
String from = (messages[i].getFrom()[0]).toString();
System.out.println("第 " + (i + 1) + "封邮件的主题:" + subject);
System.out.println("第 " + (i + 1) + "封邮件的发件人地址:" + from);
System.out.println("第 " + (i + 1) + "读写标识:" + messages[i].getFlags().contains(Flags.Flag.SEEN));
Part mp = (Part) messages[i];
boolean containAttach = isContainAttach(mp);
if (containAttach) {
//包含附件,进行附件下载
System.out.println("第 " + (i + 1) + "封邮件,包含附件");
saveAttachMent(mp, "C:\\Users\\Administrator\\Desktop\\Attach");
}
}
这个不一定是static方法,我是为了在main方法里测试,才这么写的
/**
* * 判断此邮件是否包含附件
*
* @throws MessagingException
*/
public static boolean isContainAttach(Part part) throws Exception {
boolean attachflag = false;
String contentType = part.getContentType();
if (part.isMimeType("multipart/*")) {
Multipart mp = (Multipart) part.getContent();
// 获取附件名称可能包含多个附件
for (int j = 0; j < mp.getCount(); j++) {
BodyPart mpart = mp.getBodyPart(j);
String disposition = mpart.getDescription();
if ((disposition != null)
&& ((disposition.equals(Part.ATTACHMENT)) || (disposition
.equals(Part.INLINE)))) {
attachflag = true;
} else if (mpart.isMimeType("multipart/*")) {
attachflag = isContainAttach((Part) mpart);
} else {
String contype = mpart.getContentType();
if (contype.toLowerCase().indexOf("application") != -1)
attachflag = true;
if (contype.toLowerCase().indexOf("name") != -1)
attachflag = true;
}
}
} else if (part.isMimeType("message/rfc822")) {
attachflag = isContainAttach((Part) part.getContent());
}
return attachflag;
}
/**
* * 【保存附件】
*
* @throws Exception
* @throws IOException
* @throws MessagingException
* @throws Exception
*/
public static void saveAttachMent(Part part, String saveAttachPath) throws Exception {
String fileName = "";
if (part.isMimeType("multipart/*")) {
Multipart mp = (Multipart) part.getContent();
for (int j = 0; j < mp.getCount(); j++) {
BodyPart mpart = mp.getBodyPart(j);
String disposition = mpart.getDescription();
if ((disposition != null)
&& ((disposition.equals(Part.ATTACHMENT)) || (disposition
.equals(Part.INLINE)))) {
fileName = mpart.getFileName();
if (fileName.toLowerCase().indexOf("GBK") != -1) {
fileName = MimeUtility.decodeText(fileName);
}
saveFile(fileName, mpart.getInputStream(), saveAttachPath);
} else if (mpart.isMimeType("multipart/*")) {
fileName = mpart.getFileName();
} else {
fileName = mpart.getFileName();
if ((fileName != null)) {
fileName = MimeUtility.decodeText(fileName);
saveFile(fileName, mpart.getInputStream(), saveAttachPath);
}
}
}
} else if (part.isMimeType("message/rfc822")) {
saveAttachMent((Part) part.getContent(), saveAttachPath);
}
}
/**
* * 【真正的保存附件到指定目录里】
*/
private static void saveFile(String fileName, InputStream in, String storedir) throws Exception {
String osName = System.getProperty("os.name");
String separator = "";
if (osName == null)
osName = "";
if (osName.toLowerCase().indexOf("win") != -1) {
// 如果是window 操作系统
separator = "/";
if (storedir == null || storedir.equals(""))
storedir = "c:\tmp";
} else {
// 如果是其他的系统
separator = "/";
storedir = "/tmp";
}
File strorefile = new File(storedir + separator + fileName);
BufferedOutputStream bos = null;
BufferedInputStream bis = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(strorefile));
bis = new BufferedInputStream(in);
int c;
while ((c = bis.read()) != -1) {
bos.write(c);
bos.flush();
}
} catch (Exception e) {
// TODO: handle exception
} finally {
bos.close();
bis.close();
}
}