Struts2下多文件的上传与下载
目录
关键词... 1
写在前面... 1
需求... 1
环境... 2
目录结构... 3
重要文件的看点... 3
web.xml. 3
struts.xml. 4
UploadAction. 5
DownloadAction. 8
UploadConfigurationRead. 10
工程结果截图... 13
提供原代码下载... 14
 
多文件 上传 下载 随意文件 java Struts2 单例 配置 动态读取 李顺利  
 
    在网络上,对于Java处理文件上传和下载的技术比较多,而Struts作为一款优秀的框架也提供了非常方便的文件上传和下载,而网上的一些例程都非常的不全面,概括来:
1)   文件上传比较多,多文件上传少一点
2)   文件下载很少的,看似简单,实则不然
3)   文件下载一般都是单文件或者固定的文件,并没有(很少)实现随意文件的下载的例子
最近也在研究一下文件的上传和下载,在整合网上、浪曦风中叶老师和自己的学习的思想,写了这个工程,提供给大家参考,所以的代码终在IE、FireFox、Chrome测试通过。
 
1.能够对多个文件进行上传(可以选择上传文件个数,也即上传文件个数不定)
2.能够对上传路径进行配置文件(upload.properties)指定,使用了一些类似单例模式的静态代码块
3.对配置文件中的路径可以进行动态读取(不重启服务器)
4.Struts2进行下载处理,能对上传的所有文件进行下载(多个)
5.文件保存的名称UUID生成,不过显示并下载的名称都是原文件名称
(人性化,通过UploadFiles处理)
 
最新的Struts2:struts-2.1.8、MyEclipse、Tomcat、IE、FireFox、Chrome
 

 
…
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
…
    在web.xml中使用了最新的Struts2的中央处理器类org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter,而不再是以前的org.apache.struts2.dispatcher.FilterDispatcher,FilterDispatcher在新版本Struts2中已经标注为过时了,请大家尽量使用最新的filter。
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <constant name="struts.i18n.encoding" value="utf8" />
    <package name="file" namespace="/" extends="struts-default">
       <action name="showUpload">
           <result>/upload.jsp</result>
       </action>
       <action name="upload" class="org.usc.file.UploadAction">
           <result name="input">/upload.jsp</result>
<!--          <result name="success">/upload_success.jsp</result>-->
           <result name="success">/download.jsp</result>
           <interceptor-ref name="fileUpload">
<!--大家可以设置成自己的配置,想文件类型和大小等限制          -->
<!--              <param name="maximumSize">2097152</param>单位是字节   2M  (2097152B)       -->
<!--              <param name="allowedTypes">image/bmp,image/x-png,image/png,image/gif,image/jpeg,image/jpg,image/pjpeg</param>-->
<!--              -->
<!--                 容许文件类型为doc,ppt,xls,pdf,txt,java-->
<!--              -->
           </interceptor-ref>
           <interceptor-ref name="defaultStack"></interceptor-ref>
       </action>
 
       <action name="download" class="org.usc.file.DownloadAction">
           <result name="success" type="stream">
              <param name="contentDisposition">attachment;filename="${fileName}"</param>
              <param name="inputName">downloadFile</param>
           </result>
       </action>
    </package>
</struts>
 
就是文件上传和下载的一些Struts2配置,注意上传的时候,请引入
<interceptor-ref name="defaultStack"></interceptor-ref>,
下载的配置中注意:<param name="inputName">downloadFile</param>
其他的配置解释网上很多,不懂的可以先google学习一下。
 
在此文件中请注意文件数组的使用,因为是多文件
 
package org.usc.file;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import org.usc.utils.UploadConfigurationRead;
import com.opensymphony.xwork2.ActionSupport;
 
/**
 * 多文件上传类
 * 
 * @author MZ
 * 
 * @Time 2009-11-24下午09:26:44
 */
public class UploadAction extends ActionSupport
{
 
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private File[] upload;// 实际上传文件
    private String[] uploadContentType; // 文件的内容类型
    private String[] uploadFileName; // 上传文件名
    private List<UploadFiles> uploadFiles = new ArrayList<UploadFiles>();
 
