目前分類:Java World (7)

瀏覽方式: 標題列表 簡短摘要

做轉檔的時候發現其中一些檔案資料跟資料庫拼不起來.

細心如我,早就對每一個檔案的input trim過了, 資料對不起來一定是特殊字元在作怪.

後來才發現, 把他印出來才發現是個沒有被trim掉的空白在作怪.

1. Google找到的 unicode 印出法

    System.out.println("space" + Integer.toHexString(' ' | 0x10000).substring(1));

2. Unicode

    一般的空白為\u0020, 這種non-break space (nbsp)為\u00a0

3. Wiki 

    http://en.wikipedia.org/wiki/Non-breaking_space
    很難從Window打出來, mac的話是"option + space"就可以打出

4. 解法

    無解, 當初我還呼叫了Apach commons StringUtils.trimToEmpty, 還是沒辦法trim掉.
    所以基本上就是自己寫一個一樣的Util, 加上這一段邏輯 str.replaceAll("\u00a0","")

文章標籤

minglight 發表在 痞客邦 留言(0) 人氣()

是不是想要把自己在模擬器的行為自動化, 做排程, 機器人, 或是測試網頁的工具? HtmlUnit正是你需要的一套Java API!

下面這個範例, 可以讓你在Facebook login, 並且留言 (繁體中文版限定, 經過測試, 英文版跟中文版的DOM排列方式不一樣 = =a )

API版本 : HtmlUnit 2.10 

1. Login Facebook

String email = "";
String pwd = ""; 

WebClient webClient = new WebClient(BrowserVersion.CHROME_16);
HtmlPage page = webClient.getPage("http://www.facebook.com");

HtmlTextInput emailInput = (HtmlTextInput)page.getElementById("email");
emailInput.setValueAttribute(email);
HtmlPasswordInput passInput = (HtmlPasswordInput)page.getElementById("pass");
passInput.setValueAttribute(pwd);
HtmlSubmitInput submitBtn = (HtmlSubmitInput)page.getElementById("loginbutton").getFirstChild();
mainPage = submitBtn.click();

2. Post Message

String msg = ""; 

HtmlAnchor personPageA = (HtmlAnchor)mainPage.getElementById("pageNav").getFirstChild().getFirstChild();
personalPage = personPageA.click();

DomNodeList<HtmlElement> areas = personalPage.getElementsByTagName("textarea");

for(HtmlElement e : areas){
((HtmlTextArea) e).setText(msg);
}
HtmlTextArea input = (HtmlTextArea)personalPage.getElementByName("xhpc_message");
input.setText(msg);

HtmlForm form = (HtmlForm)personalPage.getByXPath("//form[@action='/ajax/updatestatus.php']").get(0);
HtmlSubmitInput submitButton = form.getInputByValue("留言");
if(submitButton == null){
submitButton = form.getInputByValue("Post");
}
submitButton.click();

3. Run Javascript 

personalPage.executeJavaScript("alert('HelloWorld');");

 

後記 & 心得: 

會找這個API,起因是想要塞垃圾資料到某個詐騙網站, 當初只有挖出網站的JS, 然後用IE的Development Tool去Run這些JS. 但是手動的好麻煩阿阿阿~~

找到API之後,開始用FB來測試Login + 留言, 後來索性來試著寫出FB的Robot想要監看留言順便按讚 XD

基本上遇到了不少挫折, 我就放棄了Robot的實做, 其中一個原因是利用Android模擬器應該也寫得出來 

結論 : 

優點我就不多說了,就是讓你可以自動化對瀏覽器做的行為

缺點如下 :

    - 雖然可以選擇瀏覽器版本, 但是似乎沒有模擬的完全接近, 有些版本會有一些莫名其妙的bug跑出來
    - FB的中文版跟英文版的排版不一樣, load message的方式跟順序也有差別, 所以真的要寫出FB能run的程式還真的是不容易
    - 如果網站一改版, 或者是只要有個小地方不一樣, 程式就很有可能會掛掉

