目录:

»  fileupload API

>  文件上传的要求

>  fileupload组件

»  上传细节的代码演示

»  项目案例-上传头像并显示


fileupload API

文件上传的要求

上传文件对页面的要求:

  • 必须使用表单,不能用超链接
  • 表单的method必须是post, 不能是GET
  • 表单的enctype必须是multipart/form-data
  • 表单字段<input type="file"....>
 <form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">用户名:<input type="text" name="username"/><br/>文件1:<input type="file" name="file1"/><br/>文件2:<input type="file" name="file2"/><br/><input type="submit" value="提交"/></form>

上传文件对Servlet的要求:

  • 当一个表单中存在普通表单项字段和文件表单项字段时,就不能使用request.getParameter(String) 来获取了,因为request.getParameter(String) 获取的是字符内容,而上传的文件是字节内容,所以要使用request.getInputStream()来得到ServletInputStream对象,(InputStream的子类)。 ServletInputStream对象对应所有表单数据(包含文件项和普通项)。 所以当有文件作为表单项时,我们需要操作的是ServletInputStream对象

fileupload组件

ServletInputStream对象是个流对象,我们需要去解析流中的数据,过于麻烦 。所以利用apache提供的Commons FileUpload 组件,这个组件能帮助我们方便的解析  

Commons FileUpload 组件 包含 两个包:  commons-fileupload.jar(核心包) 、 commons-io.jar (依赖包),如果使用组件,则必须导入这个两个包 。 (两个包的下载,在本文项目案例下载中)

fileupload的核心类有 :  DiskFileItemFactory(工厂) 、ServletFileUpload(解析器) 、 FileItem(表单项)

fileupload组件的使用步骤如下:

  1. 创建工厂类DiskFileItemFactory 对象 : DiskFileItemFactory factory = new DiskFileItemFactory()
  2. 使用工厂创建解析器对象   : ServletFileUpload fileUpload = new ServletFileUpload(factory)
  3. 使用解析器来解析request对象:List<FileItem> list = fileUpload.parseRequest(request)

FileItem类是我们要的结果,一个FileItem对象对应一个表单项(一个表单字段),一个表单中存在文件字段和普通字段  , 该类的一些方法如下:

String   getName()  获取文件字段的文件名称   
String getString(String charset)  返回表单项的值
 boolean isFormField()  是否为普通表单项!返回true为普通表单项
 String getFieldName()  返回当前表单项的名称
 long getSize()  返回上传文件的字节数
 InputStream getInputStream()  返回上传文件对应的输入流
 void write(File destFile)  把上传的文件内容保存到指定的文件中
 String getContentType()  获取MIME类型

上传细节的代码演示

代码中 包含的内容  :   上传表单项与普通表单项 + 目录打散 + 缓存 + 文件大小限制

运行代码前: 应现在项目的WEB-INF目录下创建files目录  。  在D盘下创建temp目录

