Spring Boot实践--集成cxf完整实例

服务端

添加依赖pom.xml

<!-- cxf:serve client  -->
<dependency>
	<groupId>org.apache.cxf</groupId>
          <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
          <version>3.1.12</version>
</dependency>
<!-- 注意上楼的区别 -->
<!-- <dependency>
	<groupId>org.apache.cxf</groupId>
          <artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
          <version>3.1.12</version>
</dependency> -->

服务接口

package com.spinach.example.webservice.cxf.server;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 * web services 接口
 */
@WebService(targetNamespace = "http://server.cxf.webservice.example.spinach.com") // 命名空间,一般是接口的包名倒序
public interface CxfServices {
	@WebMethod
	String sayHello(@WebParam(name = "userName") String name);
}

服务接口实现

package com.spinach.example.webservice.cxf.server;

import org.springframework.stereotype.Component;

import javax.jws.WebService;

/**
 *  web services 接口实现
 */
@WebService(serviceName = "cxfServices"// 服务名
		, targetNamespace = "http://server.cxf.webservice.example.spinach.com"// 包名倒序,并且和接口定义保持一致
		, endpointInterface = "com.spinach.example.webservice.cxf.server.CxfServices") // 包名
@Component
public class CxfServicesImpl implements CxfServices {
	@Override
	public String sayHello(String name) {
		return "hello , " + name;
	}
}

发布服务配置

package com.spinach.example.webservice.cxf.server;

import javax.xml.ws.Endpoint;

import org.apache.cxf.Bus;
//import org.apache.cxf.endpoint.EndpointImpl;
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;

/**
 * 注意引入的包路径:
 * 是:org.apache.cxf.jaxws.EndpointImpl 不是:import org.apache.cxf.endpoint.EndpointImpl
 * 还有:import javax.xml.ws.Endpoint;
 * @author:spinach
 * @date:2018年2月1日下午4:56:02
 */
@Configuration
public class CxfConfig {
	@Autowired
    private Bus bus;
    @Autowired
    private CxfServices cxfServices;

    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(bus,cxfServices);
        endpoint.publish("/cxfServices");//接口发布在目录下
        return endpoint;
    }
    
    @Bean
    public ServletRegistrationBean dispatcherServlet() {
        return new ServletRegistrationBean(new CXFServlet(), "/cxf/*");
    }
    
    /* 方法二:方法二为@Autowired自动注入
    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus() {
        return new SpringBus();
    }
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(springBus(), userService());
        endpoint.publish("/user");
        return endpoint;
    }*/
}

拦截器(增加用户名和密码需要)AuthInterceptor.java

package com.spinach.example.webservice.cxf.server;

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;

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 = "pass";
	
	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 head = null;
		try {
			head = mess.getSOAPHeader();
		} catch (Exception e) {
			logger.error("getSOAPHeader error: {}", e.getMessage(), e);
		}

		if (head == null) {
			throw new Fault(new IllegalArgumentException("找不到Header,无法验证用户信息"));
		}
		NodeList users = head.getElementsByTagName("username");
		NodeList passwords = head.getElementsByTagName("password");
		if (users.getLength() < 1) {
			throw new Fault(new IllegalArgumentException("找不到用户信息"));
		}
		if (passwords.getLength() < 1) {
			throw new Fault(new IllegalArgumentException("找不到密码信息"));
		}
		String userName = users.item(0).getTextContent().trim();
		String password = passwords.item(0).getTextContent().trim();
		if (USER_NAME.equals(userName) && USER_PASSWORD.equals(password)) {
			logger.debug("admin auth success");
		} else {
			SOAPException soapExc = new SOAPException("认证错误");
			logger.debug("admin auth failed");
			throw new Fault(soapExc);
		}
	}

}

配置文件CxfConfig.java

package com.spinach.example.webservice.cxf.server;

import javax.xml.ws.Endpoint;

import org.apache.cxf.Bus;
//import org.apache.cxf.endpoint.EndpointImpl;
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;

/**
 * 注意引入的包路径:
 * 是:org.apache.cxf.jaxws.EndpointImpl 不是:import org.apache.cxf.endpoint.EndpointImpl
 * 还有:import javax.xml.ws.Endpoint;
 * @author:spinach
 * @date:2018年2月1日下午4:56:02
 */
