WebService之Axis2(2):复合类型数据的传递

yanzhiguo 发表于 2010-02-24 15:30 浏览次数:101 views 来源:

 

在实际的应用中,不仅需要使用WebService来传递简单类型的数据,有时也需要传递更复杂的数据,这些数据可以被称为复合类型的数据。数组与类(接口)是比较常用的复合类型。在Axis2中可以直接使用将WebService方法的参数或返回值类型声明成数组或类(接口)。但要注意,在定义数组类型时只能使用一维数组,如果想传递多维数组,可以使用分隔符进行分隔,如下面的代码所示:

     

       

        • String[] strArray = new String[]{ "自行车,飞机,火箭","中国,美国,德国", "超人,蜘蛛侠,钢铁侠" } ;

 

 

复制代码

 

   

上面的代码可以看作是一个3*3的二维数组。

   

在传递类的对象实例时,除了直接将数组类型声明成相应的类或接口,也可以将对象实例进行序列化,也就是说,将一个对象实例转换成字节数组进行传递,然后接收方再进行反序列化,还原这个对象实例。

   

下面的示例代码演示了如何传递数组与类(接口)类型的数据,并演示如何使用字节数组上传图像。本示例的客户端代码使用Java

C#编写。要完成这个例子需要如下几步:

一、实现服务端代码

    ComplexTypeService是一个WebService类,该类的代码如下:

     

       

        • import java.io.FileOutputStream;
        • import data.DataForm;
        •  
        • public class ComplexTypeService
        • {
        •     //  上传图像,imageByte参数表示上传图像文件的字节,
        •     //  length参数表示图像文件的字节长度(该参数值可能小于imageByte的数组长度)
        •     public boolean uploadImageWithByte(byte[] imageByte, int length)
        •     {
        •         FileOutputStream fos = null;
        •         try
        •         {
        •             //  将上传的图像保存在D盘的test1.jpg文件中
        •             fos = new FileOutputStream("d:\\test1.jpg");
        •             //  开始写入图像文件的字节
        •             fos.write(imageByte, 0, length);
        •             fos.close();
        •         }
        •         catch (Exception e)
        •         {
        •             return false;
        •         }
        •         finally
        •         {
        •             if (fos != null)
        •             {
        •                 try
        •                 {
        •                     fos.close();
        •                 }
        •                 catch (Exception e)
        •                 {
        •  
        •                 }
        •             }
        •         }
        •         return true;
        •     }
        •     //  返回一维字符串数组
        •     public String[] getArray()
        •     {
        •         String[] strArray = new String[]{ "自行车", "飞机", "火箭" };
        •         return strArray;
        •     }
        •     //  返回二维字符串数组
        •     public String[] getMDArray()
        •     {
        •         String[] strArray = new String[]{ "自行车,飞机,火箭","中国,美国,德国", "超人,蜘蛛侠,钢铁侠" } ;
        •         return strArray;
        •     }
        •     //  返回DataForm类的对象实例
        •     public DataForm getDataForm()
        •     {
        •         return new DataForm();
        •     }
        •     //  将DataForm类的对象实例序列化,并返回序列化后的字节数组
        •     public byte[] getDataFormBytes() throws Exception
        •     {
        •         java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
        •         java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
        •         oos.writeObject(new DataForm());        
        •         return baos.toByteArray();
        •     }   
        • }

 

 

复制代码

 

二、实现DataForm

DataForm是要返回的对象实例所对应的类,该类的实现代码如下:

  1. package data;
  2.  
  3. public class DataForm implements java.io.Serializable
  4. {
  5.     private String name = "bill";
  6.     private int age = 20;
  7.  
  8.     public String getName()
  9.     {
  10.         return name;
  11.     }
  12.     public void setName(String name)
  13.     {
  14.         this.name = name;
  15.     }
  16.     public int getAge()
  17.     {
  18.         return age;
  19.     }
  20.     public void setAge(int age)
  21.     {
  22.         this.age = age;
  23.     }
  24. }

复制代码

 

三、发布WebService

   

由于本示例的WebService类使用了一个Java类(DataForm类),因此,在发布WebService之前,需要先将DataForm.class文件复制到

<Tomcat安装目录>\webapps\axis2\WEB-INF\classes\data目录中,然后将ComplexTypeService.class文件复制到<Tomcat安装目录>\webapps\axis2\WEB-INF\pojo目录中,最后启动Tomcat(如果Tomcat已经启动,由于增加了一个DataForm类,因此,需要重新启动Tomcat)。

四、使用Java编写调用WebService的客户端代码

   

