java文件的上传和下载(细节问题)

一: 文件的上传: 

要求: 
1:jsp的页面: 
    a: form 表单: 
    b: post 提交: 
    c: form指定一个属性: enctype="multipart/form-data"
    d: file组件: 
2: Servlet: 
  request.getParamter("name");//不生效了: 
  
  ServletInputStream in = request.getInputStream();
  获得数据, 被封装了in 当中, 理论上可以解析数据。  
  
  
  
3: request 请求体当中: 

post请求体: 
请求首行: 
请求头信息: 

请求体: 
-------------------
普通组件: 只有一个头: Content-Dispositon:  name="xxx"

请求体: mrzhang : 填写的内容。 
-------------------
文件上传字段: 两个头: 
Content-Disposition: form-data; name="file"; filename="C:\Users\Mrzhang\Desktop\copy2.txt"
Content-Type: text/plain MIME

文件上传的内容:
xxxx

-----------


二: 解析request当中的请求体: 
 
 1:jar: Apache组织提供的一个公共组件: 
        commons-fileupload 
        commons-io
        
        
    和文件上传相关的两个组件, 这两个组件是强依赖。   
    
    
 2:原理: 
   把request请求体当中的每一个组件的内容都封装到了一个对象当中: 
 FileItem对象: 使用对象的方法和属性来获得数据。 
 
 3:获得FileItem: 
 a: 获得工厂: 
 b: 获得解析器: 
 c: 使用解析器解析request,得到fileItme 对象: 
 
 对象的代码: 
 // 获得工厂: 
 DiskFileItemFactory Factory = new DiskFileItemFactory(); 
 //获得解析器: 
 ServletFileUpload  upload = new ServletFileUpload(Factory); 
 
 // 解析request,获得所有的FileItem对象: 
 List<FileItem>  list=  upload.parseRequest(request);


 4: FileItem 类的详解: 
 
  isFormField() 判断组件是一个普通组件还是一个文件上传组件: true,普通组件:false: 文件上传组件: 
  getFieldName() 返回普通字段属性的值。  name= username  获得是username的值: 
  getString();  获得普通字段上传的内容。 
  
  文件上传组件: 
  getName();获得文件的名称: 
  getSize();会的文件上传的字节大小。 long 
  getInputStream();获得文件上传对应的流: 
  write(File file) ; 文件的内容写到指定的位置:  
 

 

三: 文件上传的具体代码;  
  
  (1)引入jar包: 
  (2)准备页面: 
  (3)准备Servlet:  
 
四: 细节: 
1:上传的普通字段的内容: 乱码: getString("utf-8"); 
2:上传的文件不能被外界直接访问, 应该隐藏起来: 目的,安全; 
   应该吧文件上传到web-inf下,内容不能被外界直接访问。

  获得为web-inf/files的位置: 在tomcat上真实的位置: 
  ServletContext.getRealPath("/WEB-INF/files");
  
3: 文件的的文件的路径问题:  
   不同的浏览器上传的路径不一致。 有的浏览器上传的上传相对路径, 有的浏览器上传的是绝对路径。 大部分浏览器上传的相对路径。 
   a.txt
   c:\user\mrzhang\files\a.txt
   
   截取出文件的名称: 
  String filename =  f2.getName();
  
  //截取: 
  int index = filename.lastIndexOf("\\");
  if(index!=-1){
    filename = filename.subString(index+1);
  }
 
4: 上传文件的名称乱码问题: 
  request.setCharacterEncoding("utf-8");
  解析器当中提供了一个方法: 
  servletFileUpload.setHeaderEncoding("utf-8");// 解析器提供。优先级高:  对 request.setCharacterEncoding("utf-8");的封装
5: 文件同名的问题: 
  解决方式一:   uuid+"filename".后缀名称; 
  解决方式二:    new Date().getTime()+"filename"; 