    public String execute() throws Exception
    {
       try
       {
           String targetDirectory = ServletActionContext.getServletContext()
                  .getRealPath("/"+ UploadConfigurationRead.getInstance().getConfigItem("uploadFilePath").trim());// 获得路径
           for (int i = 0; i < upload.length; i++)
           {
              String fileName = uploadFileName[i];// 上传的文件名
              String type = uploadContentType[i];// 文件类型
              String realName = UUID.randomUUID().toString()+ getExt(fileName);// 保存的文件名称,使用UUID+后缀进行保存
 
              File target = new File(targetDirectory, realName);
              FileUtils.copyFile(upload[i], target);// 上传至服务器的目录,一般都这样操作,
                                                 // 在把路径写入数据库即可
 
              UploadFiles uf = new UploadFiles();// 创建文件
              uf.setUploadContentType(type);
              uf.setUploadFileName(fileName);
              uf.setUploadRealName(realName);
 
              uploadFiles.add(uf);// 添加到需要下载文件的List集合中
 
           
           }
           ServletActionContext.getRequest().setAttribute("uploadFiles",
                  uploadFiles);
 
       } catch (Exception e)
       {
           e.printStackTrace();
           addActionError(e.getMessage());
 
           return INPUT;
       }
 
       return SUCCESS;
 
    }
 
    public File[] getUpload()
    {
       return upload;
    }
 
    public void setUpload(File[] upload)
    {
       this.upload = upload;
    }
 
    public String[] getUploadContentType()
    {
       return uploadContentType;
    }
 
    public void setUploadContentType(String[] uploadContentType)
    {
       this.uploadContentType = uploadContentType;
    }
 
    public String[] getUploadFileName()
    {
       return uploadFileName;
    }
 
    public void setUploadFileName(String[] uploadFileName)
    {
       this.uploadFileName = uploadFileName;
    }
 
    public static String getExt(String fileName)
    {
       return fileName.substring(fileName.lastIndexOf("."));
    }
 
}
 
 
 
在此文件中要注意public InputStream getDownloadFile()的名称在Struts2配置文件配置,返回的是一个InputStream类型的对象。
 
package org.usc.file;
 
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import org.usc.utils.UploadConfigurationRead;
 
public class DownloadAction extends ActionSupport
{
    private static final long serialVersionUID = 6329383258366253255L;
    private String fileName;
    private String fileRealName;
    public void setFileName()
    {
       // 得到请求下载的文件名
       String fname = ServletActionContext.getRequest().getParameter("name");
       String frealname = ServletActionContext.getRequest().getParameter("realname");
       try
       {
           /*
            * 对fname参数进行UTF-8解码,注意:实际进行UTF-8解码时会使用本地编码,本机为GBK。
            * 这里使用request.setCharacterEncoding解码无效.
            * 只有解码了getDownloadFile()方法才能在下载目录下正确找到请求的文件
            */
           fname = new String(fname.getBytes("ISO-8859-1"), "UTF-8");
           frealname= new String(frealname.getBytes("ISO-8859-1"), "UTF-8");
       } catch (Exception e)
       {
           e.printStackTrace();
       }
       this.fileName = fname;
       this.fileRealName = frealname;
//     System.out.println(fileName);
//     System.out.println(fileRealName);
    }
 
    /*
     * @getFileName 此方法对应的是struts.xml文件中的: <param
     * name="contentDisposition">attachment;filename="${fileName}"</param>
     * 这个属性设置的是下载工具下载文件时显示的文件名, 要想正确的显示中文文件名,我们需要对fileName再次编码
     * 否则中文名文件将出现乱码,或无法下载的情况
     */
    public String getFileName() throws UnsupportedEncodingException
    {
 
       fileRealName = new String(fileRealName.getBytes(), "ISO-8859-1");
 
       return fileRealName;
    }
 
    /*
     * @getDownloadFile 此方法对应的是struts.xml文件中的: <param
     * name="inputName">downloadFile</param> 返回下载文件的流,可以参看struts2的源码
     */
    public InputStream getDownloadFile()
    {
 
       this.setFileName();
       return ServletActionContext.getServletContext().getResourceAsStream("/"+UploadConfigurationRead.getInstance().getConfigItem("uploadFilePath").trim()+"/" + fileName);
    }
 
    @Override
    public String execute() throws Exception
    {
       return SUCCESS;
    }
}
动态读取配置文件,借鉴网上的代码
 
package org.usc.utils;
import java.io.File;
import java.io.FileInputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;
/**
 * 动态读取配置文件类
 * 
 * @author MZ
 *
 * @Time 2009-11-24下午08:25:22
 */
public class UploadConfigurationRead {
 