在客户端仍然使用了RPC的调用方式,代码如下:

     

       

        • package client;
        •  
        • import javax.xml.namespace.QName;
        • import org.apache.axis2.addressing.EndpointReference;
        • import org.apache.axis2.client.Options;
        • import org.apache.axis2.rpc.client.RPCServiceClient;
        •  
        • public class ComplexTypeRPCClient
        • {
        •  
        •     public static void main(String[] args) throws Exception
        •     {
        •         RPCServiceClient serviceClient = new RPCServiceClient();
        •         Options options = serviceClient.getOptions();
        •         EndpointReference targetEPR = new EndpointReference(
        •                 "http://localhost:8080/axis2/services/ComplexTypeService");
        •         options.setTo(targetEPR);
        •         // 下面的代码调用uploadImageWithByte方法上传图像文件
        •         /////////////////////////////////////////
        •         // 打开图像文件,确定图像文件的大小
        •         java.io.File file = new java.io.File("f:\\images.jpg");
        •         java.io.FileInputStream fis = new java.io.FileInputStream("f:\\images.jpg");
        •         // 创建保存要上传的图像文件内容的字节数组
        •         byte[] buffer = new byte[(int) file.length()];
        •         // 将图像文件的内容读取buffer数组中
        •         int n = fis.read(buffer);
        •         System.out.println("文件长度:" + file.length());
        •         Object[] opAddEntryArgs = new Object[]{ buffer, n };
        •         Class[] classes = new Class[]{ Boolean.class };
        •         QName opAddEntry = new QName("http://ws.apache.org/axis2","uploadImageWithByte");
        •         fis.close();
        •         // 开始上传图像文件,并输出uploadImageWithByte方法的返回传
        •         System.out.println(serviceClient.invokeBlocking(opAddEntry,opAddEntryArgs, classes)[0]);
        •         /////////////////////////////////////////
        •         
        •         // 下面的代码调用了getArray方法,并返回一维String数组
        •         /////////////////////////////////////////  
        •         opAddEntry = new QName("http://ws.apache.org/axis2", "getArray");
        •         String[] strArray = (String[]) serviceClient.invokeBlocking(opAddEntry,
        •                             new Object[]{}, new Class[]{String[].class })[0];
        •         for (String s : strArray)
        •             System.out.print(s + "  ");
        •         System.out.println();
        •         /////////////////////////////////////////
        •         
        •  
        •         // 下面的代码调用了getMDArray方法,并返回一维String数组
        •         /////////////////////////////////////////  
        •         opAddEntry = new QName("http://ws.apache.org/axis2", "getMDArray");
        •         strArray = (String[]) serviceClient.invokeBlocking(opAddEntry, new Object[]{},
        •                                                           new Class[]{String[].class})[0];
        •         for (String s : strArray)
        •         {
        •             String[] array = s.split(",");
        •             for(String ss: array)
        •                 System.out.print("<" + ss + "> ");
        •             System.out.println();
        •         }
        •         System.out.println();
        •         /////////////////////////////////////////
        •  
        •         // 下面的代码调用了getDataForm方法,并返回DataForm对象实例
        •         /////////////////////////////////////////  
        •         opAddEntry = new QName("http://ws.apache.org/axis2", "getDataForm");
        •         data.DataForm df = (data.DataForm) serviceClient.invokeBlocking(opAddEntry, new Object[]{},
        •                                                                   new Class[]{data.DataForm.class})[0];
        •         System.out.println(df.getAge());
        •         /////////////////////////////////////////
        •         
        •         // 下面的代码调用了getDataFormBytes方法,并返回字节数组,最后将返回的字节数组反序列化后,转换成DataForm对象实例
        •         /////////////////////////////////////////         
        •         opAddEntry = new QName("http://ws.apache.org/axis2", "getDataFormBytes");
        •         buffer = (byte[]) serviceClient.invokeBlocking(opAddEntry, new Object[]{}, new Class[]{byte[].class})[0];
        •         java.io.ObjectInputStream ois = new java.io.ObjectInputStream(
        •                 new java.io.ByteArrayInputStream(buffer));
        •         df = (data.DataForm) ois.readObject();
        •         System.out.println(df.getName());
        •         //////////////////////////////////////////
        •     }
        • }

 

 

复制代码

 

   

运行上面的程序,将输出如下的内容:

文件长度:3617

 

 

true

自行车 飞机 火箭

<自行车> <飞机> <火箭>

<中国> <美国> <德国>

<超人> <蜘蛛侠> <钢铁侠>

20

bill

五、使用C#编写调用WebService的客户端代码

   

Visual Studio中使用WebService就简单得多。假设引用WebService时的引用名为complexType,则下面的代码调用了uploadImageWithByte方法来上传图像文件。在Visual Studio引用WebService时,uploadImageWithByte方法多了两个out参数,在使用时要注意。

     

       

        • complexType.ComplexTypeService cts = new WSC.complexType.ComplexTypeService();
        • System.IO.FileStream fs = new System.IO.FileStream(@"f:\images.jpg", System.IO.FileMode.Open);
        • byte[] buffer = new byte[fs.Length];
        • fs.Read(buffer, 0, (int)fs.Length);
        • bool r;
        • bool rs;
        • cts.uploadImageWithByte( buffer, (int)fs.Length, true, out r, out rs);

 

 

