2009年1月22日

Java Coding Style、Code Conventions


寫程式除了讓程式能達成我們的目的之外
平常寫程式也要注意一下coding style
如同這份文件中的導論所說的:
* 一套軟體的生命期 80% 都是花費在維護上。
* 任何軟體都很難從頭到尾全由原來的作者來維護。
* 程式碼慣例改善軟體的可讀性,讓工程師可以更快速完整的了解新程式碼。
* 如果你將你的原始碼當作產品,你必須確定它跟你創造的其他產品包裝的一樣好,一樣乾淨。
這就是我們要建立好的coding style的理由

Sun Microsystems 官方文件 (英文)
Code Conventions for the JavaTM Programming Language
中文版
http://www.javaworld.com.tw/jute/post/view?bid=20&id=27897&sty=1&tpg=1&age=-1

Java:日期時間格式化輸出入處理:Date、Calendar、SimpleDateFormat


在使用Java的這些日子裡,
Java中的日期時間格式處理總是讓我覺得有些混亂不夠直覺。
例如我想要知道2009/1/1是星期幾,
那就要經過不少步的處理轉換才能得知正確的答案。

程式如下:
其中第一種方式可以接受我們常用的日期格式 2009/1/1 或 2009/01/01,
第二種看起來比較簡便但就必須自己把年月日分開再輸入呼叫程式,
其中年和日可以直接輸入2009和1,但月份的地方要特別注意,
最好使用 Calendar.月份的方式輸入,因Calendar.JANUARY的 int值是 0而非1
若直接以月份輸入的話會出錯!


(2011.11.24更新)
在程式的最下面補充如何格式化印出現在的時間。
只要先用 Date() 取得現在的日期時間,
再用SimpleDateFormat格式化即可。

 1 package demo;
 2 
 3 import java.text.DateFormat;
 4 import java.text.ParseException;
 5 import java.text.SimpleDateFormat;
 6 import java.util.Calendar;
 7 import java.util.Date;
 8 
 9 public class SimpleDateFormatDemo {
10 
11     public static void main(String[] args) throws ParseException {
12 
13         //  準備輸出的格式,如:星期四 2009/01/01
14         SimpleDateFormat sdf = new SimpleDateFormat("E yyyy/MM/dd");
15 
16         //  利用 DateFormat 來parse 日期的字串
17         DateFormat df = DateFormat.getDateInstance();
18         Date date = df.parse("2009/1/1");
19         Calendar calendar = Calendar.getInstance();
20         calendar.setTime(date);
21         System.out.println(sdf.format(calendar.getTime()));
22 
23         //  利用 set 直接輸入日期
24         calendar.set(2009, Calendar.JANUARY, 1);
25         System.out.println(sdf.format(calendar.getTime()));
26         
27         //  直接格式化輸出現在時間的方法
28         SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy/MM/dd 
29                                     HH:mm:ss.SSS");
30         Date current = new Date();
31         System.out.println(sdFormat.format(current));
32     }
33 }
輸出結果為:
星期四 2009/01/01
2011/11/24 22:38:54.631

