Perfil de eric我的地盘,我做主!FotosBlogListas Herramientas Ayuda

我的地盘,我做主!

小加逛超市

出门准备
 

狂奔摔跤

 

强苹果吃
 

随曲而舞
 

小加修风扇

 

亲子装

     

Flex, .Net and Java Interoperability

以前见到不少.NET and Java Interoperability的书籍,一直感觉只有吃饱撑着的人才会在一个系统中采用多种异构的技术平台,然后在通过WebService之类进行不同技术平台的交互。但随着各种各样的前端技术逐渐成熟强大(Flex、Silverlight、Swing、JavaFX、QT、Web...),后台可选择性越来越多(J2EE、.NET、Rails、PHP...),使得实现一个系统的可选前后台技术的排列组合相当之多,如今可交互性变得原来越重要了。
 
最近做了几个互操作的例子,后台分别用Java和.NET起了两种WebService,前台用Java、Flex和Silverlight三种客户端方式实现了6中交互:Java-Java, Java-.NET, Flex-Java, Flex-.NET,  Silverlight-Java, Silverlight-.NET,以下列了些主要步骤和需要注意的问题:
 
1、.NET通过WCF可以很容易WebService服务,为了提供给Silverlight客户端所以选择了Silverlight-enable WCF Service,需要注意的是在web.config默认提供的是customBinding和mexHttpBinding的endpoint的binding方式,需要改成basicHttpBinding的方式,如果你的客户端是WPF可以不用改动。
    <services>
      <service name="SliverlightWithWS.Web.CustomerService" behaviorConfiguration="SliverlightWithWS.Web.CustomerServiceBehavior">
        <endpoint address="" binding="basicHttpBinding" contract="SliverlightWithWS.Web.CustomerService"/>
      </service>
    </services>
 
2、Java创建WebService可以通过JDK6的bin目录中的apt对标注为javax.jws.WebService的服务类生成相应的封装类
@WebService
public class MyService{
    @WebMethod
    public int add(int a, int b) {
        return a+b;
    }
apt -d test test/MyService.java
JDK6的javax.xml.ws.Endpoint直接就具备发布服务功能,你可以将其理解成一个简单的Tomcat容器
    public static void main(String[] args){
        Endpoint e = Endpoint.create(HTTPBinding.HTTP_BINDING, new CrossDomainProvider());
        e.publish("http://localhost:8080/clientaccesspolicy.xml");
        MyService service= new MyService();
        Endpoint.publish("http://localhost:8080/service", service);          
    }
通过以上工作你已经发布了一个web服务,可以通过http://localhost:8080/service?wsdl查看具体的服务细节,另外你也注意到我还多发布了个clientaccesspolicy.xml这个注意是为了解决Flex和Silverlight跨域访问的权限问题,Flex通过http://domain/crossdomain.xml获取是否允许跨域访问权限,Silverlight通过http://domain/clientaccesspolicy.xml查看,当然作为RIA市场的后来者MS还是得照顾一下已经广为传播的Flash应用,因此Silverlight当找不到clientaccesspolicy.xml路径后也会尝试读取adobe的crossdomain.xml格式定义的访问权限配置,这里就不再细展开权限话题,好奇的话你可以看看http://twitter.com/crossdomain.xml的内容
 
@WebServiceProvider
@ServiceMode(value=Service.Mode.PAYLOAD)
public class CrossDomainProvider implements Provider<Source> {
 @Override
 public Source invoke(Source request) {
  System.out.print(request);
  String replyData =
  "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
  + "<access-policy>"
  + "<cross-domain-access>"
  + "<policy>"
  + "<allow-from http-request-headers=\"*\">"
  + "<domain uri=\"*\"/>"
  + "</allow-from>"
  + "<grant-to>"
  + "<resource path=\"/\" include-subpaths=\"true\"/>"
  + "</grant-to>"
  + "</policy>"
  + "</cross-domain-access>"
  + "</access-policy>";
  
  StreamSource reply = new StreamSource(new StringReader(replyData));
     return reply;
 }
}
 
除了以上通过直接通过JDK6的javax.xml.ws.Endpoint进行发布外,你也可以通过https://metro.dev.java.net/将服务发布到任意支持Servlet的J2EE容器中,具体的说下载https://metro.dev.java.net/1.5/metro-1_5.jar,然后java -jar metro-1_5.jar解压metro内容,将解压后的metro/lib目录下的所有jar包拷贝到apache-tomcat-5.5.27\shared\lib下面,在web.xml中配置如下
 <listener>
  <listener-class>
   com.sun.xml.ws.transport.http.servlet.WSServletContextListener
  </listener-class>
 </listener>

