08 08Struts 2.x文件上傳

如果你的代碼使用的是標準MVC開發的,那麼強烈建議使用SmartUpload完成,但是如果你的項目代碼使用的是框架開發,例如:Struts 1.x、Struts 2.x、Spring MVC,那麼就只能夠使用FileUpload,因爲這些框架針對於FileUpload的處理是比較方便的。

1 基礎上傳

如果現在使用的是Struts 1.x,那麼要接收上傳文件的時候使用的是一個FormFile類,但是這個類雖然包裝了許多的內容,不過從實際來講,有些多餘,所以在Struts 2.x中的上傳接收直接利用java.io.File類完成,這樣的操作會比較直觀一些。
範例:定義上傳表單

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>Upload</title>

  </head>
  
  <body>
  	<form action="UploadAction!insert.action" method="post" enctype="multipart/form-data">
  		Name:&nbsp;<input type="text" name="name"><br>
  		Photo:&nbsp;<input type="file" name="photo"><br>
  		<input type="submit" value="submit">
  	</form>
  </body>
</html>

隨後定義UploadAction,但是爲了可以接收上傳文件,使用File定義一個photo屬性。
範例:定義UploadAction

package org.lks.action;

import java.io.File;

import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("serial")
public class UploadAction extends ActionSupport {

	private String name;
	private File photo;
	
	public void setName(String name) {
		this.name = name;
	}
	
	public void setPhoto(File photo) {
		this.photo = photo;
	}
	
	public void insert(){
		System.out.println("Name:" + this.name + ", Photo:" + this.photo + ", Photo Size:" + this.photo.length());
	}
}

範例:在struts.xml配置Action

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
	<package name="UploadAction" namespace="/" extends="struts-default">
		<action name="UploadAction" class="org.lks.action.UploadAction">
		</action>
	</package>
</struts>    

隨後運行項目代碼。

六月 27, 2020 5:32:35 下午 com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
信息: Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir
Name:lks, 
Photo:D:\Program Files\Tomcat\apache-tomcat-9.0.13\work\Catalina\localhost\StrutsUpload\upload__5785603a_172f51f1af4__8000_00000001.tmp, 
Photo Size:13301
六月 27, 2020 5:32:36 下午 com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
信息: Removing file photo D:\Program Files\Tomcat\apache-tomcat-9.0.13\work\Catalina\localhost\StrutsUpload\upload__5785603a_172f51f1af4__8000_00000001.tmp

此時發現可以成功上傳了,但是裏面卻出現有警告信息。因爲在Struts 2.x中實現的信息上傳流程如下:首先會將上傳的文件保存在一個臨時文件夾中,而後在Action裏面所讀取的文件內容實際上就是這個臨時文件夾中的信息內容,但是嚴格來講你應該自己定義一個這樣的臨時文件夾信息。
範例:在struts.properties文件中定義臨時保存目錄

struts.multipart.saveDir=tempdir

此時文件已經可以正常的上傳了。

2 上傳的進一步操作

雖然此時可以由Action接收上傳文件,那麼並且也可以取得文件內容了,但是依然無法進行保存,因爲不知道上傳的文件是什麼東西,在使用Struts 2.x上傳的時候是將上傳的內容先臨時保存到了一個存儲目錄中,這個目錄中所保存的文件是一個隨意自動生成的名稱。

Name:lks, 
Photo:D:\Program Files\Tomcat\apache-tomcat-9.0.13\work\Catalina\localhost\StrutsUpload\upload__5785603a_172f51f1af4__8000_00000001.tmp, 
Photo Size:13301
六月 27, 2020 5:32:36 下午 com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
信息: Removing file photo D:\Program Files\Tomcat\apache-tomcat-9.0.13\work\Catalina\localhost\StrutsUpload\upload__5785603a_172f51f1af4__8000_00000001.tmp

這個時候你無法知道你上傳的文件類型以及文件的原始名稱。

如果要想得到文件的原始名稱以及文件類型,必須定義兩個屬性,如果說現在接收上傳文件的屬性名稱爲photot,則需要定義兩個屬性纔可以接收:
(1)文件名稱:photoFileName;
(2)文件類型:photoContentType。
範例:接收文件名稱以及文件類型。

package org.lks.action;

import java.io.File;

import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("serial")
public class UploadAction extends ActionSupport {

	private String name;
	private File photo;
	private String photoFileName;
	private String photoContentType;
	
	public void setPhotoFileName(String photoFileName) {
		this.photoFileName = photoFileName;
	}
	