1 <h1>上传Demo1</h1>
2  <h3>${msg }</h3>
3  <form action="<c:url value='/UploadServlet'/>" method="post" enctype="multipart/form-data">
4      用户名:<input type="text" name="username"/><br/>
5      照  片:<input type="file" name="zhaopian"/><br/>
6      <input type="submit" value="上传"/>
7  </form>

  1 package cn.kmust.web.demo1.UpLoadServlet;
  2
  3 import java.io.File;
  4 import java.io.IOException;
  5 import java.util.List;
  6
  7 import javax.servlet.ServletException;
  8 import javax.servlet.http.HttpServlet;
  9 import javax.servlet.http.HttpServletRequest;
 10 import javax.servlet.http.HttpServletResponse;
 11
 12 import org.apache.commons.fileupload.FileItem;
 13 import org.apache.commons.fileupload.FileUploadBase;
 14 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 15 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 16
 17 import cn.itcast.commons.CommonUtils;
 18 /**
 19  * 处理上传的图片
 20  * @功能 保存到web-inf下的files文件中,目录自动生成
 21  *   有缓存的设置
 22  *   有文件大小限制设置
 23  *   目录打散 : 能够自动保存到web-inf下的files文件中创建目录,保存文件
 24  *   能够保存到本地硬盘中
 25  * @author ZHAOYUQIANG
 26  *
 27  */
 28 public class UploadServlet extends HttpServlet {
 29
 30     public void doPost(HttpServletRequest request, HttpServletResponse response)
 31             throws ServletException, IOException {
 32         request.setCharacterEncoding("utf-8");
 33         response.setContentType("text/html;charset=utf-8");
 34         /*
 35          * 1. 得到工厂
 36          *      设置缓存大小和临时目录: 上传的时候是存到内存的,如果过大,内存会吃不消,
 37          *      需要先在硬盘中(D:/temp)存一下,每20*1024就往硬盘中存一下
 38          *
 39          * 2. 通过工厂创建解析器
 40          *     对大小进行限制 ,放在解析之前
 41          *       如果超过大小会抛出异常,抛出异常的类型不同
 42          */
 43         DiskFileItemFactory factory = new DiskFileItemFactory(50*1024,new File("D:/temp"));
 44         ServletFileUpload sfu = new ServletFileUpload(factory);
 45         /**
 46          * 功能1.  对单个文件大小和整个表单大小进行限制
 47          *              并且在后面的异常中进行提示
 48          */
 49         //限制单个文件大小为50KB,抛出FileUploadBase.FileSizeLimitExceededException
 50         sfu.setFileSizeMax(50*1024);//并且限制单个文件大小为5M,抛出文件大小限制异常
 51         //限制整个表单大小为50KB,抛出FileUploadBase.SizeLimitExceededException
 52         //sfu.setSizeMax(50*1024);
 53         try {
 54             /*
 55              * 3. 解析request,得到FileItem集合
 56              * 4. 遍历FileItem集合,得到普通表单项(用户名等)和
 57              *      文件表单项(上传的文件)
 58              */
 59             List<FileItem> fileItemList = sfu.parseRequest(request);
 60             FileItem fi1 = fileItemList.get(0); //得到第一个表单项
 61             FileItem fi2 = fileItemList.get(1); //得到第二个表单项
 62 //演示普通表单项与文件表单项/
 63 ///
 64             /*
 65              * 5. 输出普通表单项的演示
 66              *     输出普通表单项的名和值
 67              *
 68              */
 69             System.out.println("@@@@@@@@@");
 70             System.out.println("普通表单项演示 : "+fi1.getFieldName()+
 71                     "="+fi1.getString("UTF-8"));
 72             /*
 73              * 6. 输出文件表单项的相关演示
 74              *     对于文件表单项:获取MIME类型、获取大小、获取文件名字
 75              */
 76             System.out.println("文件表单项演示 :");
 77             System.out.println("Content-Type :"+fi2.getContentType());
 78             System.out.println("size :"+fi2.getSize());
 79             System.out.println("filename :"+fi2.getName());
 80
 81 保存文件到web-inf下的files目录
 82 //
 83             /**
 84              * 1. 保存文件  [目录打散]
 85              *    保存到web-inf下的files,这样安全
 86              *      自动保存,文件目录自动创建,按照哈希打散生成两级目录,
 87              *       分别取的十六进制前两个字符当作目录的一级和两级
 88              */
 89             /*
 90              * 1.1. 得到文件保存根路径
 91              * 1.2. 得到文件名称
 92              * 1.3. 进行两步处理
 93              * 1.4. 用文件名得到整形的hashCode,把hashCode转换成十六进制
 94              * 1.5. 获取十六进制前两个字符与根路径连接起来生成完成的目录路径
 95              * 1.6. 路径有了之后,根据路径在磁盘上创建目录链
 96              *   如果有了该目录什么也不做,如果没有就创建
 97              * 1.7. 保存文件
 98              */
 99             String root = this.getServletContext().getRealPath("/WEB-INF/files/");
100             String filename = fi2.getName();
101             /**
102              * 解决可能遇到的问题1 :
103              *    有的浏览器得到的文件名是绝对路径c:\XX\a.jpg,我们只是需要后截的路径
104              *   如果得到的是绝对路径,需要截取后半段的路径
105              */
106             int index = filename.lastIndexOf("\\"); //转义
107             if(index != -1){ //说明有\,说明是绝对路径
108                 filename = filename.substring(index+1);//截取出后半段的路径
109             }
110             /**
111              * 解决可能遇到的问题2 :
112              *    文件目录是自动生成的,可能存在文件同名问题
113              *      在生成的文件目录前面加上不同的id(利用commons中的uuid来生成)
114              */
115             String savename = CommonUtils.uuid()+"_"+filename;
116             int hCode = filename.hashCode();
117             String hex = Integer.toHexString(hCode);
118             File dirFile = new File(root,hex.charAt(0)+"/"+hex.charAt(1));
119
120             dirFile.mkdirs();
121             File destFile = new  File(dirFile,savename);
122             try {
123                 fi2.write(destFile);
124             } catch (Exception e) {
125                 throw new RuntimeException(e);
126             }
127         } catch (Exception e) {
128             /*
129              * 处理单个文件大小限制异常
130              */
131             if(e instanceof FileUploadBase.FileSizeLimitExceededException){
132                 request.setAttribute("msg", "您上传的文件超出了50KB!");
133                 request.getRequestDispatcher("/formDemo1.jsp").forward(request, response);
134             }
135             throw new ServletException(e);
136         }
137     }
138 }