 <servlet>
  <servlet-name>jaxservlet</servlet-name>
  <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
增加一个sun-jaxws.xml文件,配置如下
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="
http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
 <endpoint
  name="sum"
  implementation="test.MyService"
  url-pattern="/services/twaver"/>
</endpoints>
这样就可以将服务发布到J2EE容器中了,如果你用Netbeans工具以上这个步骤将会更加简化,当然你也可以选择CXF的解决方案http://cxf.apache.org
 
3、Java客户端可以通过JDK6\bin\wsimport -p client -keep http://localhost:8080/services/twaver?wsdl 生成相应客户端的包装代码,至于调用就非常简单了基本和操作POJO没有区别,这里需要注意的是我用Java连接.NET的WCF服务时,死活出com.sun.org.apache.xerces.internal.util.SymbolTable.hash的空异常,查了一下应该是JDK的bug,现在JDK6引入的是JAX-WS 2.0,你可以通过GlassFish更高的版本解决这个问题,不过后来试了将.NET的[ServiceContract(Namespace = "")]随便改成[ServiceContract(Namespace = "sailing8036")]的非空的Namespace就ok了
 
4、.NET客户端主要就是前面提到的跨越问题,如果是Silverlight访问跨域的Web服务需要提供clientaccesspolicy.xml或者crossdomain.xml的访问权限,另外Silverlight必须采用basicHttpBinding的方式,我用其他方式创建的WCF服务,用wsimport生成Java客户端代码时会出现java access wcf it uses non-standard SOA it uses non-standard SOAP 1.2 binding问题,反正basicHttpBinding可以走得通我就没细研究了,有知道原因者不妨回帖赐教一下。
 
5、Flex的客户端主要考虑跨域的crossdomain.xml权限提供即可,由于ActionScript的动态性其客户端代码相比Java和C#真是简洁舒服很多,以下寥寥几行已经是全部客户端代码
 
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="
http://www.adobe.com/2006/mxml" layout="absolute">
 <mx:Script>
  <![CDATA[
   import mx.rpc.events.*;
   import mx.rpc.soap.*;
   
   private function GetJavaWS():void{
    var ws:WebService = new WebService();
    ws.wsdl = "
http://localhost:8080/WebServices/services/twaver?wsdl";
    ws.useProxy = false;
    ws.addEventListener(ResultEvent.RESULT, handleJavaResult);
    ws.loadWSDL();
    ws.getPerpson("林意炜", 29);
   }
   private function handleJavaResult(e:ResultEvent):void{
    output.text = e.result.name + "|" + e.result.age;
   }
   private function GetNETWS():void{
    var ws:WebService = new WebService();
    ws.wsdl = "
http://localhost:51646/CustomerService.svc?wsdl";
    ws.useProxy = false;
    ws.addEventListener(ResultEvent.RESULT, handleNETResult);
    ws.loadWSDL();
    ws.GetUser(1);
   }
   private function handleNETResult(e:ResultEvent):void{
    output.text = e.result.Name + "|" + e.result.Age;
   }   
  ]]>
 </mx:Script>
 <mx:TextInput id="output" x="10" y="10" width="717" height="194"/>
 <mx:Button x="10" y="212" label="JavaWS" click="GetJavaWS();"/>
 <mx:Button x="83" y="212" label=".NETWS" click="GetNETWS();"/>
</mx:Application>
 
以上只是简单的实现互通,没有考虑效率和安全问题,不少其他好文可以参考一下:
 

拾掇碎片

 
 

成长的乐趣

大人的成长是烦恼的,小孩的成长是快乐的



小加一周岁

2009-04-11一周岁的小加:一头卷发,四颗门牙,横冲直撞,笑口常开
 
 

重温2008-04-11刚出生的小加:
 
 
Foto 1 de 12