UriComponentsBuilder - 如何替换一些查询参数并移除未使用的参数?

3

嘿,我有一个包含多个查询参数的URL,用于搜索。这是一个HATEOAS链接。

https://someurl/customers?customer-id={customer-id}&type={type}&something={something}

我希望只替换其中两个参数。

Map<String, String> params = new HashMap<>();
    params.put("customer-id", customerId);
    params.put("something", something)

    UriComponents customerUrl = UriComponentsBuilder
          .fromHttpUrl(specialURL)
          .buildAndExpand(params).encode();

但是这会抛出异常。
java.lang.IllegalArgumentException: Map has no value for 'type'
    at org.springframework.web.util.UriComponents$MapTemplateVariables.getValue(UriComponents.java:346) ~[spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]

这里最好的解决方法是什么?假设我有大约7个参数,用空字符串替换它们或将字符串切成一半似乎都很别扭。

它的内部实现期望所有的键都必须在参数中存在,否则你将会得到这个异常。 - Alpesh Jikadra
1
你可能想解析特殊URL的查询字符串并将其放入映射中。现在你已经知道了没有查询的URL。你知道你想要发送什么,所以你可以在这里使用两种方法。 1)只附加存在于URL中的参数进行编码。 2)始终实例化完整的映射(所有非必需字段为空/ null / empty(任何有效值)),然后可以将该映射传递给URI组件构建器。 - RAHUL ROY
想要删除所有查询参数的人可以执行以下操作:builder.replaceQuery("") - Wim Deblauwe
2个回答

3

UriComponents 始终期望映射中存在所有关键数据,以下是由 UriComponents 使用并抛出异常的代码。

@Override
public Object getValue(String name) {
    if (!this.uriVariables.containsKey(name)) {
        throw new IllegalArgumentException("Map has no value for '" + name + "'");
    }
    return this.uriVariables.get(name);
}

解决方案:

要解决您的问题,您可以尝试以下代码。

class Param extends HashMap<String, String>{


    @Override
    public String get(Object key) {
        if(!super.containsKey(key)){
            super.put(key.toString(), "");
        }
        return super.getOrDefault(key, "t");
    }

    @Override
    public boolean containsKey(Object arg0) {
        return true;
    }   
}

public class UriComponenet {

    public static void main(String[] args) {

        Param params = new Param();
        params.put("customer-id", "1");
        String specialURL="https://someurl/customers?customer-id={customer-id}&type={type}&something={something}";
        UriComponents customerUrl = UriComponentsBuilder
              .fromHttpUrl(specialURL)
              .buildAndExpand(params).encode();

        System.out.println(customerUrl);        
    }
}

我已经扩展了HashMap类到Param,并将该类用作buildAndExpand方法的输入。

我希望这能解决您的问题。


哦,为什么默认值是“t”呢?这确实解决了不抛出的问题,但是看起来我的API设计似乎没有像应该那样工作。没有返回任何响应。 - kristjan reinhold
这只是一个错误,现在你甚至不需要那个 getOrDefault 方法,你可以直接使用 get 方法了。 - Alpesh Jikadra

3
public static <T> UriComponents removeQueryParams(URI uri, Set<T> removeThese) {

    UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder
        .newInstance()
        .scheme(uri.getScheme())
        .schemeSpecificPart(uri.getSchemeSpecificPart())
        .userInfo(uri.getUserInfo())
        .host(uri.getHost())
        .port(uri.getPort())
        .path(uri.getPath())
        .fragment(uri.getFragment());

    UriComponents uriComponents = UriComponentsBuilder
        .fromUri(uri).build();

    MultiValueMap<String, String> args = new LinkedMultiValueMap<>(uriComponents.getQueryParams());
    removeThese.forEach(o -> args.remove(o.toString()));

    return uriComponentsBuilder
        .queryParams(args).build();
}

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