먼저 WSDL을 사용하는 Apache CXF

개발 한 CXF-POJO 애플리케이션은 클라이언트와 서버 사이에 매우 긴밀한 결합을 제공합니다. 서비스 인터페이스에 대한 직접 액세스 권한을 부여하면 심각한 보안 위협이 발생할 수도 있습니다. 따라서 일반적으로 클라이언트와 서버 간의 분리가 바람직하며 이는 WSDL (Web Services Description Language)을 사용하여 수행됩니다.

XML 기반의 WSDL 문서에 웹 서비스 인터페이스를 작성합니다. 이 WSDL을 Apache CXF 인터페이스에 매핑하는 도구를 사용하여 클라이언트 및 서버 응용 프로그램에서 구현하고 사용합니다. 디커플링을 제공하려면 WSDL로 시작하는 것이 선호되는 방법입니다. 이를 위해서는 먼저 새로운 언어 인 WSDL을 배워야합니다. WSDL을 작성하려면 신중한 접근 방식이 필요하며 작업을 시작하기 전에 이에 대해 어느 정도 이해할 수 있다면 더 좋을 것입니다.

이 레슨에서는 WSDL 문서에서 웹 서비스 인터페이스를 정의하는 것으로 시작합니다. CXF를 사용하여 WSDL로 시작하는 서버 및 클라이언트 응용 프로그램을 만드는 방법을 배웁니다. CXF 사용에 초점을 맞추기 위해 애플리케이션을 단순하게 유지합니다. 서버 애플리케이션이 생성 된 후 내장 CXF 클래스를 사용하여 원하는 URL에 게시합니다.

먼저 우리가 사용할 WSDL에 대해 설명하겠습니다.

HelloWorld 용 WSDL

우리가 구현할 웹 서비스에는 greetings 수락하는 string매개 변수는 사용자 이름을 보유하고 사용자 이름에 인사말 메시지를 추가 한 후 호출자에게 문자열 메시지를 반환합니다. 완전한 wsdl은 다음과 같습니다.

//Hello.wsdl
<?xml version = "1.0" encoding = "UTF-8"?>
<wsdl:definitions xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns = "http://helloworld.tutorialspoint.com/"
   xmlns:wsdl = "http://schemas.xmlsoap.org/wsdl/"
   xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
   name = "HelloWorld"
   targetNamespace = "http://helloworld.tutorialspoint.com/">
   <wsdl:types>
      <xsd:schema attributeFormDefault = "unqualified"
         elementFormDefault = "qualified"
         targetNamespace = "http://helloworld.tutorialspoint.com/">
         <xsd:element name = "greetings" type = "tns:greetings"/>
         <xsd:complexType name = "greetings">
            <xsd:sequence>
               <xsd:element minOccurs = "0" name = "arg0" type = "xsd:string"/>
            </xsd:sequence>
         </xsd:complexType>
         <xsd:element name = "greetingsResponse"
         type = "tns:greetingsResponse"/>
         <xsd:complexType name = "greetingsResponse">
            <xsd:sequence>
               <xsd:element minOccurs = "0" name = "return" type = "xsd:string"/>
            </xsd:sequence>
         </xsd:complexType>
      </xsd:schema>
   </wsdl:types>
   <wsdl:message name = "greetings">
      <wsdl:part element = "tns:greetings" name = "parameters"> </wsdl:part>
   </wsdl:message>
   <wsdl:message name = "greetingsResponse">
      <wsdl:part element = "tns:greetingsResponse" name = "parameters"> </wsdl:part>
   </wsdl:message>
   <wsdl:portType name = "HelloWorldPortType">
      <wsdl:operation name = "greetings">
         <wsdl:input message = "tns:greetings" name = "greetings">  </wsdl:input>
         <wsdl:output message = "tns:greetingsResponse" name = "greetingsResponse">
         </wsdl:output>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name = "HelloWorldSoapBinding" type = "tns:HelloWorldPortType">
      <soap:binding style = "document"
      transport = "http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name = "greetings">
         <soap:operation soapAction = "" style = "document"/>
         <wsdl:input name = "greetings"></wsdl:input>
         <wsdl:output name = "greetingsResponse">
            <soap:body use = "literal"/>
         </wsdl:output>
         </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name = "HelloWorldService">
      <wsdl:port binding = "tns:HelloWorldSoapBinding" name = "HelloWorldPort">
         <soap:address location = "http://localhost:9090/HelloServerPort"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

