• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Spring Boot应用Apache CXF发布Web Services服务

武飞扬头像
zhangbeizhen18
帮助1

记录:298

场景:使用Spring Boot应用Apache CXF发布Web Services服务,实现跨系统之间交互接口。

版本:

  1.  
    JDK 1.8
  2.  
    Spring Boot 2.6.3
  3.  
    Apache CXF 3.5.1

名词:

以下摘自官网。

Apache CXF:Apache CXF is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.

一、基础

1.Apache CXF官网地址

https://cxf.apache.org/

其中,源码下载和相应包下载均在官网中有入口。

2.Apache CXF基础

Apache CXF发布的Web Services服务,一般在跨系统之间交互接口的场景中使用。

实际开发中可以关注以下几点。

(1)服务提供方和服务调用方需约定交互的数据格式

使用普通字符串,比较容易理解,一目了然。

使用XML格式,需要约定XML格式中每个属性值代表什么业务意义。

使用JSON格式,需要约定JSON格式中每个属性值代表什么业务意义。

(2)服务提供方和服务调用方都需解析数据

服务提供方和服务调用方都需开发解析工具去解析数据,推荐约定标准化格式。

本例XML解析使用:jdom2。

本例JSON解析使用:fastjson。

(3)服务提供方需提供Web Services发布地址

服务调用方需要根据发布的Web Services地址去调用服务的具体方法。

本例地址格式举例:

格式:http://主机IP:主机端口/微服务名/CXFServlet拦截的路径/发布服务地址?wsdl

举例:

http://127.0.0.1:18080/example-cxf/WebServices/cityInfoWS?wsdl

二、部署

使用Apache CXF发布的Web Services服务功能,常用方式有以下两种。

方式一:Spring Web应用中集成Apache CXF框架。打包成war包,放入Tomcat容器中运行。

方式二:Spring Web应用中集成Apache CXF框架。打包成可执行jar包,内嵌Tomcat容器中运行。

、微服务

微服务工程名:example-106-cxf。微服务以Spring Boot 2.6.3为基础构建。

1.微服务example-106-cxf

在微服务example-106-cxf中,集成Apache CXF框架。

1.1创建微服务工程

微服务工程名:example-106-cxf。

1.2.pom.xml依赖

在pom.xml中引入核心依赖。

  1.  
    <dependency>
  2.  
    <groupId>org.springframework.boot</groupId>
  3.  
    <artifactId>spring-boot</artifactId>
  4.  
    <version>2.6.3</version>
  5.  
    </dependency>
  6.  
    <dependency>
  7.  
    <groupId>org.springframework.boot</groupId>
  8.  
    <artifactId>spring-boot-starter-web</artifactId>
  9.  
    <version>2.6.3</version>
  10.  
    </dependency>
  11.  
    <dependency>
  12.  
    <groupId>org.apache.cxf</groupId>
  13.  
    <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
  14.  
    <version>3.5.1</version>
  15.  
    </dependency>
  16.  
    <dependency>
  17.  
    <groupId>com.alibaba</groupId>
  18.  
    <artifactId>fastjson</artifactId>
  19.  
    <version>1.2.83</version>
  20.  
    </dependency>
  21.  
    <dependency>
  22.  
    <groupId>org.jdom</groupId>
  23.  
    <artifactId>jdom2</artifactId>
  24.  
    <version>2.0.6</version>
  25.  
    </dependency>
学新通

1.3.启动类

包名全路径:com.hub.example。

启动类名称:CxfExampleApplication 。

注解@SpringBootApplication:代表CxfExampleApplication 是微服务启动类。

1.4 WebServices发布实现类

WebServices发布实现类,即WebServices的请求入口实现类。

本例WebServices发布后,对外暴露3个方法。

方法一:入参和返回值都是普通字符串。

方法二:入参和返回值都是XML格式字符串。

方法三:入参和返回值都是JSON格式字符串。

1.4.1接口ICityInformation

包路径:com.hub.example.webservice.ICityInformation

@WebService标记是发布WebService的接口,targetNamespace指定命名空间。

本例指定命名空间:http://www.hub.com

当不指定命名空间时,会生成默认空间,是包名的倒序。

如果本例没有指定,则默认:webservice.example.hub.com

  1.  
    import javax.jws.WebService;
  2.  
    @WebService(targetNamespace = "http://www.hub.com")
  3.  
    public interface ICityInformation {
  4.  
    /**
  5.  
    * 入参: 两个普通字符串
  6.  
    * 返回: 普通字符串
  7.  
    */
  8.  
    String getCityInfo(String cityName, String cityNo);
  9.  
    /**
  10.  
    * 入参: XML格式字符串
  11.  
    * 返回: XML格式字符串
  12.  
    */
  13.  
    String getCityInfoXml(String xmlStr);
  14.  
    /**
  15.  
    * 入参: XML格式字符串
  16.  
    * 返回: XML格式字符串
  17.  
    */
  18.  
    String getCityInfoJson(String jsonStr);
  19.  
    }