注意 : 文件大小对目录的限制,如果超过规定的大小太多,则直接报异常错误,页面也显示无法访问此网站等信息。这是因为common-fileupload组件默认最大支持上传文件的大小为2M,当我们上传大于2M的文件时,这个异常的发生导致了fileUpload拦截器没有机会执行 。

上传的文件要到tomcat下项目的相关目录中查看

项目案例---上传头像并显示(MVC+MySQL)

CREATE TABLE `tb_employe` (`eid` char(32) NOT NULL,`ename` char(100) NOT NULL,`gender` varchar(10) DEFAULT NULL,`image` varchar(200) DEFAULT NULL,PRIMARY KEY (`eid`)
)

重要代码演示: (全部代码请下载项目查看,注意修改c3p0文件的数据库名称)  

1 <h1><center>添加员工</center></h1>
2     <form action="<c:url value='/EmployeAddServlet'/>" method="post" enctype="multipart/form-data">
3        编号 :<input type="text" name="eid" /><br/>
4    姓名: <input type="text" name ="ename"/><br/>
5   性别: <input type="radio" name="gender" value="男" />男
6       <input type="radio" name="gender" value="女"/>女 <br>
7   头像: <input type="file" name="image" />    <br/>
8   <input type="submit" value="添加"/>
9     </form>

 1 <c:forEach items="${employeList }" var="employe">
 2   <div class="icon">
 3      <img src="<c:url value='/${employe.image }'/>" border="0"/><br/>
 4        <center>
 5          <table border="0">
 6              <tr>
 7                 <td>编号: </td><td>${employe.eid }</td>
 8              </tr>
 9              <tr>
10                 <td>姓名: </td><td>${employe.ename }</td>
11              </tr>
12              <tr>
13                 <td>性别: </td><td>${employe.gender }</td>
14              </tr>
15          </table>
16        </center>
17   </div>
18 </c:forEach>

