实验 FileUpload 笔记

1. 需求

1.1 文件的上传

1.1.1 可以上传一个或多个文件,每个文件后面附加一个desc文本域,用于上传对该文件的说明信息

1.1.2 文件通过表单上传到服务器,服务器将文件保存到它的本地磁盘文件夹,并将其文件名改为一个随机数,以免有重名文件冲突;并将该文件的原文件名、保存在服务器上的路径(包含随机文件名) 以及对该文件的描述信息保存到数据库中

1.1.3 删除临时存储在磁盘上的文件(对于上传的大于5M的文件,先存在磁盘的临时目录下,而非内存中)。

  1.1.4 重定向到 list.jsp--显示所有上传文件的页面



1.2 文件的下载

1.2.1 指定客户端浏览器的响应方式为文件下载的方式 , 通知浏览器下载的文件不再由浏览器直接打开,而是由用户手动操作

1.2.2 根据 list 页面提供的 id ,从数据库获取要下载的文件的信息;

1.2.3 由 path 字段获取该文件在服务器上的存储位置,并创建 File 对象;

1.2.4 创建输入输出流: 输入流对应 下载文件对象 file; 输出流:客户端浏览器的输出流response.getOutputStream();

将文件写到输出流,完成下载工作。

 

2. 主要知识点

2.1  HTML <form> 标签的 enctype 属性

> 定义和用法 :

enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。

默认地,表单数据会编码为 "application/x-www-form-urlencoded"。就是说,在发送到服务器之

前,所有字符都会进行编码(空格转换为 "+" 加号,特殊符号转换为 ASCII HEX 值)。


> 属性值 :

 值 描述
 application/x-www-form-urlencoded 在发送前编码所有字符(默认)
 multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
 text/plain 空格转换为 "+" 加号,但不对特殊字符编码。

> 语法 :

<form action="uploadServlet" method="post" enctype="multipart/form-data">

File:<input type="file" name="fileupload" /><br><br>

...

</form>


2.2 common-fileupload 组件

> 说明:

common-fileupload 组件是apache的一个开源项目之一,可以从http://jakarta.apache.org/commons/fileupload/下载。用该组件可实现一次上传一个或多个文件,并可限制文件大小。

> 用法 :

>> 导入两个包 :commons-fileupload-1.3.1.jar 和commons-io-2.4.jar

>> 简单用法:解析request,获取所有表单提交的 input 项,存放在 List<FileItem> 对象中,

  其中一个input项对应一个 FileItem 对象

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// Create a factory for disk-based file items DiskFileItemFactory factory = new DiskFileItemFactory(); // Configure a repository (to ensure a secure temp location is used)

// 上传文件的临时存放位置 ServletContext servletContext = this.getServletConfig().getServletContext(); File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir"); factory.setRepository(repository); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // Parse the request, 解析 request; 从request中获取表单提交的所有 input 项,

// 并将其存放在 List<FileItem> 对象 List<FileItem> items = upload.parseRequest(request);

}

>> 更多操作 :设置最大内存存储文件大小,临时文件夹路径,request最多上传文件总大小

// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();

// Set factory constraints
// 设置最大内存容量:超过该值,则将文件存放到临时文件夹 
factory.setSizeThreshold(yourMaxMemorySize);
factory.setRepository(yourTempDirectory);

// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);

// Set overall request size constraint
// 设置一个request 中最多上传的文件的总大小,单位为Byte
upload.setSizeMax(yourMaxRequestSize);

