最近在编写基于mvc架构的javaEE代码时,总是想着如何才能够实现对于文件的上传和下载,今天经过一天的努力,终于实现了文件的上传和下载,在这个地方呢也将自己的编写过程总结出来,希望能够对大家有所帮助,对于源代码我也会不断的改进,那个也会上传,希望能够对大家有所帮助
对于我们javaEE程序员来说,其实文件的上传和下载其实很多的大牛都已经编写好了实现的大部分希捷,那么我们只需用编写代码进行事先就可以了,所以我在这个地方也不懂太多深层次的原理,但是如果你是想着只要会用就可以了,那么希望对你有帮助。好了进入正题
一、文件上传原理分析
1、文件上传的前提:(记住)
a、表单的method必须是post
b、表单的enctype属性必须是multipart/form-data
c、表单中提供
2、form表单的enctype属性
该属性的作用是用来告知服务器,请求正文内容的MIME类型的。相当于请求消息头Content-Type。
1、apache的:commons-fileupload组件。
依赖:commons-io组件
下载地址:http://pan.baidu.com/s/1slUxaHn
2、开发主要的步骤
1:
编写文件上传时需要的上传Servlet类
package cn.edu.nwsuaf.utils;
import java.io.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
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;
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.FilenameUtils;
public class Upload extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//解决上传文件在存放目录中的乱码问题
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//检测form是否是multipart/form-data类型的
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if(!isMultipart){
throw new RuntimeException("The form's enctype attribute value must be multipart/form-data");
}
//解析请求内容
DiskFileItemFactory factory = new DiskFileItemFactory();//产生FileItem的工厂
//指定上传文件的临时文件存放目录,当上传文件的大小大于缓存区的大小就会产生临时存储区
factory.setRepository(new File("d:/"));//指定临时文件的存放目录
ServletFileUpload sfu = new ServletFileUpload(factory);
//如果这两条语句执行的话,那么上传的文件的大小就会受到限制
// 因为此处为了方便,所以没有进行大小的限制
// sfu.setFileSizeMax(3*1024*1024);//单个文件大小限制
// sfu.setSizeMax(5*1024*1024);//总文件大小
List<FileItem> items = new ArrayList<FileItem>();
try {
items = sfu.parseRequest(request);
}catch(FileUploadBase.FileSizeLimitExceededException e) {
response.getWriter().write("单个文件不能超过3M");
}
catch(FileUploadBase.SizeLimitExceededException e) {
response.getWriter().write("总文件不能超过5M");
}catch (FileUploadException e) {
e.printStackTrace();
throw new RuntimeException("解析请求失败");
}
//遍历:
//因为可能存在多个上传文件表单,所以对于每一个表单的内容要进行一一的处理
for(FileItem item:items){
//处理普通字段
if(item.isFormField()){
processFormField(item);
}else{
//处理上传字段
processUploadField(item);
}
}
request.getRequestDispatcher("/homework.jsp").forward(request, response);
}
protected void processUploadField(FileItem item) {
try {
// InputStream in = item.getInputStream();
//找一个存放文件的位置;存放的文件名
String fileName = item.getName();//上传的文件的文件名 C:\Users\wzhting\Desktop\a.txt a.txt(浏览器不同)
if(fileName!=null&&!fileName.equals("")){
//限定上传文件的类型,从他提供的方法中查看他是不是某一类型的文件
//这个函数如果开启的话,那么就只能上传是图片类型的数据
// if(!item.getContentType().startsWith("image")){
// return;
// }
fileName = FilenameUtils.getName(fileName);
fileName = IdGenertor.genGUID()+"_"+fileName;
//存放路径
String realPath = getServletContext().getRealPath("/WEB-INF/files");
System.out.println(realPath);
//生成一个子目录,也就是在realPath下面生成新的子目录,并且返回子目录
//这个地方是根据日期来生成目录
//如果是根据时间来上传东西的话,那么对于同一天上传的东西,都会在同一个目录下
//并且每次上传即使是相同的名字,也会产生不同的hashcode从而都能偶得到保存
String childDirectory = genChildDirectory(realPath,fileName);
//创造新的存放目录
File storeDirectory = new File(realPath+File.separator+childDirectory);
//如果目录不存在,那么就创建它
if(!storeDirectory.exists()){
storeDirectory.mkdirs();
}
// OutputStream out = new FileOutputStream(new File(storeDirectory, fileName));
//
// int len = -1;
// byte b[] = new byte[1024];
// while((len=in.read(b))!=-1){
// out.write(b, 0, len);
// }
// in.close();
// out.close();
//
// item.delete();//清除临时文件
//这个方法会自动的进行临时文件的清理,也就是上传完毕之后,他会自动的清除临时文件
item.write(new File(storeDirectory, fileName));
}
} catch (Exception e) {
e.printStackTrace();
}
}
//利用hashcode来生成文件的目录
private String genChildDirectory(String realPath, String fileName) {
int hashCode = fileName.hashCode();
int dir1 = hashCode&0xf;
int dir2 = (hashCode&0xf0)>>4;
String str = dir1+File.separator+dir2;
File file = new File(realPath,str);
if(!file.exists()){
file.mkdirs();
}
return str;
}
//按照日期生成子目录
private String genChildDirectory(String realPath) {
Date now = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String str = df.format(now);
File file = new File(realPath,str);
if(!file.exists()){
file.mkdirs();
}
return str;
}
protected void processFormField(FileItem item) {
//打印到控制台
String fieldName = item.getFieldName();
String fieldValue = "";
try {
//这里是为了解决表单提交的汉字在控制台输出乱码的问题,也就是得到表单里边的
//数据在控制台输出不会乱码
fieldValue = item.getString("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(fieldName+"="+fieldValue);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
2:进行servlet的配置,找到web.xml配置文件进行配置,配置代码如下
至于为什么这么配置我想大家都能偶理解,如果有不理解的话,可以给我留言,我会及时的回复
<servlet>
<servlet-name>Upload</servlet-name>
<servlet-class>cn.edu.nwsuaf.utils.Upload</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Upload</servlet-name>
<url-pattern>/Upload</url-pattern>
</servlet-mapping>
3:编写上传文件时的登录界面,当然这个地方就需要运用到表单了,表单的话,我想在学习javaEE之前大家都学过,这里呢只是给处jsp页面的核心部分,因为javaEE代码实在是太累赘,所以我只是给出关键的部分,方便理解
<body>
<form action="${pageContext.request.contextPath}/Upload" method="post" enctype="multipart/form-data">
<table border="1">
<tr><td>姓名:</td><td><input type="text" name="sname"></td></tr>
<tr><td>学号:</td><td><input type="text" name="sno"></td></tr>
<tr><td>文件选择</td><td><input type="file" name="photo"></td></tr>
<tr><td>文件选择</td><td><input type="file" name="photo"></td></tr>
<tr><td align="center" colspan="2"><input type="submit" value="文件上传"></td></tr>
<tr><td colspan="1">对上传的文件下载</td><td><a href="${pageContext.request.contextPath}/ShowAllFiles">下载</a></td></tr>
</table>
</form>
<h1 align="center"><a href="/index.jsp">返回管理员登陆界面</a></h1>
</body>
现实之后他的界面如图所示,因忙着业务逻辑的实现,所以界面可能不太好看,将就一下吧
注意:
<form action="${pageContext.request.contextPath}/Upload" method="post" enctype="multipart/form-data">注意上面页面的这两句话,第一个action=""里边的内容就是说他需要Upload这个servlet来进行处理
<tr><td colspan="1">对上传的文件下载</td><td><a href="${pageContext.request.contextPath}/ShowAllFiles">下载</a></td></tr>
href=“”里边的内容就是说他要交给ShowAllFiles这个servlet类来处理
4:编写文件下载时候需要的处理逻辑
4.1首先需要写一个生成可下载文件列表的处理逻辑
package cn.edu.nwsuaf.utils;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ShowAllFiles extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到所有可以下载的文件名字
String realPath = getServletContext().getRealPath("/WEB-INF/files");
//key:UUID文件名;value:老文件名
Map<String, String> map = new HashMap<String, String>();
File file = new File(realPath);
//进行递归的遍历
treeWalk(file,map);
request.setAttribute("map", map);
request.getRequestDispatcher("/listFiles.jsp").forward(request, response);
}
//递归遍历,得到最终的文件
private void treeWalk(File file, Map<String, String> map) {
if(file.isFile()){
//得到文件的全名,由于文件全名在上传的时候存在一个hashcode,所以还需要进行修剪
String guidFileName = file.getName();// LKSDJFLKDSKF_a.txt
String oldFileName = guidFileName.substring(guidFileName.indexOf("_")+1);// a.txt
map.put(guidFileName, oldFileName);
}else{
File files[] = file.listFiles();
for(File f:files){
treeWalk(f,map);
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
上面这个servlet主要用于产生服务器端都有哪些数据可以提供给我们下载,所以他只是一个产后数据的作用
进行文件的配置,代开web.xml进行如下的配置
<servlet>
<servlet-name>ShowAllFiles</servlet-name>
<servlet-class>cn.edu.nwsuaf.utils.ShowAllFiles</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ShowAllFiles</servlet-name>
<url-pattern>/ShowAllFiles</url-pattern>
</servlet-mapping>
4.2:编写显示可下载文件的显示页面,注意这里运用到了JSTL和EL表达式,所以需要配合上面的处理逻辑进行理解
<body>
<c:forEach items="${ map}" var="me">
<c:url value="/DownLoad" var="u">
<c:param name="filename" value="${me.key}"></c:param>
</c:url>
<!-- //将map里边的每一个元素遍历出来 -->
${me.value} <a href="${u}">下载</a><br/>
</c:forEach>
</body>
点击下载之后的页面
这个呢,是我刚刚上传的文件,所以这个地方才会有显示,如下图这个是我的webapps下面具体某个工程里边上传的文件
5:编写下载文件所需要的下载servlet,我这里他的名字叫做DownLoad
package cn.edu.nwsuaf.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DownLoad extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到文件名
String uuidFileName = request.getParameter("filename");
uuidFileName = new String(uuidFileName.getBytes("ISO-8859-1"),"UTF-8");
//存在哪里
String realPath = getServletContext().getRealPath("/WEB-INF/files");
String childDirectory = genChildDirectory(realPath,uuidFileName);
String fullPath = realPath+File.separator+childDirectory+File.separator+uuidFileName;
//告知客户端以下载的方式
String oldFilename = uuidFileName.substring(uuidFileName.indexOf("_")+1);
//也就是告诉用户一下载的方式去下载
response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(oldFilename, "UTF-8"));
InputStream in = new FileInputStream(fullPath);
OutputStream out = response.getOutputStream();
int len = -1;
byte b[] = new byte[1024];
while((len=in.read(b))!=-1){
out.write(b, 0, len);
}
in.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
private String genChildDirectory(String realPath, String fileName) {
int hashCode = fileName.hashCode();
int dir1 = hashCode&0xf;
int dir2 = (hashCode&0xf0)>>4;
String str = dir1+File.separator+dir2;
File file = new File(realPath,str);
if(!file.exists()){
file.mkdirs();
}
return str;
}
}
进行配置文件的编写
<servlet>
<servlet-name>DownLoad</servlet-name>
<servlet-class>cn.edu.nwsuaf.utils.DownLoad</servlet-class>
</servlet>
<servlet>
<servlet-name>DownLoad</servlet-name>
<servlet-class>cn.edu.nwsuaf.utils.DownLoad</servlet-class>
</servlet>
具体点击下载之后,效果如图所示
这杨一个简单文件上传下载案例就做好了,但是还是花费了不少的时间,因为这个东西如果只是这杨看的话,也可能不太清楚,我会把源代码上传,如果有需要,那么希望会对你有帮助
具体实现代码: http://pan.baidu.com/s/1dFfuBCX 提取码:v5bk