javaweb文件上传
1.流程
-
重点:网络思想
-
创建maven项目(模板创建)
-
导入相应jar包,导入相应的依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
-
配置tomcat
-
创建我们的前端页面
-
在HTML页面input 必须有 name
<input type="file" name="filename">
,表单如果包含一个文件上传输入项的话,这个表单的enctype属性就必须设置为multipart/form-data,在服务器端想获取数据也要通过流<form action="${pageContext.request.contextPath}/upload.do" method="post" enctype="multipart/form-data"> 上传用户: <input type="text" name="username"><br/> 上传文件:<input type="file" name="file"><br/> <input type="submit" value="提交"> </form>
-
上传成功页面
<body> ${msg} </body>
-
-
post请求/upload.do,配置相应的映射
-
代码实现
package com.lcj.FileupDown; 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; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.UUID; public class FileupDown extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //判断用户上传的文件是普通表单还是带文件的表单,如果是普通文件直接返回 if (!ServletFileUpload.isMultipartContent(request)) { return; } //创建文件上传保存的路路径,在WEB-INF路径下是安全的,用户无法直接访问上传文件 //小:上传文件 String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload"); System.out.println(uploadPath); File uploadFile = new File(uploadPath); if (!uploadFile.exists()){ uploadFile.mkdir(); } //临时路径,如果文件好过了预期大小,就把他放到一个临时文件中,过几天自动删除,或者提醒用户转存为永久 //大:临时上传文件---qq String tmpPath = this.getServletContext().getRealPath("WEB-INF/tmp"); File file = new File(tmpPath); if (!file.exists()){ file.mkdir(); } //处理上传的文件,一般通过流来获取,可以使用request.getInputStream(),原生态的文件上传流获取,十分麻烦 //建议使用 Apache的文件上传组件来实现,common-fileupload,它需要依赖于 commons-io组件; //1、创建DiskFileItemFactory对象,处理文件上传路径或大小的限制 DiskFileItemFactory factory = getDiskFileItemFactory(uploadFile); //2、获取ServletFileUpload ServletFileUpload upload = getServletFileUpload(factory); //3、处理上传的文件 try { String msg = uploadParseRequest(upload,request,uploadPath); //将数据发给前端 request.setAttribute("msg",msg); request.getRequestDispatcher("msg.jsp").forward(request,response); } catch (FileUploadException e) { e.printStackTrace(); } } public static DiskFileItemFactory getDiskFileItemFactory(File file){ DiskFileItemFactory factory = new DiskFileItemFactory(); //通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中 factory.setSizeThreshold(1024*1024); //缓冲区大小为1M factory.setRepository(file);//临时文件保存的目录,需要一个File return factory; } public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){ ServletFileUpload upload = new ServletFileUpload(factory); //监听文件上传进度 upload.setProgressListener(new ProgressListener() { @Override //pBytesRead:已经读取到的文件大小 //pContentLength : 文件大小 public void update(long pBytesRead, long pContentLength, int pItems) { System.out.println("总大小:"+pContentLength+"已上传"+pBytesRead); } }); //处理乱码问题 upload.setHeaderEncoding("utf-8"); //设置单个文件的最大值 upload.setFileSizeMax(1024*1024*10); //设置总共能够上传文件的大小 upload.setSizeMax(1024 * 1024 * 10); return upload; } public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath) throws FileUploadException, IOException { String msg = ""; //把前端请求解析,封装成一个FileItem对象(表单中的输入项) List<FileItem> fileItems = upload.parseRequest(request); for (FileItem fileItem : fileItems) { if (fileItem.isFormField()){ String name = fileItem.getFieldName(); String value = fileItem.getString("UTF-8"); System.out.println(name+":"+value); }else { //****************************处理文件**************************** //拿到文件名字 String uploadFileName = fileItem.getName(); System.out.println("上传的文件名:"+uploadFileName); if (uploadFileName.trim().equals("") || uploadFileName==null){ continue; } //获得上传的文件名 String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/")+1); //获得文件的后缀名 String fileExName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1); /* * 如果文件后缀名fileExName不是所需的直接return,不进行处理,告诉用户文件类型不对 * */ System.out.println("文件信息 [文件名:"+fileName+"---文件类型"+fileExName+"]"); //可以使用UUID(唯一识别通用码)保证文件名唯一 String uuidPath = UUID.randomUUID().toString(); //****************************处理文件完毕**************************** //真实存在的路径 String realPath = uploadPath+"/"+uuidPath; //给每个文件创建一个对应的文件夹 File realPathFile = new File(realPath); if (!realPathFile.exists()){ realPathFile.mkdir(); } //****************************存放地址完毕***************************** //获得文件上传的流 InputStream inputStream = fileItem.getInputStream(); //创建一个文件输出流 //realPath是真实的文件夹 FileOutputStream fos = new FileOutputStream(realPath + "/"+fileName); //创建一个缓冲区 byte[] buffer = new byte[1024 * 1024]; //判断是否读取完毕 int len = 0; while ((len=inputStream.read(buffer))>0){ fos.write(buffer,0,len); } //关闭流 fos.close(); inputStream.close(); msg = "文件上传成功"; fileItem.delete();//上传成功,清除临时文件 //*************************文件传输完毕************************** } } return msg; } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
-
使用的类
-
ServletFileUpload
负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象(表单输入项), 在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象。所以,我们需要在进行解析工作前构造好DiskFileItemFactory对象,通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性。
-
FileItem
表单输入项
-
DiskFileItemFactory
将请求消息实体中的每一个项目封装成单独的DiskFileItem (FileItem接口的实现) 对象的任务
由 org.apache.commons.fileupload.FileItemFactory 接口的默认实现
org.apache.commons.fileupload.disk.DiskFileItemFactory 来完成。当上传的文件项目比较小时,直接保存在内存中(速度比较快),比较大时,以临时文件的形式,保存在磁盘临时文件夹(虽然速度慢些,但是内存资源是有限的)。
-
-
实现流程
- 判断用户上传的文件是普通表单还是带文件的表单,如果是普通文件直接返回(return)
- 创建文件上传保存的路路径,在WEB-INF路径下是安全的,用户无法直接访问上传文件
- 创建临时路径,如果文件好过了预期大小,就把他放到一个临时文件中
- 创建DiskFileItemFactory对象,设置文件临时路径(setRepository)或大小的限制(设置一个缓冲区,setSizeThreshold)
- 获取ServletFileUpload对象,处理乱码问题(setHeaderEncoding),设置单个文件的最大值(setFileSizeMax),设置总共能够上传文件的大小(setSizeMax),还可选择监听文件上传进度(setProgressListener)
- 通过ServletFileUpload对象的parseRequest方法把前端请求解析,封装成一个FileItem对象,判断上传的文件是普通的表单还是带文件的表单(isFormField),getFieldName获取前端表单控件的name
- 通过FileItem的getName方法获取文件名字并判断是否为空,可以使用UUID保证文件名唯一
- 拼接文件真实存在路径,并给每个文件创建一个对应的文件夹
- 通过FileItem的getInputStream方法获取文件上传的流,并创建一个文件输出流将文件写入真实保存路径,最后关闭流
- 上传成功可将页面转发到新的提示页面
-
注意事项
- 为保证服务器安全,上传文件应放在外界无法直接访问的目录下,比如放于WEB-INF目录下
- 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名(加时间戳,加UUID)
- 要限制上传文件的最大值
- 可以限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法
- 表单 method 属性应该设置为 POST 方法,不能使用 GET 方法
-
总结
- 字符串处理路径和文件名
- UUID可以进行唯一标识
- 文件上传的流程,网络思想
- 文件下载:
- 设置浏览器以下载的方式打开文件
- 输入流读取文件,输出流输出到浏览器----响应对象完成
-
邮件发送
-
网站注册邮件发送