背景:以前一直作的是數據庫的增刪改查工做,對於文件的上傳下載比較排斥,今天研究了下具體的實現,發現實際上是很簡單。此處不只要實現單文件的上傳,還要實現多文件的上傳。html
單文件的下載知道了,多文件的下載呢??java
我這裏使用的spring boot來快速搭建spring mvc框架,賊方便,不用都對不起本身。web
本篇博客將講解的是Springmvc的文件上傳和下載功能。對於上傳功能,咱們在項目中是常常會用到的,好比用戶註冊的時候,上傳用戶頭像,這個時候就會使用到上傳的功能。而對於下載,使用場景也很常見,好比咱們項目中有個使用說明是是pdf版的,會提供給用戶進行下載的功能。相對於來講,這兩個功能都是很常見。spring
使用spring boot來搭建mvc的框架。數據庫
文件目錄:apache
pom.xml文件依賴:api
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>spring.boot</groupId> <artifactId>uploadfile</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>uploadfile</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--jsp頁面使用jstl標籤 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <!--用於編譯jsp --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <!-- 配置文件上傳的bean 控制文件大大小,編碼等 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io --> <!-- 使用到其中的FileUtil工具類 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
spring-web.xml:數組
注入這個bean,控制文件的上傳。瀏覽器
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- <mvc:annotation-driven conversion-service="conversionSerivce" /> --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 默認編碼 --> <property name="defaultEncoding" value="utf-8" /> <!-- 文件大小最大值 --> <property name="maxUploadSize" value="80485760" /> <!-- 內存中的最大值 --> <property name="maxInMemorySize" value="40960" /> </bean> </beans>
ps:對於文件大小的控制,在spring boot中出現一個問題,就是xml的配置有時生效,有時不會生效,特別是單文件上傳和多文件上傳時候會致使上傳文件的參數爲null。最後的解決辦法是經過顯示的bean注入的方式。spring-mvc
在使用過程當中能夠將xml中的bean註釋掉,只用下述方式控制便可。
ConfigClass:導入xml文件
package spring.boot.uploadfile.config; import javax.servlet.MultipartConfigElement; import org.springframework.boot.web.servlet.MultipartConfigFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; /** * ClassName:ConfigClass <br/> * Function: TODO <br/> * Date: 2018年3月2日 下午8:20:05 <br/> * @author prd-lxw * @version 1.0 * @since JDK 1.7 * @see */ /** * classpath路徑:locations={"classpath:application-bean1.xml","classpath:application-bean2.xml"} * file路徑: locations = {"file:d:/test/application-bean1.xml"}; */ @Configuration @ImportResource(locations = { "classpath:spring-web.xml" }) //@ImportResource(locations={"file:d:/test/application-bean1.xml"}) public class ConfigClass { @Bean public MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); //文件最大 factory.setMaxFileSize("1000240KB"); //KB,MB /// 設置總上傳數據總大小 factory.setMaxRequestSize("102400KB"); return factory.createMultipartConfig(); } }
以上配置是spring boot中的內容,此處簡單講解,主要就是mvc框架的搭建。
2.1:首先咱們來新建一個jsp頁面,命名爲:uploadform.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="gotoAction" enctype="multipart/form-data" method="post"> <table> <tr> <td>請選擇文件:</td> <td><input type="file" name="file"></td> </tr> <tr> <td>開始上傳</td> <td><input type="submit" value="上傳"></td> </tr> </table> </form> </body> </html>
ps:上傳頁面jsp的編寫
寫一個上傳的頁面form表單,其中必定要注意的是在表單的屬性中添加entcypt="multipart/form-data",這表示上傳的將會是二進制流的格式,以規定的二進制進行上傳,便於服務器處理,使用post請求:
2.2:再寫一個上傳成功的jsp頁面,主要是用來當上傳成功時候跳轉的頁面,命名爲:success.jsp
<body> <h2>文件上傳成功!</h2> </body>
2.3:而後再寫一個上傳失敗的頁面,主要是用來當上傳失敗的時候跳轉的頁面,命名爲:error.jsp
<body> <h2>文件上傳失敗!請檢查文件是否存在</h2> </body>
2.4:寫好了jsp頁面,接下來就是寫咱們的控制器了,Springmvc控制器,咱們寫了一個FileUploadController類,而後寫上具體的代碼,以下所示,
注意其中使用MultipartFile來接受form表單傳過來的file文件,MultipartFile有幾個核心的api,能夠供咱們使用,好比 boolean isEmpty(),用來判斷文件是否爲空。void transferTo( File file),把文件寫入目標路徑地址
下屬代碼是最終實驗的Controller中的代碼。後面的詳解由於太累了,直接複製原來的文章。。。。。
/** * Project Name:uploadfile * File Name:FileUploadController.java * Package Name:spring.boot.uploadfile.controller * Date:2018年3月2日下午8:28:42 * Copyright (c) 2018, 深圳金融電子結算中心 All Rights Reserved. * */ package spring.boot.uploadfile.controller; import java.io.File; import java.io.IOException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.commons.io.FileUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import spring.boot.uploadfile.domain.User; /** * ClassName:FileUploadController <br/> * Function: 實現spring中的單文件上傳與下載,文件能夠做爲一個參數傳遞,也能夠做爲bean的一個屬性傳遞 * Date: 2018年3月2日 下午8:28:42 <br/> * @author prd-lxw * @version 1.0 * @since JDK 1.7 * @see */ @Controller public class FileUploadController { /** * 首次進入時候的頁面 * @param formName * @return */ @RequestMapping(value = "/{formName}") public String loginForm(@PathVariable String formName) { return formName; } /** * 實現單文件的上傳 * @param file * @param request * @return */ @RequestMapping(value = "/gotoAction", method = RequestMethod.POST) public String upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) { if (!file.isEmpty()) { String contextPath = request.getContextPath();//"/SpringMvcFileUpload" String servletPath = request.getServletPath();//"/gotoAction" String scheme = request.getScheme();//"http" String storePath = "E:\\testJava\\filesss";//存放咱們上傳的文件路徑 String fileName = file.getOriginalFilename(); File filepath = new File(storePath, fileName); if (!filepath.getParentFile().exists()) { filepath.getParentFile().mkdirs();//若是目錄不存在,建立目錄 } try { file.transferTo(new File(storePath + File.separator + fileName));//把文件寫入目標文件地址 } catch (Exception e) { e.printStackTrace(); return "error"; } return "success";//返回到成功頁面 } else { return "error";//返回到失敗的頁面 } } /** * 將文件做爲bean的一個屬性上傳 * @param user * @param request * @param map * @return */ @RequestMapping(value = "/register", method = RequestMethod.POST) public String reg(@ModelAttribute User user, HttpServletRequest request, Map<String, Object> map) { final String wrong = "error"; final String good = "success"; MultipartFile headimage = user.getHeadimage(); boolean empty = headimage.isEmpty(); if (!empty) { String realPath = request.getServletContext().getRealPath("/images"); String uploadPath = "E:\\testJava\\filesss"; String headimageName = headimage.getOriginalFilename(); File imageFile = new File(uploadPath, headimageName); try { headimage.transferTo(new File(uploadPath + File.separator + headimageName)); } catch (Exception e) { e.printStackTrace(); return wrong; } map.put("user", user); return "userinfo"; } else { return wrong; } } /** * 實現單文件的下載 * @param request * @param filename * @param model * @return * @throws IOException */ @RequestMapping(value = "/download", method = RequestMethod.GET) //匹配的是href中的download請求 public ResponseEntity<byte[]> download(HttpServletRequest request, @RequestParam("filename") String filename, Model model) throws IOException { String downloadFilePath = "E:\\testJava\\filesss";//從咱們的上傳文件夾中去取 File file = new File(downloadFilePath + File.separator + filename);//新建一個文件 // byte[] body = null; // InputStream is = new FileInputStream(file); // body = new byte[is.available()]; // is.read(body); HttpHeaders headers = new HttpHeaders();//http頭信息 String downloadFileName = new String(filename.getBytes("UTF-8"), "iso-8859-1");//設置編碼 headers.setContentDispositionFormData("attachment", downloadFileName); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); //MediaType:互聯網媒介類型 contentType:具體請求中的媒體類型信息 return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED); } }
User.java
/** * Project Name:uploadfile * File Name:User.java * Package Name:spring.boot.uploadfile.domain * Date:2018年3月2日下午8:41:47 * Copyright (c) 2018, 深圳金融電子結算中心 All Rights Reserved. * */ package spring.boot.uploadfile.domain; import java.io.Serializable; import org.springframework.web.multipart.MultipartFile; /** * ClassName:User <br/> * Function: 將文件做爲bean的一個屬性 * Date: 2018年3月2日 下午8:41:47 <br/> * @author prd-lxw * @version 1.0 * @since JDK 1.7 * @see */ public class User implements Serializable {//用戶實體類 /** */ private static final long serialVersionUID = 1L; private String userName; private MultipartFile headimage; //上傳文件會自動綁定到該屬性 //省略getter和setter方法 }
2.5:好了,到此咱們就能夠實現上傳功能了,發佈在Tomact容器裏,而後就能夠進行上傳文件了。
在瀏覽中輸入:http://localhost:8080/uploadform
具體的頁面請求以下,而後瀏覽具體的文件,點擊上傳按鈕:
點擊瀏覽,上傳
而後執行相應的方法,完成文件的上傳。
三:將上傳文件綁定到具體的對象上
3.1:首先咱們來定義一個實體類User,這個實體類中的headimage屬性的主要做用就是用來映射咱們上傳的文件,能夠看到它是MultipartFile類型的:
三:將上傳文件綁定到具體的對象上
3.1:首先咱們來定義一個實體類User,這個實體類中的headimage屬性的主要做用就是用來映射咱們上傳的文件,能夠看到它是MultipartFile類型的:
3.1:首先咱們來定義一個實體類User,這個實體類中的headimage屬性的主要做用就是用來映射咱們上傳的文件,能夠看到它是MultipartFile類型的:
public class User implements Serializable{//用戶實體類 private String userName; private MultipartFile headimage;//上傳文件會自動綁定到該屬性 //省略getter和setter方法 }
3.2:而後寫咱們的 jsp上傳頁面,這裏咱們來模擬一個用戶註冊上傳頭像的場景,新建一個registerForm.jsp頁面,而後寫一個form表單,以下:
<body> <h2>用戶註冊</h2> <form action="register" enctype="multipart/form-data" method="post"> <table> <tr> <td>用戶頭像:</td> <td><input type="file" name="headimage"></td> </tr> <tr> <td>上傳:</td> <td><input type="submit" value="上傳"></td> </tr> </table> </form> </body>
3.3:寫咱們的方法控制器處理註冊邏輯的層的代碼,注意其中的user對象加入了@ModelAttribute註解,其主要做用是用來映射把上面的form表單的headimage屬性自動注入到對象裏面,還有Map<String,Object> map主要是爲了存放user對象,放在requestScope裏面,這樣就可用el表達式把其中的值取出來了。
@RequestMapping(value="/register",method=RequestMethod.POST) public String reg(@ModelAttribute User user,HttpServletRequest request,Map<String,Object> map){ final String wrong="error"; final String good="success"; MultipartFile headimage = user.getHeadimage(); boolean empty = headimage.isEmpty(); if (!empty) { String realPath = request.getServletContext().getRealPath("/images"); String uploadPath="D:\\userUploadFile\\Files"; String headimageName = headimage.getOriginalFilename(); File imageFile = new File(uploadPath,headimageName); try { headimage.transferTo(new File(uploadPath+File.separator+headimageName)); } catch (Exception e) { e.printStackTrace(); return wrong; } map.put("user", user); return "userInfo"; }else { return wrong; } }
3.4:咱們來新建一個jsp頁面,取名爲userinfo.jsp,其主要做用是顯示剛纔的咱們的文件名:
<body> 用戶頭像:${requestScope.user.headimage.originalFilename} </body>
3.5:頁面寫完了,咱們在來模擬測試一下,在客戶端Ie瀏覽器中,輸入http://localhost:8080/SpringMvcFileUpload/registerForm:
4.1:首先定義一個downinfo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h3>文件下載</h3> <a href="download?filename=V.jpeg"> 用戶頭像:V </a> </body> </html>
4.2:來看看咱們的download控制器代碼:注意download方法返回的是ResponseEntity<byte[]> 類型,這個是封裝好的返回類型,咱們須要傳入byte數組、headers、HttpStatus,而後它就會返回具體的下載流,調用客戶端去下載資源
@RequestMapping(value="/download",method=RequestMethod.GET) //匹配的是href中的download請求 public ResponseEntity<byte[]> download(HttpServletRequest request,@RequestParam("filename") String filename, Model model) throws IOException{ String downloadFilePath="D:\\userUploadFile\\Files";//從咱們的上傳文件夾中去取 File file = new File(downloadFilePath+File.separator+filename);//新建一個文件 HttpHeaders headers = new HttpHeaders();//http頭信息 String downloadFileName = new String(filename.getBytes("UTF-8"),"iso-8859-1");//設置編碼 headers.setContentDispositionFormData("attachment", downloadFileName); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); //MediaType:互聯網媒介類型 contentType:具體請求中的媒體類型信息 return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.CREATED); }
ps:此處注意這兩個類的jar包。
FileUtils來自org.apache.commons.commons-io
4.3:咱們來測試一下寫的東西是否能準確運行,點擊超連接,注意此連接指向的地址:http://localhost:8080/SpringMvcFileUpload/download?filename="myheadimage".jpg,這就表示這個連接會去請求控制器,而後控制器進行處理下載, 這樣就完成了文件的下載功能了:
點擊超連接:
本篇博文介紹了SpringMvc上傳和文件的功能,須要注意的地方就是對於文件上傳包common-fileupload.jar包的使用,還有在配置文件上配置mulitipartResolver這個bean。下面又介紹了用java 實體類去映射上傳文件的屬性對應的文件,這點的好處就是它會自動映射,而後把對象放入到咱們的請求域中,就能夠展現給界面用戶層,這也是mvc思想模式的體現。接下來是介紹去下載文件,只須要從咱們的寫入的目標地址去取出文件,再進行responseEntity對象的封裝,就能夠實現下載功能