总的说图片上传有两种方式,一种是把图片文件写到数据库中,另一种是存到服务器文件目录中。写到数据库中的图片文件需要转换成二进制流的格式,占用数据库空间比较,适合少量图片的存储,比如说,系统中某些小图标,写到数据库中的优点是比较安全,不容易被用户不小心删除。
如果是大量的图片的存储通常的做法是保存到服务器的某个文件夹中。而完成上传有很多方式,可以采用流的方式,可以采用ftp的方式,这里采用fileupload方式。
随着系统规模的不同,对图片文件的处理方式也不尽相同。如果系统中图片的数量不是很大,直接把所有的图片存储到同一个目录下即可。如果图片的积累比较多,可以根据物资分类对图片进行相应的分类储存,这样会节省一些在磁盘中查找文件的时间。
图片上传到文件中,可以直接上传图片到目录中,也还可以将图片文件名、文件路径写入到数据库中,也可以在程序中动态的创建文件路径。如果公司中要求图片要用专门的服务器存放,这时候把文件路径写活还是比较合适的。一般的如果一种物资(物料)对应一张图片是比较容易处理的。如果对应多张图片,处理起来就需要配合循环使用。一方面,需要处理图片的动态显示,另一方面要检查图片文件命名是否重复。另外再图片处理(上传、删除、修改)的时候需要配合事务。
下面重点介绍一下使用fileupload方式实现图片上传的最基本的实现。
1、前端使用file标签:
- <input name = "fileName" type ="file" class ="text1" size ="40" maxlength="40">
2、设置文件的enctype格式:multipart/form-data
- <form name="itemForm" target="_self" id="itemForm" method="post" action="servlet/item/FileUploadServlet" enctype="multipart/form-data" >
关于enctype="multipart/form-data" 的说明:
在jsp中使用了该格式,对应的Servlet就不能使用request.getParameter()取得参数,要使用ServletFileUpload对象的parseRequest方法先把request对象中的数据解析,然后,使用解析出的元素的isFormField标志,配合getFieldName方法来获取数据。
3、FileUploadServlet的实现:
- package com.bjpowernode.drp.basedata.web;
- import java.io.File;
- import java.io.IOException;
- import java.util.Iterator;
- import java.util.List;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.commons.fileupload.FileItem;
- import org.apache.commons.fileupload.disk.DiskFileItemFactory;
- import org.apache.commons.fileupload.servlet.ServletFileUpload;
- import com.bjpowernode.drp.basedata.manager.ItemManager;
- import com.bjpowernode.drp.basedata.manager.ItemManagerImpl;
- import com.bjpowernode.drp.util.ApplicationException;
- public class FileUploadServlet extends AbstractItemServlet {
- private File uploadPath;
- private File tempPath;
- @Override
- public void init() throws ServletException {
- //在系统启动的时候,就开始初始化,在初始化时,检查上传图片的文件夹和存放临时文件的文件夹是否存在,如果不存在,就创建
- //获取根目录对应的真实物理路径
- uploadPath = new File(getServletContext().getRealPath("upload"));
- System.out.println("uploadPath=====" + uploadPath);
- //如果目录不存在
- if (!uploadPath.exists()) {
- //创建目录
- uploadPath.mkdir();
- }
- //临时目录
- //File tempFile = new File(item.getName())构造临时对象
- tempPath = new File(getServletContext().getRealPath("temp"));
- if (!tempPath.exists()) {
- tempPath.mkdir();
- }
- //如果不显示调用父类方法,就不会有itemManager实例,因此会造成空指针
- super.init();
- }
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- doPost(request,response);
- }
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- //从item_upload.jsp中拿取数据,因为上传页的编码格式跟一般的不同,使用的是enctype="multipart/form-data"
- //form提交采用multipart/form-data,无法采用req.getParameter()取得数据
- //String itemNo = req.getParameter("itemNo");
- //System.out.println("itemNo======" + itemNo);
- /********************************使用 FileUpload 组件解析表单********************/
- //DiskFileItemFactory:创建 FileItem 对象的工厂,在这个工厂类中可以配置内存缓冲区大小和存放临时文件的目录。
- DiskFileItemFactory factory = new DiskFileItemFactory();
- // maximum size that will be stored in memory
- factory.setSizeThreshold(4096);
- // the location for saving data that is larger than getSizeThreshold()
- factory.setRepository(tempPath);
- //ServletFileUpload:负责处理上传的文件数据,并将每部分的数据封装成一到 FileItem 对象中。
- //在接收上传文件数据时,会将内容保存到内存缓存区中,如果文件内容超过了 DiskFileItemFactory 指定的缓冲区的大小,
- //那么文件将被保存到磁盘上,存储为 DiskFileItemFactory 指定目录中的临时文件。
- //等文件数据都接收完毕后,ServletUpload再从文件中将数据写入到上传文件目录下的文件中
- ServletFileUpload upload = new ServletFileUpload(factory);
- // maximum size before a FileUploadException will be thrown
- upload.setSizeMax(1000000 * 20);
- /*******************************解析表单传递过来的数据,返回List集合数据-类型:FileItem***********/
- try {
- List fileItems = upload.parseRequest(request);
- String itemNo = "";
- //Iterator iter = fileItems.iterator()取其迭代器
- //iter.hasNext()检查序列中是否还有元素
- for (Iterator iter = fileItems.iterator(); iter.hasNext();) {
- //获得序列中的下一个元素
- FileItem item = (FileItem) iter.next();
- //判断是文件还是文本信息
- //是普通的表单输入域
- if(item.isFormField()) {
- if ("itemNo".equals(item.getFieldName())) {
- itemNo = item.getString();
- }
- }
- //是否为input="type"输入域
- if (!item.isFormField()) {
- //上传文件的名称和完整路径
- String fileName = item.getName();
- long size = item.getSize();
- //判断是否选择了文件
- if ((fileName == null || fileName.equals("")) && size == 0) {
- continue;
- }
- //截取字符串 如:C:WINDOWSDebugPASSWD.LOG
- fileName = fileName.substring(fileName.lastIndexOf("\") + 1, fileName.length());
- // 保存文件在服务器的物理磁盘中:第一个参数是:完整路径(不包括文件名)第二个参数是:文件名称
- //item.write(file);
- //修改文件名和物料名一致,且强行修改了文件扩展名为gif
- //item.write(new File(uploadPath, itemNo + ".gif"));
- //将文件保存到目录下,不修改文件名
- item.write(new File(uploadPath, fileName));
- //将图片文件名写入打数据库
- itemManager.uploadItemImage(itemNo, fileName);
- }
- }
- response.sendRedirect(request.getContextPath() + "/servlet/item/SearchItemServlet");
- } catch (Exception e) {
- e.printStackTrace();
- throw new ApplicationException("上传失败!");
- }
- }
- }
该类继承了AbstractItemServlet: 所有物料Servlet的抽象父类,负责实例化ItemManager
- /**
- * 所有物料Servlet的抽象父类,负责实例化ItemManager
- * @author LiMin
- *
- */
- public abstract class AbstractItemServlet extends HttpServlet {
- //虽然不是线程安全的,但是如果只读的话,是不会有错误的
- protected ItemManager itemManager = null;
- @Override
- public void init() throws ServletException {
- itemManager = new ItemManagerImpl()
- }
- }
ItemManagerImpl是实现了ItemManager接口的子类。这种设计模式有一个问题,有待遇优化,但这里为了说明图片上传,不多做无关的赘述。
总结:
关于init()初始化方法:
在Servlet初始化的时候,就动态创建目录,这里是把一个upload和临时文件tempPath创建到了tomcat的webapps下的项目的跟目录中。
值得注意点是这里需要显示调用super.init()方法(super不是父类对象的引用,但是负责父类的方法的调用),否则,可能会造成该类的空指针。
上传大致分三步执行:使用 FileUpload 组件解析表单;解析表单传递过来的数据,返回List集合数据-类型:FileItem;最后上传图片。
使用FileItem的isFormField()方法判断是普通文本还是文件;
使用FileItem.write(new File(uploadPath, fileName))上传文件,第一个参数是:完整路径(不包括文件名)第二个参数是:文件名称;
处理普通文本数据:
if ("itemNo".equals(item.getFieldName())) {
itemNo = item.getString();
}
上传是很多年比较成熟的技术,有很多已经封装好的,我们平时的项目中可以直接拿来用,但是了解一些基本的原理是必不可少的。