blog.Ring.idv.tw

Java

Java連結FoxPro(ODBC)

由於適逢需要利用Java連結Foxpro來操作一些資料庫~

所以找了一下資訊~這裡將利用透過ODBC的方式來連接~

所以我們必須先下載並安裝「Visual FoxPro ODBC Driver」,以便從「系統管理工具」>「資料來源ODBC」來設定~

基本設定方式

1.驅動程式請選「Microsoft Visual FoxPro Driver」

2.Data Source Name,請自定一個識別字串

3.Database type,如果你只有dbf檔案的話,請選「Free Table directory」

4.Path,請填你存放這些dbf檔案的路徑即可

設定之後便可測試一下:

import java.sql.*;
public class JDBCDemo
{
    private PreparedStatement ps;
    private ResultSet rs;
    private Connection conn;
    
    public JDBCDemo()
    {
        try
        {
            Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            conn = DriverManager.getConnection("jdbc:odbc:"+DataSourceName);
            ps = conn.prepareStatement("select * from test");
            rs = ps.executeQuery();
            while(rs.next())
            {
                System.out.println(rs.getString(1));
            }
        } catch (Exception e)
        {
            System.out.print(e);
        }
    }
    public static void main(String args[])
    {
        new JDBCDemo();        
    }
}

2007-08-17 00:55:14 | Add Comment

檔案上傳-「commons fileUpload」

一般我們常見的HTML輸入型態(例如:text、radio、select…)都是使用「application/x-www-form-urlencoded」的編碼方式,但要傳送檔案至伺服端時,編碼方式則是要仰賴「multipart/form-data」,由於兩者的編碼方式不同,所以這裡提供一個「FileUpload」的小範例~

必要的package如下:

commons fileUpload

commons IO

HTML

<%@page language="java" contentType="text/html;charset=utf-8"%>
<html>
<head>
<title>檔案上傳</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<b>檔案上傳</b></font></p>
<form name="UploadForm" enctype="multipart/form-data" method="post" action="fileupload.dan">
    <input type="file" name="File1" size="20" maxlength="20"> <br>
    <input type="text" name="File2" size="20" maxlength="20"> <br>
    <input type="submit"value="上傳">
</form>
</body>
</html>