复制代码

 

   

在获得二维数组时,可以将数据加载到DataGridView或其他类似的控件中,代码如下:

     

       

        • String[] strArray = cts.getMDArray();
        • for (int i = 0; i < strArray.Length; i++)
        • {
        •     //  用正则表达式将带分隔符的字符串转换成String数组
        •     String[] columns = strArray[i].Split(‘,’);
        •     //  如果DataGridView的表头不存在,向DataGridView控件添加三个带表头的列
        •     if (dataGridView1.Columns.Count == 0)
        •         for (int j = 0; j < columns.Length; j++)
        •             dataGridView1.Columns.Add("column" + (j + 1).ToString(), "列" + (j + 1).ToString());
        •     //  添加行
        •     dataGridView1.Rows.Add(1);
        •     for(int j = 0; j < columns.Length; j++)
        •     {
        •         dataGridView1.Rows[i].Cells[j].Value = columns[j];                       
        •     }               
        • }

 

 

复制代码

 

   

DataGridView控件添加数据后的效果如图1所示。

图1  

 

   

对于其他的WebService方法的调用都非常简单,读者可以自己做这个实验。

   

要注意的是,由于.netjava序列化和反序列化的差异,通过序列化的方式传递对象实例只使用于客户端与服务端为同一种语言或技术的情况,如客户端和服务端都使用Java来编写。

    如果读者要上传大文件,应尽量使用FTP的方式来传递,而只通过WebService方法来传递文件名等信息。这样有助于提高传输效率。

关键字: | 分类: IT文摘, Java文章 | 评论数: 1 | 阅读全文

WebService之Axis2(1):用POJO实现0配置的WebService

yanzhiguo 发表于 2010-02-24 15:15 浏览次数:127 views 来源:

 

Axis2是一套崭新的WebService引擎,该版本是对Axis1.x重新设计的产物。Axis2不仅支持SOAP1.1SOAP1.2,还集成了非常流行的REST WebService,同时还支持SpringJSON技术。这些都将在后面的系列教程中讲解。在本文中主要介绍了如何使用Axis2开发一个不需要任何配置文件WebService,并在客户端使用JavaC#调用这个WebService一、Axis2的下载和安装
    读者可以从如下的网址下载Axis2的最新版本:
    http://ws.apache.org/axis2/

    在本文使用了目前Axis2的最新版本1.4.1。读者可以下载如下两个zip包:
    axis2-1.4.1-bin.zip
    axis2-1.4.1-war.zip
    其中axis2-1.4.1-bin.zip文件中包含了Axis2中所有的jar文件, axis2-1.4.1-war.zip文件用于将WebService发布到Web容器中。
    axis2-1.4.1-war.zip文件解压到相应的目录,将目录中的axis2.war文件放到<Tomcat安装目录>\webapps目录中(本文使用的Tomcat的版本是6.x),并启动Tomcat
    在浏览器地址栏中输入如下的URL
    http:/ /localhost:8080/axis2/

    如果在浏览器中显示出如图1所示的页面,则表示Axis2安装成功。

图1

二、编写和发布WebService
  对于用Java实现的服务程序给人的印象就是需要进行大量的配置,不过这一点在Axis2中将被终结。在Axis2中不需要进行任何的配置,就可以直接将一个简单的POJO发布成WebService。其中POJO中所有的public方法将被发布成WebService方法。
    下面我们来实现一个简单的POJO,代码如下:

    • public class SimpleService
    • {
    •     public String getGreeting(String name)
    •     {
    •         return "你好 " + name;
    •     }   
    •     public int getPrice()
    •     {
    •         return new java.util.Random().nextInt(1000);
    •     }   
    • }

复制代码

   SimpleService类中有两个方法,由于这两个方法都是public方法,因此,它们都将作为WebService方法被发布。
    编译SimpleService类后,将SimpleService.class文件放到<Tomcat安装目录>\webapps\axis2\WEB-INF\pojo目录中(如果没有pojo目录,则建立该目录)。现在我们已经成功将SimpleService类发布成了WebService。在浏览器地址栏中输入如下的URL
http:/ /localhost:8080/axis2/services/listServices

    这时当前页面将显示所有在Axis2中发布的WebService,如图2所示。



图2


    在浏览器地址栏中输入如下的两个URL来分别测试getGreetinggetPrice方法:
http:/ /localhost:8080/axis2/services/SimpleService/getGreeting?name=bill

http:/ /localhost:8080/axis2/services/SimpleService/getPrice

    3和图4分别显示了getGreetinggetPrice方法的测试结果。

图3  getGreeting方法的测试结果

图4  getPrice方法的测试结果

    在编写、发布和测试0配置的WebService时应注意如下几点:

1. POJO类不能使用package关键字声明包。

