2012年4月15日 星期日

簡單的聊天室實作

聊天室
這個東西在即時通訊系統出現之前
非常流行
是掀起網路人際關係的濫觴
特色在於能立即收到回應
缺點是必須登入指定地點
所以ICQ出來之後,
立刻被打敗了
因為ICQ是裝在自己的電腦上
加上使用者的介面相對親切
並且更加方便
^^^^^^^^^^^^^^^^
只要留給別人即時通地址, 別人想聯絡你時就能聯絡你
不需要約時間在聊天室苦苦等候
做到真正的"即時"通~

最近心血來潮
用JSP想實作一個簡單的聊天室
沒想到越做越多
因為有幾點要考慮:
1.聊天內容存放處: 只是存放在application的一個變數. 吃的是記憶體空間. 所以AP SERVER重開或清掉變數內容的話, 記錄就沒了.
2.重新讀取問題: 若是用post方法, 每次重讀, 瀏覽器都會跳出視窗確認, 很麻煩又關不掉. 用get方法沒有跳出確認視窗問題, 但是之前聊天內容會一直重複增加, 原因是採用window.location.reload(), 導致重複送出帶參數的網址. 解決之道是利用window.location底下的屬性, 拼湊出不含變數的網址. 然後用window.open()取代window.reload()以指定url位址.
3.捲軸位址: 重新讀取畫面時, 捲軸會跑掉. 所以必須要能記得捲軸位址, 重新讀取時恢復上次捲軸位址. 這點用window.onscroll事件和document.body.scrollTop屬性完成.

以下是成品, 內含兩支JSP+1個HTML做窗格(FRAME)
http://goo.gl/QWriQ

2011年7月27日 星期三

原來java的修飾關鍵字是沒有順序的...!!

public class test123{
 static final private String s1 = "abc";
 private static final String s2 = "def";
 public static void main(String args[]){
  System.out.println(s1);
  System.out.println(s2);
 }
}

印出:
abc
def

一直以為java的修飾關鍵字是要照順序的
但是今天才發現
原來是不用的!
修飾關鍵字照順序應該是個習慣
但並不是文法上的要求!!

用jsp確認Server上的jvm版本

我最近用jdk 1.5版本編譯檔案
丟到遠方的AP Server上
可以執行

所以知道這台Server上的jvm版本
必定>=1.5
因為沒有向上相容這件事
舉例而言
也就是1.4無法跑1.5編譯出來的class
否則會出現java.lang.UnsupportedClassVersionError
但是詢問Server管理員
跟我說這台Server上的jvm版本是1.4
這與我的認知衝突

所以到底是幾版呢?
可以用以下jsp驗證
<%@ page import="java.util.*"%>
<%
out.println("The version of current JVM is: " + System.getProperties().getProperty("java.version"));
%>
把這支jsp丟到Server上
得到結果是1.5
證明我是對的...哦ㄝ

這裡是相關討論

表單上的type=sumbit和type=button的按鈕

表單上有兩個按鈕
一個是<input type=submit />
一個是<input type=button />
這兩個的差別
在於type=submit在預設上
會引發表單的onSubmit事件
而type=button什麼事件都不會發生!

可以看以下例子:
test.html:
<script>
function doChk(){
 alert("No way!");
 return;
}

function doChk2(){
 alert("No send!");
 return;
}
</script>

<form action="test1.jsp" onSubmit="doChk2();">
<input type=submit value="Send?" onClick="doChk();" />
</form>


test1.jsp:
<%
out.println("You send....");
%>



在瀏覽器看到的結果是:

跳出視窗:No Way!
跳出視窗:No Send!
新畫面:You send....

所以可以知道幾件事:
1.type=submit的按鈕, 會先觸發按鈕自己的onClick事件, 再觸發表單的onSubmit事件
2.無論onSubmit事件的處理函式如何寫, 最後一定會將表單送出, 無法阻止表單送出的發生

2011年7月14日 星期四

java版本的向下相容

