JAVA的文件上传和下载详解

时间:2022-05-28 22:04:17
1、过滤器案例:通用字符集编码过滤器
1.1 表单提交中文数据到servlet里面会有乱码,之前需要在每个servlet里面都需要处理

     编写过滤器,把设置中文的代码写到过滤器里面,在每个servlet里面不需要写处理代码

1.2 增强类中的方法有三种方式
(1)继承
(2)装饰者模式
(3)动态代理
1.3 实现的过程
(1)无论get提交还是post提交,在servlet都使用request里面的getParameter方法得到
(2)增强request里面getParameter方法,把逻辑增强,如果get提交编码转换,如果post提交设置编码
(3)如何增强request里面方法?
第一种做法:使用装饰者模式实现,实现HttpServletRequest接口,需要把接口里面的所有方法都实现
第二种做法:sun公司为HttpServletRequest接口提供了一个类,这个类为了让增强使用的类,HttpServletRequestWrapper 
继承类就可以了。
(4)总结
= 增强类中的方法,如果增强request里面的方法,直接继承HttpServletRequestWrapper类实现
  如果增强response里面的方法,直接继承HttpServletResponseWrapper 类实现
= 过滤器实现的过程
第一部分:文件上传
1、什么是文件的上传
1.1 把本地电脑上的文件存到服务器上面,这个过程称为上传操作,比如网盘
1.2 在servlet里面2.5版本中不能实现文件上传(使用servlet3.0版本可以实现文件上传)
1.3 依赖第三方组件实现文件上传
(1)首先导入jar包
1.4 有两个
(1)fileUpload:使用在模型二,是 Apache组织开源组件,组件FileUpload依赖于Commons IO组件(导入两个jar包)
(2)jspsmartupload:使用在模型一,适于嵌入执行上传下载操作的JSP文件中
2、代码实现文件上传
2.1 文件上传满足三个要求(**)
第一个:在表单里面提交方式 method="post"
第二个:在表单里面有文件上传项,在文件上传项里面必须有name属性
<input type="file" name="file"/>
第三个:在表单里面设置提交数据的类型 使用属性 enctype="multipart/form-data"
2.2 fileUpload代码实现的步骤(固定的)
第一步:创建磁盘文件项工厂
new DiskFileItemFactory();
第二步:创建核心上传类
new ServletFileUpload(FileItemFactory fileItemFactory)
参数:传递第一步new出来的对象就可以了,因为new出来的对象是FileItemFactory实现类
第三步:使用核心上传类解析request对象
List parseRequest(javax.servlet.http.HttpServletRequest request)
返回list集合 List<FileItem>
第四步:遍历list集合,判断是否普通输入项还是文件上传项
遍历之后每部分都是FileItem
使用FileItem里面boolean isFormField()判断是否是普通输入项,如果返回true是普通输入项
第五步:如果普通输入项获取值,如果是文件上传项写上传流操作
获取普通输入项的值:
getFieldName():获取普通输入项name的属性值
getString():获取普通输入项的输入的值
获取文件上传项内容
getName():获取到上传文件的文件名称
获取上传文件的输入流:
getInputStream()
2.3 实现的代码
String filename = fileItem.getName();
	//在某些浏览器里面得到的带路径:C:\Users\asus\Desktop\1.txt
	int lens = filename.lastIndexOf("\\");
	//判断是否带路径
	if(lens != -1) {
		filename = filename.substring(lens+1);
	}
	//流操作
	//得到表单提交的文件的输入流
	InputStream in = fileItem.getInputStream();
	//使用输出流把写到服务器上
	//得到文件夹的完全路径 servletcontext
	String path = getServletContext().getRealPath("/upload");
	OutputStream out = new FileOutputStream(path+"/"+filename);
	//流对接
	int len = 0;
	byte[] b = new byte[1024];
	while((len=in.read(b))!=-1) {
		out.write(b, 0, len);
	}
	//关闭流
	out.close();
	in.close();
3、核心api的使用
3.1 上传文件时候,上传文件名称中包含中文,乱码问题
(1)ServletFileUpload类 setHeaderEncoding(java.lang.String encoding) 
3.2 普通输入项里面中文解决
(1)FileItem : getString(java.lang.String encoding)
3.3 其他的方法介绍
ServletFileUpload类其他的方法:
(1)setFileSizeMax(long fileSizeMax):设置单个文件上传的大小
(2)setSizeMax(long sizeMax):设置总的文件的大小
(3)如果超过大小,抛出异常信息:The field filename exceeds its maximum permitted  size of 1048576 characters.
FileItem的其他的方法:
(1)getName():获取上传文件的名称

在某些浏览器里面得到文件名称包含路径,截取得到文件名称

