- 首先在pom.xml文件中引入依赖
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-spring-boot-starter-jaxws</artifactId>
<version>3.4.1</version>
</dependency>
注意:我用的springboot版本是2.3.5.RELEASE,因为cxf-spring-boot-starter-jaxws 的 3.4.1 版本依赖的springboot版本是2.3.5.RELEASE,所以我引入的cxf-spring-boot-starter-jaxws 的版本是3.4.1
- 服务端声明接口
package com.lqb.study.webservice.service;
import com.lqb.study.webservice.entity.User;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* @date 2020-11-07
* @author LQB
*/
@WebService(targetNamespace = "http://webservice.study.lqb.com/entity")
public interface UserService {
/**
* 根据用户名与密码 查询用户信息
* @param username 用户名
* @param password 密码
* @return 用户对象
*/
@WebMethod
User detail(@WebParam(name = "username") String username,@WebParam(name = "password") String password);
}
- 接口实现类
package com.lqb.study.webservice.service.impl;
import com.lqb.study.webservice.entity.User;
import com.lqb.study.webservice.service.UserService;
import org.springframework.stereotype.Component;
import javax.jws.WebMethod;
import javax.jws.WebService;
import java.util.Date;
/**
* @author LQB
* @date 2020-11-07
*/
@Component
@WebService(targetNamespace = "http://webservice.study.lqb.com/entity",// 与接口中的命名空间一致,一般是接口的包名倒
serviceName = "UserService",
endpointInterface = "com.lqb.study.webservice.service.UserService")
public class UserServiceImpl implements UserService {
@Override
@WebMethod
public User detail(String username,String password){
return new User(1,username,password,new Date(),1);
}
}
- webserivce配置类
package com.lqb.study.webservice.confg;
import com.lqb.study.webservice.service.UserService;
import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
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;
/**
* @author LQB
*/
@Configuration
public class WebServiceConfig {
@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
*/
@Bean
public ServletRegistrationBean<CXFServlet> disServlet() {
return new ServletRegistrationBean<>(new CXFServlet(), "/service/*");
}
@Bean(name = Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
/** JAX-WS
* 站点服务
* **/
@Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(bus, userService);
endpoint.getInInterceptors().add(new ClientLoginInterceptor());
endpoint.getInInterceptors().add(new AuthInterceptor());
endpoint.publish("/userService");
return endpoint;
}
}
- 服务端针对客户端请求时需要密码认证
package com.lqb.study.webservice.confg;
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;
/**
* 发布服务端,定义拦截器用户用户验证
* @date 2020-11-09
* @author LQB
*/
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";
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);
}
}
}
- 客户端请求时认证
package com.lqb.study.webservice.confg;
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;
import javax.xml.namespace.QName;
import java.util.List;
/**
* @author LQB
*/
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(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.createElement("authrity");
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("timamaes"), auth));
}
}
- 客户端测试调用
package com.lqb.study.webservice.service;
import com.lqb.study.webservice.confg.ClientLoginInterceptor;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class TestUserService {
private final static String USER_NAME="admin";
private final static String PASS_WORD="123456";
@Test
void testUserService(){
// 创建动态客户端
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://127.0.0.1:8080/service/userService?wsdl");
// 需要密码的情况需要加上用户名和密码
client.getOutInterceptors().add(new ClientLoginInterceptor(USER_NAME, PASS_WORD));
try {
// invoke("方法名",参数1,参数2,参数3....);
Object[] objects = client.invoke("detail", "scott","tiger");
if(objects[0] instanceof User){
User user = (User) objects[0];
System.out.println("用户名:" + user.getUsername());
System.out.println("密码:" + user.getPassword());
}
} catch (java.lang.Exception e) {
e.printStackTrace();
}
}
}