1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        SpringBoot 2.0實(shí)現(xiàn)基于Restful風(fēng)格的文件上傳與下載

        共 19545字,需瀏覽 40分鐘

         ·

        2021-08-20 08:01

        點(diǎn)擊藍(lán)色“黃小斜學(xué)Java”關(guān)注我喲

        加個(gè)“星標(biāo)”,每天和你一起多進(jìn)步一點(diǎn)點(diǎn)

        文件上傳與下載在Web應(yīng)用中是一個(gè)比較常見(jiàn)的功能。在本教程中,我將基于Spring 2.2.6版本實(shí)現(xiàn)一個(gè)基于Restful風(fēng)格的文件上傳與下載APIs。

        基于Spring Boot 2.0實(shí)戰(zhàn)系列源碼已經(jīng)Push到Github倉(cāng)庫(kù):https://github.com/ramostear/springboot2.0-action 。感興趣朋友歡迎Star/Fork。

        Part1環(huán)境

        • JDK: Java 1.8
        • Framework: Spring Boot 2.2.6(Only Using Spring Web MVC)
        • Maven: Maven 3.5.0+
        • IDE: IntelliJ IDEA 2019.2
        • Test: Postman 7.23.0

        Part2功能

        本教程中,使用Spring 2.2.6實(shí)現(xiàn)Restful風(fēng)格的APIs并提供以下的功能:

        1. 客戶端上傳文件到服務(wù)端
        2. 對(duì)客戶端上傳文件大小進(jìn)行限制(50MB)
        3. 點(diǎn)擊鏈接地址下載文件
        4. 獲得已上傳文件列表(文件名和下載地址)

        下面是教程所實(shí)現(xiàn)的APIs列表(服務(wù)端請(qǐng)求端口默認(rèn)8080):

        Part3工程結(jié)構(gòu)

        圖片

        工程目錄結(jié)構(gòu)說(shuō)明如下:

        1. config/FileUploadConfiguration.java: 常規(guī)組件,主要在重啟應(yīng)用時(shí)清理歷史文件;
        2. controller/FileUploadController.java: 主要的控制器,負(fù)責(zé)處理文件的上傳,下載,瀏覽等請(qǐng)求;
        3. exception/FileUploadExceptionAdvice.java: 全局的異常處理類,提供用戶友好的異常提示信息;
        4. service/FileStorageService.java: 文件上傳接口類,提供存儲(chǔ)地址初始化,保存文件,加載文件,清理文件等操作;
        5. service/impl/FileStorageServiceImpl.java: 文件上傳接口實(shí)現(xiàn)類;
        6. valueobject/UploadFile.java: 封裝了文件名和存儲(chǔ)地址的POJO類;
        7. valueobject/Message.java: 請(qǐng)求/響應(yīng)的消息對(duì)象;
        8. resources/application.yml: 項(xiàng)目配置文件,主要配置了文件上傳大小限制;
        9. pom.xml:Maven依賴配置文件。

        Part4創(chuàng)建Spring Boot項(xiàng)目

        本教程是基于IntelliJ IDEA創(chuàng)建Spring Boot項(xiàng)目的,你也可以選擇自己喜歡的IDE創(chuàng)建項(xiàng)目。創(chuàng)建完項(xiàng)目后,請(qǐng)檢查pom.xml文件中是否包含如下配置:

        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-web</artifactId>  
        </dependency>  

        本教程只使用到Spring Web MVC的功能,因此只需添加spring-boot-starter-web依賴。

        4.1 文件上傳接口

        按照面向接口編程的約定(規(guī)范),創(chuàng)建一個(gè)用于操作上傳文件的接口類FileStorageService.java,并提供相應(yīng)的方法。

        service/FileStorageService.java

        package com.ramostear.springboot.uploadfile.service;  
          
        import org.springframework.core.io.Resource;  
        import org.springframework.web.multipart.MultipartFile;  
          
        import java.nio.file.Path;  
        import java.util.stream.Stream;  
          
        /**  
         * @ClassName FileStorageService  
         * @Description TODO  
         * @Author 樹(shù)下魅狐  
         * @Date 2020/4/28 0028 18:35  
         * @Version since 1.0  
         **/
          
        public interface FileStorageService {  
          
            void init();  
          
            void save(MultipartFile multipartFile);  
          
            Resource load(String filename);  
          
            Stream<Path> load();  
          
            void clear();  
          
        }  

        在啟動(dòng)應(yīng)用時(shí),先調(diào)用clear()方法清理歷史文件,再調(diào)用init()方法初始化文件上傳地址。

        4.2 實(shí)現(xiàn)文件上傳接口

        文件上傳接口實(shí)現(xiàn)類比較簡(jiǎn)單,這里直接給出代碼:

        service/impl/FileStorageServiceImpl.java

        /**  
         * @ClassName FileStorageServiceImpl  
         * @Description TODO  
         * @Author 樹(shù)下魅狐  
         * @Date 2020/4/28 0028 18:38  
         * @Version since 1.0  
         **/
          
        @Service("fileStorageService")  
        public class FileStorageServiceImpl implements FileStorageService {  
          
            private final Path path = Paths.get("fileStorage");  
          
          
            @Override  
            public void init() {  
                try {  
                    Files.createDirectory(path);  
                } catch (IOException e) {  
                    throw new RuntimeException("Could not initialize folder for upload!");  
                }  
            }  
          
            @Override  
            public void save(MultipartFile multipartFile) {  
                try {  
                    Files.copy(multipartFile.getInputStream(),this.path.resolve(multipartFile.getOriginalFilename()));  
                } catch (IOException e) {  
                    throw new RuntimeException("Could not store the file. Error:"+e.getMessage());  
                }  
            }  
          
            @Override  
            public Resource load(String filename) {  
                Path file = path.resolve(filename);  
                try {  
                    Resource resource = new UrlResource(file.toUri());  
                    if(resource.exists() || resource.isReadable()){  
                        return resource;  
                    }else{  
                        throw new RuntimeException("Could not read the file.");  
                    }  
                } catch (MalformedURLException e) {  
                    throw new RuntimeException("Error:"+e.getMessage());  
                }  
            }  
          
            @Override  
            public Stream<Path> load() {  
                try {  
                    return Files.walk(this.path,1)  
                            .filter(path -> !path.equals(this.path))  
                            .map(this.path::relativize);  
                } catch (IOException e) {  
                    throw new RuntimeException("Could not load the files.");  
                }  
            }  
          
            @Override  
            public void clear() {  
                FileSystemUtils.deleteRecursively(path.toFile());  
            }  
        }  

        其中,F(xiàn)iles、Path和Paths是java.nio.file提供的類,Resource是org.springframework.core.io包中提供的類。

        4.3 定義值對(duì)象

        本教程中,定義了兩個(gè)簡(jiǎn)單的對(duì)象UploadFile.java和Message.java,分別封裝了上傳文件信息和響應(yīng)消息,代碼如下:

        valueobject/UploadFile.java

        /**  
         * @ClassName UploadFile  
         * @Description TODO  
         * @Author 樹(shù)下魅狐  
         * @Date 2020/4/28 0028 18:48  
         * @Version since 1.0  
         **/
          
        public class UploadFile {  
          
            private String fileName;  
            private String url;  
          
            public UploadFile(String fileName, String url) {  
                this.fileName = fileName;  
                this.url = url;  
            }  
          
            public String getFileName() {  
                return fileName;  
            }  
          
            public void setFileName(String fileName) {  
                this.fileName = fileName;  
            }  
          
            public String getUrl() {  
                return url;  
            }  
          
            public void setUrl(String url) {  
                this.url = url;  
            }  
        }  

        valueobject/Message.java

        /**  
         * @ClassName Message  
         * @Description TODO  
         * @Author 樹(shù)下魅狐  
         * @Date 2020/4/28 0028 19:21  
         * @Version since 1.0  
         **/
          
        public class Message {  
          
            private String message;  
          
            public Message(String message) {  
                this.message = message;  
            }  
          
            public String getMessage() {  
                return message;  
            }  
          
            public void setMessage(String message) {  
                this.message = message;  
            }  
        }  

        4.4 控制器

        在controller包下創(chuàng)建文件上傳控制器,用于處理客戶端的請(qǐng)求。代碼如下:

        controller/FileUploadController.java

        /**  
         * @ClassName FileUploadController  
         * @Description TODO  
         * @Author 樹(shù)下魅狐  
         * @Date 2020/4/28 0028 18:52  
         * @Version since 1.0  
         **/
          
        @RestController  
        public class FileUploadController {  
          
            @Autowired  
            FileStorageService fileStorageService;  
          
            @PostMapping("/upload")  
            public ResponseEntity<Message> upload(@RequestParam("file")MultipartFile file){  
                try {  
                    fileStorageService.save(file);  
                    return ResponseEntity.ok(new Message("Upload file successfully: "+file.getOriginalFilename()));  
                }catch (Exception e){  
                    return ResponseEntity.badRequest()  
                            .body(new Message("Could not upload the file:"+file.getOriginalFilename()));  
                }  
            }  
          
            @GetMapping("/files")  
            public ResponseEntity<List<UploadFile>> files(){  
                List<UploadFile> files = fileStorageService.load()  
                        .map(path -> {  
                            String fileName = path.getFileName().toString();  
                            String url = MvcUriComponentsBuilder  
                                    .fromMethodName(FileUploadController.class,  
                                            "getFile",  
                                            path.getFileName().toString()  
                                    ).build().toString()
        ;  
                            return new UploadFile(fileName,url);  
                        }).collect(Collectors.toList());  
                return ResponseEntity.ok(files);  
            }  
          
            @GetMapping("/files/{filename:.+}")  
            public ResponseEntity<Resource> getFile(@PathVariable("filename")String filename){  
                Resource file = fileStorageService.load(filename);  
                return ResponseEntity.ok()  
                        .header(HttpHeaders.CONTENT_DISPOSITION,  
                                "attachment;filename=\""+file.getFilename()+"\"")  
                        .body(file);  
            }  
        }  

        在控制器中,使用@RestController組合注解替換了@Controller+@ResponseBody的注解方式,并采用@RequestMapping的快捷方式注解方法。

        4.5配置上傳文件大小

        通常,出于安全和性能考慮,我們需要限定客戶端上傳文件的大小,本教程限定的文件大小最大為50MB。在application.yml(application.properties)文件中添加如下配置:

        application.yml

        spring:  
          servlet:  
            multipart:  
              max-request-size: 50MB  
              max-file-size: 50MB  

        application.properties

        spring.servlet.multipart.max-request-size=50MB  
        spring.servlet.multipart.max-file-size=50MB  
        • spring.servlet.multipart.max-request-size=50MB: 單次請(qǐng)求所能上傳文件的總文件大小

        • spring.servlet.multipart.max-file-size=50MB:?jiǎn)蝹€(gè)文件所能上傳的文件大小

        4.6 全局異常處理

        在控制器中,文件上傳過(guò)程中可能產(chǎn)生的異常我們使用try-catch語(yǔ)句進(jìn)行了用戶友好處理,但當(dāng)客戶端上傳文件大小超過(guò)50MB時(shí),應(yīng)用會(huì)拋出MaxUploadSizeExceededException異常信息,我們需要對(duì)此異常信息做處理。最簡(jiǎn)單的方式是使用@ControllerAdvice+@ExceptionHandler組合方式處理異常。在exception包下創(chuàng)建異常處理類,代碼如下:

        exception/FileUploadExceptionAdvice.java

        /**  
         * @ClassName FileUploadExceptionAdvice  
         * @Description TODO  
         * @Author 樹(shù)下魅狐  
         * @Date 2020/4/28 0028 19:10  
         * @Version since 1.0  
         **/
          
        @ControllerAdvice  
        public class FileUploadExceptionAdvice extends ResponseEntityExceptionHandler {  
          
            @ExceptionHandler(MaxUploadSizeExceededException.class)  
            public ResponseEntity<MessagehandleMaxUploadSizeExceededException(MaxUploadSizeExceededException e)
        {  
               return ResponseEntity.badRequest().body(new Message("Upload file too large."));  
            }  
        }  

        4.7 初始化文件存儲(chǔ)空間

        為了在測(cè)試時(shí)獲得干凈的測(cè)試數(shù)據(jù),同時(shí)也為了在應(yīng)用啟動(dòng)后分配好上傳文件存儲(chǔ)地址,我們需要在config包下創(chuàng)建一個(gè)配置類,在應(yīng)用啟動(dòng)時(shí)調(diào)用FileStorageService中的clear()方法和init()方法。實(shí)現(xiàn)該功能,最快的方式是配置類實(shí)現(xiàn)CommandLineRunner接口類的run()方法,代碼如下:

        config/FileUploadConfiguration.java

        @Service  
        public class FileUploadConfiguration implements CommandLineRunner {  
          
            @Autowired  
            FileStorageService fileStorageService;  
          
            @Override  
            public void run(String... args) throws Exception {  
                fileStorageService.clear();  
                fileStorageService.init();  
            }  
        }  

        使用@Autowired注解將FileStorageService注入到FileUploadConfiguration.java中。

        Part5運(yùn)行程序并測(cè)試

        運(yùn)行Spring Boot應(yīng)用程序的方式有很多,例如:

        1. 命令方式:mvn spring-boot:run
        2. IntelliJ IDEA:點(diǎn)擊IntelliJ IDEA的“Run”按鈕
        3. main()方法:直接運(yùn)行主類中的main()方法
        4. 運(yùn)行jar包:java -jar springboot-fileupload.jar

        選擇一種你比較熟悉的方式運(yùn)行Spring Boot應(yīng)用程序。當(dāng)應(yīng)用程序啟動(dòng)成功后,在項(xiàng)目的根目錄會(huì)創(chuàng)建一個(gè)名為fileStorage的文件夾,該文件夾將用于存放客戶端上傳的文件。

        圖片

        5.1 使用Postman對(duì)APIs進(jìn)行測(cè)試

        應(yīng)用程序啟動(dòng)成功后,我們使用Postman對(duì)應(yīng)用程序中的APIs進(jìn)行測(cè)試。

        調(diào)用/upload接口上傳文件:

        圖片

        上傳一個(gè)大小超過(guò)50MB的文件

        圖片

        執(zhí)行結(jié)果:

        圖片

        檢查文件存儲(chǔ)文件夾

        文件上傳成功后,我們可以查看項(xiàng)目根目錄下的fileStorage文件夾,檢查是否有文件被存儲(chǔ)到當(dāng)中:

        圖片

        調(diào)用/files接口,獲取所有已上傳文件列表

        圖片

        /files接口將返回所有已上傳的文件信息,我們可以點(diǎn)擊其中任意一個(gè)鏈接地址下載文件。在Postman中,可以通過(guò)header選項(xiàng)卡查看響應(yīng)頭中文件的詳細(xì)信息,例如:

        圖片

        你也可以復(fù)制列表中的鏈接地址,并在瀏覽器中訪問(wèn)該地址,瀏覽器會(huì)彈出一個(gè)下載詢問(wèn)對(duì)話框,點(diǎn)擊確定按鈕進(jìn)行下載。

        Part66 總結(jié)

        本章節(jié)介紹了Spring Boot 2.0實(shí)現(xiàn)基于Restful風(fēng)格的文件上傳和下載APIs,并使用Postman工具對(duì)APIs進(jìn)行測(cè)試,達(dá)到了設(shè)計(jì)的預(yù)期結(jié)果。你可以通過(guò)下面的鏈接地址獲取本次教程的相關(guān)源代碼。

        Github倉(cāng)庫(kù)地址

        https://github.com/ramostear/springboot2.0-action

        (感謝閱讀,希望對(duì)你所有幫助)
        來(lái)源:ramostear.com/blog/2020/04/28/n1k2gc12.html
        — 【 THE END 】—
        本公眾號(hào)全部博文已整理成一個(gè)目錄,請(qǐng)?jiān)诠娞?hào)里回復(fù)「m」獲??!

        最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊(cè),覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。

        獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) PDF 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

        文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

        謝謝支持喲 (*^__^*)

        瀏覽 49
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            三个男的操一个女的 | 熟女三级片 | a级大片在线观看 | 人人摸人人操人人射 | 欧美性爱免费 | 少妇wbb搡bbbb揉bbbb | 男女成人 免费视频在线观看 | 成人免费做爱视频 | 少妇掰穴 | 久久羞羞tr3.tv.com |