2. Axis2在默认情况下可以热发布WebService,也就是说,将WebService.class文件复制到pojo目录中时,Tomcat不需要重新启动就可以自动发布WebService。如果想取消Axis2的热发布功能,可以打开<Tomcat安装目录>\webapps\axis2\WEB-INF\conf\axis2.xml,找到如下的配置代码:

    • <parameter name="hotdeployment">true</parameter>

复制代码

   true改为false即可。要注意的是,Axis2在默认情况下虽然是热发布,但并不是热更新,也就是说,一旦成功发布了WebService,再想更新该WebService,就必须重启Tomcat。这对于开发人员调试WebService非常不方便,因此,在开发WebService时,可以将Axis2设为热更新。在axis2.xml文件中找到<parametername="hotupdate">false</parameter>,将false改为true即可。

3. 在浏览器中测试WebService时,如果WebService方法有参数,需要使用URL的请求参数来指定该WebService方法参数的值,请求参数名与方法参数名要一致,例如,要测试getGreeting方法,请求参数名应为name,如上面的URL所示。

4. 发布WebServicepojo目录只是默认的,如果读者想在其他的目录发布WebService,可以打开axis2.xml文件,并在<axisconfig>元素中添加如下的子元素:

    •    <deployer extension=".class" directory="my" class="org.apache.axis2.deployment.POJODeployer"/>

复制代码

   上面的配置允许在<Tomcat安装目录>\webapps\axis2\WEB-INF\my目录中发布WebService。例如,将本例中的SimpleService.class复制到my目录中也可以成功发布(但要删除pojo目录中的SimpleService.class,否则WebService会重名)。

三、 Java实现调用WebService的客户端程序
    WebService是为程序服务的,只在浏览器中访问WebService是没有意义的。因此,在本节使用Java实现了一个控制台程序来调用上一节发布的WebService。调用WebService的客户端代码如下:

    • package client;
    •  
    • import javax.xml.namespace.QName;
    • import org.apache.axis2.addressing.EndpointReference;
    • import org.apache.axis2.client.Options;
    • import org.apache.axis2.rpc.client.RPCServiceClient;
    •  
    • public class RPCClient
    • {
    •     public static void main(String[] args) throws Exception  
    •     {
    •         //  使用RPC方式调用WebService        
    •         RPCServiceClient serviceClient = new RPCServiceClient();
    •         Options options = serviceClient.getOptions();
    •         //  指定调用WebService的URL
    •         EndpointReference targetEPR = new EndpointReference(
    •                 "http://localhost:8080/axis2/services/SimpleService");
    •         options.setTo(targetEPR);
    •         //  指定getGreeting方法的参数值
    •         Object[] opAddEntryArgs = new Object[] {"超人"};
    •         //  指定getGreeting方法返回值的数据类型的Class对象
    •         Class[] classes = new Class[] {String.class};
    •         //  指定要调用的getGreeting方法及WSDL文件的命名空间
    •         QName opAddEntry = new QName("http://ws.apache.org/axis2", "getGreeting");
    •         //  调用getGreeting方法并输出该方法的返回值
    •         System.out.println(serviceClient.invokeBlocking(opAddEntry, opAddEntryArgs, classes)[0]);
    •         //  下面是调用getPrice方法的代码,这些代码与调用getGreeting方法的代码类似
    •         classes = new Class[] {int.class};
    •         opAddEntry = new QName("http://ws.apache.org/axis2", "getPrice");
    •         System.out.println(serviceClient.invokeBlocking(opAddEntry, new Object[]{}, classes)[0]);
    •     }
    • }

复制代码

运行上面的程序后,将在控制台输出如下的信息:

你好 超人
443


   在编写客户端代码时应注意如下几点:

1. 客户端代码需要引用很多Axis2jar包,如果读者不太清楚要引用哪个jar包,可以在Eclipse的工程中引用Axis2发行包的lib目录中的所有jar包。

2. 在本例中使用了RPCServiceClient类的invokeBlocking方法调用了WebService中的方法。invokeBlocking方法有三个参数,其中第一个参数的类型是QName对象,表示要调用的方法名;第二个参数表示要调用的WebService方法的参数值,参数类型为Object[];第三个参数表示WebService方法的返回值类型的Class对象,参数类型为Class[]。当方法没有参数时,invokeBlocking方法的第二个参数值不能是null,而要使用new Object[]{}

3. 如果被调用的WebService方法没有返回值,应使用RPCServiceClient类的invokeRobust方法,该方法只有两个参数,它们的含义与invokeBlocking方法的前两个参数的含义相同。

4. 在创建QName对象时,QName类的构造方法的第一个参数表示WSDL文件的命名空间名,也就是<wsdl:definitions>元素的targetNamespace属性值,下面是SimpleService类生成的WSDL文件的代码片段:

    • <?xml version="1.0" encoding="UTF-8"?>
    • <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns1="http://org.apache.axis2/xsd"
    • xmlns:ns="http://ws.apache.org/axis2" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
    • xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    • xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    • xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    • targetNamespace="http://ws.apache.org/axis2">
    •     <wsdl:types>
    •          
    •     </wsdl:types>
    •      
    • </wsdl:definitions>

