Struts2 實現上傳附件(支持多附件)

原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處 、作者信息和本人聲明。否則將追究法律責任。
作者:永恆の_☆    地址:http://blog.csdn.net/chenghui0317/article/details/9531879

一、簡單介紹

     使用Struts2上傳附件功能非常容易實現,只需要使用普通的Action類 用來獲取上傳的附件對象,然後保存到指定的路徑下即可。基本原理和Servlet上傳附件一樣,只不過封裝附件的方式實現不一樣罷了。servlet上傳附件的地址:http://blog.csdn.net/ch656409110/article/details/9502143


二、準備條件

     準備一個struts2環境的項目

    common-io.jar  ,下載地址:http://commons.apache.org/io/download_io.cgi

    common-upload.jar ,下載地址:http://jakarta.apache.org/commons/fileupload/


三、實現思路

    準備一個上傳附件的頁面,代碼如下:

<form name="saveForm" action="${ctx}/house/save.action" method="post" οnsubmit="return checkSaveHouseForm();" enctype="multipart/form-data">
    <tr>
        <td class="field">上傳附件:</td>
        <td>
            <input type="file" name="upload" class="text" οnblur="checkUpload()"/> 
            <span id="sp_upload" class="message"></span>
            <br />
        </td>
    </tr>
    <tr>
        <td class="field">附件名稱:</td>
        <td>
            <input type="text" name="fileName" class="text"/>
        </td>
    </tr>
    <div class="buttons"><input type="submit" name="submit" value="發佈"/></div>
</form>

頁面中定義的附件控件名稱是 upload,那麼在Action類中也要定義相同的upload屬性,如下:

    private File upload;   //upload file
    private String uploadFileName;   //附件名稱
    private String uploadContentType; //附件類型
    private String savePath;    //附件保存的路徑
    private List<String> fileName ;  //用戶輸入的名稱
    //省略get set方法

需要注意的是,如果定義附件對象的附加屬性,要以附件對象爲前綴,比如upload爲名的附件。

並且savePath的get方法要去讀取才能獲得,代碼如下:

	public synchronized String getSavePath() {
		return ServletActionContext.getServletContext().getRealPath(savePath);
	}

封裝好對象之後,接下來處理業務邏輯,具體代碼如下:

//處理上傳的附件
				System.err.println(upload.getAbsolutePath());
				System.err.println(upload.getName());
				System.err.println(uploadFileName);
				  
				fileName = fileName + uploadFileName.substring(uploadFileName.lastIndexOf("."));
				File target = new File(getSavePath(), fileName);
				//直接調用org.apache.commons.io.FileUtils下的copyFile 將上傳的附件複製到指定的目錄下
				//FileUtils.copyFile(upload, target);
				
				//另外還可以通過輸入流讀取字符之後 用輸出流寫入到磁盤中也是一樣的。
				OutputStream outputStream = new FileOutputStream(new File(getSavePath(),fileName));
				InputStream inputStream = new FileInputStream(getUpload());
				
				byte[] buffers = new byte[1024];
				int length = 0;
				while((length = inputStream.read(buffers))!=-1){
					outputStream.write(buffers, 0, length);
				}
				inputStream.close();
				outputStream.close();
				
				house.setAttachUrl(savePath + Constant.SEPARATOR + fileName);
				houseBiz.saveHouse(house);
				
				ServletActionContext.getRequest().setAttribute("attachurl", house.getAttachUrl());

上面代碼中 有兩種實現將上傳的附件放到指定目錄的方法,都可以實現的。另外第一種更加方便一些,直接調用org.apache.commons.io.FileUtils下的copyFile 將上傳的附件複製到指定的目錄下。

然後struts.xml配置文件中需要配置一下我們action的跳轉,以及附件保存路徑等等信息,具體如下:

	<package name="house" namespace="/house" extends="struts-default">
		<action name="*" class="com.struts2.web.action.HouseAction" method="{1}">
			<result name="listPage">/WEB-INF/system/page/house_list.jsp</result>
			<result name="detail">/WEB-INF/system/page/house_detail.jsp</result>
			<result name="detail">/WEB-INF/system/page/house_detail.jsp</result>
			<result name="loadSuccess">/WEB-INF/system/page/saveHouse.jsp</result>
			
			<param name="savePath">/attach</param>
             <interceptor-ref name="defaultStack">
                   <!-- 配置允許上傳的文件類型,多個用","分隔 -->
                   <param name="fileUpload.allowedTypes">
                     image/bmp,image/png,image/gif,image/jpeg,image/jpg ,image/x-png, image/pjpeg
                   </param>
                   <!-- 配置允許上傳的文件大小,單位字節 -->
                   <param name="fileUpload.maximumSize">102400</param>
             </interceptor-ref>
			<result name="saveSuccess">/WEB-INF/system/page/saveHouseSuccess.jsp</result>
			<result name="input">/WEB-INF/system/page/saveHouseFail.jsp</result>
		</action>
	</package>

