CXF 拦截器的使用(转)

CXF 拦截器的使用

    在做SP短信管理平台开发时,需要连接电信ISAG短信网关,而电信ISAG短信网关提供WebService 短信提交服务,需要开发WebService客户端连接网关。开发时使用CXF技术为开发技术。    连接时,根据服务要求添加头信息,在头信息中增加验证信息,比如用户ID,加密密码,还有其他业务信息,类似下面的Demo代码:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Header>

<tns:RequestSOAPHeader

xmlns:tns="http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1">

<tns:usernamexmlns="http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1">

test_username

</tns:username>

<tns:passwordxmlns="http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1">

b936443545b5061eceff663eadd8e91d

</tns:password>

<tns:timeStampxmlns="http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1">

1013135742

</tns:timeStamp>

</tns:RequestSOAPHeader>

</soap:Header>

<soap:Body>

<!--省略-->

</soap:Body>

</soap:Envelope>

而SoapHeader信息使用拦截器,可以很容易添加,下面的Sample代码添加头信息:

import java.security.NoSuchAlgorithmException;

importjava.text.SimpleDateFormat;

importjava.util.Date;

import java.util.List;

import javax.xml.namespace.QName;

import org.apache.cxf.binding.soap.SoapHeader;

importorg.apache.cxf.binding.soap.SoapMessage;

importorg.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;

importorg.apache.cxf.headers.Header;

importorg.apache.cxf.helpers.DOMUtils;

importorg.apache.cxf.interceptor.Fault;

importorg.apache.cxf.phase.Phase;

importorg.w3c.dom.Document;

import org.w3c.dom.Element;

public class SampleHeaderInterceptor extends AbstractSoapInterceptor {

    private static String namespaceURI = "http://www.chinatelecom.com.cn/schema/ctcc/common/v2_1";

    public SampleHeaderInterceptor() {

super(Phase.WRITE);

    }

    public void handleMessage(SoapMessage message) throws Fault {

        String timeStampStr = df.format(new Date());        String spPasswordStr = getSpPassword(System.getProperty("spId", ""), System.getProperty("spKey", "") );

        QName qName = new QName("RequestSOAPHeader");

        Document document = DOMUtils.createDocument();

        Element spId = document.createElement("tns:spId");        spId.setTextContent(System.getProperty("spId", ""));

        Element spPassword = document.createElement("tns:spPassword");        spPassword.setTextContent(spPasswordStr);

        Element root = document.createElementNS(namespaceURI, "tns:RequestSOAPHeader");

root.appendChild(spId);

        root.appendChild(spPassword);

        SoapHeader header = new SoapHeader(qName, root);

List<Header>headers=message.getHeaders();

headers.add(header);

    }

    private static String getSpPassword(String spId, String key) {

try{

returnMD5.md5((spId+key).getBytes());

}catch(NoSuchAlgorithmExceptione){

thrownewRuntimeException(e.getMessage(),e);

}

    }

}

使用时,在配置文件中添加Out 拦截器,配置文件如下:

<beanid="clientFactory"class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">

<propertyname="serviceClass"value="sample.service.SendSms"/>

<propertyname="address"value="http://localhost:8080/service/sms/SendSmsService"/>

<propertyname="outInterceptors">

<list>

<beanclass="sample.client.SampleSOAPHeaderInterceptor"/>

</list>

</property>

    </bean>

也可以在代码中直接添加拦截器:

JaxWsProxyFactoryBeanfactory=newJaxWsProxyFactoryBean();

factory.setAddress("http://localhost:8080/service/sms/SendSmsService");

factory.setServiceClass(SendSms.class);

        factory.getOutInterceptors().add(new sample.client.SampleSOAPHeaderInterceptor());

这样就可以完成Out拦截器了。但接下来就遇到问题了,短信上行(回复),还有状态报告返回都会添加回访用户名和密码,(类似提交短信也要进行用户名密码验证,否则我们的接收平台会收到很多可能是别人无效的信息),于是获取用户名和密码的拦截器也需要开发,但是在开发读取拦截器时都无法获取头信息,弄了快一天都行,而任务要求时间紧,到网上Google 下,使用了Handler 处理机制进行了处理,代码如下:

import javax.xml.soap.SOAPException;

importjavax.xml.soap.SOAPHeader;

importjavax.xml.soap.SOAPMessage;

importjavax.xml.ws.handler.Handler;

importjavax.xml.ws.handler.MessageContext;

import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.apache.log4j.Logger;

importorg.w3c.dom.Node;

import org.w3c.dom.NodeList;

public class SampleSoapAuthHandler implements Handler<SOAPMessageContext> {

    private static Logger log = Logger.getLogger(SampleSoapAuthHandler.class);

privateStringspRevId;

    private String spRevpassword;

    public void close(MessageContext messageContext) {

log.info("SampleSoapAuthHandlerclose");

    }

    public boolean handleFault(SOAPMessageContext messageContext) {

log.error("handleFaulterror");

returnfalse;

    }