建議 :  

     - 找那些Load網頁不會太複雜, Ajax使用上比較少比較簡單的網站比較適合
     - DOM的Select方式要抽離出來, 甚至變成常數檔, 這樣在維護上會比較容易
     - 如果自動化邏輯沒有要跟Server互動(例如存進DB), 只是單純的下指令的話, 可以考慮另外寫一個.js檔案, 直接跑Javascript會是最簡單的方式

參考連結 : 

StackOverFlow : http://stackoverflow.com/questions/7260282/apache-httpclient-4-and-javascript

HtmlUnit : http://htmlunit.sourceforge.net/
HtmlUnit內建了Selenium, 是一個沒有畫面的瀏覽器, 還可以選擇瀏覽器的版本

Selenium : http://seleniumhq.org/

minglight 發表在 痞客邦 留言(0) 人氣()

為了不誤導大家,把一些看完Source的進階心得寫在這兒

1. 把Map<Thread,value>放在ThreadLocal的缺點
    在某些情況下Thread不會重複使用. 例如Web環境,Container會產生一個新的Thread來處理Request-Response,因此如果ThreadLocal設計方式是ThreadLocal-簡介,將Map放在ThreadLocal中,你會發現這個Map越來越大,越來越大,要直到你重開Server才會重置 ( 以上純屬個人推論 XD )


2. ThreadLocal實際運作方式
    ThreadLocal並不會自己存放Map,而是把Map放到Thread裡面去!!
    Thread中會有一個ThreadLocalMap<ThreadLocal,Object> ,注意這邊的Key變成了ThreadLocal物件本身, 因此每個ThreadLocalMap都有可能會有以不同的ThreadLocal相對應的值.
    其實這種方式更直覺,每個Thread會有一個空間放一些客製的變數,而且好處是,當Thread掛掉之後,這個Map也會跟著Thread被GC掉.

3. ThreadLocal的API
    protected T initialValue() 
給繼承者使用, 預設回傳null, 當呼叫get()拿到null時會呼叫initialValue()將值擺進去.

    其他直覺的使用如下
     +get() : T 
     +set(T) : void     
     +remove(T) : void 

4. 使用ThreadLocal的時機
    我查了一下網路,有人說當你對一個bean/resource使用synchronized的時候,常常是寫法不易而且效能不彰(因為Thread都在排隊等放飯).因此ThreadLocal可以拿來取代synchronized
    這種說法是部分正確的. 其道理在於如果你今天只有一個飯鍋, 放飯的時間一定會拉很長,如果使用ThreadLocal, 當你需要吃的時候我直接給你一碗飯,這時候就不需要排隊了.
   
    ThreadLocal的觀念就是個人造業個人擔,不管你要對你的飯做什麼都不會影響到別人
    但是synchronized內的邏輯,因為是大家共用一個飯鍋,當輪到你盛飯的時候,如果你在飯鍋裡面加了滷肉,整鍋飯就會變成魯肉飯了.
    因此ThreadLocal可以取代synchronized的時機只有在於沒有人會對飯動手腳的時候才適用.
       
    可以把它當作requestScope的延伸
   
這個就不需要太多解釋了,因為跟request在同一個Thread裡面 


如果大家有什麼寫錯的地方也請不吝指教喔~

文章標籤

minglight 發表在 痞客邦 留言(0) 人氣()

前置觀念 - 必須了解Thread, Thread.currentThread()被呼叫的機制, call stack機制.

ThreadLocal的目的 : 把變數存在currentThread中, 讓每個執行中的Thread都有自己的一份Copy, 而且彼此之間不會互相影響.