구문 상 올바른 wsdl을 작성하는 것은 항상 개발자에게 도전이었습니다. wsdl을 만드는 데 사용할 수있는 많은 도구와 온라인 편집기가 있습니다. 이러한 편집기는 메시지에 전달할 매개 변수와 함께 구현할 메시지의 이름과 클라이언트 애플리케이션이 수신 할 반환 메시지의 유형을 요청합니다. wsdl 구문을 알고 있다면 전체 문서를 직접 코딩하거나 편집기 중 하나를 사용하여 직접 작성할 수 있습니다.

위의 wsdl에서 우리는 greetings. 메시지는 다음과 같은 서비스로 전달됩니다.HelloWorldService 에서 실행되는 http://localhost:9090/HelloServerPort.

이것으로 우리는 이제 서버 개발을 진행할 것입니다. 서버를 개발하기 전에 웹 서비스에 대한 Apache CXF 인터페이스를 생성해야합니다. 이것은 주어진 wsdl에서 수행됩니다. 이를 위해 다음과 같은 도구를 사용합니다.wsdl2java.

wsdl2java 플러그인

프로젝트를 빌드하기 위해 maven을 사용할 것이므로 다음 플러그인을 추가해야합니다. pom.xml 파일.

<plugins>
   <plugin>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-codegen-plugin</artifactId>
      <version>3.3.0</version>
      <executions>
         <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration>
               <wsdlOptions>
                  <wsdlOption>
                     <wsdl>src/main/resources/hello.wsdl</wsdl>
                     <faultSerialVersionUID> 1 </faultSerialVersionUID>
                  </wsdlOption>
               </wsdlOptions>
            </configuration>
            <goals>
               <goal>wsdl2java</goal>
            </goals>
         </execution>
      </executions>
   </plugin>
</plugins>

우리는 wsdl 파일로 src/main/resources/Hello.wsdl. 프로젝트에 적합한 디렉토리 구조를 생성하고 이전에 표시된 내용을 추가해야합니다.hello.wsdl 파일을 지정된 폴더에 추가합니다.

그만큼 wsdl2java플러그인은이 wsdl을 컴파일하고 미리 정의 된 폴더에 Apache CXF 클래스를 만듭니다. 여기에 전체 프로젝트 구조가 표시되어 바로 참조 할 수 있습니다.

이제 다음을 사용하여 서버를 만들 준비가되었습니다. wsdl2java생성 된 클래스. wsdl2java가 생성 한 클래스는 아래 그림과 같습니다.

생성 된 서비스 인터페이스

생성 된 클래스 목록에서 그중 하나가 Apache CXF 인터페이스임을 확인해야합니다. HelloWorldPortType.java. 코드 편집기에서이 파일을 검토하십시오. 여기에 파일 내용이 표시되어 있습니다.

//HelloWorldPortType.java
package com.tutorialspoint.helloworld;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
/**
* This class was generated by Apache CXF 3.3.0
* 2019-02-11T12:05:55.220+05:30
* Generated source version: 3.3.0
*
*/

@WebService(targetNamespace = "http://helloworld.tutorialspoint.com/",
   name = "HelloWorldPortType")
@XmlSeeAlso({ObjectFactory.class})
public interface HelloWorldPortType {
   @WebMethod
   @RequestWrapper(localName = "greetings", targetNamespace =
      "http://helloworld.tutorialspoint.com/", className =
      "com.tutorialspoint.helloworld.Greetings")
      @ResponseWrapper(localName = "greetingsResponse", targetNamespace =
         "http://helloworld.tutorialspoint.com/", className =
         "com.tutorialspoint.helloworld.GreetingsResponse")
   @WebResult(name = "return", targetNamespace =
      "http://helloworld.tutorialspoint.com/")
   public java.lang.String greetings(
      @WebParam(name = "arg0", targetNamespace =
      "http://helloworld.tutorialspoint.com/")
      java.lang.String arg0
   );
}

