手把手教你如何玩转J2EE中的文件上传下载的细节

     描述:关于文件上传下载的问题,我其实已经写了几篇关于不同情况,该如何进行处理了,这篇文章主要是针对在J2EE中如何利用方便的技能进行完成该功能,并且对里面的很多细节知识,进行了很详细的说明,请多多注意注释内容。如果需要的话,可以阅读一下另外的几篇文章来进行更加深入的学习。

文章一:http://blog.csdn.net/Cs_hnu_scw/article/details/78755519

文章二:http://blog.csdn.net/Cs_hnu_scw/article/details/77929869

一:文件上传

知识点1:单个文件上传处理

方法一:通过Apache的相关包

开发步骤:

(1)导包:


(2)JSP页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>上传文件</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/uploadservlet" method="post" enctype="multipart/form-data">
文件描述:<input type="text" name="description">
<input type="file" name="uploadfile">
<input type="submit" value="上传">
</form>

</body>
</html>

(3)servlet代码

package com.hnu.scw.upload.demo1;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.UUID;
import javax.naming.SizeLimitExceededException;
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.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import sun.security.jca.GetInstance.Instance;

/**
 * 进行文件上传的demo1
 * @author scw
 *
 */
public class UploadFileDemo1 extends HttpServlet {

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

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//解决文件乱码问题
		request.setCharacterEncoding("utf-8");
		
		//1:创建文件上传的工厂类实例对象
		DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
		
		//为了提高对于大文件上传的效率,这里就添加一个临时目录,放在WEB-INF下的tmp,当然放在WEB-INF目前外面也可以
		diskFileItemFactory.setRepository(new File("WEB-INF/tmp"));
		diskFileItemFactory.setSizeThreshold(1024*1024*3);
		
		
		//2:创建文件上传的servletFileUpload实例对象
		ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
		//解析request对象的内容
		try {
			//设置文件上传的大小限制
			servletFileUpload.setFileSizeMax(1024*1024*3); //单个文件不能超过3M
			servletFileUpload.setSizeMax(1024*1024*10); //总的上传文件大小不能超过10M
			
			//进行模拟进度条功能服务器端的实现
			//(1)获取上传的时间
			long startTime = System.currentTimeMillis();
			//(2)实现进度条监听器
			servletFileUpload.setProgressListener(new ProgressListener() {
				/**
				 * 第一个参数:已经上传的大小
				 * 第二个参数:总的大小
				 * 第三个参数:上传标签中文件是第几个顺序,这个没什么作用
				 */
				@Override
				public void update(long alreadloadsize, long totalsize, int formnumber) {
					//获取当前的时间
					long currentTime = System.currentTimeMillis();
					//计算已经花费的时间
					long useTime = currentTime - startTime;
					//计算上传的速度
					long speed  = alreadloadsize / useTime ;
					//计算还剩于未上传的大小
					long unloadsize = totalsize - alreadloadsize;
					//计算还需要上传的时间
					long nextTime = unloadsize / speed  ;
					System.out.println("已经花费时间:" + useTime);
					System.out.println("上传速度:" + speed );
					System.out.println("剩余大小:" + unloadsize);
					System.out.println("剩余时间:" + nextTime);				
				}
			});
			
			
			List<FileItem> parseRequest = servletFileUpload.parseRequest(request);
			//4:遍历内容
			for (FileItem fileItem : parseRequest) {
				//如果是true,则表示获取的当前内容数据是非上传文件内容,返回false就是上传文件的内容
				if(fileItem.isFormField()){
					//获取到JSP对应标签的name属性内容
					String fieldName = fileItem.getFieldName();
					//获取JSP对应标签value的内容,并且解决中文乱码问题
					String value = fileItem.getString("utf-8");
					System.out.println(fieldName + "@" + value);
				}else{
					//获取到上传文件中,上传文件的名字
					String name = fileItem.getName();
					//为了解决一些浏览器(比如IE6)上传文件的时候,上传文件名是整个路径,比如C:\\upload\file\aa.txt所以要特别处理一下,
					//但是一般目前不存在这个问题了,主要针对一些老浏览器
					int index = name.lastIndexOf("\\");
					//如果匹配到的索引大于等于0,就表示需要进行截取,因为匹配不到的话是返回-1
					if(index >= 0){
						name = name.substring(index+1 , name.length());
					}
					//为了防止,如果上传的文件名字一样,那么就会把之前的进行替换,所以这里也要特别处理一下(当然用时间戳也行)
					name = UUID.randomUUID().toString() + name;
					//获取到上传文件的字节流内容
					InputStream inputStream = fileItem.getInputStream();
					//获取存放上传内容的路径
					//上传路径如果是想放在web-inf目录外就下面的形式
					String realPath = getServletContext().getRealPath("/demo1path");
					//如果想放在web-inf目录内部的话,就下面的形式,建议这样的方式,因为这样的话就不能直接从浏览器访问这个目录下面的内容,更加安全
					//String realPath = getServletContext().getRealPath("WEB-INF/demo1path");
					//创建出文件路径,防止目录不存在的时候出现异常问题
					if(!new File(realPath).exists()){
						new File(realPath).mkdirs();
					}
					//创建输出流,这里用缓冲输出流,能够提高上传的效率
					OutputStream os =new BufferedOutputStream( new FileOutputStream(new File(realPath , name)));				
					//进行上传处理,用到commons.io.jar包里面的一个方法,相对比一般的处理方便点
					IOUtils.copy(inputStream, os);
					
					//将临时目录中的内容进行删除,这也是由于之前为了提高上传效率而添加的临时目录
					fileItem.delete();
					//关闭资源
					inputStream.close();
					os.close();
				}
			}
			
		} catch (Exception e) {
			//抓取单个文件上传大小超过限制
			if(e instanceof FileSizeLimitExceededException){
				System.out.println("单个文件太大啦~~~~~~~~~~~");
			}
			//抓取上传多个文件上传大小超过限制
			if(e instanceof SizeLimitExceededException){
				System.out.println("总的上传文件太大啦~~~~~~~~~~~");
			}
			e.printStackTrace();
		}
		
		
	}

}

