写点什么

SpringMVC 之文件上传

作者:andy
  • 2022-10-27
    北京
  • 本文字数:3287 字

    阅读完需:约 11 分钟

一、文件上傳簡介


Java 企业级項目開發,進行文件上傳有兩種方式:

  • 原生技術使用 SmartUpload

  • 開發框架使用 FileUpload(直接使用該組件會很麻煩,封裝到框架之後方便使用許多)。


当没有使用封装好的文件上传组件,就需要我们自身编写解析二进制代码,会非常麻烦。这也是为什么尽量使用封装好的组件进行开发。


二、基本上傳操作


Spring 框架提供了 org.springframework.web.multipart.MultipartFile 接口,其定義配置了所有文件的上傳。同時,Spring 提供了接口的子類實現文件上傳,其子類為 org.springframework.web.multipart.commons.CommonsMultipartFile。但是爲了實現完整的文件上傳操作,Spring 還提供了一個控制文件上傳的類,該類為 org.springframework.web.multipart.commons.CommonsMultipartResolver。

CommonsMultipartFile 類實現文件上傳操作,CommonsMultipartResolver 類實現文件上傳的控制

  • 添加 apache 的 fileUpload 組件:


<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>
复制代码


  • applicationContext-mvc.xml 配置信息如下,其中需要注意此類的 id,需寫為以下文字,才能被很好的調用,至於調用處,則在 jar 包中,無法找到具體調用處:


<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">		<property name="maxUploadSize" value="10485760"/>		<property name="maxInMemorySize" value="1048576"/>	</bean>
复制代码


  • Java 代碼:


@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;	}
复制代码


  • JSP 頁面:


<%		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 資源讀取的方法,配置的保存目錄進行讀取。


  • 配置信息:own.file.diretory=/file/

  • 編寫 Java 文件處理的工具類,編寫文件名生成和文件保存方法


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"/>
复制代码


用户头像

andy

关注

还未添加个人签名 2019-11-21 加入

还未添加个人简介

评论

发布
暂无评论
SpringMVC之文件上传_andy_InfoQ写作社区