[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()]
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:\Users\lilichao\Desktop\day20\图片\蒙娜丽莎.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
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();
}
}
}