1. 程式人生 > >JavaWeb框架_Struts2_(七)----->文件的上傳和下載

JavaWeb框架_Struts2_(七)----->文件的上傳和下載

change oid clas character 下載頁面 esp 分享 msi gpo

  

  這個章節是Struts2框架應用最廣泛的三個版塊(上傳下載、國際化、校驗輸入)之一,所以這一版塊的學習還蠻重要的。

1. 章節目錄

  • Struts2文件上傳
    • 單文件上傳
    • 攔截器實現文件過濾
    • 文件上傳常量配置
    • Struts2多文件上傳
  • 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) 最後的下載窗口:

技術分享圖片

JavaWeb框架_Struts2_(七)----->文件的上傳和下載