当前位置: 首页 > backend >正文

SpringBoot集成CXF框架,实现WebService

SpringBoot官网地址:https://spring.io/projects/spring-ws

1、WebService服务端搭建

Maven依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.17</version></parent><dependencies><!-- web启动器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- webService--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web-services</artifactId></dependency><!-- CXF webservice --><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><version>3.5.0</version></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-transports-http</artifactId><version>3.5.0</version></dependency></dependencies>

yml配置文件

server:port: 9180
cxf:#默认根目录是 /servicespath: /ws

WebService拦截器

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.springframework.stereotype.Component;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;import java.util.List;@Component
public class WebServiceInterceptor extends AbstractPhaseInterceptor<SoapMessage> {private static final String NAME = "YXQZ";private static final String PASSWORD = "123";public WebServiceInterceptor() {super(Phase.PRE_PROTOCOL);super.getAfter().add(SAAJInInterceptor.class.getName());}@Overridepublic void handleMessage(SoapMessage message) throws Fault {Header authHeader = null;List<Header> headers = message.getHeaders();for (Header h : headers) {if (h.getName().toString().contains("auth")) {authHeader = h;break;}}if (authHeader == null) {throw new Fault(new IllegalArgumentException("获取不到有效信息"));}Element auth = (Element) authHeader.getObject();NodeList childNodes = auth.getChildNodes();String username = null;String password = null;for (int i = 0, len = childNodes.getLength(); i < len; i++) {Node item = childNodes.item(i);if (item.getNodeName().contains("user")) {username = item.getTextContent();}if (item.getNodeName().contains("password")) {password = item.getTextContent();}}if (!NAME.equals(username) || !PASSWORD.equals(password)) {throw new Fault(new IllegalArgumentException("用户账号、密码不正确"));}}
}

接口请求参数

