国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring Boot實(shí)現(xiàn)文件上傳的兩種方式

這篇具有很好參考價(jià)值的文章主要介紹了Spring Boot實(shí)現(xiàn)文件上傳的兩種方式。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

最近的一個(gè)小項(xiàng)目里使用到了文件上傳、下載功能,今天我打算梳理一下文件上傳所涉及的技術(shù)及實(shí)現(xiàn)。 內(nèi)容主要包括兩部分,如何通過純 Servlet 的形式進(jìn)行文件上傳、保存(不通過 Spring 框架);另一部分是如何在 Spring Web MVC 中進(jìn)行文件上傳。

01-從 HTTP 協(xié)議角度分析文件上傳

HTTP 協(xié)議傳輸文件一般都遵循 RFC 1867 規(guī)范,即客戶端通過 POST 請求,Context-Type 為 "multipart/form-data"。 前端提交頁面一般為:

<form method="post" action="${user_upload_service_url}" enctype="multipart/form-data">
    Choose a file: <input type="file" name="image" accept="image/*" />
    <input type="submit" value="Upload" />
</form>

通過 Wireshark 對 POST 請求進(jìn)行抓包,發(fā)現(xiàn)發(fā)送的請求格式為:

POST /upload HTTP/1.1
Host: localhost:8080
Content-Length: 197624
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarynIbwtdWznj6QLu52

First boundary: ------WebKitFormBoundarynIbwtdWznj6QLu52
Encapsulated multipart part:  (image/png)
    Content-Disposition: form-data; name="image"; filename="Snipaste_2023-01-05_13-35-11.png"
    Content-Type: image/png
    Portable Network Graphics
Boundary: ------WebKitFormBoundarynIbwtdWznj6QLu52
Encapsulated multipart part:  (image/png)
    Content-Disposition: form-data; name="image"; filename="Snipaste_2023-01-05_13-35-12.png"
    Content-Type: image/png
    Portable Network Graphics
Last boundary: ------WebKitFormBoundarynIbwtdWznj6QLu52--

對上述過程有了基本的理解后,就可以動手來寫上傳功能(本文以圖片為例,當(dāng)然你也可以實(shí)現(xiàn)支持上傳其他類型的文件的版本)。 接下來我會展示兩種實(shí)現(xiàn)文件上傳功能的代碼,第一種是使用純 Servlet API 實(shí)現(xiàn),不依賴 Spring 框架,當(dāng)你的程序是一個(gè)簡單的基于 Servlet 的應(yīng)用時(shí),可以參考這種方式。 第二種,借助了 Spring 提供的 MultipartFile 以及 MultipartResolver 實(shí)現(xiàn)的文件上傳。

02-Servlet 處理上傳請求

首先,需要先實(shí)現(xiàn)一個(gè) Servlet。

@MultipartConfig(fileSizeThreshold = 5 * 1024 * 1024,
        maxFileSize = 1024 * 1024 * 5,
        maxRequestSize = 1024 * 1024 * 5)
@WebServlet(name = "MultipartServlet", urlPatterns = "/servlet-upload")
public class MultipartServlet extends HttpServlet {

    private File uploadDir = null;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        // 檢查存儲文件的路徑是否存在,若不存在,則創(chuàng)建一個(gè)
        String uploadPath = System.getProperty("user.dir") + File.separator + "uploads";
        uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            uploadDir.mkdir();
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 第一節(jié)中介紹過,文件上傳是通過 POST 方法完成的,所以這里我們要重寫 doPost 方法
        try {
            final Collection<Part> parts = req.getParts();   // 從請求中獲取 multipart 內(nèi)容
            for (Part part : parts) {
                if (part.getSize() <= 0) {                  // 判斷上傳的內(nèi)容是否空文件
                    System.out.println("part is empty, skip it!");
                    continue;
                }
                String fileName = getFileName(part);       // 從請求中獲取文件的名
                // or
                //final String fileName = part.getSubmittedFileName();

                // fileName 是前端提供的,并不十分可靠
                // 后端應(yīng)該自己生成一個(gè)文件名
                fileName = genNewFileName(fileName);

                String uploadedFilePath = uploadDir + File.separator + fileName;
                part.write(uploadedFilePath);   // 存儲到指定目錄
                System.out.println("saved to " + uploadedFilePath);
                resp.getWriter().write("saved to "  + uploadedFilePath);
            }
        } catch (ServletException se) {
            // request is not of type multipart/form-data
        }

