文件上传&下载

文件上传:html

1.所须要的包:前端

commons-fileupload-1.2.1.jarjava

commons-io-1.4.jarweb

2.浏览器端:数据库

        1>.请求方式必须是 postapache

        2>.须要使用组件<input type="file" name="f">浏览器

        3>.表单必须设置encType="multipart/form-data"安全

        4>.上传文件的input 中,name属性必需要填写,否则不会上传. 服务器

<form action="${pageContext.request.contextPath}/upload2" method="post"	
        enctype="multipart/form-data">
<input type="file" name="f"> 
<input type="submit" value="上传">
<form/>

3.服务器端:app

    能够经过request对象,获取InputStream,能够将浏览器提交的全部请求正文读取到。

4.核心类的使用:

1.DiskFileItemFactory    用于设置文件上传时,缓冲区大小以及临时文件存储位置.

        1 能够设置文件上传缓冲区大小

                factory.setSizeThreshold(1024*1024); //设置为1m 默认是10k

        2能够设置临时文件存储位置

                File temp=new File(this.getServletContext().getRealPath("/temp"));

                factory.setRepository(temp); //能够指定临时文件存储位置,默认是系统的临时文件存储位置

2.ServletFileUpload   它的做用是真正完成解析数据操做上传类

        1.pareRequest(HttpServletRequest request)

                获得全部的上传信息,将每一部分映射成FileItem对象.

        2.isMultipartContent(HttpServletRequest request)

                这个方法返回值是boolean,它是用于判断当前表单是不是一个上传的表单,

                简单说,就判断它的encType的值是不是 multipart/form-data.

        3.setHeaderEncoding(String encoding)

        用于解决上传文件名称中文乱码问题

        4.能够设置上传文件大小,若是超过设置大小.将会抛出异常(默认没有最大值)

        void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小 

        void  setSizeMax(long sizeMax) 设置总文件上传大小 

3.FileItem        它表明的是每个上传项(其时就是表单中的每个组件)

        1.isFormField()

                这个方法返回的是boolean类型,

                它是判断当前组件是不是上传组件 简单说,就是判断type="file",

                若是返回true,表明不是上传组件,返回false,表明是上传组件

        2.getName()

                获取非上传组件的上传文件的名称,若是是非上传组件,返回的是null

        3.getFieldName()

                获取组件名称,提交的键

        4.getString()

                获取非上传组件的value值,

                经过它也能够获取上传的文件内容,可是,使用它获取不合适。

                若是使用了commons-fileupload进行文件上传,而上传表单中包含了

                非上传组件,获取其值,不能使用request获取.

                getString()有一个重载的方法 getString(String encoding)能够解决乱码问题

                问题:使用getString()去获取上传文件内容不合适,那么怎样操做?

        基本操做:

                        经过FileItem.getInputStream();能够获取一个输入流,这个输入流就能够读取出上传文件内容。

                        InputStream is = item.getInputStream(); // 用于读取上传文件内容的输入流.

                        FileOutputStream fos = new FileOutputStream(

                        "d:/upload/" + filename);


                        int len = -1;

                        byte[] b = new byte[1024 * 10];


                        while ((len = is.read(b)) != -1) {

                        fos.write(b, 0, len);

                        fos.flush();

                        }

                        fos.close();

                        is.close();


                        能够使用IOUtils工具完成文件copy操做

                        IOUtils.copy(is, fos);

        5.delete方法

          它是用于上传完成后,删除临时文件的

4.注意问题:

        1>关于文件上传时文件名称包含中文的乱码问题?

        调用ServletFileUpload的setHeaderEncoding方法解决

        2>普通表单字段提交时,中文乱码问题?

        FileItem的 getString方法返回提交的值.经过参数来设置解码码表

                例如: getString("UTF-8");

        3>如何设置上传文件大小限制?

        调用ServletFileUpload的setSizeMax(总大小)

                setFileSizeMax(每一个大小)方法

        4>上传文件后,咱们应该把文件保存到什么位置?

                1.上传以后,客户端直接可以访问到的地方. WEBRoot下

                2.上传后其余用户不能直接访问

                放到webRoot之外的文件夹. WEB-INF(安全目录)下或硬盘其余位置 .例如 d:/xxx

        5>上传文件时,该使用什么名字将文件保存?

                文件名称不能使用用户命名的名称.

                用户命名的名称咱们须要保存到数据库中,在下载时使用.

        6>不是用用户命名的名称,咱们以什么名称保存文件(不能重复)?

        UUID

                登陆用户名+当前系统毫秒数 (只容许单文件上传,一个请求只能上传一个文件)

        7>如何得到用户命名的文件名?

                getName方法便可得到文件名.

                IE浏览器中,会把文件的在客户端的完整路径传过来.须要截取.

                其余浏览器只会文件名称传过来.直接使用,无需截取.

        8>为了防止同一个目录下方上传文件数量过多,思考如何解决? 

                 /upload/2016/03/27/xxxx  使用当前日期做为子文件夹名称

                当前登陆用户的用户名做为文件夹名称(不推荐)

实例:

  1. upload.jsp(前端仅贴出相关提交的代码)

<!-- 
    	1. 表单必须是post提交.
    	2. 修改enctype属性 . EncodeType 请求正文内容类型. 
    			application/x-www-form-urlencoded (默认值:用于提交文本类型内容).
    			multipart/form-data (多段式提交)
    	3. 文件上传时,需使用 input type=file 组件
    			注意:  该组件必定要设置name属性.
    			
     -->
  <body>
	<form action="/upload/AServlet" method="post" enctype="multipart/form-data">
		用户名:<input type="text" name="username"/><br/>
		<input type="file" name="file1" /><br/>
		<input type="file" name="file2"/>
		<input type="submit" value="提交">
	</form>
  </body>

