WebService学习笔记(五)拦截器与SOAP协议

时间:2022-05-07 09:55:55

Web Service急需解决的问题:如何进行权限控制?

解决思路:

要求Input消息总是携带用户名密码,如果没有,拒绝执行。


如果不用CXF框架,由程序员可自己完成SOAP协议;

如果使用CXF框架,则是由框架定义SOAP协议,为了能够让程序员修改SOAP协议,CXF提供了拦截器。

(一)服务端拦截器:

方式一:Endpoint方式

HelloWorldService service = new HelloWorldServiceImpl();  
String address = "http://localhost:8080/hello";

EndpointImpl endpoint = (EndpointImpl)Endpoint.publish(address, service);
endpoint.getInInterceptors().add(new AuthInterceptor());

方式二:JaxWsServerFactoryBean方式

package com.skymr.hello.ws.pub;




import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

import com.skymr.hello.ws.HelloWorld;
import com.skymr.hello.ws.impl.HelloWorldBean;

public class ServerMain {

public static void main(String[] args){
HelloWorld hw = new HelloWorldBean();
JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
factory.setServiceClass(HelloWorldBean.class);
factory.setAddress("http://192.168.2.102/helloWorld");
factory.setServiceBean(hw);
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.create();
System.out.println("Web Service发布成功");
}
}

import org.apache.cxf.endpoint.Server;
import org.apache.cxf.frontend.ServerFactoryBean;
...

MyInterceptor myInterceptor = new MyInterceptor();

Server server = serverFactoryBean.create();
server.getEndpoint().getInInterceptor().add(myInterceptor);

方式三:注解

package com.skymr.hello.ws.impl;

import javax.jws.WebService;

import org.apache.cxf.interceptor.InInterceptors;
import org.apache.cxf.interceptor.OutInterceptors;

import com.skymr.hello.ws.HelloWorld;
@InInterceptors(interceptors={
"org.apache.cxf.interceptor.LoggingInInterceptor",
"com.skymr.hello.ws.interceptor.AuthInterceptor"
})
@OutInterceptors(interceptors={"org.apache.cxf.interceptor.LoggingOutInterceptor"})
@WebService(endpointInterface="com.skymr.hello.ws.HelloWorld",serviceName="helloWorldws")
public class HelloWorldBean implements HelloWorld{

public String sayHello(String name) {
return "你好"+name+",欢迎进入Web Service学习课程";
}


}

方式四:配置文件

<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- 导入cxf xml配置 -->
<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" />

<bean id="hello" class="com.skymr.hello.ws.impl.HelloWorldBean"/>
<bean id="userOperator" class="com.skymr.hello.ws.impl.UserOperatorBean"></bean>
<!-- 先导入命名空间和配置规范
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
-->
<!-- implementor
可以是类全名,这样的话它的实例是new的,不受spring容器管理,不好
可以引用spring容器里的bean
address
wsdl的相对路径,不能是绝对路径,绝对路径是随服务器地址变动的。
-->
<jaxws:endpoint id="helloWorld" implementor="#hello" address="/HelloWorld" />
<jaxws:endpoint id="userOp" implementor="#userOperator" address="/UserOperator" ></jaxws:endpoint>

<bean id="logInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
<cxf:bus>
<cxf:inInterceptors>
<ref bean="logInterceptor"/>
</cxf:inInterceptors>
</cxf:bus>
</beans>

这种方式的拦截器对所有的endpoint都起作用;

还可以这么配置:

    <jaxws:endpoint id="helloWorld" implementor="#hello" address="/HelloWorld">
<jaxws:inInterceptors>
<ref bean="logInterceptor"/>
<ref bean="authInterceptor"/>
<bean class=""></bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
<jaxws:endpoint id="userOp" implementor="#userOperator" address="/UserOperator"></jaxws:endpoint>
<!-- 自带的拦截器 -->
<bean id="logInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
<!-- 自定义拦截器,认证拦截 -->
<bean id="authInterceptor" class="com.skymr.hello.ws.interceptor.AuthInterceptor"></bean>


这样就只对当前的endpoint起作用了。