jre是向下相容的!
這向下相容有兩個面向

1.低版本編譯好的class, 能在高版本直接執行:
你以1.4版編譯好的class
能在1.6版的jre上直接執行, 不需做任何修改
換句話說
所以1.6版的jre能夠直接地
吃下比它低版本的class

2.高版本編譯好的class, 能在低版本執行:
咦?
這樣有下向相容嗎?
在1.6的jdk直接編譯: javac hello.java
這樣你拿去1.4版jre執行
會得到以下結果:
Exception in thread "main" java.lang.UnsupportedClassVersionError: test (Unsuppo
rted major.minor version 50.0)

(拿高版本jdk編譯的java去低版本jre執行->當然不行, 因為沒有向上相容這件事)

你必須要加上兩個參數:-source和-target
-source: 要用java幾版, 來檢查程式內容, 是否合乎java文法
-target: 於前項檢查文法ok後, 編譯後產生的class檔將以何種java版本輸出

這裡要特別注意幾點:
a.-target的預設值 = -source的值
例如-source=1.4, 如果不加以設定-target
則此時-target=預設值=1.4
(但-source=1.2或1.3時, -target的值都等於1.4)

b.-target的值必須大於等於-source的值
比如-source=1.4
則-target可以等於1.5
若-target=1.3
執行javac後將會得到以下結果
javac: source release 1.4 requires target release 1.4

為-target做個實驗
用jdk 1.6寫一個簡單的java
執行:javac test.java
再拿到jre 1.4上去執行
結果是:
Exception in thread "main" java.lang.UnsupportedClassVersionError: test (Unsuppo
rted major.minor version 50.0)
若執行的是:javac test.java -target 1.5
再拿到jre 1.4上去執行
結果是:
Exception in thread "main" java.lang.UnsupportedClassVersionError: test (Unsuppo
rted major.minor version 49.0)
可以觀察到-target的值不同,
所產生出來的class檔的版本真的不一樣

這裡有個疑問
會有需要將-source和-target設定成不一樣的時候嗎
例如javac hello.java -source 1.4 -target  1.5

答案是, 需要視你要佈署的環境而定
舉個例子你本機是高版本的1.6
欲佈署在遠方的機器是低版本的1.5
然後你程式碼中有用到1.4才提供的功能
這個時候就相當適合使用:javac hello.java -source 1.4 -target  1.5

但記得前面我提過
高版本的jre能直接吃下低版本的class
所以, 結論是
你使用javac hello.java -source 1.4 -target  1.5最完美
但使用javac hello.java -source 1.4 -target  1.4也沒差, 是相同意思
可是使用javac hello.java -source 1.4 -target  1.3 <-錯誤!
因為-target的值必須大於等於-source的值

最後
提醒大家
雖然
高版本的jre能直接吃下低版本的class
但是程式總有需要修改的時候
所以在修改以前的程式後
有必要重新編譯時
必須要注要你所使用的 -source值

請看下面兩張圖, 分別是j2se1.4和j2se 5的api
其中String這個類別的api
圖一 j2se1.4的String API
圖二 j2se1.5的String API

可以注意到從1.4跨到1.5之後
本來在1.4中的方法compareTo(Object o)
已經消失了....也就是1.5把這個方法取消

可以寫個簡單類別來測試:
public class test{
 public static void main(String[] args){
  String a = "p";
  Object b = new String("p");
  if(a.compareTo(b)==0){
   System.out.println("They are equal!");
  }
 }
}

執行指令如下,
可以看到用-source 1.4編譯沒有錯誤
若用-source 1.5就會說你應該參數用String而不是Object
參照圖二, 就可以知道這是因為, j2se 1.5中已刪除 compareTo(Object o)的關係