复制代码

四、用wsdl2java简化客户端的编写
    也许有很多读者会说“有没有搞错啊,只调用两个WebService方法用要写这么多代码,太麻烦了”。
    不过幸好Axis2提供了一个wsdl2java.bat命令可以根据WSDL文件自动产生调用WebService的代码。wsdl2java.bat命令可以在<Axis2安装目录>"bin目录中找到。在使用wsdl2java.bat命令之前需要设置AXIS2_HOME环境变量,该变量值是<Axis2安装目录>
    Windows控制台输出如下的命令行来生成调用WebService的代码:
%AXIS2_HOME%\bin\wsdl2java -uri http://localhost:8080/axis2/services/SimpleService?wsdl-p client -s -o stub
    其中-url参数指定了wsdl文件的路径,可以是本地路径,也可以是网络路径。-p参数指定了生成的Java类的包名,-o参数指定了生成的一系列文件保存的根目录。在执行完上面的命令后,读者就会发现在当前目录下多了个stub目录,在."stub"src"client目录可以找到一个SimpleServiceStub.java文件,该文件复杂调用WebService,读者可以在程序中直接使用这个类,代码如下:

    • package client;
    •  
    • import javax.xml.namespace.QName;
    • import org.apache.axis2.addressing.EndpointReference;
    • import org.apache.axis2.client.Options;
    • import org.apache.axis2.rpc.client.RPCServiceClient;
    •  
    • public class StubClient
    • {
    •     public static void main(String[] args) throws Exception  
    •     {
    •         SimpleServiceStub stub = new SimpleServiceStub();
    •         SimpleServiceStub.GetGreeting gg = new SimpleServiceStub.GetGreeting();
    •         gg.setName("比尔");
    •         System.out.println( stub.getGreeting(gg).get_return());
    •         System.out.println(stub.getPrice().get_return());
    •     }
    • }

复制代码

   上面的代码大大简化了调用WebService的步骤,并使代码更加简洁。但要注意的是,wsdl2java.bat命令生成的Stub类将WebService方法的参数都封装在了相应的类中,类名为方法名,例如,getGreeting方法的参数都封装在了GetGreeting类中,要想调用getGreeting方法,必须先创建GetGreeting类的对象实例。五、使用C#调用WebService
    从理论上说,WebService可以被任何支持SOAP协议的语言调用。在Visual Studio中使用C#调用WebService是在所有语言中最容易实现的(VB.net的调用方法类似,也同样很简单)。
    新建一个Visual Studio工程,并在引用Web服务的对话框中输入如下的URL,并输入Web引用名为“WebService”:
    http:/ /localhost:8080/axis2/services/SimpleService?wsdl

    然后引用Web服务的对话框就会显示该WebService中的所有的方法,如图5所示。

图5


    在完成上面的工作后,只需要如下三行C#代码就可以调用getGreetinggetPrice方法,并显示这两个方法的返回值:

    • WebService.SimpleService simpleService = new WSC.WebService.SimpleService();
    • MessageBox.Show( simpleService.getGreeting("比尔"));
    • MessageBox.Show(simpleService.getPrice().@return.ToString());

复制代码

  .net解析WSDL文件时直接将getGreeting方法的参数映射为String类型,因此,可以直接进行传值。
    从上面的调用过程可以看出,添加Web引用的过程就相当于在Java中调用wsdl2java.bat自动生成stub类的过程。只是在调用stub类时与C#有一定的区别,但从总体上来说,都大大简化了调用WebService的过程。

 

关键字: | 分类: IT文摘, Java文章 | 评论数: 0 | 阅读全文

如何选择Java培训?

老孙 发表于 2010-02-21 11:01 浏览次数:1,655 views 来源:

     找工作两个月了,现在it行业很好就业呀,薪水也挺高,北京的java培训水平比较高,大家帮我看看哪家的java培训有特色,出来好就业呀。

     选择java培训机构的标准主要就是这几条,按重要性依次为:

     项目,课程内容,师资,学费,教学环境。

