文件上传和邮件发送
1、文件上传
在Web应用中,文件上传和下载功能是非常常用的功能,今天来实现一下Java Web中的文件上传和下载功能
1.1、准备工作
对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的。
一般选择采用apache的开源工具common-fileupload这个文件上传组件。
common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。
下载最新的jar包
https://mvnrepository.com/artifact/commons-io/commons-io
https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload
在JavaWeb项目中导入jar包
【注意:使用IDEA导包需要注意修复路径,将lib目录添加到项目输出目录】
1.2、使用类介绍
【文件上传的注意事项】
-
为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
-
为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名(时间戳、UUID、md5、位运算算法)
-
要限制上传文件的最大值。
-
可以限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
【需要用到的类详解】
ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象, 在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象。所以,我们需要在进行解析工作前构造好DiskFileItemFactory对象,通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性。
FileItem类
在HTML页面input 必须有 name <input type="file" name="filename">
表单如果包含一个文件上传输入项的话,这个表单的enctype属性就必须设置为multipart/form-data
<%--通过表单上传
get:上传文件大小有限制
post: 上传文件大小没有限制--%>
<form action = "${pageContext.request.contextPath}/upload.do" method = "post" enctype="multipart/form-data">
上传用户:<input type="text" name="username"><br/>
上传文件1:<p><input type="file" name="file1"></p>
上传文件2:<p><input type="file" name="file2"></p>
<p><input type="submit" value="提交"> |<input type="reset"></p>
</form>
浏览器表单的类型如果为multipart/form-data , 在服务器端想获取数据就要通过流。
【常用方法介绍】
//isFormField方法用于判断FileItem类对象封装的数据是一个普通文本表单
//还是一个文件表单,如果是普通表单字段则返回true,否则返回false
boolean isFormField();
//getFieldName方法用于返回表单标签name属性的值。
String getFieldName();
//getString方法用于将FileItem对象中保存的数据流内容以一个字符串返回
String getString();
//getName方法用于获得文件上传字段中的文件名。
String getName();
//以流的形式返回上传文件的数据内容。
InputStream getInputStream()
//delete方法用来清空FileItem类对象中存放的主体内容
//如果主体内容被保存在临时文件中,delete方法将删除该临时文件。
void delete();
ServletFileUpload 类
ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象中 . 使用其parseRequest(HttpServletRequest) 方法可以将通过表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回。使用该方法处理上传文件简单易用。
1.3、代码编写
UploadFileServlet
public class UploadFileServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
//判断上传的文件是普通的表单还是带文件的表单
if (!ServletFileUpload.isMultipartContent(request)) {
return;//如果是普通文件,我们可以直接返回
} //如果通过了这个if,说明我们的表单是带文件上传的;
//创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件;
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(uploadPath);
if (!uploadFile.exists()) {//如果目录不存在,创建这样一个目录;
uploadFile.mkdir();
}
//临时路径,假如文件超过了预期的大小,我们就把他放到一个临时文件中,过几天自动删除,或者提醒用户转存为永久
String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File file = new File(tmpPath);
if (!file.exists()) {//如果目录不存在,创建这样一个目录;
file.mkdir();
}
//处理上传的文件,一般都需要通过流来获取,我们可以使用request.getInputStream(),原生态的文件上传流获取,十分麻烦
//但是我们都建议使用 Apache的文件上传组件来实现,common-fileupload,它需要依赖于 commons-io组件;
/*
* ServletFileUpLoad负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象,
* 在使用ServletFileUpLoad对象解析请求时需要DiskFileItemFactory对象。
* 所以,我们需要在进行解析工作前构造好DiskFileItemFactory对象,
* 通过ServletFileUpLoad对象的构造方法或setFileItemFactory()方法设置ServletFileUpLoad对象的fileItemFactory属性。
* */
//1.创建DiskFileItemFactory对象,处理文件上传路径或者大小限制的;
DiskFileItemFactory factory = getDiskFileItemFactory(file);
//2.获取ServletFileUpload
ServletFileUpload upload = getServletFileUpload(factory);
//3.处理上传的文件
String msg = uploadParseRequest(upload, request, uploadPath);
//servlet请求转发消息
request.setAttribute("msg",msg);
request.getRequestDispatcher("msg.jsp").forward(request,response);
} catch (FileUploadException e) {
e.printStackTrace();
}
}
public static DiskFileItemFactory getDiskFileItemFactory(File file) {
DiskFileItemFactory factory = new DiskFileItemFactory();
//通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中;
factory.setSizeThreshold(1024 * 1024); //缓存区大小为1M
factory.setRepository(file);//临时目录的保存目录,需要一个File
return factory;
}
public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
ServletFileUpload upload = new ServletFileUpload(factory);
//监听文件上传进度;
upload.setProgressListener(new ProgressListener() {
@Override
//pBytesRead:已经读取到的文件大小
//pContentLength : 文件大小
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("总大小:" + pContentLength + "已上传:" + pBytesRead);
}
});
//处理乱码问题
upload.setHeaderEncoding("UTF-8");
//设置单个文件的最大值
upload.setFileSizeMax(1024 * 1024 * 10);
//设置总共能够上传文件的大小
//1024 = 1kb * 1024 = 1M * 10 = 10M
upload.setSizeMax(1024 * 1024 * 10);
return upload;
}
public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest request,String uploadPath)
throws FileUploadException, IOException {
String msg = "";
//3.处理上传的文件
// 把前端请求解析,封装成一个FileItem对象
List<FileItem> fileItems = upload.parseRequest(request);
for (FileItem fileItem : fileItems) {
if (fileItem.isFormField()){ //判断上传的文件是普通的表单还是带文件的表单
//getFieldName指的是前端表单控件的name;
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8"); //处理乱码
System.out.println(name+":"+value);
}else { //判断它是上传的文件
//=======================处理文件===============================//
//拿到文件名字
String uploadFileName = fileItem.getName();
System.out.println("上传的文件名:"+uploadFileName);
//可能存在文件名不合法的情况
if (uploadFileName.trim().equals("")||uploadFileName==null){
continue;
}
//获得上传的文件名 /images/girl/paojie.png
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("\\") + 1);
//获得文件的后缀名
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
/*
如果文件后缀名 fileExtName 不是我们所需要的
就直接return,不处理,告诉用户文件类型不对。
*/
System.out.println("文件信息 [件名:"+fileName+"---文件类型"+fileExtName+"]");
//可以使用UUID(唯一识别的通用码),保证文件名唯一;
//UUID.randomUUID(),随机生一个唯一识别的通用码;
//网络传输中的东西,都需要序列化
//POJO,实体类,如果想要在多个电脑上运行,传输===>需要把对象都序列化了
//JNI = java native interface
//implements Serializable:标记接口,JVM--->Java栈 本地方法栈 native--->C++
String uuidPath = UUID.randomUUID().toString();
//=======================处理文件完毕===============================//
//存到哪? uploadPath
//文件真实存在的路径 realPath
String realPath = uploadPath+"\\"+uuidPath;
//给每个文件创建一个对应的文件夹
File realPathFile = new File(realPath);
if (!realPathFile.exists()){
realPathFile.mkdir();
}
//=======================存放地址完毕===============================//
//获得文件上传的流
InputStream inputStream = fileItem.getInputStream();
//创建一个文件输出流
//realPath = 真实的文件夹;
//差了一个文件; 加上输出文件的名字+"/"+uuidFileName
FileOutputStream fos = new FileOutputStream(realPath+"\\"+fileName);
//创建一个缓冲区
byte[] buffer = new byte[1024*1024];
//判断是否读取完毕
int len = 0;
//如果大于0说明还存在数据;
while ((len=inputStream.read(buffer))>0){
fos.write(buffer,0,len);
}
//关闭流
fos.close();
inputStream.close();
msg = "文件上传成功!";
fileItem.delete(); //上传成功,清除临时文件
//=======================文件传输完毕===============================//
}
}
return msg;
}
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<body>
<%--通过表单上传
get:上传文件大小有限制
post: 上传文件大小没有限制
--%>
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
<p><input type="file" name="file1"></p>
<p><input type="file" name="file1"></p>
<p><input type="submit" name="file1">|<input type="reset"></p>
</form>
</body>
</html>
msg.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>消息提示</title>
</head>
<body>
${msg}
</body>
</html>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>upload</servlet-name>
<servlet-class>com.kuang.servlet.UploadFileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>upload</servlet-name>
<url-pattern>/upload.do</url-pattern>
</servlet-mapping>
</web-app>
2、邮件发送
电子邮件
-
要在网络上实现邮件功能,必须要有专门的邮件服务器。
-
这些邮件服务器类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中。
-
SMTP服务器地址:一般是 smtp.xxx.com,比如163邮箱是smtp.163.com,qq邮箱是smtp.qq.com。
-
电子邮箱(E-Mail地址)的获得需要在邮件服务器上进行申请。比如我们要使用QQ邮箱,就需要开通邮箱功能;
传输协议
- SMTP协议
发送邮件:
我们通常把处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器)。 - POP3协议
接收邮件:
我们通常把处理用户pop3请求(邮件接收请求)的服务器称之为POP3服务器(邮件接收服务器)。
- 通过SMTP协议连接到SMTP服务器,然后发送一封邮件给网易的邮件服务器
- 网易分析发现需要去QQ的邮件服务器,通过SMTP协议将邮件转投给QQ的SMTP服务器
- QQ将接收到的邮件存储在[email protected]这个邮件账号的空间中
- 通过POP3协议连接到POP3服务器收取邮件
- 从[email protected]这个邮件账号的空间中取出邮件
- POP3服务器将取出来的邮件发送给[email protected]这个账号
【注意】有可能你收件人地址,发件人地址都正确了,控制台也打印了正确的信息,但是在收件箱就是收不到信息。这可能是收件服务器拒绝了你发的邮件(比如认为你的邮件是广告),这时候可能在垃圾箱里能找到,可能找不到。解决办法是重复的邮件内容不要多次发送,或者更换收件箱试试。
1、邮件服务器
①SMTP邮件服务器:替用户发送邮件和接收外面发送给本地用户的邮件
②POP3/IMAP邮件服务器:帮助用户读取SMTP邮件服务器接收进来的邮件
2、邮件传输协议
①电子邮件需要在邮件客户端和邮件服务器之间,以及两个邮件服务器之间进行邮件传递,那就必须要遵守一定的规则,这个规则就是邮件传输协议
②SMTP协议:全称为 Simple Mail Transfer Protocol,简单邮件传输协议。它定义了邮件客户端软件和SMTP邮件服务器之间,以及两台SMTP邮件服务器之间的通信规则
③POP3协议:全称为 Post Office Protocol,邮局协议。它定义了邮件客户端软件和POP3邮件服务器的通信规则
④IMAP协议:全称为 Internet Message Access Protocol,Internet消息访问协议,它是对POP3协议的一种扩展,也是定义了邮件客户端软件和IMAP邮件服务器的通信规则
所有的邮件服务器和邮件客户端软件程序都是基于上面的协议编写的
Java发送邮件
概述:
我们将用代码完成邮件的发送。这在实际项目中应用的非常广泛,比如注册需要发送邮件进行账号激活,再比如OA项目中利用邮件进行任务提醒等等。
使用Java发送 E-mail 十分简单,但是首先你应该准备 JavaMail API 和Java Activation Framework 。
得到两个jar包:
- mail.jar
- activation.jar
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
JavaMail 是sun公司(现以被甲骨文收购)为方便Java开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发包,它支持一些常用的邮件协议,如前面所讲的SMTP,POP3,IMAP,还有MIME等。我们在使用JavaMail API 编写邮件时,无须考虑邮件的底层实现细节,只要调用JavaMail 开发包中相应的API类就可以了。
我们可以先尝试发送一封简单的邮件,确保电脑可以连接网络。
- 创建包含邮件服务器的网络连接信息的Session对象。
- 创建代表邮件内容的Message对象
- 创建Transport对象,连接服务器,发送Message,关闭连接
主要有四个核心类,我们在编写程序时,记住这四个核心类,就很容易编写出Java邮件处理程序。
2.1、纯文本邮件
先在项目中导入jar包:
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
//发送一封简单的邮件
public class MailDemo01 {
//简单邮件:没有附件和图片,纯文本邮件
//复杂邮件:有附件和图片
//要发送邮件,需要获得协议和支持!开启服务POP3和SMTP服务
//授权码:pxeolkotfaiibcca
public static void main(String[] args) throws Exception {
Properties prop = new Properties();
prop.setProperty("mail.host", "smtp.qq.com"); //设置QQ邮件服务器
prop.setProperty("mail.transport.protocol", "smtp"); // 邮件发送协议
prop.setProperty("mail.smtp.auth", "true"); // 需要验证用户名密码
// 关于QQ邮箱,还要设置SSL加密,加上以下代码即可,其他邮箱不需要
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
// prop.put("mail.smtp.ssl.protocols", "TLSv1.2");
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);
//使用JavaMail发送邮件的5个步骤
//1、创建定义整个应用程序所需的环境信息的 Session 对象
//使用QQ邮箱的时候才需要,其他邮箱不需要这一段代码
Session session = Session.getDefaultInstance(prop, new Authenticator() {//获取和SMTP服务器的连接对象
public PasswordAuthentication getPasswordAuthentication() {
//发件人邮件用户名、授权码
return new PasswordAuthentication("[email protected]", "授权码");
}
});
//开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
session.setDebug(true);
//2、通过session得到transport对象
Transport ts = session.getTransport();//通过这一次和SMTP服务器的连接对象获取发送邮件的传输对象
//3、使用邮箱的用户名和授权码连上SMTP邮件服务器,即登陆
ts.connect("smtp.qq.com", "[email protected]", "授权码");
//4、创建邮件对象MimeMessage——点击网页上的写信
//创建一个邮件对象
MimeMessage message = new MimeMessage(session);
//指明邮件的发件人——在网页上填写发件人
message.setFrom(new InternetAddress("[email protected]"));//设置发件人
//指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发——在网页上填写收件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));//设置收件人
//邮件的标题——在网页上填写邮件标题
message.setSubject("简单邮件发送实现");//设置邮件主题
//邮件的文本内容——在网页上填写邮件内容
message.setContent("<h2 style='color:red'>你好啊!</h2>", "text/html;charset=UTF-8");//设置邮件的具体内容
//5、发送邮件——在网页上点击发送按钮
ts.sendMessage(message, message.getAllRecipients());
//6、关闭连接对象,即关闭服务器上的连接资源
ts.close();
}
}
遇到的问题:
解决方法:https://blog.csdn.net/sunon_/article/details/126546007
prop.put("mail.smtp.ssl.protocols", "TLSv1.2");
2.2、内嵌图片邮件
先认识两个类一个名词:
MIME(多用途互联网邮件扩展类型)
MimeBodyPart类:
javax.mail.internet.MimeBodyPart类,表示的是一个MIME消息,它和MimeMessage类一样都是从Part接口继承过来。
MimeMultipart类:
javax.mail.internet.MimeMultipart是抽象类,Multipart的实现子类,它用来组合多个MIME消息。一个MimeMultipart对象可以包含多个代表MIME消息的MimeBodyPart对象。
MimeMultipart对象的使用的时候需要设置setSubType()的属性值,一共就下面3种取值:
我们在使得的时候如果不知道使用哪一个,直接使用mixed即可,使用这个属性值一定不会报错。
创建包含内嵌图片的邮件
前面的例子中是单独的使用HTML或者是纯文本内容,但是有时候我们需要在纯文本中使用内嵌的方式显示一些图片,因此就要将纯文本和内嵌图片单独存放在MimeBodyPart中然后再将其存放在一个Mimemultipart对象中即可。
//发送包含图片的复杂邮件
public class MailDemo02 {
public static void main(String[] args) throws Exception {
Properties prop = new Properties();
prop.setProperty("mail.host", "smtp.qq.com"); //设置QQ邮件服务器。
prop.setProperty("mail.transport.protocol", "smtp"); // 邮件发送协议。
prop.setProperty("mail.smtp.auth", "true"); // 需要验证用户名密码。
// 关于QQ邮箱,还要设置SSL加密,加上以下代码即可。大厂,其他邮箱不需要。
// 我这里加上这段报错,注掉就好了,不知道咋回事。
/*MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);*/
//使用JavaMail发送邮件的5个步骤:
//1、创建定义整个应用程序所需的环境信息的 Session 对象。
//QQ才有!其他邮箱不需要。
Session session = Session.getDefaultInstance(prop, new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
//发件人邮件用户名、授权码。
return new PasswordAuthentication("[email protected]", "pxeolkotfaiibcca");
}
});
//开启Session的debug模式,这样就可以查看到程序发送Email的运行状态。
session.setDebug(true);
//2、通过session得到transport对象。
Transport ts = session.getTransport();
//3、使用邮箱的用户名和授权码连上SMTP邮件服务器。
ts.connect("smtp.qq.com", "[email protected]", "pxeolkotfaiibcca");
//4、创建邮件:写邮件。
//注意需要传递Session。
MimeMessage message = new MimeMessage(session);
//指明邮件的发件人
message.setFrom(new InternetAddress("[email protected]"));
//指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发。
message.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
//邮件的标题。
message.setSubject("图片邮件发送");
//发送包含图片的复杂邮件==========================================
//准备图片数据。
MimeBodyPart image = new MimeBodyPart();
DataHandler dh = new DataHandler(new FileDataSource("F:\\JavaStudy\\mail-java\\src\\image\\56课截图.png"));
image.setDataHandler(dh);//在我们的Body中放入这个处理的图片数据。
image.setContentID("56.png");//给图片设置一个id,我们在后面可以使用!
// 准备正文数据。
MimeBodyPart text = new MimeBodyPart();
//这里的cid就是上面的哪个setContentID。
text.setContent("这是一封邮件正文带图片<img src='cid:56.png'>的邮件", "text/html;charset=UTF-8");
// 描述数据关系。
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(text);
mm.addBodyPart(image);
mm.setSubType("related");//设置MimeMultipart对象的相对熟悉为related,即发送的数据为文本+非附件资源。
//设置到消息中,保存修改。
message.setContent(mm);//把最后编辑好的邮件放到消息当中。
message.saveChanges();//保存上面的修改。
//发送包含图片的复杂邮件==========================================
//5、发送邮件
ts.sendMessage(message, message.getAllRecipients());
//6、关闭连接
ts.close();
}
}
注意:
image.setContentID("56.png");//给图片设置一个id,我们在后面可以使用!
如果名字中含有中文邮件就会显示不出来!
2.3、图片和附件邮件
//发送包含附件的复杂邮件。
public class MailDemo03 {
public static void main(String[] args) throws Exception {
Properties prop = new Properties();
prop.setProperty("mail.host", "smtp.qq.com"); //设置QQ邮件服务器。
prop.setProperty("mail.transport.protocol", "smtp"); // 邮件发送协议。
prop.setProperty("mail.smtp.auth", "true"); // 需要验证用户名密码。
// 关于QQ邮箱,还要设置SSL加密,加上以下代码即可。大厂,其他邮箱不需要。
//我这里加上这段报错,注掉就好了,不知道咋回事。
/*MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);*/
//使用JavaMail发送邮件的5个步骤:
//1、创建定义整个应用程序所需的环境信息的 Session 对象。
//QQ才有!其他邮箱不需要。
Session session = Session.getDefaultInstance(prop, new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
//发件人邮件用户名、授权码。
return new PasswordAuthentication("[email protected]", "pxeolkotfaiibcca");
}
});
//开启Session的debug模式,这样就可以查看到程序发送Email的运行状态。
session.setDebug(true);
//2、通过session得到transport对象。
Transport ts = session.getTransport();
//3、使用邮箱的用户名和授权码连上SMTP邮件服务器。
ts.connect("smtp.qq.com", "[email protected]", "pxeolkotfaiibcca");
//4、创建邮件:写邮件。
//注意需要传递Session。
MimeMessage message = new MimeMessage(session);
//指明邮件的发件人
message.setFrom(new InternetAddress("[email protected]"));
//指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发。
message.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
//邮件的标题。
message.setSubject("复杂邮件发送");
//发送包含附件的复杂邮件=====================================================
/*
编写邮件内容
1.图片
2.附件
3.文本
*/
//图片
MimeBodyPart body1 = new MimeBodyPart();
body1.setDataHandler(new DataHandler(new FileDataSource("F:\\JavaStudy\\mail-java\\src\\image\\56课截图.png")));
body1.setContentID("56.png"); //图片设置ID
//文本
MimeBodyPart body2 = new MimeBodyPart();
body2.setContent("请注意,我不是广告<img src='cid:56.png'>","text/html;charset=utf-8");
//附件
MimeBodyPart body3 = new MimeBodyPart();
body3.setDataHandler(new DataHandler(new FileDataSource("F:\\JavaStudy\\mail-java\\src\\file\\1.txt")));
body3.setFileName("test.c"); //附件设置名字
MimeBodyPart body4 = new MimeBodyPart();
body4.setDataHandler(new DataHandler(new FileDataSource("F:\\JavaStudy\\mail-java\\src\\file\\1.txt")));
body4.setFileName("test.txt"); //附件设置名字
//拼装邮件正文内容
MimeMultipart multipart1 = new MimeMultipart();
multipart1.addBodyPart(body1);
multipart1.addBodyPart(body2);
multipart1.setSubType("related"); //1.文本和图片内嵌成功!
//new MimeBodyPart().setContent(multipart1); //将拼装好的正文内容设置为主体
MimeBodyPart contentText = new MimeBodyPart();
contentText.setContent(multipart1);
//拼接附件
MimeMultipart allFile =new MimeMultipart();
allFile.addBodyPart(body3); //附件
allFile.addBodyPart(body4); //附件
allFile.addBodyPart(contentText);//正文
allFile.setSubType("mixed"); //正文和附件都存在邮件中,所以类型设置为mixed;
//设置到消息中,保存修改
message.setContent(allFile);//将MimeMultipart放入消息对象中。
message.saveChanges();//保存上面的修改。
//发送包含附件的复杂邮件=====================================================
//5、发送邮件
ts.sendMessage(message, message.getAllRecipients());
//6、关闭连接
ts.close();
}
}
3、JavaWeb发送邮件
现在很多的网站都提供有用户注册功能, 通常我们注册成功之后就会收到一封来自注册网站的邮件。邮件里面的内容可能包含了我们的注册的用户名和密码以及一个激活账户的超链接等信息。今天我们也来实现一个这样的功能,用户注册成功之后,就将用户的注册信息以Email的形式发送到用户的注册邮箱当中,实现发送邮件功能就得借助于JavaMail了。
思路:把收件人地址改成从前端接收过来的参数
1、导入依赖
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
2、实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String username;
private String password;
private String email;
}
3、Servlet处理请求
//脚手架
public class RegisterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接收用户请求,封装成对象
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
System.out.println(username);
System.out.println(password);
System.out.println(email);
//把用户的请求封装成一个对象
User user = new User(username,password,email);
//启动线程,重定向页面
/*
用户注册成功后,给用户发送一封邮件
我们使用线程来专门发送邮件,防止出现耗时、白屏和网站注册人数过多的情况
*/
SendMail send = new SendMail(user);
send.start();
//注册用户
req.setAttribute("message","注册成功,我们已经发了一封要了注册信息的电子邮件,请查收!如网络不稳定,等稍等");
req.getRequestDispatcher("info.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
4、邮件发送工具类
//网站3秒原则:用户体验
//多线程实现用户体验!(异步处理)
public class SendMail extends Thread{
//用于给用户发送邮件的邮箱
private String from = "[email protected]" ;
//邮箱的用户名
private String username = "[email protected]" ;
//邮箱的密码
private String password = "pxeolkotfaiibcca";
//发送邮件的服务器地址
private String host ="smtp.qq.com" ;
private User user;
public SendMail(User user){
this.user = user;
}
//重写run方法的实现,在run方法中发送邮件给指定的用户
@Override
public void run() {
try {
Properties prop = new Properties();
prop.setProperty("mail.host",host);///设置QQ邮件服务器
prop.setProperty("mail.transport.protocol","smtp");///邮件发送协议
prop.setProperty("mail.smtp.auth","true");//需要验证用户密码
//prop.put("mail.smtp.ssl.protocols", "TLSv1.2");
//QQ邮箱需要设置SSL加密
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable","true");
prop.put("mail.smtp.ssl.socketFactory",sf);
//使用javaMail发送邮件的5个步骤
//1.创建定义整个应用程序所需要的环境信息的session对象
Session session= Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("[email protected]", "pxeolkotfaiibcca");
}
});
//开启session的debug模式,这样可以查看到程序发送Email的运行状态
session.setDebug(true);
//2.通过session得到transport对象
Transport ts = session.getTransport();
//3.使用邮箱的用户名和授权码连上邮件服务器
ts.connect(host,username,password);
//4.创建邮件:写文件
//注意需要传递session
MimeMessage message = new MimeMessage(session);
//指明邮件的发件人
message.setFrom(new InternetAddress(from));
//指明邮件的收件人
message.setRecipient(Message.RecipientType.TO,new InternetAddress(user.getEmail()));//从前端接收的
//邮件标题
message.setSubject("注册通知");
//邮件的文本内容
String info = "恭喜你("+user.getUsername()+")成功注册!"+"密码:"+user.getPassword();
message.setContent(info,"text/html;charset=UTF-8");
message.saveChanges();//保存更改
//5.发送邮件
ts.sendMessage(message,message.getAllRecipients());
//6.关闭连接
ts.close();
}catch (Exception e){
System.out.println(e);
}
}
}
5、配置web.xml
<servlet>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>com.wang.servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/RegisterServlet</url-pattern>
</servlet-mapping>
6、前端请求页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/RegisterServlet" method="post">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
邮箱:<input type="text" name="email"><br/>
<input type="submit" value="注册">
</form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>注册成功!</h1>
${message}
</body>
</html>
遇到的问题,如果没有配置
prop.put("mail.smtp.ssl.protocols", "TLSv1.2");
同样会报:
javax.mail.MessagingException: Could not connect to SMTP host: smtp.qq.com, port: 465;
nested exception is:
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
但是前端很奇怪还是提示成功!