2017年2月16日 星期四

Node.js 連接 Sql Server -

這邊紀錄如何使用node.js連接Sql Server的範例,

首先我使用的node.js module是mssql,它有npm網站連結及Github連結
只要用node.js 打上
npm install mssql
即可安裝

以下是範例程式碼,
var config = {
    user: 'XXX',
    password: 'XXX',
    server: 'XXX', // You can use 'localhost\\instance' to connect to named instance
    port: 0000,
    database: 'XXX'
    /*
    ,options: {
        encrypt: true // Use this if you're on Windows Azure
    }
    */
}
//獲取連線
var connection = new sql.Connection(config); 
connection.connect(function() {
 // Query 範例   
        //建立Request來進行query,query會回傳Promise,
        //call back function裡的recordset是一個陣例,為物件的集合,
        //物件各Key為Query結果的欄位名稱,Value為值
    new sql.Request(connection).query('SELECT * FROM someTable').then(function(recordset) {
  var i = 0;
  //印出各row的各個欄位
  for (i=0; i < recordset.length; i++){
   console.log(recordset[i].column1);
   console.log(recordset[i].column2);
   console.log(recordset[i].column3);
   connection.close();  //關閉連接
  }
 }).catch(function(err) {
  // ... error checks
  console.log(err);
  connection.close();  //關閉連接
 });
});

2017年1月28日 星期六

Ardulink2使用注意事項

之前有個專案使用了Arduino + Ardulink 2,發現了一些需要注意的地方,特別在這邊做個紀錄。


1.對於連續的指命呼叫,可能會送出錯誤的指令給Arduino,例如兩個指令被合併成一個,或指今被截斷,可以在指令中間隔1秒鐘(實測覺得1秒比較穩定)。

2.要從Arduino中送回資料給Java,可以使用alp://cevnt/XXX指令,例如:

Serial.print("alp://cevnt/");
Serial.print(inputString);
Serial.print('\n'); // End of Message
Serial.flush();

Java端可以用CustomListener的方法customEventReceived,ce.getMessage()來取得XXX。

Link.addCustomListener(new CustomListener() {
 @Override
 public void customEventReceived(CustomEvent ce) {                                    
  System.out.println(ce.getMessage());
 }
});

3.要從Java端送資料給Arduino,可以用Link的方法sendCustomMessage(String message)來傳送給Arduino,例如

Link.sendCustomMessage("XXX")

在Arduino中會得到如下指令

alp://cust/XXX

解析後就可以得到送給Arduino的資料

2016年12月18日 星期日

AngularJS中使用$http的POST不要傳送JSON格式給JSP, Servlet的方法

AngularJS 在用$http的angularjs service傳POST時,參數預設會用JSON的格式傳至url指定的後台,例如如果用以下的傳送方式:
$http({
   method: 'POST',
   url: 'xxx.do',
   data: {param1: "param1", param2: "param2"}
  })

後台例如Servlet會得到一串JSON格式的文字,像是 {'param1':'param1, 'param2' : 'param2},
但通常這並不是我們想要的key-value的型式,如果想要傳遞key-value型式的話,必須要用到
$httpParamSerializer這個angularjs service,並且設定header (不設定的話預設的Content-Type是application/json;charset=utf-8),使用方法如下:

$http({
   method: 'POST',
   url: 'xxx.do',
   data: $httpParamSerializer({param1: "param1", param2: "param2"}),
   headers: {
       'Content-Type': 'application/x-www-form-urlencoded'
   }
  })


這樣AngularJS就會以param1=param1&param2=param2的方式傳至後台了。

2016年12月12日 星期一

JQuery Ajax傳遞陣列時參數名不要帶中括弧的方法

JQuery的Ajax如果使用POST的話,似乎在1.4+版本後都會把陣列的參數名加上中括弧,例如以下:
$.ajax({
 method: "POST",
 url: "/xxx.do",
 data: {
    arrayParameter : ['1','2','3','4','5']         
 }
});

預設arrayParameter會以arrayParameter[]的參數名,值為1,2,3,4,5的方式傳進url指定的後台,例如果用Servlet去接的話就要用
String[] arrayParameter = request.getParameterValues("arrayParameter[]");
才能接到。
為了能夠讓JQuery傳的陣列參數不要帶上中括弧,必須指定ajax的traditional為true,例如:

$.ajax({
 traditional: true,
 method: "POST",
 url: "/xxx.do",
 data: {
    arrayParameter : ['1','2','3','4','5']         
 }
});

或是設定全局設定,讓每個ajax都能使用traditional的參數傳遞方式:
$.ajaxSetup({traditional: true});