(4)项目目录


知识点2:多个文件上传处理

JSP页面:(后台处理和上面的单个上传的是一样的,只是必须保证<input >属性的name必须一致)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>动态多文件上传</title>
</head>
<script type="text/javascript">
	//添加文件上传的框个数
	function addFileItem() {
		document.getElementById("filediv").innerHTML +="<div><input type='file' name='uploadfile'><input type='button' onclick='deleteFileItem(this)' value='删除'></div>"
	}
	//删除文件上传的框个数
	function deleteFileItem(currentbtn){
		var divbtn = currentbtn.parentNode;
		divbtn.parentNode.removeChild(divbtn);
	}
</script>
<body>
<form action="${pageContext.request.contextPath}/uploadservlet" method="post" enctype="multipart/form-data">
	<input type="button" id ="addfile" onclick="addFileItem()" value="添加上传文件">
	<div id="filediv">
	</div>
	<input type="submit" value="上传">
</form>
</body>
</html>

方法二:通过servlet自带的方法

JSP代码:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>文件上传页面</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->

  </head>
  
  <body>
    <form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
    	<input type="text" name="filetext"><br>
    	<input type="file" name="upload"><br>
    	<input type="submit" value="上传">
    </form>
  </body>
</html>

servlet代码:(通过注解来完成了配置)
package com.hnu.scw.upload.demo3;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet(urlPatterns={"/upload"})
@MultipartConfig(
	fileSizeThreshold=1024*1024*3,	// 设置缓存大小
	maxFileSize=1024*1024*3,		// 设置上传单个文件大小
	maxRequestSize=1024*1024*10	// 设置上传总大小
)
public class UploadFileDemo3 extends HttpServlet{
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doPost(request, response);
	}

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

		// 如何来处理文件的上传逻辑:Part接口
		request.setCharacterEncoding("utf-8");
		
		/*
		 * 1 如何获取文件上传的普通项?
		 *  * 通过Request对象的getParameter(String name)方法,可以或上传的普通项.
		 *    * name参数:指定客户端页面上传普通项的name属性值.
		 */
		String filetext = request.getParameter("filetext");
		
		/*
		 * 2 如何获取Part接口的实例对象?
		 *  * 通过Request对象的getPart(String name)方法,可以获取Part接口的实例对象.
		 *    * name参数:指定客户端页面上传文件域的name属性值.
		 *  * 通过Part接口的实例对象获取有关文件上传项的名称、文件输入流.
		 *  * Part接口提供的write(filename)方法:
		 *    * 将接收到的文件输入流,写入指定的服务器端的目录中.
		 *    * 参数filename:指定的保存文件的绝对路径.
		 *  * Part接口提供getName()方法:
		 *    * 获取的是上传文件域的name属性值.
		 *    * 并没有获取真实上传的文件名称.
		 *  * 上传的真实文件名称应该是如何获取到的呢?
		 *    * Servlet 3.0完成文件上传功能的诟病.
		 *    * 
		 */
		Part part = request.getPart("upload");
		/*String filename = part.getName();
		System.out.println(filename);*/
		
		/*
		 *  获取上传的真实文件名称:
		 *  Content-Disposition: form-data; name="upload"; filename="readme.txt"
		 */
		String header = part.getHeader("Content-Disposition");
		int index = header.lastIndexOf("filename=\"");
		String filename = header.substring(index+10, header.length()-1);
		
		InputStream in = part.getInputStream();
		String realPath = getServletContext().getRealPath("/uploads");
		part.write(realPath+"/"+filename);
	}
}