인터페이스에는 greetings. 이것은 우리 wsdl의 메시지 유형이었습니다. 그만큼wsdl2java도구가 생성 된 인터페이스에이 메소드를 추가했습니다. 이제 wsdl에 어떤 메시지를 작성하든 해당 메서드가 인터페이스에서 생성된다는 것을 이해할 수 있습니다.

이제 작업은 wsdl에서 정의한 다양한 메시지에 해당하는 이러한 모든 메소드를 구현하는 것입니다. Apache CXF-First의 이전 예제에서는 웹 서비스를위한 Apache CXF 인터페이스로 시작했습니다. 이 경우 Apache CXF 인터페이스는 wsdl에서 생성됩니다.

서비스 인터페이스 구현

서비스 인터페이스의 구현은 간단합니다. 전체 구현은 아래 목록에 나와 있습니다.

//HelloWorldImpl.java
package com.tutorialspoint.helloworld;
public class HelloWorldImpl implements HelloWorldPortType {
   @Override
   public String greetings(String name) {
      return ("hi " + name);
   }
}

코드는 다음과 같은 유일한 인터페이스 메서드를 구현합니다. greetings. 이 메서드는 다음 중 하나의 매개 변수를 사용합니다.string 유형, 앞에 "hi"메시지를 추가하고 결과 문자열을 호출자에게 반환합니다.

다음으로 서버 애플리케이션을 작성합니다.

서버 개발

서버 애플리케이션 개발은 다시 한 번 사소합니다. 여기에서는 제공된 CXF를 사용합니다.Endpoint우리의 서비스를 게시하는 클래스. 이것은 다음 두 줄의 코드에서 수행됩니다.

HelloWorldPortType implementor = new HelloWorldImpl();
   Endpoint.publish("http://localhost:9090/HelloServerPort",
      implementor,
      new LoggingFeature());

먼저 서비스 구현 자 클래스의 객체를 만듭니다. HelloWorldImpl. 그런 다음이 참조를 두 번째 매개 변수로publish방법. 첫 번째 매개 변수는 서비스가 게시되는 주소입니다. 클라이언트는이 URL을 사용하여 서비스에 액세스합니다. 서버 애플리케이션의 전체 소스가 여기에 제공됩니다.

//Server.java
package com.tutorialspoint.helloworld;
import javax.xml.ws.Endpoint;
import org.apache.cxf.ext.logging.LoggingFeature;
public class Server {
   public static void main(String[] args) throws Exception {
      HelloWorldPortType implementor = new HelloWorldImpl();
      Endpoint.publish("http://localhost:9090/HelloServerPort",
         implementor,
         new LoggingFeature());
      System.out.println("Server ready...");
      Thread.sleep(5 * 60 * 1000);
      System.out.println("Server exiting");
      System.exit(0);
   }
}

이 서버 클래스를 빌드하려면 빌드 프로필을 pom.xml. 이것은 아래에 표시됩니다-

<profile>
   <id>server</id>
   <build>
      <defaultGoal>test</defaultGoal>
      <plugins>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.6.0</version>
            <executions>
               <execution>
                  <phase>test</phase>
                  <goals>
                     <goal>java</goal>
                  </goals>
                  <configuration>
                     <mainClass>
                        com.tutorialspoint.helloworld.Server
                     </mainClass>
                  </configuration>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</profile>

정규화 된 이름은 Server클래스는 구성에 지정됩니다. 또한 종속성 태그는 임베디드 jetty 웹 서버를 사용하여 서버 애플리케이션을 배포 할 것임을 지정합니다.

서버 배포

마지막으로 서버 애플리케이션을 배포하려면 pom.xml에서 한 번 더 수정하여 애플리케이션을 웹 애플리케이션으로 설정해야합니다. 추가해야하는 코드pom.xml 아래에 주어진다-

<defaultGoal>install</defaultGoal>
<pluginManagement>
   <plugins>
      <plugin>
         <artifactId>maven-war-plugin</artifactId>
         <version>3.2.2</version>
         <configuration>
            <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
            <webResources>
               <resource>
                  <directory>src/main/resources</directory>
                  <targetPath>WEB-INF</targetPath>
                  <includes>
                     <include>*.wsdl</include>
                  </includes>
               </resource>
            </webResources>
         </configuration>
      </plugin>
   </plugins>