@Configuration
public class CxfConfig {
	@Autowired
    private Bus bus;
    @Autowired
    private CxfServices cxfServices;

    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(bus,cxfServices);
        endpoint.publish("/cxfServices");//接口发布在目录下
        //打印报文日志拦截器
        //endpoint.getInInterceptors().add(new LoggingInInterceptor());
        //endpoint.getInInterceptors().add(new LoggingOutInterceptor());

        //通过拦截器校验用户名与密码
        endpoint.getInInterceptors().add(new AuthInterceptor());
        return endpoint;
    }
    
    @Bean
    public ServletRegistrationBean dispatcherServlet() {
        return new ServletRegistrationBean(new CXFServlet(), "/cxf/*");
    }
    
    /* 方法二:方法二为@Autowired自动注入
    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus() {
        return new SpringBus();
    }
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(springBus(), userService());
        endpoint.publish("/user");
        return endpoint;
    }*/
}

 

验证

## 这个地址可以看到所有方法对应的接口
http://localhost:8080/cxf/

## sayHello方法
http://localhost:8080/cxf/cxfServices?wsdl
##出现内容如下:表未服务端成功

<wsdl:definitions name="cxfServices" targetNamespace="http://server.cxf.webservice.example.spinach.com">
	<wsdl:types>
		<xs:schema elementFormDefault="unqualified" targetNamespace="http://server.cxf.webservice.example.spinach.com" version="1.0">
			<xs:element name="sayHello" type="tns:sayHello" />
			<xs:element name="sayHelloResponse" type="tns:sayHelloResponse" />
			<xs:complexType name="sayHello">
				<xs:sequence>
					<xs:element minOccurs="0" name="userName" type="xs:string" />
				</xs:sequence>
			</xs:complexType>
			<xs:complexType name="sayHelloResponse">
				<xs:sequence>
					<xs:element minOccurs="0" name="return" type="xs:string" />
				</xs:sequence>
			</xs:complexType>
		</xs:schema>
	</wsdl:types>
	<wsdl:message name="sayHello">
		<wsdl:part element="tns:sayHello" name="parameters">
		</wsdl:part>
	</wsdl:message>
	<wsdl:message name="sayHelloResponse">
		<wsdl:part element="tns:sayHelloResponse" name="parameters">
		</wsdl:part>
	</wsdl:message>
	<wsdl:portType name="CxfServices">
		<wsdl:operation name="sayHello">
			<wsdl:input message="tns:sayHello" name="sayHello">
			</wsdl:input>
			<wsdl:output message="tns:sayHelloResponse" name="sayHelloResponse">
			</wsdl:output>
		</wsdl:operation>
	</wsdl:portType>
	<wsdl:binding name="cxfServicesSoapBinding" type="tns:CxfServices">
		<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
		<wsdl:operation name="sayHello">
			<soap:operation soapAction="" style="document" />
			<wsdl:input name="sayHello">
				<soap:body use="literal" />
			</wsdl:input>
			<wsdl:output name="sayHelloResponse">
				<soap:body use="literal" />
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:service name="cxfServices">
		<wsdl:port binding="tns:cxfServicesSoapBinding" name="CxfServicesImplPort">
			<soap:address location="http://localhost:8080/cxf/cxfServices" />
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>

 

客户端

添加依赖的jar包:pom.xml:和服务端一样

spring-boot:依赖

<!-- cxf:serve client  -->
<dependency>
	<groupId>org.apache.cxf</groupId>
          <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
          <version>3.1.12</version>
</dependency>
<dependency>
	<groupId>org.codehaus.woodstox</groupId>
	<artifactId>stax2-api</artifactId>
	<version>3.1.4</version>
</dependency>
<!-- 注意上楼的区别 -->
<!-- <dependency>
	<groupId>org.apache.cxf</groupId>
          <artifactId>cxf-spring-boot-starter-jaxrs</artifactId>
          <version>3.1.12</version>
</dependency> -->

非spring-boot依赖

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxws</artifactId>
    <version>2.7.4</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-bindings-soap</artifactId>
    <version>2.7.4</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http</artifactId>
    <version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.apache.ws.security</groupId>
    <artifactId>wss4j</artifactId>
    <version>1.6.10</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-ws-security</artifactId>
    <version>2.7.5</version>
</dependency>

拦截器配置(包含header信息)

新建一个ClientLoginInterceptor.java,内容如下:

package com.spinach.example.webservice.cxf.client;

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;
import javax.xml.namespace.QName;
import java.util.List;