二:文件下载

步骤:

(1)JSP(模拟需要下载的文件列表)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件下载处理</title>
</head>
<body>
<h1>下载内容列表如下所示:</h1>
<a href="${pageContext.request.contextPath}/downfile?filename=1.et">下载1.et</a>
<a href="${pageContext.request.contextPath}/downfile?filename=2.txt">下载2.txt</a>
</body>
</html>

(2)servlet代码

package com.hnu.scw.filedown.demo2;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
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.catalina.util.Base64;
import org.apache.commons.io.IOUtils;

import sun.misc.BASE64Encoder;
/**
 * 处理文件下载
 * @author scw
 *
 */
public class FileDownDemo extends HttpServlet {

	/**
	 * 因为在JSP这里是直接用a标签过来的,所以就在Get方法里面进行请求处理
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//1: 获取要下载的文件的名字
		String fileName = request.getParameter("filename");
		//为防止中文乱码造成的问题,所以要进行处理
		fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");
		//2:然后根据文件名,去数据库找对应存储的位置(这里就不进行数据库操作,就模拟一下)
		String downPath = "";
		//假如要下载的文件名是2.txt,那么就去路径tomcat下对应工程的中路径找,我这里是放在downfilepath文件目录:找
		if("2.txt".equals(fileName)){
			downPath = "D:\\apache-tomcat-7.0.70\\webapps\\UploadFileServletProject\\downfilepath\\2.txt";
		}
		//假如要下载的文件名是1.et,那么就去路径:找
		else if("1.et".equals(fileName)){
			downPath = "D:\\apache-tomcat-7.0.70\\webapps\\UploadFileServletProject\\downfilepath\\1.et";
		}
		//-----------上面的路径实际开发中应该去去数据库进行寻找,上面只是模拟而已-----------------
		//3:获取输入流
		FileInputStream io = new FileInputStream(new File(downPath));
		
		//-----下面是解决当下载的文件名中有中文的时候,显示的时候如果不处理,会中文内容显示不出来--------
		    //主要是对IE和其他浏览器进行分别处理
		String header = request.getHeader("User-Agent");
		if(header.contains("MSIE")){
			//表示是IE浏览器
			fileName = URLEncoder.encode(fileName);
			fileName = fileName.replace("+", " ");
		}else{
			//是其他类型的浏览器
			 BASE64Encoder base64Encoder = new BASE64Encoder();
			 //这是固定的处理方式
			 fileName = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes("utf-8")) + "?=";
		}
		//-------处理结束-----------------------
		
		//4:设置告诉浏览器要以文件下载的方式进行下载(如果不指定的话,那么浏览器不会以下载的方式进行,所以就存在问题)
		response.setContentType(getServletContext().getMimeType(fileName));
		response.setHeader("Content-Disposition", "attachment;filename="+fileName);
		//5:获取输入流
		OutputStream os = response.getOutputStream();
		//6:进行下载处理
		IOUtils.copy(io, os);
		//7:关闭资源
		io.close();
		os.close();
		
	}

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

}
整合文件上传和下载的项目结构如下所示:


   慢慢的一步步分析下来的话,其实对于文件处理,并不是很复制,流程逻辑还是很清晰的,另外的话,对于不同其他情况的处理,欢迎查看其他上述提到的文章哦~!~!

猜你喜欢

转载自blog.csdn.net/cs_hnu_scw/article/details/79253763