欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringMVC教程之文件上傳與下載詳解

 更新時間:2022年12月08日 15:20:19   作者:小新要變強  
本文將對使用MultipartResolver處理文件上傳的步驟,兩種文件下載方式(直接向response的輸出流中寫入對應(yīng)的文件流、使用 ResponseEntity<byte[]>來向前端返回文件)等進行詳盡介紹,需要的可以參考一下

前言

文件上傳是項目開發(fā)中最常見的功能之一 ,SpringMVC 可以很好的支持文件上傳,但是SpringMVC上下文中默認(rèn)沒有裝配MultipartResolver,因此默認(rèn)情況下其不能處理文件上傳工作。如果想使用Spring的文件上傳功能,則需要在上下文中配置MultipartResolver。

前端表單要求:為了能上傳文件,必須將表單的method設(shè)置為POST,并將enctype設(shè)置為multipart/form-data。只有在這樣的情況下,瀏覽器才會把用戶選擇的文件以二進制數(shù)據(jù)發(fā)送給服務(wù)器。

<form action="" enctype="multipart/form-data" method="post">
    <input type="file" name="file"/>
    <input type="submit">
</form>

表單中enctype屬性的詳細說明:

  • application/x-www=form-urlencoded:默認(rèn)方式,只處理表單域中的 value 屬性值,采用這種編碼方式的表單會將表單域中的值處理成 URL 編碼方式。
  • multipart/form-data:這種編碼方式會以二進制流的方式來處理表單數(shù)據(jù),這種編碼方式會把文件域指定文件的內(nèi)容也封裝到請求參數(shù)中,不會對字符編碼。
  • text/plain:除了把空格轉(zhuǎn)換為 “+” 號外,其他字符都不做編碼處理,這種方式適用直接通過表單發(fā)送郵件。

一旦設(shè)置了enctype為multipart/form-data,瀏覽器即會采用二進制流的方式來處理表單數(shù)據(jù),而對于文件上傳的處理則涉及在服務(wù)器端解析原始的HTTP響應(yīng)。在2003年,Apache Software Foundation發(fā)布了開源的Commons FileUpload組件,其很快成為Servlet/JSP程序員上傳文件的最佳選擇。

  • Servlet3.0規(guī)范已經(jīng)提供方法來處理文件上傳,但這種上傳需要在Servlet中完成。而Spring MVC則提供了更簡單的封裝。
  • Spring MVC為文件上傳提供了直接的支持,這種支持是用即插即用的MultipartResolver實現(xiàn)的。
  • Spring MVC使用Apache Commons FileUpload技術(shù)實現(xiàn)了一個MultipartResolver實現(xiàn)類:CommonsMultipartResolver。因此,SpringMVC的文件上傳還需要依賴Apache Commons FileUpload的組件。

一、文件上傳

【MultipartResolver】用于處理文件上傳。當(dāng)收到請求時,DispatcherServlet 的 checkMultipart() 方法會調(diào)用 MultipartResolver 的 isMultipart() 方法判斷請求中【是否包含文件】。如果請求數(shù)據(jù)中包含文件,則調(diào)用 MultipartResolver 的 resolveMultipart() 方法對請求的數(shù)據(jù)進行解析,然后將文件數(shù)據(jù)解析成 MultipartFile 并封裝在 MultipartHttpServletRequest (繼承了 HttpServletRequest) 對象中,最后傳遞給 Controller。

我們可以看到DispatcherServlet的核心方法中第一句就是如下的代碼:

try {
    processedRequest = checkMultipart(request);
    multipartRequestParsed = (processedRequest != request);
    ...

注意: MultipartResolver 默認(rèn)不開啟,需要手動開啟。

文件上傳對前端表單有如下要求:為了能上傳文件,必須將表單的【method設(shè)置為POST】,并將enctype設(shè)置為【multipart/form-data】。只有在這樣的情況下,瀏覽器才會把用戶選擇的文件以二進制數(shù)據(jù)發(fā)送給服務(wù)器。

對表單中的 enctype 屬性的詳細說明:

application/x-www-form-urlencoded:默認(rèn)方式,只處理表單域中的 value 屬性值,采用這種編碼方式的表單會將表單域中的值處理成 URL 編碼方式。

multipart/form-data:這種編碼方式會以二進制流的方式來處理表單數(shù)據(jù),這種編碼方式會把文件域指定文件的內(nèi)容也封裝到請求參數(shù)中,不會對字符編碼。

<form action="" enctype="multipart/form-data" method="post">
   <input type="file" name="file"/>
   <input type="submit">
</form>

一旦設(shè)置了enctype為multipart/form-data,瀏覽器即會采用二進制流的方式來處理表單數(shù)據(jù),而對于文件上傳的處理則涉及在服務(wù)器端解析原始的HTTP響應(yīng)。

1)導(dǎo)入這個【commons-fileupload】jar包,Maven會自動幫我們導(dǎo)入它的依賴包【commons-io】

