一、文件上傳簡介
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"/>
复制代码
评论