Servlet

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class FileUpload extends HttpServlet
{
    private String base;
    
    public void init(ServletConfig sc) throws ServletException
    {
        ServletContext sco = sc.getServletContext();
        base = sco.getRealPath("/");
    }
    
    public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
    {   
        boolean isMultipart = ServletFileUpload.isMultipartContent(req);
        try
        {
            if(isMultipart)
            {
                DiskFileItemFactory factory = new DiskFileItemFactory();
                factory.setSizeThreshold(4096);
                factory.setRepository(new File(base+"temp"));
                ServletFileUpload upload = new ServletFileUpload(factory);
                upload.setSizeMax(10000000);
                List items = upload.parseRequest(req);
                Iterator iter = items.iterator();
                while(iter.hasNext())
                {
                    FileItem item = (FileItem) iter.next();
                    if (item.isFormField())
                    {
                        String name = item.getFieldName();
                        String value = item.getString();
                        System.out.println("name:"+name+" value:"+value);
                    } else {
                        String fieldName = item.getFieldName();
                        String fileName = item.getName();
                        String contentType = item.getContentType();
                        boolean isInMemory = item.isInMemory();
                        long sizeInBytes = item.getSize();
                        System.out.println("fieldName:"+fieldName+" fileName:"+fileName);
                        File to = new File(base+"upload",fileName);
                        item.write(to);
                    }
                }
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

2007-08-10 14:52:00 | Comments (2)

Java主題曲~かわいい

Java主題曲

好可愛哦~還是用Flash做出來的呢!~

呵~ 有趣!

2007-06-03 21:59:43 | Add Comment

徹底剖析JDK 5.0 Varargs

本文已刊於「#140  Run!PC 旗標資訊月刊」- 2005.09

自從1995年Java語言誕生到目前為止,已陪伴無數的程式設計人員走過這十年的光陰,尤其憑藉著Write Once, Run Anywhere的口號,便吸引了許多程式開發人員所注目的焦點,當然在這演變的過程之中,Java的版本也進步到了5.0(Tiger),但是不管是大改版或是小改版,要執行Java程式仍然是透過Java虛擬機器(JVM)(註一)去解析Java 位元碼(bytecode)來運作著,進而達成跨平台的實現,此種機制和Macromedia Flash有著異曲同工之處,為何筆者會如此認為呢?其實重點就在於Flash Player就相當於Java執行環境(JRE),而Flash SWF的檔案格式就好比如Java bytecode,兩者均依賴著中介語言來達成跨平台的機制,這也就是本文所要深入探討的重點之一。

本文會透過Java bytecode來剖析Varargs底層真實的面目,來了解這些底層的實作方式,有助於觀念的釐清,對於不管是在開發程式所在乎的效能決策上,或是想考取Java國際認證的朋友們,筆者相信本文都會提供一定的幫助!

何謂Varargs?

在我們開始探討Varargs功能之前,我們先來看一個JDK 5.0 所新增的功能之一 printf,如圖一所示,我們從API Document不難發現到printf方法(method)其實就已經運用Varargs這個新功能了!

圖一. 窺示printf API

Varargs(Variable-Length Argument Lists),從字面上顧名思義我們不難猜到Varargs代表著"變動長度參數列",筆者在這裡可以先向各位讀者透露,其實Varargs底層的處理方式就是陣列,我們稍待會一一來驗證!

開始剖析Varargs

在這裡我們先來看看一個取得字串陣列長度的方法(請參考程式一),可透過反組譯器(註二)來查看底層的bytecode。(請參考圖二)

程式一

public int getStringArrayLength(String arg[])
{
	return arg.length;
}

圖二. getStringArrayLength方法的位元碼

剖析字串陣列的位元碼

從圖二的位元碼裡,我們可以明確地看到public int getStringArrayLength(java.lang.String[]);所定義傳入的參數是「一」個字串陣列,但是為何透過反組譯器所顯示出來的參數長度設定會等於2呢?(Args_size=2)這是因為我們的getStringArrayLength()方法是一個實體方法(instance method),所以第一個參數會以隱含(implicit)的方式傳入「this」,所以第一個參數就代表「this」,第二個參數才是代表字串陣列。

getStringArrayLength 方法的位元碼(bytecode):

0# aload_1 :: 將從區域變數(local variables)的索引位置「1」來載入物件參考(object reference)至Operand Stack。

說明:「在此就是用來取得參考到字串陣列的物件參考,來將它載入至Operand Stack」。

1# arraylength :: 取得陣列的長度。

說明:「會將參考到字串陣列的物件參考(object reference)從Operand Stack取出,並推入一個int整數至Operand Stack,此整數也就代表著陣列的長度」

2# ireturn :: 傳回int值。

說明:「也就是回傳在Operand Stack裡的陣列長度」

剖析Varargs的位元碼

看透了此方法的bytecode之後,我們再來看看Varargs的程式寫法(請參考程式二),然後再一次透過反組譯器來查閱底層的bytecode,我們赫然發現,果然使用Varargs的底層bytecode和使用陣列當參數的底層bytecode居然都是如出一徹地!(如圖二)從這裡我們就已經印證了,Varargs底層的實作方式就是陣列,但是它並不僅僅只是個單純的陣列取代!

程式二

public int getStringArrayLength(String... arg)
{
	return arg.length;
}

Varargs的特性與限制

Varargs仍然擁有屬於它自己的特性與限制:

Varargs允許傳遞零或一個以上相同型態的參數。(請參考程式三)

程式三

public static int getLength(String... arg)
{
	return arg.length;
}
public static void main(String[] arg)
{
	System.out.println("getLength() ==>"+getLength());
	System.out.println("getLength() ==>"+getLength("one","two","thress"));
}

使用Varargs必須放置在該方法的最後一個參數。(請參考程式四)

程式四

public int getLength(String... arg) //#正確
{
	return arg.length;
}
public int getLength(Integer count,String... arg) //#正確
{
	return arg.length;
}
public int getLength(String... arg,Integer count) //#錯誤
{
	return arg.length;
}

一個方法裡最多只能定義一個Varargs。(請參考程式五)

程式五

public int getLength(String... arg) //#正確
{
	return arg.length;
}
public int getLength(String... arg,Integer... count) //#錯誤
{
	return arg.length;
}

既然已知Varargs就是陣列

既然已經了解Varargs的底層就是陣列,所以我們也可以取而代之地將Java程式進入點改成Varargs的形式,而且也仍然可以使用陣列唯一的屬性變數「length」及陣列元素的存取!(請參考程式六)

程式六

public static void main(String... arg)
{
	System.out.println("參數長度:"+arg.length);
	System.out.println("索引值[0] => "+arg[0]);
}

在這裡有一點仍然必須注意一下,在方法多載(Overloading)的使用上,Java允許相同的方法名稱但各自擁有不同的參數列!說到這裡或許有一些讀者已經了解筆者的用意,沒錯!當我們使用陣列及Varargs在相同的方法名稱當參數列會發生什麼情形呢?(請參考程式七)

程式七

public int getLength(String... arg)
{
	return arg.length;
}
public int getLength(String[] arg)
{
	return arg.length;
}

由於Varargs底層也是陣列的緣故,所以這時候就取決於看那一個方法宣告在最前面,以上述的程式碼為例,Java編譯器會告知我們getLength(java.lang.String...) is already defined in Test!

為何需要Varargs的存在?

現在我們換個角度來思考,那為何需要Varargs的存在呢?或許某些讀者會認為底層既然是陣列,那直接使用陣列不就好了!理論上來說是的確可以這麼做,但是既然在JDK 5.0加上Varargs這個功能,必然有它的優勢與存在的必要性,我們來看底下的程式八即可明確地了解Varargs所帶來的好處:

程式八

public static void NonVarargs(String[] str)
{
	for(String s : str)
		System.out.print(s + " ");
	System.out.println();
}
public static void Varargs(String... str)
{
	for(String s : str)
		System.out.print(s + " ");	
	System.out.println();
}
public static void main(String[] arg)
{
	System.out.print("呼叫NonVarargs method:");
	NonVarargs(new String[]{"one","two","three"}); //#1

	System.out.print("呼叫Varargs method:");
	Varargs("one","two","three"); //#2
}

從上列的程式可以看出#2的程式明顯地簡化與簡單,但實際上使用Varargs仍然是透過#1的方式,

也就是說,上列的程式使用Varargs的方式時,便不需要再宣告一個字串陣列,而是透過Varargs去委託Java編譯器去做這層的轉換處理,所以我們只要將原始檔編譯成類別(Class)檔,剩下的就交給Java編譯器自動地去幫我們處理,從這裡就可以看得出來,JDK 5.0 提供了簡化程式設計人員更方便使用的語法,這也就是中介語言所帶來的極大好處之一!

剖析「傳遞零個參數至Varargs」

由於在本文前面有談到Varargs的特性之一「Varargs允許傳遞零或一個以上相同型態的參數」,在此我們直接來測試看看呼叫Varargs()方法會產生什麼樣的變化,請將上述的程式「Varargs("one","two","three"); //#2」 改成「Varargs();」即可,接著利用反組譯器來觀察Java bytecode,在觀察之後我們又可以發現到一項JDK 5.0的改革(如圖三)。

圖三. Varargs方法的部份位元碼

從bytecode之中可以明確地看到,在JDK 5.0之前的Java Compiler會自動地將需要用到串接字串的功能時,它會在底層運用StringBuffer來處理,但是在JDK 5.0之後都將改成StringBuilder來處理串接字串的功能,而由於StringBuilder 不是一個 thread safe 類別,所以在多執行緒的環境下必須注意到JDK 5.0的這項變動。

緊接著筆者就來剖析傳遞零個參數至Varargs時,究竟底層Java Compiler又是處理的呢?(如圖四)

圖四. main 方法的部份位元碼

38# iconst_0 :: 推入一個int整數至Operand Stack。

說明:「代表一個0整數推入到Operand Stack」

39# anewarray :: 建立一個參考型態的新陣列,並從Operand Stack取出一個整數當做陣列的長度,然後將參考到此陣列的arrayref再推入Operand Stack。

說明:「在此會建立一個長度為零的字串陣列」

42# invokestatic :: 呼叫類別(static)方法。

說明:「呼叫Varargs方法,並將字串陣列傳遞進去」

相信許多的讀者閱覽到此都已經豁然開朗了,從這裡我們可以完全地了解底層是如何處理「Varargs允許傳遞零或一個以上相同型態的參數」,簡而言之,上述的程式碼經由Java Compiler編譯之後,會將「Varargs();」看待成「Varargs(new String[0]);」來處理,這就是神奇的地方!^_^

#註一 = Java虛擬機器也可稱為堆疊機器(Stack Machine),表示著JVM底層的實作概念其實就是堆疊。

#註二 = JDK有提供一個javap反組譯器,可用來顯示位元碼(bytecode)。

#參考資料

1.The JavaTM Virtual Machine Specification Second Edition

2. Java 5.0 Tiger: A Developer's Notebook

本文若有任何謬誤,希望請不吝地賜教,若能指正不勝感激。

2007-05-22 21:26:31 | Comments (2)

快速上手 - Lucene

Lucene是一個開放原始碼的資訊檢索函式庫,最初是由 Doug Cutting 利用Java程式實作完成的,它目前是 Apache Software Foundation 底下的計畫之一,由於相當的受到肯定,所以也洐生出其它的程式版本,如:Perl, C#, C++, Python, Ruby and PHP。

建立Index

一個個搜尋檔案的方式,其實是相當耗時且緩慢的,所以我們必須先為我們想要搜尋的文件建立索引,就如同書籍中提供在最後面的索引頁,可以幫助我們更快速的找到我們想要知道的東西。

Step 1:假設我們想要索引的文件放置在「D:\index」

Step 2:切換工作目錄到你的lucene目錄夾,並輸入下列指令

D:\lucene-2.1.0>java -cp .;lucene-core-2.1.0.jar;lucene-demos-2.1.0.jar org.apache.lucene.demo.IndexFiles d:\index

若出現以下類似的訊息即代表已成功索引,並會在此目錄下建立一個「index」的資料夾,底下包含了三個檔案,簡單來說就是已被索引的資訊。

Indexing to directory 'index'...
adding d:\index\Wang.txt
adding d:\index\Apollo.txt
adding d:\index\JavaFX.txt
adding d:\index\Silverlight.txt
Optimizing...
500 total milliseconds

Command搜尋

接著我們要搜尋剛剛被我們索引的那些文件中的內容~請輸入下列指令

D:\lucene-2.1.0>java -cp .;lucene-core-2.1.0.jar;lucene-demos-2.1.0.jar org.apache.lucene.demo.SearchFiles

接著會出現「Query:」的提示字元,你就可以輸入你想要搜尋的資訊囉~

例如:

Searching for: ajax
2 total matching documents
1. d:\index\Silverlight.htm
2. d:\index\Apollo.htm

Web搜尋

位於lucene目錄底下有一個「luceneweb.war」檔,請將它拷貝至你的Application Server的部署目錄下,例如:Tomcat or JBoss 等…

以Tomcat為例,啟動你的Tomcat之後,它會將此檔解壓縮成luceneweb的目錄夾,接著請修改此目錄夾底下的「configuration.jsp」如下所示:

//String indexLocation = "/opt/lucene/index";
String indexLocation = "D:\\lucene-2.1.0\\index";

也就是設定剛剛索引文件的目錄位置即可,最後開啟http://localhost:8080/luceneweb/就開始享受Lucene吧~

2007-05-18 17:56:03 | Add Comment

Next Posts~:::~Previous Posts
Copyright (C) Ching-Shen Chen. All rights reserved.

::: 搜尋 :::

::: 分類 :::

::: Ads :::

::: 最新文章 :::

::: 最新回應 :::

::: 訂閱 :::

Atom feed
Atom Comment