這裏需要指定上傳的附件指定的位置,即加一個<param>標籤就好了,然後指定 上傳的附件的限制類型、以及上傳大小。

然後下面這種配置 是網上很多,反正我試了很多次,都不起作用。

<interceptor-ref name="fileUpload">  
    <param name="allowedTypes">image/jpg,image/png,image/gif,image/jpeg,image/pjpeg</param>  
    <param name="maximunSize">10000</param>  
</interceptor-ref>  
<interceptor-ref name="defaultStack"></interceptor-ref> 
實踐證明  <interceptor-ref name="defaultStack"></interceptor-ref> 必須加上,否則接收的所有參數都爲null,因爲上面有引用fileUpload這個攔截器。


接下來就可以部署項目,啓動服務器運行了。

首先選擇附件,效果如下:



選擇發佈按鈕,然後服務器就會進行上傳操作。效果如下:

然後  在控制檯可以在到action中輸出的上傳附件信息。效果如下:


可見,在請求提交後服務器先把附件放在服務器的一個臨時文件夾下,當真正上傳成功後就會把該臨時文件刪除。


這樣,使用struts2上傳單個文件效果完成了。


四、多附件上傳

接下來看看多附件上傳,在upload上傳頁面肯定需要多個file控件,代碼如下:

<form name="saveForm" action="${ctx}/house/save.action" method="post" οnsubmit="return checkSaveHouseForm();" enctype="multipart/form-data">
    <tr>
        <td class="field">上傳附件:</td>
        <td>
            <input type="file" name="upload" class="text" οnblur="checkUpload()"/> 
            <span id="sp_upload" class="message"></span>
            <br />
        </td>
    </tr>
    <tr>
        <td class="field">附件名稱:</td>
        <td>
            <input type="text" name="fileName" class="text"/>
        </td>
    </tr>
    <tr>
        <td class="field">上傳附件:</td>
        <td>
            <input type="file" name="upload" class="text"/> 
            <br />
        </td>
    </tr>
    <tr>
        <td class="field">附件名稱:</td>
        <td>
            <input type="text" name="fileName" class="text" οnblur="checkFileName()"/>
            <span id="sp_fileName" class="message"></span>
        </td>
    </tr>
</table>
<div class="buttons"><input type="submit" name="submit" value="發佈"/></div>
</form>
較上面而言 僅僅多了一個附件控件 和 附件名稱控件。

然後後臺需要改了,原先單個附件上傳可以定義FIle 類型的對象接收參數,現在可是多個。所以需要重新定義屬性,代碼如下:

    private List<File> upload;   //upload file
    private List<String> uploadFileName;   //附件名稱
    private List<String> uploadContentType; //附件類型
    private String savePath;    //附件保存的路徑
    private List<String> fileName ;  //用戶輸入的名稱
    //省略了get set 方法

實踐 發現,這裏定義 List 類型或者該屬性原有類型的數組 都可以接收成功,可見struts2還是蠻強大的。

比如:

    private File[] upload;   //upload file
    private String[] uploadFileName;   //附件名稱
    private String[] uploadContentType; //附件類型
    private String savePath;    //附件保存的路徑
    private String[] fileName ;  //用戶輸入的名稱
    //省略了get set 方法

然後處理上傳的時候需要用循環來依次上傳,具體代碼如下:

//處理上傳的附件  
				if(upload!=null){
					for (int i=0; i<upload.size(); i++) {
						fileName.set(i, fileName.get(i) + uploadFileName.get(i).substring(uploadFileName.get(i).lastIndexOf(".")));
						File target = new File(getSavePath(), fileName.get(i));
						//直接調用org.apache.commons.io.FileUtils下的copyFile 將上傳的附件複製到指定的目錄下
						//FileUtils.copyFile(upload, target);
						
						//另外還可以通過輸入流讀取字符之後 用輸出流寫入到磁盤中也是一樣的。
						OutputStream outputStream = new FileOutputStream(new File(getSavePath(),fileName.get(i)));
						InputStream inputStream = new FileInputStream(getUpload().get(i));
						
						byte[] buffers = new byte[1024];
						int length = 0;
						while((length = inputStream.read(buffers))!=-1){
							outputStream.write(buffers, 0, length);
						}
						inputStream.close();
						outputStream.close();
						if(house.getAttachUrl()!=null && !house.getAttachUrl().equals("")){
							house.setAttachUrl(house.getAttachUrl() + "," + savePath + Constant.SEPARATOR + fileName.get(i));
						}else{
							house.setAttachUrl(savePath + Constant.SEPARATOR + fileName.get(i));
						}
					}
				}
				houseBiz.saveHouse(house);
				
				ServletActionContext.getRequest().setAttribute("attachurl", house.getAttachUrl());

顯示上傳後的代碼具體如下:

		<div class="box">
			<div class="msg">
				<p>恭喜:添加住房成功!</p>
				<p><a href="${ctx}">返回首頁</a></p>
				<%
					String attachurl = (String)request.getAttribute("attachurl");
					if(attachurl!=null){
						String []strs = attachurl.split(",");
						for(int i=0; i<strs.length; i++){
							out.print("<img src='"+request.getContextPath()+strs[i]+"' width='400' height='270'/><br/><br/>");	
						}
					}
				%>
			</div>
		</div>
ok,再重新部署,啓動服務器然後在執行一遍,效果如下圖:

點擊發布按鈕,效果如下:


界面上是成功了,然後在去附件指定目錄查看 是否真正成功。

這樣,多附件上傳就成功完成了。


五、限制上傳的附件類型和大小

前面已經配置的很清楚了,當我們想要過濾一些不好的情況,比如上傳附件的大小上限,以及類型的限制。可以先在前臺判斷,當然如果前臺被屏蔽了 就只能通過後臺再次判斷上傳的附件是否滿足需求,否則服務器會被搞垮的。

當附件的大小超過上限,默認的2M大小,如果給超過上限 就不會傳到服務器,服務器不會拋出異常,進入sturts.xml中配置的input對應的頁面,然後可以在頁面中添加

<s:fielderror></s:fielderror> 標籤捕捉具體異常。

  具體異常信息顯示如下圖所示:

當上傳的附件不是圖片格式的話,也不會上傳到服務器,會顯示如下結果:


這樣子顯示好嗎?感覺不太友好,全是一片英文字母。所以爲了友好顯示後臺拋出的異常可以這樣:

在處理上傳附件的Action中重寫addActionError(),當異常類型是超出上限的時候我就修改提示,具體代碼如下:

	@Override
	public void addActionError(String anErrorMessage) {
	    if (anErrorMessage.startsWith("the request was rejected because its size")) {
	    	super.addActionError("抱歉,你上傳的文件超過了上限 !!");
	    } else {
	    	super.addActionError(anErrorMessage);
	    }
	}

說實話,這種方式在我以前的項目中可以實現,但是這裏一直不成功,我也不知道爲什麼。。。。

不過可以用另一種方法,給struts指定一個屬性文件,比如struts.properties  ,直接放在classpath的根目錄下。

例子如下:

struts.messages.error.content.type.not.allowed=\u62B1\u6B49\uFF0C\u60A8\u4E0A\u4F20\u7684\u9644\u4EF6\u4E0D\u662F\u56FE\u7247\u683C\u5F0F\u7684\uFF01
struts.messages.error.file.too.large=\u62B1\u6B49\uFF0C\u60A8\u4E0A\u4F20\u7684\u9644\u4EF6\u592A\u5927\uFF0C\u6700\u591A10M!
struts.messages.error.uploading=\u62B1\u6B49\uFF0C\u4E0A\u4F20\u51FA\u9519\u4E86\uFF01
然後在struts的配置文件中指定一下,就好了,具體如下:
<!-- 指定struts屬性文件 -->
<constant name="struts.custom.i18n.resources" value="struts" />

然後在試試看就會發現效果以前好多了,如下圖:


這個是附件太大的友好提示,因爲傳了兩個附件,所有顯示了兩個。


這個是附件類型錯誤的友好提示。


六、實現下載功能

 其實這個下載功能和在Servlet 中處理的實現方式一樣,所以不在累贅。servlet上傳附件的地址:http://blog.csdn.net/ch656409110/article/details/9502143







發佈了67 篇原創文章 · 獲贊 47 · 訪問量 77萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章