学新通

1.4.2实现类CityInformationImpl

类CityInformationImpl实现ICityInformation接口方法。

@Component标记该类需Spring的IOC容器加载。

  1.  
    import com.hub.example.service.ICityInfoService;
  2.  
    import com.hub.example.webservice.ICityInformation;
  3.  
    import lombok.extern.slf4j.Slf4j;
  4.  
    import org.springframework.beans.factory.annotation.Autowired;
  5.  
    import org.springframework.stereotype.Component;
  6.  
    import javax.jws.WebService;
  7.  
    @Slf4j
  8.  
    @WebService(targetNamespace = "http://www.hub.com")
  9.  
    @Component
  10.  
    public class CityInformationImpl implements ICityInformation {
  11.  
    @Autowired
  12.  
    private ICityInfoService cityInfo;
  13.  
    @Override
  14.  
    public String getCityInfo(String cityName, String cityNo) {
  15.  
    log.info("WebService的getCityInfo方法,接收入参,cityName:" cityName ",cityNo=" cityNo);
  16.  
    String result = cityInfo.getCityInfo(cityName, cityNo);
  17.  
    log.info("WebService的getCityInfo方法,返回,result:" result);
  18.  
    return result;
  19.  
    }
  20.  
    @Override
  21.  
    public String getCityInfoXml(String xmlStr) {
  22.  
    log.info("WebService的getCityInfoXml方法,接收入参,xmlStr:" xmlStr);
  23.  
    String result = cityInfo.getCityInfoXml(xmlStr);
  24.  
    log.info("WebService的getCityInfoXml方法,返回,result:" result);
  25.  
    return result;
  26.  
    }
  27.  
    @Override
  28.  
    public String getCityInfoJson(String jsonStr) {
  29.  
    log.info("WebService的getCityInfoJson方法,接收入参,jsonStr:" jsonStr);
  30.  
    String result = cityInfo.getCityInfoJson(jsonStr);
  31.  
    log.info("WebService的getCityInfoJson方法,返回,result:" result);
  32.  
    return result;
  33.  
    }
  34.  
    }
学新通

1.5配置类

1.5.1 CXF发布服务的核心配置

CxfConfiguration主要做三件事。

(1)注入CXF框架的org.apache.cxf.Bus接口和注入需要发布实现类对象CityInformationImpl。

(2)在ServletRegistrationBean注册CXFServlet对象,专门拦截WebServices请求。因为这类请求需要交给CXFServlet处理。

(3)发布CXF具体服务和配置服务地址。

1.5.2 CXF发布服务的地址组成

在CxfConfiguration配置类,就能确定需要发布的WebServices全路径。

本例:

http://127.0.0.1:18080/example-cxf/WebServices/cityInfoWS?wsdl
  1.  
    import com.hub.example.webservice.impl.CityInformationImpl;
  2.  
    import org.apache.cxf.Bus;
  3.  
    import org.apache.cxf.jaxws.EndpointImpl;
  4.  
    import org.apache.cxf.transport.servlet.CXFServlet;
  5.  
    import org.springframework.beans.factory.annotation.Autowired;
  6.  
    import org.springframework.boot.web.servlet.ServletRegistrationBean;
  7.  
    import org.springframework.context.annotation.Bean;
  8.  
    import org.springframework.context.annotation.Configuration;
  9.  
    import javax.xml.ws.Endpoint;
  10.  
    @Configuration
  11.  
    public class CxfConfiguration {
  12.  
    @Autowired
  13.  
    private Bus bus;
  14.  
    /**
  15.  
    * 注入对外提供服务的实现类
  16.  
    */
  17.  
    @Autowired
  18.  
    private CityInformationImpl cityInformationImpl;
  19.  
    /**
  20.  
    * 配置CXFServlet,拦截/WebServices请求
  21.  
    * 注意: /WebServices作为http请求url前缀专门给CXFServlet使用
  22.  
    **/
  23.  
    @Bean
  24.  
    public ServletRegistrationBean<CXFServlet> configCXFServlet() {
  25.  
    return new ServletRegistrationBean<CXFServlet>(new CXFServlet(), "/WebServices/*");
  26.  
    }
  27.  
    /**
  28.  
    * 发布CXF服务,使用org.apache.cxf.jaxws包的EndpointImpl发布
  29.  
    */
  30.  
    @Bean
  31.  
    public Endpoint endpointCityInfo() {
  32.  
    EndpointImpl endpoint = new EndpointImpl(bus, cityInformationImpl);
  33.  
    endpoint.publish("/cityInfoWS");
  34.  
    return endpoint;
  35.  
    }
  36.  
    }
学新通

