【问题标题】:Using a map to set parameters for a rest call using RestTemplate使用地图为使用 RestTemplate 的休息调用设置参数
【发布时间】:2026-02-15 02:50:01
【问题描述】:

我目前正在使用一段代码来设置参数,并且我使用 restTemplate 对 URL 进行 REST 调用,它工作正常:

MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("grant_type", grantType);
map.add("client_id", clientId);
map.add("client_secret", clientSecret);
HttpEntity<?> entity = new HttpEntity<Object>(map);
restTemplate.exchange("myurl", HttpMethod.POST, entity, Void.class);

但如果我使用的是LinkedMultiValueMap,那是因为我在网上查看过 ;)

如果我用HashMap 替换它,它也能正常工作,那么任何人都可以告诉我使用LinkedMultiValueMap 的优势吗?

代码HashMap:

Map<String, String> map = new HashMap<String, String>();
map.put("grant_type", grantType);
map.put("client_id", clientId);
map.put("client_secret", clientSecret);
HttpEntity<?> entity = new HttpEntity<Object>(map);
restTemplate.exchange("myurl", HttpMethod.POST, entity, Void.class);

我可以看到我们可以保留LinkedMultiValueMap 中的参数顺序,但这在我的项目中并不重要......所以如果顺序很重要,我仍然可以使用LinkedHashMap

编辑:

如果我使用 APPLICATION_FORM_URLENCODED 和 HashMap,看起来我需要 MultiValueMap,此代码会引发异常:

Map<String, String> map = new HashMap<String, String>();
map.add("grant_type", grantType);
map.add("client_id", clientId);
map.add("client_secret", clientSecret);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<?> entity = new HttpEntity<Object>(map, headers);
restTemplate.exchange("myurl", HttpMethod.POST, entity, Void.class);

例外:

org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [java.util.HashMap] and content type [application/x-www-form-urlencoded]
        at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:784)
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:567)
        at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:530)
        at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:448)
        at uk.co.wowcher.marketplace.commons.rest.RestTemplateUtils.getForEntity(RestTemplateUtils.java:54)
        at uk.co.wowcher.marketplace.submission.service.ParameterService.getProductParameterVOs(ParameterService.java:38)
        at uk.co.wowcher.marketplace.submission.service.ParameterService$$FastClassBySpringCGLIB$$3f87231d.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85)
        at uk.co.wowcher.marketplace.submission.logging.MarketplaceLogger.logMethodCalls(MarketplaceLogger.java:27)
        at sun.reflect.GeneratedMethodAccessor72.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:483)
        at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
        at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
        at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:68)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
        at uk.co.xxx.marketplace.submission.service.ParameterService$$EnhancerBySpringCGLIB$$a52b80b.getProductParameterVOs(<generated>)
        at uk.co.xxx.marketplace.submission.service.SubmissionService.getAgreementData(SubmissionService.java:449)
       at uk.co.xxx.marketplace.submission.service.SubmissionService$$FastClassBySpringCGLIB$$92bbe798.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)

所以,看起来用 HashMap 设置一些参数根本不是一个好主意...... 所以我现在删除了接受的答案,等待更多关于这一点的解释...... 而且我有合适的转换器(converters.add(new FormHttpMessageConverter());),我的意思是如果我使用 MultiValueMap 我没有异常,所以 HashMap 是问题!

【问题讨论】:

    标签: java spring spring-mvc spring-restcontroller


    【解决方案1】:

    与其他Map 实现相比,使用LinkedMultiValueMap 的唯一真正优势是它可以存储多个值。

    如果您需要为同一个键传递多个值(例如,如果您需要传递一组表单复选框值),这将非常有用。

    请参阅 JavaDoc here

    在您的情况下,由于每个键只有一个值,因此您应该能够安全地使用 HashMap

    【讨论】:

      【解决方案2】:

      MultiValueMap 用于为单个 KEY(Map(key:ArrayOfValues[])) 存储多个值,而 LinkedMultiValueMap 做同样的事情,但插入顺序保持不变。在您的情况下,HashMap 就足够了,因为LinkedMultiValueMap 的性能将比HashMap 慢,并且您的场景不需要HashMap

      【讨论】: