1.开发服务端
a) 下载CXF:apache-cxf-3.1.6
b) 把cxf的jar包加入到项目中,其它不需要改变(同JDK开发webservice一样),webservice服务端开发完成。
2.开发客户端
a) 加入环境变量path中,E:\apache-cxf-3.1.6\bin
b) 在cmd命令下生成客户代码,命令为:wsdl2java url,该命令为cxf的bin目录下的功能。
c) 编写客户端测试代码
public class ClientTest {
public static void main(String[] args) {
HelloWSImplService factory = new HelloWSImplService();
HelloWs helloWs = factory.getHelloWSImplPort();
String result = helloWs.sayHello("xdy");
System.out.println(result);
}
}
WebService请求的流程
一次web service请求的本质:
1.客户端向服务端发送了一个soap消息(http请求+xml片断)。
2.服务器端处理完请求后,向客户端返回一个soap消息。
/**********************************华丽分割线******************************************/
CXF框架的使用
1、CXF的拦截器
为什么设计拦截器?
为了在webservice请求过程中,能动态操作请求和响应数据,CXF设计了拦截器。
拦截器分类:
1.按所处的位置分:服务器端拦截器,客户端拦截器。
2.按消息的方向分:入拦截器,出拦截器。
3.按定义者分:系统拦截器,自定义拦截器。
【示例】演示为客户端及服务端加入日志拦截器。
为服务端ServerTest加入日志拦截器。
public class ServerTest {
public static void main(String[] args) {
String address = "http://192.168.0.102:8989/day01_ws/hellows";
Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl());
System.out.println(endpoint);
EndpointImpl endpointImpl = (EndpointImpl)endpoint;
//服务端的日志入拦截器
List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
inInterceptors.add(new LoggingInInterceptor());
//服务端的日志出拦截器
List<Interceptor<? extends Message>> outInterceptors = endpointImpl.getOutInterceptors();
outInterceptors.add(new LoggingOutInterceptor());
System.out.println("发布webservice成功!");
}
}
为客户端ClientTest加入日志拦截器。
public class ClientTest {
public static void main(String[] args) {
HelloWSImplService factory = new HelloWSImplService();
HelloWs helloWs = factory.getHelloWSImplPort();
//发送请求的客户端对象
Client client = ClientProxy.getClient(helloWs);
//客户端的日志出拦截器
List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
outInterceptors.add(new LoggingOutInterceptor());
//客户端的日志入拦截器
List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors();
inInterceptors.add(new LoggingInInterceptor());
String result = helloWs.sayHello("xdy");
System.out.println(result);
}
}
2、CXF自定义拦截器
AbstractPhaseInterceptor:抽象过程拦截器,一般自定义的拦截器都会继承于它
功能:通过自定义拦截器实现用户名和密码的检查
1.客户端拦截器:设置out拦截器,向soap消息中添加用户名和密码数据
public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private String name;
private String password;
public MyInterceptor(String name,String password) {
super(Phase.PRE_PROTOCOL);
this.name = name;
this.password = password;
}
/*
<Envelope>
<head>
<xdy>
<name>xiongdy</name>
<password>123456</password>
</xdy>
</head>
<body>
<sayHello>
<arg0>xdy</arg0>
</sayHello>
</body>
</Envelope>
*/
public void handleMessage(SoapMessage message) throws Fault {
List<Header> headers = message.getHeaders();
/*
<xdy>
<name>xiongdy</name>
<password>123456</password>
</xdy>
*/
//Document document = DOMHelper.createDocument();
Document document = DOMUtils.createDocument();
//<xdy>
Element rootEle = document.createElement("xdy");
//<name>xiongdy</name>
Element nameEle = document.createElement("name");
nameEle.setTextContent(name);
rootEle.appendChild(nameEle);
//<password>123456</password>
Element passwordEle = document.createElement("password");
passwordEle.setTextContent(password);
rootEle.appendChild(passwordEle);
//添加为请求消息的<soap:Header>
headers.add(new Header(new QName("xdy"), rootEle));
System.out.println("client-----handleMessage");
}
}
2.服务端拦截器:设置in拦截器,从soap消息中获取用户名和密码数据,如果不满足条件就不执行web service的方法
public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
public MyInterceptor() {
super(Phase.PRE_PROTOCOL);
}
@Override
public void handleMessage(SoapMessage msg) throws Fault {
System.out.println("server-----handleMessage");
Header header = msg.getHeader(new QName("xdy"));
if(header==null) {
throw new Fault(new RuntimeException("用户名密码不存在 "));
} else {
Element data = (Element) header.getObject();
if(data==null) {
throw new Fault(new RuntimeException("用户名密码不存在22"));
} else {
String name = data.getElementsByTagName("name").item(0).getTextContent();
String password = data.getElementsByTagName("password").item(0).getTextContent();
if(!"xiongdy".equals(name) || !"123456".equals(password)) {
throw new Fault(new RuntimeException("用户名密码不正确"));
}
}
}
System.out.println("通过拦截器了!");
}
}
3.服务端测试代码:
public class ServerTest {
public static void main(String[] args) {
String address = "http://192.168.0.102:8989/day01_ws/hellows";
Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl());
System.out.println(endpoint);
EndpointImpl endpointImpl = (EndpointImpl)endpoint;
//服务端的自定义入拦截器
List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
inInterceptors.add(new MyInterceptor());
System.out.println("发布webservice成功!");
}
}
4.客户端测试代码
public class ClientTest2 {
public static void main(String[] args) {
HelloWSImplService factory = new HelloWSImplService();
HelloWs helloWs = factory.getHelloWSImplPort();
//发送请求的客户端对象
Client client = ClientProxy.getClient(helloWs);
//客户端的自定义出拦截器
List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
outInterceptors.add(new MyInterceptor("xiongdy", "123456"));
String result = helloWs.sayHello("xdy");
System.out.println(result);
}
}
/**********************************华丽分割线******************************************/
用CXF编写基于Spring的WebService
server端:
1. 新建web工程,导入cxf的jar包
2. 定义SEI和其实现
@WebService
public interface OrderService {
@WebMethod
public Order getOrderByNo(String orderNo);
}
@WebService
public class OrderServiceImpl implements OrderService {
public OrderServiceImpl() {
System.out.println("OrderServiceImpl()");
}
public Order getOrderByNo(String orderNo) {
System.out.println("getOrderByNo() orderNO=" + orderNo);
return new Order(3, orderNo, 10000000);
}
}
public class Order {
private int id;
private String orderNo;
private double price;
}
3. 发布web service
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 配置一些cxf的核心bean -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!--
终端:发布webservice(将SEI的实现类对象与web service所提供的网络地址关联)
-->
<jaxws:endpoint id="orderService"
implementor="com.xdy.ws.OrderServiceImpl" address="/orderService" />
</beans>
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 配置上下文初始化参数:指定cxf的spring的beans.xml -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<!-- 加载上面参数的配置文件的listener -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 匹配所有请求,将请求先交给cxf框架处理 -->
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
client端
1. 新建web工程,导入cxf的jar包
2. 根据wsdl文档生成客户端代码(src下)
3. client-beans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 配置发送请求的客户端 -->
<jaxws:client id="orderClient"
serviceClass="com.xdy.ws.OrderService" address="http://localhost:8080/wsspringserver/orderService" />
</beans>
4. 编写测试代码:
public class ClientTest {
public static void main(String[] args) {
// 加载client-beans.xml
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("client-beans.xml");
// 根据bean的id加载所对应的OrderService
OrderService orderService = (OrderService) context.getBean("orderClient");
// 调用方法,发送soap请求
Order order = orderService.getOrderByNo("hao123");
System.out.println("client " + order.getId() + "_" + order.getOrderNo()+ "_" + order.getPrice());
}
}
/**********************************华丽分割线******************************************/
用CXF编写基于Spring的WebService添加拦截器
客户端:
client-beans.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 配置发送请求的客户端 -->
<jaxws:client id="orderClient"
serviceClass="com.xdy.ws.OrderService" address="http://localhost:8080/wsspringserver/orderService" >
<jaxws:outInterceptors>
<bean class="com.xdy.ws.interceptor.MyInterceptor">
<property name="name" value="xiongdy"></property>
<property name="password" value="123456"></property>
</bean>
</jaxws:outInterceptors>
</jaxws:client>
</beans>
客户端拦截器MyInterceptor:
public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private String name;
private String password;
public MyInterceptor(String name,String password) {
super(Phase.PRE_PROTOCOL);
this.name = name;
this.password = password;
System.out.println("MyInterceptor.....");
}
public MyInterceptor() {
super(Phase.PRE_PROTOCOL);
System.out.println("MyInterceptor.....^_^");
}
/*
<Envelope>
<head>
<xdy>
<name>xiongdy</name>
<password>123456</password>
</xdy>
</head>
<body>
<sayHello>
<arg0>xdy</arg0>
</sayHello>
</body>
</Envelope>
*/
public void handleMessage(SoapMessage message) throws Fault {
List<Header> headers = message.getHeaders();
/*
<xdy>
<name>xiongdy</name>
<password>123456</password>
</xdy>
*/
//Document document = DOMHelper.createDocument();
Document document = DOMUtils.createDocument();
//<xdy>
Element rootEle = document.createElement("xdy");
//<name>xiongdy</name>
Element nameEle = document.createElement("name");
nameEle.setTextContent(name);
rootEle.appendChild(nameEle);
//<password>123456</password>
Element passwordEle = document.createElement("password");
passwordEle.setTextContent(password);
rootEle.appendChild(passwordEle);
//添加为请求消息的<soap:Header>
headers.add(new Header(new QName("xdy"), rootEle));
System.out.println("client-----handleMessage");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
服务器端:
Beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- 配置一些cxf的核心bean -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!--
终端:发布webservice(将SEI的实现类对象与web service所提供的网络地址关联)
-->
<jaxws:endpoint id="orderService"
implementor="com.xdy.ws.OrderServiceImpl" address="/orderService" >
<jaxws:inInterceptors>
<bean class="com.xdy.ws.interceptor.MyInterceptor"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
服务端拦截器MyInterceptor:
public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
public MyInterceptor() {
super(Phase.PRE_PROTOCOL);
}
public void handleMessage(SoapMessage msg) throws Fault {
System.out.println("server-----handleMessage");
Header header = msg.getHeader(new QName("xdy"));
if(header==null) {
throw new Fault(new RuntimeException("用户名密码不存在 "));
} else {
Element data = (Element) header.getObject();
if(data==null) {
throw new Fault(new RuntimeException("用户名密码不存在22"));
} else {
String name = data.getElementsByTagName("name").item(0).getTextContent();
String password = data.getElementsByTagName("password").item(0).getTextContent();
if(!"xiongdy".equals(name) || !"123456".equals(password)) {
throw new Fault(new RuntimeException("用户名密码不正确"));
}
}
}
System.out.println("通过拦截器了!");
}
}