1.6业务类

1.6.1业务Service类

包名全路径:com.hub.example.service。

接口:com.hub.example.service.ICityInfoService

实现类:com.hub.example.service.impl.CityInfoServiceImpl

笔者习惯,在WebServices发布类中,只做跟发布类相关的事情,业务实现内容独立成类,注入到WebServices实现类中。提升代码简洁和可读性。

1.6.1.1接口ICityInfoService

接口ICityInfoService。

  1.  
    public interface ICityInfoService {
  2.  
    String getCityInfo(String cityName, String cityNo);
  3.  
    String getCityInfoXml(String xmlStr);
  4.  
    String getCityInfoJson(String jsonStr);
  5.  
    }

1.6.1.2实现类CityInfoServiceImpl

在CityInfoServiceImpl实现类,对三个方法具体实现。

方法getCityInfo:处理普通字符串。

方法getCityInfoXml:处理XML字符串。

方法getCityInfoJson:处理Json字符串。

  1.  
    @Slf4j
  2.  
    @Service
  3.  
    public class CityInfoServiceImpl implements ICityInfoService {
  4.  
    @Override
  5.  
    public String getCityInfo(String cityName, String cityNo) {
  6.  
    String uuid = UUID.randomUUID().toString().toUpperCase().replace("-", "");
  7.  
    return cityName ":" cityNo ":" uuid;
  8.  
    }
  9.  
    @Override
  10.  
    public String getCityInfoXml(String xmlStr) {
  11.  
    Map<String, String> result = XlmUtils.parseXml(xmlStr);
  12.  
    String jsonStr = JSON.toJSONString(result);
  13.  
    CityBO cityBO = JSONObject.parseObject(jsonStr, CityBO.class);
  14.  
    String cityName = cityBO.getCityName();
  15.  
    log.info("正在生成地区: " cityName "的UUID信息.");
  16.  
    String uuid = UUID.randomUUID().toString().toUpperCase().replace("-", "");
  17.  
    return XlmUtils.buildXml("0", "执行成功", uuid);
  18.  
    }
  19.  
    @Override
  20.  
    public String getCityInfoJson(String jsonStr) {
  21.  
    CityBO cityBO = JSONObject.parseObject(jsonStr, CityBO.class);
  22.  
    ResultMap resultMap = new ResultMap();
  23.  
    resultMap.put("cityName", cityBO.getCityName());
  24.  
    resultMap.put("cityNo", cityBO.getCityNo());
  25.  
    String uuid = UUID.randomUUID().toString().toUpperCase().replace("-", "");
  26.  
    resultMap.put("randomUUID", uuid);
  27.  
    return JSON.toJSONString(resultMap);
  28.  
    }
  29.  
    }
学新通

1.7工具类XlmUtils

工具类XlmUtils,辅助解析XML和生成XML。

  1.  
    public class XlmUtils {
  2.  
    public static Map<String, String> parseXml(String xmlStr) {
  3.  
    if (xmlStr == null) return null;
  4.  
    if (!Objects.equals("", xmlStr)) {
  5.  
    // 对xmlStr做首尾多余空格处理
  6.  
    xmlStr = xmlStr.trim();
  7.  
    }
  8.  
    StringReader sr = new StringReader(xmlStr);
  9.  
    InputSource input = new InputSource(sr);
  10.  
    SAXBuilder sb = new SAXBuilder();
  11.  
    Map<String, String> result = new HashMap<>();
  12.  
    try {
  13.  
    Document doc = sb.build(input);
  14.  
    //data元素
  15.  
    Element dataElement = doc.getRootElement();
  16.  
    //row元素(所有row),一个data元素包含多个row元素
  17.  
    List<Element> rowElementList = dataElement.getChildren();
  18.  
    for (Element rowElement : rowElementList) {
  19.  
    //一个row元素包含多个column元素
  20.  
    List<Element> columnElementList = rowElement.getChildren();
  21.  
    for (Element columnElement : columnElementList) {
  22.  
    //从遍历出的column元素中取值
  23.  
    String key = columnElement.getAttributeValue("Name").trim();
  24.  
    String value = columnElement.getText() == null ? "" : columnElement.getText().trim();
  25.  
    result.put(key, value);
  26.  
    }
  27.  
    }
  28.  
    } catch (Exception e) {
  29.  
    e.printStackTrace();
  30.  
    }
  31.  
    return result;
  32.  
    }
  33.  
    public static String buildXml(String rtnCode, String rtnMsg, String uuid) {
  34.  
    String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
  35.  
    "<data>\n"
  36.  
    " <row>\n"
  37.  
    " <column Name=\"code\">" rtnCode "</column>\n"
  38.  
    " <column Name=\"message\">" rtnMsg "</column>\n"
  39.  
    " <column Name=\"randomUUID\">" uuid "</column>\n"
  40.  
    " </row>\n"
  41.  
    "</data>";
  42.  
    return xml;
  43.  
    }
  44.  
    }
