zoukankan      html  css  js  c++  java
  • 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 Settingswzhting妗岄潰a.txt"
                Content-Type: text/plain

                aaaaaaaaaaaaaaaaaa
                -----------------------------7dd32c39803b2
                Content-Disposition: form-data; name="f2"; filename="C:Documents and Settingswzhting妗岄潰.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、怎样保证server的安全
            把保存上传文件的文件夹放到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;
    						}
    						// Settingswzhting妗岄潰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);
    		//通知client下面载的方式打开
    		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;
    	}
    }
    


  • 相关阅读:
    数据分析1-2
    数据分析1-1
    数据分析案例:
    数据分析1:安装tushare安装包
    小爬爬7:回顾&&crawlSpider
    小爬爬6: 网易新闻scrapy+selenium的爬取
    小爬爬6:中间件
    小爬爬6:2请求传参
    前端 -----jQuery的选择器
    前端 ----jQuery的介绍
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/7066715.html
Copyright © 2011-2022 走看看