2012年8月8日 星期三

jQuery - 如何加入自動完成 ? How to achieve auto complete function?

第一步你要先 download jQuery,並且在jsp 中宣告 :

<script type="text/javascript" src="js/jquery-1.3.2.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.8.7.custom.min.js"></script>

版本號就看你下載的jQuery 來宣告。
接下來在你的 js 中,針對某一個 input 欄位,此例為料號,加入 auto complete 的功能 。

$("#material_text").autocomplete({
        source : function(request, response) {
           
            $.ajax({
                url : $("#path").val() + 'ajax.action?method=list&act=find_material_text',
                type : "POST",
                dataType : "json",
                cache : false,
                delay : 1500,
                data : {
                    term : request.term
                },
                success : function(data) {
                //    $("#material_desc").unblock();
                    response(
                        $.map(data , function(item) {
                            return {
                                label : item.label,
                                value : item.value,
                                desc : item.desc
                            };
                        })
                    );
                },
                error: function(XMLHttpRequest, textStatus, errorThrown) {
                    alert(textStatus);
                
                }
            });
        },
        select : function(event, ui) {
            $("#product_desc").attr('value', ui.item.desc);            
        }     
    });

以下針對上面的程式做簡單說明。


自動完成,主要是搭配 ajax 的技術,來動態向後端要值。此例是將回傳結果,回傳成類似下拉式的選單,讓使用者可以從這些選單做選擇,而不用記得全部的輸入值資料。可以在 SQL 中做 LIKE ,或是其它搜索方式,讓使用者不一定要從「頭」開始輸入。


delay 是輸入後趨動查詢的間隔時間,如果使用者想要馬上打馬上看,那間隔可以短一點,不過對後台的呼叫次數當然也會變多,若機器不是很強的時候可以調慢一點。


 data : {
          term : request.term
         },


這是要送到後台去的,term 可以在後面當成一個 parameter 來抓取。就是使用者目前輸入的值。


select : function(event, ui) {
            $("#product_desc").attr('value', ui.item.desc);            
        } 


這裡是指,當使用者「點選了自動完成給你的結果集」之後所觸發的事件。
若沒有要特別做什麼,這裡可以不用去實作。
這裡是將 ui.item.desc 的值設入 某個 html input element 中 。
ui.item 是固定的,就是後台回傳的一個一個物件。
desc 是你自己可以在後台加入的屬性。
desc 我是放料號的說明。等下會解釋。

這樣前端的部份大概就好了。再來後端要提供觸發回傳的結果集有哪些。
至於這一段方法怎麼去觸發,就是看你web framework 使用的是哪一種,簡單來說就是要觸發到這一段,並且要用 ajax + json 的方式吐回去。


value = p("term");
sb.append("[");
List<Object[]> list = sap.createSQLQuery("select top 500 MATERIAL,MATERIAL_DESC from  MATERIAL where 1=1  and (material like  :val  or MATERIAL_DESC like :val )")
.setParameter("val", "%" + value + "%").list();
int i = 0;
for (Object[] ob : list) {
    sb.append(String.format("{\"label\":\"%s\",\"value\":\"%s\",\"desc\":\"%s\"}", getString(ob[0]) + " " + getString(ob[1]).replaceAll("\"", ""), getString(ob[0]), getString(ob[1])));
    if (i != list.size() - 1)
        sb.append(",");
    i++;
}
sb.append("]");

首先我只撈前500筆,若太多的話前端顯示會當掉。
可以用關鍵字查詢。
 json 裡則有三個屬性 label , value 與 desc ,desc是我自己加的,要和前端的程式同名才能使用。

  1. label 放料號的 id + 說明。這個是顯示用的。
  2. value 則放料號的 id。這個值在點了之後,會真的塞到原來的 input field中。
  3. desc 則只放料號的說明。我拿這個值來塞到畫面別處,讓使用者可以看到很長的料號說明。 將此三值分開,在前端可以方便使用。

組json 字串是當初花比較多時間的部份。


getString = String.valueOf 而已。  p 是取parameter 我自己簡化過的方式。

jQuery - 如何隱藏 select 下的 option. How to hide the options in select using jQuery.

$("#sel option").hide();    ?

沒辦法耶…

因為hide 不是跨瀏覽器的,至少 IE 8 無法達到這個效果。

網路上有一些solution,但是要以plugin 的方式進行,我覺得沒有必要。

最簡單的原則就是 「把option 搬走」

先宣告變數來裝。


var from_text="" ;
var to_text="";


$("#from_year").change(function(){
            if($(this).val()==''){                                                 
                from_text = $("#from_Q").html();                
                $("#from_Q option").remove();
            }else{
                $("#from_Q").html(from_text);
            }
        });

如果年選成空白的時候,把第幾季(Q1-Q4的select)的選擇搬走。
如果年選回某一年的時候,再把第幾季的文字加回來即可。


2012年8月3日 星期五

Android 如何使用外部gps 裝置?