项目:

     项目是选择java培训班的核心问题,选择项目就是在选择培训班。项目水平的高低直接关系到你项目经验累积的水平以及毕业后的就业方向,也可以直接反映了老师水平的高低。高水平的、与IT行业热门技术相关的项目经验非常有助于你将来的就业,甚至直接影响你的薪资水平。那么,我们如何去判断java培训机构项目水平的高低呢?

    项目不能太滥。

     很多java培训机构号称会在学习期间做到近十个项目,甚至多于十个的都有。这种蜻蜓点水式的项目根本无益于学员水平的提高。基本上每个项目都是介绍一下项目需求,做个框架,注册、登录,写个基本流程就草草了事,项目时间基本上就是四五天而已,每个项目基本都是重复劳作,糊弄学员,学员根本累积不到项目经验。再说,这种项目也根本拿不出手。将来去公司面试,人家问你做过什么项目,你一说十几个。再问问项目的具体细节,你肯定傻眼。

     项目一定得是真实的业界项目。

    很多java培训机构都称自己的项目是真实的案例,那么怎么判断他们有没有蒙我们呢?好办,他不是说真实的吗?如果是网站系统,总有个在线跑得吧。如果是企业管理系统,演示一下总可以吧。是骡子是马,拉出来溜溜。如果他们推三阻四,找各种借口推脱,好办,趁着钱还在自己口袋里,立刻闪人。

    项目一定要高水平。

    所谓的“高水平”无非就是指所用的技术是否高级、业界是否急需。大家都在用struts-hibernate-spring架构,这是热点,架构都一样,没啥说的。但是项目中是否包含了别的有用的业界流行的技术,比如搜索引擎技术,ajax,开源工作流等等,这才是判断项目水平高低的标准。如果项目是一个 OA项目,可是没有讲授开源工作流技术,而是写个简单的类,那就是在蒙人。如果项目中有全文检索,没有讲业界流行的Lucene,而是自己写个简单的分析类,那同样是在蒙人。总之,如果能在项目中学到更多的技术,而这技术又是业界急需的、流行的,那这项目就是“实在是高”,这样的培训班也值得去。

    项目一定要做的深。

    在有老师讲解,带领的情况下,将一个完整的项目深入的剖析,至少要有2-3周的时间。只有深入开发,才有助于学员全面深刻的理解项目的需求、技术,积累真正的项目开发经验。只有深入开发才能将企业开发中的一些问题展现给学员,将解决问题的方法教给学员,授之以渔,学员才能举一反三,完全适应以后的实际开发。蜻蜓点水式的项目开发除了浪费时间,对学员根本没有任何帮助。
课程内容

    基本上各个java培训机构的J2EE课程都是雷同的,大家都差不多。这一块可说的东西也不多。

师资问题

    大牌老师不见得就是"好老师",别把"大牌老师"当回事很多java培训机构的头牌老师,也就是天天被用来宣传的老师往往是不代课的,即使带也是最基础的课程。这就像我们大家高考报考时,老被那些大学的宣传蒙蔽,很多大学总是号称有多少科学院院士,基本上大学四年你都不会有缘一睹院士风采的,这些老头子基本与咱们凡夫俗子无关。呵呵,别把“大牌老师“当回事。

高手一般在创业型的小培训机构中可能存在。

    这些机构一般是几个在软件行业混了几年,技术比较精湛的人合伙开设。收费也较低。因为是老师自己的机构,也比较负责任。我就是在这样的小机构培训的,学到了不少东西。尤其是项目经验。受益无穷呀。

    判断java培训机构师资状况,主要是以带项目的老师的技术状况来衡量J2EE的课程虽然庞杂,但是知识都不难掌握,难点在项目经验的传授上面。一般的老师给学生讲授知识是没有什么问题的,讲的都差不多,都是照本宣科而已,无所谓水平高低。所以,判断java培训机构师资状况,主要是以带项目的老师的技术状况来衡量。不管培训机构如何吹他的那些老师了得,只要问清楚哪位大侠带项目就行了,这才是核心。项目老师水平过得去,就万事OK了。

教学环境:

     人数尽量不能太多,一定要小班教学,这是原则,否则与老师的沟通不畅,会直接影响项目经验的累积。

     地点可以偏点,坐公交,不超过1小时,就可以了。

     教学环境主要包括三个因素:班级人数,教学点位置,电脑硬件。其中最重要的当然是学员人数的问题。学员人数最好不要太多,人数过多,一个老师根本照顾不过来,跟放羊没什么区别,老师和学员良好的沟通是获取项目经验的重要渠道。教学点位置偏点没关系,只要学费低就OK了。班级人数和教学点位置会直接影响学费的高低,人数越少,学费越高;地点越偏,学费越低,最好能在这些因素中找到一个好的平衡点。

总结

    废话说了这么一大堆,给大家总结一下。我们参加java培训的目的就是为了找份好工作呀,企业最看重的是什么?不就是“项目经验”吗!如果你做过OA系统,然后去面试做OA的公司,那就不可能不进。你做过GIS系统,去面试做GIS系统的公司,不要你才怪呢。你做过搜索引擎,去面试做搜索的公司,肯定也十拿九稳,当然google就不一定能去了,呵呵。如果java培训班有几个高水平的项目,有大牛老师指导,肯定能帮你积累相当的项目经验(其实项目经验就是工作经验),到时候,找不到好工作,拿不到高薪水,都难!说白了,选择培训班就是选择项目。

Java之父点评技术趋势 Java使云计算更简单

