1、添加依赖
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.kangswx</groupId>
<artifactId>springboot-webservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-webservice</name>
<description>springboot整合webservice</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- SpringBoot依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot整合WebService依赖 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.2.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、webservice配置类
package com.pbm.webservice.config;
import javax.xml.ws.Endpoint;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.pbm.webservice.business.UserService;
/**
* webservice配置类
* @author Administrator
*
*/
@Configuration
public class CxfConfig {
@Autowired
private Bus bus;
@Autowired
private UserService userService;
/**
* 此方法作用是改变项目中服务名的前缀名,此处127.0.0.1或者localhost不能访问时,请使用ipconfig查看本机ip来访问
* 此方法被注释后:wsdl访问地址为http://127.0.0.1:8080/services/user?wsdl
* 去掉注释后:wsdl访问地址为:http://127.0.0.1:8080/soap/user?wsdl
* @return
*/
/*@SuppressWarnings("all")
@Bean
public ServletRegistrationBean servletRegistrationBean(){
return new ServletRegistrationBean(new CXFServlet(), "/soap/*");
}*/
/**
* JAX-WS
* 站点服务
* @return
*/
@Bean
public Endpoint endpoint(){
EndpointImpl endpoint = new EndpointImpl(bus, userService);
endpoint.publish("/user");
return endpoint;
}
}
3、User.java
package com.pbm.webservice.business;
import java.io.Serializable;
/**
* 实体类
* @author Administrator
*
*/
public class User implements Serializable {
private static final long serialVersionUID = -3718315085738793442L;
private Integer id;
private String name;
private String email;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
4、UserService
package com.pbm.webservice.business;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
/**
* WebService接口
* WebService(targetNamespace = "http://business.webservice.pbm.com")
* 如果不添加的话,动态调用invoke的时候,会报找不到接口内的方法
*/
@WebService(targetNamespace = "http://business.webservice.pbm.com")
public interface UserService {
@WebMethod //标注该方法为webservice暴露的方法,用于向外公布,它修饰的方法是webservice方法
String getUser(@WebParam(name = "id") int id);
@WebMethod
@WebResult(name = "String", targetNamespace = "")
String getUserName(@WebParam(name = "id") int id);
}
5、UserServiceImpl
package com.pbm.webservice.business;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
import javax.jws.WebService;
import java.util.HashMap;
import java.util.Map;
/**
* serviceName UserService 对外发布的服务名
* targetNamespace 指定名称空间,通常为包名倒序
* endpointInterface 指定做SEI(Service EndPoint Interface)服务端点接口
* 注意:com.pbm.webservice.business的倒序是business.webservice.pbm.com
*
* @author Administrator
*
*/
@WebService(serviceName = "UserService",
targetNamespace = "http://business.webservice.pbm.com",
endpointInterface = "com.pbm.webservice.business.UserService")
@Component
public class UserServiceImpl implements UserService {
private Map<Integer, User> userMap = new HashMap<>();
public UserServiceImpl(){
User user = new User();
user.setId(1);
user.setName("张三");
user.setEmail("zhangsan@test.com");
userMap.put(user.getId(), user);
User user1 = new User();
user1.setId(2);
user1.setName("李四");
user1.setEmail("lisi@test.com");
userMap.put(user1.getId(), user1);
}
@Override
public String getUser(int id) {
return JSONObject.toJSONString(userMap.get(id));
}
@Override
public String getUserName(int id) {
System.out.println("getUserName: "+id);
return userMap.get(id).getName();
}
}
6、运行并访问http://localhost:8080/services/user?wsdl
注意:http://localhost:8080/services/中的services是固定的。
出现以下说明成功了
7、测试调用
package com.pbm.demo;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.junit.Test;
import com.pbm.webservice.business.UserService;
import com.pbm.webservice.config.ClientLoginInterceptor;
/**
* 两种不同的方式来调用webservice服务
* 1:代理工厂方式
* 2:动态调用webservice
*/
public class WebServiceTest {
/**
* 代理工厂的方式,需要拿到对方的接口地址
*/
@Test
public void getUserTest1() {
// 接口地址
String address = "http://localhost:8080/services/user?wsdl";
// 代理工厂
JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
// 设置代理地址
jaxWsProxyFactoryBean.setAddress(address);
// 设置接口类型
jaxWsProxyFactoryBean.setServiceClass(UserService.class);
// 创建一个代理接口实现
UserService us = (UserService) jaxWsProxyFactoryBean.create();
//测试数据
int id = 2;
// 调用代理接口的方法调用并返回结果
String userName = us.getUserName(id);
/*System.out.println("返回结果: "+userName);*/
}
/**
* 动态调用
*/
@Test
public void getUserNameTest2() {
// 创建动态客户端
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://localhost:8080/services/user?wsdl");
// 需要密码的情况需要加上用户名和密码
//client.getOutInterceptors().add(new ClientLoginInterceptor("admin", "123456"));
Object[] objects = new Object[0];
try {
// invoke("方法名",参数1,参数2,参数3....);
objects = client.invoke("getUserName", 2);
System.out.println("返回数据:" + objects[0]);
} catch (java.lang.Exception e) {
e.printStackTrace();
}
}
}
8、添加安全认证
(1)AuthInterceptor为权限过滤
package com.pbm.webservice.config;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.NodeList;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
/**
* AuthInterceptor为权限过滤
* @author Administrator
*
*/
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private static final Logger logger = LoggerFactory.getLogger(AuthInterceptor.class);
private SAAJInInterceptor saa = new SAAJInInterceptor();
private static final String USER_NAME = "admin";
private static final String USER_PASSWORD = "123456";
public AuthInterceptor() {
super(Phase.PRE_PROTOCOL);
getAfter().add(SAAJInInterceptor.class.getName());
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
SOAPMessage mess = message.getContent(SOAPMessage.class);
if(mess==null){
saa.handleMessage(message);
mess=message.getContent(SOAPMessage.class);
}
SOAPHeader header =null;
try {
header = mess.getSOAPHeader();
} catch (SOAPException e) {
logger.error("getSOAPheader error:{}",e.getMessage(),e);
e.printStackTrace();
}
if(header==null){
throw new Fault(new IllegalAccessException("找不到Header,无法验证用户信息"));
}
NodeList username = header.getElementsByTagName("username");
NodeList password = header.getElementsByTagName("password");
if(username.getLength()<1){
throw new Fault(new IllegalAccessException("找不到Header,无法验证用户信息"));
}
if(password.getLength()<1){
throw new Fault(new IllegalAccessException("找不到Header,无法验证用户信息"));
}
String userName = username.item(0).getTextContent().trim();
String passWord = password.item(0).getTextContent().trim();
if(USER_NAME.equals(userName)&&USER_PASSWORD.equals(passWord)){
logger.debug("admin auth success");
}else {
SOAPException soapException = new SOAPException("认证错误");
logger.debug("admin auth failed");
throw new Fault(soapException);
}
}
}
(2)定义拦截器用户用户验证
package com.pbm.webservice.config;
import java.util.List;
import javax.xml.namespace.QName;
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;
/**
* 定义拦截器用户用户验证
* @author Administrator
*
*/
public class ClientLoginInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private String username;
private String password;
public ClientLoginInterceptor() {
// 定义在哪个阶段进行拦截
super(Phase.PREPARE_SEND);
}
public ClientLoginInterceptor(String username, String password) {
//super();
// 定义在哪个阶段进行拦截
super(Phase.PREPARE_SEND);
this.username = username;
this.password = password;
}
@Override
public void handleMessage(SoapMessage soap) throws Fault {
List<Header> headers = soap.getHeaders();
Document doc = DOMUtils.createDocument();
Element auth = doc.createElementNS("http://config.springbootwebservice.kangswx.com","UserService"); // WebServices:命名空间
Element username = doc.createElement("username");
Element password = doc.createElement("password");
username.setTextContent(this.username);
password.setTextContent(this.password);
auth.appendChild(username);
auth.appendChild(password);
headers.add(0, new Header(new QName("identification"), auth));
}
}
(3)在配置类CxfConfig中添加配置
endpoint.getInInterceptors().add(new ClientLoginInterceptor());
endpoint.getInInterceptors().add(new AuthInterceptor());
(4)调用时增加账号和密码验证
client.getOutInterceptors().add(new ClientLoginInterceptor("admin", "123456"));