參考資料:

  1. How do I remove the square brackets at the end of a JS variable name during AJAX calls?

2016年12月11日 星期日

Angular 簡易安裝使用 - Eclipse + Typescript plugin + System.js

Angular 的配置比起它的前一代AngularJs來說,稍微麻煩一點,因為涉及了typescript和module的使用。

在這裡我要介紹在Eclipse的開發環境中,以一個簡單的Angular 範列來說明如何簡單的在Eclipse中設置Angular 的初始設置。Typescript使用了Eclipse的typescript外掛、module使用了System.js。


需準備的步驟如下:

  1. node.js因為等下會使用到npm (Angular CLI),並且Eclipse的Typescript也需要用到node.js的功能,所以我們要先安裝node.js。
    node.js官網
  2. git for windows
    因為Angular CLI會需要用到git,所以需安裝windows版本的git。
    windows版本下載
  3. Angular CLI (選用)
    一個對於建置Angular 專案非常方便的工具,不過這裡為了要學習自己建置,所以只利用了Angular CLI來取得Angular 所需的modules,取得modules不一定要用Angular CLI,所以為選用。
    Angular CLI官方網站
  4. system.js
    這裡我們使用了system.js來使用javascript module,但也可選擇其他的module工具,例如webpack。

取得Angular 所需的modules
我們可以利用node.js的npm來安裝Angular 所需的modules (會放到node_modules資料夾中),
但這裡我們也可以利用Angular CLI來簡單取得modules,
安裝好Angular CLI後,可以在命令列視窗中使用
ng new XXX
來在當下資料夾中建立Angular專案,在建立好的專案資料中,可以
找到Angular 所需的modules已經都下載後放在node_modules資料夾中

Eclipse (這裡安裝的是neon版本) + Typescript plugin
Help --> Install New Software...
--> 加入一個連結 : http://eclipse-update.palantir.com/eclipse-typescript/
下載安裝Eclipse的Typescript plugin

建立我們的專案
以下是我們的檔案結構圖

其中紅色框裡的是我們會建立的,藍框則是Typescript plugin幫我們編譯產生的。
在這裡Typescript plugin不是也不需使用如tsconfig.json的設定檔,而是直接在Eclpse裡設定,
對著專案按右鍵,選擇 Properties --> Typescript 可以看到如下畫面,其中
Source folder(s): ts檔放置的位置
Exported folder(s): 在 import module時,預設的路徑位置,例如node_modules之下的import路徑不用再打node_modules,預設會先重這裡找
Output folder: ts編譯成的js檔要放置的位置
接著設定 Compiler,這邊可以位照下面的設定就好,紅色框是比較重要的設定
再來就可以開始製作Angular 的範例了。

/index.jsp:
<%@ page language="java" contentType="text/html; charset=BIG5" pageEncoding="BIG5"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=BIG5">
<title>Insert title here</title>

<script src="node_modules/core-js/client/shim.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="app/js/system.js"></script>
<script>
 System.config({
  defaultJSExtensions: true,
  paths: {
   'app/*': './app/*',
   '@angular/*': './node_modules/@angular/*',
   'rxjs/*': './node_modules/rxjs/*'
  },
  packageConfigPaths: ['./node_modules/@angular/*/package.json']
 });
 SystemJS.import('app/js/index.js');
</script>
</head>
<body>
 <my-app>Loading...</my-app>
</body>
</html>
其中Angular所需的shim.js、Reflect.js、zone.js雖然有被放在node_modules中,但因為它們並沒有寫成modules的型式,所以要直接用<script>來載入。
在這邊我們使用了system.js來載入module,System.config()設置了module的載入設定,以下說明:
defaultJSExtension: 如果為ture,則import module時可以不用寫副檔名,預設為js
paths:規定了module查找路徑,需注意的是在這裡除了使用了@angular之下的module,還有rxjs之下的module。
packageConfigPaths:預設先去尋找指定路徑資料夾內的package.json設定檔,如果找到了main屬性,以main指定的js檔案為要import的module

設定完後,用SytemJS.import()來載入此頁要用的,一開始的js程式。

/ts/index.ts:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

/ts/app.module.ts:
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }   from './app.component';
@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

/ts/app.component.ts
import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  template: '<h1>My First Angular2!!! App</h1>'
})
export class AppComponent { }


最後啟動Server,瀏覽index.jsp,應該就可以看到頁面一開始有Loading...字樣,然後很快變成My First Angular2!!! App的字的效果了
原始碼下載:

2016年11月28日 星期一

