带有附件的SOAP分析 带有附件的SOAP信息并没有给SOAP增加新的特征。 确切的说,它定义了如何利用在SOAP信息中MIME类型来定义附件, 并且还定义了如何引用在SOAP体(SOAP Body)中的那些附件。
MIME类型的复合块/关联(multipart/related)特性能定义由多部分组成的一个文档。带有附件的SOAP信息一定要符合这样的复合块/关联(multipart/related)的MIME类型。下面的例子展示了一个复合块/关联的 SOAP 信息,它被绑定到到 HTTP 协议,带有两个附件:
POST /propertyListing HTTP/1.1
Host: www.realproperties.com
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml; start="
"
Content-Length: NNNN
--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID:
xmlns:realProperty="http://schemas.realhouses.com/listingSubmission";>
Really Nice Homes, Inc.
Add
1234 Main St
Pleasantville
CA
94323
250000
--MIME_boundary
Content-Type: image/jpeg
Content-ID:
....JPEG DATA .....
--MIME_boundary
Content-Type: image/jpeg
Content-ID:
....JPEG DATA .....
--MIME_boundary--
上述的复合块信息包含一系列的MIME头和相关的数据。文件的底层是SOAP体(SOAP Body)。 因为SOAP体只包含XML数据,整个信息的MIME类型是本文/xml(text/xml)类型 。 在SOAP封套(SOAP envelope)后面是二个附件,每个附件都包含一个连同信息一起发送的图像文件。
用内容ID(Content ID)来识别每一个附件。W3C 备忘录允许用内容ID或内容位置来引用附件,但是它优先选择前者。这样的一个内容ID作为统一资源标志符URI(Uniform Resource Identifier)引用给附件;SOAP 1.1的编码规则定义了如何通过URI来引用SOAP信息里面的任何资源,不仅仅是引用XML( 参考SOAP1.1第5节资源)。当SOAP处理机处理信息时,它会解析这些URI引用。在上述的例子中,SOAP处理器把元素frontImage关联到内容ID为[email protected]的数据段中。
创建并发送带有附件的SOAP信息
SAAJ能让你创建并编辑SOAP信息的任何部份, 包括附件。 大多数的SAAJ以抽象类和接口为基础,所以每个供应商都能实现它自己的SAAJ产品。Sun Microsystems公司的参考实现附在JWSDP包(Java Web Services Developer Pack)中。
因为SOAP信息只是XML文档的一种特殊形式,JAAS在DOM(document.nbspObject Model)API的基础上处理XML。大多数的SOAP信息组件派生自 avax.xml.soap.Node接口, 而这个接口又是org.w3c.dom.Node的子类。SAAJ继承了Node来添加SOAP样式的结构。 举例来说,这个特别的Node, SOAPElement,代表了一个SOAP信息元素。
SAAJ依赖于接口和抽象类的直接结果是:你要通过工厂方法(factory methods)来完成大多数与SOAP相关的工作。 要把你的程序链接到SAAJ API,你首先要创建一个来自工厂方法SOAPConnectionFactory的链接SOAPConnection。要创建和编辑SOAP信息,你可以初始化MessageFactory和SOAPFactory。MessageFactory能让你产生SOAP信息,而 SOAPFactory则提供方法产生SOAP信息的各个部份:
SOAPConnectionFactory spConFactory = SOAPConnectionFactory.newInstance();
SOAPConnection con = spConFactory.createConnection();
SOAPFactory soapFactory = SOAPFactory.newInstance();
把这些工具用在适当的位置,你就可以创建一个 SOAP 信息,在前面的例子中,来自房产代理的客户可以使用这些信息发送项目表更新给一个网站入口。
SAAJ 提供了几个方法来产生一个新的 SOAP 信息。 下面例子演示了用最简单的方法来创建一个有封套(envelope)的空白SOAP信息,这个封套还带有头(heade)和体(body)。如果你在这个信息中不需要SOAP头(SOAP header),那么你可以将这个元素从信息中删除:
SOAPMessage message = factory.createMessage();
SOAPHeader header = message.getSOAPHeader();
header.detachNode();
把 XML 结构加入信息也是直接了当的:
SOAPBody body = message.getSOAPBody();
Name listingElementName = soapFactory.createName(
"propertyListing", "realProperty",
"http://schemas.realhouses.com/listingSubmission";);
SOAPBodyElement listingElement = body.addBodyElement(listingElementName);
Name attname = soapFactory.createName("id");
listingElement.addAttribute(attname, "property_1234");
SOAPElement listingAgency = listingElement.addChildElement("listingAgency");
listingAgency.addTextNode("Really Nice Homes, Inc");
SOAPElement listingType = listingElement.addChildElement("listingType");
listingType.addTextNode("add");
SOAPElement propertyAddress = listingElement.addChildElement("propertyAddress");
SOAPElement street = propertyAddress.addChildElement("street");
street.addTextNode("1234 Main St");
SOAPElement city = propertyAddress.addChildElement("city");
city.addTextNode("Pleasantville");
SOAPElement state = propertyAddress.addChildElement("state");
state.addTextNode("CA");
SOAPElement zip = propertyAddress.addChildElement("zip");
zip.addTextNode("94521");
SOAPElement listPrice = listingElement.addChildElement("listPrice");
listPrice.addTextNode("25000");
注意,你要把属性的ID作为一个参数加入到属性列表元素(propertyListing)中。 更进一步的是,你要用QName, 或namespace来限定propertyListing元素。
你可以用几种方法把附件加入到SOAP信息中。 在这一个例子中,你首先要创建元素来指示列表属性的背景图片和前景图片。它们每个都有一个href属性指明附件的内容ID:
String frontImageID = "[email protected]";
SOAPElement frontImRef = listingElement.addChildElement("frontImage");
Name hrefAttName = soapFactory.createName("href");
frontImRef.addAttribute(hrefAttName, frontImageID);
String interiorID = "[email protected]";
SOAPElement interiorImRef = listingElement.addChildElement("interiorImage");
interiorImRef.addAttribute(hrefAttName, interiorID);
要方便地把需要的图像文件附加在信息中,可以使用JavaBeans Activation Framework架构里面的javax.activation.DataHandler对象。DataHandler能自动地检测传递给它的数据类型,而且它还能自动地分配适当的MIME类型给附件:
URL url = new URL("file&:///export/files/pic1.jpg?http://www.xvna.com");
DataHandler dataHandler = new DataHandler(url);
AttachmentPart att = message.createAttachmentPart(dataHandler);
att.setContentId(frontImageID);
message.addAttachmentPart(att);
另一种方法,你可以把一个对象,连同正确的MIME类型一起,传递到createAttachmentPart()方法里。这个方法跟第一个方法类似。在内部,SAAJ将会寻找处理器DataContentHandler 来处理这个MIME类型。 如果它不能找一个合适的处理器,createAttachmentPart() 方法将会抛出一个IllegalArgumentException异常:
URL url2 = new URL("file&:///export/files/pic2.jpg?http://www.xvna.com");
Image im = Toolkit.getDefaultToolkit().createImage(url2);
AttachmentPart att2 = message.createAttachmentPart(im, "image/jpeg");
att2.setContentId(interiorID);
message.addAttachmentPart(att2);
这个方法的缺点集中在:它依赖于AWT中示例UI(用户界面user interface)相关的类。 在一些粗心的(服务器)设置中,这些库并没有被正确的设置。
不管你选择什么方法来产生附件,上述的代码表示了在第一个列表里面的SOAP信息。 既然这只是一个简