一。文件上传:
是指允许客户将本地文件,上传到服务器端
常见的应用:上传照片、上传新闻图片、上传附件
文件上传编程基本步骤:
1、在用户页面中添加上传输入项 (客户端页面操作)也就是编写一个jsp页面里面编写一个表单提交
<from action="跳转路径" method="post" enctype="multipart/from-data">
<input type="file" name="fileUpload"/>
<input type ="submit" value="上传"/>
</from>
注意事项:
1) 必须为文件上传input 提供name属性,否则文件上传内容不会被表单提交
2) 表单的提交是post (get提交数据在url地址上显示,有长度限制)
3) 设置enctype=multipart 使得文件上传编码 ----- MIME编码格式
常用文件上传API :
1) JSP独立开发年代 jsp-smartupload ---- JSP Model1
jspSmartUpload是一个可免费使用的全功能的文件上传下载组件,适于嵌入执行上传下载操作的JSP文件中。
2) JSP+Servlet 开发web应用 Apache commons-fileupload ---- JSP Model2
FileUpload 是 Apache commons下面的一个子项目,用来实现Java环境下面的文件上传功能,与常见的SmartUpload齐名。
3) Servlet3.0规范中提供对文件上传的支持
Apache commons-fileupload 的使用:
1) 去 http://commons.apache.org/fileupload/ 下载fileupload jar包
同时下载 commons-fileupload 和 commons-io 两个包 -------- 因为fileupload依赖io包
2) 将jar包导入 web 工程WEB-INF/lib下
3) 编写步骤:
步骤一:获得DiskFileItemFactory 文件项工厂
步骤二:通过工厂获得文件上传请求核心解析类 ServletFileUpload构造函数中传入工厂示例对象
步骤三:使用ServletFileUpload对request进行解析 ---- 获得很多个FileItem
步骤四:对每个FileItem进行操作 判断FileItem是不是个文件上传项FileItem.isFormField()
返回boolean true代表不是一个文件上传项 false代表是一个文件上传项
--------文件上传项是指获得的input标签type是不是一个上传文件的标签
代表普通字段FileItem
getFieldName(); ---- 获得表单项name属性
getString(); ----- 获得表单项value
代表文件上传FileItem
getInputStream() --- 获得文件内容输入流
getName() ------ 获得上传文件名称(注意:IE6版本获得的是文件的全路径需要进行切割去到文件名)
int index = 取到的文件全路径.lastIndexOf("\\");找到最后一个\出现的位置
if (index != -1)
{
filename = 取到的文件全路径.substring(index + 1);// 获得真实文件名
}
二、commons-fileupload 核心API分析:
1、DiskFileItemFactory 磁盘文件项工厂类
public DiskFileItemFactory(int sizeThreshold, java.io.File repository) 构造工厂时,指定内存缓冲区大小和临时文件存放位置
public void setSizeThreshold(int sizeThreshold) 设置内存缓冲区大小,默认10K
public void setRepository(java.io.File repository)设置临时文件存放位置,默认System.getProperty("java.io.tmpdir").
什么是内存缓冲区: 上传文件时,上传文件的内容优先保存在内存缓冲区中,当上传文件大小超过缓冲区大小时,就会在服务器端产生临时文件
什么是临时文件: 保存超过了内存缓冲区大小上传文件而产生临时文件
产生的临时文件可以通过 FileItem的delete方法删除
2、ServletFileUpload 文件上传核心类
static boolean isMultipartContent(javax.servlet.http.HttpServletRequest request) 判断request的编码方式是否为multipart/form-data
java.util.List parseRequest(javax.servlet.http.HttpServletRequest request) 解析request,将请求体每个部分封装FileItem对象,返回List<FileItem>
void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小
void setSizeMax(long sizeMax) 设置总文件上传大小
void setHeaderEncoding(java.lang.String encoding) 设置编码集 解决上传文件名乱码 *****
void setProgressListener(ProgressListener pListener)
设置文件上传监听器(用来监控文件上传进度)上传时间、剩余大小、速度、剩余时间
3、FileItem 表示文件上传表单中 每个数据部分
boolean isFormField() 判断该数据项是否为文件上传项,true 不是文件上传 false 是文件上传
if(fileItem.isFormField()){
// 不是上传项
java.lang.String getFieldName() 获得普通表单项name属性
java.lang.String getString() / java.lang.String getString(java.lang.String encoding) 获得普通表单项value属性 传入编码集用来解决输入value乱码
}else{
// 是上传项
java.lang.String getName() 获得上传文件名 (注意IE6存在路径)
java.io.InputStream getInputStream() 获得上传文件内容输入流
// 上传文件
void delete() 删除临时文件(删除时,必须要管理输入输出流)
}
注意事项:因为文件上传表单采用编码方式multipart/form-data 与传统url编码不同,所有getParameter 方法不能使用 setCharacterEncoding 无法解决输入项乱码问题
对于出现的乱码问题的几个针对解决:
1.使用get方式提交中文时
<a href="/day21/downloadList?path=D:\TTPmusic\何晟铭\何晟铭 - 爱的供养.mp3">何晟铭 - 爱的供养.mp3</a><br/>
问题:IE6 提交后,服务器经过get乱码处理获得乱码
原因:IE6对中文直接进行 get提交时,进行URL编码 ---- 编码发生问题
解决:手动对get提交中文进行编码 ----- URLEncoder
2.如果下载文件是中文名,设置 response.setHeader("Content-Disposition", "attachment;filename=" + filename); 出现附件名乱码
不同浏览器处理下载附件名乱码处理方式不同 ,例如 IE使用URL编码 、fireFox使用BASE64编码
通过USER-AGENT 请求头信息字段,判断来访者浏览器类型
注意:火狐浏览器在使用MimeUtility 进行Base64编码时存在问题 ,如果字符串中没有中文,无法进行编码
解决:采用手动BASE64 编码
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
三实例:
public class UploadServlet extends HttpServlet{
DiskFileItemFactory factory=new DiskFileItemFactory();
ServletFileUpload upload=new ServletFileUpload(factory);
//判断提交表单的类型是否为multipart/form-data
if(!upload.isMultipartContent(request))
{
return;
}
try {
List list=upload.parseRequest(request);
Iterator it=list.iterator();
while(it.hasNext()){
FileItem item=(FileItem)it.next();//每一个item就代表一个表单输出项
String name=item.getFieldName();input的名称
String value= item.getString();input的值
}else{
得到上传文件的名称,并截取
String filename=item.getName();
得到上传文件要写入的目录
String path=this.getServletContext().getRealPath("/upload");
根据目录和文件创建输出流
FileOutputStream out=new FileOutputStream(path+filename);
InputStream in = item.getInputStream();
byte buffer[] = new byte[1024];
int len = 0;
while((len=in.read(buffer))>0){
out.write(buffer,0,len);
}
in.close();
out.close();
}
}
} catch (FileUploadException e)
{
e.printStackTrace();
}
}
}
四文件上传注意的细节问题
1.解决上传中文乱码问题
可以通过upload.setHeaderEncoding("utf-8");
2.上传文件怎么保证服务器的安全? (上传文件时不安全应用举例Runtime.getRuntime.exec("")可以执行DOS命令)
解决方案:上传目录要禁止外界直接访问,一般的做法是把上传目录放到服务器的WEB-INF目录下.这个目录服务器是保护的,外界无法访问.
2.上传文件被覆盖的问题
服务器要为每一个上传文件生成一个唯一的文件名.可以使用UUID算法.
3.上传的文件需要打散
4.临时文件的删除
FileItemDelete.删除临时文件一定要在流关闭之后,否则会出现文件占用,而导致删除失败.
5.多文件上传问题:
主要是javascript编码,在页面动态添加文件上传项.
6.监听上传进度:
自己写一个监听器progressListener