还是先一张图,来的更直接点
看到这个图也就明白我要写些什么了,没错使用commons-fileupload实现上传。
完成的主要需求是:
1、实现页面无刷新的上传(还是通过iframe实现),上传进度的监控。
2、采用fileupload组件比使用smartupload会更加减少服务器负载。
3、服务器端只返回响应的状态码,view进行响应的操作,更好的解耦。
4、简单的使用了jqueryui,实现一个简单的交互界面。
5、实现下载。
ok,废话不多说,进入正题看一下demo目录结构
一、核心类FileUploadTools.java用来解析request中的参数,并进行文件的上传保存。贴出代码。
package com.akwolf.upload; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.fileupload.FileItem; 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; /** * @author zhanghua * */ public class FileUploadTools { private HttpServletRequest request; private List<FileItem> items; // 全部上传内容 private Map<String, List<String>> params = new HashMap<String, List<String>>(); // 保存�?��参数 private Map<String, FileItem> files = new HashMap<String, FileItem>(); private int maxSize = 30 * 1024 * 1024; // 默认�?��文件体积 private String fileName = new Date().toString(); private String[] allowedExts; private ServletFileUpload upload ; /** * FileUploadTools tool = null ; try{ tool = new * FileUploadTools(request,1,this * .getServletContext().getRealPath("/")+"temp") ; * }catch(FileUploadException e){ if(e instanceof * SizeLimitExceededException){ out.print("上传文件过大�?) ; return ; } * * } * * @param request * 包含上传的request * @param maxSize * 最大上传体积 * @param tempDir * 临时上传文件夹 * @throws FileUploadException * @throws UnsupportedEncodingException * 不支持上传的后缀名异常 */ @SuppressWarnings("unchecked") public FileUploadTools(final HttpServletRequest request, int maxSize, String tempDir,boolean progress) throws FileUploadException, UnsupportedEncodingException { this.request = request; // 创建磁盘工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); // 创建临时上传文件夹 if (tempDir != null) { File tempFile = new File(tempDir); if (!tempFile.exists()) { tempFile.mkdir(); } factory.setRepository(tempFile); } // buffer factory.setSizeThreshold(4096); upload = new ServletFileUpload(factory); if(progress){ this.registProgressListener(request) ; } if (maxSize > 0) { this.maxSize = maxSize; } // 设置最大上传体积 upload.setSizeMax(this.maxSize); try { // 解析上传request this.items = upload.parseRequest(this.request); } catch (FileUploadException e) { throw e; } this.init(this.fileName); } /** * 解析请求,将表单输入域与文件域分开并存储在map中 * * @param fileName * @throws UnsupportedEncodingException */ private void init(String fileName) throws UnsupportedEncodingException { Iterator<FileItem> iter = this.items.iterator(); // 迭代每一个表单请求项 while (iter.hasNext()) { FileItem item = iter.next(); // 是否为表单域 if (item.isFormField()) { // 取得输入项的名称 String name = item.getFieldName();// 取得表单域的名称name="xxx" // 对应的值 String value = new String(item.getString().getBytes("ISO-8859-1"), "UTF-8"); // 存储所有表单项值 List<String> temp = null; if (this.params.containsKey(name)) { // 已存在就直接取值 temp = this.params.get(name); } else { // 不存在就创建数组 temp = new ArrayList<String>(); } temp.add(value); // 放入表单域中形式是 name-------value this.params.put(name, temp); } else { // 不是表单输入框,则可能是文件上传项 String str = item.getName(); String finalName = str.substring(str.lastIndexOf(File.separator) + 1); // 取出文件上传项存储起来 name ----file this.files.put(finalName, item); } } } /** * 取得单�?的表单域,如:type="text" * * @param name * @return */ public String getParameter(String name) { String ret = null; List<String> list = this.params.get(name); if (list != null) { ret = list.get(0); } return ret; } /** * 取得多�?的表单域,如:type="checkbox" * * @param name * @return */ public String[] getParameterValues(String name) { String[] ret = null; List<String> list = this.params.get(name); if (list != null) { ret = list.toArray(new String[] {}); } return ret; } /** * 取得上传文件 * * @return */ public Map<String, FileItem> getUploadFiles() { return this.files; } /** * 指定存储路径和储存名�? 储存名不用带后缀�? * * @param saveDir * 指定存储路径 * @param saveName * 指定存储文件的名称 * @return * @throws Exception */ public List<UploadMsg> saveFile(String saveDir, String[] saveName) throws UnAllowedExtException { //System.out.println(saveDir+"--->"+saveName); List<UploadMsg> msgs = new ArrayList<UploadMsg>(); long size = 0; // 存储随机生成的名称 // List<String> names = new ArrayList<String>(); // 创建存储目录 File saveDiretory = new File(saveDir); if (!saveDiretory.exists()) { saveDiretory.mkdir(); } // 如果有输入文件表单项 if (this.files.size() > 0) { // 指定的文件名称与文件数目不相等 if (files.size() != saveName.length) { throw new IllegalArgumentException("the saveName length is not match the file size!!"); } // 上传文件后缀名 String ext; // 取得文件表单项的名称 Set<String> keys = this.files.keySet(); // 迭代取出每个文件内容 Iterator<String> iter = keys.iterator(); // 用来创建进行存储的文件 File saveFile = null; // 简单计数器,记录自己指定的名称 int i = 0; boolean flag = true; while (iter.hasNext()) { String fileName = iter.next(); // 后缀名的判断 ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); // 不区分大小写 for (int j = 0; j < allowedExts.length; j++) { if (ext.equals(allowedExts[j])) { flag = false; break; } } if (flag) { try { throw new UnAllowedExtException("不允许上传的文件"); } catch (UnAllowedExtException e) { throw e; } } FileItem item = this.files.get(fileName); // 得到文件大小 size = item.getSize(); // 拼装出用户指定的文件名 String saveFileName = saveName[i] + fileName.substring(fileName.lastIndexOf(".")); // 添加到返回列表中 //names.add(saveFileName); msgs.add(new UploadMsg(saveFileName, size)) ; saveFile = new File(saveDir + saveFileName); // 写入磁盘 InputStream input; FileOutputStream fos; try { input = item.getInputStream(); fos = new FileOutputStream(saveFile); byte[] b = new byte[512]; while (input.read(b) != -1) { fos.write(b); } fos.close(); input.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // item.write(saveFile) ; // 删除临时文件 item.delete(); i++; } } return msgs; } public List<UploadMsg> saveFileRandomName(String saveDir) throws UnAllowedExtException { return this.saveFile(saveDir, new String[] { randomName() }); } /** * * 设置可上传的后缀名 * @param exts */ public void setAllowedExts(String[] exts) { this.allowedExts = exts; } /** * 注册进度监听器 */ public void registProgressListener(final HttpServletRequest request){ upload.setProgressListener(new ProgressListener() { @Override public void update(long bytesRead, long contentLength, int items) { long percent = Math.round((double) bytesRead / contentLength * 100); request.getSession().setAttribute("percent", percent); } }); } private String randomName() { SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); return sdf.format(new Date()) + getRandom(); } /** * 产生随机命名 * * @return */ private String getRandom() { StringBuffer buffer = new StringBuffer(); Random ran = new Random(); for (int i = 0; i < 3; i++) { buffer.append(ran.nextInt(10)); } return buffer.toString(); } }二、UploadMsg.java封装上传后回传的信息类,里面的属性可以根据需要自行添加 package com.akwolf.upload; /** * @Title: UploadMsg.java * @author zhanghua * @date 2011-10-16 下午12:20:58 * @version V1.0 * @Description: 保存上传后文件的信息的类 */ public class UploadMsg { private String name; //单位 B private long size; public UploadMsg() { } public UploadMsg(String name, long size) { this.name = name; this.size = size; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getSize() { return size; } public void setSize(long size) { this.size = size; } @Override public String toString() { return "UploadMsg [name=" + name + ", size=" + size + "]"; } }
三、UnAllowedExtException.java自定义一个异常,用于对不支持后缀名的异常捕获,在前台进行显示。
四、建立一个进行业务处理的servlet(UploadServlet.java)
package com.akwolf.servlet; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Iterator; import java.util.List; 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.fileupload.FileUploadBase.SizeLimitExceededException; import org.apache.commons.fileupload.FileUploadException; import com.akwolf.upload.FileUploadTools; import com.akwolf.upload.UnAllowedExtException; import com.akwolf.upload.UploadMsg; /** * @author zhanghua * */ public class UploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request.getParameter("action"); if ("upload".equals(action)) { doUpload(request, response); } else if ("download".equals(action)) { doDownload(request, response); }else if("progress".equals(action)){ doProgress(request, response); } } /** * 取得上传进度 * * @param request * @param response * @throws IOException */ private void doProgress(HttpServletRequest request, HttpServletResponse response) throws IOException { long percent = 0 ; if(request.getSession().getAttribute("percent")!=null) { percent = (Long)request.getSession().getAttribute("percent") ; } StringBuilder builder = new StringBuilder(); builder.append("<percent>").append(percent).append("</percent>") ; response.setContentType("text/xml") ; response.getWriter().write(builder.toString()) ; } /** * @param request * @param response * @throws IOException */ private void doUpload(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/html"); FileUploadTools fut = null; // 闲着上传文件后缀名 String[] exts = { "gif", "jpg", "png", "bmp","doc","docx","zip" }; List<UploadMsg> list = new ArrayList<UploadMsg>(); //String at = request.getParameter("articleId"); // warning在进行request解析之前要进行乱码的处理 request.setCharacterEncoding("UTF-8"); StringBuilder builder = new StringBuilder() ; builder.append("<msg>") ; try { fut = new FileUploadTools(request, 300 * 1024 * 1024, this.getServletContext().getRealPath("/") + "temp",true); //fut.registProgressListener(request.getSession()) ; fut.setAllowedExts(exts); list = fut.saveFileRandomName(this.getServletContext().getRealPath("/") + "uploadfile" + java.io.File.separator); UploadMsg uploadMsg = list.get(0); System.out.println(uploadMsg); // 遍历返回上传文件的重命名 Iterator iters = list.iterator(); builder.append("ok").append("</msg>") ; } catch (UnsupportedEncodingException e) { //e.printStackTrace(); builder.append("unSupportedEncoding").append("</msg>") ; } catch (FileUploadException e) { if(e instanceof SizeLimitExceededException){ builder.append("unSizeLimit").append("</msg>") ; } //e.printStackTrace(); } catch (UnAllowedExtException e) { builder.append("unAllowedExt").append("</msg>") ; //e.printStackTrace() ; //不支持的文件后缀名 //response.getWriter().write( // "<script type=\"text/javascript\"> parent.document.alert('只允许上传jpg,gif,png,bmp格式的图片');</script>"); } response.getWriter().write(builder.toString()) ; } /** * @param request * @param response * @throws IOException */ private void doDownload(HttpServletRequest request, HttpServletResponse response) throws IOException { // 取得下载文件的名称 String name = request.getParameter("fileName"); // name = "20111013165257234281.png"; // web绝对路径 String path = request.getSession().getServletContext().getRealPath("/"); String savePath = path + File.separator + "uploadfile"; // 设置为下载application/x-download response.setContentType("application/x-download"); // 即将下载的文件在服务器上的绝对路径 String filenamedownload = savePath + File.separator + name; // 下载文件时显示的文件保存名称 String filenamedisplay = name; // 中文编码转换 filenamedisplay = URLEncoder.encode(filenamedisplay, "UTF-8"); response.addHeader("Content-Disposition", "attachment;filename=" + filenamedisplay); java.io.OutputStream os = response.getOutputStream(); java.io.FileInputStream fis = new java.io.FileInputStream(filenamedownload); ServletOutputStream out = response.getOutputStream(); try { byte[] b = new byte[1024]; int i = 0; while ((i = fis.read(b)) > 0) { os.write(b, 0, i); } } catch (Exception e) { out.print("<script language=javascript>window.alert('file not found');history.back();</script>"); } finally { out.close(); fis.close(); os.flush(); os.close(); } } }ok,到这里整个下载和上传功能基本实现。剩下简单的内容就打包好给大家下载了(代码贴的太多了),好了洗洗睡觉了。
http://download.csdn.net/detail/akwolf/3839604