大部份的android 智慧手機早有 GPS  晶片,何必還需要開 GPS  外部裝置呢?
我發現手機在「國外」(購買地外) ,打開 GPS  後定位的速度異常的慢。
查了一下才知道手機都有內建搜尋的國家,若非本國來說會比較慢。
並不清楚我的 GPS 裝置 ( Wintec ) 是否有類似的問題,不過試試看連外部裝置也是不錯的事。

最近離開購買國 ( 荷蘭 ) 後,在比利時旅行時的定位速度非常慢,所以想說透過之前已經買的 Wintec 來做實驗

首先去Google Play 下載Bluetooth GPS 。
安裝好之後,打開你的藍芽,也打開你GPS 的藍芽。
配對。連接。並且勾選用此軟體模擬你內部的GPS 晶片。
如此一來,你的Google Map 上就會出現小藍點了。中間不需要打開自己手機的 GPS 功能。


連外部 GPS 比較省電,還是使用內部的GPS 晶片比較省電? 目前還不得而知。

到時候去英國旅行的時候就可以知道效果如何了。
記得配溫開水服用「google 離線地圖」。
離線地圖 加 GPS ,真的是個無敵利器!
大部份的台灣人在本國使用3g 沒有感覺,但是出國旅行的時候,這樣的組合可以讓你免於迷路之苦。

如何將程式碼漂亮的post 在部落格中

最簡單的方法,就是去

http://formatmysourcecode.blogspot.nl/

將自己的程式貼上,按 format text ,再將結果貼回來即可。

Java - 如何透過jco 與 TimerTask 做自動資料同步

前提 :

  1. 自己的資料庫準備好對應的sap表格,欄位名稱和格式要確定好了。
  2. 在servlet 中也要設定這個程式何時要跑,這個就不多提了。
  3. 這個class 會繼承 TimerTask ,當servlet 設定的時間條件觸發時,便會執行。

說明 : 

  1. 本程式提供了成功、失敗寄信的考量。當失敗時會將java exception寄出。
  2. 若sap 的程式有變,只要在db 的表格中新增sap 多的欄位即可,不用動程式。
  3. 每100筆就會flush 出去,不會快速增加無用的暫存記憶體。



public void run() {
        Session s = null;
        JCoDestination jCoDestination = null;
        Transaction tx = null;
        Boolean trans_done = false;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
       
        synchronized (this) { // 一次只能有一個進程在執行
            try {    
                Boolean need_to_run = true;
                s = BaseDAO.getSession();
                tx = s.beginTransaction();
                RptLogger.logger.info("== START ==");
                RptLogger.logger.info(new Date());
                //如果沒有執行過 ,或是執行過失敗的時候會自動跑 : 有
              
                if(need_to_run){
 
                    RptLogger.logger.info("try to connect to  SAP Table ...");                                                
                    jCoDestination = ConnectSAPServer.ConnectDETest();
                    RptLogger.logger.info("connect to  SAP Table OK!");
                    JCoFunction function = jCoDestination.getRepository().getFunction("sap 提供的function name");
                    RptLogger.logger.info("get function OK!");
                    if (function == null)
                        throw new RuntimeException("function not found in SAP.");
    
                    // 傳入的參數
                    // SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
                    Calendar ca = Calendar.getInstance();
                    int this_year =  ca.get(Calendar.YEAR);
                    int this_month = ca.get(Calendar.MONTH)+1;
                    ca.add(Calendar.MONTH, -1);
                    int pre_year  = ca.get(Calendar.YEAR);
                    int pre_month = ca.get(Calendar.MONTH)+1;
                    //這邊是視你sap 程式的參數需要而加。
                    function.getImportParameterList().setValue("SALES_YEAR", this_year);
                    function.getImportParameterList().setValue("SALES_MONTH",this_month);
                    function.getImportParameterList().setValue("SALES_YACO", "COGS");
    
                    function.execute(jCoDestination);
    
                    JCoTable returnTable = function.getTableParameterList().getTable("sap 吐出來的表格名稱");
                    RptLogger.logger.info("get SAP Table OK!");
    
                    
                    List<String> header_cols = s.createSQLQuery("select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '你自己db的表格名稱'").list();
                         
                    String sql = "Insert into 你自己db的表格名稱(  ";
                    int x = 0;
                    for (String string : header_cols) {
                        sql = sql + string;
                        if (x != header_cols.size() - 1) {
                            sql = sql + ",";
                        }
                        x++;
                    }
                    x = 0;
                    sql = sql + ") values (";
                    for (String string : header_cols) {
                        sql = sql + "?";
                        if (x != header_cols.size() - 1) {
                            sql = sql + ",";
                        }
                        x++;
                    }
                    sql = sql +" ) ";
                    Query q = s.createSQLQuery(sql);
                 
                    RptLogger.logger.info("There are " + returnTable.getNumRows() + " rows to be inserted.");
                    if (returnTable.getNumRows() > 0) {
                        
                        returnTable.firstRow();
                        for (int i = 0; i < returnTable.getNumRows(); i++, returnTable.nextRow()) { // 總共幾筆資章要塞
                            x = 0;
                            for (String col : header_cols) {
                                q.setParameter(x, returnTable.getValue(col));
                                x++;
                            }
                            q.executeUpdate();
                            if (i % 100 == 0) {
                                s.flush();
                                s.clear();
                            }
                        }
                        s.flush();
                                                                       
                        tx.commit();
                        trans_done = true;
                        RptLogger.logger.info("== YURSWEBFICS END ==");
                    }
                    if(trans_done){                       
                        sendOKEmail();
                    }
                }
            } catch (Exception ex) {
                if (tx != null)
                    tx.rollback();
                ex.printStackTrace();
                StringWriter sw = new StringWriter();
                ex.printStackTrace(new PrintWriter(sw));
                RptLogger.logger.info(sw.toString());                                  
                sendWrongEmail(sw);                                                
            } finally {
                if (s != null && s.isOpen()) {
                    s.close();
                }
             
            }
        }
    }
    
    private void sendOKEmail() {
        MessageSender msender = MessageSender.getInstance();
        //寄ok信
        
    }

    private void sendWrongEmail(StringWriter sw) {
        MessageSender msender = MessageSender.getInstance();
        //寄失敗信,把java exception 寄出去,讓it可以第一時間抓到問題點。
    }
    

