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端的工程源码见附件。