1、如何保证服务器的安全
把保存上传文件的目录放到WEB-INF目录中。
2、中文乱码问题
2.1普通字段的中文请求参数
String value = FileItem.getString("UTF-8");
2.2上传的文件名是中文
解决办法:request.setCharacterEncoding("UTF-8");
3、重名文件被覆盖的问题
System.currentMillions()+"_"+a.txt(乐观)
UUID+"_"+a.txt:保证文件名唯一
4、分目录存储上传的文件
方式一:当前日期建立一个文件夹,当前上传的文件都放到此文件夹中。
例如:生成一个2014-10-6的文件夹
Date date = new Date();DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);String s = df.format(date);String path = storePath+""+s;File file = new File(path);if(!file.exists()){ file.mkdirs();//创建多级目录,mkdir只创建一级目录}return path;//文件夹的地址
方式二:利用文件名的hash码打散目录来存储。
int hashCode = fileName.hashCode();
1001 1010 1101 0010 1101 1100 1101 1010
hashCode&0xf 0000 0000 0000 0000 0000 0000 0000 1111 &
---------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1010 取hashCode的后4位
0000~1111:整数0~15共16个
1001 1010 1101 0010 1101 1100 1101 1010
(hashCode&0xf0) 0000 0000 0000 0000 0000 0000 1111 0000 &
--------------------------------------------
0000 0000 0000 0000 0000 0000 1101 0000 >>4
--------------------------------------------
0000 0000 0000 0000 0000 0000 0000 1101
0000~1111:整数0~15共16个
5、限制用户上传的文件类型
通过判断文件的扩展名来限制是不可取的。
通过判断其Mime类型才靠谱。FileItem.getContentType();
6、如何限制用户上传文件的大小
6.1单个文件大小限制。超出了大小友好提示
抓异常进行提示:
org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException
6.2总文件大小限制。超出了大小友好提示
抓异常进行提示:
org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededExcept
7、临时文件的问题
commons-fileupload组件不会删除超出缓存的临时文件。
FileItem.delete()方法删除临时文件。但一定要在关闭流之后。
8、多个文件上传时,没有上传内容的问题
if(fileName==null||"".equals(fileName.trim())){continue;}
9、上传进度检测
给ServletFileUpload注册一个进度监听器即可,把上传进度传递给页面去显示
//pBytesRead:当前以读取到的字节数
//pContentLength:文件的长度
//pItems:第几项
public void update(long pBytesRead, long pContentLength,int pItems) {System.out.println("已读取:"+pBytesRead+",文件大小:"+pContentLength+",第几项:"+pItems);}
完整实例 :
表单:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <base href="<%=basePath%>"> <title>My JSP '1.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!--<link rel="stylesheet" type="text/css" href="styles.css">--> </head> <body> <form action="${pageContext.request.contextPath}/servlet/UploadServlet3" method="post" enctype="multipart/form-data"> 用户名<input type="text" name="username"/> <br/> <input type="file" name="f1"/><br/> <input type="file" name="f2"/><br/> <input type="submit" value="保存"/> </form> </body></html>
UploadServlet3
package com.mair.upload;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.PrintWriter;import java.text.DateFormat;import java.util.Date;import java.util.List;import java.util.UUID;import java.util.logging.SimpleFormatter;import javax.servlet.ServletException;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.FileUploadException;import org.apache.commons.fileupload.ProgressListener;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;public class UploadServlet3 extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {//设置编码request.setCharacterEncoding("UTF-8");response.setContentType("text/html;charset=UTF-8");PrintWriter pw = response.getWriter();try {//设置系统环境DiskFileItemFactory factory = new DiskFileItemFactory();//文件存储的路径String storePath = getServletContext().getRealPath("/WEB-INF/files");//判断传输方式 form enctype=multipart/form-databoolean isMultipart = ServletFileUpload.isMultipartContent(request);if(!isMultipart){ pw.write("传输方式有错误!"); return;}ServletFileUpload upload = new ServletFileUpload(factory);upload.setFileSizeMax(4*1024*1024);//设置单个文件大小不能超过4Mupload.setSizeMax(4*1024*1024);//设置总文件上传大小不能超过6M//监听上传进度upload.setProgressListener(new ProgressListener() {//pBytesRead:当前以读取到的字节数 //pContentLength:文件的长度 //pItems:第几项public void update(long pBytesRead, long pContentLength,int pItems) {System.out.println("已读去文件字节 :"+pBytesRead+" 文件总长度:"+pContentLength+" 第"+pItems+"项");}});//解析List<FileItem> items = upload.parseRequest(request);for(FileItem item: items){if(item.isFormField())//普通字段,表单提交过来的{String name = item.getFieldName();String value = item.getString("UTF-8");System.out.println(name+"=="+value);}else{//String mimeType = item.getContentType(); 获取上传文件类型//if(mimeType.startsWith("image")){InputStream in =item.getInputStream();String fileName = item.getName(); if(fileName==null || "".equals(fileName.trim())){continue;}fileName = fileName.substring(fileName.lastIndexOf("")+1);fileName = UUID.randomUUID()+"_"+fileName;//按日期来建文件夹String newStorePath = makeStorePath(storePath);String storeFile = newStorePath+""+fileName;OutputStream out = new FileOutputStream(storeFile);byte[] b = new byte[1024];int len = -1;while((len = in.read(b))!=-1){ out.write(b,0,len);}in.close();out.close();item.delete();//删除临时文件} }//}}catch(org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException e){ //单个文件超出异常pw.write("单个文件不能超过4M");}catch(org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException e){//总文件超出异常pw.write("总文件不能超过6M");}catch (FileUploadException e) {e.printStackTrace();}} //用日期生成的目录,如果想用hashcode,后面private String makeStorePath(String storePath) {Date date = new Date();DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);String s = df.format(date);String path = storePath+""+s;File file = new File(path);if(!file.exists()){file.mkdirs();//创建多级目录,mkdir只创建一级目录}return path; }public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { doGet(request, response);}}
用hashcode生成目录:只需要改写一下makeStorePath(String storePath, String fileName)函数
private String makeStorePath(String storePath, String fileName) {int hashCode = fileName.hashCode();int dir1 = hashCode & 0xf;// 0000~1111:整数0~15共16个int dir2 = (hashCode & 0xf0) >> 4;// 0000~1111:整数0~15共16个String path = storePath + "" + dir1 + "" + dir2; // WEB-INF/files/1/12File file = new File(path);if (!file.exists())file.mkdirs();return path;}