老孙 发表于 2010-01-04 14:35 浏览次数:63 views 来源:

 

   近日James?Gosling就有关Sun的一系列话题,如IBM收购传闻,云计算,SOA以及Java做了一次访谈,内容整理如下。

   记者:您在媒体面前不便对收购的事情做太多评论,这点我可以理解。不过,假设IBM对Sun的收购成了事实,您认为会不会有Sun的NetBeans和IBM的Eclipse合并的此类情况发生呢?

   Gosling:当然可能了。我们双方在Java的旅途中已经合作了好几年。从很多方面来看(这次收购)对Java的进展而言是不会有太大影响的。现在而言(这次收购)只不过是一个比较吸引眼球的事件罢了。

   记者:IBM和Sun看上去是十分不同的组织呢。

   Gosling:企业文化上的冲突是一定存在的。我们比他们要更加奔放野性一些。我们从一堆嬉皮士中发展出来,头上还几乎插着鲜花。不过相比Sun 刚刚起步的时候,我们现在已经是一个成熟很多的公司了,我们的成员组成也十分不同。我们现在是一个完善的企业软件公司。

   记者:你在伦敦对开发者和合作者们谈了不少。可否问问你们讨论的主题是哪些?

   Gosling: 主题就是,现在有非常多发展中的技术。看看人们在用Java做什么,而Java又如何将他们联系起来——实在令人惊叹。我们看到了企业级平台的演变发展, 同时在客户端——也就是我所为之负责的人群,以及根深蒂固的Java技术,这其中围绕富用户界面以及增进交流方面的开发工具有很多待开掘的宝地。

   记者:您指的是JavaFX这个RIA(富网络应用)开发平台吧。能讲讲它的目标么。

   Gosling:大意就是,令部署在Web上的应用有如桌面端应用一样,有架构上丰富的表现层,动画效果及行为。它包含了丰富的功能设施,API(应用程序界面)以及组件,同时也遵循正确的网络协议。

   记者:相比Adobe?Flash或微软Silvelight,这有哪些不同或更好的地方??

   Gosling:主要的区别在于我们可以充分利用Java平台的所有性能。这使得开发者能够建立在网络端运行的功能强大的桌面端应用。Java架构对于减少延迟时间方面大有助益,因为你将更多的行为放在离用户更近的地方执行。

论 是高深的科教动画还是电子游戏,JavaFX都提供了很大发挥的潜力。NASA?World?Wind就是一个很好的例子(它可以让用户从卫星的高度放大 俯瞰地球上的任意一点。这通过卫星摄影与雷达拓扑图融合生成地面地形的3D成像图而实现)。要知道,支持Java的设施数目超过百亿,其中包括三十亿台手 机。

   记者:Java中最持久的一个内容就在于它的虚拟机,这为它提供了“编写一次,到处执行”的能力。对于目前诸多供应厂商拥护虚拟化的举动您一定也很关注吧,尽管这和JVM的虚拟化不在一个层面上。

   Gosling:JVM 相对一个微软或VMware的虚拟机而言更加抽象。我使用Java虚拟机有几个原因。我们需要将很大范围的硬件虚拟化——不光是 Mac,Unix,Linux和Windows,还有像手机甚至智能卡这样的设备。对计算的封装,转移,以及对不同设备的优化方法的需求,(都是我使用 Java虚拟机的原因)。

   记者:JVM对安全性也有帮助?

   Gosling:是,而且是安全性中重要的一个环节。虚拟机提供了我们可以强制实施的墙,而且还可以决定如何与其他虚拟机或计算群岛交流信息。

   记者:是指“沙箱”么?

   Gosling: 是的。一个沙箱即使被弄得一团糟,也不会影响到其他的沙箱。安全管理员要么给你权限,要么不给你权限。为什么那些大银行都用Java做系统,正是因为他们 需要绝对的信任。不过(JVM的安全性)不仅仅是沙箱,它还包括ID管理,加密安全随机数生成器等等。

   记者:Sun最近也提出了云计算策略。Java在其中起到什么作用么?

   Gosling:我们多年来一直在建造围绕云的工具。现在我们是第一次尝试提供这样的开放云,人们可以在上面做任何事。Java?API使在云端工作相当简单。问题在于如何为公众提供访问权,如何收费,以及如何在那样的环境下验证。

   记者:Sun的云平台会和亚马逊的EC2差不多么?

   Gosling: 从某种程度而言会和EC2差不多,不过它还会提供更高层次的服务。EC2基本上是原始数据存储和原始的计算能力。我们还将提供更高层次的设施。比如 OpenOffice的最新版就涵盖了云存储的概念,你可以开始在云端存储文档树,而无须再依赖你自己的存储阵列。

   记者:您仍然认为SOA是软件开发的正确方法么?

   Gosling: 我认为SOA是一种哲学,有如氧气一般:你天天呼吸它,你的生命依赖于它,但是你不会天天想到它。OO(面向对象)编程是SOA.很大程度上SOA也就是 OO,而且是一个设计系统的很敏感的方法。不过我同时也是函数式编程的支持者(这是一个着重函数应用方面的编程模式,与着重状态变化的命令式编程相对 应)。这是一系列的概念,很多开发者都感觉难以使用。

