【问题标题】:Make Spring use Jackson to convert JSON encoded @RequestParam in GET endpoint让 Spring 使用 Jackson 在 GET 端点中转换 JSON 编码的 @RequestParam
【发布时间】:2023-03-20 08:51:01
【问题描述】:

这是我在stackoverflow中的第一个问题,所以请温柔:)

有一个现有的 GET 端点可以转换为 POST。 需要对其进行扩展以接受查询参数filterKeys,该参数将包含 JSON 编码数据。这种方法不是很常见,但是一些大型 API 正在使用它。 工作方法是将查询参数映射到字符串,然后使用控制器方法中的 Jackson ObjectMapper 反序列化为 Java 对象。 有什么方法可以在后台某处应用此 Jackson 反序列化,就像 Spring 开箱即用地支持 @RequestBody 一样?

JSON 编码的filterKeys 示例:

[
  {
    "parameter": "datetime",
    "value": {
      "type": "INT_RANGE",
      "start": 1275782400,
      "end": 1571443199
    }
  },
  {
    "parameter": "value",
    "value": {
      "type": "LONG_RANGE",
      "start": 100,
      "end": 200
    }
  }
]

Java 对象:

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Getter;

import javax.validation.constraints.NotNull;
import java.util.List;

@Getter
@AllArgsConstructor
@JsonInclude
public class FilterKeyRequest {

    @NotNull
    private String parameter;
    @NotNull
    private FilterValue value;

}

我尝试简单地将filterKeys 映射到FilterKeyRequest,这当然行不通。 当前的解决方案是在控制器方法中进行反序列化:

@GetMapping("/data")
public List<TransferResponse> getData(@RequestParam(required = false) int someOtherParam,
                                          @RequestParam(required = false) String filterKeys) throws BadFilterKeyParameter {

        List<FilterKeyRequest> filters = List.of();
        try {
            filters = objectMapper.readValue(filterKeys, new TypeReference<List<FilterKeyRequest>>() {});
        } catch (IOException e) {
            throw new BadFilterKeyParameter("The filterKeys parameters couldn't be encoded due do bad JSON format");
        }

        return someService.getData(someOtherParam, filters);
    }

我真的很想在后台的某个地方优雅地处理这个问题。 org.springframework.core.convert.converter.Converterorg.springframework.web.method.support.HandlerMethodArgumentResolver 可能会以某种方式实现。最好不要显式调用 Jackson 对象映射器。

更新: 我找到了一个带有Converter 的解决方案,但这仍然意味着显式调用Jackson ObjectMapper,但我可以接受:

@Slf4j
@RequiredArgsConstructor
@Component
public class FilterKeyConverter implements Converter<String, List<FilterKeyRequest>> {

    private final ObjectMapper mapper;

    @Override
    public List<FilterKeyRequest> convert(String source) {
        List<FilterKeyRequest> filters = List.of();
        try {
            filters = mapper.readValue(source, new TypeReference<List<FilterKeyRequest>>() {});
        } catch (IOException e) {
            log.warn("The parameter couldn't be encoded due do bad JSON encoding");
        }
        return filters;
    }
}

【问题讨论】:

    标签: java spring spring-mvc jackson


    【解决方案1】:

    你的 getData() 方法应该在一个@RestController-annotated 类中定义(并且不是 @Controller)

    @RestController
    public DataController {
        @GetMapping("/data")
        public List<TransferResponse> getData(@RequestParam(required = false) int someOtherParam,
                                              @RequestParam(required = false) String filterKeys) throws BadFilterKeyParameter {
    
            List<FilterKeyRequest> filters = List.of();
            try {
                filters = objectMapper.readValue(filterKeys, new TypeReference<List<FilterKeyRequest>>() {});
            } catch (IOException e) {
                throw new BadFilterKeyParameter("The filterKeys parameters couldn't be encoded due do bad JSON format");
            }
    
            return someService.getData(someOtherParam, filters);
        }
    }
    

    【讨论】:

    • 该方法已经在使用@RestController 注释的类中,否则如果没有@ResponseBody 注释,它就无法工作,我的方法中缺少该注释(故意)。感谢您的回答,但不幸的是它与我的问题无关。 @RestController 仅消除了对 @ResponseBody (docs.spring.io/spring/docs/current/javadoc-api/org/…) 的需要,我正在尝试从请求参数中反序列化 JSON。响应的序列化始终有效。
    • @Raif,对不起,我误解了你的问题。 Spring 将尝试非常通用地转换请求参数。如果我有一个包含 JSON 的请求参数,我通常会在控制器方法中将其定义为 Map
    猜你喜欢
    • 1970-01-01
    • 2023-03-09
    • 2014-04-26
    • 1970-01-01
    • 1970-01-01
    • 2017-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多