一.介紹
1.eclipse官方網站:
2.賽迪網
3.Eclipse平臺入門
二.教程
3Plus4 Software
Omondo
Tutorial for building J2EE Applications using JBOSS and ECLIPSE
Getting Started with Eclipse and the SWT
我認為最好的教程還是eclipse軟件自帶的幫助文件(現在有了中文幫助)。
三.插件
三.插件
Eclipse Plugin Resource Center and Marketplace
eclipse-plugins
eclipse-workbench
以上3個網站都是綜合性插件網站,你可以查詢自己所需的插件,而且還有各種排名。
Jigloo SWT/Swing GUI Builder
Lomboz
Matrix網站介紹eclipse plugins
posted @
2005-10-27 12:55 rkind 閱讀(154) |
評論 (0) |
編輯 收藏
一、通過ResultSet對象對結果集進行處理
從前面的學習中,我們掌握了通過Statement類及其子類傳遞SQL語句,對數據庫管理系統進行訪問。一般來說,對數據庫的操作大部分都是執行查詢語句。這種語句執行的結果是返回一個ResultSet類的對象。要想把查詢的結果返回給用戶,必須對ResultSet對象進行相關處理。今天,我們就來學習對結果集的處理方法。
按照慣例,讓我們先來看一個例子:
package com.rongji.demo;
import java.sql.*;
public class dataDemo {
public dataDemo() {
}
public static void main(String[] args) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
//建立連接
//第二步是用適當的驅動程序連接到DBMS,看下面的代碼[自行修改您所連接的數據庫相關信息]:
String url = "jdbc:oracle:thin:@192.168.4.45:1521:oemrep";
String username = "ums";
String password = "rongji";
//用url創建連接
Connection con = DriverManager.getConnection(url, username, password);
Statement sta = con.createStatement();
String sql = "select * from rbac_application ";
ResultSet resultSet = sta.executeQuery(sql);
while (resultSet.next()) {
int int_value = resultSet.getInt(1);
String string_value = resultSet.getString(2);
String a = resultSet.getString(3);
String b = resultSet.getString(4);
//從數據庫中以兩種不同的方式取得數據。
System.out.println(int_value + " " + string_value + " " + a + " " +
b);
//將檢索結果在用戶瀏覽器上輸出。
}
//獲取結果集信息
ResultSetMetaData resultSetMD = resultSet.getMetaData();
System.out.println("ColumnCount:" + resultSetMD.getColumnCount());
for (int i = 1; i < resultSetMD.getColumnCount(); i++) {
System.out.println("ColumnName:" + resultSetMD.getColumnName(i) + " " +
"ColumnTypeName:" +
resultSetMD.getColumnTypeName(i));
System.out.println("isReadOnly:" + resultSetMD.isReadOnly(i)
+ " isWriteable:" + resultSetMD.isWritable(i)
+ " isNullable:" + resultSetMD.isNullable(i));
System.out.println("tableName:" + resultSetMD.getTableName(i));
}
//關閉
con.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
1、ResultSet類的基本處理方法
一個ResultSet對象對應著一個由查詢語句返回的一個表,這個表中包含所有的查詢結果,實際上,我們就可以將一個ResultSet對象看成一個表。對ResultSet對象的處理必須逐行進行,而對每一行中的各個列,可以按任何順序進行處理。
ResultSet對象維持一個指向當前行的指針。最初,這個指針指向第一行之前。Result類的next()方法使這個指針向下移動一行。因此,第一次使用next()方法將指針指向結果集的第一行,這時可以對第一行的數據進行處理。處理完畢后,使用next()方法,將指針移向下一行,繼續處理第二行數據。next()方法的返回值是一個boolean型的值,該值若為true, 說明結果集中還存在下一條記錄,并且指針已經成功指向該記錄,可以對其進行處理;若返回值是false,則說明沒有下一行記錄,結果集已經處理完畢。
在對每一行進行處理時,可以對各個列按任意順序進行處理。不過,按從左到右的順序對各列進行處理可以獲得較高的執行效率.ResultSet類的getXXX()方法可以從某一列中獲得檢索結果。其中XXX是JDBC中的Java數據類型,如int, String ,Date等,這與PreparedStatement類和CallableStatement類設置SQL語句參數值相類似。 Sun公司提供的getXXX() API提供兩種方法來指定列名進行檢索:一種是以一個int值作為列的索引,另一種是以一個String對象作為列名來索引。大家可以參照一下上面的例子。
2、獲取結果集的信息
在對數據庫的表結構已經了解的前提下,可以知道返回的結果集中各個列的一些情況,如:列名數據類型等等。有時并不知道結果集中各個列的情況,這時可以使用Resultset類的getMetaData方法來獲取結果集的信息。如上面的例子:
ResultSetMetaData resultSetMD = resultSet.getMetaData();
GetMetaData()方法返回一個ResultSetMetaData類的對象,使用該類的方法,得到許多關于結果集的信息,下面給出幾個常用的方法:
(1) getColumnCount()返回一個int值,指出結果集中的列數。
(2) getTableName(int column)返回一個字符串,指出參數中所代表列的表的名稱。
(3) getColumnLabel(int column)返回一個String對象,該對象是column所指的列的顯示標題。
(4) getColumnName(int column)返回的是該列在數據庫中的名稱。可以把此方法返回的String對象作為Resultset類的getXXX()方法的參數。不過,并沒有太大的實際意義。
(5) getColumnType(int comlumn)返回指定列的SQL數據類型。他的返回值是一個int值。在java.sql.Types類中有關于各種SQL數據類型的定義。
(6) getColumnTypeName(int comlumn)返回指定列的數據類型在數據源中的名稱。他的返回值是一個String對象。
(7) isReadOnly(int column) 返回一個boolean值,指出該列是否是只讀的。
(8) isWriteable(int column) 返回一個boolean值,指出該列是否可寫。
(9) isNullable(int column)返回一個boolean值,指出該列是否允許存入一個NULL 值。
posted @
2005-10-27 12:53 rkind 閱讀(166) |
評論 (0) |
編輯 收藏
Java和SQL各自有一套自己定義的數據類型(jsp的數據類型實際上就是Java的數據類型),我們要在Jsp程序和數據庫管理系統之間正確的交換數據,必然要將二者的數據類型進行轉換。先讓我們來看兩個表:
表SQL到Java數據類型影射表
SQL 數據類型
JAVA數據類型
CHAR
String
VARCHAR
String
LONGVARCHAR
String
NUMERIC
java.math.BigDecimal
DECIMAL
java.math.BigDecimal
BIT
Boolean
TINYINT
Byte
SMALLINT
Short
INTEGER
Int
BIGINT
Long
REAL
Float
FLOAT
Double
DOUBLE
Double
BINARY
byte[]
VARBINARY
byte[]
LONGVARBINARY
byte[]
DATE
java.sql.Date
TIME
java.sql.Time
TIMESTAMP
java.sql.Timestamp
Java到SQL數據類型影射表
JAVA數據類型
SQL 數據類型
String
VARCHAR or LONGVARCHAR
java.math.BigDecimal
NUMERIC
Boolean
BIT
Byte
TINYINT
Short
SMALLINT
Int
INTEGER
Long
BIGINT
Float
REAL
Double
DOUBLE
byte[]
VARBINARY or LONGVARBINARY
java.sql.Date
DATE
java.sql.Time
TIME
java.sql.Timestamp
TIMESTAMP
這里,大伙要注意了,并不是所有的數據類型在各種數據庫管理系統中都被支持。下面,就幾種常用的數據類型之間的轉化進行說明:
(1) CHAR, VARCHAR, 和 LONGVARCHAR
在SQL語言中,有三種分別表示不同長度的字符類型CHAR, VARCHAR, 和 LONGVARCHAR,在Java/Jsp中并沒有相應的三種不同的數據類型與之一一對應,JDBC的處理方法是將其與String或者char[]對應起來。在實際編程中不必對著三種SQL數據類型進行區分,全部將他們轉化為Sting或者char[]就可以了。而且通常使用應用的非常普遍的String類型。我們還可以利用String類提供的方法將一個String對象轉化為char[],或者用char[]為參數構造一個Stirng對象。
對于定長度的SQL數據類型CHAR(n),當從數據庫管理系統中獲得的結果集提取該類型的數據時,JDBC會為其構造一個長度為n的String對象來代表他,如果實際的字符個數不足’n’,系統會自動為String對象補上空格。當向數據庫管理系統寫入的數據類型應該是CHAR(n)時,JDBC也會將該String對象的末尾補上相應數量的空格。
一般情況下,CHAR, VARCHAR, LONGVARCHAR和String之間可以無差錯的進行轉換。但非常值得注意的是LONGVARCHAR,這種SQL的數據類型有時在數據庫中代表的數據可能有幾兆字節的大小,超過了String對象的承受范圍。JDBC解決的辦法是用Java的Input Stream來接受這種類型的數據[以后我們回涉及到]。Input Stream不僅支持ASCII,而且支持Unicode,我們可以根據需要進行選擇。
(2) DECIMAL 和 NUMERIC
SQL的DECIMAL 和 NUMERIC通常用來表示需要一定精度的定點數。在Java的簡單數據類型中,沒有一種類型與之相對應。但從JDK1.1開始,Sun公司在java.math.*包中加入了一個新的類BigDecimal,該類的對象可以與DECIMAL 、NUMERIC進行轉換。
另外,當從數據庫管理系統中讀取數據時,還可以用getString()方法來獲取DECIMAL 和 NUMERIC。
(3) BINARY, VARBINARY, 和 LONGVARBINARY
在編程時無須精確區分這三種SQL數據類型,JDBC將他們統一影射為byte[]。其中LONGVARBINARY和LONGVARCHAR相似,可以代表幾兆字節的數據,超出數組的承受范圍。解決的辦法依然是用Input Stream來接受數據。
(4) BIT
代表一個二進制位的BIT類型被JDBC影射為boolean型。
(5) TINYINT, SMALLINT, INTEGER, 和 BIGINT
SQL語言的TINYINT, SMALLINT, INTEGER, 和 BIGINT分別代表8位、16位、32位、64位的數據。他們分別被影射為Java的byte, short, int, 和 long
(6) REAL, FLOAT, 和 DOUBLE
SQL定義了REAL, FLOAT, DOUBLE來支持浮點數。JDBC將REAL影射到Java的float,將FLOAT,DOUBLE影射到java的double。
(7) DATE, TIME, 和 TIMESTAMP
SQL定義了三種和日期相關的數據類型。 DATE代表年、月、日,TIME代表時、分、秒,TIMESTAMP結合了DATE和TIME的全部信息,而且增加了更加精確的時間計量單位。
在java的標準類庫中,java.util.*包中的Date類用來表示日期和時間。但是該類和SQL中的DATE, TIME, 和 TIMESTAMP直接影射關系并不清晰。并且,該類也不支持TIMESTAMP的精確時間計量單位。因此,Sun公司在java.sql.*中為java.util.Date增加了三個子類:java.sql.Date,java.sql.Time ,java.sql.Timestamp,分別與SQL中的三個日期數據類型相對應。
總之,關于SQL與JAVA之見數據類型的轉化,還有很多細節方面的東西,這里就不一一介紹了,有需要的朋友自己可以去查一下相關文檔。這里給大家介紹一個我常去的網站:
http://java.sun.com/docs/books/tutorial/jdbc。
posted @
2005-10-27 12:52 rkind 閱讀(307) |
評論 (0) |
編輯 收藏
二、通過PreparedStatement對象訪問數據庫
前面,我們討論了用連接對象Connection產生Statement對象,然后用Statement與數據庫管理系統進行交互。Statement對象在每次執行SQL語句時都將該語句傳遞給數據庫。在多次執行同一語句時,這樣做效率較低。解決這個問題的辦法是使用PreparedStatement對象。如果數據庫支持預編譯,可以在創建PreparedStatement對象時將SQL語句傳遞給數據庫做預編譯,以后每次執行這個SQL語句時,速度就可以提高很多。如果數據庫不支持預編譯,則在語句執行時,才將其傳給數據庫。這對于用戶來說是完全透明的。
PreparedStatement對象的SQL語句還可以接受參數。在語句中指出需要接受那些參數,然后進行預編譯。在每一次執行時,可以將不同的參數傳遞給SQL語句,大大提高了程序的效率與靈活性。一般情況下,使用PreparedStatement對象都是帶輸入參數的。
為了更好的理解,請看下面這個例子:
package com.rongji.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
public class DataConn {
public DataConn() {
}
public static void main(String[] args) {
try
{
//加載驅動程序
//下面的代碼為加載JDBD-ODBC驅動程序
Class.forName("oracle.jdbc.driver.OracleDriver");
//建立連接
//第二步是用適當的驅動程序連接到DBMS,看下面的代碼[自行修改您所連接的數據庫相關信息]:
String url="jdbc:oracle:thin:@192.168.4.45:1521:oemrep";
String user = "ums1";
String password = "rongji";
//用url創建連接
Connection con=DriverManager.getConnection(url,user,password);
//當前的表中有如下幾個字段:ID,NAME,PASSWORD,TEXT,NOTE
PreparedStatement insertStatement = con.prepareStatement(
"INSERT INTO rbac_application values(?,?,?,?,?)");
insertStatement.setInt(1,10);
insertStatement.setString(2,"thinkersky");
insertStatement.setString(3,"88888");
insertStatement.setString(4,"這是個測試的應用程序");
insertStatement.setString(5,"備注");
int result = insertStatement.executeUpdate();
System.out.println("the result is" + result);
con.close();
}
catch (Exception e)
{
//輸出異常信息
System.err.println("SQLException :"+e.getMessage());
e.printStackTrace();
}
}
}
相信通過這個例子,對PreparedStatement這個類的應用應該有了初步的了解。恩,讓我詳細介紹一下這個例子吧:)
1、 創建一個PreparedStatement對象
PreparedStatement類是Statement類的子類。同Statemetn類一樣,PreparedStatement類的對象也是建立在Connection對象之上的。如下所示:
PreparedStatement insertStatement = con.prepareStatement(
"INSERT INTO rbac_application values(?,?,?,?,?)");
創建該PreparedStatement對象時,相應的插入記錄的SQL語句已經被傳遞到數據庫管理系統中進行預編譯。
2、 為PreparedStatement對象提供參數
如果以帶輸入參數的SQL語句形式創建了一個PreparedStatement對象(絕大多數情況下都是如此)。在SQL語句被數據庫管理系統正確執行之前,必須為參數(也就是SQL語句中是’?’的地方)進行初始化。初始化的方法是調用PreparedStatement類的一系列setXXX()方法。如果輸入參數的數據類型是int型,則調用setInt()方法;如果輸入參數是String型,則調用setString()方法。一般說來,Java中提供的簡單和復合數據類型,都可以找到相應的setXXX()方法。
現在,讓我們再回頭看看我們例子中對幾個參數的初始化情況:
insertStatement.setInt(1,10);
insertStatement.setString(2,"thinkersky");
insertStatement.setString(3,"88888");
insertStatement.setString(4,"這是個測試的應用程序");
insertStatement.setString(5,"備注");
這里,setXXX()方法一般有兩個參數,第一個參數都是int型,該參數指示JDBC PreparedStatement對象的第幾個參數將要被初始化。第二個參數的值就是PreparedStatemetn將要被初始化的參數取值,數據類型自然也就相同。這里要說明的是當PreparedStatement的一個對象的參數被初始化以后,該參數的值一直保持不變,直到他被再一次賦值為止。
3、 調用PreparedStatement對象的executeUpdate()方法
這里,要清楚PreparedStatement對象的executeUpdate()方法不同于Statement對象的executeUpdate()方法,前者是不帶參數的,其所需要的SQL語句型的參數已經在實例化該對象時提供了。另外,executeUpdate()方法將返回一個整數,這個整數代表executeUpdate()方法執行后所更新的數據庫中記錄的行數。執行完上面的例子,其結果返回為1。那么什么情況下返回0呢?其實啊,當PreparedStatement對象的executeUpdate()方法的返回值是0時。有兩種可能:
(1) 所執行的SQL語句是對數據庫管理系統的記錄進行操作;并且沒有記錄被 更新
(2) 所執行的SQL語句是對數據庫管理系統的表、視圖等對象進行操作的DDL語言,沒有數據記錄被直接修改。
posted @
2005-10-27 12:52 rkind 閱讀(1816) |
評論 (1) |
編輯 收藏
一、通過DatabaseMetaData對象了解數據庫的信息
JSP通過JDBC對數據庫管理系統進行連接以后,得到一個Connection 對象,可以從這個對象獲得有關數據庫管理系統的各種信息,包括數據庫中的各個表,表中的各個列,數據類型,觸發器,存儲過程等各方面的信息。根據這些信息,JDBC可以訪問一個實現事先并不了解的數據庫。獲取這些信息的方法都是在DatabaseMetaData類的對象上實現的,而DataBaseMetaData對象是在Connection對象上獲得的。
按照慣例,讓我們先來看看下面這個例子:
package com.rongji.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.DatabaseMetaData;
public class DataConn {
public DataConn() {
}
public static void main(String[] args) {
try
{
//加載驅動程序
//下面的代碼為加載JDBD-ODBC驅動程序
Class.forName("oracle.jdbc.driver.OracleDriver");
//建立連接
//用適當的驅動程序連接到DBMS,看下面的代碼[自行修改您所連接的數據庫相關信息]:
String url="jdbc:oracle:thin:@192.168.4.45:1521:oemrep";
String user = "ums";
String password = "rongji";
//用url創建連接
Connection con=DriverManager.getConnection(url,user,password);
//獲取數據庫的信息
DatabaseMetaData dbMetaData = con.getMetaData();
//返回一個String類對象,代表數據庫的URL
System.out.println("URL:"+dbMetaData.getURL()+";");
//返回連接當前數據庫管理系統的用戶名。
System.out.println("UserName:"+dbMetaData.getUserName()+";");
//返回一個boolean值,指示數據庫是否只允許讀操作。
System.out.println("isReadOnly:"+dbMetaData.isReadOnly()+";");
//返回數據庫的產品名稱。
System.out.println("DatabaseProductName:"+dbMetaData.getDatabaseProductName()+";");
//返回數據庫的版本號。
System.out.println("DatabaseProductVersion:"+dbMetaData.getDatabaseProductVersion()+";");
//返回驅動驅動程序的名稱。
System.out.println("DriverName:"+dbMetaData.getDriverName()+";");
//返回驅動程序的版本號。
System.out.println("DriverVersion:"+dbMetaData.getDriverVersion());
//關閉連接
con.close();
}
catch (Exception e)
{
//輸出異常信息
System.err.println("SQLException :"+e.getMessage());
e.printStackTrace();
}
}
}
通過上面的例子,我們可以看出,DatabaseMetaData類的對象的實現,如下語句
<%
DatabaseMetaData datameta=con.getMetaData();
%>
DatabaseMetaData類中提供了許多方法用于獲得數據源的各種信息,通過這些方法可以非常詳細的了解數據庫的信息。就如我們上面例子中所顯示的幾個信息[其他的方法請讀者參考JDK API中的DatabaseMetaData類]:
getURL()
返回一個String類對象,代表數據庫的URL。
getUserName()
返回連接當前數據庫管理系統的用戶名。
isReadOnly()
返回一個boolean值,指示數據庫是否只允許讀操作。
getDatabaseProductName()
返回數據庫的產品名稱。
getDatabaseProductVersion()
返回數據庫的版本號。
getDriverName()
返回驅動驅動程序的名稱。
getDriverVersion()
返回驅動程序的版本號。
posted @
2005-10-27 12:51 rkind 閱讀(81) |
評論 (0) |
編輯 收藏
JSP調用JDBC API訪問數據庫管理系統是通過以下五個步驟來實現的:
(1)加載特定的JDBC驅動程序
為了與特定的數據源連接,JDBC必須加載相應的驅動程序。這些驅動程序都是通過語句:Class.forName("Driver Name"); 來加載的。這里面有一個小技巧,我們可以在”Driver Name”出填入一系列的驅動程序名稱,例如:“Class.forName("sun.jdbc.odbc.JdbcOdbcDriver:oracle.jdbc.driver.OracleDriver”); 中間用冒號隔開。JSP將按照列表順序搜索驅動程序,并且加載第一個能與給定的URL相連的驅動程序。在搜索驅動程序列表時,JSP將跳過包含不可信任代碼的驅動程序,除非他與要打開的數據庫管理系統是來源于同一處.
(2)用已注冊的驅動程序建立到數據庫管理系統的連接
我們要做的第二步是用已經注冊的驅動程序建立到數據庫管理系統的連接,這要通過DriverManager類的getConncetion方法來實現。這里特別需要注意的是String類型 url 參數的取值,url代表一個將要連接的特定的數據庫管理系統的數據源。使用不同的數據庫驅動程序,url的取值方式是不同的。例程中加載了“com.mysql.jdbc.Driver”驅動,url的取值方式“jdbc:mysql://localhost:3306/ums_db?useUnicode=true&characterEncoding=GB2312”,如果加載“oracle.jdbc.driver.OracleDriver”驅動,url的取值方式應該是“jdbc:oracle:thin:@host name:port number:service name”。其他驅動程序的url的取值方式,各位自行參閱相應的文擋。
例程中的GetConnection()方法只有一個參數String url,代表ODBC數據源,如果連接大型數據庫,則需要三個參數:String url、Strng user、String password。User和password代表數據庫管理系統的用戶名和口令。一般的大型數據庫如Oracle、MS SQL Server、DB2等用戶名和口令是必須的。而小型的數據庫如ACCESS、Foxpro等并不需要。
如果連接成功,則會返回一個Connection類的對象con。以后對數據庫的操作都是建立在con對象的基礎上的。GetConnection()方法是DriverManager類的靜態方法,使用時不用生成DriverManager類的對象,直接使用類名DriverManager就可以調用。
(3)創建Statement聲明,執行SQL語句
在實例化一個Connection類的對象con,成功建立一個到數據庫管理系統的連接之后。我們要做的第三步是利用該con對象生成一個Statement類的對象stmt。該對象負責將SQL語句傳遞給數據庫管理系統執行,如果SQL語句產生結果集,stmt對象還會將結果集返回給一個ResultSet類的對象。
Statement類的主要的方法有三個:
executeUpdate(String sql)
executeQuery(String sql)
execute(String sql)
executeUpdate(String sql)方法用于執行DDL類型的SQL語句,這種類型的SQL語句會對數據庫管理系統的對象進行創建、修改、刪除操作,一般不會返回結果集。
executeQuery(String sql)方法用于執行一條查詢數據庫的SELECT語句。如果有符合查詢條件的數據存在,該方法將返回一個包含相應數據的ResultSet類對象,否則,該對象的next()方法將返回false。
execute(String sql)方法用于執行一個可能返回多個結果集的存儲過程(Stored Procedure)或者一條動態生成的不知道結果集個數的SQL語句。如果存儲過程或者SQL語句產生一個結果集,該方法返回false.如果產生多個結果集,該方法返回true。我們可以綜合運用Statement類的getResultSet(), getUpdateCount(), getMoreResults()方法來檢索不同的結果集。
服務器對JSP程序進行編譯時,并不對將要執行的SQL語句作語法檢查,只是將其作為一個String對象。只有當客戶端發出HTTP請求,Java虛擬機對Servlet進行解釋執行,將SQL語句傳遞給數據庫管理系統時,才能知道他是否正確。對于錯誤的SQL語句,在執行時會產生SQLExcepion。其實,所有與JDBC操作的JSP語句都與數據庫管理系統及相應的驅動程序有關,是超出JSP的控制范圍的。這些語句只有在實際的解釋執行中才能檢驗出是否能順利執行,因此一定要聲明并捕獲例外:
try{
….
}catch(SQLException e)
{
Sytem.err.println(“SQLException:”+e.getMessage());
}
否則,JSP程序無法被編譯成Servlet。
(4)關閉Statement對象
一個Statement對象在打開后可以多次調用executeQuery(String sql)、executeUpdate(String sql)、execute(String sql)方法來執行SQL語句,與數據庫管理系統進行交互。但一個Statement對象在同一時間只能打開一個結果集,對第二個結果集的打開隱含著對第一個結果集的關閉。如果想對多個結果集同時進行操作,必須創建多個Statement對象,在每個Statement對象上執行SQL語句獲得相應的結果集。
(5)關閉Connection對象
在處理完對數據庫的操作后,一定要將Connection對象關閉,以釋放JDBC占用的系統資源。在不關閉Connection對象的前提下再次用DriverManager靜態類初始化新的Connection對象會產生系統錯誤。而一個已經建立連接的Connection對象可以同時初始化多個Statement對象。對應不同的數據庫管理系統的Connection對象可以初始化Statement對象的個數是不同的。在Oracle中是50個。
posted @
2005-10-27 12:51 rkind 閱讀(190) |
評論 (0) |
編輯 收藏
首先加載mm.mysql2.0.4-bin.jar驅動,并把其加入classpath,注意一定要打開遠程mysql的你的主機的訪問權限
然后編寫如下代碼
String name="org.gjt.mm.mysql.Driver";///加載jdbc driver
String url="jdbc:mysql://172.20.0.73/jilei"; //連接到172.20.0.73上的jilei的mysql數據庫
Class.forName(name),//創建類
con=DriverManager.getConnection(url,"你的username","你的密碼")//創建連接
輸入以下代碼供測試使用
Statement stmt=con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from student";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {
System.out.println("您的第一個字段內容為:"+rs.getString(1));
System.out.println("您的第二個字段內容為:"+rs.getString(2) );
System.out.println("您的第三個字段內容為:"+rs.getString(3) );
}
rs.close();
stmt.close();
con.close();
posted @
2005-10-27 12:49 rkind 閱讀(1055) |
評論 (0) |
編輯 收藏
孔子說:“學而不思則罔,思而不學則殆?!睆奈易鲰椖康慕洑v,我深深感嘆古人的智慧。
去年我畢業設計時候做的一個項目是畢業設計管理系統。當時老師給我們的要求是用Jsp 和 Javabean來實現。我主要負責項目建模和Javabean部分,后來負責數據庫的同學被SARS困在家不能返校,所以數據庫部分也由我來完成了。當時對java的知識是非常貧乏的,只有簡單的語法基礎,連jsp、 javabean都是第一次聽到過。不知道從哪里開始,于是就研究老師給的一個非常簡單的演示項目,首先覺得javabean是個比較簡單的東西,于是就先開始分析用戶需求。
需求怎么來描述呢?由于學校教育的局限,加上自己研究了很長時間高數,政治,英語(干什么用大家都明白吧),造成了知識的嚴重匱乏。我就以參加畢業設計人員為中心,建立他們的需求列表。但是這樣的需求描述是非常片面的,幾乎都是靜態的需求,而且很難設計幾個用戶的交互過程,和某些狀態的改變。而且這種需求是否有真正符合需要是個問題,所以我立刻和同學一起設計web界面,目的很簡單,因為用戶的需求都是通過界面來實現的,對界面的設計能涵蓋最終提交用戶的功能,而且還能發掘很多非用戶的需求。這樣我在實現這些功能的時候會有數。在一年后當我仔細看過用例分析,uml后感覺是如獲至寶。心頭的結全部打開。
建模該怎么建?當時真是什么概念都沒有,雖然知道uml,但是僅僅知道皮毛。于是我就很簡單的從對象的角度考慮問題,首先找畢業設計管理系統中涉及的人員,這個是很明顯找出來的,涉及到學生,教師,管理員,進一步提取出項目對象,各個人員之間通訊的消息對象,畢業設計文檔對象,等等。接下來設計數據庫表,由于學校教數據庫的時候只有講述了ER圖到關系模式的轉化,而根本沒有講ODL到關系模式的轉化(現在看來,ODL應該更好,對理解O/R Mapping有更多的幫助。)于是就畫ER圖,建立各種表,設定主鍵,外鍵,等等。
我遇到的首要問題就是學生,教師,管理員該怎么辦,每一個對象建一個表,似乎也沒有什么問題。但是在建立消息對象的時候就有問題了,因為消息是要在學生,教師,管理員任意兩者都能傳送的,我建消息表的時候是這樣設計的:一個消息的內容,消息的發送人,消息的接收人(消息內容和發送人一個表,為解決冗余接收人單獨一個表),這樣這個消息就有很大的靈活程度了,消息發送人可以是三種角色間的隨便一種,更進一步,這樣的消息可以是系統生成的消息,而且接收者可以是隨便哪種角色。但隨之帶來的問題是:消息發送人、接收者該去參照誰呢?顯然填一個發送者、接收者的id是不夠的,必須連發送者的角色也填上。第二種方法,每個角色有一個收到消息的列表,讓它去參照單一的消息表id,這樣也能解決問題。第三種方法,把學生,教師,管理員合并成一個用戶表,那么消息發送人,接收人只要簡單的參照一個通用的用戶id了。這種合并子類的方法會造成教師,管理員的行有些null值,但是考慮到教師和管理員的數目遠遠小于學生的數目,所以這樣的冗余是忽略不計的。最后我還是選擇了最后一種方法。不過我還是覺的是對象模型向關系模型的一種妥協。
接著我著手設計javabean,訪問數據庫用的是單純的JDBC。因為我對前臺界面要訪問一個對象的哪些屬性是不了解的,事實上也不該了解。所以我只能從數據庫取出一個完整的對象,讓他來決定究竟要訪問哪些屬性。而且對對象的修改也是這樣,前臺修改好新的對象的屬性,我來進行更數據庫的同步。于是我的javabean就出現了這樣的方法:load()、 store()、 update()、delete()這樣的對象和數據庫表同步的方法。這在一年后的今天看來,實際上我已經自己做了一個O/R Mapping的工作了。當時自己做這樣的O/R Mapping是相當痛苦的事情,而且用的方法也是最粗淺的,就是整個對象更數據庫同步,即使沒有修改的屬性也同步,所以要同步的話,必須要先把對象從數據庫取出來,修改后再寫回。而且要求所有屬性必須是nullable的non-primitive類型。第二個問題,對表中的外鍵怎么反應到bean中?比如每個學生有一個輔導教師,在數據庫中很明顯學生表需要一個外鍵參照教師id,但是在StudentBean中教師屬性是寫Teacher對象呢,還是Teacher id值呢,按照面向對象,很明顯應該Teacher對象,但是我就覺得這是個多么heavy的事情呀!再想想教師情況,一個教師有一個Collection的Student對象是多么“重”!意味著load一個教師要load所有的students。于是我采用的方法是:還是用對象,比如teacher 的學生屬性,還是一個collection Student對象,同時提供了一個loadStudents()的方法,load teacher對象的時候并不load 學生屬性,只有bean的用戶顯式調用loadStudents()的時候才會加載一組student對象,這在現在看來似乎我自覺不自覺的實現了lazy loading?
現在審視當時編寫的javabean,犯的最大最大的錯誤就是把data access object和business workflow混在一起了。比如把教師所有要調用的功能都放在教師對象里面,而有些功能有時是要涉及幾個bean的?,F在看了簡直是慘不忍睹的設計,雖然當時也困惑過,但是卻沒有動動腦筋來解決,我現在看了session bean 的思路時,覺得是那么的舒暢、自然。
當時困惑的還有關于jsp的處理,jsp只是負責顯示的,但是為什么一個jsp提交的數據要給另外一個jsp去處理呢?這是很不舒暢的做法,于是有了最初的servlet做控制器的想法,但是當時顧不了研究那么多,也沒有最終實現,畢竟前臺不是我負責的。當我現在知道了Structs,MVC Model2的時候,我以前的困惑都隨之解決。又一次感覺非常舒暢。
以上是我一個新手的第一個項目的一些情況,是在非常閉塞的環境里面做的,上網都是電話卡撥號,根本沒有接觸到主流技術,但是正是這種環境下積累的無數困惑,使我遇到EJB、Hibernate、Structs的時候如飲甘露,迅速的吸收了他們的營養。否則我想學習這些技術無疑是很耗時間的,因為根本沒有更這種技術產生共鳴,不知道他們搞那么多框框究竟想干什么,而我產生了一種共鳴,他們這些框框,正是開我心頭疑惑的鎖。
又回到開頭孔子的話,事實上我在做項目中,一直都是按自己的思考方式在“思”而沒有去“學”,所以常常感到疲倦而無所得,即“殆”。但是如果不實際自己去動手做,而光光學j2ee,必然會很迷惑,即“罔”。我感覺先有困惑再有解決,是掌握技術的十分有效的而且鞏固的方法,而且很有創造性,是屬于歸納的思考方式。所以碰到問題,首先需要想想按常理該怎么去解決,再去尋找別人怎么解決的,這樣自己提高會十分迅速。
現在我正在用EJB、Structs來重寫那個項目。雖然我對整個需求已經相當清楚,畢竟有了第一個項目作為原型,但是我還是試圖使用比較規范的方法來設計。首先分析了很多use case,并且使用Rational的RequisitePro來跟蹤需求的變化。接著又使用Rose對use case畫了use case diagram。對關鍵對象交互過程畫了 sequence diagram,對某些對象的狀態畫了state diagram。最后很自然的導出了最重要的class diagram。
我現在最大的困惑在Entity Bean上面,建模的時候很自然會有一個User對象,Student, Teacher, Manager 對象繼承自這個User對象。那數據庫表怎么設計呢?第一種,三個對象三個表,對應StudentBean TeacherBean ManagerBean三個EntityBean。第二種,三個對象一個表,只有一個UserBean。第三種,把User單獨一個對象,那么就是四個對象四個表,這樣一個子對象,要映射兩張表EntityBean不行吧。
暫時不管究竟用什么設計,來考察一下文檔對像DocBean,我們主要看看它的cmr部分,一個cmr是author 屬性,它應該是三種角色對象中的一種,問題來了,如果三個對象三個表,那么我這里的cmr怎么寫?
public abstract StudentLocal getAuthor(); ?
public abstract TeacherLocal getAuthor(); ?
public abstract ManagerLocal getAuthor(); ?
考察第二種,三個對象一個表,只有一個UserBean。那這個是相當簡單的只需要
public abstract UserLocal getAuthor();
那最后只有第二種方式才能解決問題,就是只有一個User對象,于是我為了使用EntityBean不得不對我的模型進行修改,把原來清晰的三個對象揉合到一起,雖然說以后某個student變成了teacher 或者manager可以很方便的升級,但是這種情況在我這個例子里面是很少有的,而且數據庫這種合并子類的方法給teacher,manager形成了很多的null值,雖然這是忽略不計的,但是總不是優雅的做法,最關鍵的是我的對象模型又一次向關系模型妥協了。
CMR的另外一個問題是,要CMR必須把所有相關的Bean放一個包里面,在一個xml文件里面配置,我的項目里面的entity bean都是要更user有關系的,那我都需要把這些bean打成一個包,用一個xml描述!我的還是小項目,如果一個項目有100個entity bean,這些entity bean都是相互關聯的,那我要把這100個entity bean放在打成一個包,用一個xml配置!那這個xml文件該有多長!一個小小的錯誤全部完蛋。
看來Entity Bean確實如很多人說的那樣不是十分靈活,我也開始傾向于用hibernate來做持久化了,但是我需要有足夠的靈活性,我想繼承和多態的支持還是很重要的,這樣才能真正是“object-oriented domain models”方式,而不是以數據庫表為中心的方式,引用Hibernate的一句話“Hibernate may not be the best solution for data-centric applications that only use stored-procedures to implement the business logic in the database, it is most useful with object-oriented domain models and business logic in the Java-based middle-tier”
我對AOP也是十分關注,因為它實在是太激動人心的概念了,有了AOP那么我們還要容器干什么,容器的功能完全可以通過AOP來實現,就像Spring框架,除了沒有分布式外幾乎都能支持吧。而jboss4.0也已經通過AOP實現了??疾煳业捻椖?,我發現有一個這樣的需求需要滿足,就是:在執行某些business logic之前必須要檢測對這個方法的調用是否超過期限了,比如學生去選擇研究課題,如果選擇過了就不能再次選擇,雖然這個方法可以由前臺很簡單的解決,但是我覺得在業務邏輯層防止這種行為的發生是業務完整性的一個部分。而通過AOP,把這樣一個很多方法都要調用的公共功能作為一個aspect是很好的。我的問題是在容器中運行的EJB能夠用AOP嗎?在Jboss4.0里面各種EJB都是通過AOP方式來提供服務的,似乎我自己多加一層業務層面的服務應該是可行的(使用jboss aop),但是這樣的EJB放在別的容器里面運行會怎么樣?會影響到容器對EJB的干預嗎?請各位前輩指點。
posted @
2005-10-27 12:48 rkind 閱讀(154) |
評論 (0) |
編輯 收藏
在這里我談談我在學習J2EE流程,并談到在此過程中領會的經驗和教訓。以便后來者少走彎路。
Java發展到現在,按應用來分主要分為三大塊:J2SE,J2ME和J2EE。這三塊相互補充,應用范圍不同。
J2SE就是Java2的標準版,主要用于桌面應用軟件的編程;
J2ME主要應用于嵌入是系統開發,如手機和PDA的編程;
J2EE是Java2的企業版,主要用于分布式的網絡程序的開發,如電子商務網站和ERP系統。
先學習J2SE
要學習J2EE就要先學習J2SE,剛開始學習J2SE先建議不要使用IDE,然后漸漸的過渡到使用IDE開發,畢竟用它方便嘛。學習J2SE推薦兩本書,《java2核心技術一二卷》,《java編程思想》,《java與模式》。其中《java編程思想》要研讀,精讀。這一段時間是基本功學習,時間會很長,也可能很短,這要看學習者自身水平而定。
不要被IDE糾纏
學習java和J2EE過程中,你會遇到五花八門的IDE,不要被他們迷惑,學JAVA的時候,要學語言本身的東西,不要太在意IDE的附加功能,JAVA編程在不同IDE之間的轉換是很容易的,過于的在意IDE的功能反而容易耽誤對語言本身的理解。目前流行的IDE有jbuilder,eclipse和eclipse的加強版WSAD。用好其中一個就可以了,推薦從eclipse入手J2EE。因為Jbuilder更適合于寫J2SE程序。
選擇和學習服務器使用配置
當你有了J2SE和IDE的經驗時,可以開始J2EE的學習了,web服務器:tomcat,勿庸置疑,tomcat為學習web服務首選。而應用服務器目前主要有三個:jboss、weblogic、websphere。有很多項目開始采用jboss,并且有大量的公司開始做websphere或weblogic向jboss應用服務器的移植(節省成本),這里要說的是,學習tomcat和jboss我認為是首選,也是最容易上手的。
學習服務器使用配置最好去詢問有經驗的人(有條件的話),因為他們或許一句話就能解決問題,你自己上網摸索可能要一兩天(我就干過這種傻事),我們應該把主要時間放在學習原理和理論上,一項特定技術的使用永遠代替不了一個人的知識和學問。
學習web知識
如果你是在做電子商務網站等時,你可能要充當幾個角色,這是你還要學習:
1、html,可能要用到dreamwave等IDE。
2、Javascript,學會簡單的數據校驗,數據聯動顯示等等
J2EEAPI學習
學習J2EEAPI和學習服務器應該是一個迭代的過程。先學習jsp和servlet編程,這方面的書很多,我建立看oreilly公司的兩本《jsp設計》和《java servlet編程》,oreilly出的書總是那么優秀,不得不佩服
。學習jdbc數據庫編程,J2EE項目大多都是MIS系統,訪問數據庫是核心。這本應屬于J2SE學習中,這里拿出來強調一下。學習jndi api,它和學習ejb可以結合起來。學習ejb api,推薦書《精通ejb》。經過上面的這些的學習,大概可以對付一般的應用了。有人說跟著sun公司的《J2EE tutorial》一路學下來,當然也可以。
學習ejb設計模式和看代碼(最重要)
設計模式是練內功,其重要性可以這么說吧,如果你不會用設計模式的話,你將寫出一堆使用了ejb的垃圾,有慢又是一堆bug,其結果不如不用ejb實現(ejb不等于J2EE)。無論學習什么語言,都應該看大量代碼,你看的代碼量不到一定數量,是學不好J2EE的。
目前有很多開源的工程可以作為教材:
jive論壇
petstore sun公司
dune sun公司等等,研讀一個,并把它用到自己的工程中來。
J2EE其他學習
當你漸漸對J2EE了解到一定深度時,你要開始關注當前領域中的一些技術變化,J2EE是一塊百家爭鳴的領域,大家都在這里提出自己的解決方案,例如structs,hiberate,ofbiz等等,學習這些東西要你的項目和目標而定,預先補充一下未嘗不可,但不用涉及太深,畢竟學習原理和理論是最最重要的事。
目前常見J2EEAPI
JavaServer Pages(JSP)技術1.2
Java Servlet技術2.3
JDBC API 2.0
Java XML處理API(JAXP)1.1
Enterprise JavaBeans技術2.0
Java消息服務(JMS)1.0
Java命名目錄接口(JNDI)1.2
Java事務API(JTA) 1.0
JavaMail API 1.2
JavaBeans激活架構(JAF)1.0
J2EE連接器體系結構(JCA)1.0
Java認證和授權服務(JAAS)1.0
posted @
2005-10-27 12:47 rkind 閱讀(164) |
評論 (0) |
編輯 收藏
現在JDK1.4里終于有了自己的正則表達式API包,JAVA程序員可以免去找第三方提供的正則表達式庫的周折了,我們現在就馬上來了解一下這個SUN提供的遲來恩物- -對我來說確實如此。
1.簡介:
java.util.regex是一個用正則表達式所訂制的模式來對字符串進行匹配工作的類庫包。
它包括兩個類:Pattern和Matcher Pattern 一個Pattern是一個正則表達式經編譯后的表現模式。
Matcher 一個Matcher對象是一個狀態機器,它依據Pattern對象做為匹配模式對字符串展開匹配檢查。 首先一個Pattern實例訂制了一個所用語法與PERL的類似的正則表達式經編譯后的模式,然后一個Matcher實例在這個給定的Pattern實例的模式控制下進行字符串的匹配工作。
以下我們就分別來看看這兩個類:
2.Pattern類:
Pattern的方法如下: static Pattern compile(String regex)
將給定的正則表達式編譯并賦予給Pattern類
static Pattern compile(String regex, int flags)
同上,但增加flag參數的指定,可選的flag參數包括:CASE INSENSITIVE,MULTILINE,DOTALL,UNICODE CASE, CANON EQ
int flags()
返回當前Pattern的匹配flag參數.
Matcher matcher(CharSequence input)
生成一個給定命名的Matcher對象
static boolean matches(String regex, CharSequence input)
編譯給定的正則表達式并且對輸入的字串以該正則表達式為模開展匹配,該方法適合于該正則表達式只會使用一次的情況,也就是只進行一次匹配工作,因為這種情況下并不需要生成一個Matcher實例。
String pattern()
返回該Patter對象所編譯的正則表達式。
String[] split(CharSequence input)
將目標字符串按照Pattern里所包含的正則表達式為模進行分割。
String[] split(CharSequence input, int limit)
作用同上,增加參數limit目的在于要指定分割的段數,如將limi設為2,那么目標字符串將根據正則表達式分為割為兩段。
一個正則表達式,也就是一串有特定意義的字符,必須首先要編譯成為一個Pattern類的實例,這個Pattern對象將會使用matcher()方法來生成一個Matcher實例,接著便可以使用該 Matcher實例以編譯的正則表達式為基礎對目標字符串進行匹配工作,多個Matcher是可以共用一個Pattern對象的。
現在我們先來看一個簡單的例子,再通過分析它來了解怎樣生成一個Pattern對象并且編譯一個正則表達式,最后根據這個正則表達式將目標字符串進行分割:
import java.util.regex.*;
public class Replacement{
public static void main(String[] args) throws Exception {
// 生成一個Pattern,同時編譯一個正則表達式
Pattern p = Pattern.compile("[/]+");
//用Pattern的split()方法把字符串按"/"分割
String[] result = p.split(
"Kevin has seen《LEON》seveal times,because it is a good film."
+"/ 凱文已經看過《這個殺手不太冷》幾次了,因為它是一部"
+"好電影。/名詞:凱文。");
for (int i=0; i<result.length; i++)
System.out.println(result[i]);
}
}
輸出結果為:
Kevin has seen《LEON》seveal times,because it is a good film.
凱文已經看過《這個殺手不太冷》幾次了,因為它是一部好電影。
名詞:凱文。
很明顯,該程序將字符串按"/"進行了分段,我們以下再使用 split(CharSequence input, int limit)方法來指定分段的段數,程序改動為:
tring[] result = p.split("Kevin has seen《LEON》seveal times,because it is a good film./ 凱文已經看過《這個殺手不太冷》幾次了,因為它是一部好電影。/名詞:凱文。",2);
這里面的參數"2"表明將目標語句分為兩段。
輸出結果則為:
Kevin has seen《LEON》seveal times,because it is a good film.
凱文已經看過《這個殺手不太冷》幾次了,因為它是一部好電影。/名詞:凱文。
由上面的例子,我們可以比較出java.util.regex包在構造Pattern對象以及編譯指定的正則表達式的實現手法與我們在上一篇中所介紹的Jakarta-ORO 包在完成同樣工作時的差別,Jakarta-ORO 包要先構造一個PatternCompiler類對象接著生成一個Pattern對象,再將正則表達式用該PatternCompiler類的compile()方法來將所需的正則表達式編譯賦予Pattern類:
PatternCompiler orocom=new Perl5Compiler();
Pattern pattern=orocom.compile("REGULAR EXPRESSIONS");
PatternMatcher matcher=new Perl5Matcher();
但是在java.util.regex包里,我們僅需生成一個Pattern類,直接使用它的compile()方法就可以達到同樣的效果:
Pattern p = Pattern.compile("[/]+");
因此似乎java.util.regex的構造法比Jakarta-ORO更為簡潔并容易理解。
3.Matcher類:
Matcher方法如下: Matcher appendReplacement(StringBuffer sb, String replacement)
將當前匹配子串替換為指定字符串,并且將替換后的子串以及其之前到上次匹配子串之后的字符串段添加到一個StringBuffer對象里。
StringBuffer appendTail(StringBuffer sb)
將最后一次匹配工作后剩余的字符串添加到一個StringBuffer對象里。
int end()
返回當前匹配的子串的最后一個字符在原目標字符串中的索引位置 。
int end(int group)
返回與匹配模式里指定的組相匹配的子串最后一個字符的位置。
boolean find()
嘗試在目標字符串里查找下一個匹配子串。
boolean find(int start)
重設Matcher對象,并且嘗試在目標字符串里從指定的位置開始查找下一個匹配的子串。
String group()
返回當前查找而獲得的與組匹配的所有子串內容
String group(int group)
返回當前查找而獲得的與指定的組匹配的子串內容
int groupCount()
返回當前查找所獲得的匹配組的數量。
boolean lookingAt()
檢測目標字符串是否以匹配的子串起始。
boolean matches()
嘗試對整個目標字符展開匹配檢測,也就是只有整個目標字符串完全匹配時才返回真值。
Pattern pattern()
返回該Matcher對象的現有匹配模式,也就是對應的Pattern 對象。
String replaceAll(String replacement)
將目標字符串里與既有模式相匹配的子串全部替換為指定的字符串。
String replaceFirst(String replacement)
將目標字符串里第一個與既有模式相匹配的子串替換為指定的字符串。
Matcher reset()
重設該Matcher對象。
Matcher reset(CharSequence input)
重設該Matcher對象并且指定一個新的目標字符串。
int start()
返回當前查找所獲子串的開始字符在原目標字符串中的位置。
int start(int group)
返回當前查找所獲得的和指定組匹配的子串的第一個字符在原目標字符串中的位置。
(光看方法的解釋是不是很不好理解?不要急,待會結合例子就比較容易明白了)
一個Matcher實例是被用來對目標字符串進行基于既有模式(也就是一個給定的Pattern所編譯的正則表達式)進行匹配查找的,所有往Matcher的輸入都是通過CharSequence接口提供的,這樣做的目的在于可以支持對從多元化的數據源所提供的數據進行匹配工作。
我們分別來看看各方法的使用:
★matches()/lookingAt ()/find():
一個Matcher對象是由一個Pattern對象調用其matcher()方法而生成的,一旦該Matcher對象生成,它就可以進行三種不同的匹配查找操作:
matches()方法嘗試對整個目標字符展開匹配檢測,也就是只有整個目標字符串完全匹配時才返回真值。
lookingAt ()方法將檢測目標字符串是否以匹配的子串起始。
find()方法嘗試在目標字符串里查找下一個匹配子串。
以上三個方法都將返回一個布爾值來表明成功與否。
★replaceAll ()/appendReplacement()/appendTail():
Matcher類同時提供了四個將匹配子串替換成指定字符串的方法:
replaceAll()
replaceFirst()
appendReplacement()
appendTail()
replaceAll()與replaceFirst()的用法都比較簡單,請看上面方法的解釋。我們主要重點了解一下appendReplacement()和appendTail()方法。
appendReplacement(StringBuffer sb, String replacement) 將當前匹配子串替換為指定字符串,并且將替換后的子串以及其之前到上次匹配子串之后的字符串段添加到一個StringBuffer對象里,而appendTail(StringBuffer sb) 方法則將最后一次匹配工作后剩余的字符串添加到一個StringBuffer對象里。
例如,有字符串fatcatfatcatfat,假設既有正則表達式模式為"cat",第一次匹配后調用appendReplacement(sb,"dog"),那么這時StringBuffer sb的內容為fatdog,也就是fatcat中的cat被替換為dog并且與匹配子串前的內容加到sb里,而第二次匹配后調用appendReplacement(sb,"dog"),那么sb的內容就變為fatdogfatdog,如果最后再調用一次appendTail(sb),那么sb最終的內容將是fatdogfatdogfat。
還是有點模糊?那么我們來看個簡單的程序:
//該例將把句子里的"Kelvin"改為"Kevin"
import java.util.regex.*;
public class MatcherTest{
public static void main(String[] args)
throws Exception {
//生成Pattern對象并且編譯一個簡單的正則表達式"Kelvin"
Pattern p = Pattern.compile("Kevin");
//用Pattern類的matcher()方法生成一個Matcher對象
Matcher m = p.matcher("Kelvin Li and Kelvin Chan are both working in Kelvin Chen's KelvinSoftShop company");
StringBuffer sb = new StringBuffer();
int i=0;
//使用find()方法查找第一個匹配的對象
boolean result = m.find();
//使用循環將句子里所有的kelvin找出并替換再將內容加到sb里
while(result) {
i++;
m.appendReplacement(sb, "Kevin");
System.out.println("第"+i+"次匹配后sb的內容是:"+sb);
//繼續查找下一個匹配對象
result = m.find();
}
//最后調用appendTail()方法將最后一次匹配后的剩余字符串加到sb里;
m.appendTail(sb);
System.out.println("調用m.appendTail(sb)后sb的最終內容是:"+ sb.toString());
}
}
最終輸出結果為:
第1次匹配后sb的內容是:Kevin
第2次匹配后sb的內容是:Kevin Li and Kevin
第3次匹配后sb的內容是:Kevin Li and Kevin Chan are both working in Kevin
第4次匹配后sb的內容是:Kevin Li and Kevin Chan are both working in Kevin Chen's Kevin
調用m.appendTail(sb)后sb的最終內容是:Kevin Li and Kevin Chan are both working in Kevin Chen's KevinSoftShop company.
看了上面這個例程是否對appendReplacement(),appendTail()兩個方法的使用更清楚呢,如果還是不太肯定最好自己動手寫幾行代碼測試一下。
★group()/group(int group)/groupCount():
該系列方法與我們在上篇介紹的Jakarta-ORO中的MatchResult .group()方法類似(有關Jakarta-ORO請參考上篇的內容),都是要返回與組匹配的子串內容,下面代碼將很好解釋其用法:
import java.util.regex.*;
public class GroupTest{
public static void main(String[] args)
throws Exception {
Pattern p = Pattern.compile("(ca)(t)");
Matcher m = p.matcher("one cat,two cats in the yard");
StringBuffer sb = new StringBuffer();
boolean result = m.find();
System.out.println("該次查找獲得匹配組的數量為:"+m.groupCount());
for(int i=1;i<=m.groupCount();i++){
System.out.println("第"+i+"組的子串內容為: "+m.group(i));
}
}
}
輸出為:
該次查找獲得匹配組的數量為:2
第1組的子串內容為:ca
第2組的子串內容為:t
Matcher對象的其他方法因比較好理解且由于篇幅有限,請讀者自己編程驗證。
4.一個檢驗Email地址的小程序:
最后我們來看一個檢驗Email地址的例程,該程序是用來檢驗一個輸入的EMAIL地址里所包含的字符是否合法,雖然這不是一個完整的EMAIL地址檢驗程序,它不能檢驗所有可能出現的情況,但在必要時您可以在其基礎上增加所需功能。
import java.util.regex.*;
public class Email {
public static void main(String[] args) throws Exception {
String input = args[0];
//檢測輸入的EMAIL地址是否以 非法符號"."或"@"作為起始字符
Pattern p = Pattern.compile("^\\.|^\\@");
Matcher m = p.matcher(input);
if (m.find()){
System.err.println("EMAIL地址不能以'.'或'@'作為起始字符");
}
//檢測是否以"www."為起始
p = Pattern.compile("^www\\.");
m = p.matcher(input);
if (m.find()) {
System.out.println("EMAIL地址不能以'www.'起始");
}
//檢測是否包含非法字符
p = Pattern.compile("[^A-Za-z0-9\\.\\@_\\-~#]+");
m = p.matcher(input);
StringBuffer sb = new StringBuffer();
boolean result = m.find();
boolean deletedIllegalChars = false;
while(result) {
//如果找到了非法字符那么就設下標記
deletedIllegalChars = true;
//如果里面包含非法字符如冒號雙引號等,那么就把他們消去,加到SB里面
m.appendReplacement(sb, "");
result = m.find();
}
m.appendTail(sb);
input = sb.toString();
if (deletedIllegalChars) {
System.out.println("輸入的EMAIL地址里包含有冒號、逗號等非法字符,請修改");
System.out.println("您現在的輸入為: "+args[0]);
System.out.println("修改后合法的地址應類似: "+input);
}
}
}
例如,我們在命令行輸入:java Email www.kevin@163.net
那么輸出結果將會是:EMAIL地址不能以'www.'起始
如果輸入的EMAIL為@kevin@163.net
則輸出為:EMAIL地址不能以'.'或'@'作為起始字符
當輸入為:cgjmail#$%@163.net
那么輸出就是:
輸入的EMAIL地址里包含有冒號、逗號等非法字符,請修改
您現在的輸入為: cgjmail#$%@163.net
修改后合法的地址應類似: cgjmail@163.net
5.總結:
本文介紹了jdk1.4.0-beta3里正則表達式庫--java.util.regex中的類以及其方法,如果結合與上一篇中所介紹的Jakarta-ORO API作比較,讀者會更容易掌握該API的使用,當然該庫的性能將在未來的日子里不斷擴展,希望獲得最新信息的讀者最好到及時到SUN的網站去了解。
6.結束語:
本來計劃再多寫一篇介紹一下需付費的正則表達式庫中較具代表性的作品,但覺得既然有了免費且優秀的正則表達式庫可以使用,何必還要去找需付費的呢,相信很多讀者也是這么想的:,所以有興趣了解更多其他的第三方正則表達式庫的朋友可以自己到網上查找或者到我在參考資料里提供的網址去看看。
posted @
2005-10-27 12:44 rkind 閱讀(185) |
評論 (0) |
編輯 收藏