==============================================================
总结
1、过滤器案例
(1)增强类中的方法(增强request里面的方法)
2、上传
(1)上传三个要求
(2)代码实现上传的步骤
(3)如何使用代码实现上传
(4)核心api的方法
===============================================================
1、文件上传的问题
1.1 文件重名问题
(0)如果上传多个相同名称的文件,最后一次上传的文件会把之前的文件覆盖
(1)解决方法:保证文件名称唯一的,不会覆盖
(2)具体实现:在文件名称里面拼接唯一的值(UUID、毫秒数)
(3)代码
	//生成uuid值
	String uuid = UUID.randomUUID().toString();
	// uuid_filename
	filename = uuid+"_"+filename;
1.2 在文件夹里面过多文件
(0)如果文件夹里面文件过多,造成读写很慢
(1)解决方法:
第一种:按照日期进行存储(年、月、日、小时)
第二种:根据用户进行存储(张三的文件存到张三文件夹里面)
第三种:根据文件数量进行存储(比如3000个文件存到一个文件夹中)
(2)第四种:使用目录分离算法(**)
第一步:得到文件的唯一的名称,计算唯一的文件名称 hashcode值,返回int值
第二步:使用第一步得到int值,& 0xf (1111),把结果作为第一级目录
第三步:使用第一步的int值,把值右移4位,把右移4位的结果再 & 0xf,把结果作为第二级目录
......以此类推
(3)int是32位,在计算机如何表示的?
 0 1 10 11 100 101 .........
 = 表示方式:每四位表示一段,一共有8段
0001 1000 1010 1001 0010 1001 1010  1010 
(4)代码
public static String getPath(String filename) {
		//计算文件名称hashcode值
		int code1 = filename.hashCode();
		//把得到int值 & 0xf
		int d1 = code1 & 0xf;
		//把int值右移4位
		int code2 = code1 >>> 4;
		//再&0xf
		int d2 = code2 & 0xf;
		return "/"+d1+"/"+d2;
	}
(5)上传中分离目录完善
//得到文件夹的完全路径 servletcontext
	String path = getServletContext().getRealPath("/upload");
	//得到分离的目录
	String url = UploadUtils.getPath(filename);
	//因为分离的目录没有创建,首先创建,在存文件
	File file = new File(path+url);
	//判断文件是否存在
	if(!file.exists()) {
		//创建
		file.mkdirs();
	}
	OutputStream out = new FileOutputStream(path+url+"/"+filename);
2、案例-添加商品(上传商品图片)
2.1 最终目的:把图片上传到服务器、把商品信息存到数据库
2.2 实现的步骤
(1)创建添加商品的页面,表单,满足上传的三个要求,提交servlet
(2)创建servlet,实现上传,获取表单提交过来的商品的信息,把商品信息存到数据库
(3)上传图片(在数据库里面存储上传图片的路径)
2.3 总结
(1)在上传代码中如何获取普通输入项的值,把多个普通输入项的值封装到javabean
(2)上传代码实现
(3)添加数据到数据库
第二部分:文件下载
1、什么是文件的下载
1.1 把服务器上面的文件保存到本地的硬盘上,这个过程称为文件的下载
2、实现文件下载
2.1 实现的步骤
(1)在服务器上需要有可以下载的文件
(2)得到服务器上面文件的内容
= 使用字节流,使用输入流
(3)使用输出流把文件内容写到浏览器中
(4)重要步骤:设置头信息 Content-Disposition,无论什么格式文件都是以下载方式打开
= response.setHeader("Content-Disposition", "attachment;filename="+filename);
3、下载中文名称的文件
3.1 如果下载文件名称包含中文,下载显示时候不能正常显示
3.2 解决方法:
(1)不同的浏览器有不同的编码  火狐和非火狐
(2)ie采用url编码,火狐采用base64编码
(3)实现方式:
区分不同的浏览器,(使用请求头 User-Agent得到不同的浏览器信息)
对不同的浏览器进行不同的编码
(4)代码
String agent = request.getHeader("User-Agent");
	//如果是火狐浏览器
	if(agent.contains("Firefox")) {
		//base64编码
		filename = "=?UTF-8?B?"+
			new BASE64Encoder().encode(filename.getBytes("utf-8"))+"?=";
	} else {//ie浏览器 url编码
		filename = URLEncoder.encode(filename, "utf-8");
	}
4、文件下载有两种方式
第一种:代码实现文件下载
第二种:使用超链接下载文件
(1)在超链接里面直接写文件在项目中的路径
<a href="${pageContext.request.contextPath }/img/2.zip">2.zip</a>
(2)如果文件格式是图片格式,直接打开