如何在Java上使用 pngquant png壓縮工具 (JNI)

pngquant是一個不錯的png圖檔縮工具,但它是用C語言寫成的,如果要用Java來使用它的話,就必需使用JNI (Iava Native Interface)的方式來調用C的程式,剛好工作上需要在Java的環境上使用它,特別在這紀錄下要使用pngquant的JNI流程。

pngquant的官網上有提供圖形化GUI的工具及命令列的Command-Line工具,如果要用程式碼的使用方式的話,可以點 "a library" 連結到它的 lib 網站 (libimagequant),在lib網站中,可以看到許多不同語言的使用方式。

我的環境是Windows 7,jdk1.5.0_15,必須製作相應libimagequant專案的dll檔。
制作dll檔有許多方式,libimagequant官網給Windows的建議為使用Viusal Studio或MinGW工具來產生dll,我選擇最簡單的方式,去Microsoft官網下載安裝Visual Studio 2015來用。

點擊 "MSVC-compatible branch of the library" 可連到MSVC版lib的Git網站,把整個專案下載下來後,就可以開始進行JNI的步驟。

以下是JNI的詳細步驟:

  1. 使用命令列視窗(cmd)到下載並已被解壓縮的libimagequant-msvc資料夾,打上以下指令來產生相應PngQuant.class、Image.class、 Result.class (Class檔請自行compile產生)的 標頭檔 (副檔名為h)
    javah org.pngquant.PngQuant
    javah org.pngquant.Image
    javah org.pngquant.Result
    產生出來的檔名會被多加一些前綴,把它們都刪掉,再把得到的pngQuant.h、Image.h、Result.h丟到org/pngquant的目錄下。
  2. 開啟Visual Studio 2015,New 一個 Win32 Project,Application type選 DLL ,Additional options選Empty Project就好。
  3. 先把org/pngquant/PngQuant.c丟到org外面那層(因為要配合裡面寫的include的path路徑),在Solution Explorer的Source File中,將全部檔(包括org資料夾之下)都Add進去(有些其實用不到,不過沒關係都先丟進去)
  4. 這時看PngQuant.h可能會發現有被畫紅線的Error,對專案安右鍵選擇"Properties" --> Configuration --> C/C++  設定 Additional Include Directories ,請設定jdk中include和include/win32的位置,例如以下路徑:
    C:\Program Files (x86)\Java\jdk1.5.0_15\include
    C:\Program Files (x86)\Java\jdk1.5.0_15\include\win32
    然後將專案的mode從debug改成release
  5. 開啟Eclipse,建立一個測試專案,將org/pngquant下的java檔全部丟到專案中,並且再將Visual Studio release出來的dll檔丟進去。
    撰寫一個測試的程式,例如叫做libimagequantTest.java,內容如下:
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    
    import javax.imageio.ImageIO;
    
    import org.pngquant.PngQuant;
    
    public class libimagequantTest {
    
     public static void main(String[] args) {
       BufferedImage newImg;
       
       PngQuant pngQuant = new PngQuant();
       
       try {
        newImg = pngQuant.getRemapped(ImageIO.read(new File("D:\\old_picture.png")));
        ImageIO.write(newImg, "png", new File("D:\\new_picture.png"));
       } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
       }
       
       pngQuant.close();
     }
    
    }
    
    最後的檔案結構會像這樣
  6. 在專案上按右鍵選擇Properties --> Java Build Path 設定 Nativ Library Location,例如此例我設定的是
    libimagequant_Test/src/org/pngquant
  7. 最後放上一張檔案大小較大的圖 D:\\old_picture.png,執行libimagequantTest.java,如果有出現另一張圖D:\\new_picture.png,就代表大功告成了。
源始碼下載:
pngquant JNI_Test.7z

2016年11月27日 星期日

Ardulink - Arduino的Java控制方案

Ardulink是一個開源Arduino的Java解決方案,提供了使用Java來控制Arduino的方法,讓Java操作Arduino版子變的更簡單,其源裡是先再Arduino上寫入程式,用來監聽從序列阜(Serial Port)上傳來的指令並做相應的操作、也用序列阜傳回相應的回應,序列阜的連接方式用到了之前文章"用Java與Arduino的序列阜溝通(使用RXTX)"講到的RXTX,而Java就用包好的API來對Arduino送指令。

