반응형
반응형 Spring Web Client - SOAP 콜 발신
spring reactive webclient에서 SOAP 콜을 발신하려고 합니다.나는 그것에 대한 서류를 찾을 수 없었다.어떻게 접근할지 궁금하네요.지금 나는 생각하고 있다.
- 별도의 스레드 풀에서 JAXB를 사용하여 SOAP 메시지 생성
- webclient를 통해 문자열로 변환하여 콜을 발신하다
- 돌아오는 길에 별도의 tp로 jaxb를 사용하여 java로 변환하십시오.
단점이나 다른 접근법은 무엇입니까?
다음으로 Spring Reactor의 작업 예를 나타냅니다.https://github.com/gungor/spring-webclient-soap
생성된 JAXB 클래스를 다음과 같이 커스텀인코더로 비누 봉투에 싸서 WebClient의 교환 전략에 추가해야 합니다.
package webclient.soap.encoding;
import org.reactivestreams.Publisher;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.CodecException;
import org.springframework.core.codec.Encoder;
import org.springframework.core.codec.EncodingException;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.PooledDataBuffer;
import org.springframework.util.ClassUtils;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.support.DefaultStrategiesHelper;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.MarshalException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class Jaxb2SoapEncoder implements Encoder<Object> {
private final JaxbContextContainer jaxbContexts = new JaxbContextContainer();
@Override
public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
Class<?> outputClass = elementType.toClass();
return (outputClass.isAnnotationPresent(XmlRootElement.class) ||
outputClass.isAnnotationPresent(XmlType.class));
}
@Override
public Flux<DataBuffer> encode(Publisher<?> inputStream, DataBufferFactory bufferFactory, ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
return Flux.from(inputStream)
.take(1)
.concatMap(value -> encode(value, bufferFactory, elementType, mimeType, hints))
.doOnDiscard(PooledDataBuffer.class, PooledDataBuffer::release);
}
@Override
public List<MimeType> getEncodableMimeTypes() {
return Arrays.asList( MimeTypeUtils.TEXT_XML );
}
private Flux<DataBuffer> encode(Object value ,
DataBufferFactory bufferFactory,
ResolvableType type,
MimeType mimeType,
Map<String, Object> hints){
return Mono.fromCallable(() -> {
boolean release = true;
DataBuffer buffer = bufferFactory.allocateBuffer(1024);
try {
OutputStream outputStream = buffer.asOutputStream();
Class<?> clazz = ClassUtils.getUserClass(value);
Marshaller marshaller = initMarshaller(clazz);
// here should be optimized
DefaultStrategiesHelper helper = new DefaultStrategiesHelper(WebServiceTemplate.class);
WebServiceMessageFactory messageFactory = helper.getDefaultStrategy(WebServiceMessageFactory.class);
WebServiceMessage message = messageFactory.createWebServiceMessage();
marshaller.marshal(value, message.getPayloadResult());
message.writeTo(outputStream);
release = false;
return buffer;
}
catch (MarshalException ex) {
throw new EncodingException(
"Could not marshal " + value.getClass() + " to XML", ex);
}
catch (JAXBException ex) {
throw new CodecException("Invalid JAXB configuration", ex);
}
finally {
if (release) {
DataBufferUtils.release(buffer);
}
}
}).flux();
}
private Marshaller initMarshaller(Class<?> clazz) throws JAXBException {
Marshaller marshaller = this.jaxbContexts.createMarshaller(clazz);
marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name());
return marshaller;
}
}
Web Client 구성
@Bean
public WebClient webClient(){
TcpClient tcpClient = TcpClient.create();
tcpClient
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.doOnConnected(connection -> {
connection.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS));
connection.addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS));
});
ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder().codecs( clientCodecConfigurer -> {
clientCodecConfigurer.customCodecs().encoder(new Jaxb2SoapEncoder());
}).build();
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient).wiretap(true)))
.exchangeStrategies( exchangeStrategies )
.build();
return webClient;
}
웹 클라이언트
public void call(GetCountryRequest getCountryRequest) throws SOAPException, ParserConfigurationException, IOException {
webClient.post()
.uri( soapServiceUrl )
.contentType(MediaType.TEXT_XML)
.body( Mono.just(getCountryRequest) , GetCountryRequest.class )
.retrieve()
.onStatus(
HttpStatus::isError,
clientResponse ->
clientResponse
.bodyToMono(String.class)
.flatMap(
errorResponseBody ->
Mono.error(
new ResponseStatusException(
clientResponse.statusCode(),
errorResponseBody))))
.bodyToMono(GetCountryResponse.class)
.doOnSuccess( (GetCountryResponse response) -> {
//handle success
})
.doOnError(ResponseStatusException.class, error -> {
//handle error
})
.subscribe();
}
SOAP 클라이언트를 비동기 메서드를 가진 stub 클래스로 생성해야 합니다.JAX-WS API는 비동기 호출을 지원합니다.메서드 operationAsync(입력 요구, AsyncHandler 비동기 핸들러)를 생성하려면 enableAsyncMapping과 함께 wsiimport를 사용합니다.
Mono.create()를 사용한 AsyncHandler 작성
Service service = new Service();
ServicePortType portType = service.getPortType();
public Mono<Output> operation(Input input) {
return Mono.create(sink ->
portType.operation(input, outputFuture -> {
try {
sink.success(outputFuture.get());
} catch (Exception e) {
sink.error(e);
}
})
);
}
모노를 재활성화할 수 있습니다.
https://blog.godatadriven.com/jaxws-reactive-client의 투고에서 제안을 발견했습니다.
언급URL : https://stackoverflow.com/questions/49685056/reactive-spring-webclient-making-a-soap-call
반응형
'programing' 카테고리의 다른 글
RewriteRule에서 폴더/디렉토리 제외 (0) | 2023.03.07 |
---|---|
Postgres SQL의 '->>'과 '->'의 차이점은 무엇입니까? (0) | 2023.03.02 |
WooCommerce 3+에서 후크를 통해 제품 가격 변경 (0) | 2023.03.02 |
종료 코드 1 Spring Boot Intellij로 프로세스가 종료되었습니다. (0) | 2023.03.02 |
nginx try_files, proxy_pass 및 업스트림 (0) | 2023.03.02 |