SpringBoot官网地址:https://spring.io/projects/spring-ws
1、WebService服务端搭建
Maven依赖
XML
<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: #默认根目录是 /services path: /ws
WebService拦截器
java
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());
}
@Override
public 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("用户账号、密码不正确"));
}
}
}
接口请求参数
java
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;
}
}
定义接口和它的实现类
java
public interface UserService {
String queryUserInfo(String username, String password);
User saveUser(User user);
}
java
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")
@WebResult
public User saveUser(@WebParam(name = "accountInfo") User user) {
System.out.println("保存用户信息");
return user;
}
}
CXF配置类
java
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总线 实例
@Autowired
private Bus bus;
//注入业务实例
@Autowired
private UserServiceImpl userService;
//添加拦截器
@Autowired
private WebServiceInterceptor webServiceInterceptor;
//WebService访问的父路径,会展示所有的wsdl
//默认访问地址 http://localhost:9180/services
// 由于,我在配置文件重新设置了路径,所有,访问路径会有一点变化
// @Bean
// public ServletRegistrationBean getServletRegistrationBean() {
// return new ServletRegistrationBean(new CGIServlet(), "/services/");
// }
@Bean
public 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依赖 和 接口请求参数 ,跟服务端保持一致
定义客户端接口,不需要定义实现类
java
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")
@WebResult
User saveUser(@WebParam(name = "accountInfo") User user);
}
发起远程调用,访问服务端
java
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、定义客户端的拦截器,在拦截器里设置头信息
java
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、调整客户端的远程调用,新增一个拦截器进去
java
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);
//客户端添加到outInterceptors
factory.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);
}
}
客户端远程调用正常获取
