CXF是支持对附件上传的协议MTOM。
MTOM(SOAP Message Transmission Optimization Mechanism)SOAP 消息传输优化机制,可以在SOAP 消息中发送二进制数据,与SAAJ 传输附件不同,MTOM需要XOP(XML-binary Optimized Packing)来传输二进制数据。MTOM 允许将消息中包含的大型数据元素外部化,并将其作为无任何特殊编码的二进制数据随消息一起传送。MTOM 消息会打包为多部分相关 MIME 序列,放在SOAP 消息中一起传送。因此你可以看出MTOM 并不是将附件转为Base64 编码,这样可以大大的提高性能,因为二进制文件转Base64 编码会非常庞大。
MTOM 方式中要传输的附件必须使用javax.activation.DataHandler 类,然后对象类型还要使用@javax.xml.binding.annotation.XmlMimeType 进行注解,标注这是一个附件类型的数据。
这里拿上传及下载用户的图像为例子,大致的说下CXF的MTOM协议对附件的支持
1、POJO对象类的处理
@XmlRootElement(name="User") @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name="User") public class User { @XmlElement(nillable=true) private Long id; @XmlElement(nillable=true) private String name; @XmlElement(nillable=true) private int age; @XmlMimeType("application/octet-stream") private DataHandler imageData; //人员的图像 public User() {} public User(Long id, String name, int age) { super(); this.id = id; this.name = name; this.age = age; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public DataHandler getImageData() { return imageData; } public void setImageData(DataHandler imageData) { this.imageData = imageData; } }
注意:图像的类型必须为DataHandle类型。这里标注imageData 是一个二进制文件(application/octet-stream),当然你也可以使用具体的MIME类型,譬如:image/jpg、image/gif 等,但你要考虑客户端是否有对应的类型(因为JAVA语言之外的客户端的特性未必是你完全了解的),而且javax.activation.*中的MIME 的相关API 可以完成MIME 类型的自动识别。这里你要注意的是必须在类上使用@XmlAccessorType(FIELD)注解,标注JAXB 在进行JAVA 对象与XML 之间进行转换时只关注字段,而不关注属性(getXXX()方法),否则发布Web 服务时会报出现了两个imageData 属性的错误
2、让你要在服务端和客户端分别启用MTOM 支持。可以与spring整合后,可以修改CXF的spring配置文件,来启用MTOM
t添加代码如下:
<jaxws:properties> <entry key="mtom-enabled" value="true" /> </jaxws:properties>
这段内容加到<jaxws:server … 、<jaxws:endpoint … 、<jaxws:client … 之间即可,例如:
<jaxws:endpoint id="helloWorld" implementor="#HelloWorldImpl" address="/HelloWorld" > <!-- 输入日志拦截器 --> <jaxws:inInterceptors> <ref bean="inMessageInterceptor"/> </jaxws:inInterceptors> <!-- 输出日志拦截器 --> <jaxws:outInterceptors> <ref bean="outMessageInterceptor"/> </jaxws:outInterceptors> <jaxws:properties> <entry key="mtom_enabled" value="true"></entry> </jaxws:properties> </jaxws:endpoint>
也可以使用Java Code 实现启用MTOM
3、具体实现
(1)HelloWorld.java接口添加如下两个方法
@WebMethod public User getUser(); @WebMethod public void updateUser(@WebParam(name="user")User user);
(2)HellWorld.java实现接口添加的两个方法
/** * <修改用户信息,包括上传用户的图像 * 创 建 人: XX * 创建时间: 2012-9-26 下午04:50:23 * @param user * @see [类、类#方法、类#成员] */ public void updateUser(User user){ System.out.println("姓名:"+user.getName()+",年龄:"+user.getAge()); DataHandler handler = user.getImageData(); try { InputStream is = handler.getInputStream(); OutputStream os = new FileOutputStream(new File("c:\\test11.jpg")); byte[] b = new byte[100000]; int bytesRead = 0; while ((bytesRead = is.read(b)) != -1) { os.write(b, 0, bytesRead); } os.flush(); os.close(); is.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 查询用户信息,包括以附件的形式返回用户的图像 * 创 建 人: XX * 创建时间: 2012-9-26 下午04:49:43 * @return * @see [类、类#方法、类#成员] */ public User getUser(){ User user =new User(11L,"李四",21); user.setImageData(new DataHandler(new FileDataSource(new File("d:"+File.separator)+"test.jpg"))); return user; }
4、测试
User user =client.getUser(); //修改用户信息,包括上传图像 user =new User(12L,"王五",23); DataSource source = new FileDataSource(new File("d:"+File.separator+"test.jpg")); user.setImageData(new DataHandler(source)); client.updateUser(user); //查询用户信息 InputStream is = user.getImageData().getDataSource().getInputStream(); OutputStream os = new FileOutputStream(new File("d:"+File.separator+"test11.jpg")); byte[] b = new byte[100000]; int bytesRead = 0; while ((bytesRead = is.read(b)) != -1) { os.write(b, 0, bytesRead); } os.close(); is.close();
附件中的Demo所需要的jar,请在【CXF之一 (与Spring整合)】中下载