Spring Cloud OpenFeign创建动态查询参数失败

8

Spring Cloud OpenFeign 无法创建动态查询参数。它会抛出以下异常,因为 SpringMvcContract 尝试查找不存在的 RequestParam value 属性。

java.lang.IllegalStateException: RequestParam.value() was empty on parameter 0


@RequestMapping(method = RequestMethod.GET, value = "/orders")
Pageable<Order> searchOrder2(@RequestParam CustomObject customObject);

我尝试使用@QueryMap代替@RequestParam,但是@QueryMap不会生成查询参数。

顺便说一下,@RequestParam Map<String, Object> params方法参数可以很好地生成动态查询参数。

但是我想使用自定义对象,使得feign客户端可以从该对象的属性中生成动态查询参数。


1
据我所知,Spring在将查询参数绑定到自定义DTO时不需要使用RequestParam注释。 (参考)。您尝试过不使用RequestParam注释吗?此接口在服务器端是否正常工作?如果此接口仅用于在Feign端生成客户端,请尝试其他格式吗?动态查询参数是什么意思?据我所知,http规范没有动态查询参数这样的东西。 - bhdrkn
感谢 @bhdrkn 的帮助。请查看我的回答。 - mstzn
2个回答

12

来自 Spring Cloud OpenFeign 文档:

Spring Cloud OpenFeign 提供了一个等效的 @SpringQueryMap 注解,用于将 POJO 或 Map 参数注释为查询参数映射

所以你的代码应该是:

@RequestMapping(method = RequestMethod.GET, value = "/orders")
Pageable<Order> searchOrder2(@SpringQueryMap @ModelAttribute CustomObject customObject);

它起作用了,非常感谢。我移除了 @RequestParam,因为它会将对象添加到 URL 中。 - mstzn
1
@mstzn,已删除 - StasKolodyuk
最好希望CustomObject没有任何嵌套对象需要作为查询参数传递。 - James

5

spring-cloud-starter-feign有一个开放问题,用于支持pojo对象作为请求参数。因此,我使用了一个请求拦截器,从feign方法中获取对象,并从其字段创建url的查询部分。感谢@charlesvhe。

public class DynamicQueryRequestInterceptor implements RequestInterceptor {

private static final Logger LOGGER = LoggerFactory.getLogger(DynamicQueryRequestInterceptor.class);

private static final String EMPTY = "";

@Autowired
private ObjectMapper objectMapper;

@Override
public void apply(RequestTemplate template) {
    if ("GET".equals(template.method()) && Objects.nonNull(template.body())) {
        try {
            JsonNode jsonNode = objectMapper.readTree(template.body());
            template.body(null);

            Map<String, Collection<String>> queries = new HashMap<>();
            buildQuery(jsonNode, EMPTY, queries);
            template.queries(queries);
        } catch (IOException e) {
            LOGGER.error("IOException occurred while try to create http query");
        }
    }
}

private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
    if (!jsonNode.isContainerNode()) {
        if (jsonNode.isNull()) {
            return;
        }
        Collection<String> values = queries.computeIfAbsent(path, k -> new ArrayList<>());
        values.add(jsonNode.asText());
        return;
    }
    if (jsonNode.isArray()) {
        Iterator<JsonNode> it = jsonNode.elements();
        while (it.hasNext()) {
            buildQuery(it.next(), path, queries);
        }
    } else {
        Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
        while (it.hasNext()) {
            Map.Entry<String, JsonNode> entry = it.next();
            if (StringUtils.hasText(path)) {
                buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
            } else {
                buildQuery(entry.getValue(), entry.getKey(), queries);
            }
        }
    }
}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接