文件上传
文件上传概述
上传文件对页面的要求
- 必须使用表单,而不能是超链接。
- 表单的 method 必须是 post,而不能是 get。
- 表单的 enctype 必须是 multipart/form-data。
- 在表单中添加 file 表单字段,即
<input type="file" ...>
上传文件表单与普通文件表单的区别
文件上传表单的 enctype=“multipart/from-data”,表示多部件表单数据。
普通文本表单可以不设置 enctype属性:
- 当 method="post"时,enctype的默认值为application/x-www-form-urlencoded,表示使用url编码正文。当method="get"时,enctype的默认值为null,没有正文,所以就不需要enctype了。
文件上传对Servlet的要求
request.getParameter(String name)方法获取指定的表单字段字符内容,但上传表单已经不在是字符内容,而是字节内容,所以失效。
这时我们可以使用request的getInputStream()方法获取ServeltInputStream对象。它是InputStream的子类,这个ServletInputStream对象对应整个表单的正文部分(从第一个分割线开始,到最后)。
-
不能再使用request.getParameter()来获取表单数据。
-
可以使用request.getInputStream()得到所有的表单数据,而不是一个表单项的数据。
-
这说明不使用fileupload,我们需要自己来对request.getInputStream()的内容进行解析。
fileupload
fileupload是由apache的commons组件提供的上传组件。它最主要的工作就是帮我们解析request.getInputStream()。
fileupload组件需要的jar包:
- commons-fileupload.jar。核心包
- commons-io.jar。依赖包
fileupload的核心类有:DiskFileItemFactory,ServletFileUpload,FileItem。
使用fileupload组件的步骤如下:
- 创建工厂类DiskFileItemFactory对象:
DiskFileItemFactory factory = new DiskFileItemFactory();
- 使用工厂创建解析器对象:
ServletFileUpload fileUpload = new ServletFileUpload(fctory);
- 使用解析器来解析request对象:
List<FileItem> list = fileUpload.parseRequest(request);
方法:
String getName():获取文件字段的文件名称。
String getString():获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文件文件。
String getFileldName():获取字段名称,例如:<input type="text" name="username">
返回的是username。
String getContentType():获取上传的文件的类型,例如:text/plain。
Long getSize():获取上传文件的大小。
boolean isFormFIeld():判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段。
InputStream getInputStream():获取文件上传文件对应的输入流。
void write(File file):把上传的文件保存到指定文件中。
小例子:
//创建接收文件的工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//创建文件解析对象
ServletFileUpload sfu = new ServletFileUpload(factory);
try {
//解析request获得表单中的每一个文件项(包含普通文本域)
List<FileItem> fiList = sfu.parseRequest(req);
//遍历循环
for(FileItem fi : fiList){
//获取文件字段的文件名称
String name = fi.getName();
//获取字段的内容
String str = fi.getString();
//获取字段名称
String filedName = fi.getFieldName();
//获取上传文件的类型
String content = fi.getContentType();
//获取上传文件的大小
long size = fi.getSize();
//判断当前表单字段是否为文本字段
boolean formField = fi.isFormField();
}
} catch (FileUploadException e) {
e.printStackTrace();
}
文件上传细节
把文件上传放到WEB-INF目录下
如果没有把用户上传的文件存放到WEB-INF目录下,那么用户就可以通过浏览器直接访问上传的文件,这是非常危险的。可以使用浏览器进行访问上传的文件。
WEB-INF里面的文件都是受保护的,将隐私的文件放到WEB-INF中可以提高文件的安全性。
中文乱码问题
上传文件中包含中文:
里面的name为"UTF-8"编码方式。
-
request.setCharacterEncoding(String name)
-
fileUpload.setHeaderEncoding(String name)
上传文件的文件内容包含中文:
文本文件内容和普通表单项内容使用FileItem类的getString(“utf-8”)来处理编码。
上传文件同名问题(文件重命名)
处理这一问题,我们可以使用UUID生成唯一名称。
上传的单个文件的大小限制
限制上传文件的大小很简单,ServletFileUpload类的setFileSizeMax(long)
就可以了。参数就是上传文件的上限字节数,例如:servletFileUpload.setFileSizeMax(1024*10)
表示上限为10KB。
一旦上传的文件超出了上限,那么就会抛出FileUploadBase.FileSizeLimitExceededException异常
。
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
//创建接收文件的工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//创建文件解析对象
ServletFileUpload sfu = new ServletFileUpload(factory);
//解析request
try {
//解析request获得表单中的每一个文件项(包含普通文本域)
List<FileItem> fiList = sfu.parseRequest(req);
//遍历循环
for(FileItem fi : fiList){
//获得原始文件名
String origFileName = fi.getName();
//获得文本域的名字
String fieldName = fi.getFieldName();
//获得是否是普通文本,如果是true是普通文本,如果是false是文件字段
boolean isFileldForm = fi.isFormField();
if(!isFileldForm){
if(fieldName != null && !"".equals(fieldName)){
//指定要上传的目录
String uploadPath = req.getSession().getServletContext().getRealPath("/WEB-INF/upload");
//生成uuid文件名,使文件不会重复
String uuid = UUID.randomUUID().toString();
//获得原始文件名的后缀
String suffix = origFileName.substring(origFileName.lastIndexOf("."));
//创建文件对象
File file = new File(uploadPath, uuid+suffix);
//把文件写入到硬盘
fi.write(file);
resp.getWriter().print("文件上传成功");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}