自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

實(shí)戰(zhàn)揭秘!Spring Boot 3.4 多 @RequestBody 處理技巧,輕松應(yīng)對復(fù)雜入?yún)?/h1>

開發(fā) 前端
在實(shí)際開發(fā)中,你可以根據(jù)項(xiàng)目需求選擇合適的方案,從而更高效地處理復(fù)雜的 JSON 請求體解析。希望本指南能幫助你輕松應(yīng)對 Spring Boot 3.4 的多 @RequestBody 解析問題!?

在 Spring Boot 3.4 開發(fā)過程中,@RequestBody 注解是解析 HTTP 請求體 JSON 數(shù)據(jù)的常見方式,能夠自動將數(shù)據(jù)綁定到 Java 對象中。然而,當(dāng) API 需要同時接收多個對象時,直接使用多個 @RequestBody 會導(dǎo)致 HttpMessageNotReadableException 異常。究其原因,這是由于 HttpServletRequest 的輸入流只能被讀取一次,第二個 @RequestBody 無法再次獲取數(shù)據(jù)。

本文將深入剖析這一問題的本質(zhì),并提供兩種不同的解決方案:

  1. 使用 DTO 進(jìn)行封裝(適用于前端可以調(diào)整數(shù)據(jù)格式的場景)。
  2. 自定義 HttpServletRequestWrapper(適用于無法修改前端請求結(jié)構(gòu)的情況)。

通過這些方法,你可以在 Spring Boot 3.4 項(xiàng)目中靈活應(yīng)對復(fù)雜的 JSON 請求體解析問題。

解決方案

方法 1:使用 DTO 進(jìn)行封裝

我們可以創(chuàng)建一個 RequestDTO 類,將 User 和 Person 統(tǒng)一封裝。

package com.icoderoad.dto;

public class RequestDTO {
    private User user;
    private Person person;
    // getter 和 setter
}

然后修改 Controller 方法:

package com.icoderoad.controller;


import com.icoderoad.dto.RequestDTO;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/api")
public class MultiRequestBodyController {
    @PostMapping("/multi")
    public String handleMultiple(@RequestBody RequestDTO dto) {
        return "Received: " + dto.getUser().getName() + " and " + dto.getPerson().getName();
    }
}

這種方式雖然簡單,但要求前端調(diào)整 JSON 數(shù)據(jù)格式。

方法 2:自定義 HttpServletRequestWrapper 允許多次讀取請求體

如果前端無法調(diào)整請求格式,我們可以使用 HttpServletRequestWrapper 解決 InputStream只能讀取一次的問題。

自定義 CachedBodyHttpServletRequest

package com.icoderoad.wrapper;


import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import org.springframework.util.StreamUtils;


import java.io.*;


public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
    private final byte[] cachedBody;


    public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        InputStream requestInputStream = request.getInputStream();
        this.cachedBody = StreamUtils.copyToByteArray(requestInputStream);
    }


    @Override
    public ServletInputStream getInputStream() {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(cachedBody);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener listener) {}
            @Override
            public int read() {
                return byteArrayInputStream.read();
            }
        };
    }
}

創(chuàng)建過濾器攔截請求

package com.icoderoad.filter;


import com.icoderoad.wrapper.CachedBodyHttpServletRequest;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;


import java.io.IOException;


@Component
public class CachedBodyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (request instanceof HttpServletRequest) {
            CachedBodyHttpServletRequest wrappedRequest = new CachedBodyHttpServletRequest((HttpServletRequest) request);
            chain.doFilter(wrappedRequest, response);
        } else {
            chain.doFilter(request, response);
        }
    }
}

配置過濾器

package com.icoderoad.config;


import com.icoderoad.filter.CachedBodyFilter;
import jakarta.servlet.Filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import java.util.List;


@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<Filter> cachedBodyFilter() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new CachedBodyFilter());
        registrationBean.setUrlPatterns(List.of("/*"));
        return registrationBean;
    }
}

結(jié)論

在 Spring Boot 3.4 版本中,同時解析多個 @RequestBody 參數(shù)是一項(xiàng)常見但容易踩坑的挑戰(zhàn)。本文提供了兩種解決方案:

  • DTO 封裝方式適用于可以修改前端請求格式的場景,簡單易用,但需要前端配合調(diào)整 JSON 結(jié)構(gòu)。
  • HttpServletRequestWrapper 方案適用于無法修改前端數(shù)據(jù)格式的情況,能夠確保多個 @RequestBody 參數(shù)的正常解析。

在實(shí)際開發(fā)中,你可以根據(jù)項(xiàng)目需求選擇合適的方案,從而更高效地處理復(fù)雜的 JSON 請求體解析。希望本指南能幫助你輕松應(yīng)對 Spring Boot 3.4 的多 @RequestBody 解析問題!

責(zé)任編輯:武曉燕 來源: 路條編程
相關(guān)推薦

2025-04-27 04:00:00

錯誤頁Spring底層

2025-03-31 01:22:00

2020-04-23 15:59:04

SpringKafka集群

2023-10-23 09:44:00

并發(fā)管理線程

2025-03-27 08:10:19

Spring開發(fā)架構(gòu)

2025-02-17 00:00:45

接口支付寶沙箱

2024-07-03 08:49:32

2023-04-11 16:04:19

Spring Boo端點(diǎn)運(yùn)維

2025-01-07 08:21:03

2024-01-31 08:50:41

Guava并發(fā)工具

2024-12-03 10:46:48

Spring優(yōu)化開發(fā)

2023-09-24 13:55:42

Spring應(yīng)用程序

2024-02-01 18:06:04

Python編程系統(tǒng)

2025-01-13 12:46:31

SpringBootJacksonJSON

2025-02-21 16:00:00

SpringBoot代碼開發(fā)

2025-04-07 03:00:00

SpringBoot數(shù)據(jù)庫

2025-01-15 12:43:23

2025-04-03 07:56:08

電子簽名合同系統(tǒng)Spring

2024-08-09 08:52:26

2025-02-13 08:06:54

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號