还是接着上次的WebService接口设计的问题,为了提高易用性,需要在接收到消息的时候按照指定的xslt把接收到的soap消息转换为期望的格式。这样对客户端来说更加友好,但是服务器端的工作无疑是加大了呵呵。本着公司服务为先的理念,再难再险也要上啊。
参考了cxf自带的例子(configuration_interceptor),然后加上了自己需要的xslt转换功能,就这样大功告成了。整个过程基本上还是比较顺利的。
客户端发过来的soap消息为:
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
- <soap:Body>
- <ns2:process1 xmlns:ns2="http://ws.test/">
- <ns2:process>
- <version>0</version>
- <name>test</name>
- <category>website.test</category>
- <arg0><userName>username</userName><extension>extension</extension></arg0>
- </ns2:process>
- </ns2:process1>
- </soap:Body>
- </soap:Envelope>
转换使用的xslt内容如下:test.xsl
- <?xml version="1.0" encoding="UTF-8"?>
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
- <xsl:template match="/">
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
- <xsl:copy-of select="/soapenv:Envelope/soap:Header"/>
- <soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
- <ns2:process1 xmlns:ns2="http://ws.test/">
- <ns2:process>
- <!--把version字段在原来值的基础上,在前面加个1-->
- <version >1<xsl:value-of select="/soapenv:Envelope/soap:Body/ns2:process1/ns2:process/version"/></version>
- <xsl:copy-of select="/soapenv:Envelope/soap:Body/ns2:process1/ns2:process/name"/>
- <xsl:copy-of select="/soapenv:Envelope/soap:Body/ns2:process1/ns2:process/category"/>
- <xsl:copy-of select="/soapenv:Envelope/soap:Body/ns2:process1/ns2:process/arg0"/>
- </ns2:process>
- </ns2:process1>
- </soap:Body>
- </soapenv:Envelope>
- </xsl:template>
- </xsl:stylesheet>
可以看到,这里只是简单的将原有的version值前面加了个1然后就完事了。顺带着提一下,本人对xslt的了解不多,只是随便写了一个马马虎虎能用的,如果有高人看见了这个东东感到胃部不适的话请告诉我该怎么样写更好呵呵。谢了先
负责XSLT转换的类XSLTTransfomer.java:
- import java.io.File;
- import javax.xml.transform.Transformer;
- import javax.xml.transform.TransformerException;
- import javax.xml.transform.TransformerFactory;
- import javax.xml.transform.stream.StreamSource;
- import org.dom4j.Document;
- import org.dom4j.io.DocumentResult;
- import org.dom4j.io.DocumentSource;
- public class XSLTTransfomer {
- public static Document transformDocument(Document document, File styleSheet)
- throws TransformerException {
- TransformerFactory factory = TransformerFactory.newInstance();
- Transformer transformer = factory.newTransformer(new StreamSource(
- styleSheet));
- DocumentSource source = new DocumentSource(document);
- DocumentResult result = new DocumentResult();
- transformer.transform(source, result);
- Document transformedDoc = result.getDocument();
- return transformedDoc;
- }
- }
import java.io.File;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;
import org.dom4j.Document;
import org.dom4j.io.DocumentResult;
import org.dom4j.io.DocumentSource;
public class XSLTTransfomer {
public static Document transformDocument(Document document, File styleSheet)
throws TransformerException {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(
styleSheet));
DocumentSource source = new DocumentSource(document);
DocumentResult result = new DocumentResult();
transformer.transform(source, result);
Document transformedDoc = result.getDocument();
return transformedDoc;
}
}
CXF拦截器的类:XLSTInterceptor.java
- import java.io.ByteArrayInputStream;
- import java.io.File;
- import java.io.InputStream;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
- import org.apache.cxf.interceptor.Fault;
- import org.apache.cxf.message.Message;
- import org.apache.cxf.phase.AbstractPhaseInterceptor;
- import org.apache.cxf.phase.Phase;
- import org.dom4j.Document;
- import org.dom4j.io.SAXReader;
- import test.xml.XSLTTransfomer;
- public class XLSTInterceptor extends AbstractPhaseInterceptor<Message> {
- Log logger = LogFactory.getLog(XLSTInterceptor.class);
- public XLSTInterceptor() {
- //这里的设置相当要紧,阶段不同,拿到的内容会完全的不同。切记切记!!!
- super(Phase.PRE_STREAM);
- addBefore(SoapPreProtocolOutInterceptor.class.getName());
- }
- public void handleMessage(Message message) throws Fault {
- try {
- InputStream in = message.getContent(InputStream.class);
- SAXReader reader = new SAXReader();
- Document document = reader.read(in);
- //这里只是简单的从硬盘上把文件读进来了,具体实现的时候要按自己的需要来实现
- Document result = XSLTTransfomer.transformDocument(document, new File("E://soa//test.xsl"));
- message.setContent(InputStream.class,new ByteArrayInputStream(result.asXML().getBytes()));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import test.xml.XSLTTransfomer;
public class XLSTInterceptor extends AbstractPhaseInterceptor<Message> {
Log logger = LogFactory.getLog(XLSTInterceptor.class);
public XLSTInterceptor() {
//这里的设置相当要紧,阶段不同,拿到的内容会完全的不同。切记切记!!!
super(Phase.PRE_STREAM);
addBefore(SoapPreProtocolOutInterceptor.class.getName());
}
public void handleMessage(Message message) throws Fault {
try {
InputStream in = message.getContent(InputStream.class);
SAXReader reader = new SAXReader();
Document document = reader.read(in);
//这里只是简单的从硬盘上把文件读进来了,具体实现的时候要按自己的需要来实现
Document result = XSLTTransfomer.transformDocument(document, new File("E://soa//test.xsl"));
message.setContent(InputStream.class,new ByteArrayInputStream(result.asXML().getBytes()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
- super(Phase.PRE_STREAM);这一句相当要紧,一定要设置对了。不然肯定达不到你想要的效果。
super(Phase.PRE_STREAM);这一句相当要紧,一定要设置对了。不然肯定达不到你想要的效果。
Phase | Functions |
---|---|
RECEIVE | Transport level processing |
(PRE/USER/POST)_STREAM | Stream level processing/transformations |
READ | This is where header reading typically occurs. |
(PRE/USER/POST)_PROTOCOL | Protocol processing, such as JAX-WS SOAP handlers |
UNMARSHAL | Unmarshalling of the request |
(PRE/USER/POST)_LOGICAL | Processing of the umarshalled request |
PRE_INVOKE | Pre invocation actions |
INVOKE | Invocation of the service |
POST_INVOKE | Invocation of the outgoing chain if there is one |
上面是cxf官方文档里面对各个阶段的解释。大家可以参考一下。
怎么样设置cxf的拦截器就不提了,免得大家以为我在侮辱大家的智商呵呵。