programing

개체를 데이터 및 응용 프로그램/x-www-form-url 인코딩된 콘텐츠 유형으로 RestTemplate를 사용하시겠습니까?

sourcejob 2023. 6. 28. 21:41
반응형

개체를 데이터 및 응용 프로그램/x-www-form-url 인코딩된 콘텐츠 유형으로 RestTemplate를 사용하시겠습니까?

개체를 게시해야 합니다(예: 그렇지 않음).MultiValueMapa를 통해RestTemplate내용 유형과 함께application/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)

다음 오류가 발생합니다.

기관.스프링 골조웹.클라이언트RestClientException:요청을 쓸 수 없습니다. 요청 유형 [com]에 적합한 HttpMessageConverter를 찾을 수 없습니다.신경쓰지 말아요.MyRequestPayload] 및 내용 유형 [application/x-www-form-urloded]

안에 보이는 것은 다음과 같습니다.restTemplate.getMessageConverters():

message converters

다음 두 가지 이유를 제공하지 않는 이유:

  1. 이것은 여러 엔드포인트로 요청을 보내는 데 사용되는 범용 코드이기 때문에 특별히 오버로드를 추가합니다.x-www-form-urlencoded일을 복잡하게 만들 뿐입니다.
  2. 그럴 필요는 없을 것 같습니다. 개체 변환을 지원하기 위해 어떤 HttpMessageConverter를 사용해야 하는지 모르겠습니다.x-www-form-urlencoded

저는 결국 임의의 객체를 가져와서 요청 본문에 www-form-url-encoded 콘텐츠로 쓰는 사용자 지정 HTTP 메시지 변환기를 작성해야 했습니다.

사용.

RestTemplate template = new RestTemplate(...);

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

개체ToUrl 인코딩 변환기

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

이유: 에서 Java 개체를 요청 본문으로 변환할 수 있는 변환기가 없습니다.x-www-form-urlencoded서식을 정하다

해결책 1: @Josh M.이 게시하는 것처럼 이러한 종류의 변환기를 만듭니다.

솔루션 2: Java 객체를 다음으로 변환MultiValueMap그리고 이미 이름이 붙은 변환기가 있습니다.FormHttpMessageConverter전환되는 봄 부츠에서.MultiValueMap의 요청 단체에.x-www-form-urlencoded자동으로 포맷합니다.

따라서 솔루션 2에서 필요한 것은 Java 객체를 다음으로 변환하는 것입니다.MultiValueMap:

        MultiValueMap<String, String> bodyPair = new LinkedMultiValueMap();
        bodyPair.add(K1, V1);
        bodyPair.add(K1, V2);
        bodyPair.add(K2, V2);
        ...

K1,V1,K2,V2...는 Java 개체의 필드 이름과 해당 값을 의미합니다.Java 클래스에서 선언한 모든 필드를 추가해야 합니다.필드가 너무 많은 경우 Java Reflection 사용을 고려합니다.

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

당신은 다음과 같은 것을 시도해 보았습니까?MappingJackson2HttpMessageConverter에게RestTemplate

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

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

사용 중인 경우WebMvcConfigurerAdapter그런 오류가 발생할 수 있습니다.또한 WebMvcConfigurerAdapter는 Spring 5.x.x에서 더 이상 사용되지 않습니다.사용해 보십시오.WebMvcConfigurer작업이 완료되면 다음을 재정의해야 합니다.

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

아래와 같이 콘텐츠 유형 "application/x-www-form-urlenced"에 대해 FormHttpMessageConverter를 사용하여 본문에 대한 RestTemplate 게시 메서드로 데이터를 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 구성 버전

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

언급URL : https://stackoverflow.com/questions/56564262/use-resttemplate-with-object-as-data-and-application-x-www-form-urlencoded-conte

반응형