• 博客分类:
  • WebService

一、几个相关的概念

1、MTOM基础概念

MTOM(Message Transmission Optimization Mechanism)消息优化传输机制。

它提出的模型适用于大量数据的交互情况。针对Base64编码情况带来的开销提出的解决方案。当数据量小的时候,SOAP依然使用XML进行消息的传递。

消息传输优化机制 (MTOM) 标准允许将消息中包含的大型数据元素外部化,并将其作为无任何特殊编码的二进制数据随消息一起传送。MTOM 消息会打包为多部分/相关 MIME 序列,放在SOAP 消息中一起传送。

但是在大量数据情况下,如果数据依然进行Base64编码,会带来33%的额外开销,这样的情况对于大量数据交换的情况是无法容忍的。MTOM 就是针对SOAP 消息传输的基础上提出的改进办法。对于大量数据的传递,不会进行进行Base64编码,而是直接以附件的二进制原始数据的形式封装在SOAP消息的 MIME 部分,进行传输。SOAP 消息通过指向随其发送的 MIME 部分来引用二进制内容,另外包括SOAP基本的XML 数据,这些还是Base64编码。因为此模型与简单邮件协议SMTP 模型基本一致。

MTOM通过简化大量数据的编码过程,从而提高数据的处理效率。因为SOAP消息等必要的信息,MTOM 也有一些必要的开销。MTOM仅在二进制数据元素的大小超过大约 1 KB 时,才能体现出其优势。

什么是BASE64编码、MTOM消息优化传输机制、MIME。这些对于我们理解MTOM消息优化传输机制问题非常的必要。

2、BASE64编码

BASE64编码 的原理很简单,其方法是,将输入数据流每次取6 bit(每bit代表1位二进制),不足6bit的补0,这样,每3个8位字节将编码为4个6位字节(3×8 → 4×6);不满4个字节的以“=”填充。其实这4个六位字节 仍然是8位,只不过高两位被设置为0。当一个字节只有6位有效时,它的取值空间为0 到 2的6次方减1 即63,也就是说被转换的Base64编码的每一个编码的取值空间为(0~63)。

  这样就可以将3个8位字节,转换为4个字节,这4个转换的字节都可以映射到字符中。也即数据都可以使用字符编码代替。 因为转换后的字符串要比原来的多一个字节,长1/3。因此编码后的数据长度增加到4/3倍。这里也是为什么使用SOAP消息效率比MTOM低的原因。因为 SOAP使用XML语言进行消息传递,XML是基于BASE64编码的语言。

3、MIME

MIME表示多用途Internet邮件扩允协议。MIME扩允了基本的面向文本的Internet邮件系统,以便可以在消息中包含二进制附件。MIME(Multipurpose Internet Mail Extentions),一般译作"多用途的网络邮件扩充协议"。顾名思义,它可以传送多媒体文件。 MIME (Multipurpose Internet Mail Extensions,多目的Internet邮件扩展)是创建用于电子邮件交换,网络文档,及企业网和Internet上的其他应用程序中的文件格式的规范。

二、MTOM之旅

1、POJO

Java代码  
  1. package org.wy.pojo;
  2. import javax.activation.DataHandler;
  3. import javax.xml.bind.annotation.XmlAccessType;
  4. import javax.xml.bind.annotation.XmlAccessorType;
  5. import javax.xml.bind.annotation.XmlMimeType;
  6. import javax.xml.bind.annotation.XmlRootElement;
  7. import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
  8. @XmlRootElement
  9. @XmlAccessorType(XmlAccessType.FIELD)
  10. public class User {
  11. private String name = "wy";
  12. private String sex = "man";
  13. public int age = 20;
  14. //private Address address;
  15. //注这是一个附件类型的数据
  16. @XmlMimeType("application/octet-stream")
  17. private DataHandler dataHandler;
  18. public String getName() {
  19. return name;
  20. }
  21. public void setName(String name) {
  22. this.name = name;
  23. }
  24. //处理复杂的对象
  25. /*@XmlJavaTypeAdapter(AddressAdapter.class)
  26. public Address getAddress() {
  27. return address;
  28. }
  29. public void setAddress(Address address) {
  30. this.address = address;
  31. }*/
  32. public DataHandler getDataHandler() {
  33. return dataHandler;
  34. }
  35. public void setDataHandler(DataHandler dataHandler) {
  36. this.dataHandler = dataHandler;
  37. }
  38. }

MTOM 方式中要传输的附件必须使用javax.activation.DataHandler 类,还要注意必须在类上使用@XmlAccessorType(XmlAccessType.FIELD)注解,标注JAXB 在进行JAVA 对象与XML 之间进行转换时只关注字段,而不关注属性(getXXX()方法)。

