Struts2之文件上传与下载

 

时间:2017-1-11 15:47

 

——使用commons-fileupload组件上传

1、客户端
    *   method="post"
    *   <input type="file" name="xx" />
    *   encType="multipart/form-data"

2、服务器端
    使用commons-fileupload。
    *   DiskFileItemFactory
    *   ServletFileUpload
    *   FileItem

——Struts2文件上传

默认情况下,Struts2框架使用commons-fileupload组件进行上传操作,所以需要导入commons-fileupload.jar。

Struts2使用了一个interceptor帮助我们完成文件上传操作:
    <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>

实现文件上传操作:

    页面中:

        <form action="${pageContext.request.contextPath }/upload" method="post" enctype="multipart/form-data">
            <input type="file" name="file" />
            <input type="submit" value="上传" />
        </form>

        如果要同时上传多个文件,那么所有"file"的name属性值必须相同。 


    Action中:
        public class UploadAction extends ActionSupport {

            /*
             * 在Action类中需要声明三个属性
             */
            private File file; // 上传文件,名称必须与表单页面中的name值相同
            private String fileContentType; // 上传文件类型,名称格式:name + ContentType
            private String fileFileName; // 上传文件名,名称格式:name + FileName
 
            /*
             * 在FileUploadInterceptor中有如下三行代码,所以起名必须要规范
             * String inputName = (String) fileParameterNames.nextElement();
             * String contentTypeName = inputName + "ContentType";
             * String fileNameName = inputName + "FileName";
             */
            @Override
            public String execute() throws Exception {
                System.out.println("上传文件的类型:" + fileContentType);
                System.out.println("上传文件的名称:" + fileFileName);
 
 
                // 完成文件上传
                // 使用FileUtils的copyFile()方法将文件的输入流输出到指定位置
                FileUtils.copyFile(file, new File("f:/upload", fileFileName));
 
                return NONE;
            }
            public File getFile() {
                return file;
            }
            public void setFile(File file) {
                this.file = file;
            }
            public String getFileContentType() {
                return fileContentType;
            }
            public void setFileContentType(String fileContentType) {
                this.fileContentType = fileContentType;
            }
            public String getFileFileName() {
                return fileFileName;
            }
            public void setFileFileName(String fileFileName) {
                this.fileFileName = fileFileName;
            }
        }



——Struts2中文件上传细节

1、控制上传文件大小
    在default.properties文件中定义了上传文件的大小:
        struts.multipart.maxSize=2097152 上传文件大小默认2M
    超出文件大小时,跳转到input视图,通过<s:actionerror />显示错误信息。

    可以在struts.xml文件中重新定义常量来修改上传文件大小限制。

    <constant name="struts.multipart.maxSize" value="86170804"/>
 


2、修改显示错误信息
    默认在页面中显示的错误信息是英文的,可以在Struts2核心包下的struts-message.properties文件中找到预定义上传错误信息,在国际化文件中通过覆盖对应key显示错误信息:

    // 上传错误:{0}

    struts.messages.error.uploading=Error uploading: {0}
    // 上传文件过大:{0} "{1}" "{2}" {3}
    struts.messages.error.file.too.large=The file is to large to be uploaded: {0} "{1}" "{2}" {3}
    // 上传文件不允许:{0} "{1}" "{2}" {3}
    struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
    // 上传文件扩展名不允许:{0} "{1}" "{2}" {3}
    struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
 
    # dedicated messages used to handle various problems with file upload - check {@link     JakartaMultiPartRequest#parse(HttpServletRequest, String)}
    struts.messages.upload.error.SizeLimitExceededException=Request exceeded allowed size limit! Max size allowed is: {0} but request was: {1}!
    struts.messages.upload.error.IOException=Error uploading: {0}!


    {0}:<input type=“file” name=“uploadImage”>中name属性的值
    {1}:上传文件的真实名称
    {2}:上传文件保存到临时目录的名称
    {3}:上传文件的类型(对struts.messages.error.file.too.large是上传文件的大小)
 
 


3、多文件上传时每个文件大小控制以及上传文件的扩展名限制

    多文件上传时,要将Action中的属性声明为List集合或者数组:
        private List<File> file;
        private List<String> fileContentType;
        private List<String> fileFileName;
    然后在excuete()方法中进行操作。

    怎样限制每一个上传文件的大小及其上传文件的类型?

    在FileUploadInterceptor中有如下代码:

        protected Long maximumSize;    // 表示每个上传文件的大小
        protected Set<String> allowedTypesSet = Collections.emptySet();    // 表示上传文件的类型
        protected Set<String> allowedExtensionsSet = Collections.emptySet();    // 表示上传文件的扩展名
 

       使用配置文件设置上传文件总大小,对所有上传form有效,如果只想对当前form进行设置,可以设置fileUplpad拦截器属性:
        *   maximumSize:上传文件的最大长度(以字节为单位),默认为2M。
        *   allowedTypes:允许上传的文件类型,各类型之间以逗号分隔。
        *   allowedExtendsions:允许上传文件扩展名,各扩展名之间以逗号分隔。

    例如:
        <action name="upload" class="com.wyc.action.UploadAction">

            <interceptor-ref name="defaultStack">
                <!-- 对fileUpload下的allowedExtension属性赋值 --> 
                <param name="fileUpload.allowedExtensions">txt,mp3,doc</param>
            </interceptor-ref>
            <result name="input">/upload.jsp</result>
        </action>

    如果针对fileUpload进行参数设置,当出错时,在页面通过<s:filedError />回显错误信息。      