<!--文件上傳-->
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3.3</version>
</dependency>

2)配置bean:multipartResolver

注意: 這個bena的id必須為:multipartResolver , 否則上傳文件會報400的錯誤!

<!--文件上傳配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
   <!-- 請求的編碼格式,必須和jSP的pageEncoding屬性一致,以便正確讀取表單的內(nèi)容,默認(rèn)為ISO-8859-1 -->
   <property name="defaultEncoding" value="utf-8"/>
   <!-- 上傳文件大小上限,單位為字節(jié)(10485760=10M) -->
   <property name="maxUploadSize" value="10485760"/>
   <property name="maxInMemorySize" value="40960"/>
</bean>

CommonsMultipartFile 的常用方法:

String getOriginalFilename():獲取上傳文件的原名

InputStream getInputStream():獲取文件流

void transferTo(File dest):將上傳文件保存到一個目錄文件中

(3)編寫前端頁面

<form action="/upload" enctype="multipart/form-data" method="post">
 <input type="file" name="file"/>
 <input type="submit" value="upload">
</form>

(4)編寫Controller類

package com.wang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller
public class FileController {
    //@RequestParam("file") 將name=file控件得到的文件封裝成CommonsMultipartFile 對象
    //批量上傳CommonsMultipartFile則為數(shù)組即可
    @RequestMapping("/upload")
    public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
        //獲取文件名 : file.getOriginalFilename();
        String uploadFileName = file.getOriginalFilename();
        //如果文件名為空,直接回到首頁!
        if ("".equals(uploadFileName)){
            return "redirect:/index.jsp";
        }
        System.out.println("上傳文件名 : "+uploadFileName);
        //上傳路徑保存設(shè)置
        String path = request.getServletContext().getRealPath("/upload");
        //如果路徑不存在,創(chuàng)建一個
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }
        System.out.println("上傳文件保存地址:"+realPath);
        InputStream is = file.getInputStream(); //文件輸入流
        OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件輸出流
        //讀取寫出
        int len=0;
        byte[] buffer = new byte[1024];
        while ((len=is.read(buffer))!=-1){
            os.write(buffer,0,len);
            os.flush();
        }
        os.close();
        is.close();
        return "redirect:/index.jsp";
    }
}

(5)測試上傳文件

(6)采用file.Transto 來保存上傳的文件

編寫Controller類:

/*
 * 采用file.Transto 來保存上傳的文件
 */
@RequestMapping("/upload2")
public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
    //上傳路徑保存設(shè)置
    String path = request.getServletContext().getRealPath("/upload");
    File realPath = new File(path);
    if (!realPath.exists()){
        realPath.mkdir();
    }
    //上傳文件地址
    System.out.println("上傳文件保存地址:"+realPath);
    //通過CommonsMultipartFile的方法直接寫文件(注意這個時候)
    file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
    return "redirect:/index.jsp";
}

小知識: 我們在文件上傳可以考慮以下幾點:

(1)文件的原始信息,或者叫文件的元數(shù)據(jù)是不是可以存在數(shù)據(jù)庫,具體應(yīng)該怎么做?

(2)文件的上傳目錄能不能寫在配置文件當(dāng)中,這個應(yīng)該怎么做?

(3)文件上傳到服務(wù)器后可不可以安裝一定的規(guī)則分目錄存儲,比如日期?

(4)思考怎么使用阿里云的oss進行圖片存儲?

二、文件下載

第一種可以直接向response的輸出流中寫入對應(yīng)的文件流

第二種可以使用 ResponseEntity<byte[]>來向前端返回文件

1.傳統(tǒng)方式

文件下載步驟:

(1)設(shè)置 response 響應(yīng)頭

(2)讀取文件 — InputStream

(3)寫出文件 — OutputStream

(4)執(zhí)行操作

(5)關(guān)閉流 (先開后關(guān))

