據說很久之前我曾經寫過一個用C#作的郵遞區號查詢程式,這次物件導向程式設計的期末專題當然也想再用Java寫一次囉XD
如果只是單純想查詢郵遞區號或者是看原始碼的話請直接點選下面的連結下載Java版本即可,希望這次的原始碼沒有太多累贅(不得不說用正規表達式處理文字我還不是很熟練XD)
如果不想下載任何程式,小弟也有為了交作業特別使用的Applet版本(因為就是Applet作業啊,科):http://homepage.ntu.edu.tw/~b94103065/Applet/
Applet板和視窗程式版沒有任何差異,就是三個功能(Applet版的憑證會在6個月後自動過期,屆時要用請通知我重簽或是改用視窗程式板)
- 隨打隨查郵遞區號
- 輸出橫式信封,採用Office 2003 XML格式,用Openoffice 3.0或Office 2000以上版本可以打開
- 地圖預覽,可以告訴你要寄的地方「大概」在哪裡(受限於郵局和Google資料庫的緣故,所以不一定很準確)
- 如果發現本系統內帶的資料庫舊了,請自行去郵局網站下載TXT版的資料庫(下載位置:http://www.post.gov.tw/post/internet/down/index.html),程式自帶的是2009/03的版本
正文開始前說明一下,正如同小地方的站長教學一樣(http://unkb.com/other/postcode.htm),這支程式你要是不查詢直接輸出信封一定會發生錯誤,這是因為如果你只打三個字,那勢必不符合3+2郵遞區號規則,所以最起碼必須把查詢到的地址拿來修改比較能讓使用者的輸入邏輯比較,至於為什麼直接輸入「台北市錦州街5號9樓」會找不到,那是因為郵局資料庫是用「錦州街 單15號以下」的樣寫,除非作很複雜的處理,否則希望又快又能夠蒐尋到完整地址是有難度的,也因此如果要這樣找,請先找「台北市錦州街」,在步步進逼就好了,那就麻煩大家了XD
跳轉後是技術文章,不喜慎入,要用程式的話上面的說明或者是小地方的站長教學應該都可以指出該如何使用~
大致上來講就跟C#版本的功能是一模一樣的,但是因為這學期課太多沒時間再處理Java產生信封的事情,所以只作了一個地圖查詢(連接到Google Map),然後和C#版最大的差異就是這個版本完全使用layout manager和郵局提供的檔案(而不是透過SQL轉檔查詢),這當然也不是什麼了不起的事情,但是至少如果有人要用的話,會比較好更新XD(要更新資料檔就點選「載入資料」)
接下來寫一寫開發心得充版面好了XD
- 郵局會更新郵遞區號的檔案XD
- 郵遞區號檔案的下載位置在:http://www.post.gov.tw/post/internet/down/index.html
- 不得不說他整裡的真的很不好,巷和號都混再一起,要作比較好的查詢的話正規表達式寫的沒完囧
- 而且有三種格式,Txt、XML、Excel
- parseXML變成DOM Tree還頗占資源的,在不調整記憶體使用的情況下SAX也沒好到哪裡,最後我乾脆用TXT,反正只是要作搜尋而已
- 因此這支程式不只可以查郵遞區號,有規律一行一行的TXT檔都可以查XD
- 郵遞區號檔案的下載位置在:http://www.post.gov.tw/post/internet/down/index.html
- Applet和一般程式在取用jar檔中檔案的不同(Accessing file in a jar file)
- 在一般的程式中用ClassLoader.getSystemResource("檔名")就可以拿到檔案了
- 在Applet中要用getClass().getResource("檔名")存取檔案,這可能是因為Applet在loadClass的過程不一樣吧~
- JTextField沒有onchange的Event handler
- 所以,如果要偵測JTextField的文字屬性變動,英文的話可以用addKeyListener然後實作KeyListener,但是這樣用IME打字的話會送出太多的Event,這時可能要偵測到底文字內容有沒有變更,有的話再送,我是用addCaretListener然後時作CaretListener,這樣只有在游標移動的時候才會送出event,看起來是比較單純一些
- JavaVM不設定的話是使用的記憶體是固定的(有些人說最大是16M,有些人說是64M),所以會有heap memory overflow!!!
- 即使heap memory overflow這個問題被catch住了也不一定可以解決問題,因為memory overflow的話事情就一定無法完成,所以只有以下兩種方法可以解決
- java -Xmx512m(跟JavaVM說最大請給這支程式512M的記憶體)
- 不過因為交作業不想想一堆說明,後來我乾脆改程式不是郵局的郵遞區號XML檔案了XD
- 即使heap memory overflow這個問題被catch住了也不一定可以解決問題,因為memory overflow的話事情就一定無法完成,所以只有以下兩種方法可以解決
- JTable在Java 1.6(所謂的Java6)之後就有了.net framework的DataTable下的rowfilter
- 主要是實作TableRowSorter(http://java.sun.com/javase/6/docs/api/javax/swing/table/TableRowSorter.html)裡的rowfilter,然後再把Tablerowsorter指定給TableModel,這樣搜尋就完成了
- 但是只有Java 6可以做這件事情,由此可見還得寫字指定JRE的版本也是很麻煩,乾脆自己用Thread寫一個搜尋ArrayList的程式就好了
- 目前我還沒有想到郵遞區號這種沒規率的東西該怎麼parse成比較有規律的tree方便作binary search,所以還是用sequence search,速度看似可以接受
- JLabel裡可以放圖
- C#裡有picturebox之類的元件,在swing架構下是用類似C#裡的Textbox的JLable來放圖,setIcon就可以了
- layout manager還蠻好玩的
- 這個小程式裡主要用了兩個layout,一個是card layout,他的用處就是把所有指定要用他的物件都「折疊」起來,就跟撲克牌一樣
- 另外一個是GridBagLayout,這個Layout功能比一開始上課都會介紹的boxlayout這些都強大很多,但是一定要注意他有一個weightx、weighty的「權值」屬性,一定要輸入,用setSize調整大小也是沒用的(這算是layout managet的常識XD),如果用預設值就跟沒用layout差不多
- layout manager可以參考Sun的介紹(http://java.sun.com/docs/books/tutorial/uiswing/layout/index.html)
- swing可以改變look ‘n feel
- 但是很麻煩!如果是要改用Windows的look ‘n feel的話要用這樣的敘述:UIManager.setLookAndFeel(new com.sun.java.swing.plaf.windows.WindowsLookAndFeel());,然後記得try … catch住
- 詳細說明和可以使用的look ‘n feel在Sun有介紹(http://java.sun.com/docs/books/tutorial/uiswing/lookandfeel/plaf.html)但是不同平台的介面是不可能跨平台使用的
- Thread.stop已經被廢棄了
- 很明顯,雖然現在可以用,可以參考API手冊(http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Thread.html)
- 所以如果要中止一個Thread,可以用thread.interrupt來完成,當然建議(http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html)看起來是用Runnable裡面實作叫,發現該停的時候就自動結束,不過他也有建議用thread.interrupt來完成,記得要try…catch起來
- jar
- 把一堆class打包成jar很簡單(http://caterpillar.onlyfun.net/Gossip/JavaGossip-V2/ExecutableJAR.htm),然後如果要在jar包裡增加其他的檔案類型也很簡單,因為他就是一個ZIP
- 所以如果是要用jar包裡面的資源,必須要使用以下的方法:ClassLoader.getSystemResource("檔名"),classloader的API說明中也有寫(http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ClassLoader.html)
- 這樣的話代表我原本用String當作xmlfile檔名的型別就不大妥當,因為getSystemResource會回傳URL這個型別,但是JFilechooser.getSelectedFile().getAbsolutePath()回傳的是String
- 只能用URL當作xmlfile這個存檔名的變數的型別,JFilechooser回傳的檔案乾脆就用一個JFilechooser.getSelectedFile.toURL().toURL()把他給包起來
- 把Java轉換成程式
- 有Native compiler,這點比.net framework好(意思是執行速度可能會快一點點,然後「綠色軟體」人見人愛),Native compiler有JNC之類的(http://jnc.mtsystems.ch/)
- 因為不想喪失Java的跨平台特性,所以針對視窗程式版本我是把jar弄好之後用JSmooth(http://jsmooth.sourceforge.net/)來wrapper jar,讓他變成exe,不得不說JSmooth還蠻好用的
- 但是和C#那種一寫好就是exe,實在不能比啊,科
- JFrame的Icon不是ico檔
- 這點還蠻奇怪的,setIcon裡放的得是一個Image物件,但是Toolkit.getDefaultToolkit().getImage好像不能讀入ico檔,可能是不同程式語言特性不同吧~
- Applet寫好之後就很容易移植到視窗程式
- 當然可能是這個程式沒有很複雜
- 不過主要就是叫Class不要再Extends applet,this.add改成JFrame.getContentPane()(當然得先增加一個JFrame),最後就是寫一個main method和class來呼叫原本作applet用的那個class(因為static method不能存取non-static變數、方法)
- 當然可能是這個程式沒有很複雜
- Java的XML parser
- 講到這個就心酸了,因為我不想再import什麼PDF、ODF的package,但是我也不希望把信封輸出成圖檔(就不能改了),所以選了Office 2003XML格式
- 但是,用C#作XMLDocument.load都很正常,輕鬆愉快幾分鐘就搞定了,Java對同一個檔案完全不是這樣,一直都回傳null,經過兩個小時的奮戰之後,我放棄了Orz
- 應該是缺少DTD的緣故,但是用了網路上說的實作EntityResolver()也沒效果,反正我也沒有要新增行,只是要照表填入而已,就算了吧Orz
- 如果是不同一份XML,一份有DTD的就可以正常載入,沒有DTD的就回傳null…Orz
- Applet有權限
- Applet不能存取IO、網路(在本地端執行的話)等東西,主要是Security Manager限制的,可以參考這篇文章(http://www.javaworld.com.tw/jute/post/view?id=71700&sty=1&bid=29&tpg=1&age=0&ppg=1)
- 在這篇文章(http://jeffreyjc.pixnet.net/blog/post/13970514)裡有教jarsigner的用法,或者是ptt的java版精華區(按z)的5-2-4篇有教學,5-2-8篇有原理,要注意keytool.exe產生的key是在user.home下面的,這要自己找一下,或者是執行以下敘述「System.out.print(System.getProperty("user.home"));」,如果發生問題請看微軟的文章XD(http://support.microsoft.com/kb/221206/zh-tw)
- 總之,簽好之後的Applet拿來交作業是夠用了,但是只能維持6個月,實在說也不是很實用…
- Java中「開啟網頁連結」
- Applet的話很簡單,應該各平台通用,就是加上「getAppletContext().showDocument(new URL("網址"),"你希望怎麼開,可能是_blank")」(參考API手冊:http://java.sun.com/j2se/1.4.2/docs/api/java/applet/AppletContext.html#showDocument(java.net.URL, java.lang.String)),就可以了
- 一般的話比較麻煩,而且我以為這應該只能用在Windows,不過就不考慮這麼多了,就是加上「Runtime.getRuntime().exec("cmd /c start " + "網址")」(可參考:http://www.javaworld.com.tw/jute/post/view?bid=29&id=7002&sty=3&age=0&tpg=1&ppg=1#7002)
- 或許在.net上不用想這麼多,反正.net目前看起來也只有Windows支援,再者說.net本來就有LinkLabel,mono不實作實在不夠義氣XD
- 同理,這道指令就跟C#裡的System.Diagnostics.Process.Start()用處相同
- Google Static Map API
- 這部份很簡單,首先得先申請Google API Key,需要你的Google帳號(http://code.google.com/intl/zh-TW/apis/maps/signup.html)
- 然後需要像Google Map API的Geocoding問經緯度(http://code.google.com/intl/zh-TW/apis/maps/documentation/geocoding/)
- 然後用BufferedReader(new InputStreamReader(new URL("字串").openStream()))去讀http://maps.google.com/maps/geo?q="+URLEncoder.encode(‘"搜尋字串", "UTF-8")+"&output=csv&key=你的API Key"的回傳值(通常是一個經緯度),再用這個回傳值去查Google static map
- 拿到經緯度之後才可以去要Google Static Map(http://code.google.com/intl/zh-TW/apis/maps/documentation/staticmaps/),當然如果是C#的話我會直接丟一個Webbroswer,省事XD
- Static Map一定是一張圖,不能拖來拖去,要拖來拖去你要自己寫程式碼,在這裡我沒這麼無聊,有一張圖就很夠了~
- Google Static Map的服務網址在:http://maps.google.com/staticmap?center="+"經緯度"+"&zoom=17&size=400×400&markers="+"如果要加標記的話,這裡放經緯度"+"&key="+你的API Key+"&sensor=false
- 這個連結會回傳圖片,可以用ImageIcon來接他,然後就大功告成
- 其實我是看萍水相逢大的部落格學的,他是用C#完成:http://www.dotblogs.com.tw/chhuang/archive/2008/04/03/2593.aspx
嗯,大致上就是這樣了,不得不說Java應該是很好的物件導向語言學習工具(廢話要不然幹嘛用Java教XD),不過他實在太廢話了(相較於C#),但是開放很多API原始碼可以學習實在很棒XD