而 SimpleDateFormat可以讓我們選擇日期輸出的格式可以參考以下的表格:
Date and Time Pattern Result
"yyyy.MM.dd G 'at' HH:mm:ss z" 2001.07.04 AD at 12:08:56 PDT
"EEE, MMM d, ''yy" Wed, Jul 4, '01
"h:mm a" 12:08 PM
"hh 'o''clock' a, zzzz" 12 o'clock PM, Pacific Daylight Time
"K:mm a, z" 0:08 PM, PDT
"yyyyy.MMMMM.dd GGG hh:mm aaa" 02001.July.04 AD 12:08 PM
"EEE, d MMM yyyy HH:mm:ss Z" Wed, 4 Jul 2001 12:08:56 -0700
"yyMMddHHmmssZ" 010704120856-0700
"yyyy-MM-dd'T'HH:mm:ss.SSSZ" 2001-07-04T12:08:56.235-0700
(來源為:http://java.sun.com/javase/6/docs/api/java/text/SimpleDateFormat.html)

另外更多關於日期時間的處理可以看這兩篇:
1. java日期加减法 (也有繁體中文版本)
2. 藍色小鋪的討論串

關鍵字:Date, Calendar, DateFormat, SimpleDateFormat, parse, Java, 時間, 處理, 格式, 轉換,
參考資料:
1. Java Api:SimpleDateFormat
2. java日期加减法繁體中文版本
3. 藍色小鋪的討論串

2009年1月20日

利用Jakarta.Commons.HttpClient抓取網頁、網站(Parser)


HttpClient 已推出 4.x 版,若您要使用最新的版本請看:
Apache HttpClient 4.x 使用 GET, POST 範例

在撰寫程式的時候有時會我們需要取回網路上的資料做處理
或者是要以程式模擬Client端發出request
這時候我們就可以使用Jakarta.Commons.HttpClient來完成

Jakarta.Commons.HttpClient使用到下列的函式庫
Apache Commons HttpClient 3.xApache Commons CodecApache Commons Logging
三者必須在使用前就都設好classpath否則在執行時會出錯

[Jakarta Commons] HttpClient模擬Client端發出request的介紹
Jakarta.Commons.HttpClient 能支援許多功能,例如:
實作所有的 HTTP methods (GET, POST, PUT, DELETE,HEAD, OPTIONS, and TRACE)
支援 HTTPS 的協定
支援 proxies 的各種情況
支援認證機制
自動的 cookie 處理模式 .....等等
更多介紹可連回[Jakarta Commons] HttpClient模擬Client端發出request查看

以下有幾個比較完整的 Get 和 Post的範例程式連結:
Get範例:
[Jakarta Commons] HttpClient模擬Client端發出request
JSP精選實用範例(五):抓取網頁
Post範例:
Re:TinyUrl using Jakarta HttpClient [Re:qrtt1]
更多原始的範例可以在HttpClient Examples看到

最後附上我自己改來用的程式碼
可能要看過上面的範例之後比較知道在做什麼


  1. import org.apache.commons.httpclient.HttpClient;
  2. import org.apache.commons.httpclient.HttpMethod;
  3. import org.apache.commons.httpclient.NameValuePair;
  4. import org.apache.commons.httpclient.methods.GetMethod;
  5. import org.apache.commons.httpclient.methods.PostMethod;
  6. public class ParseWeb extends HttpClient {
  7. public static void main(String[] args) {
  8. ParseWeb pw = new ParseWeb();
  9. // executeGet Example
  10. System.out.println(pw.execute(pw.setGet("http://www.google.com.tw/")));
  11. // executePost Example
  12. NameValuePair[] pairArray = {new NameValuePair("searchtype", "t"),
  13. new NameValuePair("searchscope", "keyword"),
  14. new NameValuePair("searcharg", "哈利波特"),
  15. new NameValuePair("SORT", "D")
  16. };
  17. System.out.println(pw.execute(
  18. pw.setPost("http://tulips.ntu.edu.tw:1081/search*cht/a?", pairArray)));
  19. }
  20. public ParseWeb() {
  21. this.getParams().setParameter("http.protocol.content-charset", "UTF-8");
  22. }
  23. public ParseWeb(String pageEncoding) {
  24. this.getParams().setParameter("http.protocol.content-charset", pageEncoding);
  25. }
  26. private GetMethod setGet(String url) {
  27. GetMethod method = new GetMethod(url);
  28. return method;
  29. }
  30. private PostMethod setPost(String url, NameValuePair[] pairArray) {
  31. PostMethod method = new PostMethod(url);
  32. for (NameValuePair pair : pairArray) {
  33. method.addParameter(pair);
  34. }
  35. return method;
  36. }
  37. private String execute(HttpMethod method) {
  38. try {
  39. this.executeMethod(method);
  40. String responseString = new String(method.getResponseBodyAsString());
  41. method.releaseConnection();
  42. return responseString;
  43. } catch (Exception e) {
  44. e.printStackTrace();
  45. method.releaseConnection();
  46. return "Error: executePost() fails";
  47. }
  48. }
  49. }

關鍵字:HttpClient, executeMethod, getResponseBodyAsString
參考資料:
1. Jakarta.Commons.HttpClientHttpClient Examples
2. [Jakarta Commons] HttpClient模擬Client端發出request
3. JSP精選實用範例(五):抓取網頁
4. Re:TinyUrl using Jakarta HttpClient [Re:qrtt1]

2009年1月15日

java.util.regex正規式的應用:Pattern和Matcher


Regular Expression,中文稱:正規式、正規表示式、正則表示式,
在字串的比對上是無比強大的工具,
在java 1.4之後Regular Expression正式被java所支援,
若你使用Eclipse來開發Java,下面這兩個套件可在 Eclipse中幫助你測試你的Regular Expression。
  1. Eclipse 好用套件:Regular Expression Tester
  2. Eclipse 的 plugin,http://myregexp.com/eclipsePlugin.html
而若你需要的是線上的測試工具,可以參考:

一般我們常用的字串操作有很多
譬如說檢查字串中是否包含某個字串
這點可以利用contains來達到
也可以利用Regular Expression來比對

除此之外Regular Expression也可以達到更多判別
例如說字串是不是由什麼特定字串開始或結束
而更強大的功能在於能將符合需求的字串濾出
只要掃過一次就能得到所有符合的項目真的非常方便

如果想得到更詳細的介紹請看 Regular Expression 簡介
語法的介紹則可參考 Java Regular Expression的學習筆記 [精華]

以下的程式簡單地示範了幾個常用的method:
  1. package demo.regex;
  2. import java.util.regex.Matcher;
  3. import java.util.regex.Pattern;
  4. public class Regex {
  5. public static void main(String[] args) {
  6. // 測試 testString 中是否包含了 aa
  7. String testString = "ABCaaabcaac";
  8. System.out.println("String.contains():\t"+testString.contains("aa"));
  9. // 和上面目的相同,但運用了 regular expression
  10. // 而這其實是利用了 Pattern 的靜態方法matches()
  11. System.out.println("String.matches():\t"+testString.matches(".*aa.*"));
  12. System.out.println("Pattern.matches():\t"+Pattern.matches(".*aa.*",testString));
  13. System.out.println();
  14. // 如果要用相同的 regular expression 測試很多資料
  15. // 可以使用Pattern的靜態方法compile()來編譯
  16. // 之後就可以重覆使用這個pattern的matcher()方法來進行字串比對
  17. String testString2 = "aababcAc";
  18. Pattern pattern = Pattern.compile(".*aa.*");
  19. Matcher matcher = pattern.matcher(testString);
  20. System.out.println("matcher.matches():\t"+matcher.matches());
  21. matcher = pattern.matcher(testString2);
  22. System.out.println("matcher.matches():\t"+matcher.matches());
  23. System.out.println();
  24. // 另外Matcher中還有很多方法可以使用
  25. // 除了用 matcher.matches()可以比對字串是不是符合regular expression
  26. // 也可以利用 matcher.lookingAt()比對字串是不是某個regular expression開頭
  27. pattern = Pattern.compile("aa");
  28. matcher = pattern.matcher(testString);
  29. System.out.println("matcher.matches():\t"+matcher.lookingAt());
  30. matcher = pattern.matcher(testString2);
  31. System.out.println("matcher.matches():\t"+matcher.lookingAt());
  32. System.out.println();
  33. // 想取出字串中符合的區段則可以運用 matcher
  34. // 例如想從下面四個號碼找出手機的格式
  35. // 就可以用 matcher.find()及matcher.group()來取出符合的項目
  36. String testString3 = "0911-111111, 02-22222222, 0922-222222, 03-33333333";
  37. pattern = Pattern.compile("\\d{4}-\\d{6}");
  38. matcher = pattern.matcher(testString3);
  39. while (matcher.find()) {
  40. System.out.println("matcher.group():\t"+matcher.group());
  41. }
  42. }
  43. }
而輸出的結果如下:
String.contains(): true
String.matches(): true
Pattern.matches(): true

matcher.matches(): true
matcher.matches(): true

matcher.matches(): false
matcher.matches(): true

matcher.group(): 0911-111111
matcher.group(): 0922-222222

關鍵字:Regular Expression, Pattern, Matcher, 正規式, 正規表示式, 正則表示式
參考資料:
  1. JAVA API:java.util.regex
  2. Java Gossip: Pattern、Matcher
  3. Regular Expression 簡介
  4. Java Regular Expression的學習筆記 [精華]
  5. Eclipse 好用套件:Regular Expression Tester
  6. Online Regular Expression Tester:線上正規式測試驗證工具網站

Java:JSON in Java 的簡單程式範例


若你要找的是打包 json.jar 的方式或想直接下載,
請到 Java:JSON.jar 下載與JSON source code 打包教學

JSON(JavaScript Object Notation)
因為格式簡單且用純文字方便讀取
支援了各式各樣的語言(都有相關的函式可用)
在資料處理交換上是很方便的格式
可以在這邊看到詳細介紹

以下的程式簡單地示範了JAVA中JSON的應用
其中包含了一個 PeopleBean 及主要的程式碼

PeopleBean:
 1 package werdna1222coldcodes.blogspot.com.demo.json;
 2 
 3 public class PeopleBean {
 4 
 5     private String name;
 6     private int age;
 7     private boolean gender;
 8 
 9     public PeopleBean(String name, int age, boolean gender) {
10         setPeopleBean(name, age, gender);
11     }
12 
13     public String getName() {
14         return name;
15     }
16 
17     public void setName(String name) {
18         this.name = name;
19     }
20 
21     public int getAge() {
22         return age;
23     }
24 
25     public void setAge(int age) {
26         this.age = age;
27     }
28 
29     public boolean getGender() {
30         return gender;
31     }
32 
33     public void setGender(boolean gender) {
34         this.gender = gender;
35     }
36 
37     /***************************************************************/
38     public void setPeopleBean(String name, int age, boolean gender) {
39         setName(name);
40         setAge(age);
41         setGender(gender);
42     }
43 
44 }

主程式:
 1 package werdna1222coldcodes.blogspot.com.demo.json;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 import org.json.JSONArray;
 6 import org.json.JSONException;
 7 import org.json.JSONObject;
 8 
 9 public class JsonDemo {
10 
11     public static void main(String[] args) throws JSONException {
12 
13         // 利用bean來產生一個對應的JSONObject
14         PeopleBean Mary = new PeopleBean("Mary", 20, false);
15         JSONObject jsonObjectMary = new JSONObject(Mary);
16         System.out.println("1: " + jsonObjectMary);
17 
18         // 利用map的對照來產生JSONObject
19         Map map = new HashMap();
20         map.put("name", "Jacky");
21         map.put("age", 30);
22         map.put("gender", true);
23         JSONObject jsonObjectJacky = new JSONObject(map);
24         System.out.println("2: " + jsonObjectJacky);
25 
26         // 每個JSONObject都能利用JSONObject.put(key, value)
27                                                       來增加屬性
28         jsonObjectJacky.put("height", 180);
29         System.out.println("3: " + jsonObjectJacky);
30 
31         // 利用 JSON 的字串產生 JSONObject
32         String jackyJsonString = jsonObjectJacky.toString();
33         JSONObject jsonObjectJackyFromString = new JSONObject(
34                                                jackyJsonString);
35 
36         // JSONObject.get(key) 可取得 JSONObject中對應的值
37         // 找不到的話會丟出 org.json.
38         JSONException如下面註解掉那行
39         System.out.println("4: " + jsonObjectJackyFromString.get(
40                            "name"));
41         // System.out.println(jsonObjectJackyFromString.get("weight"));
42 
43         // 由JSONObject.names()取回names的JSONArray
44         JSONArray jsonArrayNames = jsonObjectJacky.names();
45         System.out.println("5: " + jsonArrayNames);
46 
47         // JSONArray可藉由JSONArray.put(value)
48                                            來增加Array中的值
49         jsonArrayNames.put("weight");
50         System.out.println("6: " + jsonArrayNames);
51     }
52 }

產生的結果
1: {"gender":false,"age":20,"name":"Mary"}
2: {"gender":true,"age":30,"name":"Jacky"}
3: {"gender":true,"age":30,"height":180,"name":"Jacky"}
4: Jacky
5: ["gender","age","height","name"]
6: ["gender","age","height","name","weight"]

更多 Java 程式範例,可見:Java 教學及程式範例大全

關鍵字:JSON, 程式範例, 程式教學
參考資料:
  1. JSON in Java

2009年1月7日

在blogger上使用Lightbox


Lightbox 2使用了Prototype FrameworkScriptaculous Effects Library
透過內嵌的 .js(JavaScript)和.css 達成圖片顯示的特效
這對會在blog上發表有照片的文章的部落客相當有幫助
因為只要點一下在文章中長寬受限的圖就能顯示完整的原始圖片了

首先先展示一下Lightbox 2實際運作的效果
點下圖片後應該就能感受到Lightbox 2的魅力了
如果沒辦法看到Demo請直接連結至Lightbox 2網頁觀看



要在blog上使用Lightbox 2的效果有兩個步驟
第一是要在blog本身的html中內嵌語法
以blogger來說先到 Lightbox 2下載最新的 zip檔後解壓縮
將 css、image、js資料夾上傳至自己的網路空間
上傳完後再到版面配置中的修改html
<head></head>之間加入類似以下的語法
<!-- /************************  LightBox  **************************/ //-->
<link href='你的網路空間/css/lightbox.css' media='screen' rel='stylesheet' type='text/css'/>
<script src='你的網路空間/js/prototype.js' type='text/javascript'/>
<script src='你的網路空間/js/scriptaculous.js?load=effects,builder' type='text/javascript'/>
<script src='你的網路空間/js/lightbox.js' type='text/javascript'/>
<!-- /************************* End LightBox *********************/ //-->
其中淺藍色的地方是註解,方便以後修改用
你的網路空間的部分
若是自己架的blog可以使用相對路徑(相對於網頁)
在blogger之中必須是可以連結到的 http 網址
另外在blogger還必須修改解壓縮出來js資料夾中 lightbox.js 的這兩行
fileLoadingImage: '你的網路空間/images/loading.gif',
fileBottomNavCloseImage: '你的網路空間/images/closelabel.gif',
這個檔案中也有其他一些設定可以更改,可以照他的註解設定
記得改完後要再上傳一次喔

設定完blog中的html後就可以使用了
只要在新發表的文章中加入這樣的語法就可以有上面Demo的效果了
<a href="大圖連結" rel="lightbox" title="說明文字">小圖連結</a>
另外他也支援類似相簿的功能
只要在網頁上有相同相簿名稱的連結都能一起瀏覽
點下第一張圖後在圖片的右半邊點滑鼠就能直接往下一張
同樣的在圖片左半邊點滑鼠就能往前一張
<a
href="大圖1連結" rel="lightbox[相簿名]">小圖連結1</a>
<a href="大圖2連結" rel="lightbox[相簿名]">小圖連結2</a>
<a href="大圖3連結" rel="lightbox[相簿名]">小圖連結3</a>
這也來個小小的Demo好了
一樣若在這的Demo失效可以回Lightbox 2去看





以上就是 Lightbox 的簡單介紹
網路上還有許多類似 Lightbox 的東西且功能更強大
譬如說可以使用iframe的Lytebox可以嵌入flash和影片的ThickBox
FancyBox 則有 iframe、inline 功能
目前看到最完整的是 LightView 上面提到的功能全包了
和這些比起來 Lightbox 就只是很單純的顯示圖片了

關鍵字:blogger, blogspot, Lightbox, Lytebox, ThickBox, FancyBox, LightView