文件上传和下载
一.文件的上传
(一)基本概念及其入门案例
1.什么是文件上传:将本地的文件上传到服务器端。
2.应用:百度网盘,上传照片,上传附件。
3.javaweb端实现文件上传;
客户端:需要文件的输入项 <input type="file"/>
必须有三点设置:
1)type="file" name 必须有 name="myfile"
2)form表单 method="post"提交方式 (get参数显示在url上,get数据大小1k)
3)form表单 enctype="multipart/form-data" 编码格式
服务端:写一段文件上传的程序。
requestl.getInputStream(); 获取输入流
System.out.write();
4.fileupload 文件上传的组件
1)jspsmartupload 上传组件,嵌入在jsp中。model1时代,jsp。
2)jsp+servlet时代 fileuplaod
5.fileupload的jar commons-fileupload-1.2.1jar包和commons-io-1.4jar包 要一起使用。 依赖。
package cn.itcast.servlet; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import cn.itcast.util.UploadUtil; public class UploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filedesc = request.getParameter("filedesc"); System.out.println("文件描述:"+filedesc); // 获取输入流 //InputStream in = request.getInputStream(); // 打印控制台上 /*int b; while((b = in.read()) != -1){ System.out.write(b); } System.out.flush();*/ if(!ServletFileUpload.isMultipartContent(request)){ throw new RuntimeException("请设置正确的enctype"); } /** * 1.创建磁盘文件项工厂 */ DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置内存缓冲区的大小 factory.setSizeThreshold(2*1024*1024); //2M // 设置临时文件的存储位置 String temppath = this.getServletContext().getRealPath("/temp"); File filetemp = new File(temppath); factory.setRepository(filetemp); /** * 2.创建文件上传类 */ ServletFileUpload upload = new ServletFileUpload(factory); // 设置上传文件的总大小 upload.setSizeMax(50L*1024*1024); // 50M // 设置文件名称的编码 upload.setHeaderEncoding("UTF-8"); /** * 3.解析request */ try { List<FileItem> list = upload.parseRequest(request); /** * 4.循环遍历list集合,拿到fileItem对象,判断是否普表单项 */ for (FileItem fileItem : list) { // isFormField() if(fileItem.isFormField()){ // 普通表单项 // 获取参数的名称 String name = fileItem.getFieldName(); // 获取值 //String value = fileItem.getString(); String value = fileItem.getString("UTF-8"); System.out.println(name+" = "+value); }else{ // 文件上传项 // 获取文件的名称 String filename = fileItem.getName(); // 先判断filename不能空 if(filename == null || filename.trim().length() == 0){ throw new RuntimeException("请选择文件"); } // 解决IE6的问题 D:\class\resource\hello.txt int index = filename.lastIndexOf("\\"); if(index != -1){ filename = filename.substring(index+1); } //解决文件名重名的问题 filename = UUID.randomUUID().toString()+"_"+filename; // 目录分离 String dir = UploadUtil.getRanromDir(filename); System.out.println("文件名称:"+filename); // 获取输入流 InputStream in = new BufferedInputStream(fileItem.getInputStream()); // 先获取upload的绝对路径 String filepath = this.getServletContext().getRealPath("/upload"+dir); // 创建多级目录 new File(filepath).mkdirs(); // 创建file对象 File file = new File(filepath,filename); // 输出流 OutputStream os = new BufferedOutputStream(new FileOutputStream(file)); int b; while((b = in.read()) != -1){ os.write(b); } os.close(); in.close(); // 删除临时文件(必须写在流关闭之后) fileItem.delete(); } } } catch (FileUploadException e) { e.printStackTrace(); } } public static void main(String[] args) { System.out.println(System.getProperty("java.io.tmpdir")); } }
(二)入门案例存在的问题
1.IE6上传文件的问题:
产生原因:把文件的绝对路径传过来了。
解决办法:切割。把文件名称切出来。
// 解决IE6的问题 D:\class\resource\hello.txt
int index = filename.lastIndexOf("\\");
if(index != -1){
filename = filename.substring(index+1);
}
2.注意事项(*****)
String filedesc = request.getParameter("filedesc"); 在文件上传 enctype="multipart/form-data"拿不到值了。
想拿到值就下面方法。
// 获取参数的名称
String name = fileItem.getFieldName();
// 获取值
String value = fileItem.getString();
(三)文件上传的核心类及其API
1.磁盘文件项工厂类 DiskFileItemFactory
1)DiskFileItemFactory(int sizeThreshold, java.io.File repository) 第一个参数内存缓冲区的大小 第二个参数临时文件的存储位置
内存缓冲区:上传文件时,文件首先会上传到内存缓冲区中,上传的文件的大小超过设置的内存缓冲区的大小,就会产生临时文件。
临时存储位置:用来保存临时文件的。
2)void setSizeThreshold(int sizeThreshold) 设置内存缓冲区的大小 默认10k
3)void setRepository(java.io.File repository) 设置临时文件存储位置 System.getProperty("java.io.tmpdir") C:\Users\ADMINI~1\AppData\Local\Temp\
2. 文件上传类 ServletFileUpload
1)static boolean isMultipartContent(javax.servlet.http.HttpServletRequest request) 判断enctype是否是multipart方式
2)java.util.List parseRequest(javax.servlet.http.HttpServletRequest request) 解析request 返回list<FileItem>集合
3)void setSizeMax(long sizeMax) 设置上传所有文件的总大小 和 void setFileSizeMax(long fileSizeMax) 设置单个上传文件的大小
4)(*****)void setHeaderEncoding(java.lang.String encoding) 设置编码 可以解决中文文件名乱码的问题
5)void setProgressListener(ProgressListener pListener) 设置进度条的监听器 进度条速度 剩余时间 剩余大小
3. 文件项FileItem
1)boolean isFormField() 判断是否是普通表单项还是文件上传项
if(fileItem.isFormFiele()){
// 表单
2)java.lang.String getFieldName() 获取参数的名称
3)java.lang.String getString() 获取值
4)(*****)java.lang.String getString(java.lang.String encoding) 设置表单中文的编码 解决普通表单项的中文乱码的问题
}else{
// 文件
5)java.io.InputStream getInputStream() 获取输入流
6)java.lang.String getName() 获取文件名称
}
7)void delete() 删除临时文件((必须写在流关闭之后))
(四)多文件上传案例(js控制)
需求:多文件上传。
(五)上传文件的扩展
1.上传文件存放目录问题:
1)在webroot目录下,安全级别较低,允许用户直接访问。
购物商城的网站:京东。
2)上传文件目录访问WEB-INF目录下,安全级别较高。通过程序。
例子:视频网站。
2.文件名重名的问题
解决办法:UUID+"_"+文件名称
3.解决一个目录内文件过多的问题(目录分离算法)
1)根据上传文件的时间(周,月)
2)根据上传文件的数量(3000)
3)根据用户创建一个文件夹(张三,李四)
4)根据唯一文件名的hashcode值算法。
二.文件的下载
(一)基本概念及其入门案例
1.什么的文件的下载:将服务器的文件下载到本地。
2.应用:百度网盘,下载歌曲,下载图片。
3.javaweb实现文件的下载:
1)超链接下载 <a href="文件的绝对路径">文件名称</a>
浏览器可以解析你文件的格式。浏览器直接打开。
2)程序的文件下载。
接收文件的名称,获取download的绝对路径,并且拼接file对象,读入到输入流中。
两点注意:两个头一个流
两个响应头:设置Content-Type 属性 MIME类型
设置Content-Disposition 值attachment;filename= + 文件名称 以附件的形式打开。
一个响应流:向浏览器输出 response.getOutputStream()
(二)文件下载扩展案例
需求:在磁盘随便指定一个目录,要把该目录下的所有文件及其子目录下的所有文件列在页面上,并且提供下载。
采用广度非递归的遍历,依赖于数据结构。队列 FIFO 先进先出 JDK5.0 提供了接口 Queue
package cn.itcast.servlet; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 下载的入门案例 * @author Administrator * */ public class DownloadServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取文件的名称 String filename = request.getParameter("filename"); // 获取download的绝对路径 String filepath = this.getServletContext().getRealPath("/download"); // 创建file对象 File file = new File(filepath,filename); // 读入到输入流 InputStream in = new BufferedInputStream(new FileInputStream(file)); // 设置两个头 String mimeType = this.getServletContext().getMimeType(filename); // 设置类型 response.setContentType(mimeType); // 设置以附件形式打开 response.setHeader("Content-Disposition", "attachment;filename="+filename); // 输出流 OutputStream os = response.getOutputStream(); int b; while((b = in.read()) != -1){ os.write(b); } os.close(); in.close(); } }
2.get方式提交 中文乱码
filepath = new String(filepath.getBytes("ISO-8859-1"),"UTF-8");
3.IE6中文乱码
产生原因:代码没有问题。IE6对中文的编码有bug。
解决办法:自己编码。URLEncoder.encode(f.getCanonicalPath(), "UTF-8")
4.弹出的下载框显示的中文乱码
三.JavaMail(邮件)
(一)邮件的基本概念及其传输过程
1.为什么学习邮件:比较好的用户体验,比较火的技术。
2.常见邮件:祝福邮件,通知邮件,垃圾邮件
3.基本概念
1)邮件服务器:是一台电脑,装关于邮件服务器的软件。收发邮件。
2)电子邮箱:邮件服务器上的账号,在邮件服务器分配一块空间,用来保存邮件。
3)邮件的传输协议:
发送邮件协议:SMTP协议 默认端口 25
接收邮件协议:POP3协议 默认端口 110
接收邮件协议:IMAP协议 默认端口 143
区别:允许不用下载,直接在服务器端可以修改。
gmail 支持IMAP
4.邮件的传输过程
看图七
(二)通过telnet命令手动发送邮件(网络)
1.如果是win7的系统,需要手动开启telnet命令。如果xp不用。
2.发送邮件的协议(SMTP)
1)telnet smtp.sina.com 25 链接新浪的发送邮件的服务器
2)ehlo hi 打个招呼
3)auth login 是否需要登陆认证
4)输入用户名 (必须要经过BASE64进行编码)
5)输入密码
6)mail from:<javamail_day@sina.com> 发件人
7)rcpt to:<javamail_day@163.com> 收件人
8)Data RFC822文档(规范)
9)输入邮件内容(RFC822文档)
10). 代表邮件的结束
11)quit 断开链接
3.RFC822文档
包含邮件头 和邮件体,中间用空行分隔。
邮件头:
from:<javamail_day@sina.com> 发件人
to:<javamail_day@163.com> 收件人
subject:girl 邮件的标题
邮件体:
I LOVE YOU TOO TOO
4.接收邮件的协议 POP3协议
telnet pop3.163.com 110 链接接收邮件服务器
user 输入用户名
pass 输入密码
stat 返回邮件的数量
list 返回邮件列表结合
retr 2 访问第二封邮件
quit 端口链接
(三)邮件服务器,客户端安装及其telnet命令发送邮件(本机)
1.安装邮件服务器
配置:工具--服务器设置--修改域名(estore.com)
新建账号:账号--新建账号。
2.安装客户端软件
安装foxmail。
配置:建立新的账户:bbb@estore.com 密码111
指定邮件服务器:localhost
(四)通过JavaMail创建简单的邮件
1.javamial sun官方提供api,关于邮件的api。
2.下载jar包 javamail1_4_4和jaf-1_1_1 包,必须一起使用,依赖。
JDK6.0之后 jaf内置。如果是JDK1.6版本之前,需要引入jaf的包。
3.入门案例。
1)Session 链接服务器会话。
2)Message 邮件对象
3)Transport 发送邮件工具类
4.邮件的内容打印在控制台上保存
java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream
产生的原因:myeclipse自带的jar与javamail的jar包冲突导致。
解决办法: