使用Apache CXF开发SOAP Web服务

在上一篇文章中,我逐步介绍了使用apache CXF开发简单的RESTFull服务的步骤。 在本文中,我将讨论使用CXF开发SOAP Web服务。 在继续前进之前,让我们了解构成SOAP Web服务的一些概念/元素。

SOAP或简单对象访问协议

SOAP是一种协议,用于使用诸如http,smtp等应用程序协议作为载体在网络上交换基于XML的消息。 SOAP消息包含一个SOAP信封。 信封可以分为标题和正文。 标头包含与上下文相关的定义(例如安全性),而主体包含实际的应用程序数据。 典型的SOAP消息看起来像

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Header>
  </soap:Header>
  <soap:Body>
    <m:GetStockPrice xmlns:m="http://www.example.org/stock">
      <m:StockName>IBM</m:StockName>
    </m:GetStockPrice>
  </soap:Body>
</soap:Envelope>

WSDL或Web服务描述语言

WSDL是基于标准的XML语言,用于描述Web服务。 WSDL完全描述了Web服务公开的公共接口,期望的参数,返回的输出结构以及Web服务的位置。 WSDL将Web服务定义为能够交换消息的通信端点的集合。 这些通信端点称为端口。 端口由两部分组成。

  1. 包含Web服务公开的公共接口。 接口包含所有方法,调用它们所需的参数以及它们返回的响应结构。
  2. 第二部分将公共接口绑定到诸如http之类的网络协议。 绑定包括诸如公共接口的位置和服务的消息格式之类的信息。

SOAP通讯样式

存在两种类型的沟通方式

  1. 文献
  2. RPC

SOAP Web服务使用的通信样式在其WSDL中定义。

在文档样式中,作为肥皂主体一部分的应用程序数据作为XML文档发送。 可以通过也是WSDL一部分的xml模式来完全验证该文档。 由于XML可以按照服务开发人员的意愿包含结构,因此,编组和解编xml有效负载的责任在于提供者和使用者代码的末尾。

顾名思义,以RPC风格表示,使用者调用服务方法就像调用本地方法一样。 为此,RPC消息包含使用者可以调用的公共接口方法的列表。 这些方法按名称列为xml元素。 这些方法所需的方法参数构成方法元素的子元素。 封送/取消封送的责任在于Web服务框架。 该框架包含其自己的封送/解封库。 RPC样式导致应用程序代码和Web服务框架之间的代码紧密耦合,因此规范是创建文档样式服务。 掌握了关键概念之后,让我们看一下如何使用Apache CXF编写肥皂网络服务的示例。

获取本教程的源代码

我已经在SVN中提交了本教程的源文件。

注意:这两个都是ItelliJ maven项目,因此您可以将它们直接导入到intelliJ IDE或将文件手动复制到其他IDE

创建一个struts2框架应用程序以包含您的服务。

您可以使用任何MVC框架,但出于我自己的原因,我更喜欢struts2。 您可以在此处看到有关如何使用Eclipse在eclipse中创建空的struts2应用程序的示例。

添加CXF依赖项

在您的项目POM中添加以下依赖项以下载CXF jar

<properties>
       <cxf.version>2.5.0</cxf.version>
</properties>
<dependencies>
       <!-- apache cxf -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>${cxf.version}</version>
        </dependency>

        <dependency>
          <groupId>org.apache.cxf</groupId>
          <artifactId>cxf-rt-frontend-jaxrs</artifactId>
          <version>${cxf.version}</version>
       </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>${cxf.version}</version>
        </dependency>
</dependencies>

例如,让我们创建一个简单的书架网络服务。 为简单起见,让我们假设以下用例。

  1. 在自己的书中插入一本书
  2. 从书架上按标题检索一本书。

开发服务

可以通过两种方式完成:“代码优先”和“合同优先”。 我们将使用代码优先方法。

创建服务端点接口(SEI)

让我们创建一个名为BookShelfService的SEI接口

package com.aranin.weblog4j.services;

import com.aranin.weblog4j.vo.BookVO;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface BookShelfService {

    @WebMethod
    public  String insertBook(BookVO bookVO);
    @WebMethod
    public  BookVO getBook(String title);
}

如果看上面的SEI,可以看出它是一个普通的Java接口,但有两个注释

  • @WebService –这是一个注释JAXWS库。 它将普通的POJO转换为Web服务。 在我们的例子中,注释位于接口定义的正上方,它通知BookShelfService不是普通接口,而是Web服务接口或SEI。 该注释还有其他一些属性可以完全定义Web服务,但是我们现在不会使用它。
  • @WebMethod –此注释是可选的,主要用于为wsdl中的公共方法提供名称属性。

实施服务。

现在我们有了SEI,因此让我们在BookShelfServiceImpl的接口中实现方法

package com.aranin.weblog4j.services;

import com.aranin.weblog4j.hashdb.HashDB;
import com.aranin.weblog4j.vo.BookVO;

import javax.jws.WebService;

@WebService(endpointInterface = "com.aranin.weblog4j.services.BookShelfService",
		serviceName="bookShelfService")
public class BookShelfServiceImpl implements BookShelfService {
    public String insertBook(BookVO bookVO) {
        HashDB.insertBook(bookVO);
        return "Book with name : " + bookVO.getBookName() + " is now available on the shelf";  //To change body of implemented methods use File | Settings | File Templates.
    }

    public BookVO getBook(String title) {

        return HashDB.getBook(title);  //To change body of implemented methods use File | Settings | File Templates.
    }
}

此类是实现SEI的简单POJO。 这里唯一值得注意的是@WebService批注。 如果您仔细看一下,我们提供了它实现的SEI的完全合格的类名和Web服务的名称。

数据绑定类(BookVO)

package com.aranin.weblog4j.vo;

import javax.xml.bind.annotation.XmlRootElement;
import java.io.Serializable;

@XmlRootElement(name = "Book")
public class BookVO implements Serializable {

    private long bookId;
    private String bookName;
    private String author;

    public long getBookId() {
        return bookId;
    }

    public void setBookId(long bucketId) {
        this.bookId = bookId;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

这里唯一要注意的是@XmlRootElement批注。 该注释是JAXB库的一部分。 CXF使用JAXB作为默认数据绑定组件。 由于BookVO在Web服务调用期间需要作为XML进行传输,因此需要在CXF安装中由JAXB引擎进行编组/解组。 使用@XmlRootElement批注,我们可以帮助JAXB将BookVO类映射到xml,并将其name属性作为xml的根元素。

基于Spring的服务器Bean

使CXF成为Web服务框架的第一选择的原因在于,它通过基于Spring的配置文件发布其服务端点。 让我们创建一个配置文件并在其中注册我们的服务。 我们将文件命名为beans.xml并将其保存在应用程序的WEB-INF文件夹中

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:jaxws="http://cxf.apache.org/jaxws"
    xmlns:jaxrs="http://cxf.apache.org/jaxrs"
	xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://cxf.apache.org/jaxrs

http://cxf.apache.org/schemas/jaxrs.xsd

http://cxf.apache.org/jaxws

http://cxf.apache.org/schemas/jaxws.xsd">

<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />	

<jaxws:endpoint
       id="bookShelfService"
       implementor="com.aranin.weblog4j.services.BookShelfServiceImpl"
       address="/bookshelfservice" />

</beans>

现在要加载beans.xml,我们只需在web.xml中添加以下内容

<context-param>
<param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/beans.xml,/WEB-INF/applicationContext.xml</param-value>
</context-param>

最后,我们需要通过web.xml连接spring和CXF。

<servlet>
       <servlet-name>CXFServlet</servlet-name>
       <display-name>CXF Servlet</display-name>
	<servlet-class>
		org.apache.cxf.transport.servlet.CXFServlet
	</servlet-class>
	<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>CXFServlet</servlet-name>
	<url-pattern>/*</url-pattern>
</servlet-mapping>

注意:我没有包括Spring ContextLoaderListner的加载。 如果您使用struts2入门原型通过maven创建了struts2应用程序,那么spring将由maven项目本身下载并注册。

现在您的Web服务已准备就绪。 在任何servlet容器中编译和部署应用程序。 如果一切都很好,那么您可以在以下位置看到您的wsld: http:// localhost:8080 / weblog4jdemo / bookshelfservice?wsdl

创建您的客户

有许多工具可用于使用wsdl生成客户端代码。 为了节省您的更多麻烦,我们将利用CXF自己的前端api。 因此,让我们看看步骤。

  1. 使用您选择的IDE创建一个简单的Maven项目。 我目前正在使用IntelliJ,它很棒。 可以说该项目的名称为DemoClient。
  2. 如创建框架应用程序部分所示,添加CXF依赖项。
  3. 既然我们知道SEI,公共方法和绑定对象是什么。 我们将在客户端创建它们,以免给我们带来麻烦。 如果有很多此类,我们可以使用wsdl2java等工具来生成我们的代码。
  4. 在与父SEI完全相同的包结构中创建存根SEI。
  5. 以与父BookVO相同的包结构创建BookVO。
  6. 以上类应与在父应用程序中创建的类完全相同。
  7. 我们不需要在客户端创建SEI实现。
  8. 现在,我们将使用JaxWsProxyFactoryBean创建一个客户端。 此类是与SEI代理一起使用以调用Web服务方法的工厂。 这是课程。
package com.aranin.weblog4j.client;

import com.aranin.weblog4j.services.BookShelfService;
import com.aranin.weblog4j.vo.BookVO;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

public class DemoClient {
    public static void main(String[] args){
        String serviceUrl = "http://localhost:8080/weblog4jdemo/bookshelfservice";
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
		factory.setServiceClass(BookShelfService.class);
		factory.setAddress(serviceUrl);
		BookShelfService bookService = (BookShelfService) factory.create();

        //insert book
        BookVO bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Earth");

        String result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Empire");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Arthur C Clarke");
        bookVO.setBookName("Rama Revealed");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        //retrieve book

        bookVO = bookService.getBook("Foundation and Earth");

        System.out.println("book name : " + bookVO.getBookName());
        System.out.println("book author : " + bookVO.getAuthor());

    }
}

这是上述调用的输出

INFO: Creating Service {http://services.weblog4j.aranin.com/}BookShelfServiceService from class com.aranin.weblog4j.services.BookShelfService
result : Book with name : Foundation and Earth is now available on the shelf
result : Book with name : Foundation and Empire is now available on the shelf
result : Book with name : Rama Revealed is now available on the shelf
book name : Foundation and Earth
book author : Issac Asimov

Process finished with exit code 0

您可以在Apache CXF中探索大量其他内容,例如创建动态客户端,拦截器,利用其他传输协议,基于https的Web服务等。但是,我打算将本文作为入门教程。

ew,这又是一个漫长的帖子。 我需要提高写作技巧以缩短篇幅。 但我仍然希望您喜欢它并发现它有用。 我打算在我的下一篇文章中撰写有关Web服务的javascript客户端的文章。 在那之前,再见,编码愉快。

参考: Weblog4j博客上的JCG合作伙伴 Niraj Singh 使用Apache CXF开发SOAP Web服务

翻译自: https://www.javacodegeeks.com/2013/06/developing-soap-web-service-using-apache-cxf.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值