Spring Boot이 포함된 SOAP 마이크로서비스, 1부에서는 Apache CXF 사용
If you want to skip the introduction and go directly to the code, then you can find it in my GitHub repository ws-employee-soapcxf
회사 명 / 직원 soapcxf
Spring Boot 2.3 및 Apache CXF 3.4가 포함된 SOAP 마이크로서비스
Spring Boot 및 Apache CXF가 포함된 SOAP 마이크로서비스
Spring Boot에서 만든 docker 용기를 사용하여 남겨진 클라이언트에 SOAP 노드를 공개합니다
POC의 기술 스택은 다음과 같습니다.
소프트웨어 요구 사항
워크스테이션은 다음 도구를 올바르게 구성해야 합니다.
WSDL 및 도메인 모델
예제에서는 허구의 직원 SOAP 서비스에서 다음 두 가지 작업을 사용합니다.
WSDL…
View on GitHub
소개
잠깐만...SOAP 마이크로서비스?현재 우리는 REST 웹 서비스나 RPC 프로토콜(예를 들어 gRPC) 등 기술을 바탕으로 하는 마이크로서비스 구조가 다르다.그렇다면 우리는 왜 SOAP와 같은 낡은 협의를 이용하여 마이크로서비스를 실현하는 것에 흥미를 가져야 합니까?좋습니다. 오래된 유류된 단일 프로그램에서 이동하고 있을 때 특히 유용할 수 있습니다. 이 프로그램에서 SOAP 서비스를 통해 다른 시스템이 연결되어 있습니다.이러한 시스템 (클라이언트) 은 업데이트할 수 없으므로 다음과 같은 새로운 인프라에 연결할 수 없는 경우가 많습니다.
서비스의 WSDL 가져오기
Getting the WSDL from an existing SOAP web service is very simple; the standardized way to do it (although it may depend on the framework used to create the webservice) is by postfixing the URL with ?WSDL
or .WSDL
example:
http://mywebservice.domain:8080/endpoint?WSDL
This approach is commonly known as contract-first; we start with the WSDL contract, and then we use Java to implement it. Many times the WSDL comes with the domain model in separate XSD's files.
In our example, we are going to work in a fictitious Employee SOAP service with 2 operations:
- GetEmployeeById
- GetEmployeeByName
WSDL은 SOAP 기반 웹 서비스의 기능을 설명합니다.본고의 가장 중요한 부분은
wsdl:portType
.이 절은 우리가 실현하고자 하는 서비스의 인터페이스를 정의합니다: 조작, 입력과 출력 매개 변수:Next is the WSDL section for
wsdl:portType
:<!--This element defines the service operations and the combination of input and output elements to clients-->
<wsdl:portType name="EmployeeServicePortType">
<wsdl:operation name="GetEmployeeById">
<wsdl:input message="tns:EmployeeByIdRequest"/>
<wsdl:output message="tns:EmployeeResponse"/>
</wsdl:operation>
<wsdl:operation name="GetEmployeesByName">
<wsdl:input message="tns:EmployeeByNameRequest"/>
<wsdl:output message="tns:EmployeesResponse"/>
</wsdl:operation>
</wsdl:portType>
항목 설정
이 항목은 maven을 사용합니다. pom.xml의 속성과 의존성은 다음과 같습니다.
<properties>
<!-- Override BOM property in Spring Boot for Rest Assured and Groovy-->
<!-- With rest-assured 4.3.X upgrade the Groovy from 2.5.7 to 3.0.2 -->
<rest-assured.version>4.3.1</rest-assured.version>
<groovy.version>3.0.2</groovy.version>
<!-- Other properties-->
<java.version>15</java.version>
<cxf.version>3.4.0</cxf.version>
<springboot.version>2.3.3.RELEASE</springboot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- CXF Framework -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- Required if you need to log the request/response -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-features-logging</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
메모:코드 생성
우리는 영역 모델과 WSDL에 기술된 조작에 비추는 자바 클래스를 생성할 것입니다.Apache CXF 프로젝트의 maven 플러그인을 사용하여 코드를 생성합니다.
XSD 및 wsdl 파일은 다음 구조에 있습니다.
<source-code>
├───src
└───main
└───resources
└───wsdl
다음은 pom.xml 플러그인 구성<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
<wsdlOptions>
<wsdlOption> <wsdl>${basedir}/src/main/resources/wsdl/EmployeeServices.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
이 플러그인은 다음 디렉터리에 자바 클래스를 생성합니다.<source-code>/target/generated-sources/cxf
프로젝트 루트 디렉터리의 명령 창에서 실행하여 자바 클래스를 생성합니다.mvn compile
다음 그림은 생성된 클래스를 표시하고 웹 서비스를 실현하는 단점으로 사용할 클래스를 강조합니다. EmployeeServicePortType.
Apache CXF 실행 구성 시
구성이 간단합니다.application.yml 에서는 Apache CXF의 기본 경로를 덮어쓸 수 있습니다. 기본적으로 이 경로는
/services
입니다. 예제에서는 /soap.
를 사용합니다.cxf:
path: /soap
우리는 공개된 서비스에 대한 경로를 제공해야 한다: /service/employee
.@Bean 노드를 생성하여 다음과 같은 구성을 제공합니다.import org.springframework.context.annotation.Configuration;
import javax.xml.ws.Endpoint;
@Configuration
public class ApplicationConfiguration {
@Autowired
private Bus bus;
@Bean
public Endpoint endpoint(EmployeeEndpoint employeeEndpoint) {
EndpointImpl endpoint = new EndpointImpl(bus, employeeEndpoint);
endpoint.publish("/service/employee");
return endpoint;
}
}
구현 서비스
생성된 클래스 중 하나는
EmployeeServicePortType
입니다.이것은 2개의 조작과 입력/출력 파라미터가 있는 인터페이스입니다.다음 예에서 우리는 실현 wsdl:portType section
의 클래스 EmployeeEndpoint
를 만들었다.프레젠테이션 목적으로 우리는 가짜 백엔드를 사용했는데, 이 백엔드는 서비스에 데이터를 제공할 것이다.예를 들어, 백엔드는 데이터 저장소 또는 기타 웹 서비스일 수 있습니다.import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.feature.Features;
import org.springframework.stereotype.Service;
import com.jpworks.employee.*;
@Service
@Slf4j
@Features(features = "org.apache.cxf.ext.logging.LoggingFeature")
public class EmployeeEndpoint implements EmployeeServicePortType{
BackendService backendService;
public EmployeeEndpoint (BackendService backendService){
this.backendService = backendService;
}
@Override
public EmployeesResponse getEmployeesByName(EmployeeByNameRequest parameters) {
EmployeesResponse employeesResponse = new EmployeesResponse();
try{
employeesResponse.getEmployee().addAll(backendService.getEmployeesByName(parameters.getFirstname(), parameters.getLastname()));
}
catch (Exception e){
log.error("Error while setting values for employee object", e);
}
return employeesResponse;
}
@Override
public EmployeeResponse getEmployeeById(EmployeeByIdRequest parameters) {
EmployeeResponse employeeResponse = new EmployeeResponse();
try{
employeeResponse.setEmployee(backendService.getEmployeeById(parameters.getId()));
}
catch (Exception e){
log.error("Error while setting values for employee object", e);
}
return employeeResponse;
}
}
위의 예시에서 우리는 EmployeeServicePortType
을 사용하여 요청과 응답을 응용 프로그램 로그에 기록합니다.@ 기능 응용 프로그램 실행
루트 항목이 실행되는 명령 창에서:
mvn spring-boot:run
콘솔의 로그: . ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.4.RELEASE)
2020-10-02 22:23:49.563 INFO 1 --- [ main] com.jpworks.datajdbc.MainApplication : Starting MainApplication v1.0.1-SNAPSHOT on b6e50b2f461b with PID 1 (/app.jar started by root in /)
2020-10-02 22:23:49.572 DEBUG 1 --- [ main] com.jpworks.datajdbc.MainApplication : Running with Spring Boot v2.3.4.RELEASE, Spring v5.2.9.RELEASE
2020-10-02 22:23:49.573 INFO 1 --- [ main] com.jpworks.datajdbc.MainApplication : The following profiles are active: local
2020-10-02 22:23:51.163 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8081 (http)
2020-10-02 22:23:51.179 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-10-02 22:23:51.179 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.38]
2020-10-02 22:23:51.254 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-10-02 22:23:51.255 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1625 ms
2020-10-02 22:23:51.541 INFO 1 --- [ main] o.s.boot.web.servlet.RegistrationBean : Servlet CXFServlet was not registered (possibly already registered?)
2020-10-02 22:23:51.885 INFO 1 --- [ main] o.a.c.w.s.f.ReflectionServiceFactoryBean : Creating Service {http://service.datajdbc.jpworks.com/}EmployeeEndpointService from class com.jpworks.employee.EmployeeService
2020-10-02 22:23:52.455 INFO 1 --- [ main] org.apache.cxf.endpoint.ServerImpl : Setting the server's publish address to be /service/employee
2020-10-02 22:23:52.646 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-10-02 22:23:52.870 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''
2020-10-02 22:23:52.889 INFO 1 --- [ main] com.jpworks.datajdbc.MainApplication : Started MainApplication in 4.018 seconds (JVM running for 4.625)
사용 가능한 끝점을 얻으려면 브라우저에 다음과 같이 쓰십시오.http://localhost:8081/soap
서비스의 wsdl을 가져오려면 브라우저에 다음과 같이 쓰십시오.
http://localhost:8081/soap/service/employee?wsdl
우리는 POST 호출을 사용하여 Http 클라이언트(예를 들어 PostMan이나 Jmeter)를 사용하여 응용 프로그램을 테스트할 수 있다. (테스트 용례에 대해 응용 프로그램은 다시 발표된 라이브러리를 사용한다.)그러나 저는 전통적인 SoapUI를 사용할 것입니다. 서비스의 단점은 다음과 같습니다.
http://localhost:8081/soap/service/employee.
애플리케이션 콘솔에서 기록된 요청/응답을 볼 수 있습니다.
2020-10-06 15:36:01.396 INFO 102696 --- [ main] com.jpworks.datajdbc.MainApplication : Started MainApplication in 3.104 seconds (JVM running for 3.988)
2020-10-06 15:36:23.958 INFO 102696 --- [nio-8081-exec-1] o.a.c.s.EmployeeServicePortType.REQ_IN : REQ_IN
Address: http://localhost:8081/soap/service/employee
HttpMethod: POST
Content-Type: text/xml;charset=UTF-8
ExchangeId: 872e1281-4545-45ad-9871-331d96c450cf
ServiceName: EmployeeEndpointService
PortName: EmployeeEndpointPort
PortTypeName: EmployeeServicePortType
Headers: {SOAPAction="http://www.jpworks.com/employee/GetEmployeesByName", host=localhost:8081, connection=Keep-Alive, content-type=text/xml;charset=UTF-8, Content-Length=273, accept-encoding=gzip,deflate, user-agent=Apache-HttpClient/4.5.5 (Java/12.0.1)}
Payload: <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:emp="http://www.jpworks.com/employee">
<soapenv:Header/>
<soapenv:Body>
<emp:EmployeeByNameRequest firstname="John" lastname="Miller"/>
</soapenv:Body>
</soapenv:Envelope>
2020-10-06 15:36:23.995 INFO 102696 --- [nio-8081-exec-1] o.a.c.s.E.RESP_OUT : RESP_OUT
Address: http://localhost:8081/soap/service/employee
Content-Type: text/xml
ResponseCode: 200
ExchangeId: 872e1281-4545-45ad-9871-331d96c450cf
ServiceName: EmployeeEndpointService
PortName: EmployeeEndpointPort
PortTypeName: EmployeeServicePortType
Headers: {}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><EmployeesResponse xmlns="http://www.jpworks.com/employee"><employee id="1" firstname="Jeffery" lastname="Lewis" birthdate="2000-01-01" gender="M"/><employee id="2" firstname="Francis" lastname="Stevens" birthdate="1999-01-01" gender="M"/></EmployeesResponse></soap:Body></soap:Envelope>
결론
본고는 모든 남겨진 응용 프로그램의 이동 경로에서 SOAP를 도구로 간주하는 것이 왜 여전히 중요한지 설명한다.우리는 데모 WSDL을 사용하고 관련 부분을 되돌아보았다.우리는 Apache CXF를 사용하여 SOAP를 구현하고 구성하는 방법을 배웠습니다.
질문이 있으시면 언제든지 댓글로 질문해 주십시오.읽어주셔서 감사합니다!
Reference
이 문제에 관하여(Spring Boot이 포함된 SOAP 마이크로서비스, 1부에서는 Apache CXF 사용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/jpontdia/soap-microservices-with-spring-boot-and-cxf-on-the-monolithic-migration-path-439h텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)