    public boolean handleMessage(SOAPMessageContext messageContext) {

SOAPMessagemessage=messageContext.getMessage();

BooleanoutboundProperty=(Boolean)messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

if(!outboundProperty){//InBoundMessage,

StringspRevid="";

StringspRevpassword="";

try{

SOAPHeadersoapHeader=message.getSOAPHeader();

NodeListnodeList=soapHeader.getChildNodes();

for(inti=0;i<nodeList.getLength();i++){

NodenodeAuth=nodeList.item(i);

if(nodeAuth.getNodeType()==Node.ELEMENT_NODE&&"SampleSOAPHeader".equals(nodeAuth.getLocalName())){

for(Nodenode=nodeAuth.getFirstChild();node!=null;node=node.getNextSibling()){

if(node.getNodeType()==Node.ELEMENT_NODE){

if("spRevId".equals(node.getLocalName())&&node.getFirstChild()!=null){

spRevId=node.getFirstChild().getTextContent();

}elseif("spRevpassword".equals(node.getLocalName())&&node.getFirstChild()!=null){

spRevpassword=node.getFirstChild().getTextContent();

}

}

}

}

                }

                boolean ret = validUserAndPswd(spRevId, spRevpassword);

if(!ret){

log.warn("错误的反调用户名和密码,spRevId:"+spRevId+",spRevPassword:"+spRevpassword);

returnret;

}

log.info("收到信息,验证通过");

System.setProperty("mo:linkId",linkId);

                return ret;

            } catch (SOAPException e) {

log.error("解析异常,SOAPException:"+e,e);

}

}

returnfalse;

}

privatebooleanvalidUserAndPswd(StringspRevId,StringspRevpassword){

if(this.spRevId==null&&this.spRevpassword==null)

returntrue;

if(this.spRevId==null&&this.spRevpassword!=null)

returnthis.spRevpassword.equals(spRevpassword);

if(this.spRevId!=null&&this.spRevpassword==null)

returnthis.spRevId.equals(spRevId);

returnthis.spRevId.equals(spRevId)&&this.spRevpassword.equals(spRevpassword);

    }

    public void setSpRevId(String spRevId) {

this.spRevId=spRevId;

    }

    public void setSpRevpassword(String spRevpassword) {

this.spRevpassword=spRevpassword;

    }

    }

上述代码部分来自google 搜索到的,在此谢谢原作者。

添加处理器配置文件:

<beanid="isagReceiver"class="sample.SampleReceiver"singleton="false">

<propertyname="address"value="http://localhost:8080/service/MessageService"/>

<propertyname="handlers">

<list>

<refbean="authHandler"/>

</list>

</property>

</bean>

<beanid="authHandler"class="sample.SampleSoapAuthHandler"singleton="true">

<propertyname="spRevId"value="username"></property>

<propertyname="spRevpassword"value="pawd"></property>

</bean>

因为自定义的处理器实现Handler接口,所以代码中只需要把自己的业务处理放在handler方法中即可,处理器链会自动调用。

终于可以完成任务了。

之后,有了空闲时间,对cxf的拦截器还是决定各种方式进行测试,今天终于得到满意的结果,把拦截验证的拦截器代码贴出来,如果有更好的建议,可以交流下:

import javax.xml.soap.SOAPException;

importjavax.xml.soap.SOAPHeader;

import javax.xml.soap.SOAPMessage;

import org.apache.cxf.binding.soap.SoapMessage;

importorg.apache.cxf.binding.soap.saaj.SAAJInInterceptor;

importorg.apache.cxf.interceptor.Fault;

importorg.apache.cxf.phase.AbstractPhaseInterceptor;

importorg.apache.cxf.phase.Phase;

importorg.w3c.dom.Node;

import org.w3c.dom.NodeList;

public class SpInfoInterceptor extends AbstractPhaseInterceptor<SoapMessage> {    private SAAJInInterceptor inInterceptor = new SAAJInInterceptor();

    public SampleInterceptor() {

super(Phase.PRE_PROTOCOL);

getAfter().add(SAAJInInterceptor.class.getName());//这一步好像是必须的,与inInterceptor.handleMessage(message);关联

    }

    public void handleMessage(SoapMessage message) throws Fault {

//此处注意是javax.xml.soap.SOAPMessage而不是org.apache.cxf.binding.soap.SoapMessage

//虽然方法参数是SoapMessage

SOAPMessagesm=message.getContent(SOAPMessage.class);

if(sm==null){

inInterceptor.handleMessage(message);

sm=message.getContent(SOAPMessage.class);

}

SOAPHeaderheader=null;

try{

header=sm.getSOAPHeader();

}catch(SOAPExceptione){

e.printStackTrace();

}

if(header==null){

return;

        }

        //获取<soap:Header ..><tns:RequestSOAPHeader ...> ... </tns:RequestSOAPHeader></soap:Header>中指定的标签的内容

NodeListnodeList=header.getElementsByTagName("tns:RequestSOAPHeader");

for(inti=0;i<nodeList.getLength();i++){

NodenodeAuth=nodeList.item(i);

for(Nodenode=nodeAuth.getFirstChild();node!=null;node=node.getNextSibling()){

if(node.getNodeType()==Node.ELEMENT_NODE){

//if("username".equals(node.getLocalName())&&node.getFirstChild()!=null){

//username=node.getFirstChild().getTextContent();//获取<soap:Header>中的username参数的值

//}

if(node.getLocalName()!=null&&node.getFirstChild()!=null)

System.out.println(node.getLocalName()+"<===========>"+node.getFirstChild().getTextContent());

}

}

//}

}

    }

}

上述部分代码也是参考网上代码,谢谢原作者。代码中省略的日志信息的输出,可以自行添加。

至此, cxf 添加头信息和验证信息的两种拦截器都完成了,其他类似的功能的拦截器可以相互参考,其他的如附件的拦截器有空再补充了,今天就写到这里。

文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/java/javajs/20100106/186733.html

相关推荐