    /**
     * 属性文件全名,需要的时候请重新配置PFILE
     */
    private static String PFILE = "upload.properties";
 
    /**
     * 配置文件路径
     */
    private URI uri = null;
 
    /**
     * 属性文件所对应的属性对象变量
     */
    private long m_lastModifiedTime = 0;
 
    /**
     * 对应于属性文件的文件对象变量
     */
    private File m_file = null;
 
    /**
     * 属性文件所对应的属性对象变量
     */
    private Properties m_props = null;
 
    /**
     * 唯一实例
     */
    private static UploadConfigurationRead m_instance = new UploadConfigurationRead();
 
    /**
     * 私有构造函数
     * 
     * @throws URISyntaxException
     */
    private UploadConfigurationRead() {
       try {
           m_lastModifiedTime = getFile().lastModified();
           if (m_lastModifiedTime == 0) {
              System.err.println(PFILE + "file does not exist!");
           }
           m_props = new Properties();
           m_props.load(new FileInputStream(getFile()));
 
       } catch (URISyntaxException e) {
           System.err.println(PFILE+"文件路径不正确");
           e.printStackTrace();
       } catch (Exception e) {
           System.err.println(PFILE+"文件读取异常");
           e.printStackTrace();
       }
    }
 
    /**
     * 查找ClassPath路径获取文件
     * 
     * @return File对象
     * @throws URISyntaxException
     */
 
    private File getFile() throws URISyntaxException {
       URI fileUri = this.getClass().getClassLoader().getResource(PFILE).toURI();
       m_file = new File(fileUri);
       return m_file;
    }
 
    /**
     * 静态工厂方法
     * 
     * @return 返回ConfigurationRead的单一实例
     */
    public synchronized static UploadConfigurationRead getInstance() {
       return m_instance;
    }
 
    /**
     * 读取一特定的属性项
     */
    public String getConfigItem(String name, String defaultVal) {
       long newTime = m_file.lastModified();
       // 检查属性文件是否被修改
       if (newTime == 0) {
           // 属性文件不存在
           if (m_lastModifiedTime == 0) {
              System.err.println(PFILE + " file does not exist!");
           } else {
              System.err.println(PFILE + " file was deleted!!");
           }
           return defaultVal;
       } else if (newTime > m_lastModifiedTime) {
           m_props.clear();
           try {
              m_props.load(new FileInputStream(getFile()));
           } catch (Exception e) {
              System.err.println("文件重新读取异常");
              e.printStackTrace();
           }
       }
       m_lastModifiedTime = newTime;
       String val = m_props.getProperty(name);
       if (val == null) {
           return defaultVal;
       } else {
           return val;
       }
    }
 
    /**
     * 读取一特定的属性项
     * 
     * @param name
     *            属性项的项名
     * @return 属性项的值(如此项存在), 空(如此项不存在)
     */
    public String getConfigItem(String name) {
       return getConfigItem(name, "");
    }
 
}
 
 
在IE(遨游)中多文件上传

在IE(遨游)中多文件下载

在Firefox中多文件上传

在Firefox中多文件下载

在Chrome中多文件上传

在Chrome中多文件下载

服务器中所以文件

FileUpLoadAndDownLoad 
multi-files-upload-and-download(maven)
为了有更好得兼容性,这个小demo已经移植到用maven构建(有些网页反映在eclipse里面部署失败),你可以下载上面的标记为maven的源码,或者通过
svn checkout http://usc.googlecode.com/svn/trunk/multi-files-upload-and-download/  
or
后,自己进行maven install并部署。 
如果你已经看到这儿了,那就请再欣赏 使用Struts2上传图片存取到Mysql中并读取出来显示在页面上 另一篇有点类似的博客吧,谢谢。
实际上,这个还可以进行扩展,可以存取上传的文件名和路径到数据库中,再在UI(jsp)上面根据需求进行显示文件,并提供下载,仅抛下砖头了,其它的...如果有什么建议或意见可以通过Q:506817493 或 E:leeshunli<at>qq.com,大家一起交流。
 
顺利写于2009年11月24日
最后更新于2013年4月12日
博客中的一些下载已经放到了百度云了,请根据需要下载。【点我去百度云下载】
最后弱弱地说一下,如果可以的话,转载请提供出处(
),谢谢。
 
	posted on 2010-01-07 21:21 
李顺利 阅读(27297) 
评论(38)  编辑  收藏