實作概念 : 
public class ThreadLocalConcept{
private Map<Thread,Object> localMap = Collections.synchronizedMap(new HashMap<Thread,Object>());

public void set(Object obj){
this.localMap.put(Thread.currentThread(), obj);
}

public Object get(){
this.localMap.get(Thread.currentThread());
}


基本上就是這個localMap會放著各個Thread對應的變數, 因此在不同的Thread中呼叫到的Value都會是獨立的.

用途範例 : 在DAO中拿到Login User
     
一般來說Login User都是放在Session中, 但是平常我們使用的Service & DAO都會是Singleton, 是共用的, 因此不能夠將Login User放入
        
我們可以利用一個Request-Response是一個獨立Thread的特性, 搭配ThreadLocal將Login User存入各個Thread中,就可以拿到相對應的Login User了


Step1. 建立一個共用的Thread Local

public class LoginUserUtil{
public static ThreadLocal<User> local = new ThreadLocal<User>();

public static User getUser(){
return local.get();
}

public static void setUser(User user){ 
local.set(user);

step2. 在BaseAction/BaseServlet/BaseController內放入LoginUser

public class BaseAction extends ...{
public doBaseRequest(){
User user = this.getRequest().getSession().getAttribute("loginUser");
LoginUserUtil.set(user);
}
}

step3. 在DAO中拿出LoginUser - 完工!!

public class XXXDAOImpl extends ...{
public void updateData(Data data){
data.setUpdateUser(LoginUserUtil.get());
this.update(data);
}
}

 




 

文章標籤

minglight 發表在 痞客邦 留言(1) 人氣()

1. 分別描述 TCP , IP , HTTP 的
    a.功能
        TCP : 保證檔案完整, 管port的2^16(1~1023官方用的)
        IP  : 保證送對地方, 管IP的
        HTTP : 請求與回應,在TCP&IP之上建立的

2. Request包括了 method, url, param(包含header)
   Respnose包括了 state ,content-type , 內容(HTML)
   
3.Html是 Response的一部分

4.Get&Post
  a.Get有字數限制
  b.Get可以被加入書簽(因為在URL後面),Post沒辦法
 
5.URL(Uniform Resource Locator)

6.CGI (Common Gateway Interface)& Servlet
    a.語言 :
        CGI : PHP , c , Python , Perl
    Servlet : Java
    
    b.比較
        CGI : @多用Process處理(搞肛),
              @Servlet使用Thead
              @Servlet可以寫在JavaEE裡面, CGI只能呼叫

minglight 發表在 痞客邦 留言(0) 人氣()

1. java.lang.Class代表class or Interface;
    class : 基本class, array ,enum , primitive type , void
    interface : interface , annotation
    +isInterface():boolean
    +isArray():boolean
    

2.用obj.class or obj.getClass()可以得到Class物件, 是在建立.class檔案時放入的
   因此也可以用Class.forName("ming.MyClass");方式得到Class物件
   
3.Class物件訊息在建立.class檔案就已經儲存好,編譯時期檢查相對應的.class檔案,
  Runtime會將有被使用到的Class資訊Load入定義區,因此有.class不一定會在定義區內,就不能做成物件
  使用Class.forName("package.name");將Class註冊入定義區中,並且將此Class回傳
  ==>Class.forName("package.name").newInstance();就會回傳此物件
  ps.只能new無參數建構子,如果沒有此定義就會出錯,也可以使用myClass.getConstructor.newInstance(Object...)來彌補有參數建構子的不足

4.使用Class物件可以得到各式各樣類別的定義, Constructors, Fields, Methods, package, SuperClass等

minglight 發表在 痞客邦 留言(0) 人氣()

最常犯的邏輯上的錯誤是 沒考慮到null的情形 而做instanceof , 卻又要在裡面做null判斷

ex :

public void m1(Object s1){

if(s1 instanceof  String){

if(s1 == null || "".equals(s1)){

sout("S1不存在!!");

}

}

}

上面這個例子, null情形永遠不會發生sout

 

另外一個rookie mistake是complie time error ,反而就沒那麼致命了

(reference  instanceof Class or Array)

int i = 0

if( i instanceof Integer) {

sout(i);

}

上面會出現要求你instanceof前面要放reference 不能放primitive type

minglight 發表在 痞客邦 留言(0) 人氣()