6: 上传的文件不能存在同一个目录下 :  上传的目录打散: 
  a: 时间打散:   获得当前的时间, 创造目录:  
  b: 文件名称首字母打散:  abc.txt :  charAt("0")
  c: 哈希打散:  
  实现步骤: 
         (1)  获得文件名称: 
         (2)获得哈希值: hashCode(); int
         (3)转换成十六进制: Integer.toHexString(); //字符串: 9A8B7C
         (4)  获得字符串的前两个:  第一个字母做第一层目录。     第二个字母做第二层目录。  16*16
   
 

package com.yidongxueyuan.web.servlet;

import java.io.File;
import java.io.IOException;
import java.util.List;

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.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/*
 * 处理文件上传的servlet: 
 * 
 * 1:细节: 
 *  乱码解决了文件名称上传的乱码, 
 *  普通字段: getString("utf-8");
 *  
 * 2:对相对路径进行了处理:  subString(); 
 * 
 * 3: 文件名称同名的问题,处理: 
 * 
 * 4: 哈希打散: 
 *   filename.hashCode();
 *   filename.toHexString(); 
 *   filename.charAt(0);  
 *   
 *  File dir=   new File(root, charAt(0)+"\"+charAt(1));
 *  
 *  File destFile = new File(dir, savefilename);
 *  
 *  write(); 
 *   
 *  
 *  
 *  
 */
public class FileUploadServlet extends HttpServlet {

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//解决上传文件名称的乱码问题:  
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");//告知客户端浏览器响应的内容: text/html charset=utf-8
		/*
		 * 三步走: 
		 * 1:获得工厂: 
		 * 2: 获得解析器: 
		 * 3:解析request:
		 */
		
		//获得获得解析器工厂; 
		DiskFileItemFactory factory = new DiskFileItemFactory(1024*20,new File("C:/Users/Mrzhang/javaEE/javaEE-07/temp")); 
//		DiskFileItemFactory factory = new DiskFileItemFactory(); 
		//获得解析器:
		ServletFileUpload upload = new ServletFileUpload(factory);
		
		//解析之前设置上传单个文件的大小: 
//		upload.setFileSizeMax(1024*10);//这是最大是10K: 
//		upload.setSizeMax(1024*1024*10); //设置了整个request 的大小, 如果上传的request 大于设定的最大值, 也会触发异常
		
		//解析request: 获List<FileItem>
		try {
			List<FileItem> fileItem = upload.parseRequest(request);
			
			
			//解析fileItem当中的内容:  web-inf下的: 目录安全: 不能被外界随机的访问:  
			FileItem f2 = fileItem.get(1);//文件上传的组件: 
			
			/*
			 * 获得文件的名称: 
			 * f2.getName(); 
			 * f2.getInputStream(); 文件当中的内容: 
			 * new FileOutputStream("path"); 
			 * 实现流对接: 
			 */
			
			/*
			 * 获得要保存的路径: 
			 * WEB-INF/files/ 
			 * 目的: 安全: 不能被外界直接通过浏览器访问: 
			 * 获得ServletContext对象: 获得真实路径:
			 */
			String root = this.getServletContext().getRealPath("/WEB-INF/files/");
			
			
			
			//获得上传文件的名称: 
			String filename = f2.getName();
			
			/*
			 * 细节的处理: 
			 * 1: 绝对路径的问题:  兼顾小部分浏览器: 
			 */
			int index = filename.lastIndexOf("\\");
			if(index != -1){//说明路径当中存在\\ : 
				filename = filename.substring(index+1);
			}
			
			
			/*
			 * 处理文件同名的问题: uuid 
			 */
			
			String savename = CommonsUtils.uuid()+"_"+filename;
			
			/*
			 * 哈希码 生产多个目录: 将上传的文件存放在多个目录当中:  
			 */
			
//			1:获得文件名称的哈希值: 
			int code  = filename.hashCode();// int
			
			
//			2:获得code 的十六进制的值: 
			String hex = Integer.toHexString(code);//  9c0a1d
			
//			获得前两位: 充当第一层目录 和第二层目录: 
			char firstDir = hex.charAt(0);
			char secDir = hex.charAt(1);
			
			/*
			 * 获得保存的文件路径: 
			 */
			
			File dirFile = new File(root, firstDir+"/"+secDir);//存放的目录: 
			
			
			//dirFile 如果不存在,创建: 
			if(!dirFile.exists()){//说明不存在
				//创建“: 
				dirFile.mkdirs();//创建多层的目录: 
			}
			
			//创建保存的文件: 
			File destFile = new File(dirFile, savename);
			
			//保存: 
			
			try {
				f2.write(destFile);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		} catch (FileUploadException e) {
			// 触发异常: 说明文件过大: 
			request.setAttribute("msg", "您传的文件过大"); 
			request.getRequestDispatcher("/index.jsp").forward(request, response); 
			
			e.printStackTrace();
		}
	}

}

 
文件的下载

 

