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

如何用Spring自定义ArgumentResolver封装请求参数到MyStructure类?

简化Spring Controller方法参数的实现方案

问题背景

现有Spring Controller方法签名如下:

@RequestMapping(value = {"/article", "/article/{id}", "/article/{name}"}, method = RequestMethod.GET,
                consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

public ResponseEntity<JsonNode> get(@PathVariable Map<String, String> pathVarsMap, @RequestParam(value="test") MultiValueMap<String, String> test, @RequestBody(required=false) JsonNode requestBody )

希望将该方法简化为:

public ResponseEntity<JsonNode> get( MyStructure mystr)

其中MyStructure类需要包含原方法中路径变量Map、请求参数test、可选请求体对应的属性,已知需自定义Resolver实现resolveArgument方法,但不清楚完整步骤,也不确定能否在MyStructure中兼容MultiValueMap和RequestBody类型属性。


完整实现步骤

1. 定义MyStructure类

直接封装需要的参数属性,无需添加Spring参数注解(注解逻辑在Resolver中处理):

import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.util.MultiValueMap;
import java.util.Map;

public class MyStructure {
    private Map<String, String> pathVarsMap;
    private MultiValueMap<String, String> test;
    private JsonNode requestBody;

    // 生成getter/setter,或用Lombok的@Data注解简化
    public Map<String, String> getPathVarsMap() {
        return pathVarsMap;
    }

    public void setPathVarsMap(Map<String, String> pathVarsMap) {
        this.pathVarsMap = pathVarsMap;
    }

    public MultiValueMap<String, String> getTest() {
        return test;
    }

    public void setTest(MultiValueMap<String, String> test) {
        this.test = test;
    }

    public JsonNode getRequestBody() {
        return requestBody;
    }

    public void setRequestBody(JsonNode requestBody) {
        this.requestBody = requestBody;
    }
}

2. 实现自定义HandlerMethodArgumentResolver

核心逻辑是从请求中提取路径变量、请求参数、请求体,组装成MyStructure对象:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.support.ServletServerHttpRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;

public class MyStructureArgumentResolver implements HandlerMethodArgumentResolver {

    private final ObjectMapper objectMapper;
    private final HttpMessageConverter<JsonNode> jsonConverter;

    // 构造注入Spring容器中的ObjectMapper和Json转换器
    public MyStructureArgumentResolver(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
        this.jsonConverter = new MappingJackson2HttpMessageConverter(objectMapper);
    }

    // 判断当前参数是否为MyStructure类型,是则启用该Resolver
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return MyStructure.class.isAssignableFrom(parameter.getParameterType());
    }

    // 提取请求数据并组装MyStructure
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        MyStructure myStructure = new MyStructure();
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

        // 1. 获取路径变量Map(Spring标准存储位置)
        if (request != null) {
            Map<String, String> pathVars = (Map<String, String>) request.getAttribute(
                org.springframework.web.servlet.HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE
            );
            myStructure.setPathVarsMap(pathVars);
        }

        // 2. 获取请求参数test对应的MultiValueMap
        MultiValueMap<String, String> testParams = webRequest.getParameterMap();
        myStructure.setTest(testParams);

        // 3. 获取可选请求体(兼容无请求体的情况)
        try {
            if (request != null && request.getContentLength() > 0) {
                HttpInputMessage inputMessage = new ServletServerHttpRequest(request);
                JsonNode requestBody = jsonConverter.read(JsonNode.class, inputMessage);
                myStructure.setRequestBody(requestBody);
            }
        } catch (IOException ignored) {
            // 非必填参数,捕获异常后保持requestBody为null即可
        }

        return myStructure;
    }
}

3. 注册自定义Resolver

将Resolver加入Spring MVC的参数解析器列表:

Spring Boot项目(配置类方式)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    private final ObjectMapper objectMapper;

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

    @Bean
    public MyStructureArgumentResolver myStructureArgumentResolver() {
        return new MyStructureArgumentResolver(objectMapper);
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(myStructureArgumentResolver());
    }
}
传统Spring MVC项目(XML配置方式)
<mvc:annotation-driven>
    <mvc:argument-resolvers>
        <bean class="com.yourpackage.MyStructureArgumentResolver">
            <constructor-arg ref="objectMapper"/>
        </bean>
    </mvc:argument-resolvers>
</mvc:annotation-driven>

<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"/>

4. 修改Controller方法

直接使用简化后的方法签名:

@RequestMapping(value = {"/article", "/article/{id}", "/article/{name}"}, method = RequestMethod.GET,
                consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<JsonNode> get(MyStructure mystr) {
    // 直接通过mystr.getPathVarsMap()、mystr.getTest()、mystr.getRequestBody()获取参数
    // 业务逻辑处理...
    return ResponseEntity.ok(...);
}

关键说明

  • 完全可以在MyStructure中包含MultiValueMap和JsonNode(请求体)类型属性,自定义Resolver能完整提取对应数据并赋值。
  • 路径变量通过Spring标准的URI_TEMPLATE_VARIABLES_ATTRIBUTE属性获取,逻辑稳定可靠。
  • 请求体使用Spring原生的HttpMessageConverter处理,和@RequestBody的解析逻辑一致,保证兼容性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 00:25:17