package cn.kmust.employe.web.servlet;import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.ImageIcon;import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;import cn.itcast.commons.CommonUtils;
import cn.kmust.employe.domain.Employe;
import cn.kmust.employe.service.EmployeService;/*** web层* @author ZHAOYUQIANG**/
public class EmployeAddServlet extends HttpServlet {private EmployeService employeService = new EmployeService();public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");/** 上传三步*   创建工厂、得到解析器、使用解析器去解析request对象,得到List<FileItem>*/DiskFileItemFactory factory = new DiskFileItemFactory(100*1024,new File("D:/temp"));ServletFileUpload sfu = new ServletFileUpload(factory);/** 校验 头像是否>50KB*///sfu.setFileSizeMax(50*1024);try{List<FileItem> fileItemList = sfu.parseRequest(request);/** 把fileItemList中的数据封装到Employe对象中*/Map<String,String> map = new HashMap<String,String>();/** 首先把所有的普通表单字段先封装到Map中,再把map中的数据封装到Employe中*/for(FileItem fileItem : fileItemList){if(fileItem.isFormField()){ //判断是不是普通表单项map.put(fileItem.getFieldName(), fileItem.getString("UTF-8"));}}Employe employe = CommonUtils.toBean(map, Employe.class);/** 保存上传的文件,即把上传的头像图片保存到带有盘符的目录中*     要保存的路径*     要保存的文件名称*/String savepath = this.getServletContext().getRealPath("/images");//得到保存目录        //得到文件名称,给文件名称添加uuid前缀,避免名称冲突。//需要注意: get(3)表示文件表单项在表单的第3个位置3String filename = CommonUtils.uuid()+"_"+fileItemList.get(3).getName();
//            for(int i =0;i<30;i++){
//                 System.out.println(i+":"+fileItemList.get(i).getName());
//            }/* * 校验文件扩展名是否是jpg格式的*/if(!filename.toLowerCase().endsWith("jpg")){request.setAttribute("msg", "您上传的图片不是jpg扩展名!");request.getRequestDispatcher("/AddEmploye.jsp").forward(request, response);return ;}File destFile = new File(savepath,filename); //使用目录和文件名创建目标文件fileItemList.get(3).write(destFile);//保存上传文件到目标位置/** 设置Employe对象的image*/employe.setImage("images/"+filename);/** 调用service完成添加*/System.out.println("3333333333333333333");employeService.add(employe);/** 校验图片的尺寸*/Image image = new ImageIcon(destFile.getAbsolutePath()).getImage();if(image.getWidth(null)>200 || image.getHeight(null)>200){//删除图片
                destFile.delete();request.setAttribute("msg", "您上传的图片尺寸超过了200*200");request.getRequestDispatcher("/AddEmploye.jsp").forward(request, response);return ;}/** 完成添加,返回员工列表*/request.getRequestDispatcher("/EmployeServlet?method=findAll").forward(request, response);}catch(Exception e){/** 处理上传图片过程中出现的图片大小异常*/if(e instanceof FileUploadBase.FileSizeLimitExceededException){request.setAttribute("msg", "您上传的图片超过了50KB");request.getRequestDispatcher("/AddEmploye.jsp").forward(request, response);}}}
}

项目下载 : https://files.cnblogs.com/files/zyuqiang/fileuploadProject.zip

转载于:https://www.cnblogs.com/zyuqiang/p/7494296.html

