commons-fileupload实现文件上传
一、准备需要上传的文件
上传文件的准备就不用多说了,先准备一个jsp页面。此页面中有一个form表单,此表单有如下三个特征。
a、表单的method必须是post
b、表单的enctype属性值必须是multipart/form-data
c、表单中提供<input type="file"/>
二、开始上传
我们需要建立一个servlet,在此servlet中准备上传所需要的类,也就是DiskFileItemFactory类和ServletFileUpload类;DiskFileitemFactory类负责管理磁盘文件,ServletFileUpload类负责上传和解析文件,如下是具体代码实现
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//处理中文乱码问题
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//检查请求是否是multipart/form-data类型
if(!ServletFileUpload.isMultipartContent(req)){ //不是multipart/form-data类型
throw new RuntimeException("表单的enctype属性不是multipart/form-data类型!!");
}
//创建上传所需要的两个对象
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload sfu = new ServletFileUpload(factory); //解析器依赖于工厂
//创建容器来接受解析的内容
List<FileItem> items = new ArrayList<FileItem>();
//将上传的文件信息放入容器中
try {
items = sfu.parseRequest(req);
} catch (FileUploadException e) {
e.printStackTrace();
}
//遍历容器,处理解析的内容;封装两个方法,一个处理普通表单域,一个处理文件的表单域
for(FileItem item : items){
if(item.isFormField()){
handleFormField(item);
}else{
handleUploadField(item);
}
}
}
三、解析上传文件并保存到服务器
下面是两个需要解析的方法,一个是专门处理普通表单域的,一个是专门处理文件表单域的
/**
* 处理普通表单域
* @param item
*/
private void handleFormField(FileItem item) {
String fieldName = item.getFieldName(); //得到表单域的name的值
String value = "";
try {
value = item.getString("utf-8"); //得到普通表单域中所输入的值
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//打印到控制台
System.out.println("fieldName:"+fieldName+"--value:"+value);
}
/**
* 处理文件的表单域
* @param item
*/
private void handleUploadField(FileItem item) {
String fileName = item.getName(); //得到上传文件的文件名
if(fileName!=null && !"".equals(fileName)){
//控制只能上传图片
if(!item.getContentType().startsWith("image")){
return;
}
//向控制台打印文件信息
System.out.println("fileName:"+fileName);
System.out.println("fileSize:"+item.getSize());
}
//上传文件存储路径
String path = this.getServletContext().getRealPath("/files");
//创建子目录
File childDirectory = getChildDirectory(path);
//写入服务器或者磁盘
try {
item.write(new File(childDirectory.toString(),UUID.randomUUID()+"_"+fileName));
} catch (Exception e) {
e.printStackTrace();
}
}
为了防止上传的文件都是在同一个目录下,对于以后的遍历查找十分的不便,所以为上传的文件创建子目录
/**
* 按照时间创建子目录,防止一个目录中文件过多,不利于以后遍历查找
* @param path
* @return
*/
private File getChildDirectory(String path) {
Date currTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String time = sdf.format(currTime);
File file = new File(path,time);
if(!file.exists()){
file.mkdirs();
}
return file;
}
四、文件上传时的一个限制要求
一、限制文件的类型,如,只能上传图片
//控制只能上传图片
if(!item.getContentType().startsWith("image")){
return;
}
二、限制上传文件的大小
//创建上传所需要的两个对象
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload sfu = new ServletFileUpload(factory); //解析器依赖于工厂
//限制单个文件的大小
sfu.setFileSizeMax(1024*10);
//限制上传的总文件大小
sfu.setSizeMax(1024*200);
//创建容器来接受解析的内容
List<FileItem> items = new ArrayList<FileItem>();
//将上传的文件信息放入容器中
try {
items = sfu.parseRequest(req);
}catch(FileUploadBase.FileSizeLimitExceededException e){
resp.getWriter().write("文件大小不能超过10kb");
}catch (FileUploadException e) {
e.printStackTrace();
}
五、其他的一些配置
DiskFileItemFactory有两个方法:setSizeThreshold和setRepository
1、 setRepository方法用于设置当上传文件尺寸大于setSizeThreshold方法设置的临界值时,将文件以临时文件形式保存在磁盘上的存放目录。有一个对应的获得临时文件夹的 File getRespository() 方法。
注意:当从没有调用此方法设置临时文件存储目录时,默认采用系统默认的临时文件路径,可以通过系统属性 java.io.tmpdir 获取。如下代码:
System.getProperty(“java.io.tmpdir”);
Tomcat系统默认临时目录为“<tomcat安装目录>/temp/”
。
2、setSizeThreshold方法用于设置是否将上传文件已临时文件的形式保存在磁盘的临界值(以字节为单位的int值),如果从没有调用该方法设置此临界值,将会采用系统默认值10KB。对应的getSizeThreshold() 方法用来获取此临界值。
附:Apache文件上传组件在解析上传数据中的每个字段内容时,需要临时保存解析出的数据,以便在后面进行数据的进一步处理(保存在磁盘特定位置或插入数据库)。因为Java虚拟机默认可以使用的内存空间是有限的,超出限制时将会抛出“java.lang.OutOfMemoryError”错误。如果上传的文件很大,例如800M的文件,在内存中将无法临时保存该文件内容,Apache文件上传组件转而采用临时文件来保存这些数据;但如果上传的文件很小,例如600个字节的文件,显然将其直接保存在内存中性能会更加好些。