[1] 简介
> 将一个客户端的本地的文件发送到服务器中保存。
> 上传文件是通过流的形式将文件发送给服务器。
[2] 表单的设置(文件上传一般利用表单)
> 向服务器上传一个文件时,表单要使用post请求。
> 表单的默认属性enctype="application/x-www-form-urlencoded"
- 这个属性的意思是请求体中的内容将会使用URL编码
> 上传文件的表单enctype需要设置为 multipart/form-data
- multipart/form-data表示的是表单是一个多部件的表单
- 如果类型设置为它,则我们的每一个表单项都会作为一个单独的部件发送给服务器。
- 多个部件之间使用类似 -----------------------------7df2d08c0892 分割符来分开
> 当表单设置为multipart/form-data时,我们request.getParameter()将失效,我们不能再通过该方法获取请求参数。
1 <form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data"> 2 用户:<input type="text" name="name"> 3 <input type="file" name="photo"><br> 4 <input type="submit" value="提交"> 5 </form>
[3] FileUpload
> 我们一般情况下使用commons-fileupload-1.3.1.jar这个工具来解析多部件请求。
> fileupload 依赖 commons-io 所以我们要是Filtupload需要同时导入io包。
> 核心类:
DiskFileItemFactory
- 工厂类,用于构建一个解析器实例。
ServletFileUpload
- 解析器类,通过该类实例来解析request中的请求信息。
FileItem
- 工具会将我们请求中每一个部件,都封装为一个FileItem对象,处理文件上传时,只需要调用该对象的方法
- 方法:
boolean isFormField() --> 当前表单项是否是一个普通表单项,true是普通表单项, false是文件表单项
String getContentType() --> 返回的是文件的类型,是MIME值
String getFieldName() --> 获取表单项的name属性值
String getName() --> 获取上传的文件的名字
long getSize() --> 获取文件的大小
String getString(String encoding) --> 获取表单项的value属性值,需要接受一个编码作为参数。
void write(File file) --> 将表单项中的内容写入到磁盘中
> 使用步骤:
1.获取工厂类实例[DiskFileItemFactory]
2.获取解析器类实例[ServletFileUpload]
3.解析request获取FileItem[parseRequest()]
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 @WebServlet("/FileUploadServlet") 2 public class FileUploadServlet extends HttpServlet { 3 private static final long serialVersionUID = 1L; 4 5 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 6 7 //创建工厂类 8 DiskFileItemFactory factory=new DiskFileItemFactory(); 9 //创建FileUploadServlet对象,通过这个对象完成上传功能 10 ServletFileUpload fileUpload=new ServletFileUpload(factory); 11 //用这个fileUpload对象解析request请求 12 try { 13 List<FileItem> fileList = fileUpload.parseRequest(request); 14 for(FileItem item:fileList){ 15 if (item.isFormField()) { 16 //代表普通表单项 17 String name = item.getFieldName(); 18 String value = item.getString("UTF8"); 19 System.out.println(name+":"+value); 20 }else { 21 //代表上传的文件 22 long size = item.getSize(); 23 String contentType = item.getContentType(); 24 String name = item.getName(); 25 String fieldName = item.getFieldName(); 26 System.out.println(size+":"+contentType+":"+name+":"+fieldName); 27 String uuid = UUID.randomUUID().toString();//名字重复,后一章会覆盖前一章 28 uuid.replace("-", ""); 29 item.write(new File("C:\Users\kanglu\Desktop\"+uuid+"_"+name)); 30 }//MIME 31 } 32 }catch (Exception e) { 33 // TODO Auto-generated catch block 34 e.printStackTrace(); 35 } 36 } 37 }
[4] 细节
第一个问题
> 部分浏览器会将文件的完整路径作为文件名发送。
C:UserslilichaoDesktopday20图片蒙娜丽莎.jpg
> 像这类文件名我们需要截取一下字符串,只获取名字这部分,而不需要获取路径部分的信息。
通过如下代码对文件名进行截取字符串的操作:
if(name.contains("\")){
//如果包含则截取字符串
name = name.substring(name.lastIndexOf("\")+1);
}
第二个问题
> 上传的文件有可能出现重名,后上传的文件会将先上传的文件覆盖。
> 解决:给文件名加一个唯一的前缀。
唯一标识_fennu.jpg
UUID_fennu.jpg
1 //添加唯一前缀 2 String uuid = UUID.randomUUID().toString();//名字重复,后一章会覆盖前一章 3 uuid.replace("-", "");
第三个问题
> 有些情况需要限制上传文件的大小。
- 设置单个文件大小为50KB:
fileUpload.setFileSizeMax(1024*50);
- 设置完单个文件大小限制以后,一旦上传的文件超过限制,则会抛出如下异常:
FileSizeLimitExceededException
所有可以对该异常进行捕获,当出现该异常时则设置一个错误消息。
- 设置多个文件的总大小为150KB
fileUpload.setSizeMax(1024*150);
- 当多个文件的大小超出范围时,会抛出如下异常
SizeLimitExceededException
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //单个文件 2 fileUpload.setFileSizeMax(1024*50); 3 try{ 4 ...... 5 }catch (FileSizeLimitExceededException e) { 6 System.out.println("文件大小超出限制"); 7 } 8 9 //多个文件 10 设置插入多个文件 11 <input type="file" name="photo"><br> 12 <input type="file" name="photo"><br> 13 限制大小处理 14 fileUpload.setSizeMax(1024*150); 15 try{ 16 ...... 17 }catch (SizeLimitExceededException e) { 18 System.out.println("整体文件大小超出限制"); 19 }
第四个问题
> 当用户上传一个空的文件,依然会将文件保存到硬盘上。
> 在保存文件应该先对文件的大小进行判断,如果size为0,则不处理。
1 long size = item.getSize(); 2 if(size==0){ 3 System.out.println("文件大小为空"); 4 continue; 5 }//若是多个文件,空文件可能位于首位,所以用continue; 6 //若是单个文件,可用break; 7 //此处针对上面所写代码,其位于for循环中
[5]上传服务器
上面代码中文件直接传到自己的电脑上,用户不能通过浏览器进行网络访问。
若要能通过浏览器访问,可上传到tomcat服务器位于eclipse的镜像中。(本人使用的是eclipse进行编码)
1 将文件上传到服务器上: 2 1、将links和tc-servlet包复制到eclipse文件目录下; 3 4 2、 //将文件存在tomcat服务器镜像上,获取镜像目录 5 ServletContext servletContext=request.getServletContext(); 6 String realPath = servletContext.getRealPath("/upload");//要存储的具体位置 7 File file = new File(realPath); 8 if(!file.exists()){ 9 file.mkdirs();//文件不存在,创建文件(目录) 10 //file.isDirectory()表明上传的文件是个目录 11 }
通过realPath获取文件所在位置,在浏览器上输入(如图片地址),即可获取
1 localhost:9999/web-upload/upload/168ea717-401b-485c-9d1f-c62cfa50d361_fennu.jpg 2 //在浏览器地址栏输入如上地址内容即可查看刚刚上传的文件(以图片为例), 3 //localhost:9999为tomcat端口号,web-upload为所写项目名, 4 //upload为文件所在位置, 5 //168ea717-401b-485c-9d1f-c62cfa50d361_fennu.jpg为图片名 6 6//_前内容为随机生成的唯一标识符
完整代码,包含上传服务器:
package com.neuedu.servlet; import java.io.File; import java.io.IOException; import java.util.List; import java.util.UUID; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; 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.FileUploadBase.FileSizeLimitExceededException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; @WebServlet("/FileUploadServlet") public class FileUploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //创建工厂类 DiskFileItemFactory factory=new DiskFileItemFactory(); //创建FileUploadServlet对象,通过这个对象完成上传功能 ServletFileUpload fileUpload=new ServletFileUpload(factory); fileUpload.setFileSizeMax(1024*50); //将文件上传到服务器,是能在互联网上访问 ServletContext servletContext=request.getServletContext(); String realPath = servletContext.getRealPath("/upload"); File file = new File(realPath); if(!file.exists()){ file.mkdirs();//文件不存在,创建文件(目录) //file.isDirectory()表明上传的文件是个目录 } //用这个fileUpload对象解析request请求 try { List<FileItem> fileList = fileUpload.parseRequest(request); for(FileItem item:fileList){ if (item.isFormField()) { //代表普通表单项 String name = item.getFieldName(); String value = item.getString("UTF8"); System.out.println(name+":"+value); }else { //代表上传的文件 fileUpload.setFileSizeMax(1024*50); long size = item.getSize(); String contentType = item.getContentType(); String name = item.getName(); String fieldName = item.getFieldName(); if(size==0){ System.out.println("文件大小为空"); continue; } System.out.println(size+":"+contentType+":"+name+":"+fieldName); String uuid = UUID.randomUUID().toString();//名字重复,后一章会覆盖前一章 uuid.replace("-", ""); try { item.write(new File(realPath+"\"+uuid+"_"+name)); } catch (Exception e) { // TODO: handle exception } }//MIME } }catch (FileSizeLimitExceededException e) { System.out.println("文件大小超出限制"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }