欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringBoot开发WebService之CXF

程序员文章站 2022-04-02 16:15:26
...
一、在服务器端的WebSerivce服务发布
1、POM.xml文件引入相关的依赖包
<?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>

	<groupId>net.logcd</groupId>
	<artifactId>springboot_wscxf</artifactId>
	<version>1.0.0</version>
	<packaging>jar</packaging>

	<name>springboot_wscxf</name>
	<description></description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.8.RELEASE</version>
		<relativePath/>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.7</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-web-services</artifactId>
		</dependency>
		
		<dependency>
		    <groupId>org.apache.cxf</groupId>
		    <artifactId>cxf-rt-frontend-jaxws</artifactId>
		    <version>3.1.6</version>
		</dependency>
		<dependency>
		    <groupId>org.apache.cxf</groupId>
		    <artifactId>cxf-rt-transports-http</artifactId>
		    <version>3.1.6</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(targetNamespace="http://cxf.logcd.net")
@Service("helloService")
public class HelloService{

    public String sayHello(String user, String userData) {
        return "hello," + user+"! userData = "+userData;
    }

}

3、定义访问权限验证的拦截器
/**
 * 校验(用户名、密码)拦截器
 */
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {

	private Logger logger = Logger.getLogger(this.getClass());
	private static final String USERNAME = "admin";
	private static final String PASSWORD = "admin";

	public AuthInterceptor() {
		// 定义在哪个阶段进行拦截
		super(Phase.PRE_PROTOCOL);
	}

	@Override
	public void handleMessage(SoapMessage soapMessage) throws Fault {
		List<Header> headers = null;
		String username = null;
		String password = null;
		try {
			headers = soapMessage.getHeaders();
		} catch (Exception e) {
			logger.error("getSOAPHeader error: {}", e);
		}

		if (headers == null) {
			throw new Fault(new IllegalArgumentException("找不到Header,无法验证用户信息"));
		}
		// 获取用户名,密码
		for (Header header : headers) {
			SoapHeader soapHeader = (SoapHeader) header;
			Element e = (Element) soapHeader.getObject();
			NodeList usernameNode = e.getElementsByTagName("username");
			NodeList pwdNode = e.getElementsByTagName("password");
			username = usernameNode.item(0).getTextContent();
			password = pwdNode.item(0).getTextContent();
			if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
				throw new Fault(new IllegalArgumentException("用户信息为空"));
			}
		}
		// 校验用户名密码
		if (!(username.equals(USERNAME) && password.equals(PASSWORD))) {
			SOAPException soapExc = new SOAPException("认证失败");
			logger.info("用户认证信息错误");
			throw new Fault(soapExc);
		}
	}

}

4、发布webserive服务
/**
 * 配置并发布WebService
 */
@Configuration
public class WSCxfConfig {
	
	@Bean
	public ServletRegistrationBean dispatcherServlet() {
		//接口访问的过滤路径
		return new ServletRegistrationBean(new CXFServlet(), "/cxf/*");
	}

	@Bean(name = Bus.DEFAULT_BUS_ID)
	public SpringBus springBus() {
		return new SpringBus();
	}

	@Bean
	public HelloService helloService() {
		return new HelloService();
	}

	@Bean
	public Endpoint endpoint() {
		EndpointImpl endpoint = new EndpointImpl(springBus(), helloService());
		endpoint.getInInterceptors().add(new AuthInterceptor());//添加校验拦截器
		endpoint.publish("/helloService");
		return endpoint;
	}

}

5、SpringBoot应用启动
@SpringBootApplication
public class Application {
	
	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
	
}

二、客户端测试调用WebService
1、调用WebSerivce时,设置帐号密码的拦截器
/**
 * 调用时添加用户名密码信息
 */
public class LoginInterceptor extends AbstractPhaseInterceptor<SoapMessage> {

	private String namespace = "http://cxf.cdmcs.com";
	private String username = "admin";
	private String password = "admin";

	public LoginInterceptor(String username, String password) {
		// 设置在发送请求前阶段进行拦截
		super(Phase.PREPARE_SEND);
		this.username = username;
		this.password = password;
	}

	@Override
	public void handleMessage(SoapMessage soapMessage) throws Fault {
		List<Header> headers = soapMessage.getHeaders();
		Document doc = DOMUtils.createDocument();
		Element auth = doc.createElementNS(namespace, "SecurityHeader");
		Element UserName = doc.createElement("username");
		Element UserPass = doc.createElement("password");

		UserName.setTextContent(username);
		UserPass.setTextContent(password);

		auth.appendChild(UserName);
		auth.appendChild(UserPass);

		headers.add(0, new Header(new QName("SecurityHeader"), auth));
	}

}

2、客户端调用测试
public class TestClientCXFWS {

	/**
	 * 动态调用方式
	 * @throws Exception
	 */
	@Test
	public void invokeHelloService_WS() throws Exception {
		//WSDL路径 
        String wsUrl = "http://127.0.0.1:8080/cxf/helloService?wsdl";
        String nameSpace = "http://cxf.logcd.net";
		//方法名 
		String method = "sayHello"; 
		
		JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        Client client = dcf.createClient(wsUrl);
        //需要密码的情况需要加上用户名和密码
        client.getOutInterceptors().add(new LoginInterceptor("admin","admin"));
        Endpoint endpoint = client.getEndpoint();
        
        //endpoint.getService().getName().getNamespaceURI()
        QName opName = new QName(nameSpace, method);
        BindingInfo bindingInfo = endpoint.getEndpointInfo().getBinding();
        
        //如果命名空间不对,需要重新寻找operationName
        if (bindingInfo.getOperation(opName) == null) {
            for (BindingOperationInfo operationInfo : bindingInfo.getOperations()) {
              if (method.equals(operationInfo.getName().getLocalPart())) {
                opName = operationInfo.getName();
                break;
              }
            }
        }
        
        Object[] params = new Object[] {"Lucy","{time:"+new Date().toString()+"}"};
        Object[] retArr = client.invoke(opName, params);
        System.out.println(retArr[0]);
	}
	
}