</pluginManagement>

애플리케이션을 배포하기 전에 프로젝트에 두 개의 파일을 더 추가해야합니다. 아래 스크린 샷에 나와 있습니다.

이 파일은 다음에 대한 매핑을 정의하는 CXF 표준 파일입니다. CXFServlet. 내 코드web.xml 파일은 빠른 참조를 위해 여기에 표시됩니다.

//cxf-servlet.xml
<web-app xmlns = "http://java.sun.com/xml/ns/javaee"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" version="2.5"
   xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
   <display-name>cxf</display-name>
   <servlet>
      <description>Apache CXF Endpoint</description>
      <display-name>cxf</display-name>
      <servlet-name>cxf</servlet-name>
      <servlet-class>
         org.apache.cxf.transport.servlet.CXFServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>cxf</servlet-name>
      <url-pattern>/services/*</url-pattern>
   </servlet-mapping>
   <session-config>
      <session-timeout>60</session-timeout>
   </session-config>
</web-app>

에서 cxf-servlet.xml서비스 엔드 포인트에 대한 속성을 선언합니다. 이것은 아래 코드 스 니펫에 나와 있습니다.

<beans ...>
   <jaxws:endpoint xmlns:helloworld = "http://tutorialspoint.com/"
      id="helloHTTP"
      address = "http://localhost:9090/HelloServerPort"
      serviceName = "helloworld:HelloServiceService"
      endpointName = "helloworld:HelloServicePort">
   </jaxws:endpoint>
</beans>

여기에서 서비스 엔드 포인트의 ID, 서비스를 사용할 수있는 주소, 서비스 이름 및 엔드 포인트 이름을 정의합니다. 이제 서비스가 CXF 서블릿에 의해 라우팅되고 처리되는 방식을 이해했습니다.

최종 pom.xml

그만큼 pom.xml몇 가지 더 많은 종속성이 포함됩니다. 모든 종속성을 설명하는 대신 아래에 pom.xml의 최종 버전을 포함했습니다.

<?xml version="1.0" encoding = "UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>cxf-wsdl</artifactId>
   <version>1.0</version>
   <packaging>jar</packaging>
   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
   </properties>
   <build>
      <defaultGoal>install</defaultGoal>
      <pluginManagement>
         <plugins>
            <plugin>
               <artifactId>maven-war-plugin</artifactId>
               <version>3.2.2</version>
               <configuration>
                  <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
                  <webResources>
                     <resource>
                        <directory>src/main/resources</directory>
                        <targetPath>WEB-INF</targetPath>
                        <includes>
                           <include>*.wsdl</include>
                        </includes>
                     </resource>
                  </webResources>
               </configuration>
            </plugin>
         </plugins>
      </pluginManagement>
      <plugins>
         <plugin>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-codegen-plugin</artifactId>
            <version>3.3.0</version>
            <executions>
               <execution>
                  <id>generate-sources</id>
                  <phase>generate-sources</phase>
                  <configuration>
                     <wsdlOptions>
                        <wsdlOption>
                           <wsdl>src/main/resources/Hello.wsdl</wsdl>
                           <faultSerialVersionUID>1</faultSerialVersionUID>
                        </wsdlOption>
                     </wsdlOptions>
                  </configuration>
                  <goals>
                     <goal>wsdl2java</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
   <profiles>
      <profile>
         <id>server</id>
         <build>
            <defaultGoal>test</defaultGoal>
            <plugins>
               <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>exec-maven-plugin</artifactId>
                  <version>1.6.0</version>
                  <executions>
                     <execution>
                        <phase>test</phase>
                        <goals>
                           <goal>java</goal>
                        </goals>
                        <configuration>
                           <mainClass>
                              com.tutorialspoint.helloworld.Server
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
         <dependencies>
            <dependency>
               <groupId>org.apache.cxf</groupId>
               <artifactId>cxf-rt-transports-http-jetty</artifactId>
               <version>3.3.0</version>
            </dependency>
         </dependencies>
      </profile>
      <profile>
         <id>client</id>
         <build>
            <defaultGoal>test</defaultGoal>
            <plugins>
               <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>exec-maven-plugin</artifactId>
                  <executions>
                     <execution>
                        <phase>test</phase>
                        <goals>
                           <goal>java</goal>
                        </goals>
                        <configuration>
                           <mainClass>
                              com.tutorialspoint.helloworld.Client
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </profile>
   </profiles>
   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-frontend-jaxws</artifactId>
         <version>3.3.0</version>
      </dependency>
     
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-management</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-features-metrics</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf.xjc-utils</groupId>
         <artifactId>cxf-xjc-runtime</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-features-logging</artifactId>
         <version>3.3.0</version>
      </dependency>
     
     <dependency>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>exec-maven-plugin</artifactId>
         <version>1.6.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.8.0-beta2</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</project>

클라이언트 구축을위한 프로필도 포함되어 있으며 이는 이후 섹션에서 곧 배울 것입니다.

HelloWorld 서비스 실행

이제 웹앱을 실행할 준비가되었습니다. 명령 창에서 다음 명령을 사용하여 빌드 스크립트를 실행합니다.

mvn clean install

그러면 wsdl에서 적절한 Apache CXF 클래스가 생성되고, Apache CXF 클래스를 컴파일하고, 임베디드 jetty 서버에 서버를 배포하고 애플리케이션을 실행합니다.

콘솔에 다음 메시지가 표시됩니다.

INFO: Setting the server's publish address to be 
http://localhost:9090/HelloServerPort
Server ready...

이전과 마찬가지로 브라우저에서 서버 URL을 열어 서버를 테스트 할 수 있습니다.

작업을 지정하지 않았으므로 응용 프로그램에서 오류 메시지 만 브라우저에 반환합니다. 이제?wsdl URL에 다음과 같은 출력이 표시됩니다.

따라서 서버 응용 프로그램이 예상대로 실행됩니다. 다음과 같은 SOAP 클라이언트를 사용할 수 있습니다.Postman 서비스를 추가로 테스트하기 위해 앞서 설명했습니다.

이 튜토리얼의 다음 부분은 우리 서비스를 사용하는 클라이언트를 작성하는 것입니다.

클라이언트 개발

CXF 애플리케이션에서 클라이언트를 작성하는 것은 서버 작성만큼 중요합니다. 다음은 기본적으로 세 줄로만 구성된 클라이언트의 전체 코드이며 나머지 줄은 사용자에게 서비스 정보를 인쇄합니다.

//Client.java
package com.tutorialspoint.helloworld;
public class Client {
   public static void main(String[] args) throws Exception {
      //Create the service client with its default wsdlurl
      HelloWorldService helloServiceService = new HelloWorldService();
      System.out.println("service: " +
         helloServiceService.getServiceName());
      System.out.println("wsdl location: " +
         helloServiceService.getWSDLDocumentLocation());
      HelloWorldPortType helloService =
         helloServiceService.getHelloWorldPort();
      System.out.println(helloService.greetings
      (System.getProperty("user.name")));
   }
}

여기서는 단순히 서비스의 인스턴스를 생성합니다. HelloWorldService, 호출하여 포트를 가져옵니다. getHelloWorldPort 메서드를 전달한 다음 greetings그것에 메시지. 클라이언트를 실행하면 다음 출력이 표시됩니다.

service: {http://helloworld.tutorialspoint.com/}HelloWorldService
wsdl location: file:/Users/drsarang/Desktop/tutorialpoint/cxf-
wsdl/src/main/resources/Hello.wsdl
hi drsarang

지금까지 Apache CXF-First 및 WSDL-First 아키텍처에서 CXF를 사용하는 방법을 배웠습니다. Apache CXF-First 접근 방식에서는 다음과 함께 POJO를 사용했습니다.ServerFactoryBeanCXF 라이브러리의 클래스를 사용하여 서버를 만듭니다. 사용한 클라이언트를 만들려면ClientProxyFactoryBeanCXF 라이브러리의 클래스. WSDL-First 접근 방식에서는Endpoint원하는 URL과 지정된 구현 자에 서비스를 게시하는 클래스입니다. 이제 이러한 기술을 확장하여 다양한 프로토콜과 전송을 통합 할 수 있습니다.