一. 文件上傳的基本方法
1. 最簡單的上傳文件
我們新建一個Action類:public class UploadAction {
private File myFile;
public File getMyFile() {
return myFile;
}
public void setMyFile(File myFile) {
this.myFile = myFile;
}
public String upload() {
try {
FileUtils.copyFile(myFile, new File("d:/temp.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
}
使用了FileUtils.copyFile將一個文件複製到另一個文件。
然後配置struts文件和對象的jsp文件:
<struts>
<include file="common.xml"></include>
<package name="basicstruts2" extends="common" namespace="/test">
<action name="upload" class="com.thr.struts2.action.UploadAction">
<result>/upload_success.jsp</result>
</action>
</package>
</struts>
<body>
<form action="/web/test/upload.action" enctype="multipart/form-data" method="post">
選擇文件:<input name="myFile" type="file"/><br />
<input type="submit" name="method:upload" value="上傳" />
</form>
</body>
運行,選擇一個文件之後點擊提交就可以是上傳文件了。
2. 獲取文件名
如果我們想獲取源文件相關的信息,例如文件名等,就需要這樣子修改Action文件:
public class UploadAction {
private File myFile;
private String myFileFileName;
private String myFileContentType;
public File getMyFile() {
return myFile;
}
public void setMyFile(File myFile) {
this.myFile = myFile;
}
public String getMyFileFileName() {
return myFileFileName;
}
public void setMyFileFileName(String myFileFileName) {
this.myFileFileName = myFileFileName;
}
public String getMyFileContentType() {
return myFileContentType;
}
public void setMyFileContentType(String myFileContentType) {
this.myFileContentType = myFileContentType;
}
public String upload() {
try {
System.out.println("文件名:" + myFile.getName());
System.out.println(myFileFileName);
System.out.println(myFileContentType);
FileUtils.copyFile(myFile, new File("d:/" + myFileFileName));
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
}
注意新創建的兩個String變量,一個在myFile後面加FileName,另一個是在後面加ContentType,這兩個變量一個是用來獲取文件名,另一個是用來指定處理文件類型的,這樣在傳輸文件的時候就可以按照原有的文件名進行上傳了。
3. 上傳到自己的web路徑
可以使用 FileUtils.copyFile(myFile,
new File(ServletActionContext.getServletContext()
.getRealPath("/upload/" + "/" + myFileFileName)));
來上傳到自己的空間下,這裏在upload目錄後又跟了一個"/"是因爲它將/upload/整體解析爲一個目錄了,所以要在加一個斜槓。
爲了避免上傳時會遇到報錯,還可以加入下面兩個常量:
<constant name="struts.multipart.saveDir" value="D:/web/temp"></constant>
<constant name="struts.multipart.maxSize" value="80000000"></constant>
第一個是用來指定上傳保存的臨時目錄,第二是允許上傳文件的最大容量。
二. 上傳文件至數據庫
1. 以文件轉換成字節數組格式上傳至數據庫
我們增加一個方法:
public String upload2() {
Connection conn = DB.getConnection();
String sql = "insert into t_user(id, my_file) values(?, ?)";
try {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 12);
ps.setBytes(2, FileUtils.readFileToByteArray(myFile));
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
DB.closeConnection(conn);
return "success";
}
使用FileUtils的readFileToByteArray方法可以將文件類型轉換爲字節數組類型,然後插入到數據庫。
2. 以字節數組轉換器保存至數據庫
要直接將byte數組存至數據庫,就要寫一個轉換器:
public class FileConverter extends DefaultTypeConverter {
@Override
public Object convertValue(Object arg0, Class arg1) {
if (arg0 instanceof File[]) {
try {
byte[] bytes = FileUtils
.readFileToByteArray(((File[]) arg0)[0]);
return bytes;
} catch (IOException e) {
e.printStackTrace();
}
}
throw new RuntimeException("不是文件類型,無法轉換!");
}
}
配置和之前配轉化器一樣,穿件UploadAction-conversion.properties:
myBytes=com.thr.struts2.converter.FileConverter
在UploadAction中創建myBytes成員變量,生成set和get方法:
public String upload3() {
Connection conn = DB.getConnection();
String sql = "insert into t_user(id, my_file) values(?, ?)";
try {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 15);
ps.setBytes(2, myBytes);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
DB.closeConnection(conn);
return "success";
}
記得修改jsp頁面的變量名爲myBytes,這樣就可以直接以byte數組存入數據庫了。
三. 複雜參數傳遞和多文件上傳
1. 複雜參數傳遞
新寫一個CollectionAciton類,裏面包括了一個List和一個Map:
public class CollectionAction {
private List<Contact> contacts;
private Map<String, Contact> contactsMap;
public List<Contact> getContacts() {
return contacts;
}
public void setContacts(List<Contact> contacts) {
this.contacts = contacts;
}
public Map<String, Contact> getContactsMap() {
return contactsMap;
}
public void setContactsMap(Map<String, Contact> contactsMap) {
this.contactsMap = contactsMap;
}
public String execute() {
return "success";
}
}
裏面裝的類型就是我們之前的Contact類。
配置struts文件,寫一個jsp文件用來顯示上傳內容:
<form action="/web/test/collection.action" enctype="multipart/form-data" method="post">
List:<br />
Contact:<br />
qq:<input name="contacts[0].qq" />,
tel:<input name="contacts[0].tel" />,
phone:<input name="contacts[0].phone" />,<br />
Contact2:<br />
qq:<input name="contacts[1].qq" />,
tel:<input name="contacts[1].tel" />,
phone:<input name="contacts[1].phone" />,<br />
Map:<br />
Contact:<br />
qq:<input name="contactsMap['contact'].qq" />,
tel:<input name="contactsMap'contact'].tel" />,
phone:<input name="contactsMap'contact'].phone" />,<br />
Contact2:<br />
qq:<input name="contactsMap['contact2'].qq" />,
tel:<input name="contactsMap['contact2'].tel" />,
phone:<input name="contactsMap['contact2'].phone" />,<br />
<input type="submit" value="上傳" />
</form>
通過這個文件,我們看到了如果使用OGNL表達式來傳遞複雜的參數。
2. 多文件上傳
想要實現多文件上傳,只需在jsp頁面中添加多個input就可以了:
<form action="/web/test/upload.action" enctype="multipart/form-data" method="post">
選擇文件1:<input name="multiFile" type="file"/><br />
選擇文件2:<input name="multiFile" type="file"/><br />
<input type="submit" name="method:multiUpload" value="上傳" />
</form>
然後在Action中指定我們的變量:
private File[] multiFile;
private String[] multiFileFileName;
private String[] multiFileContentType;
這樣子就可以獲取我們上傳的文件信息啦。四. 文件下載
我們先修改一下數據庫增加varchar類型的fileName和contentType類型。我們上傳幾個文件到數據庫。
創建一個用來下載文件的Action:
public class DownloadAction {
private InputStream stream;
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public InputStream getStream() {
InputStream inputStream = null;
Connection conn = DB.getConnection();
String sql = "select myFile, fileName, contentType from t_user where id=?";
try {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ResultSet rs = ps.executeQuery();
rs.next();
inputStream = rs.getBinaryStream("myFile");
ActionContext.getContext()
.put("fileName", rs.getString("fileName"));
ActionContext.getContext().put("contentType",
rs.getString("contentType"));
} catch (SQLException e) {
e.printStackTrace();
}
DB.closeConnection(conn);
return inputStream;
}
public String execute() {
return "success";
}
}
id用來接收頁面上傳過來的id,我們將文件名和文件類型保存到了ActionContext中,方便在配置文件中動態讀取。
然後配置struts文件:
<action name="download" class="com.thr.struts2.action.DownloadAction">
<result type="stream">
<param name="contentType">%{#contentType}</param>
<param name="inputName">stream</param>
<param name="contentDisposition">attachment;filename="%{#fileName}"</param>
</result>
</action>
最後寫下載頁面:
<body>
<a href="/web/test/download.action?id=16">下載id16</a><br />
<a href="/web/test/download.action?id=17">下載id17</a><br />
<a href="/web/test/download.action?id=18">下載id18</a><br />
</body>
id=16、17、18對應我們數據庫中保存的3個id的文件。