        resp.setStatus(HttpServletResponse.SC_OK);
        resp.getWriter().flush();
        resp.getWriter().close();
    }

    private String getFileName(Part part) {
        for (String s : part.getHeader("Content-Disposition").split(";")) {
            if (s.trim().startsWith("filename")) {
                return s.substring(s.indexOf("=") + 2, s.length() - 1);
            }
        }
        // 默認(rèn)文件名
        return "foo.txt";
    }
    private String genNewFileName(String filename) {
        String filenameFormat = "%s.%s";
        return String.format(filenameFormat,
                UUID.randomUUID().toString().replace("-", "").substring(8),
                FilenameUtils.getExtension(filename)
        );

    }
}

這里面有幾個(gè)地方需要解釋一下;

  • 其一,getFileName 為什么要這么實(shí)現(xiàn)?參考第一節(jié)給出的 HTTP 報(bào)文,發(fā)現(xiàn)每個(gè) Part,即兩個(gè) boundary 之間的內(nèi)容,通過 Content-Disposition 給出了內(nèi)容類型、文件名等信息。 getFileName 中的邏輯就是從這個(gè)格式里獲得文件名的。 不過,這個(gè)文件名是由前端提供的,它其實(shí)也可以不提供,所以這個(gè)值就不是那么可靠。 所以,在我們將上傳文件保存到磁盤上時(shí),最好重新生成一個(gè)文件名,這就使 genNewFileName 的動機(jī)。
  • 其二,根據(jù) HttpServletRequest 接口的文檔,getParts 方法在請求不是 multipart 類型時(shí)會拋異常。 而且,Part 的內(nèi)容有可能是為空的,如果我們不做判斷,可能會在服務(wù)端創(chuàng)建一個(gè)空文件。
  • Servlet 類上的注解,@WebServlet 不再介紹,@MultipartConfig 是對請求、請求中文件大小的限制條件,當(dāng)請求或文件超過這個(gè)限制時(shí)會拋對應(yīng)的異常。

有了上面的定義,我們就可以測試下上傳功能了。?

服務(wù)啟動后,訪問 頁面能夠得到上傳頁面。 選擇文件,提交后,服務(wù)端響應(yīng)成功,并將新名字傳給前端。例如:

Spring Boot實(shí)現(xiàn)文件上傳的兩種方式

注:這里 會返回 Thymeleaf 實(shí)現(xiàn)的上傳界面。

 @GetMapping("/servlet-upload-page")
public String uploadImageByServlet(Model model) {
    model.addAttribute("message", "please choose file to be uploaded");
    return "upload/servlet-upload";
}

界面內(nèi)容為:

<body>
<h2>Upload Image Example</h2>
<p th:text="${message}" th:if="${message ne null}" class="alert alert-primary"></p>
<form method="post" th:action="@{/servlet-upload}" enctype="multipart/form-data">
    <div class="form-group">
        <input type="file" name="image" accept="image/*" class="form-control-file">
        <input type="file" name="image" accept="image/*" class="form-control-file">
    </div>
    <button type="submit" class="btn btn-primary">Upload image</button>
</form>
<span th:if="${msg != null}" th:text="${msg}"></span>
</body>
</html>

其中,@{/servlet-upload} 指向的是 @WebServlet(name = "MultipartServlet", urlPatterns = "/servlet-upload") 中將 Servlet 注冊到的 url。

03-通過 Spring Boot 中的 MultipartFile 處理上傳請求

通過 Spring Boot 來實(shí)現(xiàn)文件上傳功能會更簡單,它的自動化配置機(jī)制已經(jīng)做了大部分的工作。 開發(fā)人員的工作就是定義一個(gè) Controller,處理文件上傳請求就可以了。

@Controller
public class UploadController {

    public static String UPLOAD_DIRECTORY = System.getProperty("user.dir") + File.separator + "uploads";

    @GetMapping("/upload")   // 主要返回文件上傳頁面
    public String uploadImage(Model model) {
        model.addAttribute("message", "please choose file to be uploaded");
        return "upload/index";
    }
    
