オブジェクトをデータとして、コンテンツ タイプを application/x-www-form-urlencoded にして RestTemplate を使用しますか? 質問する

オブジェクトをデータとして、コンテンツ タイプを application/x-www-form-urlencoded にして RestTemplate を使用しますか? 質問する

コンテンツ タイプ の を介してオブジェクト ( 以外MultiValueMap)を投稿する必要があります。 そうしようとすると...RestTemplateapplication/x-www-form-urlencoded

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)

...次のエラーが発生します:

org.springframework.web.client.RestClientException: リクエストを書き込めませんでした: リクエスト タイプ [com.whatever.MyRequestPayload] およびコンテンツ タイプ [application/x-www-form-urlencoded] に適した HttpMessageConverter が見つかりません

内部で私が見ているものは次のとおりですrestTemplate.getMessageConverters()

メッセージコンバータ

を提供したくないのはなぜですかMultiValueMap?理由は2つあります。

  1. これは複数のエンドポイントにリクエストを送信するために使用される汎用コードなので、専用のオーバーロードを追加すると、x-www-form-urlencoded物事が複雑になるだけです。
  2. そうする必要はないようです。オブジェクトをx-www-form-urlencoded文字列に変換するにはどの HttpMessageConverter を使用すればよいのか分からないだけです。

ベストアンサー1

最終的には、任意のオブジェクトを受け取り、それを www-form-urlencoded コンテンツとしてリクエスト本体に書き出すカスタム HTTP メッセージ コンバーターを作成する必要がありました。

使用法

RestTemplate template = new RestTemplate(...);

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

オブジェクトから URL エンコードされたコンバーター

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();
        }
    }
}

おすすめ記事