• 文件上传下载


    配套视频https://www.bilibili.com/video/BV14Z4y1p763?p=1&vd_source=3558fd85254f40ca0361146cc92d2cce

    1、文件上传

    1.1 提出问题

    客户需要将自己的文件上传给服务器怎么处理? 文件上传的时候是怎样提交给服务器的?
    答:我们可以使用 multipart/form-data 表单处理文件上传,文件的上传是以流的形式提交给服务器的

    1.2 文件上传步骤

    文件上传我们需要用到两个包。commons-fileupload-1.3.1.jar、commons-io-2.4.jar。 所以先导入包。然后进行文件上传测试
    文件上传步骤:
    1)修改表单 enctype 值为 multipart/form-data,并且 method=post

    <form action="upload" method="post" enctype="multipart/form-data"> 
    	<input type="file" name="file"> 
    	<input type="submit"> 
    form>
    
    • 1
    • 2
    • 3
    • 4

    2)创建文件上传请求解析器
    在 doPost 方法中创建 ServletFileUpload 对象,并传入 DiskFileItemFactory 工厂对象

    DiskFileItemFactory factory = new DiskFileItemFactory(); 
    ServletFileUpload fileUpload = new ServletFileUpload(factory);
    
    • 1
    • 2

    3)解析并上传文件
    解析上传文件请求

    List<FileItem> list = fileUpload.parseRequest(request);
     for(FileItem f : list){ 
    	 if(f.isFormField()){
    	 //普通表单项
    	 }else{ 
    	 //文件表单项 
    	 String name = f.getName(); 
    	 System.out.println(name); 
    	 f.write(new File("D:/"+name));
        } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    注意事项:
    ①、当文件上传表单的文件项未选择文件时,文件大小为 0,应该做判断,当文件 大小为 0 则不进行上传
    ②、使用 fileItem.getName()获取文件名。在火狐谷歌下,为文件的名字。在 ie 下为 文件的路径,因此要获取文件名需要进行处理
    ③、使用 fileItem.getString(“utf-8”),获取文件普通表单项的值

    完整的文件上传代码

    protected void doPost(HttpServletRequest request,HttpServletResponse response) throws
    ServletException, IOException {
    	// 1、创建fileItem工厂
    	DiskFileItemFactory factory = new DiskFileItemFactory();
    	// 2、创建文件上传对象
    	ServletFileUpload fileUpload = new ServletFileUpload(factory);
    	// 3、解析文件上传请求
    	try {
    		List<FileItem> list = fileUpload.parseRequest(request); 
    		// 4、遍历解析出的每个FileItem文件
    		for (FileItem f : list) { 
    			// 这是普通表单项
    			if (f.isFormField()) { 
    				// 表单项的name值
    				String fieldName = f.getFieldName(); 
    				// 表单项value,使用编码取得中文 
    				String fieldValue = f.getString("utf-8"); 
    				System.out.println(fieldName + ":" + fieldValue);
    			// 表示文件表单项 
    			} else {
    				//获取文件大小,有可能并没有上传文件 
    				long size = f.getSize(); 
    				if(size == 0){ 
    					continue; 
    				}
    				// 获取文件名字 
    				String name = f.getName(); 
    				// ie下是全路径,火狐谷歌为文件名,需要不同处理 
    				if (name.contains("\\")) { 
    				name = name.substring(name.lastIndexOf("\\") + 1); 
    				}
    				//获取文件保存的服务端路径 
    				String realPath = request.getServletContext().getRealPath("/upload"); 
    				File file = new File(realPath); 
    				if(!file.exists()){ 
    				file.mkdirs(); 
    				}
    				//生成一个唯一不重复的文件名 
    				name = UUID.randomUUID().toString().replace("-", "")+"-"+name; 
    				//将文件内容写入 
    				f.write(new File(realPath+"/"+name));
    			} 
    		} 
    	} catch (FileUploadException e) {
    		e.printStackTrace(); 
    	} catch (Exception e) { 
    		e.printStackTrace(); 
    	}
    	response.setContentType("text/html;charset=UTF-8"); 
    	response.getWriter().write("上传完成!"); 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    其他注意

    fileUpload 可以来限制文件的大小 :
    
    //1、设置当文件的大小为 50KB 
    fileUpload.setFileSizeMax(1024*50); 
    
    //2、设置多个文件的总大小为 150KB 
    fileUpload.setSizeMax(1024*150);
    
    当文件超出大小限制的时候会抛出异常,增加 catch 子句来处理
    catch (SizeLimitExceededException e) { 
    	response.setContentType("text/html;charset=UTF-8"); 
    	response.getWriter().write("文件大小超出限制"); 
    	return; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1.3 原理

    分析文件上传的请求我们会发现,文件上传的时候 request 的 body 会增加一个分界符,分界符用来分割正常的表单域和文件表单域,文件的内容在分界符的中间,以流的形式传递,文件上传的 request 请求如下:
    在这里插入图片描述以上是请求头;
    下面是请求体携带的数据:
    ![![在这里插入图片描述](https://img-blog.csdnimg.cn/b0542b4081d94554a2ab7fdfecea6688.png](https://img-blog.csdnimg.cn/43d21b3c618145159f98949b72bbbb81.png

    2、文件下载

    2.1 提出问题

    如何把服务器上的文件传输给客户端。href 可以吗?
    1、href 可以传送某些资源,当客户端不支持此资源的显示或者打开时,就会启动下载。
    2、但是如果客户端支持显示或者打开此资源。如: 图片,视频,音频,文本文件等。浏览器会直接打开他们。我们需要浏览器进行下载操作。 所以单纯的 href 已经不能操作了。
    3、如果资源文件是比较重要的文件,我们需要放到 WEB-INF 下将其保护,那么 href 是链接不到的。

    2.2 文件下载步骤

    2.2.1 下载步骤

    1)设置响应体 
    response.setContentType(this.getServletContext().getMimeType("abc.txt")); 
    //表示是一个附件
    response.setHeader("Content-Disposition", "attachment;filename="+"abc.txt"); 
    2)输出文件流 
    FileInputStream fis = new FileInputStream(this.getServletContext().getRealPath("/abc.txt")); 
    ServletOutputStream stream = response.getOutputStream(); 
    //使用commons.io工具输出流
    IOUtils.copy(fis, stream); 
    fis.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.2.2 存在的问题

    1)文件名为中文
    使用 URLEncoder.encode 方法将文件名进行编码
    String fileName = URLEncoder.encode(“中文.txt”,“utf-8”);
    response.setHeader(“Content-Disposition”, “attachment;filename=”+fileName);

    火狐不支持,显示格式不正确

    火狐需要使用 base64 编码,加上 utf-8 标注。 
    String fileName = ""; 
    String header = request.getHeader("User-Agent"); 
    if(header.contains("Firefox")){ 
    	fileName = "=?utf-8?b?"+new BASE64Encoder().encode(name.getBytes("utf-8"))+"?="; 
    }else{ 
    	fileName = URLEncoder.encode("中文.txt","utf-8"); 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    先用 GBK 解码,再使用 iso8859-1 编码

    String fileName = new String(name.getBytes("gbk"),"iso8859-1"); 
    response.setHeader("Content-Disposition", "attachment;filename="+fileName);
    
    • 1
    • 2
  • 相关阅读:
    rabbitmq 延时队列和死信队列的分析
    day 10.4
    前端性能精进之优化方法论(二)——分析
    图论2023.11.12
    IPIDEA的使用方式
    Vue之绑定样式和渲染、收集表单数据、过滤器
    java运算符
    windows查看端口占用和结束端口进程
    第二次作业
    oracle中获取连续几天最低数据
  • 原文地址:https://blog.csdn.net/weixin_46055693/article/details/125880520