(二)客户端拦截器:

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
...

MyInterceptor myInterceptor = new MyInterceptor();
FooService client = ... ; // created from ClientProxyFactoryBean or generated JAX-WS client

//You could also call clientProxyFactroyBean.getInInterceptor().add(myInterceptor) to add the interceptor

Client cxfClient = ClientProxy.getClient(client);
cxfClient.getInInterceptors().add(myInterceptor);

// then you can call the service
client.doSomething();

(三)协议分析

为服务端添加LoggingInInterceptor和LoggingOutInterceptor后,可在控制台查看输入输出消息,并分析SOAP协议。

INFO: Inbound Message
----------------------------
ID: 1
Address: http://192.168.2.102/helloWorld?wsdl
Http-Method: GET
Content-Type:
Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[192.168.2.102], User-Agent=[Java/1.7.0_21]}
--------------------------------------
九月 12, 2015 9:51:15 上午 org.apache.cxf.services.helloWorldws.HelloWorldBeanPort.HelloWorld
INFO: Inbound Message
----------------------------
ID: 2
Address: http://192.168.2.102/helloWorld?wsdl=HelloWorld.wsdl
Http-Method: GET
Content-Type:
Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[192.168.2.102], User-Agent=[Java/1.7.0_21]}

前两个消息是请求WSDL的

下面的消息才是SOAP消息:

九月 12, 2015 9:51:15 上午 org.apache.cxf.services.helloWorldws.HelloWorldBeanPort.HelloWorld
INFO: Inbound Message
----------------------------
ID: 2
Address: http://192.168.2.102/helloWorld?wsdl=HelloWorld.wsdl
Http-Method: GET
Content-Type:
Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[192.168.2.102], User-Agent=[Java/1.7.0_21]}
--------------------------------------
九月 12, 2015 9:51:16 上午 org.apache.cxf.services.helloWorldws.HelloWorldBeanPort.HelloWorld
INFO: Inbound Message
----------------------------
ID: 3
Address: http://192.168.2.102/helloWorld
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[text/xml, multipart/related], connection=[keep-alive], Content-Length=[202], content-type=[text/xml; charset=UTF-8], Host=[192.168.2.102], SOAPAction=[""], User-Agent=[JAX-WS RI 2.2.4-b01]}
Payload: <?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:sayHello xmlns:ns2="http://ws.hello.skymr.com/"><arg0>skymr</arg0></ns2:sayHello></S:Body></S:Envelope>
--------------------------------------
九月 12, 2015 9:51:16 上午 org.apache.cxf.services.helloWorldws.HelloWorldBeanPort.HelloWorld
INFO: Outbound Message
---------------------------
--------------------------------------

sayHello inBound消息

<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:sayHello xmlns:ns2="http://ws.hello.skymr.com/">
<arg0>skymr</arg0>
</ns2:sayHello>
</S:Body>
</S:Envelope>

sayHello outBound消息

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:sayHelloResponse xmlns:ns2="http://ws.hello.skymr.com/">
<return>你好,skymr,欢迎进入Web Service学习课程</return>
</ns2:sayHelloResponse>
</soap:Body>
</soap:Envelope>

getAllUsers Inbound消息,没有参数标签

<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body><ns2:getAllUsers xmlns:ns2="http://ws.hello.skymr.com/"/>
</S:Body>
</S:Envelope>

getAllUsers OutBound消息

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getAllUsersResponse xmlns:ns2="http://ws.hello.skymr.com/">
<return>
<entryList>
<key>aaa</key>
<user>
<address>aaaAdress</address>
<id>1</id>
<password>aaa</password>
<userName>aaa</userName>
</user>
</entryList>
<entryList>
<key>ccc</key>
<user>
<address>cccAdress</address>
<id>3</id>
<password>ccc</password>
<userName>ccc</userName>
</user>
</entryList>
<entryList>
<key>bbb</key>
<user>
<address>bbbAdress</address>
<id>2</id>
<password>bbb</password>
<userName>bbb</userName>
</user>
</entryList>
</return>
</ns2:getAllUsersResponse>
</soap:Body>
</soap:Envelope>