You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将HTML表单数据作为JSON请求体传入Java Spring控制器的最佳实践

Spring Boot 表单数据转JSON请求体原生实现方案

首先明确:HTML原生表单默认不支持application/json格式的提交,仅支持application/x-www-form-urlencoded和multipart/form-data两种内容类型。如果你不想使用前端AJAX代码,完全基于Spring官方原生能力处理表单数据,有以下两种成熟的最佳实践:

方案1:使用@ModelAttribute自动绑定表单参数(最推荐轻量方案)

Spring原生提供@ModelAttribute注解,可以直接将表单提交的键值对自动映射到Java对象属性中,无需额外配置,你如果需要JSON格式数据直接用Spring内置的Jackson序列化即可。

示例代码

  1. 定义表单数据传输DTO
// 必须提供无参构造、对应属性的getter/setter
public class UserFormDTO {
    private String username;
    private String email;
    private Integer age;

    // 无参构造
    public UserFormDTO() {}

    // getter和setter省略
}
  1. 控制器接收逻辑
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.ObjectMapper;

@RestController
public class FormController {
    // Spring内置的ObjectMapper可以直接注入,不需要自己new
    private final ObjectMapper objectMapper;

    public FormController(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @PostMapping("/submit/form")
    public String handleFormSubmit(@ModelAttribute UserFormDTO formDTO) throws Exception {
        // 直接将绑定好的DTO序列化为JSON字符串
        String formJson = objectMapper.writeValueAsString(formDTO);
        // 后续业务逻辑处理
        return "提交成功,JSON数据:" + formJson;
    }
}

适用场景

  • 不需要强制请求体为JSON格式,仅需要服务端拿到JSON结构数据
  • 项目业务简单,不想增加额外过滤器配置
  • 兼容传统表单提交的所有场景,包括文件上传

方案2:自定义过滤器统一转换表单请求为JSON请求体

如果你需要让控制器直接通过@RequestBody接收JSON格式的表单数据,和接口接收JSON参数的逻辑完全统一,可以自定义Spring全局过滤器,自动将表单提交的参数转换为JSON请求体,无需修改任何前端代码。

示例代码

  1. 定义全局转换过滤器
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

@Component
public class FormToJsonConverterFilter extends OncePerRequestFilter {
    private final ObjectMapper objectMapper;

    public FormToJsonConverterFilter(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 仅处理表单提交的请求
        if (MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType())) {
            // 读取所有表单参数
            var paramMap = request.getParameterMap();
            // 转换为普通JSON结构,单值参数直接存值,多值参数存数组
            var jsonMap = paramMap.entrySet().stream()
                    .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            entry -> entry.getValue().length == 1 ? entry.getValue()[0] : entry.getValue()
                    ));
            String jsonBody = objectMapper.writeValueAsString(jsonMap);

            // 包装请求,替换请求体和Content-Type
            HttpServletRequest wrappedRequest = new HttpServletRequestWrapper(request) {
                @Override
                public ServletInputStream getInputStream() {
                    var bis = new ByteArrayInputStream(jsonBody.getBytes(StandardCharsets.UTF_8));
                    return new ServletInputStream() {
                        @Override
                        public boolean isFinished() { return bis.available() == 0; }
                        @Override
                        public boolean isReady() { return true; }
                        @Override
                        public void setReadListener(ReadListener listener) {}
                        @Override
                        public int read() { return bis.read(); }
                    };
                }

                @Override
                public String getContentType() {
                    return MediaType.APPLICATION_JSON_VALUE;
                }
            };
            filterChain.doFilter(wrappedRequest, response);
            return;
        }
        filterChain.doFilter(request, response);
    }
}
  1. 控制器直接用@RequestBody接收
@PostMapping("/submit/form")
public String handleFormSubmit(@RequestBody UserFormDTO formDTO) throws Exception {
    // 直接拿到和接口请求一致的DTO对象,不需要额外转换
    return "提交成功";
}

适用场景

  • 需要统一表单提交和接口JSON提交的处理逻辑,减少重复代码
  • 后续计划逐步升级为前后端分离架构,不需要修改控制器逻辑

注意事项

  • 两种方案均为Spring官方原生能力支持,不需要引入任何第三方依赖
  • 如果需要处理带文件上传的表单,仅方案1的@ModelAttribute可以直接兼容,方案2需要单独适配multipart/form-data类型的请求
  • 所有用到的DTO类必须提供无参构造方法和对应属性的getter/setter,否则Spring无法完成自动绑定

内容的提问来源于stack exchange,提问作者Hunter Yavitz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 08:06:05