最近调研了对webservice实现比较好的框架,觉得Apache的CXF不错.
做了一个简单的技术预研,其中主要包括2方面:1.与Spring的集成,2.安全性方面即WS-Security
首先与Spring的集成可以通过ContextLoaderListener去装配bean
在WS-Security方面可以与WSS4J集成
WSS4J支持多种模式:
XML Security:1.XML Signature 2.XML Encryption
Tokens:1.Username Tokens 2.Timestamps 3.SAML Tokens
做个了小的集成demo项目,项目的包结构如下:
服务端部分
1. 下面是web.xml的配置,主要配置cxf核心cxfServlet以及Spring的ContextLoaderListener
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID"
version="2.5">
<display-name>CXF_Spring_INTG_Test</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:cxf.xml
</param-value>
</context-param>
<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>/ws/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
<!-- configuration unique Web app root for log4j -->
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>cxf.root</param-value>
</context-param>
</web-app>
2. cxf.xml配置
主要包括两部分:wss4j安全验证及webservice的管理
<?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">
<bean id="saaj" class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<bean id="wss4j" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" >
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
<entry key="passwordCallbackClass" value="com.test.ws.handler.ServerWsAuthHandler" />
</map>
</constructor-arg>
</bean>
<jaxws:endpoint implementor="com.test.service.ITestWSImpl" address="/TestWS">
<jaxws:inInterceptors>
<ref bean="saaj" />
<ref bean="wss4j" />
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
3. Server端进行WSS4J处理的Handler ServerWsAuthHandler,做了一个简单的密码为明文的验证
public class ServerWsAuthHandler implements CallbackHandler {
private String passwd = "test";
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
pc.setPassword(passwd);
}
}
}
4. WebService的接口ITestWS.java
package com.test.service;
import javax.jws.WebService;
@WebService
public interface ITestWS {
public String sayHello(String name);
}
5. WebService的实现类ITestWSImpl.java
package com.test.service;
import javax.jws.WebService;
@WebService(endpointInterface="com.test.service.ITestWS"
,serviceName="ITestWS")
public class ITestWSImpl implements ITestWS{
@Override
public String sayHello(String name) {
return "Hello "+name;
}
}
客户端部分
1. Client端进行WSS4J处理的Handler ClientWsAuthHandler.java
package com.test.ws.handler;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
public class ClientWsAuthHandler implements CallbackHandler {
private String passwd = "test";
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
pc.setPassword(passwd);
}
}
}
2. Client端进行调用的测试类ClientTest
public class ClientTest {
private static List list = new ArrayList();
static{
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put(WSHandlerConstants.ACTION,WSHandlerConstants.USERNAME_TOKEN);
outProps.put(WSHandlerConstants.USER, "admin");
//密码类型明文测试使用,还有很多如WSConstants.PASSWORD_DIGEST
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
//outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PASSWORD_DIGEST);
// 指定在调用远程ws之前触发的回调函数ClientWsAuthHandler,其实类似于一个拦截器
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,ClientWsAuthHandler.class.getName());
// 添加cxf安全验证拦截器
list.add(new SAAJOutInterceptor());
list.add(new WSS4JOutInterceptor(outProps));
}
public static void main(String[] args){
//客户端采用动态创建及调用的方式
JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();
Client client =factory.createClient("http://localhost:8080/Spring_CXF/ws/TestWS?wsdl");
client.getOutInterceptors().addAll(list);
try {
String name = "Tom";
Object[] param = new Object[]{name};
Object[] obj =client.invoke("sayHello",param);
String rtnStr = (String) obj[0];
System.out.println(rtnStr);
} catch (Exception e) {
e.printStackTrace();
}
}
}