4、在Struts2中默认使用的是commons-fileupload进行文件上传
    在default.properties文件中:
        # struts.multipart.parser=cos
        # struts.multipart.parser=pell
        struts.multipart.parser=jakarta    // jakarta表示apache开源项目
    可以修改默认上传方式。

    如果使用pell、cos进行文件上传,必须导入其jar包。



——文件下载

1、文件下载方式:
    超链接
    服务器编码,通过流向客户端写回。

    下载的要求
    两个头、一个流
        *   Content-Type:表示传递给客户端文件的MIME类型。
            >   通过文件名称调用ServletContext的getMimeType()方法得到MIME类型。
        *   Content-Disposition:
            >   它的默认值为inline,表示在浏览器窗口中打开(当打不开时会弹框)。
            >   attachment;filename=xxx:表示类型为附件,并在弹框的界面中显示下载的文件名。
        *   流:要下载的文件数据。
            >   自己new 一个输入流即可,然后通过IOUtils完成流的数据写入。

2、Struts中的文件下载
    通过<result type="stream">来完成。

    指定stream结果类型 需要指定一个 inputName参数,该参数指定一个输入流,提供被下载文件的入口。

    在struts-default.xml文件中可以找到stream结果视图:
        <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>

    在StreamResult类中有三个属性:
        *   protected String contentType = "text/plain";    // 该属性用于设置下载文件的MIME类型
        *   protected String contentDisposition = "inline";    // 该属性用于设置进行下载操作以及下载文件的名称
        *   protected InputStream inputStream;    // 该属性用于读取要下载的文件

    其中contentType、contentDisposition、inputStream可以在struts.xml文件中进行配置:
        <action name="download" class="com.wyc.action.DownloadAction">
            <result type="stream">
                <param name="contentType">text/plain</param>
                <param name="contentDisposition">attachment;filename=a.txt</param>
                <!-- ${inputStream}表示调用当前Action的getInputStream()方法,是ognl表达式,如果不设置,则默认"inputStream",可查看StreamResult源码 -->
                <param name="inputStream">${inputStream}</param>
            </result>
        </action>

    inputStream可以在Action获得,在Action类中定义一个方法:
        public InputStream getInputStream() throw FileNotFound {
            FileInputStream fis = new FileInputStream("F;/upload/" + filename);
            return fis;
        }

    然后直接在execute()方法中return SUCCESS即可。


3、文件乱码问题
    超链接下载的文件是中文名,会出现乱码情况,服务器会出错。

    解决方法:
        在getInputStream()方法中添加:
            filename = new String(filename.getBytes("iso-8859-1"), "utf-8");


4、动态获取下载文件名和文件类型
    在struts.xml文件中使用ognl表达式动态获取。
        <result type="stream">
            <!-- 调用当前Action中的getContentType()方法,得到其返回值 -->
            <param name="contentType">${contentType}</param>
            <param name="contentDisposition">attachment;filename=${downloadFileName}</param>
            <!-- ${inputStream}表示调用当前Action的getInputStream()方法,如果不设置,则默认"inputStream",可查看StreamResult源码 -->
            <param name="inputStream"></param>
        </result>


5、示例代码:

=============================================================================

DownloadAction:

package com.wyc.action;
 
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Base64;
 
import org.apache.struts2.ServletActionContext;
 
import sun.misc.BASE64Encoder;
 
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
 
public class DownloadAction extends ActionSupport {
 
    // 要下载文件的名称
    private String filename;
 
    public InputStream getInputStream() throws FileNotFoundException, UnsupportedEncodingException{
        filename = new String(filename.getBytes("iso-8859-1"), "utf-8");
 
        FileInputStream fis = new FileInputStream("f:/upload/" + filename);
        return fis;
    }
 
    // 获取下载文件MIME类型
    public String getContentType(){
        return ServletActionContext.getServletContext().getMimeType(filename);
    }
 
    /*
     * 获取下载文件名称
     * 解决浏览器差异问题
     */
    public String getDownloadFileName() throws UnsupportedEncodingException{
        String agent = ServletActionContext.getRequest().getHeader("User-Agent");
        if(agent.contains("MSIE")){
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        } else if (agent.contains("FireFox")) {
            // 火狐浏览器
            BASE64Encoder base64Encoder = new BASE64Encoder();
            filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其他浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
 
    @Override
    public String execute() throws Exception {
        System.out.println("进行下载...");

        // 直接return SUCCESS即可。 
        return SUCCESS;
 
    }
 
    public String getFilename() {
        return filename;
    }
 
    public void setFilename(String filename) {
        this.filename = filename;
    }
}
 
----------------------------------------------------------------------------------------------------------------------------

struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <package name="default" namespace="/" extends="struts-default">
        <action name="download" class="com.wyc.action.DownloadAction">
 
            <result type="stream">
                <!-- 调用当前Action中的getContentType()方法,得到其返回值 -->
                <param name="contentType">${contentType}</param>
                <param name="contentDisposition">attachment;filename=${downloadFileName}</param>
                <!-- ${inputStream}表示调用当前Action的getInputStream()方法,如果不设置,则默认"inputStream",可查看StreamResult源码 -->
                <param name="inputStream"></param>
            </result>
        </action>
    </package>
</struts>
posted @ 2017-02-07 18:18  WWWYC  阅读(229)  评论(0编辑  收藏  举报