- 文件上传(重要)
- 创建一个空项目
- 空项目的好处:
- 创建web项目的三种方式:
- 架构图
- 1.准备工作
- 2.使用类介绍(了解)
- 【文件上传的注意事项】
- 【需要用到的类详解】
- Fileltem类
- ServletFileUpload类
- 3.编写代码
- 代码实现
- 表单
- FileServlet类
- 配置:web.xml
- 提交后表单
- 结果
在web应用中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现。
创建一个空项目 空项目的好处:- ieda中一个项目独占一个文件夹,通过一个空的项目new 模块,可以放很多个项目
这个做可以管理很多项目
创建模块
- 选择java,勾上web模块
没有web模块,先都不勾选,直接建立项目,建完项目后,右键项目,x选绎添加框架支持就有了
2. 通过maven模板创建项目
3. 通过maven创建,给它增加web支持
对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的
—般选择采用apache的开源工具common-fileupload这个文件上传组件。
common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。
文件上传依赖这两的包,这两个包的作用?
-
common-io
- 通过一个io *** 作,把大量的工具类封装到这个包里边,拿来即用
- 相当于网站的常用工具类打包,拿来即用
-
common-fileupload
- 针对于文件上传,做的包
jar包
- 本质是zip压缩包,后缀名是.jar
- 压缩的是就java代码,编译后的
jar包如何导入项目?
-
项目发布之后,会把里边的东西全部打包,包括jdk里的东西,
-
导包,两种方式
- 1、要把jar添加到类库里边 Add as Libray
- 2、项目结构中,项目目录的图书馆中添加
问题:lib目录没有放到最后项目发布里边
添加前:
添加后
文件上传调优
-
为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
-
为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
- 如:1.txt 1.txt 文件重名,解决方案:
- 加,时间戳(最常见)
- 不安全,两个人不能在同一时间上传
- uuid
- 生成一段随机的,不会重复的,数字
- md5
- 加密码
- 位运算算法
- 如,上传东西:二进制流,左移一位……
- 加,时间戳(最常见)
- 如:1.txt 1.txt 文件重名,解决方案:
-
要限制上传文件的最大值。
- 服务器要钱
-
可以限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
- 如,上传文件类型:.txt、.doc…………
- 如,上传图片类型:.jpg、.png、.bmp……
四个类
-
ServletFileUpload:文件上传
-
Fileltem:文件遍历
-
DiskFileltemFactory:磁盘文件遍历一个迭代系统
-
fileltemFactory:文件工厂,
- 对应的设计模式:工厂模式
- 为了偷懒,不去new对象,用工厂生产对象
- 对应的设计模式:工厂模式
流程
ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个Fileltem对象,在使用ServletFilelpload对象(上传)解析请求时,需要DiskFileltemFactory对象。所以,我们需要在进行解析工作前构造好DiskFileltemFactory对象,通过SevletFileUpload对象的构造方法或setFileltemFactory()方法设置ServletFileUpload对象的fileltemFactory属性。
ServletFileUpload这个类专门负责:上传文件的数据,
ServletFileUpload这个类会把表单(上传文件的表单)中的每一项封装成一个对象Fileltem,
再使用ServletFileUpload对象(上传)解析请求时,需要DiskFileltemFactory对象。
我们再把它解析到磁盘的时候(放到网站,或服务器中),会需要它(ServletFileUpload)的构造方法,一个fileltemFactory属性
Fileltem类在HTML页面input必须有name
在页面中必须有一个包含file的表单
第一步
让表单支持文件上传需要加属性
表单如果包含一个文件上传输入项的话,这个表单的enctype属性就必须设置为multipart/form-data
浏览器表单的类型如果为multipart/form-data,在服务器端想获取数据就要通过流。
【常用方法介绍】
//isFormField方法用于:判断FileItem类对象封装的数据 //是一个普通文本表单还是一个文件表单,如果是普通表单字段则返回true,否则返回false boolean isFormField();//判断表单的字段,没有文件的表单统称普通表单 //getFieldName方法用于:(获取)返回表单标签name属性的值。 string getFieldName(); //getstring方法用于将:FileItem对象中保存的数据流内容以一个字符串返回 string getstring(); //getName方法用于:获得文件上传字段中的文件名。 String getName(); //以流的形式返回上传文件的数据内容。 Inputstream getInputstream() // delete方法用来:清空FileItem类对象中存放的主体内容 //如果主体内容被保存在临时文件中,delete方法将删除该临时文件。 void delete();ServletFileUpload类
ServletFileUpload:负责处理上传的文件数据,并将表单中每个输入项封装成一个Fileltem对象中,使用其parseRequest(HttpServletRequest)方法可以将通过表单中每一个HTML标签提交的数据封装成—个Fileltem对象,然后以List列表的形式返回。使用该方法处理上传文件简单易用。
3.编写代码 代码实现 表单<%@ page contentType="text/html;charset=UTF-8" language="java" %>FileServlet类$Title$ <%--通过表单上传文件 问题:用get/post? get:上传文件大小有限制 post:上传文件大小没有限制 --%> <%--真实开发,放在服务器中需要在 ${'地址'} 里面 ${pageContext.request.contextPath} 固定的写法,写死,代表:获取服务器当前路径 --%>
package com.yin.servlet; 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.*; import java.util.List; import java.util.UUID; public class FileServlet extends HttpServlet { //处理表单 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //判断上传的文件是普通表单还是带文件的表单,两者有区别,文件的要传输,普通的表单收取字符串 if (!ServletFileUpload.isMultipartContent(req)) {//是否包含文件 return;//不是,终止方法运行,说明这个一个普通的表单,直接返回 }//如果通过了这个if,说明我们的表单是带文件上传的 //创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件; String uploadPath = this.getServletContext().getRealPath("WEB-INF/upload");//获得:全局上下文.真实地址 //判断这个文件有没有 File uploadFile = new File(uploadPath); if (!uploadFile.exists()) {//如果文件不存在 uploadFile.mkdir();//创建这个目录 } //临时路径,假设文件超过了预期的大小,我们就把他放到一个临时文件中,过几天自动删除,或者提醒用户转存为永久 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组件 try { //1.创建 DiskFileItemFactory(磁盘工厂)对象,处理文件上传路径或者大小限制 DiskFileItemFactory factory = getDiskFileItemFactory(file); //2.获取 ServletFileUpload ServletFileUpload upload = getServletFileUpload(factory);//把 factory 类作为参数传递进来 //3.处理上传的文件 String msg = uploadParseRequest(upload, req, uploadPath); //servlet请求转发消息 req.setAttribute("msg", msg);//存 req.getRequestDispatcher("info.jsp").forward(req, resp); } 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); //设置总共能够上传文件的大小 //1024 = 1kb * 1024 = 1M * 10 = 10M upload.setSizeMax(1024 * 1024 * 10); return upload; } public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath) throws IOException, FileUploadException { String msg = ""; //3.把前端请求解析,封装成一个FileItem对象,需要从ServletFileUpload对象中获取 List配置:web.xmlfileItems = upload.parseRequest(request); //fileItem 每一个表单对象 for (FileItem fileItem : fileItems) { //判断上传的文件(控件)是普通的表单还是带文件的表单,判断是不是 input file if (fileItem.isFormField()) {//普通表单 //getFieldName:前端表单控件的name 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; } //获得上传的文件名 /images/girl/paojie/png //字符串游戏 String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);//最后一个 / +1 //获得文件的后缀名 String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1); System.out.println("文件信息[件名:" + fileName + "---文件类型" + fileExtName + "]"); //可以使用UUID(唯一识别的通用码),保证文件名唯一 //UUID.randomUUID():随机生成一个唯一识别的通用码 String uuidPath = UUID.randomUUID().toString(); //===============处理文件完毕=================== //文件存到哪? uploadPath //文件真实存在的路径 realPath String realPath = uploadPath + "/" + uuidPath; //给每个文件创建一个对应的文件夹 File realPathFile = new File(realPath); if (!realPathFile.exists()) {//不存在 realPathFile.mkdir();//创建文件夹,保证不会重复 } //===============存放地址完毕=================== //获得文件上传的流 InputStream inputStream = fileItem.getInputStream(); //创建一个文件输出流 FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);// 输出的地址 //创建一个缓存区 byte[] buffer = new byte[1024 * 1024]; //判断是否读取完毕 int len = 0; //如果大于0说明还存在数据 while ((len = inputStream.read(buffer)) > 0) { fos.write(buffer, 0, len); } //关闭流 fos.close(); inputStream.close(); msg = "文件上传成功"; fileItem.delete();//上传成功,清除临时文件 //===============文件传输完毕=================== } } return msg; } }
提交后表单FileServlet com.yin.servlet.FileServlet FileServlet /upload.do
取值
<%-- Created by IntelliJ IDEA. User: Lenovo Date: 2021/12/10 Time: 19:01 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %>结果Title <%--取msg值--%> ${msg}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)