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

Java Spring中如何将QueryParams里的JSON转为嵌套对象?

解决URL查询参数中JSON字符串转嵌套泛型对象的问题

你遇到的核心问题是URL中search参数的JSON字符串无法自动绑定到泛型记录CsvParams<T>的search字段,以下是几种无需重复编写ObjectMapper样板代码的简洁解决方案:

方案1:Spring全局注册JSON字符串转对象转换器

自定义Spring类型转换器,让框架自动将search参数的JSON字符串转为目标对象:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

@Component
public class JsonToTargetObjectConverter<T> implements Converter<String, T> {
    private final ObjectMapper objectMapper;

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

    @Override
    @SuppressWarnings("unchecked")
    public T convert(String jsonStr) {
        try {
            // 获取泛型目标类型并完成反序列化
            return (T) objectMapper.readValue(jsonStr, 
                objectMapper.getTypeFactory().constructType(getClass().getGenericSuperclass()));
        } catch (Exception e) {
            throw new IllegalArgumentException("search参数JSON格式错误", e);
        }
    }
}

之后在Controller中直接使用泛型记录即可,框架会自动完成转换:

@GetMapping("/list/csv")
public ResponseEntity<?> getCsvData(@ModelAttribute CsvParams<YourSearchDto> params) {
    // params.search()已自动转为YourSearchDto类型,可直接使用
    return ResponseEntity.ok(params);
}

方案2:自定义参数解析器(针对CsvParams专属处理)

如果不想全局生效,可自定义参数解析器,仅处理CsvParams<T>类型的参数:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.MethodParameter;
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;

public class CsvParamsResolver implements HandlerMethodArgumentResolver {
    private final ObjectMapper objectMapper;

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

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return CsvParams.class.isAssignableFrom(parameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                 NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String searchJson = webRequest.getParameter("search");
        // 获取泛型参数的实际类型
        Class<?> searchType = (Class<?>) parameter.getGenericParameterType().getActualTypeArguments()[0];
        Object searchObj = objectMapper.readValue(searchJson, searchType);
        
        // 此处可扩展处理其他查询参数,示例简化仅处理search
        return new CsvParams<>(searchObj);
    }
}

注册解析器到Spring配置:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    private final ObjectMapper objectMapper;

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

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new CsvParamsResolver(objectMapper));
    }
}

Controller中直接使用即可:

@GetMapping("/list/csv")
public ResponseEntity<?> getCsvData(CsvParams<YourSearchDto> params) {
    return ResponseEntity.ok(params);
}

方案3:在记录类上添加Jackson反序列化注解

直接在CsvParams记录类上配置自定义反序列化器,让Jackson自动处理转换:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

@JsonDeserialize(using = CsvParamsDeserializer.class)
public record CsvParams<T>(T search) {}

实现对应的反序列化器:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

public class CsvParamsDeserializer extends JsonDeserializer<CsvParams<?>> {
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public CsvParams<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        Class<?> searchType = (Class<?>) ctxt.getContextualType().getActualTypeArguments()[0];
        Object searchObj = objectMapper.readValue(p.getText(), searchType);
        return new CsvParams<>(searchObj);
    }
}

Controller中使用@RequestParam结合注解即可:

@GetMapping("/list/csv")
public ResponseEntity<?> getCsvData(@RequestParam CsvParams<YourSearchDto> params) {
    return ResponseEntity.ok(params);
}

以上方案均基于Spring或Jackson的原生机制,彻底消除了手动调用ObjectMapper的样板代码,实现参数的自动绑定转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 03:41:31