然后使用@XmlMimeType 注解标注这是一个附件类型的数据,这里我们标注imageData 是一个二进制文件,当然你也可以使用具体的MIME类型,譬如:image/jpg、image/gif 等,但要考虑到客户端是否支持。

2、接口类

Java代码  
  1. package org.wy.service;
  2. import javax.jws.WebService;
  3. import javax.jws.soap.SOAPBinding;
  4. import javax.xml.ws.soap.MTOM;
  5. import org.wy.pojo.User;
  6. @WebService(name="userService") //name属性标注在接口类上,可以指定wsdl中接口名称,也就是生成的客户端代码中接口类的名字。
  7. @SOAPBinding(style = SOAPBinding.Style.RPC) //指定SOAP消息样式
  8. @MTOM  //开启MTOM功能
  9. public interface IUserService {
  10. public User getUser();
  11. }

@MTOM注解用于开启MTOM功能。

@WebService注解中的name属性标注在接口类上,可以指定wsdl中接口名称,也就是生成的客户端代码中接口类的名字。

@SOAPBinding(style = SOAPBinding.Style.RPC)指定SOAP消息样式,有两个枚举值:SOAPBinding.Style.DOCUMENT(默认)和 SOAPBinding.Style.RPC,可以对比这两种方式生成的wsdl会有所不同,而且生成的客户端代码也会有所不同。

实现类:

Java代码  
  1. package org.wy.service.impl;
  2. import java.io.File;
  3. import javax.activation.DataHandler;
  4. import javax.activation.FileDataSource;
  5. import javax.jws.WebService;
  6. import org.wy.pojo.User;
  7. import org.wy.service.IUserService;
  8. /**
  9. *
  10. * @author wy
  11. *
  12. */
  13. @WebService
  14. public class UserServiceImpl implements IUserService{
  15. public User getUser()
  16. {
  17. User user = new User();
  18. user.setName("wy");
  19. user.setDataHandler(new DataHandler(new FileDataSource(new File("D:\\resume\\logo.gif"))));
  20. return user;
  21. }
  22. }

3、服务端配置

applicationContext-cxf.xml

Xml代码  
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:jaxws="http://cxf.apache.org/jaxws"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  8. http://cxf.apache.org/jaxws
  9. http://cxf.apache.org/schemas/jaxws.xsd">
  10. <!-- 导入资源 -->
  11. <import resource="classpath:META-INF/cxf/cxf.xml" />
  12. <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
  13. <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
  14. <!-- <jaxws:endpoint implementor="org.wy.service.impl.UserServiceImpl" address="/UserService"/> -->
  15. <!-- 使用bean -->
  16. <jaxws:endpoint implementor="#userService" address="/UserService" />
  17. </beans>

在命令行键入“wsimport -p org.wy.client -keep  http://localhost:8080/WebServiceCXF/services/UserService?wsdl”生成客户端代码,拷贝到工程相应文件夹

当然也可以使用CXF中的wsdl2java命令生成客户端。

这时,就可以调用这个服务了:

测试类:

Java代码  
  1. package org.wy.jdkclienttest;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import javax.activation.DataHandler;
  6. import org.wy.jdkclient.User;
  7. import org.wy.jdkclient.UserServiceImplService;
  8. /**
  9. *
  10. * @author wy
  11. *
  12. */
  13. public class Test {
  14. public static void main(String[] args) throws IOException {
  15. UserServiceImplService userService = new UserServiceImplService();
  16. User user = userService.getUserServiceImplPort().getUser();
  17. String name = user.getName();
  18. int age = user.getAge();
  19. String sex = user.getSex();
  20. System.out.println(name+"\r\n"+age+"\r\n"+sex);
  21. //输出传递过来的文件
  22. DataHandler dataHandler = user.getDataHandler();
  23. String fileName = dataHandler.getName();
  24. String fileType = dataHandler.getContentType();
  25. Object content = dataHandler.getContent();
  26. System.out.println(fileName+"\r\n"+fileType+"\r\n"+content.toString());
  27. //Streaming Mode
  28. InputStream is = dataHandler.getInputStream();
  29. FileOutputStream fos = new FileOutputStream("D:\\logo.gif");
  30. byte[] bytes = new byte[2048];
  31. int len = 0;
  32. while((len = is.read(bytes))!=-1){
  33. fos.write(bytes, 0, len);
  34. }
  35. fos.flush();
  36. fos.close();
  37. is.close();
  38. }
  39. }

来看下结果:

Java代码  
  1. 2011-12-25 14:03:49 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL
  2. 信息: Creating Service {http://impl.service.wy.org/}UserServiceImplService from WSDL: http://localhost:8080/WebServiceCXF/services/UserService?wsdl
  3. name= wy
  4. age= 20
  5. sex= man
  6. fileName= null
  7. fileType= image/gif
  8. fileContent= org.apache.cxf.attachment.DelegatingInputStream@11e1bbf

附件中是上一篇和本篇的代码。

WebService CXF --- 传输文件MTOM相关推荐

  1. CXF之七 传输文件

    CXF的文件传输通过MTOM实现.MTOM(SOAP Message Transmission Optimization Mechanism)SOAP消息传输优化机制,可以在SOAP消息中发送二进制数 ...

  2. WebService CXF系列: SpringBoot同一个项目中集成JaxWS和JaxRS

    WebService CXF系列: SpringBoot同一个项目中集成JaxWS和JaxRS 介绍 项目介绍 项目架构 项目介绍 项目集成的原则 SpringBoot集成JaxWS 1. JaxWs ...

  3. Linux系统管理必备知识之利用ssh传输文件

    在使用SSH时候,有时我们需要传输文件,这就需要用到命令scp. 从服务器上下载文件 scp username@servername:/path/filename /local_dir(本地目录) e ...

  4. tftp:timeout问题解决 - 从Windows传输文件到开发板

    通过串口工具ping一下主机,确定是否能ping通,确保通信无问题,如下 ping通后,确保PC tftp软件打开, 检查防火墙是否关闭,专用网络是家庭网络,允许同网段下的数据传输,无需关闭,因此只需 ...

  5. 使用nc传输文件和目录【转】

    方法1,传输文件演示(先启动接收命令) 使用nc传输文件还是比较方便的,因为不用scp和rsync那种输入密码的操作了 把A机器上的一个rpm文件发送到B机器上 需注意操作次序,receiver先侦听 ...

  6. linux cp sync,通过SSH使用Rsync传输文件,复制和同步文件及目录

    在本文中,我们将解释如何通过SSH使用rsync复制文件.当涉及在网络上的系统之间传输文件时,Linux和Unix用户可以使用许多工具,最流行的数据传输协议是SSH和FTP,虽然FTP很受欢迎,但总是 ...

  7. 用 Dubbo 传输文件?被老板一顿揍

    以下文章来源方志朋的博客,回复"666"获面试宝典 公司之前有一个 Dubbo 服务,其内部封装了腾讯云的对象存储服务 SDK,目的是统一管理这种三方服务的SDK,其他系统直接调用 ...

  8. 使用C++的Socket实现从客户端到服务端,服务端到客户端传输文件

    使用: (1)首先运行服务端,待服务端运行起来: (2)最后运行客户端,输入要传输文件到哪个目标机器的IP地址: (3)输入传输文件的路径及文件(完成的路径),其中包含文件的类型,也就是后缀需要包含( ...

  9. 使用C++实现Socket编程传输文件

    使用: (1)首先运行服务端,待服务端运行起来: (2)最后运行客户端,输入要传输文件到哪个目标机器的IP地址: (3)输入传输文件的路径及文件(完成的路径),其中包含文件的类型,也就是后缀需要包含( ...

最新文章

  1. NS_ASSUME_NONNULL_BEGIN 延伸
  2. 人工智能应用于建筑领域新前沿
  3. 再谈应用环境下的TIME_WAIT和CLOSE_WAIT
  4. Hibernate学习笔记
  5. bzoj4525[Usaco2016 Jan]Angry Cows
  6. php 谷歌语音,php 语音参考
  7. MTK 驱动开发(35)---待机功耗分析流程
  8. 【hive】hive权限
  9. Echarts数据可视化polar极坐标系,开发全解+完美注释
  10. mysql找出最大的天数_mysql 计算连续登录最大天数
  11. 开源美狐美颜SDK功能代码分析
  12. RDS MySQL和Mongodb 物理备份文件.xb恢复到自建数据库
  13. JavaScript中逻辑运算符的优先级
  14. 9.17 hive高级语法01
  15. 《Adobe Photoshop大师班:经典作品与完美技巧赏析》目录—导读
  16. 芜湖赛宝机器人研究院_中国赛宝官方网站
  17. 进出口(海关)新系统的操作流程--20040923
  18. 洋桃技术支持0006:开发板上电扬声器有杂音怎么办?
  19. 人脸识别(基于阿里云)
  20. zokeeper(-)

热门文章

  1. Django文件部署(3.涉及到的vim指令必须提一下)(全)
  2. Missing dependencies for SOCKS support.
  3. 2020-10-22OpenCV 获取摄像头并显示摄像头视频
  4. cvs数据格式 gps_CVS 操作
  5. mysql大数据迁移,备份
  6. eclipse 下载
  7. 在线制作9 patch图片
  8. Stall Reservations
  9. No Network Security Config specified问题和android网络白名单的配置
  10. 如何在MCU上通过ToD+PPS 获取同步时间(二)