使用Struts1實現文件上傳(一)
今天研究了一下Struts的文件上傳機制,可以方便的將客戶端文件上傳至服務器端,感覺很方便、實用,特此記錄一下。
完成文件上傳功能大致需要以下幾個步驟:
(1)創建用於文件上傳的JSP頁面;
(2)創建用於承載數據的ActionForm;
(3)創建用於處理上傳的Action;
(4)配置文件上傳大小;
(5)配置從web.xml文件中讀取文件存放路徑;
步驟一:創建用於文件上傳的JSP頁面
在項目中新建一個用於文件上傳的JSP頁面,如命名爲:FileUpload.jsp,在頁面的頂頭處引入Struts的html標籤庫。
- <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
並在頁面的<body></body>標籤內書寫如下代碼:
- <html:form enctype="multipart/form-data" action="/fileUpload" method="post">
- <html:file property="uploadFile"></html:file>
- <html:submit>Upload File</html:submit>
- </html:form>
<html:form enctype="multipart/form-data" action="/fileUpload" method="post">
<html:file property="uploadFile"></html:file>
<html:submit>Upload File</html:submit>
</html:form>
<html:form>是Struts表單,要想用此表單上傳文件必須要設置 enctype 和 method 參數才行,enctype 參數用於設置該表單的編碼方式,當該表單中包含了<input type = "file"> 或 <html:file> 是必須要將enctype的屬性值設置爲:"multiparty/form-data" ,並且要將表單的提交方式Method屬性設置爲"Post";在action處填入處理表單的Action訪問路徑。
<html:file>是Struts提供的文件上傳組件,其屬性property要與承載數據的ActionForm類的FormFile類型的屬性保持一一對應的關係。ActionForm類中的屬性書寫見步驟二。
步驟二:創建用於承載數據的ActionForm
在項目中新建一個ActionForm的子類,如命名爲:FileUploadForm.java,在其中新增一個FormFile類型的屬性uploadFile,並設置getter、setter方法。
在Struts中,一個FormFile類型的對象對應Form表單中創送的一個文件,Struts將上傳的文件信息封裝金FormFile中,通過FormFile提供的方法可以方便的進行文件的操作。其實FormFile是一個接口,位於 org.apache.struts.upload.FormFile 中,它定義了操作上傳文件的基本方法。
FormFile接口定義的常用方法:
(1) getFileName()/setFileName() //用於獲取或設置文件名;
(2) getFileSize() / setFileSize() //用於獲取或設置文件字節數;
(3) getFileData() //用於獲取文件的字節數組,用於小的文件;
(4) getInputStream() //用於獲取文件的輸入流,用於較大的文件;
(5) destory() //銷燬FromFile;
步驟三:創建用於處理上傳的Action
在項目中新建一個Action的子類,如命名爲:FileUploadAction.java,在其execute方法中添加處理代碼。
在代碼中可以看到,我們從FileUploadForm中找到了FormFile類型的屬性,通過其提供的方法得到文件的信息,並將其存入服務器的磁盤中。在保存的過程中需要用到文件流的一些基本操作。
到此爲止,文件的上傳已經基本成功,剩下的兩步爲配置文件上傳大小和從web.xml文件中讀取文件存放路徑,可以選擇學習。
步驟四:配置文件上傳大小
在Struts中可以配置上傳文件的大小,以避免服務器的硬盤消化不良。
打開項目中WebRoot\WEB-INF\struts-config.xml ,切換至源碼視圖,在其中添加如下節點信息,便可以控制上傳文件的大小了。
其中maxFileSize屬性的單位可以是K,也可以是M或G;Struts在寫 FormFile類時藉助的是fileupload中的API,設置的默認大小爲250M
注意:操作struts-config.xml文件時應當特別注意各個節點間的順序,因爲Struts要求配置文件的各個元素順序有一定的要求,順序一旦被打亂,也就意味着web容器即將進入癱瘓狀態,因此在添加<controler>節點時,要將此節點添加在<action-mapping>和<message-resources>節點之間。
附:Struts-config.xml配置文件各元素的順序列表。
步驟五:配置從web.xml文件中讀取文件存放路徑
在步驟三中的代碼中我們已經看到,在保存文件時,我寫的是一個固定的存放路徑,有沒有什麼辦法讓它動態改變呢?答案是肯定的,Struts提供了一些方法可以讀取web.xml中讀取數據,那麼我們可以把存放的路徑存放在web.xml文件中,存儲文件時再將路徑讀取出來。這樣做的好處是,如果存放路徑發生改變,我們只需要修改配置文件,而不需要改動代碼。
打開項目WebRoot\WEB-INF\web.xml , 找到一個servlet,在該servlet的節點下添加如下代碼:
要想讀取此節點的信息,在處理上傳文件的Action代碼中加入如下代碼:
到此基於Struts的文件上傳操作已經基本完成。
使用Struts1實現文件上傳(二)
在使用Struts1實現文件上傳(一)中,我將文件保存在服務器端的硬盤裏,有沒有辦法將其保存在Oracle10g數據庫中呢?答案是肯定的,只需要對程序稍加改造就可以實現將文件保存在數據庫中。用到時再將文件從數據庫中還原出來供用戶下載。
在數據庫中保存文件的方法和保存其他基本數據類型相差不多,只是要存入即可,但是其對應的數據類型比較特殊,一般選擇二進制的數據類型。Oracle10g中提供了RAW和Long RAW數據類型,這兩中數據類型用於保存二進制的數據;二進制類型的好處在於當數據在不同系統之間傳輸時,可以不做任何數據類型的轉換,方便了系統之間的操作。RAW類型的最大寬度爲2000字節,而Long RAW類型的最大寬度可以達到2GB,非常適合保存圖像、聲音、視頻等數據量較大的數據。
因此,要想將文件保存在數據庫中用到時在取出來,就要完成三個步驟:
(1)新建Oracle10g數據表,在表中添加Long RAW類型的字段;
(2)在程序中將上傳的文件以流的形式保存到數據庫中;
(3)將文件從數據庫中還原出來。
一、新建Oracle10g數據表
在Oracle10g中新建一張數據表,如命名爲UploadFiles,在表中添加相應的字段;
其中FileContent便是用來存放文件的Long RAW二進制數據類型。
二、將上傳文件保存在數據庫
剩下的工作便是在程序中編寫代碼將用戶上傳的文件保存在數據庫中了,主要的代碼已經在文章“使用Struts1實現文件上傳(一)”中實現,現在只需要將原來保存在文件中的部分代碼替換爲保存在數據庫的代碼即可。
當用戶點擊上傳後就可以將文件存儲在數據庫中了。
三、將文件從數據庫中還原出來
當用戶需要用到文件時,就需要從數據中將文件查詢出來,方法也很簡單,看代碼:
將文件從數據庫中讀取出來後得到的將是一個InputStream類型的對象,可以根據需要操作這個對象還原文件。
struts1文件上傳和下載
FileAction
import org.apache.struts.action.*;
import javax.servlet.http.*;
import com.actionForm.FileActionForm;
import org.apache.struts.actions.DispatchAction;
import java.util.Date;
import java.text.*;
import org.apache.struts.upload.FormFile;
import java.io.*;
import java.net.URLEncoder;
import com.dao.*;
public class FileAction extends DispatchAction {
private JDBConnection connection =new JDBConnection();
//以下方法實現文件的上傳
public ActionForward upLoadFile(ActionMapping mapping, ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws
Exception {
ActionForward forward=null;
Date date = new Date();
FileActionForm fileActionForm = (FileActionForm) form;
//FormFile用於指定存取文件的類型
FormFile file = fileActionForm.getFile(); //獲取當前的文件
// 獲得系統的絕對路徑 String dir = servlet.getServletContext().getRealPath("/image");
//我上傳的文件沒有放在服務器上。而是存在D:D:\\loadfile\\temp\\
String dir="D:\\loadfile\\temp\\";
int i = 0;
String type = file.getFileName();
while(i!=-1){
//找到上傳文件的類型的位置,這個地方的是'.'
i = type.indexOf(".");
/**//* System.out.println(i);*/
/**//*截取上傳文件的後綴名,此時得到了文件的類型*/
type = type.substring(i+1);
}
// 限制上傳類型爲jpg,txt,rar;
if (!type.equals("jpg") && !type.equals("txt")&& !type.equals("bmp"))
{//當上傳的類型不爲上述類型時,跳轉到錯誤頁面。
forward=mapping.findForward("error");
}
else
{
// 將上傳時間加入文件名(這個地方的是毫秒數)
String times = String.valueOf(date.getTime());
//組合成 time.type
String fname = times + "." + type;
//InInputStream是用以從特定的資源讀取字節的方法。
InputStream streamIn = file.getInputStream(); //創建讀取用戶上傳文件的對象
//得到是字節數,即byte,我們可以直接用file.getFileSize(),也可以在創建讀取對象時用streamIn.available();
// int ok=streamIn.available();
int ok=file.getFileSize();
String strFee = null;
//這個地方是處理上傳的爲M單位計算時,下一個是以kb,在下一個是byte;
if(ok>=1024*1024)
{
float ok1=(((float)ok)/1024f/1024f);
DecimalFormat myformat1 = new DecimalFormat("0.00");
strFee = myformat1.format(ok1)+"M";
System.out.println(strFee+"M");
}
else if(ok>1024 && ok<=1024*1024)
{
double ok2=((double)ok)/1024;
DecimalFormat myformat2=new DecimalFormat("0.00");
strFee = myformat2.format(ok2)+"kb";
System.out.println(strFee+"kb");
}
else if(ok<1024)
{
System.out.println("aaaaaaaaa");
strFee=String.valueOf(ok)+"byte";
System.out.println(strFee);
}
System.out.println( streamIn.available()+"文件大小byte");
//這個是io包下的上傳文件類
File uploadFile = new File(dir); //指定上傳文件的位置
if (!uploadFile.exists() || uploadFile == null) { //判斷指定路徑dir是否存在,不存在則創建路徑
uploadFile.mkdirs();
}
//上傳的路徑+文件名
String path = uploadFile.getPath() + "\\" + fname;
//OutputStream用於向某個目標寫入字節的抽象類,這個地方寫入目標是path,通過輸出流FileOutputStream去寫
OutputStream streamOut = new FileOutputStream(path);
int bytesRead = 0;
byte[] buffer = new byte[8192];
//將數據讀入byte數組的一部分,其中讀入字節數的最大值是8192,讀入的字節將存儲到,buffer[0]到buffer[0+8190-1]的部分中
//streamIn.read方法返回的是實際讀取字節數目.如果讀到末尾則返回-1.如果bytesRead返回爲0則表示沒有讀取任何字節。
while ((bytesRead = streamIn.read(buffer, 0, 8192)) != -1) {
//寫入buffer數組的一部分,從buf[0]開始寫入並寫入bytesRead個字節,這個write方法將發生阻塞直至字節寫入完成。
streamOut.write(buffer, 0, bytesRead);
}
// 關閉輸出輸入流,銷燬File流。
streamOut.close();
streamIn.close();
file.destroy();
String paths=path;
System.out.println(paths);
String fileName = Chinese.toChinese(fileActionForm.getFileName()); //獲取文件的名稱
//String fileSize = String.valueOf(file.getFileSize());
String fileDate = DateFormat.getDateInstance().format(date);
String sql = "insert into tb_file values('" + fileName + "','" +
strFee + "','" + fileDate + "','" + paths + "')";
connection.executeUpdate(sql);
connection.closeConnection();
forward=mapping.findForward("upLoadFileResult");
}
return forward;
}
//實現文件的下載
public ActionForward downFile(ActionMapping mapping, ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws
Exception {
String path = request.getParameter("path");
System.out.println(path+"111");
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
OutputStream fos = null;
InputStream fis = null;
//如果是從服務器上取就用這個獲得系統的絕對路徑方法。 String filepath = servlet.getServletContext().getRealPath("/" + path);
String filepath=path;
System.out.println("文件路徑"+filepath);
File uploadFile = new File(filepath);
fis = new FileInputStream(uploadFile);
bis = new BufferedInputStream(fis);
fos = response.getOutputStream();
bos = new BufferedOutputStream(fos);
//這個就就是彈出下載對話框的關鍵代碼
response.setHeader("Content-disposition",
"attachment;filename=" +
URLEncoder.encode(path, "utf-8"));
int bytesRead = 0;
//這個地方的同上傳的一樣。我就不多說了,都是用輸入流進行先讀,然後用輸出流去寫,唯一不同的是我用的是緩衝輸入輸出流
byte[] buffer = new byte[8192];
while ((bytesRead = bis.read(buffer, 0, 8192)) != -1) {
bos.write(buffer, 0, bytesRead);
}
bos.flush();
fis.close();
bis.close();
fos.close();
bos.close();
return null;
}
}
FileActionForm
import org.apache.struts.action.*;
import org.apache.struts.upload.*;
public class FileActionForm extends ActionForm {
private String fileName;//上傳文件的名稱
private String fileSize;//上傳文件的大小
private String filePath;//上傳文件到服務器的路徑
private String fileDate;//上傳文件的日期
private FormFile file;//上傳文件
public String getFileName() {
return fileName;
}
public FormFile getFile() {
return file;
}
public String getFileSize() {
return fileSize;
}
public String getFilePath() {
return filePath;
}
public String getFileDate() {
return fileDate;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public void setFile(FormFile file) {
this.file = file;
}
public void setFileSize(String fileSize) {
this.fileSize = fileSize;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public void setFileDate(String fileDate) {
this.fileDate = fileDate;
}
}
index.jsp
<tr>
<td width="115" rowspan="4" align="center"><img src="<%=form.getFilePath()%>" width="100" height="100"></td>
<td width="133" align="center">圖片名稱:<%=form.getFileName()%></td>
</tr>
<tr align="center">
<td>圖片大小:<%=form.getFileSize()%></td>
</tr>
<tr align="center">
<td>上傳日期:<%=form.getFileDate()%></td>
</tr>
<tr>
<td align="center"><a href="fileAction.do?method=downFile&path=<%=form.getFilePath()%>" ><img src="priture/bottond.jpg"></a>
</td>
</tr>
</table>
<html:form action="fileAction.do?method=upLoadFile" enctype="multipart/form-data" onsubmit="return Mycheck()">
<table height="52" border="0" align="center" cellpadding="0" cellspacing="0">
<tr align="center">
<td width="60" height="26">圖片名稱:</td>
<td width="160"> <html:text property="fileName"/> </td>
<td width="60">圖片路徑:</td>
<td width="198"> <html:file property="file"/> </td>
</tr>
<tr align="right">
<td height="26" colspan="4"> <html:submit>上傳</html:submit> </td>
</tr>
</table>
</html:form>
struts-config.xml
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd">
<struts-config>
<form-beans>
<form-bean name="fileActionForm" type="com.actionForm.FileActionForm" />
</form-beans>
<action-mappings>
<action name="fileActionForm" parameter="method" path="/fileAction" scope="request" type="com.action.FileAction" validate="true">
<forward name="upLoadFileResult" path="/result.jsp"/>
<forward name="error" path="/fail.jsp"></forward>
</action>
</action-mappings>
<message-resources parameter="ApplicationResources" />
</struts-config