文件的下载:  
  原来: 服务器响应回来的数据:text/html 浏览器能够自动解析:   
 
 原理: 现在要求服务器传递过来的数据是一个字节数组: 只需要在服务器端响应回来一个字节流即可。 
 
 下载的要满足的条件一个流两个头: 
 
  流: 服务器端响应回来的字节流.  new FileOutputStream("String path");
  设置两个头: 
  * Content-Type: 这是成文件类型的MIME类型: text/css text/javascript : tomcat : web.xml 
  * Content-Disposition :  默认值: inline 在浏览器当中打开。  
        文件下载: attachment;filename=xxxx; 
  
 下载的细节: 
 1: 下载文件的名称乱码问题:  
   通用的解决方案: 
 new String(name.getBytes("gbk"),"iso-8859-1");
 弊端: 该种方式能够解决大部分浏览器,  但是个别的特殊字符不能解决: 
 
 不同的浏览器对文件的名称编码方式不一样: 
  fixfox: Base64 : 
  其他的浏览器: url
  
 2:  通用性方式: 提供一个工具类到时候再搜吧 : 

文件下载 servlet代码如下:

package com.yidongxueyuan.web.servlet;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

import sun.misc.BASE64Encoder;

/*
 * 负责下载的Servlet: 
 */
public class DownLoadFileServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
	/*	request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");*/
		
		
		/*
		 *  1: 文件的下载具备一个流: 两个头: 
		 */
		
		String filename = "C:/Users/Mrzhang/Desktop/API/a练习图片/girl.jpg"; 
		
		//头信息:  
		// Content-Type: MIME 文件的MIME类型: 
		String conentType= this.getServletContext().getMimeType(filename);//能够获得.jpg文件的MIME类型: image/jpeg 
		
		String name = "凤姐.jpg"; 
//		String savename =  new String(name.getBytes("gbk"),"iso-8859-1"); 解决 大部分情况: 
		
		String savename = FilenameEncodingUtils.filenameEncoding(name, request);
		String contentDisposition = "attachment;filename="+savename;
		
		//设置响应头信息: 
		response.setHeader("Content-Type",conentType ); 
		response.setHeader("Content-Disposition", contentDisposition); 
		
		
		//准备的一个流: 
		
		//将图片读取到fis当中: 
		FileInputStream fis = new FileInputStream(filename);
		//响应输出流: 
		ServletOutputStream out = response.getOutputStream(); 
		//流对接: IOUtils 
		IOUtils.copy(fis, out);
		
		fis.close(); 
		out.close(); 
		
		
	}

}

 class FilenameEncodingUtils {
	// 用来对下载的文件名称进行编码的!
	public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException {
		String agent = request.getHeader("User-Agent"); //获取浏览器
		if (agent.contains("Firefox")) {
			BASE64Encoder base64Encoder = new BASE64Encoder();
			filename = "=?utf-8?B?"
					+ base64Encoder.encode(filename.getBytes("utf-8"))
					+ "?=";
		} else if(agent.contains("MSIE")) {
			filename = URLEncoder.encode(filename, "utf-8");
		} else {
			filename = URLEncoder.encode(filename, "utf-8");
		}
		return filename;
	}
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东方-教育技术博主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值