如何用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
相关产品推荐
相关产品推荐

