一、文件上傳簡介
Java 企业级項目開發,進行文件上傳有兩種方式:
当没有使用封装好的文件上传组件,就需要我们自身编写解析二进制代码,会非常麻烦。这也是为什么尽量使用封装好的组件进行开发。
二、基本上傳操作
Spring 框架提供了 org.springframework.web.multipart.MultipartFile 接口,其定義配置了所有文件的上傳。同時,Spring 提供了接口的子類實現文件上傳,其子類為 org.springframework.web.multipart.commons.CommonsMultipartFile。但是爲了實現完整的文件上傳操作,Spring 還提供了一個控制文件上傳的類,該類為 org.springframework.web.multipart.commons.CommonsMultipartResolver。
CommonsMultipartFile 類實現文件上傳操作,CommonsMultipartResolver 類實現文件上傳的控制。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
复制代码
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="1048576"/>
</bean>
复制代码
@RequestMapping("addGoalAndFile")
public ModelAndView addGoalAndFile(Goal goal,MultipartFile file){
ModelAndView mav = new ModelAndView("addGoalAndFile");
logger.info("Goal is " + goal);
if(file!=null){
logger.info("原文件名稱 :" + file.getOriginalFilename());
logger.info("文件名稱 :" + file.getName());
logger.info("文件大小 :" + file.getSize());
logger.info("文件類型 :" + file.getContentType());
}
return mav;
}
复制代码
<%
String url = request.getContextPath() + "/goal/addGoalAndFile";
%>
<form action="<%=url %>" method="post" enctype="multipart/form-data">
<table align="center" bgcolor="" background="">
<tbody align="center" valign="middle">
<tr>
<td align="left">名稱</td>
<td align="left"><input name="name" type="text" value=""/></td>
</tr>
<tr>
<td align="left">文件</td>
<td align="left"><input name="file" type="file"/></td>
</tr>
<tr>
<td colspan="2"><input name="submit" type="submit" value="提交"/></td>
</tr>
</tbody>
</table>
</form>
复制代码
三、文件保存
對於文件的保存,爲其配置相對路徑,建立 config.properties 文件,使用 Spring 資源讀取的方法,配置的保存目錄進行讀取。
package org.fuys.own.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FilesUtil {
private static Logger logger = LoggerFactory.getLogger(FilesUtil.class);
/**
* create new file name to save
* @param fileName
* @return
*/
public static String createFileNameToSave(String fileName){
if(fileName == null || "".equals(fileName)){
return null;
}
if(!fileName.contains(".")){
return UUID.randomUUID().toString();
}
return UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."));
}
/**
* save file
* @param is file-inputStream
* @param finalFilePath finally-saving-filepath
*/
public static boolean saveFile(InputStream is,String finalFilePath){
boolean flag = true;
File finalFile = new File(finalFilePath);
if(!finalFile.getParentFile().exists()){
finalFile.getParentFile().mkdirs();
}
OutputStream os = null;
try {
os = new FileOutputStream(finalFile);
byte[] bytes = new byte[1024];
int temp = 0;
while((temp = is.read(bytes))!=-1){
os.write(bytes, 0, temp);
}
} catch (Exception e) {
flag = false;
logger.error("Reading inputStream or Writing outputStream throws Exception .", e);
}finally{
try {
os.close();
} catch (Exception e2) {
logger.error("OutputStream can't be closed and throw Exception .", e2);
}
}
return flag ;
}
}
复制代码
@RequestMapping("addGoalAndFile")
public ModelAndView addGoalAndFile(Goal goal,MultipartFile file,HttpServletRequest request){
ModelAndView mav = new ModelAndView("addGoalAndFile");
logger.info("Goal is " + goal);
if(file!=null){
logger.info("原文件名稱 :" + file.getOriginalFilename());
logger.info("文件名稱 :" + file.getName());
logger.info("文件大小 :" + file.getSize());
logger.info("文件類型 :" + file.getContentType());
// save file
String newFileName = null;
String newFilePath = null;
boolean savingResult = false;
try {
newFileName = FilesUtil.createFileNameToSave(file.getOriginalFilename());
newFilePath = request.getServletContext().getRealPath(super.getValue("own.file.diretory"))
+ newFileName;
savingResult = FilesUtil.saveFile(file.getInputStream(), newFilePath);
} catch (Exception e) {
logger.error("save file exception." + e);
}
logger.info("newFileName=" + newFileName );
logger.info("newFilePath=" + newFilePath );
logger.info("saving result is " + savingResult );
}
return mav;
}
复制代码
四、上傳控制
當我們上傳文件的大小超過了配置所允許的大小,會報出一下異常:
nested exception is org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (25990976) exceeds the configured maximum (10485760)] with root cause
但是,頁面不會展示任何信息,顯然這不是我們所要的效果,應該跳轉到錯誤頁,給出錯誤提示,這樣才是最好的效果。因此,建立一個錯誤頁面 error.jsp,然後通過配置文件進行上傳控制。采用這樣的方式,也可以給出啓迪,對於所有異常而言,不要太多進行硬編碼進行控制頁面跳轉,應該交由配置完成后。
4.1、建立 errors.jsp 錯誤頁
4.2、進行上傳控制,配置指定出現的異常,自動跳轉到指定的錯誤頁面
<bean id="mappingException" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException">
errors
</prop>
<prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">
errors
</prop>
</props>
</property>
</bean>
复制代码
4.3、爲了防止上傳文件超過了 tomcat 容器允許的大小,因爲出現以上問題,程序是不會報錯的。所以,還需要修改當前項目所運行的容器的 server.xml 文件,修改如下:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" maxSwallowSize="-1"/>
复制代码
评论