JSP中文件的上传于下载示例

一、文件上传的原理
    1、文件上传的前提:
        a、form表单的method必须是post
        b、form表单的enctype必须是multipart/form-data(决定了POST请求方式,请求正文的数据类型)
            注意:当表单的enctype是multipart/form-data,传统的获取请求参数的方法失效。
            
            请求正文:(MIME协议进行描述的,正文是多部分组成的)
            -----------------------------7dd32c39803b2
            Content-Disposition: form-data; name="username"

            wzhting
            -----------------------------7dd32c39803b2
            Content-Disposition: form-data; name="f1"; filename="C:\Documents and Settings\wzhting\妗岄潰\a.txt"
            Content-Type: text/plain

            aaaaaaaaaaaaaaaaaa
            -----------------------------7dd32c39803b2
            Content-Disposition: form-data; name="f2"; filename="C:\Documents and Settings\wzhting\妗岄潰\b.txt"
            Content-Type: text/plain

            bbbbbbbbbbbbbbbbbbb
            -----------------------------7dd32c39803b2--

            
        c、form中提供input的type是file类型的文件上传域
        
二、利用第三方组件实现文件上传
    1、commons-fileupload组件:
        jar:commons-fileupload.jar  commons-io.jar
    2、核心类或接口
        DiskFileItemFactory:设置环境
            public void setSizeThreshold(int?sizeThreshold) :设置缓冲区大小。默认是10Kb。
                    当上传的文件超出了缓冲区大小,fileupload组件将使用临时文件缓存上传文件
            public void setRepository(java.io.File repository):设置临时文件的存放目录。默认是系统的临时文件存放目录。
                    
        ServletFileUpload:核心上传类(主要作用:解析请求的正文内容)
            boolean isMultipartContent(HttpServletRequest?request):判断用户的表单的enctype是否是multipart/form-data类型的。
            List parseRequest(HttpServletRequest request):解析请求正文中的内容
            setFileSizeMax(4*1024*1024);//设置单个上传文件的大小
            upload.setSizeMax(6*1024*1024);//设置总文件大小
        FileItem:代表表单中的一个输入域。
            boolean isFormField():是否是普通字段
            String getFieldName:获取普通字段的字段名
            String getString():获取普通字段的值
            
            InputStream getInputStream():获取上传字段的输入流
            String getName():获取上传的文件名
            
三、文件上传中要注意的9个问题
    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、分目录存储上传的文件
        方式一:当前日期建立一个文件夹,当前上传的文件都放到此文件夹中。
        方式二:利用文件名的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.SizeLimitExceededException
    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);

        }

四:文件上传示例:

JSP代码:

<form action="${pageContext.request.contextPath}/servlet/UploadServlet" method="post" enctype="multipart/form-data">
    	用户名:<input type="text" name="username"/><br/>
    	文件1:<input type="file" name="f1"/><br/>
    	文件2:<input type="file" name="f2"/><br/>
    	<input type="submit" value="保存"/>
    </form>
servlet后台代码:

public class UploadServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter pout = response.getWriter();
		try {
			// 得到存放上传文件的真实路径
			String storePath = getServletContext()
					.getRealPath("/WEB-INF/files");

			// 设置环境
			DiskFileItemFactory factory = new DiskFileItemFactory();
			factory.setRepository(new File(getServletContext().getRealPath("/temp")));//设置临时存放目录
			// 判断一下form是否是enctype=multipart/form-data类型的
			boolean isMultipart = ServletFileUpload.isMultipartContent(request);
			if (!isMultipart) {
				System.out.println("大傻鸟");
				return;
			}
			// ServletFileUpload核心类
			ServletFileUpload upload = new ServletFileUpload(factory);
//			upload.setProgressListener(new ProgressListener() {
//				//pBytesRead:当前以读取到的字节数
//				//pContentLength:文件的长度
//				//pItems:第几项
//				public void update(long pBytesRead, long pContentLength,
//						int pItems) {
//					System.out.println("已读取:"+pBytesRead+",文件大小:"+pContentLength+",第几项:"+pItems);
//				}
//				
//			});
			upload.setFileSizeMax(4 * 1024 * 1024);// 设置单个上传文件的大小
			upload.setSizeMax(6 * 1024 * 1024);// 设置总文件大小
			// 解析
			List<FileItem> items = upload.parseRequest(request);
			for (FileItem item : items) {
				if (item.isFormField()) {
					// 普通字段
					String fieldName = item.getFieldName();
					String fieldValue = item.getString("UTF-8");
					System.out.println(fieldName + "=" + fieldValue);
				} else {
					// 得到MIME类型
					String mimeType = item.getContentType();
					// 只允许上传图片
					 if(mimeType.startsWith("image")){
						// 上传字段
						InputStream in = item.getInputStream();
						// 上传的文件名
						String fileName = item.getName();// C:\Documents and
						if(fileName==null||"".equals(fileName.trim())){
							continue;
						}
						// Settings\wzhting\妗岄潰\a.txt
						// a.txt
						fileName = fileName
								.substring(fileName.lastIndexOf("\\") + 1);// a.txt
						fileName = UUID.randomUUID() + "_" + fileName;
						System.out.println(request.getRemoteAddr()+"=============="+fileName);
						// 构建输出流
						// 打散存储目录
						String newStorePath = makeStorePath(storePath, fileName);// 根据
						// /WEB-INF/files和文件名,创建一个新的存储路径
						// /WEB-INF/files/1/12
						String storeFile = newStorePath + "\\" + fileName;// WEB-INF/files/1/2/sldfdslf.txt
	
						OutputStream out = new FileOutputStream(storeFile);
	
						byte b[] = new byte[1024];
						int len = -1;
						while ((len = in.read(b)) != -1) {
							out.write(b, 0, len);
						}
						out.close();
						in.close();
						item.delete();//删除临时文件
					}
				 }
			}
		} catch (org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException e) {
			// 单个文件超出大小时的异常
			pout.write("单个文件大小不能超出4M");
		} catch (org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException e) {
			// 总文件超出大小时的异常
			pout.write("总文件大小不能超出6M");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	// 根据 /WEB-INF/files和文件名,创建一个新的存储路径 /WEB-INF/files/1/12
	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/12
		File file = new File(path);
		if (!file.exists())
			file.mkdirs();

		return path;
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

五:文件下载

1.显示上述存储所有的照片信息:

//显示所有上传的文件,封装到域对象中,交给jsp去显示
public class ShowAllFilesServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Map<String, String> map = new HashMap<String, String>();//key:UUID文件名;value:老文件名
		//得到存储文件的根目录
		String storePath = getServletContext().getRealPath("/WEB-INF/files");
		//递归遍历其中文件
		File file = new File(storePath);
		treeWalk(file,map);
		//交给JSP去显示:如何封装数据.用Map封装。key:UUID文件名;value:老文件名
		request.setAttribute("map", map);
		request.getRequestDispatcher("/listFiles.jsp").forward(request, response);
	}
	//遍历/WEB-INF/files所有文件,把文件名放到map中
	private void treeWalk(File file, Map<String, String> map) {
		if(file.isFile()){
			//是文件
			String uuidName = file.getName();//  UUID_a_a.txt//真实文件名
			String oldName = uuidName.substring(uuidName.indexOf("_")+1);
			map.put(uuidName, oldName);
		}else{
			//是一个目录
			File[] fs = file.listFiles();
			for(File f:fs){
				treeWalk(f,map);
			}
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}
2.显示所有文件listFiles.jsp页面中的内容:
<body>
    <h1>本站有以下好图片</h1>
    <c:forEach items="${map}" var="me">
    	<c:url value="/servlet/DownloadServlet" var="url">
    		<c:param name="filename" value="${me.key}"></c:param>
    	</c:url>
    	${me.value}  <a href="${url}">下载</a><br/>
    </c:forEach>
  </body>
3.文件下载DownloadServlet:

public class DownloadServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=UTF-8");
		OutputStream out = response.getOutputStream();
		
		String filename = request.getParameter("filename");//get请求方式
		filename = new String(filename.getBytes("ISO-8859-1"),"UTF-8");//中文编码
		
		//截取老文件名
		String oldFileName = filename.split("_")[1];
		//得到存储路径
		String storePath = getServletContext().getRealPath("/WEB-INF/files");
		//得到文件的全部路径
		String filePath = makeStorePath(storePath, filename)+"\\"+filename;
		
		//判断文件是否存在
		File file = new File(filePath);
		if(!file.exists()){
			out.write("对比起!你要下载的文件可能已经不存在了".getBytes("UTF-8"));
			return;
		}
		
		InputStream in = new FileInputStream(file);
		//通知客户端以下载的方式打开
		response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(oldFileName, "UTF-8"));
		
		byte[] b = new byte[1024];
		int len = -1;
		while((len=in.read(b))!=-1){
			out.write(b, 0, len);
		}
		in.close();
		out.write("下载成功".getBytes("UTF-8"));
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}
	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/12
		File file = new File(path);
		if (!file.exists())
			file.mkdirs();

		return path;
	}
}


JSP中文件的上传于下载示例,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。