还有一个大难题就是如何让一组技能不同的人对项目做出同等的 贡献。工程小组不再仅仅由工程师组成——你会发现小组由一个工程师和几个文科生组成。瀑布式流程(这种序列式流程需要一步一步走过开发中的每一个环节:构 思,分析,设计到建造,测试以及维护)很不适合这样的小组,因为这意味着这些艺术家们将所有的活儿丢到墙那边的开发者头上。

   记者:那么您认为敏捷是正确的方法??

   Gosling:敏捷是一种哲学,这种哲学解决了很多问题,但问题可能是由于缺乏工具支持所导致的。标准工具普遍强制一种瀑布式模式,而说实话,瀑布式模式是十分糟糕的。

   记者:Java现在完全是开源的。您是否仍然觉得您有职责引导它前进的方向?

   Gosling:那个(开源)运动现在正处在稳定的状态。这有点像是这条路上有很多岩石,那条路上又比较冷这样。我尝试将进展引导至正确的方向,不过这个社区如此庞大,没有人能够操控它。如果有人做此尝试,那只会毁了它。

Java SE编程技术-对象造型

老孙 发表于 2009-10-19 11:49 浏览次数:1,421 views 来源:

在多态的情况下,由于对象以其父类的身份出现,对子类中新添加成员的访问受到限制,有时我们可能又需要恢复一个对象的本来面目——造型(Casting),以发挥其全部潜力。让我们结合一个具体的例子来介绍对象造型。

例6-14 对象造型举例
源文件:Person.java

public class Person{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public String getInfo(){
return "Name: " + name + "tAge: " + age;
}
}

源文件:Student.java

public class Student extends Person{
private String school;
public void setSchool(String school){
this.school = school;
}
public String getSchool(){
return school;
}
}

源文件:Test.java

public class Test{
public void cast(Person p){
//System.out.println(p.getSchool()); //非法,编译出错!
Student stu = (Student)p; //p1
System.out.println(stu.getSchool());
}

public static void main(String[] args){
Test t = new Test();
Student s = new Student();
s.setSchool("THU");
t.cast(s);
}
}

程序运行输出结果为:
THU
本次程序运行中,实参s所引用的实际上是子类Student的对象,该子类中确实封装了功能方法getSchool(),但是由于cast()方法中形参p声明为Person类型,因此不能通过变量p直接访问getSchool()方法。但是通过造型将Person类型变量p的值赋给新声明的Student类型变量stu之后,通过变量stu就可以直接访问getSchool()方法了。
实际上,所谓的造型其实就是引用类型数据值之间的强制类型转换,为更好地说明造型操作的实现细节,特给出相应的内存状态如图6-4所示。

图6-4 程序运行到p1处的内存状态
从上图中可以看出,造型操作只是将父类类型引用变量的值直接赋给声明为子类类型的变量,但并不是随便什么类型的数据之间都可以进行造型,Java语言中造型的具体规则如下:

从子类到父类的类型转换可以自动进行;

在多态的情况下,从父类到子类的类型转换必须通过造型(强制类型转换)实现;

无继承关系的引用类型间的转换是非法的。

例如由于String类和Person类之间没有继承关系,因此下述语句是非法的:

String s = "Hello,World!";
Person p = (Person)s; //编译出错

事实上,此时引用变量s所引用的String类对象中根本不可能封装Person类中定义的name、age等属性,因此也就无法将一个String对象替代Person类型对象来使用。
基于类似的原因,从父类到子类的造型也不是都能成功——只有当对象的真正类型本就是子类类型,只是在多态的情况下,被一个声明为父类类型的变量所引用,才可以进行造型处理,即再恢复该对象的本来面目。而一个对象如果其真正类型就是父类类型,是不能被造型为子类类型的,假定Student类仍然继承了Person类,则下述代码虽能通过编译,但运行时会出错:

Person p = new Person();
Student stu = (Student)p; //运行出错

相关错误信息为:java.lang.ClassCastException: Person cannot be cast to Student
关于造型的合法性检查是分两个阶段进行的:

编译时只检查造型操作所涉及的两种类型间是否存在继承关系,有则通过编译,否则报错;

运行时再检查该时刻对象真正的类型是否确为造型的目标类型或其子类类型,是则通过,否则运行出错。

版权说明:
本文摘自北京新科海学校-v512工作室(张利国刘伟老师)编著《JavaSE应用程序设计》一书,版权所有,转载请注明出处。

 

相关课程:JAVA软件工程师就业班————7月13日开课




返回首页 | 关于我们 | 联系我们 | 诚聘英才 | 网站地图 | 友情链接 | 版权声明 | 乘车路线| 地铁路线