[日常笔记]文件上传

文件上传

文件上传概述

上传文件对页面的要求

  1. 必须使用表单,而不能是超链接。
  2. 表单的 method 必须是 post,而不能是 get。
  3. 表单的 enctype 必须是 multipart/form-data。
  4. 在表单中添加 file 表单字段,即<input type="file" ...>

上传文件表单与普通文件表单的区别

文件上传表单的 enctype=“multipart/from-data”,表示多部件表单数据。
普通文本表单可以不设置 enctype属性:

  • 当 method="post"时,enctype的默认值为application/x-www-form-urlencoded,表示使用url编码正文。当method="get"时,enctype的默认值为null,没有正文,所以就不需要enctype了。

文件上传对Servlet的要求

request.getParameter(String name)方法获取指定的表单字段字符内容,但上传表单已经不在是字符内容,而是字节内容,所以失效。
这时我们可以使用request的getInputStream()方法获取ServeltInputStream对象。它是InputStream的子类,这个ServletInputStream对象对应整个表单的正文部分(从第一个分割线开始,到最后)。

  • 不能再使用request.getParameter()来获取表单数据。

  • 可以使用request.getInputStream()得到所有的表单数据,而不是一个表单项的数据。

  • 这说明不使用fileupload,我们需要自己来对request.getInputStream()的内容进行解析。

fileupload

fileupload是由apache的commons组件提供的上传组件。它最主要的工作就是帮我们解析request.getInputStream()。

fileupload组件需要的jar包:

  • commons-fileupload.jar。核心包
  • commons-io.jar。依赖包

fileupload的核心类有:DiskFileItemFactory,ServletFileUpload,FileItem。

使用fileupload组件的步骤如下:

  1. 创建工厂类DiskFileItemFactory对象:DiskFileItemFactory factory = new DiskFileItemFactory();
  2. 使用工厂创建解析器对象:ServletFileUpload fileUpload = new ServletFileUpload(fctory);
  3. 使用解析器来解析request对象:List<FileItem> list = fileUpload.parseRequest(request);

方法:
String getName():获取文件字段的文件名称。

String getString():获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文件文件。

String getFileldName():获取字段名称,例如:<input type="text" name="username">返回的是username。

String getContentType():获取上传的文件的类型,例如:text/plain。

Long getSize():获取上传文件的大小。

boolean isFormFIeld():判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段。

InputStream getInputStream():获取文件上传文件对应的输入流。

void write(File file):把上传的文件保存到指定文件中。

小例子:

//创建接收文件的工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//创建文件解析对象
ServletFileUpload sfu = new ServletFileUpload(factory);
try {
//解析request获得表单中的每一个文件项(包含普通文本域)
	List<FileItem> fiList = sfu.parseRequest(req);
	//遍历循环
		for(FileItem fi : fiList){
			//获取文件字段的文件名称
			String name = fi.getName();
			//获取字段的内容
			String str = fi.getString();
			//获取字段名称
			String filedName = fi.getFieldName();
			//获取上传文件的类型
			String content = fi.getContentType();
			//获取上传文件的大小
			long size = fi.getSize();
			//判断当前表单字段是否为文本字段
			boolean formField = fi.isFormField();
		}
	} catch (FileUploadException e) {
		e.printStackTrace();
}
文件上传细节

把文件上传放到WEB-INF目录下

如果没有把用户上传的文件存放到WEB-INF目录下,那么用户就可以通过浏览器直接访问上传的文件,这是非常危险的。可以使用浏览器进行访问上传的文件。

WEB-INF里面的文件都是受保护的,将隐私的文件放到WEB-INF中可以提高文件的安全性。

中文乱码问题

上传文件中包含中文:
里面的name为"UTF-8"编码方式。

  • request.setCharacterEncoding(String name)

  • fileUpload.setHeaderEncoding(String name)

上传文件的文件内容包含中文:

文本文件内容和普通表单项内容使用FileItem类的getString(“utf-8”)来处理编码。

上传文件同名问题(文件重命名)

处理这一问题,我们可以使用UUID生成唯一名称。

上传的单个文件的大小限制

限制上传文件的大小很简单,ServletFileUpload类的setFileSizeMax(long)就可以了。参数就是上传文件的上限字节数,例如:servletFileUpload.setFileSizeMax(1024*10)表示上限为10KB。

一旦上传的文件超出了上限,那么就会抛出FileUploadBase.FileSizeLimitExceededException异常

resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
		
//创建接收文件的工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//创建文件解析对象
ServletFileUpload sfu = new ServletFileUpload(factory);
//解析request
try {
	//解析request获得表单中的每一个文件项(包含普通文本域)
	List<FileItem> fiList = sfu.parseRequest(req);
	//遍历循环
	for(FileItem fi : fiList){
		//获得原始文件名
		String origFileName = fi.getName();
		//获得文本域的名字
		String fieldName = fi.getFieldName();
		//获得是否是普通文本,如果是true是普通文本,如果是false是文件字段
		boolean isFileldForm = fi.isFormField();				
		if(!isFileldForm){
			if(fieldName != null && !"".equals(fieldName)){
				//指定要上传的目录
				String uploadPath = req.getSession().getServletContext().getRealPath("/WEB-INF/upload");
				//生成uuid文件名,使文件不会重复
				String uuid = UUID.randomUUID().toString();
				//获得原始文件名的后缀
				String suffix = origFileName.substring(origFileName.lastIndexOf("."));						
				//创建文件对象
				File file = new File(uploadPath, uuid+suffix);
				//把文件写入到硬盘
				fi.write(file);
				resp.getWriter().print("文件上传成功");
			}
		}
	}
} catch (Exception e) {
	e.printStackTrace();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值