    @PostMapping("/upload")  // 處理文件上傳 POST 請求
    public String upload(@RequestParam("image")MultipartFile[] files,
                         Model model)
            throws IOException {

        StringBuilder sb = new StringBuilder();
        for (MultipartFile file : files) {
            if (file.getSize() <= 0) {
                continue;
            }
            final String newFileName = save(file);
            final String msg = String.format("uploaded file %s, and new filename is %s%n", file.getOriginalFilename(), newFileName);
            sb.append(msg);
        }
        model.addAttribute("msg", sb.toString());

        return "upload/index";
    }

    private String save(MultipartFile file) throws IOException{
        String newFileName = genNewFileName(file.getOriginalFilename());
        final Path filePath = Paths.get(UPLOAD_DIRECTORY, newFileName);
        Files.write(filePath, file.getBytes());

        System.out.println("file saved to: " + filePath);
        return newFileName;
    }
}

Spring Boot 中,文件上傳請求(multipart request)被 StandardServletMultipartResolver 進(jìn)一步封裝為 StandardMultipartHttpServletRequest。 解析原請求的過程與我在前面介紹 Servlet 的方式時(shí)基本類似:

private void parseRequest(HttpServletRequest request) {
    try {
        Collection<Part> parts = request.getParts();
        this.multipartParameterNames = new LinkedHashSet<>(parts.size());
        MultiValueMap<String, MultipartFile> files = new LinkedMultiValueMap<>(parts.size());
        for (Part part : parts) {  
            String headerValue = part.getHeader(HttpHeaders.CONTENT_DISPOSITION);
            ContentDisposition disposition = ContentDisposition.parse(headerValue);
            String filename = disposition.getFilename();
            if (filename != null) {
                // 把文件添加到 files
                if (filename.startsWith("=?") && filename.endsWith("?=")) {
                    filename = MimeDelegate.decode(filename);
                }
                // part 被封裝為 StandardMultipartFile,它是 MultipartFile 的一個(gè)實(shí)現(xiàn)類
                files.add(part.getName(), new StandardMultipartFile(part, filename));
            }
            else {
                // 把不是文件的屬性添加到 multipartParameterNames 中
                this.multipartParameterNames.add(part.getName());
            }
        }
        setMultipartFiles(files);
    }
    catch (Throwable ex) {
        handleParseFailure(ex);
    }
}

通過上面的代碼可以了解到,Client 提交的 POST 請求中,上傳的文件被封裝稱 MultipartFile。 所以,我們在 Controller 中的處理方法中,可以通過 @RequestParam 的方式拿到這個(gè)文件列表進(jìn)行處理,就像我們的 UploadController 實(shí)現(xiàn)的那樣。

04-總結(jié)

在今天的文章中,我介紹了文件上傳的兩種實(shí)現(xiàn)方式,從純 Servlet 實(shí)現(xiàn),到基于 Spring Boot MVC 實(shí)現(xiàn)。 并且分析了 Spring Boot 中對 Multipart 請求的封裝過程。

?文章來源地址http://www.zghlxwxcb.cn/news/detail-449847.html