public class ClientLoginInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
	private String username;
	private String password;

	public ClientLoginInterceptor(String username, String password) {
		//super(Phase.PREPARE_SEND);
		super(Phase.WRITE);
		this.username = username;
		this.password = password;
	}

	/**
	 * method1
	 * <soap:header>
	  	 <authrity>
		    <username>username</username>
		    <password>password</username>
		  </authrity>
		</soap:header>
	 * @author:spinach
	 * @date:2018年2月8日下午2:54:37
	 * @param soap
	 * @throws Fault
	 */
	/*@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("RequestSOAPHeader"), auth));
	}*/

	/**
	 * method2
	 *  <soap:header>
		    <username>username</username>
		    <password>password</username>
		</soap:header>
	 * @author:spinach
	 * @date:2018年2月8日下午2:55:21
	 * @param soap
	 * @throws Fault
	 */
	@Override
	public void handleMessage(SoapMessage message) throws Fault {
		List<Header> headers = message.getHeaders();
		headers.add(getHeader("username", this.username));
		headers.add(getHeader("password", this.password));
	}

	/**
	 * 拼接头文件
	 * @author:spinach
	 * @date:2018年2月8日下午2:57:48
	 * @param key
	 * @param value
	 * @return
	 */
	private Header getHeader(String key, String value) {
		QName qName = new QName("http://webservice.webxml.com.cn/", key);
		Document document = DOMUtils.createDocument();
		Element element = document.createElementNS("http://webservice.webxml.com.cn/", key);
		element.setTextContent(value);
		SoapHeader header = new SoapHeader(qName, element);
		return (header);
	}

}

再给个有子节点的header例子:

  <soap:Header>
    <AuthorizationSoapHeader xmlns="http://tempuri.org/">
      <UserName>string</UserName>
      <Password>string</Password>
    </AuthorizationSoapHeader>
  </soap:Header>
    /**
     * 处理soap信息
     * @param message soap信息
     */
    public void handleMessage(SoapMessage message) throws Fault {
        // SoapHeader部分待添加的节点
        QName qName = new QName("AuthorizationSoapHeader");

        Document doc = DOMUtils.createDocument();
        // 验证用户名
        Element id = doc.createElement("UserName");
        id.setTextContent("0001");
        // 验证密码
        Element pwd = doc.createElement("Password");
        pwd.setTextContent("123");

        Element root = doc.createElementNS("http://tempuri.org/","AuthorizationSoapHeader");
        root.appendChild(id);
        root.appendChild(pwd);
        // 创建SoapHeader内容
        SoapHeader header = new SoapHeader(qName, root);
        // 添加SoapHeader内容
        List<Header> headers = message.getHeaders();
        headers.add(header);
    }

调用方式CxfServicesClient.java

package com.spinach.example.webservice.cxf.client;
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.spinach.example.webservice.cxf.server.CxfServices;

/**
 * cxf:接口测试
 * @author:spinach
 * @date:2018年2月1日下午5:05:00
 */
public class CxfServicesClient {
    /**
     * 方式1.代理类工厂的方式,需要拿到对方的接口
     */
    @Test
    public void method1() {
        try {
            // 接口地址
            String address = "http://localhost:8080/cxf/cxfServices?wsdl";
            // 代理工厂
            JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
            // 设置代理地址
            jaxWsProxyFactoryBean.setAddress(address);
            // 设置接口类型
            jaxWsProxyFactoryBean.setServiceClass(CxfServices.class);
            // 创建一个代理接口实现
            CxfServices cs = (CxfServices) jaxWsProxyFactoryBean.create();
            // 数据准备
            String userName = "method1";
            // 调用代理接口的方法调用并返回结果
            String result = cs.sayHello(userName);
            System.out.println("返回结果:" + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 动态调用方式
     */
    public void method2() {
        // 创建动态客户端
        JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
        Client client = dcf.createClient("http://localhost:8080/cxf/cxfServices?wsdl");
        // 需要密码的情况需要加上用户名和密码
         client.getOutInterceptors().add(new ClientLoginInterceptor("admin","pass"));
        Object[] objects = new Object[0];
        try {
            // invoke("方法名",参数1,参数2,参数3....);
            objects = client.invoke("sayHello", "method2");
            System.out.println("返回数据:" + objects[0]);
        } catch (java.lang.Exception e) {
            e.printStackTrace();
        }
    }
}

效果验证:运行:junit test: 打印对应的:"返回结果:hello , method1" 表示客户端成功。

转载于:https://my.oschina.net/spinachgit/blog/1616674

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值