【SpringMVC】SpringMVC之文件上傳/下載

學習一個框架少不了學習文件上傳和下載,原理來說上傳和下載都是基本二進制流的轉換,所以搞清楚了這一點就很容易理解上傳和下載了


在使用springMVC進行系統實現時,springMVC默認的解析器裏面是沒有加入對文件上傳的解析的,這可以方便我們實現自己的文件上傳。但如果你想使用springMVC對文件上傳的解析器來處理文件上傳的時候就需要在spring的applicationContext裏面加上springMVC提供的MultipartResolver的申明。這樣之後,客戶端每次進行請求的時候,springMVC都會檢查request裏面是否包含多媒體信息,如果包含了就會使用MultipartResolver進行解析,springMVC會使用一個支持文件處理的MultipartHttpServletRequest來包裹當前的HttpServletRequest,然後使用MultipartHttpServletRequest就可以對文件進行處理了。


一.文件上傳


1.引入依賴包

文件上傳需要額外引入包分別是

  1. commons-fileupload-1.3.1.jar
  2. commons-io-2.4.jar

2.配置jsp頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
    <meta charset="utf-8">
    <title>用戶登錄</title>
</head>
<body>
    <%--文件上傳的話需要enctype="multipart/form-data"--%>
    <sf:form modelAttribute="user" method="post" enctype="multipart/form-data">
        用戶名:<sf:input path="username"/><sf:errors path="username"/>
        <br>
        密碼:<sf:input path="password"/><sf:errors path="password"/>
        <br>
        暱稱:<sf:input path="nickname"/><sf:errors path="nickname"/>
        <br>
        <%--這裏設置文件上傳--%>
        文件:<input type="file" name="file">
        <input type="submit" value="提交">
    </sf:form>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

3.配置相應的控制器

@RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(@Validated User user, BindingResult br, Model model,@RequestParam("file") MultipartFile file){
        if (br.hasErrors()){
            return "user/login";
        }
        //分別獲取的是變量名file---文件類型---文件名
        System.out.println(file.getName()+"---"+file.getContentType()+"---"+file.getOriginalFilename());
        try {
            if (!file.isEmpty()){
            //使用StreamsAPI方式拷貝文件
                Streams.copy(file.getInputStream(),new FileOutputStream("E:/temp/"+file.getOriginalFilename()),true);
            }
        } catch (IOException e) {
            System.out.println("文件上傳失敗");
            e.printStackTrace();
        }
        System.out.println(user.toString());
        return "user/login";
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

至此單個文件上傳完成.

4.多文件上傳

多文件上傳很簡單,只需要把參數改爲數組就可以了

    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(@Validated User user, BindingResult br, Model model,@RequestParam("file") MultipartFile[] file){
        if (br.hasErrors()){
            return "user/login";
        }
        //這裏對文件進行遍歷
        for (MultipartFile mul:file){
        //分別獲取的是變量名file---文件類型---文件名
            System.out.println(mul.getName()+"---"+mul.getContentType()+"---"+mul.getOriginalFilename());
            try {
                if (!mul.isEmpty()){
                    Streams.copy(mul.getInputStream(),new FileOutputStream("E:/temp/"+mul.getOriginalFilename()),true);
                }
            } catch (IOException e) {
                System.out.println("文件上傳失敗");
                e.printStackTrace();
            }
        }
        System.out.println(user.toString());
        return "user/login";
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

二.文件下載


下載需要把文件轉換成二進制流,然後讓客戶端讀取這個二進制流寫入到本機,這樣就實現了下載功能.那麼現在就要想兩個問題:1.怎麼把文件寫成二進制流? 2.怎麼把讓客戶端相應,開始下載?

答案;

  1. 寫成二進制流可以用之前導入的上傳組件提供的方法:FileUtils.readFileToByteArray(file)
  2. 讓瀏覽器響應,則需要設置相應的httpHeader了,並且利用spring提供的ResponseEntity把返回值設置爲header和響應內容

1.創建控制器代碼

            @RequestMapping(value = "/download",produces = "application/octet-stream;charset=UTF-8")
            public ResponseEntity<byte[]> download() throws IOException {
//                指定文件,必須是絕對路徑
            File file = new File("E:/temp/me-bg.jpg");
//                下載瀏覽器響應的那個文件名
            String dfileName = "1.jpg";
//                下面開始設置HttpHeaders,使得瀏覽器響應下載
            HttpHeaders headers = new HttpHeaders();
//                設置響應方式
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//                設置響應文件
            headers.setContentDispositionFormData("attachment", dfileName);
//                把文件以二進制形式寫回
            return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

2.測試下載

訪問指定的控制器就能觸發下載了


3.補充

有時候下載下來的文件會出現被壓縮現象,也就是之前的格式都不存在了.解決辦法爲配置SpringMVC的messageConverter如下:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
    <property name="messageConverters">  
        <list>  
            <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>  
        </list>  
    </property>  
</bean>  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在SpringBoot中和fastjson一起使用可以如下:

本質上和xml配置是一樣的,注入的時候有些轉換器都有默認處理類型,所以沒必要再次配置

 @Bean
    public HttpMessageConverters customConverters() {

        //fastjson處理消息轉換
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue);
        /*
          List<MediaType> fastMediaTypes = new ArrayList<>();
          fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
          fastConverter.setSupportedMediaTypes(fastMediaTypes);
        */
        fastConverter.setFastJsonConfig(fastJsonConfig);

        //文件下載使用ByteArrayHttpMessageConverter處理
        ByteArrayHttpMessageConverter byteArrayHttpMessageConverter = new ByteArrayHttpMessageConverter();
        byteArrayHttpMessageConverter.setDefaultCharset(Charset.forName("UTF-8"));
        /*
         //ByteArrayHttpMessageConverter默認處理請求類型就是APPLICATION_OCTET_STREAM
         List<MediaType> byteMediaTypes = new ArrayList<>();
         byteMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
         byteArrayHttpMessageConverter.setSupportedMediaTypes(byteMediaTypes);
         */
        List<HttpMessageConverter<?>> converters = new ArrayList<>();
        converters.add(fastConverter);
        converters.add(byteArrayHttpMessageConverter);

        return new HttpMessageConverters(converters);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

另外關於文件名亂碼,可以使用URLEncoder轉換下即可解決

String filename = URLEncoder.encode(file.getName(),"UTF-8");
  • 1
  • 1
  • 1
  • 1

項目示例可以參考: 

發佈了96 篇原創文章 · 獲贊 218 · 訪問量 64萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章