到了這里,關(guān)于Spring Boot實(shí)現(xiàn)文件上傳的兩種方式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • gitee上傳代碼到倉庫的兩種方式

    gitee上傳代碼到倉庫的兩種方式

    代碼上傳到gitee有兩種方式 通過命令窗口實(shí)現(xiàn) 通過idea實(shí)現(xiàn) 目錄 一、gitee創(chuàng)建倉庫 ?二、通過命令行上傳代碼到倉庫 ?1.打開命令行 ?2.配置信息 ?3.初始化本地倉庫 ?4.上傳代碼至本地倉庫 ?5.添加注釋 ?6.本地倉庫與遠(yuǎn)程倉庫連接 7.強(qiáng)制推送(遠(yuǎn)程倉庫為空可跳過) 8.本地倉

    2024年02月10日
    瀏覽(27)
  • React下載文件的兩種方式

    React下載文件的兩種方式 - 代碼先鋒網(wǎng) 不知道有用沒用看著挺整齊? 沒試過

    2024年02月12日
    瀏覽(31)
  • Spring Boot 實(shí)現(xiàn)多文件上傳

    Spring Boot 實(shí)現(xiàn)多文件上傳

    代碼結(jié)構(gòu): Controller層 跨域攔截器配置 application.properties 配置 前端頁面 效果展示 獲取圖片的url并且讀取圖片 修改tomcat的server.xml文件 加上下面這句

    2023年04月08日
    瀏覽(23)
  • Spring Boot實(shí)現(xiàn)文件上傳和下載

    1.文件上傳 在pom.xml文件中添加依賴: spring-boot-starter-web 和 spring-boot-starter-thymeleaf 。 創(chuàng)建一個(gè)上傳前端的頁面,包括一個(gè)表單來選擇文件和一個(gè)提交按鈕。 在Controller中添加一個(gè)POST方法,該方法接受 MultipartFile 參數(shù),將文件保存在服務(wù)器上。 在application.properties文件中配置上

    2024年02月04日
    瀏覽(20)
  • Springboot之把外部依賴包納入Spring容器管理的兩種方式

    Springboot之把外部依賴包納入Spring容器管理的兩種方式

    在Spring boot項(xiàng)目中,凡是標(biāo)記有@Component、@Controller、@Service、@Configuration、@Bean等注解的類,Spring boot都會在容器啟動的時(shí)候,自動創(chuàng)建bean并納入到Spring容器中進(jìn)行管理,這樣就可以使用@Autowired等注解,在需要使用bean的業(yè)務(wù)類中進(jìn)行注入。這里起到關(guān)鍵作用的就是@ComponentScan,

    2024年02月14日
    瀏覽(21)
  • Spring Boot 實(shí)現(xiàn)文件本地以及OSS上傳

    Maven依賴 封裝工具類 上面的代碼我們可以定義一個(gè)工具類,這樣在任何需要文件上傳的地方只需要調(diào)用 upload 方法即可,大大減少了代碼量 使用工具類

    2024年03月08日
    瀏覽(22)
  • Spring boot實(shí)現(xiàn)上傳文件至本地或服務(wù)器

    大家好 我是程序猿小張 圖片文件上傳是項(xiàng)目中必不可少的一個(gè)功能,上傳的地址也當(dāng)然是優(yōu)先選擇第三方的對象存儲,例如七牛云、阿里云等等,但是當(dāng)中的話只有七牛云是有一個(gè)免費(fèi)額度的,其他都是要收錢的。所以就想著,哎,這個(gè)能不能上傳到本地呢?答案是肯定可

    2024年02月11日
    瀏覽(98)
  • js - 圖片base64轉(zhuǎn)file文件的兩種方式

    js - 圖片base64轉(zhuǎn)file文件的兩種方式

    最近項(xiàng)目中需要實(shí)現(xiàn)把圖片的base64編碼轉(zhuǎn)成file文件的功能,然后再上傳至服務(wù)器。 1.通過new File()將base64轉(zhuǎn)換成file文件,此方式需考慮瀏覽器兼容問題 2.先將base64轉(zhuǎn)換成blob,再將blob轉(zhuǎn)換成file文件,此方法不存在瀏覽器不兼容問題 vue中配合vant的uploader上傳組件使用案例: 打

    2024年02月14日
    瀏覽(32)
  • Pyqt5將.ui文件轉(zhuǎn)換成.py文件的兩種方式

    Pyqt5將.ui文件轉(zhuǎn)換成.py文件的兩種方式

    PyQt 5安裝成功后,pyuic5命令默認(rèn)安裝在%/python3x/Scripts目錄下。我的pyuic5的安裝路徑是E:python35.Scripts。 如果想將firstMainWin.ui轉(zhuǎn)換成.py文件,輸入以下命令即可: 注意:如果輸入pyuic5命令沒有得到正確提示,而是提示“pyuic5不是內(nèi)部命令或外部命令,也不是可運(yùn)行的程序或批處理

    2024年02月11日
    瀏覽(21)
  • Spring Boot + MinIO 實(shí)現(xiàn)文件切片極速上傳技術(shù)

    Spring Boot + MinIO 實(shí)現(xiàn)文件切片極速上傳技術(shù)

    ??歡迎來到SpringBoot框架學(xué)習(xí)專欄~ ☆* o(≧▽≦)o *☆嗨~我是IT·陳寒?? ?博客主頁:IT·陳寒的博客 ??該系列文章專欄:SpringBoot ??其他專欄:Java學(xué)習(xí)路線 Java面試技巧 Java實(shí)戰(zhàn)項(xiàng)目 AIGC人工智能 數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí) ??文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指

    2024年02月04日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包