@GetMapping("/download1")
@ResponseBody
public R download1(HttpServletResponse response){
    FileInputStream fileInputStream = null;
    ServletOutputStream outputStream = null;
    try {
        // 這個文件名是前端傳給你的要下載的圖片的id
        // 然后根據(jù)id去數(shù)據(jù)庫查詢出對應(yīng)的文件的相關(guān)信息,包括url,文件名等
        String  fileName = "wang.jpg";

        //1、設(shè)置response 響應(yīng)頭,處理中文名字亂碼問題
        response.reset(); //設(shè)置頁面不緩存,清空buffer
        response.setCharacterEncoding("UTF-8"); //字符編碼
        response.setContentType("multipart/form-data"); //二進制傳輸數(shù)據(jù)
        //設(shè)置響應(yīng)頭,就是當(dāng)用戶想把請求所得的內(nèi)容存為一個文件的時候提供一個默認(rèn)的文件名。
        //Content-Disposition屬性有兩種類型:inline 和 attachment 
        //inline :將文件內(nèi)容直接顯示在頁面 
        //attachment:彈出對話框讓用戶下載具體例子:
        response.setHeader("Content-Disposition",
                           "attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));

		// 通過url獲取文件
        File file = new File("D:/upload/"+fileName);
        //2、 讀取文件--輸入流
        fileInputStream = new FileInputStream(file);
        //3、 寫出文件--輸出流
        outputStream = response.getOutputStream();

        byte[] buffer = new byte[1024];
        int len;
        //4、執(zhí)行寫出操作
        while ((len = fileInputStream.read(buffer)) != -1){
            outputStream.write(buffer,0,len);
            outputStream.flush();
        }

        return R.success();
    } catch (IOException e) {
        e.printStackTrace();
        return R.fail();
    }finally {
        if( fileInputStream != null ){
            try {
                // 5、關(guān)閉輸入流
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if( outputStream != null ){
            try {
                // 5、關(guān)閉輸出流
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2.使用ResponseEntity方式

@GetMapping("/download2")
public ResponseEntity<byte[]> download2(){
    try {
        String fileName = "wang.jpg";
        byte[] bytes = FileUtils.readFileToByteArray(new File("D:/upload/"+fileName));
        HttpHeaders headers=new HttpHeaders();
        // Content-Disposition就是當(dāng)用戶想把請求所得的內(nèi)容存為一個文件的時候提供一個默認(rèn)的文件名。
        headers.set("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
        headers.set("charsetEncoding","utf-8");
        headers.set("content-type","multipart/form-data");
        ResponseEntity<byte[]> entity=new ResponseEntity<>(bytes,headers, HttpStatus.OK);
        return entity;
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

到此這篇關(guān)于SpringMVC教程之文件上傳與下載詳解的文章就介紹到這了,更多相關(guān)SpringMVC文件上傳下載內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實現(xiàn)的基于socket通信的實例代碼

    Java實現(xiàn)的基于socket通信的實例代碼

    Java實現(xiàn)的基于socket通信的實例代碼,需要的朋友可以參考一下
    2013-03-03
  • Springboot整合GuavaCache緩存過程解析

    Springboot整合GuavaCache緩存過程解析

    這篇文章主要介紹了springboot整合GuavaCache緩存過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • XML解析四種方式代碼示例詳解

    XML解析四種方式代碼示例詳解

    這篇文章主要介紹了XML解析四種方式代碼示例詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-12-12
  • java啟動命令中-D和--的區(qū)別解析

    java啟動命令中-D和--的區(qū)別解析

    在 SpringBoot 項目中,啟動時,通過 -D 或 -- 添加參數(shù),都可以直接覆蓋 yml 或 properties 配置文件中的同名配置,如果不存在則相當(dāng)于添加了一個配置,這篇文章主要介紹了java啟動命令中-D和--的區(qū)別,需要的朋友可以參考下
    2024-08-08
  • Java多線程之死鎖詳解

    Java多線程之死鎖詳解

    這篇文章主要介紹了Java多線程的死鎖,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-10-10
  • java使用Dijkstra算法實現(xiàn)單源最短路徑

    java使用Dijkstra算法實現(xiàn)單源最短路徑

    這篇文章主要為大家詳細介紹了java使用Dijkstra算法實現(xiàn)單源最短路徑,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • SpringBoot詳解如何進行整合Druid數(shù)據(jù)源

    SpringBoot詳解如何進行整合Druid數(shù)據(jù)源

    Druid是阿里開發(fā)的一款開源的數(shù)據(jù)源,被很多人認(rèn)為是Java語言中最好的數(shù)據(jù)庫連接池,本文主要介紹了SpringBoot整合Druid數(shù)據(jù)源的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Java?數(shù)據(jù)庫連接池Druid?的介紹

    Java?數(shù)據(jù)庫連接池Druid?的介紹

    這篇文章主要給大家分享的是?Java?數(shù)據(jù)庫連接池Druid?的介紹,Druid是一個JDBC組件,它包括三部分:?DruidDriver?代理Driver,能夠提供基于Filter-Chain模式的插件體系。?DruidDataSource?高效可管理的數(shù)據(jù)庫連接池,下面來看看文中的詳細內(nèi)容,需要的朋友也可以參考一下
    2021-11-11
  • Java線程安全中的原子性淺析

    Java線程安全中的原子性淺析

    這篇文章主要介紹了Java線程安全中的原子性,原子性是指一條線程在執(zhí)行一系列程序指令操作時,該線程不可中斷。一旦出現(xiàn)中斷,那么就可能會導(dǎo)致程序執(zhí)行前后的結(jié)果不一致
    2023-02-02
  • mybatis中mapper-locations的作用

    mybatis中mapper-locations的作用

    這篇文章主要介紹了mybatis中mapper-locations的具體作用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06

最新評論