文件上传
注意事项:
- 为保证服务器安全,上传的文件应该放在外界无法直接访问的目录下,比如放在WEB-INF目录下
- 为防止文件覆盖,要为上传的文件产生唯一一个文件名 运用时间戳、uuid、md5
- 要限制上传文件的最大值
- 可以限制上传文件的类型,在收到上传文件名时,判断后缀是否合法
用到的jar包:commons-io-2.6.jar、commons-fileupload-1.4.jar
前端代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
上传用户:<input type="text" name="username"><br/>
<p><input type="file" name="file1"></p>
<p><input type="file" name="file2"></p>
<p><input type="submit" value="提交"> | <input type="reset" value="重置"></p>
</form>
</body>
</html>
Servlet代码:
public class FileServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 判断上传的文件是普通表单还是文件的表单
if (!ServletFileUpload.isMultipartContent(req)) {
return; //终止方法运行,说明这是一个普通表单
}
// 创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(uploadPath);
if (!uploadFile.exists()) {
uploadFile.mkdir(); //创建这个目录
}
// 缓存,临时文件
// 临时路径,假如文件超过预期的大小,我们就把他放到一个临时文件中,过几天自动删除,或者提醒用户转存为永久
String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
File file = new File(tempPath);
if (!file.exists()) {
file.mkdir(); //创建临时目录
}
//1. 创建DiskFileItemFactory对象,处理文件上传路径或者大小限制的
DiskFileItemFactory factory = getDiskFileItemFactory(file);
//2. 获取ServletFileUpload
ServletFileUpload upload = getServletFileUpload(factory);
//3.处理上传的文件
try {
String msg = uploadParseRequest(upload, req, uploadPath);
req.setAttribute("message",msg);
req.getRequestDispatcher("info.jsp").forward(req,resp);
} catch (FileUploadException e) {
e.printStackTrace();
}
}
public static DiskFileItemFactory getDiskFileItemFactory(File file){
//1. 创建DiskFileItemFactory对象,处理文件上传路径或者大小限制的
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
public void update(long l, long l1, int i) { // l:已经读取的文件大小 l1:文件大小
System.out.println("总大小:"+l1+"已上传:"+l);
}
});
// 处理乱码问题
upload.setHeaderEncoding("utf-8");
// 设置单个文件的最大值
upload.setFileSizeMax(1024*1024*10); //10M
// 设置总共能够上传的文件的大小
upload.setSizeMax(1024*1024*10);
return upload;
}
public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest request,String uploadPath) throws FileUploadException, IOException {
String msg = "";
// 把前端请求解析,封装成一个FileItem对象,需要从ServletFileUpload对象中获取
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;
}
//获得上传的文件名
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
//获得文件后缀名
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
System.out.println("文件信息[文件名:"+fileName+"----文件类型:"+fileExtName+"]");
// 使用UUID,保证文件名唯一 UUID.randomUUID() 随机生成一个唯一识别的通用码
String uuidPath = UUID.randomUUID().toString();
//================处理文件完毕=================
// 存到那? uploadPath
// 文件真是存在的路径 realPath
String realPath = uploadPath+"/"+uuidPath;
//给每个文件创建一个对应的文件夹
File realPathFile = new File(realPath);
if(!realPathFile.exists()){
realPathFile.mkdir();
}
//===============存放地址完毕==================
// 获得文件上传流
InputStream is = fileItem.getInputStream();
// 创建一个文件输入流
// realPath = 真实文件夹
// 差一个文件;加一个输入文件的名字+"/"+uuidFileName
FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);
// 创建一个缓冲区
byte[] buffer = new byte[1024];
int len = 0;
while((len=is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
fos.close();
is.close();
msg = "文件上传成功";
fileItem.delete(); // 上传成功,清楚临时文件
}
}
return msg;
}
}
文件会保存在在输出目录下:
邮件发送
1. 文本邮件
用到的jar包:activation-1.1.1 mail-1.4.7.jar
//发送简单邮件
public class MailTest {
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发送邮件的五个步骤
// 创建定义整个应用程序所需的环境信息的Session对象 qq才有
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("发送方邮箱","授权码");
}
});
// 开启session的debug模式,这样就可以看到程序发送Email的运行状态
session.setDebug(true);
//2. 通过session得到transport对象
Transport ts = session.getTransport();
//3. 使用邮箱的用户名和授权码连接到邮件服务器
ts.connect("smtp.qq.com","发送方邮箱","授权码");
//4. 创建邮件
// 创建邮件对象
MimeMessage message = new MimeMessage(session);
// 指明邮件的发件人
message.setFrom(new InternetAddress("发送方邮箱"));
// 指明邮件收件人,收件人和发件人是一样的,自己给自己发
message.setRecipient(Message.RecipientType.TO,new InternetAddress("接收方邮箱"));
// 邮件的标题
message.setSubject("只包含文本的简单邮件");
// 邮件的文本内容
message.setContent("<h1 style='color:red'>你好啊</h1>","text/html;charset=utf-8");
//5. 发送邮件
ts.sendMessage(message, message.getAllRecipients());
ts.close();
}
}
2.附件邮件
public class test {
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
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发送邮件的五个步骤
// 创建定义整个应用程序所需的环境信息的Session对象 qq才有
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("邮箱","授权码");
}
});
// 开启session的debug模式,这样就可以看到程序发送Email的运行状态
session.setDebug(true);
//2. 通过session得到transport对象
Transport ts = session.getTransport();
//3. 使用邮箱的用户名和授权码连接到邮件服务器
ts.connect("smtp.qq.com","邮箱","授权码");
//4. 创建邮件
// 创建邮件对象
MimeMessage message = new MimeMessage(session);
// 指明邮件的发件人
message.setFrom(new InternetAddress("邮箱"));
// 指明邮件收件人,收件人和发件人是一样的,自己给自己发
message.setRecipient(Message.RecipientType.TO,new InternetAddress("邮箱"));
// 邮件的标题
message.setSubject("带图片的邮件");
// 准备图片数据
MimeBodyPart image = new MimeBodyPart();
// 图片需要经过数据处理,DataHandler :数据处理
DataHandler dh = new DataHandler(new FileDataSource("路径"));
image.setDataHandler(dh);// 在boby中放入处理的图片数据
image.setContentID("1.jpg"); // 给图片设置一个id,后面可以使用
// 准备正文数据
MimeBodyPart text = new MimeBodyPart();
text.setContent("这是<img src = 'cid:1.jpg'>的照片","text/html;charset=utf-8");// 这里的cid对象上一行的contentID
// 附件
MimeBodyPart body3 = new MimeBodyPart();
body3.setDataHandler(new DataHandler(new FileDataSource("路径")));
body3.setFileName("db.properties");
// 拼接邮件正文
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(text);
mm.addBodyPart(image);
mm.setSubType("related"); // related是内嵌资源 如果为mixed是附件
// 将拼接好的正文内容设置为主体
MimeBodyPart contentText = new MimeBodyPart();
contentText.setContent(mm);
//拼接附件
MimeMultipart allFile = new MimeMultipart();
allFile.addBodyPart(body3); // 附件
allFile.addBodyPart(contentText);//正文 文字和图片
allFile.setSubType("mixed");
//设置到消息中,保存修改
message.setContent(mm);
message.saveChanges();
//5. 发送邮件
ts.sendMessage(message, message.getAllRecipients());
ts.close();
}
}
案例(注册时邮件确认)
前端:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<div style="text-align: center">
<h1>用户注册</h1>
<form action="${pageContext.request.contextPath}/register" method="post">
用户名:<input type="text" name="username"><br/>
<br/>
密码:<input type="password" name="password"><br/>
<br/>
邮箱:<input type="text" name="email"><br/>
<br/>
<input type="submit" value="注册">
</form>
</div>
</body>
</html>
多线程实现邮件发送功能
为什么实现多线程? 因为连接邮箱服务器比较慢,用户可能会等待较长时间,用线程开启可以加快速度,另也可防止人数过多
public class SendMail extends Thread{
private String form = "发送方用户名";
private String username = "发送方邮箱"; //模拟系统邮箱
private String password = "发送方授权码";
private String host = "smtp.qq.com";
private User user;
public SendMail(User user){
this.user = user;
}
@Override
public void run() {
Properties prop = new Properties();
prop.setProperty("mail.host","smtp.qq.com"); // 设置qq邮件服务器
prop.setProperty("mail.transport.protocol","smtp"); // 邮件发送协议
prop.setProperty("mail.smtp.auth","true"); // 需要验证用户名和密码
try{
// 关于qq邮箱,还要设置SSL加密,加上以下代码即可
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable","true");
prop.put("mail.smtp.ssl.socketFactory",sf);
// 使用javaMail发送邮件的五个步骤
// 创建定义整个应用程序所需的环境信息的Session对象 qq才有
Session session = Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("邮箱","授权码");
}
});
// 开启session的debug模式,这样就可以看到程序发送Email的运行状态
session.setDebug(true);
//2. 通过session得到transport对象
Transport ts = session.getTransport();
//3. 使用邮箱的用户名和授权码连接到邮件服务器
ts.connect(host,username,password);
//4. 创建邮件
// 创建邮件对象
MimeMessage message = new MimeMessage(session);
// 指明邮件的发件人
message.setFrom(new InternetAddress(form));
// 指明邮件收件人,收件人和发件人是一样的,自己给自己发
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");
//5. 发送邮件
ts.sendMessage(message, message.getAllRecipients());
ts.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
Servlet
public class registerServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try{
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setEmail(email);
System.out.println(user);
SendMail sendMail = new SendMail(user);
sendMail.start();
req.setAttribute("message","注册成功,我们给您发了一封带有注册信息的电子邮件,请查收!");
req.getRequestDispatcher("info.jsp").forward(req,resp);
}catch (Exception e){
e.printStackTrace();
req.setAttribute("message","注册失败");
req.getRequestDispatcher("info.jsp").forward(req,resp);
}
}
}