CXF服务端代码:
1、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"> <!-- Spring Config Location --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/beans.xml</param-value> </context-param> <!-- Spring ContextLoaderListener --> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- Apache CXFServlet --> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- CXFServlet Mapping --> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/service/*</url-pattern> </servlet-mapping> </web-app>
2、beans.xml配置, 在beans.xml中配置服务端的拦截器interceptor.AuthenticationInterceptor,拦截器需要
继承AbstractPhaseInterceptor
<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-2.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- Import Apache CXF Bean Definition --> <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" /> <!-- serviceClass指定接口 --> <jaxws:server id="hello" serviceClass="service.SampleWebService" address="/HelloWorld"> <jaxws:serviceBean> <bean class="service.SampleWebService" /> </jaxws:serviceBean> <jaxws:inInterceptors> <bean class="interceptor.AuthenticationInterceptor"> <property name="username" value="admin" /> <property name="password" value="admin" /> </bean> </jaxws:inInterceptors> </jaxws:server> </beans>
3、在拦截器中对用户身份进行验证
package interceptor;
import java.util.List;
import javax.xml.soap.SOAPException;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Node;
public class AuthenticationInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private String username;
private String password;
public AuthenticationInterceptor() {
// 指定该拦截器在哪个阶段被激发
super(Phase.PRE_INVOKE);
}
public void handleMessage(SoapMessage msg) throws Fault {
List<Header> headers = msg.getHeaders();
if (null == headers || headers.size() < 1) {
throw new Fault(new SOAPException("SOAPHeader格式错误"));
}
for (Header header : headers) {
Node root = (Node) header.getObject();
if("Authentication".equals(root.getNodeName())){
Node userNode = root.getFirstChild();
Node passwordNode = root.getLastChild();
if(userNode == null || passwordNode == null){
throw new Fault(new SOAPException("SOAPHeader需要包含Username和Password节点"));
}
if(!userNode.getNodeName().equals("Username") || !passwordNode.getNodeName().equals("Password")){
throw new Fault(new SOAPException("SOAPHeader需要包含Username和Password节点"));
}
if(username.equals(userNode.getTextContent()) && password.equals(passwordNode.getTextContent())){
System.out.println("认证通过");
}
else{
throw new Fault(new SOAPException("用户名或密码错误"));
}
}
else{
throw new Fault(new SOAPException("SOAPHeader需要包含Authentication节点"));
}
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
4、服务接口,CXF可以直接发布JavaBean,只需要一个@WebService注解
package service;
import javax.jws.WebService;
@WebService
public class SampleWebService{
public String sayHello(String name) {
return "Hello, "+name;
}
public String sayHi(String name) {
return "Hi, "+name;
}
}
5、Axis客户端:
/**
* <soapenv:Header>
* <Authentication
* soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next"
* soapenv:mustUnderstand="0"
* xmlns="">
* <Username>admin</Username>
* <Password>admin</Password>
* </Authentication>
* </soapenv:Header>
* @param user
* @param password
*/
public static void authentication(String user, String password){
try {
Call call = (Call)new Service().createCall();
call.setTargetEndpointAddress("http://localhost:8080/ws/service/HelloWorld");
String namespace = "";//命名空间
SOAPHeaderElement header = new SOAPHeaderElement(namespace,"Authentication");
header.setPrefix("");//前缀
header.addChildElement("Username").addTextNode(user);
header.addChildElement("Password").addTextNode(password);
call.addHeader(header);
Object obj = call.invoke("sayHi", new String[]{"sam"});
System.out.println(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
在axis的jar包中还提供了一个tcp_moniter,可以用来拦截soap消息,便于debug。
可以使用java -Djava.ext.dirs=lib org.apache.axis.utils.tcpmon来启动,启动前要先将axis的jar包都放在lib目录下,然后在lib的同级目录中建一个bat脚本,脚本中写:java -Djava.ext.dirs=lib org.apache.axis.utils.tcpmon。
这样双击bat脚本就可以启动tcp_moniter了。
tcp_moniter界面:
cxf_server端和axis_client端的工程源码见附件。