Java - 如何透過jco 連接SAP 程式

這一篇主要是一個共用的類別來連結,下一篇會提供可以動態將SAP 吐出來的表格原封不動的塞入自己Database的表格,當然,你這個自己的表格內容要和SAP 的一樣,可以少,但是不可以多。詳細內容是下一篇會介紹。


package com.deu.report.util;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;

import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.ext.DestinationDataProvider;

public class ConnectSAPServer {
     //SAP服務器IP地址 
   // static  String DEI_SAP_CONN_SERVER =   ; 
    //static  String T11 =  "172.test.test.test" ; 
     
    static  String DE_SAP_CONN =  "DE_SAP_CONN" ; 
    static  String DE_TEST_SAP_CONN =  "DE_TEST_SAP_CONN" ; 
     
    static { 
        Properties connectProperties =  new  Properties(); 
        connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "172.test.test.test");  
        connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR,   "00" );         //系統編號 
        connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT,  "025" );        //SAP集團 
        connectProperties.setProperty(DestinationDataProvider.JCO_USER,    "test" );   //SAP用戶名 
        connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD,  "test" );      //密碼 
        connectProperties.setProperty(DestinationDataProvider.JCO_LANG,    "EN" );         //登錄語言 
        connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY,  "3" );   //最大連接數 
        connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10" );      //最大連接線程 
     
        createDataFile(DEI_SAP_CONN,  "jcoDestination" , connectProperties); 
        
        connectProperties =  new  Properties(); 
        connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "172.16.test.test");  
        connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR,   "00" );         //系統編號 
        connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT,  "025" );        //SAP集團 
        connectProperties.setProperty(DestinationDataProvider.JCO_USER,    "test" );   //SAP用戶名 
        connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD,  "test" );      //密碼 
        connectProperties.setProperty(DestinationDataProvider.JCO_LANG,    "EN" );         //登錄語言 
        connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY,  "3" );   //最大連接數 
        connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10" );      //最大連接線程 
     
        createDataFile(DE_TEST_SAP_CONN,  "jcoDestination" , connectProperties); 
        
    } 
     
    static  void  createDataFile(String name, String suffix, Properties properties){ 
        File cfg =  new  File( name+ "." +suffix); 
        if (!cfg.exists()){ 
            try { 
                FileOutputStream fos =  new  FileOutputStream(cfg,  false ); 
                properties.store(fos,  "for DEI only !" ); 
                fos.close(); 
            } catch  (Exception e){ 
                throw  new  RuntimeException( "Unable to create the destination file "  + cfg.getName(), e); 
            } 
        } 
    } 
 
    public  static  JCoDestination ConnectDE(){ 
        JCoDestination destination = null ;    
        try  { 
            destination = JCoDestinationManager.getDestination( DE_SAP_CONN ); 
        }  catch  (JCoException e) { 
            e.printStackTrace();
        } 
         
        return  destination; 
    } 
    public  static  JCoDestination ConnectDETest(){ 
        JCoDestination destination = null ;    
        try  { 
            destination = JCoDestinationManager.getDestination( DE_TEST_SAP_CONN ); 
        }  catch  (JCoException e) { 
            e.printStackTrace();
        } 
         
        return  destination; 
    } 
}

Java - jco3 如何在windows + tomcat 下使用 ( 部署篇)

SAP JCO 主要用於 Java 呼叫 Sap 程式時使用。當然sap 的程式要開放remote call 與帳號密碼。

1. 首先要下載 jco  的不同版本,windows 主要是分32位元與64位元。
( 這部份可以向貴公司的sap 管理者請求,因為下載時需要提供sap伺服器的資訊 )

2. 將 sapjco3.jar 丟到 tomcat 的共用lib 下面。

3. 將 sapjco3.dll 丟到 C:\\Windows\System32 下

4. 要安裝 Microsoft Visual C++ 2005 SP1 在 tomcat server 那台機器上! 否則無法使用。

下二篇將紀錄如何透過 jco 呼叫 SAP 的程式。