将RestTemplate与对象一起用作数据和application / x-www-form-urlencoded内容类型?

时间:2019-06-12 14:13:18

标签: java spring spring-boot

我需要通过内容类型为MultiValueMap的{​​{1}}发布对象(例如,不是RestTemplate)。当我尝试这样做时...

application/x-www-form-urlencoded

...我收到以下错误:

  

org.springframework.web.client.RestClientException:无法写入请求:未为请求类型[com.whatever.MyRequestPayload]和内容类型[application / x-www-form-urlencoded]找到合适的HttpMessageConverter

这是我在HttpHeaders headers = new HttpHeaders(); HttpEntity request; headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED) // data is some generic type request = new HttpEntity<>(data, headers); // clazz is the Class<T> being returned restTemplate.exchange(url, method, request, clazz) 中看到的内容:

message converters

我为什么不想提供restTemplate.getMessageConverters()两个原因:

  1. 这是通用代码,用于将请求发送到多个端点,因此添加专门用于MultiValueMap的重载只会使事情复杂化
  2. 似乎没有必要-我只是不知道需要使用哪个HttpMessageConverter来支持将对象转换为x-www-form-urlencoded字符串

5 个答案:

答案 0 :(得分:0)

您是否尝试过将MappingJackson2HttpMessageConverter添加到RestTemplate

restTemplate.getMessageConverters().add(getMappingJackson2HttpMessageConverter());

public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
    MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
    mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_FORM_URLENCODED));
    return mappingJackson2HttpMessageConverter;
}

答案 1 :(得分:0)

我最终不得不编写一个自定义HTTP消息转换器,该转换器接收任何对象并将其作为www-form-urlencoded内容写到请求主体中:

用法

RestTemplate template = new RestTemplate(...);

template.getMessageConverters().add(new ObjectToUrlEncodedConverter(mapper));

ObjectToUrlEncodedConverter

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;

public class ObjectToUrlEncodedConverter implements HttpMessageConverter
{
    private static final String Encoding = "UTF-8";

    private final ObjectMapper mapper;

    public ObjectToUrlEncodedConverter(ObjectMapper mapper)
    {
        this.mapper = mapper;
    }

    @Override
    public boolean canRead(Class clazz, MediaType mediaType)
    {
        return false;
    }

    @Override
    public boolean canWrite(Class clazz, MediaType mediaType)
    {
        return getSupportedMediaTypes().contains(mediaType);
    }

    @Override
    public List<MediaType> getSupportedMediaTypes()
    {
        return Collections.singletonList(MediaType.APPLICATION_FORM_URLENCODED);
    }

    @Override
    public Object read(Class clazz, HttpInputMessage inputMessage) throws HttpMessageNotReadableException
    {
        throw new NotImplementedException();
    }

    @Override
    public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws HttpMessageNotWritableException
    {
        if (o != null)
        {
            String body = mapper
                .convertValue(o, UrlEncodedWriter.class)
                .toString();

            try
            {
                outputMessage.getBody().write(body.getBytes(Encoding));
            }
            catch (IOException e)
            {
                // if UTF-8 is not supporter then I give up
            }
        }
    }

    private static class UrlEncodedWriter
    {
        private final StringBuilder out = new StringBuilder();

        @JsonAnySetter
        public void write(String name, Object property) throws UnsupportedEncodingException
        {
            if (out.length() > 0)
            {
                out.append("&");
            }

            out
                .append(URLEncoder.encode(name, Encoding))
                .append("=");

            if (property != null)
            {
                out.append(URLEncoder.encode(property.toString(), Encoding));
            }
        }

        @Override
        public String toString()
        {
            return out.toString();
        }
    }
}

答案 2 :(得分:0)

如果您使用WebMvcConfigurerAdapter,则可能会遇到此类错误。从Spring 5.x.x开始不推荐使用WebMvcConfigurerAdapter。尝试使用WebMvcConfigurer。完成后,您将必须覆盖:

@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}

答案 3 :(得分:0)

您可以尝试使用https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/converter/FormHttpMessageConverter.html

RestTemplate template = new RestTemplate(...);
template.getMessageConverters().add(new org.springframework.http.converter.FormHttpMessageConverter.FormHttpMessageConverter());

答案 4 :(得分:-1)

您可以如下所示将FormHttpMessageConverter用于内容类型“ application / x-www-form-urlencoded”,并在主体的RestTemplate post方法中以MultiValueMap

的形式发送数据
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate" lazy-init="true">
    <constructor-arg name="requestFactory" ref="bufferingClientHttpRequestFactory" />
    <property name="errorHandler" ref="responeErrorHandler" />
    <property name="messageConverters">
    <list>
        <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
    </list>
</property>
</bean>

Java Config版本

@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();          
    restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
    restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    return restTemplate 
}