2.Aservlet.jsp

package cn.test.upload;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;

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;
import org.apache.commons.io.IOUtils;

public class AServlet extends HttpServlet {

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//1.建立解析器配置工厂
			//DiskFileItemFactory:用于设置文件上传时,缓冲区的大小以及临时文件的存储位置
		DiskFileItemFactory factory = new DiskFileItemFactory();
		//2.根据配置工厂的配置建立解析器类
			//ServletFileUpload:真正完成解析上传数据的操做类
		ServletFileUpload upload = new ServletFileUpload(factory);
		//3.判断是否为多段式方式提交,也就是判断它的encType的值是不是 multipart/form-data
		if(!upload.isMultipartContent(request)){
			throw new RuntimeException("您的表单提交方式错误");
		}
		//设置多段式每一段段头的编码表
		upload.setHeaderEncoding("UTF-8");
		//FileItem:表明的就是每个上传项,其实就是表单中的每个组件
		List<FileItem> list=null;
		//3.调用解析方法,解析request对象
		try {		
			list = upload.parseRequest(request);
		}catch (FileUploadException e) {
			e.printStackTrace();
			throw new RuntimeException("解析request对象失败!");
		}
		if(list!=null){
			for(FileItem item:list){
				//判断item为普通文本提交段
				if(item.isFormField()){
					//得到普通文本提交的键
					String key = item.getFieldName();
					//得到普通文本提交的值,使用item.getString()的重载方法,解决中文乱码问题
					String value = item.getString("UTF-8");
					System.out.println(key+":"+value);
				}
				//处理文件上传段
				else{
					//获取上传的文件名
					//String name = item.getName();
					//System.out.println(name);
					InputStream is = item.getInputStream();
					//将文件保存到upload目录下(文件名称不能重复,不能存储在单一文件夹下)
					//生成uuid文件名称
					String uuid = UUID.randomUUID().toString();
					//使用日期进行分目录
					//得到upload目录所在的绝对路径
					String dirPath = getServletContext().getRealPath("/upload");
					//根据当前时间,得到时间路径
					Date date = new Date();
					SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
					String datePath = sdf.format(date);
					//检查当前时间目录结构是否存在,若是不存在则建立
					File file = new File(dirPath+datePath);
					if(!file.exists()){
						file.mkdirs();
					}
					//
					InputStream in = item.getInputStream();
					FileOutputStream out = new FileOutputStream(dirPath+datePath+uuid);
					IOUtils.copy(in, out);
					//释放资源,删除临时文件
					out.close();
					in.close();
					item.delete();
				}
			}
		}
	}

}

文件下载

1.文件下载方式

        1> 直接将待下载文件放到webRoot文件夹或子文件夹下.

        2>须要控制资源的下载.在下载前要通过逻辑处理.

  将资源放到用户不能直接访问的地方. 例如: WEB-INF  或  d:/upload

2.下载文件名称中文乱码问题

        response.setHeader("content-disposition", "attachment;filename="+ filename);

        这段代码中的filename是指定下载文件时的名称

        对于IE浏览器,它要求必须给一个UTF-8码

        对于firefox浏览器,它要求必须给一个base64编码

if (agent.contains("MSIE")) {
	// IE浏览器
	filename = URLEncoder.encode(filename, "utf-8");
	filename = filename.replace("+", " ");
} else if (agent.contains("Firefox")) {
	// 火狐浏览器
	BASE64Encoder base64Encoder = new BASE64Encoder();
	filename = "=?utf-8?B?"
	+ base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
	// 其它浏览器
	filename = URLEncoder.encode(filename, "utf-8");					
}

文件下载实例:

1.DownLoadServlet.java

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;

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;


public class DownloadServlet extends HttpServlet {

	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//1.得到请求的文件名
		String fileName = request.getParameter("name");
		fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");
		//2.设置content-type头|content-disposition头
		response.setContentType(getServletContext().getMimeType(fileName));
		response.setHeader("content-disposition","attachment;filename="+DownloadUtils.encode(fileName, request));
		//3.根据参数指定的文件,找到对应的文件资源流
		InputStream is = getServletContext().getResourceAsStream("/WEB-INF/"+fileName);
		//4.得到向浏览器输出的流
		ServletOutputStream os = response.getOutputStream();
		//5.将两个流对接
		IOUtils.copy(is, os);
		//6.关闭资源
		is.close();
		os.close();
	}
}

2.DownLoadUtils.java

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;


public class DownloadUtils {
	public static String encode(String fileName,HttpServletRequest request){
		//1.得到浏览器的类别
		String agent = request.getHeader("User-Agent");
		//2.判断浏览器类型
		if(agent.contains("Firefox")){
			//火狐浏览器=>按照base64进行编码
			BASE64Encoder base64Encoder = new BASE64Encoder();
			try {
				fileName = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes("utf-8")) + "?=";
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}else{
			//非火狐浏览器=>按照urlencoded编码方式编码
			 try {
				fileName = URLEncoder.encode(fileName,"UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		//3.返回编码后的结果
		return fileName;
	}
}

3.download.jsp

<body>
    <a href="/download/DownloadServlet?name=top.csv">下载top.csv文件</a><br/>
    <a href="/download/DownloadServlet?name=走遍中国.JPG">下载图片_走遍中国</a><br/>
    <a href="/download/DownloadServlet?name=原点.mp3">下载原点.mp3</a>
  </body>
相关文章
相关标签/搜索