// Parse the request
List<FileItem> items = upload.parseRequest(request);
>> 处理上传的 items
// Process the uploaded items
Iterator<FileItem> iter = items.iterator();
while (iter.hasNext()) {
    FileItem item = iter.next();

    // 处理文本信息
    if (item.isFormField()) {
        processFormField(item);
	String name = item.getFieldName();
   	String value = item.getString();
        ...
    }
    // 处理二进制文件
    else {
        String fieldName = item.getFieldName();
        String fileName = item.getName();
    	String contentType = item.getContentType();
    	boolean isInMemory = item.isInMemory();
    	long sizeInBytes = item.getSize();
	// 存储到服务器的本地磁盘文件夹
    	if (writeToFile) {
    		File uploadedFile = new File(...);
   		item.write(uploadedFile);
	} 
	// 若要写入数据库,需要获取上传文件的输入流
	else {
    	InputStream uploadedStream = item.getInputStream();
   	 ...
   	 uploadedStream.close();
	}
    }
}
2.3 文件下载 :

> //3. 指定客户端浏览器的响应方式为文件下载的方式

response.setContentType("application/x-msdownload");

// 通知浏览器下载的文件不再由浏览器直接打开,而是由用户手动操作

response.setHeader("Content-Disposition","attachment; filename="+fileName);

public class DownloadServlet extends HttpServlet{ private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String idStr = request.getParameter("id"); int id = Integer.parseInt(idStr); //1. 从数据库获取要下载文件的信息 FileUploadBean fileInfo = FileDaoImpl.getInstance().getFileInfo(id); //2. 将文件名由 UTF-8 编码转成 ISO_8859_1 编码,以免浏览器解析乱码 String fileName = new String(fileInfo.getName().getBytes("UTF-8"),"ISO_8859_1"); //3. 指定客户端浏览器的响应方式为文件下载的方式 response.setContentType("application/x-msdownload"); // 通知浏览器下载的文件不再由浏览器直接打开,而是由用户手动操作 response.setHeader("Content-Disposition","attachment; filename="+fileName); //4. 获取该文件在服务器上的存储路径,并创建 File 对象 File file = new File(fileInfo.getPath()); //5. 创建输入流和输出流, 输入流对应 下载文件对象 file; 输出流:response.getOutputStream(); //完成文件从服务器下载到本地的功能 InputStream in = null; ServletOutputStream out = null; try { in = new FileInputStream(file); out = response.getOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while((len = in.read(buffer)) != -1){ out.write(buffer, 0, len); } } catch (Exception e) { e.printStackTrace(); } finally { if(out != null) out.close(); if(in != null) in.close(); } }


3. 注意事项

3.1 文件合法性检查 :对文件的后缀名,大小做检查,前端用js获取文件名及大小的方法如下:

File:<input type="file" name="fileupload" οnchange="checkFile(this)"/>

function checkFile(file){ var fielSize = file.files[0].size; var fileName = file.files[0].name; var fileType = fileName.split(".").pop(); if(fielSize >= 5*1024*1024){ $(file).val(""); $("h4").text("您上传的 "+ fileName +" 文件太大(超过 5 M)! 请重新上传..."); return; } if(fileType != "rar" && fileType != "jpg" && fileType != "png" && fileType != "zip"){ $(file).val(""); $("h4").text("您上传的 "+fileName+" 文件格式不合适(rar, jpg, png格式可用)! 请重新上传..."); return; } $("h4").text(""); }


3.2  上传文件时出现 文件名中文乱码 及 文件描述信息中文乱码的解决方法:

3.2.1  文件名中文乱码:request.setCharacterEncoding("UTF-8");

3.2.2 文件描述信息中文乱码:String desc = fileItem.getString("UTF-8"); // fileItem 为 FileItem 对象


3.3 下载文件时,浏览器解析中文乱码:

浏览器只能解析 ISO_8859_1 编码。将文件名由 UTF-8 编码转成 ISO_8859_1 编码,以免浏览器解析乱码

String fileName = new String(fileInfo.getName().getBytes("UTF-8"),"ISO_8859_1");


3.4 bean的一个字段为desc 是 MySQL的一个关键字,sql语句:"SELECT id, NAME, path, file_desc desc  FROM files where id=?";不能通过,报 sql语句异常。

应改为:"SELECT id, NAME, path, file_desc AS \"desc\"  FROM files where id=?"

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值