要使用Ardulink,可以先到Ardulink的下載頁下載,會得到一個壓縮檔,找個位置解壓縮後就可以開始進行Ardulink的Java範例,LED閃光(BlinkLED),下面講解詳細步驟:
  1. 下載Ardulink並解壓縮以後,可以看到如下的檔案結構。
    我們會需要用到的有"winDLLs"及"lib"資料夾。
    打開winDLLs,可以看到32bit和64bit兩個資料夾,依自已需求選擇打開資料夾後可以再看到三個檔案:LibusbJava.dll、RXTXcomm.jar、rxtxSerial.dll,
    LibusbJava.dll及rxtxSerial.dll是Java使用JNI要用的檔案。
    RXTXcomm.jar是Java要引入lib的其中一個檔案。
    lib資料夾裡的檔案是要給Java要引入的lib。
    而在bin資料夾裡面,放了兩個bat檔,其內容就只是幫忙把LibusbJava.dll、RXTXcomm.jar、rxtxSerial.dll放到lib資料夾而已。
    為了之後方便且起,在這裡我也把LibusbJava.dll、RXTXcomm.jar、rxtxSerial.dll通通放到lib資料夾。
  2. 接著是Arduino這端,我們必需要先再Arduino版子上寫入Serial Port溝通相關的程式,打開sketches資料夾,可以看到許多角本,這邊選擇ArdulinkProtocol裡的ArdulinkProtocol.ino執行就好,當然如果有相應的版子也可以選擇相應的角本,例如Digispark可以選擇ArdulinkProtocol4Digispark。
    需要注意的是,也為不同型號的版子有些許不同,例如Arduino Due目前沒支援tone()和noTone()這兩個函式,所以要稍微修改角本,因為我使用的是Arduino Due,為了簡單測試方便,就先把用到tone()和noTone()的指令先注解掉。
  3. 再來是Java這端,這裡以Eclipse Neon IDE及jdk1.8.0_05為例,檔案結構如下,
    BlinkLED是我們的主程式,用來控制Arduino的LED燈開闗(第13號PIN),先把剛剛lib資料夾裡的jar檔及RXTXcomm.jar引入library中。
    接著設定專案的Native library location,路徑為LibusbJava.dll、rxtxSerial.dll所在的路徑。
    BlinkLED.java的內容如下(參考https://github.com/Ardulink/Ardulink-2),作用為一秒亮、一秒暗Arduino板子的LED燈(Pin 13)。
    import java.io.IOException;
    import java.util.concurrent.TimeUnit;
    
    import org.ardulink.core.Link;
    import org.ardulink.core.Pin;
    import org.ardulink.core.Pin.DigitalPin;
    import org.ardulink.core.convenience.Links;
    
    public class BlinkLED {
    
     public static void main(String[] args) {
          Link link = Links.getDefault();
             DigitalPin pin = Pin.digitalPin(13);  //這裡13 pin是板子的LED燈
             boolean power = true;
             while (true) {
                 System.out.println("Send power:" + power);
                 try {
                  //swicthDigitalPin()為數位輸出,對應了Arduino的digitalWrite()
         link.switchDigitalPin(pin, power);  
         power = !power;
                  TimeUnit.SECONDS.sleep(1);  //1秒亮、1秒暗
        } catch (IOException | InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
        }             
             }
     }
    }
    
  4. 執行BlinkLED.java後,應該就可以看到Arduino板子上的LED燈一亮一暗了。
    執行時可能會有下警告訊息,主要是RXTX版本及SLF4J Class衝突等警告,不過並不會影響程式運行,所以可暫且忽略。
    Stable Library
    =========================================
    Native lib Version = RXTX-2.2-20081207 Cloudhopper Build rxtx.cloudhopper.net
    Java lib Version   = RXTX-2.1-7
    WARNING:  RXTX Version mismatch
     Jar version = RXTX-2.1-7
     native lib Version = RXTX-2.2-20081207 Cloudhopper Build rxtx.cloudhopper.net
    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/C:/Users/Administrator/Downloads/ardulink/lib/slf4j-jdk14-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/C:/Users/Administrator/Downloads/ardulink/lib/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [org.slf4j.impl.JDK14LoggerFactory]



附注:
Ardulink有做一個UI介面可以跟Arduino板子作連接並控制(ardulink-console-2.0.1.jar),放在下載下來的 lib/ardulink-console-2.0.1.jar,在執行set32bitWindowsRXTX.bat或set64bitWindowsRXTX.bat(或自己手動把LibusbJava.dll、RXTXcomm.jar、rxtxSerial.dll丟到lib資料下)後,可以直接開啟ardulink-console-2.0.1.jar,看到如下視窗介面,按下Connect與Arduino連接後,在許多功能可以使用,對於想要測一下Arduino,還不想花太多時間寫程式時是個不錯的工具。