文件上传与下载
一、文件上传
文件上传即将本地文件(图片、文本文件、压缩文件等)上传到服务器,并将文件在服务器的地址保存到数据库表中。
文件上传常用第三方插件实现,常见的有:
SmartUpload、Commons-fileupload等。
1. SmartUpload
SmartUpload用于实现文件上传及下载的免费组件(第三方上传插件)。
优点 | 缺点 |
使用简单,编写代码少; 能控制上传内容及文件大小、类型 | 目前已停止更新,并且使用SmartUpload上传过大文件或多文件时,可能出现CPU或内存占用过高的问题,只有重新启动服务器才能恢复正常 |
具体实现:
1.1 导包
在项目WEB-INF\lib中导入SmartUpload插件所需要的jar包:jspsmartupload.jar。
1.2 表单设置
在前端页面form表单中设置文件上传属性:
<form action="/upload.jsp" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="uploadFile" /> <input type="submit" value="上传" /> </form> |
注意:
l form表单的method属性值必须是post,因为文件大小会超过255个字符。
l enctype属性表示发送到服务器之前应该如何对表单数据进行编码,multipart/form-data表示不对字符编码,将按照二进制的方式提交。
1.3 编写上传代码
在使用SmartUpload插件做提交时必须严格按照如下程序进行:
// 实例化SmartUpload上传组件 SmartUpload smart = new SmartUpload(); // 初始化上传操作 smart.initialize(pageContext); //上下文 // 上传准备 smart.upload(); // 将上传文件保存在upload文件夹中 smart.saveAs("upload"); |
限制文件的上传类型:
// 允许上传类型 smart.setAllowedFilesList("gif,jpg,png,doc,rar"); // 不允许上传类型 smart.setDeniedFilesList("jsp,asp,php,aspx"); |
限制文件上传的大小:
smart.setMaxFileSize(2*1024*1024); |
设置字符编码:(如果未设,当请求中含有中文时会报:java.lang.NullPointerException: charsetName)
smart.setCharset("utf-8"); |
获得第一个上传文件的文件名:
String file = smart.getFiles().getFile(0).getFileName(); |
获得第一个上传文件的后缀名:
String ext = smart.getFiles().getFile(0).getFileExt(); |
拼凑文件名:
String fileName = file+"."+ext; |
由于此时要用新的文件名称保存上传文件,所以要通过smart.getFiles().getFile(0).saveAs()方法进行手工保存。具体代码:
// file.saveAs(路径 , 上传方式) smart.getFiles().getFile(0).saveAs(getServletContext().getRealPath("/")+"upload"+java.io.File.separator+fileName); |
源代码:
<%@ page language="java" import="java.util.*,java.sql.*,com.jspsmart.upload.*" pageEncoding="gbk"%> <%@page import="java.text.SimpleDateFormat"%> <% SmartUpload su = new SmartUpload(); su.initialize(pageContext);
com.jspsmart.upload.File file = null; com.jspsmart.upload.Request req = null;
try { // 定义允许上传文件类型 su.setAllowedFilesList("gif,jpg,png"); // 不允许上传文件类型 // su.setDeniedFilesList(“jsp,asp,php,aspx,html,htm,exe,bat”); // 单个文件最大限制 su.setMaxFileSize(2*1024*1024); // 设置上传编码 su.setCharset("UTF-8"); // 执行上传 su.upload();
// 获得单个上传文件的信息 file = su.getFiles().getFile(0); // 声明文件路径 String filepath = null; // 用户是否选择了文件 if(!file.isMissing()){ // 设置文件在服务器的保存位置 filepath = "upload\\"; // 拼接上文件名 filepath += file.getFileName(); // 设置文件流编码 file.setCharset("utf-8"); // 文件流按保存模式保存到filepath路径下 file.saveAs(filepath, SmartUpload.SAVE_VIRTUAL); } } catch (Exception e) { e.printStackTrace(); } %> |
1.4 混合表单
当表单使用enctype封装后,其他的非文件类的表单控件的内容就无法通过JSP的Request内置对象取得,此时必须通过SmartUpload类中提供的getRequest()方法获取表单的请求数据,例如:
String uname = smart.getRequest().getParameter("uname"); |
注意:该句代码一定要在执行完upload()方法之后才可以使用
1.5 为上传文件自动命名
如果多个用户上传的文件名称一样,则肯定会发生覆盖的情况,为了避免这类问题产生,可以采用为上传文件自动命名的方式。主要方式有:
l 时间戳
SimpleDateFormat date = new SimpleDateFormat("yyyyMMddHHmmssSSS"); String filename = date.format(new Date()) + file.getFileExt(); |
l IP地址 + 时间戳 + 三位随机数
// 封装方法 public String getIPTimeRand(){ // 实例化StringBuffer对象,用来做文件名拼接 StringBuffer buf=new StringBuffer();
// 获得本机的IP地址 InetAddress addr = InetAddress.getLocalHost(); ip=addr.getHostAddress().toString();//获得本机IP address=addr.getHostName().toString();//获得本机名称
// 获得当前时间戳 SimpleDateFormat date=new SimpleDateFormat("yyyyMMddHHmmssSSS"); date.format(new Date());
// 获得一个3位数的随机数 Random r=new Random(); for(int i=0; i<3; i){ buf.append(r.nextInt(10)); } return buf; } |
1.6 批量上传
如要完成批量上传,则肯定需要循环的方式进行,那么就必须通过如下方法取得上传文件数量。
Form表单代码:
<form action="smartupload.jsp" method="post" enctype="multipart/form-data"> 文件1:<input type="file" name="pic1"><br/> 文件2:<input type="file" name="pic2"><br/> 文件3:<input type="file" name="pic3"><br/> <input type="submit" value="上传" > <input type="reset" value="重置"> </form> |
SmartUpload.jsp代码:
<% …… SmartUpload smart=new SmartUpload(); smart.initialize(pageContext); smart.upload(); for(int i=0; i<smart.getFiles().getCount(); i++){ smart.save("upload"); } …… %> |
1.7 在Servlet中写SmartUpload的问题
在Servlet中使用SmartUpload时会出现pageContext上下文报错,解决办法如下:
方式一:
SmartUpload smart=new SmartUpload(); smart.initialize(this.getServletConfig(), request, response); |
方式二:
使用了JspFactory.getDefaultFactory()方法。
SmartUpload smart=new SmartUpload(); PageContext context = JspFactory.getDefaultFactory().getPageContext(this, request, response, null, true, 8*1024, true); // 或者 // PageContext context = JspFactory.getDefaultFactory().getPageContext(this, request, response, null, true, JspWriter.DEFAULT_BUFFER, true); smart.initialize(context); |
参数说明:
第一个参数是传递一个Servlet,在servlet中传递this就可以了;
第二个和第三个参数是request与response不多说明了;
第四个参数是发生错误后的url路径地址,如果没有可以键入null;
第五个参数是是否需要session,这里可以写入true;
第六个参数是缓存大小,我用了8*1024,也可以用JspWriter.DEFAULT_BUFFER;
第七个参数是是否需要刷新,键入ture;
<要注意抛异常>
1.8 设置表单上传文件类型
accept="image/gif, image/jpeg"指定允许上传的只有gif和jpg文件。
<form action="/upload.jsp" method=”post” accept="image/gif, image/jpeg"> <p>First name: <input type="text" name="fname" /></p> <p>Last name: <input type="text" name="lname" /></p> <p>Your image: <input type="file" name="pic" id="pic" /></p> <input type="submit" value="Submit" /> </form> |
2. Commons-FileUpload
文件上传下载一般使用commons-fileupload实现上传功能,因为commons-fileupload依赖于commons-io这个包,所以需要下载这两个包commons-fileupload-1.2.1.jar和commons-io-1.3.2.jar。
2.1 导包
将相关jar包添加到项目的WEB-INF/lib目录下:
commons-fileupload-1.2.1.jar
commons-io-1.3.2.jar
2.2 表单设置
<form action="/fileupload" method="post" enctype="multipart/form-data" name="form1"> <input type="file" name="myFile"> <input type="submit" value="确定"> </form> |
2.3 文件上传后台关键代码
虚拟路径的转换
application.getRealPath(path);
// 临时文件缓存目录设置以及文件上传时的缓存大小设置
DiskFileItemFactory
setRepository
setSizeThreshold
注:文件缓存目录(temp)及文件上传目录(uploads)必须提前建好
// 上传文件大小设置及请求处理
ServletFileUpload
setFileSizeMax
parseRequest(request);
// 表单数据获取和类型判断
无法通过request对象获得,只能通过FileItem获得
表单数据分为:普通元素(如:文件框、密码框)和文件
FileItem.isFormField
// 获得上传文件的文件名,根据文件名对上传文件类型进行限制
String fileName = FileItem.getName();
String regex = "^.+\\.(jpg|gif|txt|doc)$";
Pattern pattern = Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(fileName);
boolean b = matcher.matches();
// IO流保存文件
UUID生成32位长唯一字符串,保存时无需考虑文件名及类型
UUID.randomUUID();
保存文件后记得删除临时文件(重要)
FileItem.delete();
2.4 案例:上传代码
public class UploadServlet extends HttpServlet { private static final long serialVersionUID = 1L;
// 上传文件存储目录 private static final String UPLOAD_DIRECTORY = "upload";
// 上传配置 private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3; // 3MB private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB
/** * 上传数据及保存文件 */ protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { // 检测是否为多媒体上传 if (!ServletFileUpload.isMultipartContent(request)) { // 如果不是则停止 PrintWriter writer = response.getWriter(); writer.println("Error: 表单必须包含 enctype=multipart/form-data"); writer.flush(); return; }
// 配置上传参数 DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中 factory.setSizeThreshold(MEMORY_THRESHOLD); // 设置临时存储目录 factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大文件上传值 upload.setFileSizeMax(MAX_FILE_SIZE);
// 设置最大请求值 (包含文件和表单数据) upload.setSizeMax(MAX_REQUEST_SIZE);
// 编码处理 upload.setHeaderEncoding("UTF-8");
// 构造临时路径来存储上传的文件 // 这个路径相对当前应用的目录 String uploadPath = request.getServletContext().getRealPath("./") + File.separator + UPLOAD_DIRECTORY;
// 如果目录不存在则创建 File uploadDir = new File(uploadPath); if (!uploadDir.exists()) { uploadDir.mkdir(); }
try { // 解析请求的内容提取文件数据 @SuppressWarnings("unchecked") List<FileItem> formItems = upload.parseRequest(request);
if (formItems != null && formItems.size() > 0) { // 迭代表单数据 for (FileItem item : formItems) { // 处理不在表单中的字段 if (!item.isFormField()) { String fileName = new File(item.getName()).getName(); String filePath = uploadPath + File.separator + fileName; File storeFile = new File(filePath); // 在控制台输出文件的上传路径 System.out.println(filePath); // 保存文件到硬盘 item.write(storeFile); request.setAttribute("message", "文件上传成功!"); } } } } catch (Exception ex) { request.setAttribute("message", "错误信息: " + ex.getMessage()); } // 跳转到 message.jsp request.getServletContext().getRequestDispatcher("/message.jsp").forward(request, response); } } |
message.jsp 文件代码如下:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>文件上传结果</title> </head> <body> <center> <h2>${message}</h2> </center> </body> </html> |
3. 百度上传插件
http://www.jq22.com/yanshi5302
二、文件下载
1. 使用Commons-FileUpload实现下载
导入commons-fileupload-1.2.1.jar和commons-io-1.3.2.jar。
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> </head>
<body> <a href="/download/DownloadServlet?filename=1.jpg">文件下载</a> </body> </html> |
Servlet源代码:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8"); //设置ContentType字段值 response.setContentType("text/html;charset=utf-8"); //获取所要下载的文件名称 String filename = request.getParameter("filename"); //下载文件所在目录 String folder = "/filename/"; //通知浏览器以下载的方式打开 response.addHeader("Content-type", "appllication/octet-stream"); response.addHeader("Content-Disposition", "attachment;filename="+filename); //通知文件流读取文件 InputStream in = getServletContext().getResourceAsStream(folder+filename); //获取response对象的输出流 OutputStream out = response.getOutputStream(); byte[] buffer = new byte[1024]; int len; //循环取出流中的数据 while((len = in.read(buffer)) != -1){ out.write(buffer,0,len); } } |
1. mime介绍
MIME意为多用途Internet邮件扩展协议,它设计的最初目的是为了在发送电子邮件时附加多媒体数据,
让邮件客户程序能根据其类型进行处理。每个MIME类型由两部分组成,前面是数据的大类别,后面为具体的种类。
例如:image/bmp、image/jpeg、audio/mpeg
2. 文件上传记录表结构介绍
t_file_upload_recored
3. entity/dao创建及测试
FileUploadRecored
FileUploadRecoredDao
add
load
list
4. 文件下载的两种方式
4.1 直接打开
response.setHeader("content-disposition","filename=\"2.jpg\"");
4.2 另存为
response.setHeader("content-disposition","attachment;filename=\"2.jpg\"");
5. 中文文件名的处理
fileName = URLEncoder.encode(fileName,"UTF-8");