《JavaWeb从入门到改行》fileupload,没毛病相关推荐

  1. 《JavaWeb从入门到改行》过滤器学习笔记

    目录:(点击红色方框展开子目录) Filter API 无 Filter详解 过滤器配置 四种拦截方式 经典案例 分IP统计网站的访问次数 粗粒度权限控制 解决全站字符乱码 页面静态化 使用@WebF ...

  2. 《JavaWeb从入门到改行》JDBC经典秘方QueryRunner

    目录: 基础篇_功能各自回顾 JDBC基础代码回顾(使用JdbcUtils工具简化) c3p0数据库连接池的使用(使用JdbcUtils工具简化) 大数据的插入(使用c3p0+JdbcUtils工具简 ...

  3. 《JavaWeb从入门到改行》注册时向指定邮箱发送邮件激活

    javaMail API javaMail是SUN公司提供的针对邮件的API . 两个jar包  mail.jar 和 activation.jar java mail中主要类:javax.mail. ...

  4. 《JavaWeb从入门到改行》多重外键关系在java中的处理方案

    目录:(点击红色方框展开子目录) 问题描述 无 项目案例说明 业务描述 数据库说明 项目源码及下载 无 问题描述 如上两图,数据库中各个表之间有很多的外键关系,其中业务关系是一个用户下有该用户的订单, ...

  5. 《JavaWeb从入门到改行》分页功能的实现

    @目录 什么是分页 ? 两个子模块功能的问题分析 和 解决方案 有条件查和无条件查询的影响 和 解决方案 项目案例: mysql + commons-dbutils+itcast-tools+Base ...

  6. 【技术培训】招收Jeecg门徒 ---javaweb初级入门班

    招收Jeecg门徒[javaweb初级入门班] 最近准备带徒弟,带些人才出来,我带徒弟的理念是实践为王,在实践中掌握原理,积累经验. 我带徒弟的方向是JAVA WEB,掌握各种主流框架.(后期会开展j ...

  7. JavaWeb 从入门到入门

    技术事简单报,看老王带你从入门JavaWeb,从删库到跑路 本篇文章适用于大学学习javaweb的入门同学,理解不深,欢迎交流 目录 第一章 服务器入门/tomcat 第一节:BS/CS 模式 第二节 ...

  8. 暴力裁员?小米回应来了,网友表示没毛病!

    点击蓝色"视学算法"关注我哟 加个"星标",和我一起,成为更好的自己 继网易暴力辞退绝症员工.华为"251"事件之后,又一家互联网企业传出违 ...

  9. JavaWeb项目+MVC三层架构+Mysql+Tomcat+汽车配件销售系统前后端+可以用于学习javaweb项目入门

    JavaWeb项目+MVC三层架构+Mysql+Tomcat+汽车配件销售系统前后端+可以用于学习javaweb项目入门 可以用于课程设计.毕业设计的知识点入门学习 提示:此资源仅用于javaweb网 ...

最新文章

  1. 内存溢出和内存泄漏的定义,产生原因以及解决方法(面试经验总结)
  2. java element 属性_属性'value'在'HTMLElement'类型的值上不存在
  3. View视图类与Dialog对话框通信实例
  4. 斯诺登的密码(洛谷-P1603)
  5. 如何在 Python 数据中清洗常用 4 板斧?
  6. JavaCV最小依赖
  7. FPGA:verilog实现直接型巴特沃斯高通IIR滤波器
  8. 010 Editor 之 二进制查看修改神器
  9. 拿webshell的一些姿势
  10. 存储型路由器和SAN路由器
  11. 完美解决异常问题UnicodeEncodeError: ‘ascii‘ codec can‘t encode characters in position 0-7: ordinal not in ra
  12. TX2--Tegra架构介绍
  13. coldfusion_ColdFusion教程:第一部分
  14. 一文了解肠-器官轴,肠好身体好
  15. cannot access memory
  16. 【渝粤教育】 广东开放大学 21秋期末考试大学英语210262k2
  17. 80c51单片机指令大全
  18. Linux系统 QT+Faac实时音频采集编码(QT音频采集篇)
  19. Google Pixel手机解锁 bootloader
  20. 编写python代码获取4k高清壁纸

热门文章

  1. php基础知识速记,php基础速记
  2. 银行间债市衍生工具扩容:新版CRM落地 参与门槛降低
  3. 区块链智能合约solidity入门 1
  4. 从月薪3万到月薪5000:无效努力,解决不了系统困境
  5. 02_控制系统的数学模型拉普拉斯变换概念及常用定理(有简单证明过程)
  6. Fact Table 数据表什么意思
  7. 杨兴计算机专业讲师,杨兴林:得天下英才而教育之不亦乐乎
  8. Web应急:网站被批量挂黑页
  9. Proteus仿真-DS18B20温度传感器使用方法
  10. springboot基于vue.js的掌上博客系统的设计与实现毕业设计源码063131