public class User {private String username;private Integer age;private String password;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

 

定义接口和它的实现类

public interface UserService {String queryUserInfo(String username, String password);User saveUser(User user);
}

import org.springframework.stereotype.Service;import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;@WebService(name = "UserWebServiceDemo", serviceName = "UMR",targetNamespace = "http://impl.service.com/")
@Service
public class UserServiceImpl implements UserService {@WebMethod@WebResult(name = "resultCode")public String queryUserInfo(@WebParam(name = "username") String username,@WebParam(name = "password") String password) {System.out.println("用户名:" + username + "密码:" + password);return "success";}@WebMethod(operationName = "saveFunction")@WebResultpublic User saveUser(@WebParam(name = "accountInfo") User user) {System.out.println("保存用户信息");return user;}
}

CXF配置类

import com.interceptor.WebServiceInterceptor;
import com.service.impl.UserServiceImpl;
import org.apache.catalina.servlets.CGIServlet;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.xml.ws.Endpoint;@Configuration
public class CXFConfig {//注入 CXF总线 实例@Autowiredprivate Bus bus;//注入业务实例@Autowiredprivate UserServiceImpl userService;//添加拦截器@Autowiredprivate WebServiceInterceptor webServiceInterceptor;//WebService访问的父路径,会展示所有的wsdl//默认访问地址 http://localhost:9180/services// 由于,我在配置文件重新设置了路径,所有,访问路径会有一点变化
//    @Bean
//    public ServletRegistrationBean getServletRegistrationBean() {
//        return new ServletRegistrationBean(new CGIServlet(), "/services/");
//    }@Beanpublic Endpoint messageEndpoint() {EndpointImpl endpoint = new EndpointImpl(bus, userService);endpoint.publish("/hello");  //发布服务endpoint.getInInterceptors().add(webServiceInterceptor);return endpoint;}
}

2、访问wsdl说明书

springboot启动成功之后,查看发布的所有WSDL文件

默认的WSDL访问地址  http://localhost:9180/services

但是,我们在配置文件添加了自定义路径  http://localhost:9180/ws 

如果想访问某一个WSDL文件,就需要在后面添加具体的服务地址,以及wsdl参数。

比如    http://localhost:9180/ws/hello?wsdl

后面,如果真要使用WebService,可以使用动态发布(通过自定义注解,或其他方式)。不然每有一个服务,就要在Config类里面配置一次,比较麻烦

3、WebService客户端搭建

maven依赖 和 接口请求参数 ,跟服务端保持一致

定义客户端接口,不需要定义实现类

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;@WebService(name = "UserWebServiceDemo", serviceName = "UMR", targetNamespace = "http://impl.service.com/")
public interface UserClient {@WebMethod@WebResult(name = "resultCode")String queryUserInfo(@WebParam(name = "username") String username,@WebParam(name = "password") String password);@WebMethod(operationName = "saveFunction")@WebResultUser saveUser(@WebParam(name = "accountInfo") User user);
}

 

发起远程调用,访问服务端

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;public class UserConsumer {public static void main(String[] args) {//创建cxf代理工厂JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();//设置服务端的地址factory.setAddress("http://localhost:9180/ws/hello");//设置接口类型factory.setServiceClass(UserClient.class);//生成代理对象UserClient userClient = factory.create(UserClient.class);String result = userClient.queryUserInfo("hello", "123");System.out.println(result);}
}

 控制台打印结果如下


 

可以看见,因为客户端传入的时候,没有在头信息放入用户名和密码,导致在服务端的拦截器报错,说明,服务端的拦截器是生效了。

4、定义客户端的拦截器,在拦截器里设置头信息

import java.util.List;import javax.xml.namespace.QName;import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;public class AuthHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage> {private String username;private String password;public AuthHeaderInterceptor(String username, String password) {super(Phase.PREPARE_SEND);this.username = username;this.password = password;}public void handleMessage(SoapMessage message) throws Fault {// SoapHeader部分待添加的节点QName qName = new QName("auth");Document doc = DOMUtils.createDocument();Element root = doc.createElement("auth");  //认证信息Element pwdEl = doc.createElement("password");pwdEl.setTextContent(password);Element userEl = doc.createElement("username");userEl.setTextContent(username);root.appendChild(userEl);root.appendChild(pwdEl);// 新增一个头信息SoapHeader header = new SoapHeader(qName, root);List<Header> headers = message.getHeaders();// 添加SoapHeader内容headers.add(header);}}

5、调整客户端的远程调用,新增一个拦截器进去

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;public class UserConsumer {public static void main(String[] args) {//创建cxf代理工厂JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();//设置服务端的地址factory.setAddress("http://localhost:9180/ws/hello?wsdl");//映射的接口factory.setServiceClass(UserClient.class);//客户端添加到outInterceptorsfactory.getOutInterceptors().add(new AuthHeaderInterceptor("YXQZ", "123"));UserClient userClient = factory.create(UserClient.class);User user = new User();user.setUsername("123");user.setAge(18);user.setPassword("666");User result = userClient.saveUser(user);//打印远程调用返回结果System.out.println(result);}
}

客户端远程调用正常获取

http://www.xdnf.cn/news/4047.html

相关文章:

  • 2025系统架构师---论面向对象的软件设计
  • Python字符串全面指南:从基础到高级操作
  • 计算机视觉与深度学习 | 点云配准算法综述(1992-2025)
  • Python核心技巧 类与实例:面向对象编程的基石
  • 协程补充---viewModelScope 相关知识点
  • 【计算机视觉】3d人脸重建:3DDFA_V2:实时高精度3D人脸重建与密集对齐技术指南
  • 【NLP】 26. 语言模型原理与概率建模方法详解(Language Models)
  • QT聊天项目DAY08
  • C 语言逻辑运算符:组合判断,构建更复杂的条件
  • Cisco Packet Tracer 选项卡的使用
  • Python中的客户端和服务端交互的基本内容
  • vue实现AI问答Markdown打字机效果
  • 【C/C++】函数模板
  • Auto.js 脚本:清理手机数据但保留账号
  • 第R8周:RNN实现阿尔兹海默病诊断(pytorch)
  • 基于EFISH-SCB-RK3576工控机/SAIL-RK3576核心板的网络安全防火墙技术方案‌(国产化替代J1900的全栈技术解析)
  • Python生活手册-正则表达式:从快递单到咖啡订单的文本魔法
  • Level DB --- MergingIterator
  • Compose 中使用 WebView
  • 基于YOLOv的目标检测训练数据构建方法研究—图像采集、标注、划分与增强一体化流程设计
  • Softmax回归与单层感知机对比
  • 【platform push 提示 Invalid source ref: HEAD】
  • 双目视觉的核心目标
  • NGINX 的 ngx_http_auth_jwt_module模块
  • 模块方法模式(Module Method Pattern)
  • JavaScript 实现输入框的撤销功能
  • 算力经济模型推演:从中心化到去中心化算力市场的转变(区块链+智能合约的算力交易原型设计)
  • Python项目源码57:数据格式转换工具1.0(csv+json+excel+sqlite3)
  • C++ 类与对象(下)—— 进阶特性与底层机制解析(构造函数初始化,类型转换,static成员,友元,内部类,匿名对象)
  • 基于 HTML 和 CSS 实现的 3D 翻转卡片效果