学新通

1.8配置文件

在\src\main\resources\目录下添加application.yml。

1.8.1 application.yml

application.yml内容如下:

  1.  
    server:
  2.  
    port: 18080
  3.  
    servlet:
  4.  
    context-path: /example-cxf

2.实体包example-200-entity

微服务使用的实体对象均集中放在example-200-entity模块中,每个微服务只需在pom.xml中引用此模块依赖即可。

2.1引用实体包

引用实体包。

  1.  
    <dependency>
  2.  
    <groupId>com.hub</groupId>
  3.  
    <artifactId>example-200-entity</artifactId>
  4.  
    <version>${hub.example.version}</version>
  5.  
    </dependency>

2.2实体类

本例使用实体包括CityVO、CityBO、ResultMap。

2.2.1 CityVO类

CityVO,使用在对http请求入参的JSON格式数据封装。

  1.  
    import lombok.Data;
  2.  
    @Data
  3.  
    public class CityVO {
  4.  
    private String cityName;
  5.  
    private String cityNo;
  6.  
    }

2.2.2 CityBO类

CityBO,使用在对http请求入参的JSON格式数据封装。

  1.  
    import lombok.Data;
  2.  
    @Data
  3.  
    public class CityBO {
  4.  
    private String cityName;
  5.  
    private String cityNo;
  6.  
    }

2.2.3 ResultMap类

ResultMap使用在对http请求结果包装。可以便利的转换为JSON数据。

  1.  
    public class ResultMap extends HashMap<String, Object> {
  2.  
    public ResultMap() {
  3.  
    put("code", 0);
  4.  
    put("message", "success");
  5.  
    }
  6.  
    public static ResultMap error(int code, String msg) {
  7.  
    ResultMap resultMap = new ResultMap();
  8.  
    resultMap.put("code", code);
  9.  
    resultMap.put("msg", msg);
  10.  
    return resultMap;
  11.  
    }
  12.  
    }

应用

1.验证服务example-106-cxf

WS地址:

http://127.0.0.1:18080/example-cxf/WebServices/cityInfoWS?wsdl

当服务启动

1.1验证

1.1.1工具

本例使用SoapUI工具,发起请求。也可以使用其它工具,或者直接写一个客户端。

1.1.2判断服务发布成功(在浏览器中)

在Tomcat容器启动成功后,可以把WebServices地址直接在浏览器访问一下,能生成如下信息则发布成功(本例)。

在页面中可以看到服务端发布的具体方法、命名空间等信息。

学新通

1.1.3判断服务发布成功(在Linux操作系统中)

在生产环境中,服务一般部署在Linux操作系统中,可以使用curl指令验证,同样也会返回如上截图信息。

命令:

curl http://127.0.0.1:18080/example-cxf/WebServices/cityInfoWS?wsdl

1.1.4在SoapUI工具查看发布的方法

在SoapUI工具查看发布的方法列表。

学新通

1.2验证getCityInfo方法

1.2.1入参

参数0:杭州西湖

参数1:310012

1.2.2返回值

返回值:杭州西湖区:310012:19F011E63F9C4A069C205E4456AB676F

1.2.3结果

学新通

1.3验证getCityInfoXml方法

1.3.1入参

  1.  
    <?xml version="1.0" encoding="UTF-8"?>
  2.  
    <data>
  3.  
    <row>
  4.  
    <column Name="cityName">杭州西湖区</column>
  5.  
    <column Name="cityNo">310012</column>
  6.  
    </row>
  7.  
    </data>

 1.3.2返回值

  1.  
    <?xml version="1.0" encoding="UTF-8"?>
  2.  
    <data>
  3.  
    <row>
  4.  
    <column Name="code">0</column>
  5.  
    <column Name="message">执行成功</column>
  6.  
    <column Name="randomUUID">04A09D40FDDA418A91D3728A97D9621C</column>
  7.  
    </row>
  8.  
    </data>

1.3.3结果

使用XML时,XML字符串需要使用<![CDATA[ ]]>包裹起来。

学新通

1.4验证getCityInfoJson方法

1.4.1入参

  1.  
    {
  2.  
    "cityName":"杭州西湖区",
  3.  
    "cityNo":"310012"
  4.  
    }

1.4.2返回值

  1.  
    {
  2.  
    "cityNo": "310012",
  3.  
    "code": 0,
  4.  
    "cityName": "杭州西湖区",
  5.  
    "randomUUID": "8CF23D119D88457EB3C73670C774CB7F",
  6.  
    "message": "success"
  7.  
    }

 1.4.3结果

学新通

 以上,感谢。

2022年10月19日

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgjkhfj
系列文章
更多 icon
同类精品
更多 icon
继续加载