C:\jpractice>javac test.java -source 1.4
C:\jpractice>javac test.java -source 1.5
test.java:5: compareTo(java.lang.String) in java.lang.String cannot be applied t
o (java.lang.Object)
                if(a.compareTo(b)==0){
                    ^
1 error
C:\jpractice>

編譯的時候
要注意使用哪個版本的java來檢查程式文法
但是只要一編譯好
以上例而言
以javac test.java -source 1.4編譯完成
拿到jre 1.6去執行時
雖然test.java裡使用了1.4版才有的String.compareTo()功能
但是因為高版本的jre能直接吃下低版本的class
所以能執行執行沒有問題
只不過編譯時要比較麻煩
加個-source參數
當然你應該不會想替專案裡的少數幾支java特別加上-source參數
專案裡所有的程式應該都是以同樣版本的java去編譯的
這樣才好維護
所以有發現有使用到已被高版本取消的方法時
還是趁早修改比較理想

2011年7月5日 星期二

jquery選擇器的問題

選擇html畫面上的dom物件進行操作
以往都是要用getElementById(), getElementsByName()等來操作
但有了jquery之後
使用他的選擇器
就可以方便地選取畫面上的元件了

選擇器長這樣: $()
一個錢字號, 後面帶一個小括號
詳細用法可以參考這裡

今天碰上一個jquery選擇器的問題
$('input[name=test]:checked').each(function() {//處理的程式碼});
上面這個意思是說
選取所有input標籤, 其name屬性為test, 且被選取(checked)的元件.
然後逐一將這些元件, 交付function(){//處理的程式碼}去處理

乍看之下沒問題
問題是我程式裡本來是這樣寫的
$('input[name=test][checked]).each(function() {//處理的程式碼});
他用[], 而不是:
妙的是, 經過測試, 
這樣的句子在IE8較低版本(我同事的電腦, IE8版本< 8.0.7601.17514, 確切版本數記不住)可以選到東西
但在較高版本(我的電腦, IE8版本8.0.7601.17514)卻連個鬼都選不到

WHY?

本來我對jquery的處理器雖有概念
但對語法並不熟悉
看了這一頁後,
恍然大悟可能是出在[checked]的關係
應該改為:checked才對
修改後果真可以在IE8版本8.0.7601.17514運行

結論:
要選擇被選取的元件
要用冒號:checked
而不是中括弧[checked]
但無法解是為何在較低版本的IE8,
中括弧[checked]也可以運行??

關於:checked的用法
亦可參考這裡



eclipse無法建置?

今天替專案加了旗標flag
為了觀察程式執行的流程與參數值

加了旗標就是改了程式
所以要重新編譯
疑?
為什麼選擇專案->建置專案
看起來是順利完成
可是跑去專案的classes資料夾一看
都還是舊的東西

一氣之下選擇專案->清除
打算乾脆全部都重新建置算了
沒想到連一個class都沒編譯出來
情況更糟.....

我後來知道原因了!
那是因為該專案的建置路徑裡
我本來有加一些外部jar
可是這些外部jar後來被我移除所以專案就無法參考到
而會一直出現紅色驚嘆號



 (
為什麼我知道紅色驚嘆號的意義?
答:從eclipse documentation中查到的, 如下




)


將這些已經移除的外部jar
從建置路徑中移除
則紅色驚嘆號就會消失
再選擇一次專案->建置專案
已經可以的classes資料夾看到編譯後的.class檔了

總結:
eclipse中, 只要專案建置路徑有一個錯誤, 就無法再建置任何東西!

20110728補充:

今天幫同事測專案時
專案裡面會用到spring+hibernate
然後hibernate所需連線
會寫在一個設定檔裡面

專案啟動時
spring會根據此設定檔內容
去讀取db相關設定
然後試著去new出一個org.springframework.jdbc.datasource.DriverManagerDataSource
但是此設定檔帳號密碼設定錯誤
所以拋出Exception
然後此專案就"起不來"
AP Server(在此例中是Tomcat)會跳過此一專案
繼續啟動其他專案...

所以
除了建置路徑中有不存在的jar, 會導致專案啟動失敗外
如果建置中有任何Exception,
或是任何錯誤
都會導致專案怎樣都無法啟動