• JavaWeb框架_Struts2_(七)----->文件的上传和下载


    1.  前言

       

      这个章节是Struts2框架应用最广泛的三个版块(上传下载、国际化、校验输入)之一,所以这一版块的学习还蛮重要的。

    2.  具体内容

    2.1Struts2文件上传

    2.1.1单文件上传

      本小节通过一个示例讲解Struts2如何实现单文件的上传。

    (1) 先写一个选择上传单文件页面(select.jsp)

    <%@ taglib prefix="s" uri="/struts-tags" %>
    <%--
      Created by IntelliJ IDEA.
      User: mairr
      Date: 17-12-7
      Time: 下午9:04
      To change this template use File | Settings | File Templates.
    --%>
    
    
    <%@ page contentType="text/html;charset=UTF-8" import="java.util.*" language="java" pageEncoding="UTF-8" %>
    
    <html>
    <head>
        <title>upload_test</title>
    </head>
    
    <body>
        <s:form action="upload" method="post" theme="simple" enctype="multipart/form-data">
            输入帐号:<s:textfield name="uid"/><br>
            选择头像:<s:file name="headImage"/><br>
            <s:submit value="提交"/>
        
         <s:fielderror/>
        
    </s:form> </body> </html>

      如下所示的一个上传选择界面框:

    (2) 当文件上传页面提交请求时,请求发送到upload.action,这是一个Struts2的Action,该Action处理上传请求,具体的UploadAction类代码如下:

    package action;
    
    import com.opensymphony.xwork2.ActionSupport;
    import org.apache.commons.io.FileUtils;
    import org.apache.struts2.ServletActionContext;
    import java.io.File;
    import java.io.IOException;
    
    public class UploadAction extends ActionSupport {
        private String uid;                 // 封装帐号(uid)请求参数属性
        private File headImage;             // 封装上传文件域属性
        private String headImageContentType;     // 封装上传文件类型的属性
        private String headImageFileName;     // 封装上传文件属性
    
        public String getUid() {
            return uid;
        }
        public void setUid(String uid) {
            this.uid = uid;
        }
    
        public File getHeadImage() {
            return headImage;
        }
        public void setHeadImage(File headImage) {
            this.headImage = headImage;
        }
    
        public String getHeadImageContentType() {
            return headImageContentType;
        }
        public void setHeadImageContentType(String headImageContentType) {
            this.headImageContentType = headImageContentType;
        }
    
        public String getHeadImageFileName() {
            return headImageFileName;
        }
        public void setHeadImageFileName(String headImageFileName) {
            this.headImageFileName = headImageFileName;
        }
    
        public String execute() throws IOException {
            // 上传文件的保存位置在“/image”,该位置在tomcat服务器的“webapps”之中
            String  realpath= ServletActionContext.getServletContext().getRealPath("/image");
    
            // 声明文件目录image,如果文件名不存在就建一个呗~
            File file = new File(realpath);
            if(!file.exists()){
                file.mkdirs();
            }
    
            // 实现文件上传,也就是做了一个方法调用~
            FileUtils.copyFile(headImage,new File(file,headImageFileName));
            return SUCCESS;
        }
    }

      需要注意的是,上面的Action除了包含两个表单域的name属性外,还包含headImageContentType和headImageFileName两个属性,这两个属性分别能用于封装上传文件的文件类型、上传文件的文件名。可以这样认为:如果表单中包含一个name属性为xxx的文件域,则对应的Action需要使用3个属性来封装文件域信息:

    1. 类型为java.io.File的xxx属性来封装文件域的信息;
    2. 类型为String的xxxFileName属性封装了该文件域对应的文本内容;
    3. 类型为String的xxxContentType属性封装了该文件域对应的文件类型

       所以,在Action的execute方法中,可以直接通过这3个属性获取上传文件的文件名、文件类型和文件内容。

    (3) 接下来进行UploadAction的配置(struts.xml文件配置),具体代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
            "http://struts.apache.org/dtds/struts-2.5.dtd">
    
    <struts>
        <!--指定国际化资源文件(下一章会讲到)-->
        <constant name="struts.custom.i18n.resources" value="messageResource"/>
    
        <!--设置Struts应用的解码集-->
        <constant name="struts.i18n.encoding" value="utf-8"/>
       
      <!-- --- 包配置 ---- --> <package name="default" namespace="/" extends="struts-default"> <action name="upload" class="action.UploadAction"> <result>/uploadSuccess.jsp</result> </action> </package> </struts>

    (4) 最后写一个上传成功页面(uploadSuccess.jsp)

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <html>
    <head>
        <title>上传初始页</title>
    </head>
    <body>
        上传成功!<br>
    
        <!--输入表单里的用户帐号属性-->
        用户帐号:<s:property value="uid"/><br>
    
        <!--根据上传文件名字,显示上传头像-->
        您的头像:<img src="<s:property value="'image/' + headImageFileName"/> " alt="图像无法显示"/>
    </body>
    </html>

      上传过程图:

      (a)选择图片

      (b)确认选择

      (c)提交之后,显示上传成功

    2.1.2 拦截器实现文件的过滤

      Struts2提供了一个名为fileUpload拦截器,通过配置该拦截器可以轻松地实现文件过滤。为了让fileUpload拦截器起作用,只需要在处理文件上传的Action中配置该拦截器引用即可。
      配置fileUpload拦截器时可以指定如下两个参数:

    1. allowTypes:该参数指定允许上传文件的类型,多个文件类型之间以英文逗号隔开;
    2. maximumSize:该参数指定允许上传文件的大小,单位是字节。

      当文件过滤失败后,系统自动转入input逻辑视图,因此必须为Action配置名为input的逻辑视图。

    (1) 通过拦截器来实现文件过滤的struts.xml配置文件如下:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
            "http://struts.apache.org/dtds/struts-2.5.dtd">
    
    <struts>
        <!--指定国际化资源文件(下一讲会讲到)-->
        <constant name="struts.custom.i18n.resources" value="messageResource"/>
    
        <!--设置Struts应用的解码集-->
        <constant name="struts.i18n.encoding" value="utf-8"/>
    
        <!--package中加入拦截器-->
        <package name="default" namespace="/" extends="struts-default">
            <interceptors>
                <!--配置拦截器栈(在拦截器章节有讲述)-->
                <interceptor-stack name="myStack">
                    <!--配置fileUpload拦截器-->
                    <interceptor-ref name="fileUpload">
                        <!--配置允许上传文件的类型(此处要注意的是png图片在ie浏览器中是image/x-png类型)-->
                        <param name="allowedTypes">image/x-png,image/bmp,image/gif,image/jpeg,image/jpg</param>
                        <!--配置允许上传文件大小拦截器,单位是字节(2的16次幂=65536(64k))-->
                        <param name="maximumSize">65536</param>
                    </interceptor-ref>
                    <interceptor-ref name="defaultStack"/>
                </interceptor-stack>
            </interceptors>
    
            <action name="upload" class="action.UploadAction">
                <!--使用拦截器栈-->
                <interceptor-ref name="myStack"/>
                <result>/uploadSuccess.jsp</result>
    
                <!--过滤失败,系统会转入input逻辑视图,这里配置其返回选择界面-->
                <result name="input">/select.jsp</result>
            </action>
        </package>
    </struts>

      格式不对和容量大于64kb会上传失败,直接返回重新选择的界面。如果上传失败,系统需要回应上传失败信息。因此,需要在文件上传页selectFile.jsp页面中加上“<s:filederror/>”------->(我直接加到了selectFile.jsp代码中,你可以回看上面)

    (a) 文件格式不对

    ------(提交之后)------->

     

     

    (b) 文件大小超过了限额

    -------(提交之后)----->

     

    2.1.3  文件上传的常量配置

     

       上传文件时,系统默认使用web服务器的工作路径作为临时路径。为了避免文件上传时候使用Web服务器的工作路径作为临时路径,则应该设置struts.multipart.saveDir常量。该常量指定上传文件的临时保存路径。该常量配置示例如下:

     <constant name="struts.multipart.saveDir" value="HOME/....(写上路径)..."/>

      此外,还有一个文件上传的常量struts.multipart.maxSize。该常量指定struts.mutipart.maxSize。该常量指定在struts2文件上传中整个请求内容所允许的最大字节数,默认为2097152(即2MB)。该常量配置示例如下:

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

    2.1.4  Struts2多文件上传

      在Struts2应用中,如果一个页面有多个文件域需要实现上传,则可以为每个文件域提供三个属性,分别封装该文件域对应的文件名、文件类型和文件内容。多文件上传与单文件上传没有什么区别,仅仅是利用数组同时上传多个文件的方式。

      在处理多文件上传时,要注意改变的是,在Action类中,需要使用三个数组分别封装文件名、文件类型和文件内容

     // 实现单文件上传代码如下:
    FileUtils.copyFile(headImage,new File(file,headImageFileName));
    
            
     // 实现多文件下载代码如下:
    for(int i = 0; i < headImage.length(); i++){
        File uploadImage = headImage[i];
        FileUtils.copyFile(uploadImage,new File(file,headImageFileName[i]));
     }

     2.2  Struts2文件下载

     

      利用Struts2来处理文件的下载的问题时,能够解决下载文件的文件名为中英文等等都不出现乱码。此外,还能够在用户下载之前进行检查,判断用户是否有足够的权限来下载该文件等。下面用一个示例来讲解文件的下载:

     

    (1) 先写一个下载页面:(index.jsp)

    <%--
      Created by IntelliJ IDEA.
      User: mairr
      Date: 17-12-9
      Time: 下午2:20
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    
    
    <html>
      <head>
        <title>test_download</title>
      </head>
      <body>
        请下载中文课件:<a href="downLoad.action?downPath=第一章节.doc"></a><br>
        请下载英文课件:<a href="downLoad.action?downPath=chapter01.doc"></a><br>
      </body>
    </html>

    (2) 在Struts2框架文件下载Action类中,需要提供一个返回InputStream流方法,该输入流代表了被下载文件的入口。该Action类代码如下所示:(DownLoadAction.java)

    package action;
    
    import com.opensymphony.xwork2.ActionSupport;
    import org.apache.struts2.ServletActionContext;
    import util.MyUtil;
    import java.io.InputStream;
    import java.io.UnsupportedEncodingException;
    
    public class DownLoadAction extends ActionSupport{
    
        private String downPath;        // 下载时的文件名
        private String contentType;     // 保存文件类型
        private String filename;        // 保存时的文件名
    
        public String getContentType() {
            return contentType;
        }
    
        public void setContentType(String contentType) {
            this.contentType = contentType;
        }
    
        public String getFilename() {
            return filename;
        }
    
        public void setFilename(String filename) {
            this.filename = filename;
        }
    
        public String getDownPath() {
            return downPath;
        }
        public void setDownPath(String downPath) {
            try {
                // 解决下载时候的中文文件乱码问题
                downPath = new String(downPath.getBytes("ISO-8859-1"),"UTF-8");
            }catch (UnsupportedEncodingException e){
                e.printStackTrace();
            }
            this.downPath = downPath;
        }
    
       /*
        *下载用的Action返回一个InputString实例,该方法对应Action配置
        *里面的result的inputName参数,值为inputString
        *
        */
    
       public InputStream getInputString(){
           return ServletActionContext.getServletContext().getResourceAsStream(downPath);
       }
    
       public String execute(){
           // 下载保存时的文件名和被下载的文件名一样
           filename = downPath;
           // 下载的文件路径,请在webapps目录下创建images
           downPath = "images/" + downPath;
           // 保存文件的类型
    
           contentType = "application/x-msdownload";
    
           /*
            *对下载的文件名按照UTF-8进行编码,解决下载窗口中的中文乱码问题
            * 其中,MyUtil是自己定义的一个类
            */
    
           filename = MyUtil.toUTF8String(filename);
           return SUCCESS;
       }
    }

    (3) 在上述的Action类中定义了一个工具类MyUtil,该类中有一个静态方法toUTF8String实现对下载的文件名按照UTF-8进行编码,解决下载窗口中中文乱码的问题:(MyUtil.java)

    package util;
    
    import java.io.UnsupportedEncodingException;
    
    public class MyUtil {
        // 对下载文件按照 UTF-8 进行编码
    
        public static String toUTF8String(String str){
            StringBuffer sb = new StringBuffer();
            int len = str.length();
            for (int i = 0; i < len; i++)
            {
                // 取出字符中的每个字符
                char c = str.charAt(i);
                // Unicode码值在0~255之间,不做处理
                if(c>=0 && c <= 255){
                    sb.append(c);
                }else {
                    // 转换 UTF-8 编码
                    byte b[];
                    try{
                        b = Character.toString(c).getBytes("UTF-8");
                    }catch(UnsupportedEncodingException e){
                        e.printStackTrace();
                        b = null;
                    }
                    // 转换为%HH的字符串形式
                    for(int j = 0;j < b.length ; j++){
                        int k = b[j];
                        if(k < 0){
                            k &= 255;
                        }
                        sb.append("%" + Integer.toHexString(k).toUpperCase());
                    }
                }
            }
            return sb.toString();
        }
    }

    (4) 最后,完成Action的配置,关键是要配置一个类型为stream的结果,配置时需要指定如下四个属性:

    • contentType:  指定被下载文件的文件类型;
    • inputName:  指定被下载文件的入口输入流;
    • contentDisposition:  指定下载的文件名;
    • bufferSize:  指定下载文件时的缓冲大小。

      具体代码如下:(struts.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
            "http://struts.apache.org/dtds/struts-2.5.dtd">
    
    <struts>
        <package name="default" namespace="/" extends="struts-default">
            <action name="downLoad" class="action.DownLoadAction">
                <!--结果类型为String-->
                <result type="stream">
    
                    <param name="contentType">${contentType}</param>
                    <!--默认就是inputStream,它将会指示StreamResult通过
                      inputName属性值的getter和setter方法,如这里就是
                      getInputStream()来获取下载文件的内容,意味着Action
                      要有这个方法
                      -->
                    <param name="inputName">inputStream</param>
                     <!--默认为inline(在线打开),设置为attachment将会告诉浏览器下载
                         该文件,filename指定下载文件时的文件名,若未指定将会以浏览器
                         页面名作为文件名,如:以download.action作为文件名
                       -->
                    <param name="contentDisposition">attachment;filename=${filename}</param>
                    <!--指定下载文件的缓冲大小-->
                    <param name="bufferSize">4096</param>
    
                </result>
            </action>
        </package>

    (5)  最后的下载窗口:

     

     

  • 相关阅读:
    RabbitMq的死信队列和延迟队列
    Rabbitmq的过期时间
    技术干货 | 源码解析 Github 上 14.1k Star 的 RocketMQ
    深入分析 Flutter 渲染性能
    重磅发布 阿里云数据中台全新产品DataTrust聚焦企业数据安全保障
    DataWorks搬站方案:Airflow作业迁移至DataWorks
    DataWorks搬站方案:Azkaban作业迁移至DataWorks
    基于 Flutter 的 Web 渲染引擎「北海」正式开源!
    走完线上 BUG 定位最后一公里
    10种编程语言实现Y组合子
  • 原文地址:https://www.cnblogs.com/Mairr/p/8005178.html
Copyright © 2020-2023  润新知