	public void setPhotoContentType(String photoContentType) {
		this.photoContentType = photoContentType;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public void setPhoto(File photo) {
		this.photo = photo;
	}
	
	public void insert(){
		System.out.println("Name:" + this.name + ", Photo:" + this.photo + ", Photo Size:" + this.photo.length());
		System.out.println("Photo Name: " + this.photoFileName);
		System.out.println("File type: " + this.photoContentType);
	}
}

既然文件的原始信息已經可以找到,那麼對用戶而言就可以進行文件的存儲操作了,但是如果要進行文件的保存,一定需要設置一個保存的目錄,同時也需要進行文件的名稱生成,考慮到所有的問題,下面可以單獨定義一個類,這個類專門負責文件的保存。
範例:實現文件保存的工具類

package org.lks.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

public class UploadFileUtil{
	
	private File uploadFile; //保存上傳文件的內容
	private String contentType; //保存上傳文件的類型
	private String fileName; //生成文件名稱
	
	/**
	 * 構造進行操作的文件內容以及文件類型
	 * @param uploadFile 包含了上傳文件的信息
	 * @param contentType 上傳文件的類型
	 */
	public UploadFileUtil(File uploadFile, String contentType) {
		this.uploadFile = uploadFile;
		this.contentType = contentType;
	}
	
	/**
	 * 取得文件名稱,根據uuid生成
	 * @return 返回一個不會重複的文件名稱
	 */
	public String getFileName(){ //取得文件的名稱
		if(this.fileName ==null || "".equals(this.fileName)){
			String fileExt = null; //保存文件的擴展類型
			if("image/bmp".equalsIgnoreCase(this.contentType)){
				fileExt = "bmp";
			}else if("image/gif".equalsIgnoreCase(this.contentType)){
				fileExt = "gif";
			}else if("image/jpeg".equalsIgnoreCase(this.contentType)){
				fileExt = "jpg";
			}else if("image/png".equalsIgnoreCase(this.contentType)){
				fileExt = "png";
			}
			
			this.fileName = UUID.randomUUID() + "." + fileExt;
		}
		return this.fileName;
	}
	
	public boolean saveFile(String outFilePath) throws IOException{  //文件的保存操作
		File file = new File(outFilePath);
		OutputStream output = null;
		InputStream input = null;
		try{
			if(!file.getParentFile().exists()){
				file.getParentFile().mkdirs();
			}
			output = new FileOutputStream(file);
			input = new FileInputStream(this.uploadFile);
			byte data[] = new byte[2048];
			int len = 0;
			while((len = input.read(data, 0, len)) != -1){
				output.write(data,0, len);
			}
			return true;
		}catch(Exception e){
			throw e;
		}finally{
			if(output != null){
				output.close();
			}
			
			if(input != null){
				input.close();
			}
		}
	}
	
	public boolean deleteFile(String filePath){
		return new File(filePath).delete();
	}
}

隨後在Action裏面調用此類的方法進行文件保存。
範例:在Action中保存信息

public void insert(){
		UploadFileUtil ufu = new UploadFileUtil(this.photo, this.photoContentType);
		String fileName = ufu.getFileName();
		System.out.println(fileName);
		String outFilePath = ServletActionContext.getServletContext().getRealPath("/upload/") + fileName;
		try {
			System.out.println(ufu.saveFile(outFilePath));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

對於任何的開發代碼,如果發現重複編寫了,必須要進行很好的類功能設計。

3 上傳限制

現在雖然可以進行文件的上傳了,但是上傳是有一些限制的,也就是說它本身是有一些文件大小的限制。

1、改變上傳文件的大小限制——修改struts.properties文件
(1)以下爲默認的上傳文件的最大額限制

struts.multipart.maxSize=2097152

但是一般圖片別弄得太大,除非你是那種專業的圖片網站。但是如果文件一大,那麼肯定要進行錯誤的顯示,那麼也就是說應該繼續配置一個input的路徑,修改struts.xml文件。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
	<package name="UploadAction" namespace="/" extends="struts-default">
		<action name="UploadAction" class="org.lks.action.UploadAction">
			<result name="input">upload.jsp</result>
		</action>
	</package>
</struts>    

2、這個時候如果文件太大,那麼struts 2.x就默認出現了錯誤操作,但是雖然大的方向上不能夠進行錯誤處理,但是可以在每一個Action中進行錯誤的配置;
範例:修改struts.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
	<package name="UploadAction" namespace="/" extends="struts-default">
		<action name="UploadAction" class="org.lks.action.UploadAction">
			<interceptor-ref name="fileUpload">
				<param name="maximumSize">10000</param>
				<param name="allowedTypes">
					image/gif,image/jpg,image/jpeg,image/png,image/bmp
				</param>
			</interceptor-ref>
			<interceptor-ref name="defaultStack"></interceptor-ref>
			<result name="input">upload.jsp</result>
		</action>
	</package>
</struts>    

所有的錯誤依然保存在了fieldErrors集合裏面。

<h1>${fieldErros['photo'][0] }</h1>

但是此時輸出的錯誤的默認信息是英文,不是中文。可以在全局資源文件中定義顯示的文字。
範例:在Messages.properties裏面定義文字信息


Struts 2.x的文件上傳的確考慮了不少的情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章