2015年12月8日

Gradle(17) Android開發

前言

本章會介紹如何建立基本Android應用,我們開發主要Android Strudio做為開發工具,選擇Gradle為建構
工具主要的原因,是因為它已經是官方的開發工具,你只需要寫幾行建構方式,就可以給不同平台去使用。

事前準備

下載Android Strudio:  http://developer.android.com/sdk/index.html

建立Android APP專案

File –> New –> New Project…

Image 21

選擇目的裝置的類型: 選擇平板和手機

Image 22

選擇空白活動

Image 23

預設活動名稱和版面名稱不變
Image 24

專案家目錄可以看到build.gradle和settings.gradle,

Image 16

Gradle Scripts檔案 說明
build.gradle  
local.properties sdk.dir=<Location of Android sdk>



settings.gralde  

在android專案會有兩個build.gradle的檔案,一個是/app/build.gradle和/root/build.gradle,
(1) root/app/build.gradle

apply plugin: 'com.android.application'

android {
compileSdkVersion 23
buildToolsVersion "23.0.1"

defaultConfig {
applicationId "tw.com.bryan.myapplication"
minSdkVersion 8
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.0'
compile 'com.android.support:design:23.1.0'
}

2015年12月3日

Gradle(15)–– 深入Gradle專案

目標
本章深入介紹多個專案、屬性管理和日誌功能三方面討論,多個專案建置會由一個主專案的build.gradle
編譯各個子專案模組。這樣方便管理每個專案的功能。

  • War plugin

網頁專案通常會打包成.war或是.ear的檔案形式,在.gradle需要加入下列任務後,在建構的過程中,war會
取代原先的jar任務,

apply plugin : "war"    //打包為.war檔案
apply plugin : “ear”     //打包為.ear檔案

使用gradle建構網頁專案,在src/main/java裡面為java檔、/src/main/webapp為jsp檔與WEB-INF檔案

image

在war plugin裡面增加providedCompile和providedRuntime跟java plugin的complie和runtime相同,於不同的地方
它不會為打包入war檔案中,下面為例servlet-api:2.5將不會被打包進去WEB-INF/lib/裡面,因為這些在tomcat的
lib就有提供。

apply plugin: “war”

repositories{
   mavenCentral()
}

dependencies{
    providedCompile "javax.servlet:servlet-api:2.1"

}

 

apply plugin: 'war'

webAppDirName="WebContent"

repositories {
     mavenCentral()
}
dependencies {
      providedCompile "javax.servlet:servlet-api:2.1"

}

war{
    baseName = "simpleapp"
    version = "1.0"
    extension = "war"
    includeEmptyDirs = false
}

 

  • 日誌

日誌可以提供開發者方便區分資訊分級程度,

日誌層級 描述
ERROR 錯誤資訊
QUIET 使用者資訊
WARNING 警告資訊
LIFECYCLE 程序資訊(預設)
INFO 一般資訊
DEBUG 所有資訊

task showLogging << {
println "This is println example"
    logger.error "This is error message"
    logger.quiet "This is quiet message"
    logger.warn "This is WARNING message"
    logger.lifecycle "This is LIFECYCLE message"
    logger.info "This is INFO message"
    logger.debug "This is DEBUG message"
}

>gralde showLoggin


  • 多專案建立

(1)
本節我們會說明多專案的建立,當我們有一個root專案為team,底下有三個專案: Tool、application和Employee
。application專案需要呼叫Tool和Employee方法。如圖所示

Image3

settings.gradle

include ':Tool',':application',':Employee'

build.gradle

apply plugin: 'java'
apply plugin: 'eclipse'
 
project(":Tool"){
    apply plugin: "java"
    println "project name is $name"
    task toolTask << {
        println "Task name is $name"
    }
}

project(":Employee"){
   apply plugin: 'java'

    repositories {
        mavenCentral()
    }
   println "Project name is $name"
    task employeeTask << {
        println "Task name is $name"
    }
}

project(":application"){
   apply plugin: 'java'
    println "Project name is $name"
 
    dependencies{
        compile project(':Employee')
        compile project(':Tool')
    }

}

(2) Flat 階層
我們可以同階層來當作子專案(subproject),使用includeFlat ‘專案名稱’

includeFlat ‘application’

2015年11月28日

Gradle(14)–– Dependency Management

目標
在本章我們會著重在如何管理專案相依、解決相互衝突、解析策略並教你如何發佈artifacts
在不同的元件版本下。

歷史相依管理在建構工具是一個很重要的指標,在傳統的ANT建構工具,他無法幫你處理相依
問題,你必須自己將每一個jar名稱和它的位置寫在build.xml。但是在企業應用,有些軟體
會相依其他函式庫,使用ANT的方式,需要花費很多成本去維護相依的問題。後來,Maven
解決這個缺點,ANT整合Ivy也是解決這個問題。在Gradle有自己的相依管理方式,同時它也
支援Ivy和Maven的套件。Gradle主要定義相依關係

  • 相依環境
當我們開發完成的軟體套件,必須要做版本部署並儲存中央版本庫(central repository),讓所有
團隊可以分享使用這些軟體套件。版本命名參考http://semver.org/

  • Gradle相依管理
gradle相依管理定義在dependencies裡面,需要遵循它的規則和定義方式即可。
宣告相依定義:
dependencies
{
    <configuration name> <dependencies>
}

區塊內定義方式:
1. 個別定義
    compile group: 'log4j', name: 'log4j', version: '1.2.16'
2.陣列定義:
   compile 'log4j:log4j:1.2.16','junit:junit:4.10'
3. Closure定義:
   compile ('log4j:log4j:1.2.16') ) {
            // extra configurations
   }

apply plugin: 'java'repositories {
       
mavenCentral()}
dependencies {
        compile group: 'log4j', name: 'log4j', version: '1.2.16'
}

  • 版本庫(Repositories)
建立版本庫是告訴dependencies要去哪裡下載套件,他會檢查群組、名稱和版本
,符合才下載到gradle版本庫中。

1. 內建版本庫
(1) Maven Central repository :  mavenCentral()
(2) Maven JCenter repository:  jcenter()
(3) Maven local Repository :    mavenLocal()
(4) Ivy repository:    
   ivy {
       url "
http://<ivyrepositorylocation>"
       layout "ivy" // valid values are maven, gradle, ivy
   }

(5) Organization repository: 你可以為你的公司定義私人的程式庫。
repositories {
   maven {
      url "
http://private.repository/path"
      credentials {
        username 'guest'
        password '123123'
     }
   }
   ivy { // For Ivy repositories
   url "
http://private.repository/path"
   }
}

(6) Local directory repository : 有時候開發軟體載入相依性,會用到本地系統檔案目錄,可以定義flatDir方法。
repositories {
   flatDir {
       dirs '/localfile/dir1', '/localfile/dir2'
   }
}

  • 相依深入解析
剛剛介紹相依探討,本節介紹如何解析如何
(1) 遞移相依 :
當套件相依另一個套件時,另一個套件有相依其它套件,一層層的相依關係,可以稱為遞移相依,例如
commons-httpclient –> commons-logging –> 其它套件->…。Gradle會處理這些複雜的相依關係,預設
將這些相依下載到最後一層。

(2)排除相依設定

(2.1) 完全排除(Exclude)
有些情況,你不希望gradle處理相依問題,我們可以使用將transitive為off,
範例一、 只下載commons-httpclient套件apply plugin:'java'
repositories {
          mavenCentral()
}

dependencies {
     compile group:'commons-httpclient', name:'commons-httpclient',
     version:'3.1',
transitive: false}

(2.2) 選擇排除(selective)
如果你不想要全部都不檢查相依,只是部分檢查可以使用exclude定義
dependencies{
    compile('commons-httpclient:commons-httpclient:3.1') {
    exclude group:'commons-codec' // exclude by group
     //exclude group:'commons-codec',module:'commons-codec'
    }
}


(3)動態訂義相依版本

(3.1)版本
Gradle抓取版本超過1.0以上的,如果是用'latest.integration只會捉最新的版本。
compile group:'commons-codec',name:'commons-codec', version: '1.+'
compile group:'commons-codec',name:'commons-codec', version:'latest.integration’

(3.2)副檔名
當我們用ext只會下載所定義的副檔名,範例只會下載 .war的檔案下來。
dependencies {
     runtime group: 'org.mywar', name: 'sampleWeb', version: '1.0',
    
ext: 'war'}

(3.3)特定檔案名稱
當我們利用classifier來定義特定下載檔案名稱,例如版本庫有兩個jar檔為assys-1.0-test.jar和assys-1.0-publish.jar
兩種。使用classifier只會下載publish的jar檔下來。
dependencies {
    runtime group: 'org.assys, name: ‘assys’, version: '1.0',  classifier: 'publish', ext:'war'
}

  • 報表
我們可以顯示本專案各任務的所有相依關係,例如: compile、testCompile等等

build.gradle
apply plugin: 'java'
version=1.0
repositories {
    mavenCentral()
}
dependencies {
     testCompile 'junit:junit:4+'
    compile group: 'log4j', name: 'log4j', version: '1.2.16'
    compile 'commons-httpclient:commons-httpclient:3.1'
    compile 'dom4j:dom4j:1.6.1'
}
C:\Users\bryan\workspace\ex1>gradle -b build.gradle dependencies
:dependencies
------------------------------------------------------------
Root project
------------------------------------------------------------
archives - Configuration for archive artifacts.
No dependencies
compile - Compile classpath for source set 'main'.
Download https://repo1.maven.org/maven2/commons-httpclient/commons-httpclient/3.
1/commons-httpclient-3.1.pom
Download https://repo1.maven.org/maven2/dom4j/dom4j/1.6.1/dom4j-1.6.1.pom
Download https://repo1.maven.org/maven2/commons-logging/commons-logging/1.0.4/co
mmons-logging-1.0.4.pom
Download https://repo1.maven.org/maven2/commons-codec/commons-codec/1.2/commons-
codec-1.2.pom
Download https://repo1.maven.org/maven2/xml-apis/xml-apis/1.0.b2/xml-apis-1.0.b2
.pom
+--- log4j:log4j:1.2.16
+--- commons-httpclient:commons-httpclient:3.1
|    +--- commons-logging:commons-logging:1.0.4
|    \--- commons-codec:commons-codec:1.2
\--- dom4j:dom4j:1.6.1
     \--- xml-apis:xml-apis:1.0.b2
default - Configuration for default artifacts.
+--- log4j:log4j:1.2.16
+--- commons-httpclient:commons-httpclient:3.1
|    +--- commons-logging:commons-logging:1.0.4
|    \--- commons-codec:commons-codec:1.2
\--- dom4j:dom4j:1.6.1
     \--- xml-apis:xml-apis:1.0.b2
runtime - Runtime classpath for source set 'main'.
+--- log4j:log4j:1.2.16
+--- commons-httpclient:commons-httpclient:3.1
|    +--- commons-logging:commons-logging:1.0.4
|    \--- commons-codec:commons-codec:1.2
\--- dom4j:dom4j:1.6.1
     \--- xml-apis:xml-apis:1.0.b2
testCompile - Compile classpath for source set 'test'.
+--- log4j:log4j:1.2.16
+--- commons-httpclient:commons-httpclient:3.1
|    +--- commons-logging:commons-logging:1.0.4
|    \--- commons-codec:commons-codec:1.2
+--- dom4j:dom4j:1.6.1
|    \--- xml-apis:xml-apis:1.0.b2
\--- junit:junit:4+ -> 4.12
     \--- org.hamcrest:hamcrest-core:1.3
testRuntime - Runtime classpath for source set 'test'.
+--- log4j:log4j:1.2.16
+--- commons-httpclient:commons-httpclient:3.1
|    +--- commons-logging:commons-logging:1.0.4
|    \--- commons-codec:commons-codec:1.2
+--- dom4j:dom4j:1.6.1
|    \--- xml-apis:xml-apis:1.0.b2
\--- junit:junit:4+ -> 4.12
     \--- org.hamcrest:hamcrest-core:1.3
BUILD SUCCESSFUL
Total time: 20.567 secs

2015年11月27日

Gradle(13)–– Plugin Management

前面有介紹如何建立web專案或是Java專案等等,本章詳細說明Gralde

  • 多Gradle腳本運用

當你需要載入其他gradle腳本時,使用apply from 還載入

語法: apply from: <Path of otherfile.gradle>

範例一、 多Gradle腳本載入

C\:>calcuate.gradle   //計算

apply plugin: 'java'
task task1 {
    println "task1"
}


C\:>project.gradle

apply from:  "calcuate.gradle"

task  mainTask {
    println "It is a main task!"
}

結果

task1
It is a main task!



二位元插件
二進位插件必須實做Plugin的介面功能後,你可以載入它到你的建構腳本。Gradle已經內件函式庫
可以使用。如果你想要使用其他third-party pluings,需要確定可用的classpath路徑,請使用buildscript{}
來設定。

語法 : apply plugin: '<pluginid>'
範例一、 apply plugin : “java”

  • Gradles內建plugins

(1) 建構和測試常用plugins
     Java , Groovy , Scala,  War
(2) 分析plugins
    Checkstyle ,FindBugs ,Sonar ,Sonar Runner ,PMD
(3) IDE plugins
     Eclipse, IDEA ..etc

參考: https://docs.gradle.org/current/userguide/userguide.

  • Third plugins

https://plugins.gradle.org/

  • Java plugin

Java plugin是Gradle的核心一部份,它可以保證我們建構Java專案可以正確編譯、測試和打包。
載入方式為apply plugin: 'java'。

接下來討論建構的任務,我們可以在命令列執行下列的指令:
$ gradle tasks --all

可以看出顯示任務不同有建構任務、測式任務、文件任務等等,使用Java plugin需要符合內建的規範
例如: compileJava和processResources會執行src/main/java 的src/main/resources內的檔案,所以將
完成的java檔和環境設定檔需要分別放在src/main/java 的src/main/resources裡面。接下來我們會說明
gradle的Java plugin指令的功用

範例一、當編譯在src/main底下的java檔案,我們可以使用任務 classes,編譯後的.classes會放在
/build/classes底下,可以下面看到gradle所執行任務的流程。

$ gradle classes

:compileJava
:processResources UP-TO-DATE
:classes

範例二、testClasses用來編譯測試檔與測試環境,編譯後的.classes會放在/build/classes/test底下,
可以下面看到gradle所執行任務的流程。

$ gradle testClasses

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE

範例三、任務test除了編譯檔案外,他會幫我們產生測試報表,放在/build/reports裡面

$ gradle test

C:\Users\bryan\workspace\ex1>gradle test
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE                                                  //執行junit並產生報表

範例四、使用assemble任務或是jar任務會打包.class和resource的資料到jar檔中並放在build/libs
檔案命名為<project-name>.jar ,如果有加入版本會以<name>-<version>.jar.

$ gradle assemble

Total time: 11.204 secs
C:\Users\bryan\workspace\ex1>gradle assemble
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:assemble

範例五、 Gradle也有提供一連串完成的任務叫做build,它會從編譯、打包、測試到完整執行,就不需要
分別的執行,其中clean任務會先清除在build/裡面的資料,再進行build任務

$ gradle clean
$ gradle build

C:\Users\bryan\workspace\ex1>gradle clean
:clean

Total time: 5.866 secs
C:\Users\bryan\workspace\ex1>gradle build
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build UP-TO-DATE

BUILD SUCCESSFUL

範例六、可以在build.gradle列印出這些變數,顯示出目前目前專案libs路徑、程式的路徑等等。詳細可以查https://docs.gradle.org/current/userguide/java_plugin.html.

task displayJavaPluginConvention << {
    println "Lib Directory: $libsDir"
    println "Lib Directory Name: $libsDirName"
    println "Reports Directory: $reportsDir"
    println "Test Result Directory: $testResultsDir"
    println "Source Code in two sourcesets: $sourceSets"
    println "Production Code: ${sourceSets.main.java.srcDirs}"
    println "Test Code: ${sourceSets.test.java.srcDirs}"
    println "Production code output: ${sourceSets.main.output.classesDir}  ${sourceSets.main.output.resourcesDir}"
    println "Test code output: ${sourceSets.test.output.classesDir}  ${sourceSets.test.output.resourcesDir}"

}

  • 專案環境設定

在上面我們學到如何是用預設環境(default properties or conventions)去建立java專案且可以成功編譯,在本節
會學習到如何根據我們的需求客置設定環境

範例一、我們有一個專案需要將編譯的路徑做一些調整如下:
系統預設: src/main/java  => src/sale
系統預設:  src/test/java   => src/saleTest
系統預設:

buildDir = 'buildfolder'
libsDirName = 'libfolder'
sourceSets {
main {
     java {
         srcDir 'src/sale/java'
      }
      resources {
      srcDir 'src/saleTest/resources'
     }
  }
test{
    java {
        srcDir 'src/testcode/java'
         }
        resources {
        srcDir 'src/testcode/resources'
     }
  }
}

testResultsDirName = "$buildDir/new-test-result"
sourceSets.main.output.classesDir="${buildDir}/classes/sale/java"
sourceSets.main.output.resourcesDir="${buildDir}/classes/sale/resources"
sourceSets.test.output.classesDir="${buildDir}/classes/saleTest/java"
sourceSets.test.output.resourcesDir="${buildDir}/classes/saleTest/resources"

2015年11月22日

Gradle(12)–– Groovy

本章會介紹Gradle的核心語法為Groovy,讓使用者更容易了解gradle工具使用,Groovy運行在JVM上面,
所以很容易與Java做整合利用。

  • 資料類型
Data type Wrapper type values
byte Byte 0
short Short 0
int Integer 0
long Logn 0L
float Float 0.0f
double Double 0.0d
char Character \u0000
boolean Boolean false
String Not Applicable null

資料型態跟Java相同,現在介紹如何宣告變數,

範例一、 宣告變數
def a1 = ‘ It is a sunday.’
def a2 = “It is a sunday.”
def a3 = “example1. ${a1}”
def a4 =/ This is                //斷航符號 /
              a
             book /

  • 動態型別(Dynamic typing)宣告

Groovy支援動態型別與靜態型別兩種,靜態型別通常會再編譯時檢查、記憶體最佳化等等工作。
動態型別表示你不知道宣告的函式的型態或回傳的資料類型是什麼,但是這種方式開發人員比較
有彈性宣告方式。當我宣告時,不會預設型別給宣告之變數,會決定變數型別是在執行的時候才
會決定要丟甚麼型別給他。

範例二、動態型別宣告
//(1) 宣告變數
def  var1
var1 = “It’s a book”
println var1.class       // java.lang.String
var1 = 10
println var1.class      // class java.lang.Integer

//(2) 宣告函式
def addition(a,b) 
addition(1,2)
addition(‘Jack’,‘Janet’)

 

  • 控制結構
    常用的控制語法有if、else、for、switch等等,在groovy也有相同的用法

(1) if-lelse
二元運算:

if( a<input){
    println input
}else{
    println a
}


三元運算
(a<input) ? input : a

(2) switch

switch(input)
{
    case Integer : println("Integer Matched"); break;
    case BigDecimal : println("BigDecimal Matched");break;
    case String : println("String Matched");break;
    default : println("Nothing Matched"); break;
}


(3) for

def fruit = ['apple','banana','strawberry']
for(String s : fruit){
    println s
}


(4) while

int count = 0
while(count < 5) {
     println count++
}

  • 集合

(1) Set
集合是一群沒有排序且不重複物件,set集合可以有Null的資料,常用方法有add, addAll, remove, or removeAll

def set1 = [1,2,3,4,5,6] as Set
def set2 = new HashSet(['a','b','c','d'])

set1.add(7)
set1.add([8,9])
print set1                  //[1, 2, 3, 4, 5, 6, 7, [8, 9],]

set2.remove('d')
println set2              // [a, b, c]

Set union = set1 + set2
println union            // [1, 2, 3, 4, 5, 6, 7, [8, 9], a, b, c]

(2)List

List是一組有順序並且可以有重覆資料的物件集合,

def list1 = ['a','d','c']
def list2 = [5,1,7,2,9,1] as list

println list1[1]              // d
println list1.get(1)         // d
println list2.sort()         //[1, 1, 2, 5, 7, 9]
println list1.reverse()    // [c, d, a]

(3) Map
Map是一種主鍵-值的集合,為java.util.HashMap.

Map ageMap = [Jack:20, MaraYa:30,Katy:16,Li:19,Herry:18] as Map
ageMap.each{key, value ->
   print "Name is "+key
    print "Age is "+ value
   print "\n"
}

ageMap.each{entry –>
    print "Name is "+entry.key
    print "Age is "+ entry.value
    print "\n"
}

//結果
// Name is JackAge is 20
// Name is MaraYaAge is 30
// Name is KatyAge is 16
// Name is LiAge is 19
// Name is HerryAge is 18

(4) Range
這是Groovy特有的集合物件,用來做連續數列的集合。

def range1 = 1..10
Range range2 = 'c'..'e'
range1.each { print it }    //12345678910
range1.any { it > 5 }
range1.every { it > 0 }

List list3 = range1.step(2)
print list1                   // [a, d, c]

 

  • Closure

Closurer可以當作函式來使用,但是不需要回傳值或是輸入值會自動回傳,

範例一、 加法closure

def add = { it + it}
add("Hi!")                      // Hi!Hi!
add()                            // null + null => NullPointerException

closure會將外部變數的值,自動配置成內部的值,變數名稱要相同

範例二、 外部變數參考

def name="bryant"
def sayHello = { println name + " hello "}
sayHello()                            // bryant hello


Gradle(11)–– Eclipse for Gradle


本章會介紹使用Eclipse,如何安裝Gradle套件與應用

  • 安裝篇

步驟1 : Help -> Eclipse MaketPlace...

image

步驟2: 在Find打上gralde 按下 Go按鈕,如果未安裝請你按下Install ,已經安裝過,確定是否要更新gralde版本

image

步驟3 : 接著只要一直按next,最後按finish就可以在eclipse使用gradle

2015年11月18日

Gradle(10)–– Web專案

在本章節我們會介紹使用gradle架構下,web專案的架構和常用的設定

  • web 架構

(1) 專案架構

+---bank
+------src
+-----------main
+-------------------java
+---------------------|---com
+---------------------------|-account
+--------------------------------|----createAccount.java                  
+--------------------webapp
+------------------------------jsp/
+-----------------------------------Account.jsp

 

apply plugin: ‘java’
apply plugin: ‘eclipse-wtp’   //有使用eclispe需要

2015年5月19日

3.2 組織網頁應用產品(Webapp)

  • Yeoman介紹
    我們建議使用Yeoman來發展你的網頁應用產品,他整合很多JS前端的技術,例如BootstrapCompassModernizrCoffeeScriptJasminePhantomJSGrunt等。

  • Yeoman軟體開發流程
    在軟體開發流程階段可以分為需求訪談、產品分析、產品開發、產品測試和上線,這些步驟Yeoman有提供完整前端開發工具與架構。在官方網站可以看到下圖Yeoman前端開發流程架構圖,從產品開發到上線,Yeoman 首先利用yo工具快速開發網頁的骨架、當會載入不同JS框架時可以應用bower框架之間相依性,最後產品上線前會經過壓縮、測試、打包 package 等佈署動作這些可以使用grunt完成。

    yeoman

    Yeoman包含三套工具
    (1) yo      : 當建構新的應用系統,可以用來建立新的建構環境
    (2) bower : 套件管理用來管理JS框架之間的相依關係
    (3) grunt  :  部屬前檔案壓縮、預覽、測試webapp專案

  • Yeoman環境安裝
    為了可以安裝Yeoman的架構,我們必須先安裝node.js , Git for WindowsRubyInstaller 這三套工具,
    才可以安裝Yeoman的工具,

    Step1. 下載node.js,安裝node.js: https://nodejs.org/download/
    注意: 需要安裝python 2.6或是python 2.7
    nodejs

    確定是否安裝成功
    image

    Step2. 下載git安裝,git : https://git-scm.com/

    git

    確定git安裝成功
    image

    Step3. 下載ruby安裝 :http://rubyinstaller.org/downloads/
    image

    安裝時,注意的事項
    ruby

    image

 

  • Yeoman安裝
    步驟一、確定node.js版本與npm的版本
    在命令列輸入:

    node --version && npm --version
    v0.12.3
    2.9.1


    步驟二: 安裝yo bower和 grunt套件
    C:\Users\bryan\npm> npm install --global yo bower grunt-cli
    …安裝明細

    C:\Users\bryan\npm>node --version && npm --version
    v0.12.3
    2.9.1


    步驟三: 安裝產生器
    (1) 安裝webapp產生器
    C:\Users\bryan\npm> npm install -g generator-webapp

    (2) 安裝angular產生器
    C:\Users\bryan\npm> npm install -g generator-angular






3.1前言


我們接下來介紹使用AngularJS開發產品時,使用哪些工具或是方法會讓開發流程更有效率且符合軟體開發流程使用。

  1. 如何規畫網頁應用程式開發用於快速應用程式開發模式
  2. 使用Karma工具用於單元測試
  3. 產品佈署時,將AngularJS編碼編譯為最小化
  4. 使用Batarang來偵錯(debug)
  5. 簡化開發流程
  6. 整合RequireJS來管理版本JS函式庫相依性





2015年5月17日

Router and Multiple Views

  • Router and Multiple Views 介紹
    在angularJS提供一個很強大的功能叫作路由(router),主要應用在切換不同model和views,更容易做出SPA( Single Page Application)註一等級的產品。本章我們介紹如何利用ngRoute的模組切換不同的網頁視圖。
註一: SPA 的概念傳統的 HTML 網頁一樣,需要每做一個動作就整個更新網頁,但是SAP希望可以像視窗軟體一樣,只需要變更顯示的內容而不需更新整個網頁。
  • 載入路由功能
    <head>
         <script src="angular.js" />
        <script src="angular-route.js"/></head>
  • 定義路徑與規畫控制器
    我們利用$routeProvider來切換網頁內容,下列範例定/home, /viewItems
    兩個畫面規畫。在mainApp.controller控制器來切換/home, /viewItems的
    之內容。


    itemController.js
    var mainApp = angular.module("mainApp", ['ngRoute']);

    mainApp.config(function($routeProvider) {
       $routeProvider
            .when('/home', {
                templateUrl: 'home.html',
                controller: 'ItemController'
            })
            .when('/viewItems', {
                templateUrl: 'viewItems.html',
                controller: 'ItemController'
            })
            .otherwise({
                redirectTo: '/home'
            });
    });

    mainApp.controller('ItemController', function($scope) {
        $scope.items = [
            {name: 'apple', city:'New York'},
            {name: 'banana', city:'London'},
        ];

        $scope.message = "Click on the hyper link to view the item list.";
    });
    說明:
    (1)var mainApp = angular.module("mainApp", ['ngRoute']);
    加入ngRoute模組為應用程式

    (2)$routeProvider :用來規化路由,其中when()方法是由path和route當做參數,path為#符號的路徑;route裡面有兩個參數分別為templateUrl用來指定網頁檔案以及controller控制器來指定控制器

    syntx:   when(path, route)

    (3)mainApp.controller: 控制器功能實做


    home.html
    <body ng-controller="ItemController">
        <div class="container">
            <h2> Welcome </h2>
            <p>{{message}}</p>
            <a href="#/viewItems"> View Items List</a>
        </div>   
    </body>

    viewItems.html
    <div class="container">
        <h2> View Items </h2>
        Search:
        <br/>
            <input type="text" ng-model="name" />
        <br/>
        <ul>
            <li ng-repeat="item in items | filter:name">{{item.name}} , {{item.city}}</li>
        </ul>
    </div>

2015年5月13日

Filters

  • 過濾器(Filters)
    angularJS在資料格式顯示方面,他們使用過濾器轉換資料,首先我們需要了解過濾器可以處理範圍:

    過濾器的格式:
    {{ filter_expression | filter : expression : comparator}}

    過濾器類型 說明
    currency 貨幣格式
    filter 搜尋集合符合條件的子集合
    lowercase 轉換成小寫型態
    orderBy 排序
    uppercase 轉換成大寫型態


    (1)currency

    範例: 當宣告currency會補上$的符號

    <body ng-app="myList" >
        <div ng-controller='ListController' >
            <div ng-repeat='item in items'>
                <span>{{item.title}}</span>
                <input ng-model='item.quantity'>
                <span>unit price: {{item.price | currency}}</span>
                <span>total: {{item.price * item.quantity | currency}}</span>
            </div>
        </body>

    <script>
         var myApp = angular.module('myList',[]);
         myApp.controller('ListController', function($scope){
            $scope.items=[
                {title:"apple",quantity:10, price:350},
                {title:"banana",quantity:8,  price:450},
                {title:"star",quantity:7,  price:350}
            ];
           
        
         });
    </script>

    apple    unit price: $350.00 total: $3,500.00
    banana unit price: $450.00 total: $3,600.00
    star       unit price: $350.00 total: $2,450.00



    (2) filter
    範例:過濾符合條件的資料

    <html ng-app="myList">
        <head>
             <script src="angular.js"></script>
        </head>
       
        <body>
            <div ng-controller='ListController' >
             <input ng-model="searchText">
            <div ng-repeat='item in items | filter:searchText'>
                <span>{{item.title}}</span>
                <input ng-model='item.quantity'>
                <span>unit price: {{item.price | currency}}</span>
                <span>total: {{item.price * item.quantity | currency}}</span>
            </div>
        </body>
        </body>
        <script>
         var myApp = angular.module('myList',[]);
         myApp.controller('ListController', function($scope){
            $scope.items=[
                {title:"apple",quantity:10, price:350},
                {title:"banana",quantity:8,  price:450},
                {title:"star",quantity:7,  price:350}
            ];
         });
        </script>
    </html>

    apple unit price: $350.00 total: $3,500.00




    (3)lowercase

    範例: 當輸入apple會自動改為小寫的文字

    <div ng-app="myApp" ng-controller="lowerController">
    <input type="text" name="message" ng-model="message" />
    <p> upper case:{{message | lowercase}} </p>

    </div>

    <script>
    var myApp = angular.module("myApp",[])
    myApp.controller("lowerController", function($scope){
    });

    </script>

    input:
    upper case:apple


(4)orderBy

範例: 當利用ng-repeat印出水果明細,再利用orderBy:'price' 依照單價去排序

<body ng-app='myList' >
        <div ng-controller='ListController'>
            <div ng-repeat="item in items | orderBy:'price'" >
            <span>{{item.title}}</span>
            <input ng-model='item.quantity'>
            <span>{{item.price | currency}}</span>
            <span>total: {{item.price * item.quantity | currency}}</span>
            
        </div>
    </body>
<script>
     var myApp = angular.module('myList',[]);
     myApp.controller('ListController', function($scope){
        $scope.items=[
            {title:"apple",quantity:4, price:350},
            {title:"banana",quantity:4,  price:450},
            {title:"start",quantity:4,  price:350}
        ];
     });
   
</script>

apple    $350.00 total: $1,400.00
start     $350.00 total: $1,400.00
banana $450.00 total: $1,800.00




(5) uppercase

範例: 當輸入apple會自動改為大寫的文字

<div ng-app="myApp" ng-controller="upperController">
<input type="text" name="message" ng-model="message" />
<p> upper case:{{message | uppercase}} </p>

</div>

<script>
var myApp = angular.module("myApp",[])
myApp.controller("upperController", function($scope){
});

</script>

input:
upper case:APPLE

Organizing Dependencies with Modules

  • 工廠模式(Factory)
  • 你可以使用工廠模式建立服務,並傳回資料給模組。
    1.  factory(name,Function())
    2.  factory(name,[], Function() )

    <body  ng-app="myShoppingList">
             <div>
                <table ng-controller="itemsController">
                    <tr ng-repeat="item in items" >
                        <td>{{item.title}}</td>
                        <td>{{item.description}}</td>
                        <td>{{item.price | currency}}</td>
                    </tr>
                </table>
             </div>
        </body>
        <script>
            var myApp = angular.module('myShoppingList',[]);
             myApp.factory('Items', function(){
                 var items = {};
                 items.query = function(){
                    return [
                        {title:"apple", descript:"5 start", price:500},
                        {title:"apple", descript:"3 star",  price:200},
                        {title:"apple", descript:"2 star",  price:100}
                    ];
                 };
                 return items ;
                
             });
             myApp.controller("itemsController", function($scope, Items){
                 $scope.items = Items.query() ;
             })
            
           
        </script>

    apple $500.00
    apple $200.00
    apple $100.00

 

  • Service
    service 常被用來組織或是封裝成一個服務,它有幾個特點:
    (1) 服務寫成的物件只會一個實例

    例子: 我們寫一個baseService當為基本利率換算來轉換水果的價格需要乘上10倍

<body  ng-app="myapp">
         <div>
            <table ng-controller="rateController">
                <tr ng-repeat="item in items" >
                    <td>{{item.name}}</td>
                    <td>{{item.price | currency}}</td>
                </tr>
            </table>
         </div>
    </body>
    <script>

        //基本利率換算
       var m = angular.module("baseService",[]) ;
        m.service("serviceSample",function(){
            this.rate= function(price){
                return  price* 10;   
            }
        });
       
        //轉換水果的價格
        var myapp = angular.module("myapp",["baseService"]);
         myapp.controller('rateController',function($scope, serviceSample){
           
            items = [
                     {name:"apple" , price:serviceSample.rate(20) },
                     {name:"banana", price:serviceSample.rate(30) }
                    ]
           
                return  $scope.items = items    ;
           
            }) ;        
       
    </script>

apple $200.00
banana $300.00

  • provide

2015年5月12日

List、Tables and Other Repeated Elements

  • 複數元素資料
    當我們要顯示出多筆物件的資料時,angular有提供ng-repeat的元素它會複製每一筆資料出來

    範例一
    <html ng-app="myApp">
        <head>
             <script src="angular.js"></script>
        </head>
       
        <body>
            <form ng-controller="fruitController">
                <ul>
                    <li ng-repeat="f in fruit">
                        <a href="/fruit/view/{{f.id}}"> {{f.name}} </a>
                    </li>
               
                </ul>
            </form>
        </body>
       <script>
            var fruit = [{name:"apple",id:"2"},
                             {name:"orange",id:"3"},
                             {name:"watermelon",id:"4"}
                            ]
            var myApp = angular.module('myApp',[]) ;
            myApp.controller('fruitController',function($scope){
                $scope.fruit = fruit;
            })
        </script>
    </html>


  • Hiding and Showing
    當我們需要隱藏或是顯示資訊時,angular提供ng-show和ng-hide兩種方法可以使用,menuState預設
    為隱藏(false),當按下'toggleMenu會更改menuState為顯示(true)。

<html ng-app="myApp">
    <head>
         <script src="angular.js"></script>
    </head>
   
    <body>
        <form ng-controller="hideController">
            <button ng-click='toggleMenu()'>Toggle Menu</button>
            <ul ng-show='menuState.show'>
                <li>menu1</li>
                <li>menu2</li>
            </ul>
        </form>
    </body>
    <script>
        var myApp = angular.module('myApp',[]);
         myApp.controller('hideController', function($scope){
            $scope.menuState = {show:false};
            $scope.toggleMenu = function(){
                $scope.menuState.show =  !$scope.menuState.show;
            }
         });
       
    </script>
</html>

  • menu1
  • menu2

  • Class and Styles

    <html ng-app="myApp">
        <head>
             <script src="angular.js"></script>
             <style>
                .error {
                    background-color: red;
                }
                .warning {
                    background-color: blue;
                }
             </style>
        </head>
       
        <body>
            <form ng-controller="cssController">
                
                <div ng-class="{error:error, warning:warning}" >{{message}}</div>
                <input type="button" ng-click="error()" name="btnerror" value="show error" />
                <input type="button"  ng-click="warning()" name="btnwarning" value="show warning"  />
               
            </form>
        </body>
        <script>
            var myApp = angular.module('myApp',[]);
             myApp.controller('cssController', function($scope){
                
                 $scope.error = function(){
                    $scope.error = true;
                    $scope.warning = false;
                    $scope.message = "It is a error !"
                 }
                
                  $scope.warning = function(){
                    $scope.error = false;
                    $scope.warning = true;
                    $scope.message = "It is a warning !"
                 }
                
             });
           
        </script>
    </html>

    It is a warning !




Templates and Data Binding

  • 樣版(templates)
    使用Angular框架它是一種樣板的開發模式,我們會在HTML網頁上,規劃需要載入內容或是效果,其他交給Angular處理就可以

    <div ng-model=”greeting” >
          {{greeting}}    //->樣板開發方式</div>

  • 資料繫結(Data Binding)
    你可以利用資料繫結去同步更新資料,這裡提供兩種寫法
    (1)
    <p ng-bind="greeting"></p>
    (2)
    <p>{{greeting}}</p>

2015年5月10日

第一個AngularJS程式

  • 開始撰寫第一個程式
    下載Angular套件:https://angularjs.org/

    Image 1

    載入套件:
    <script src="angular.js"></script>

    宣告Angular’s Boundaries
    (1)和(2) 載入的範圍不同,用來告訴Angular該網頁哪個部分需要處理
    (1)載入整個網頁為Template
    <html ng-app>

    </html>
    (2)載入div元素之間為Template
    <html>

    <div ng-app>

    </div>

    </html>
  • 完整的網頁
<html ng-app="myList">
<head>
     <title>My Shopping List</title>
     <script src="angular.js"></script> </head>
     <body ng-controller='ListController'>
          <div >
               <div ng-repeat='item in items'>                   <span>{{item.title}}</span>
                   <input ng-model='item.quantity'>
                   <span>{{item.price | currency}}</span>,
                   <span>總價: {{item.price * item.quantity | currency}}</span>
                   <button ng-click="remove($index)">Remove</button>
               </div>
          </div>
     </body>
<script>
    var myApp = angular.module('myList',[]);
     myApp.controller('ListController', function($scope){
          $scope.items=[
               {title:"國語",quantity:10, price:350},
               {title:"英文",quantity:8,  price:450},
               {title:"公民",quantity:7,  price:350}
          ];
          $scope.remove = function(index) {
               $scope.items.splice(index, 1);
           }
     });
</script>
</html>
說明:
ng-app : 用來告訴Angular該網頁哪個部分需要處理,此範例定義在<html>標簽中表示整個網頁都需要處理,。
ng-controller : 宣告控制器用來處理網頁
ng-repeat : 我們將物品陣列利用item的物件逐一的讀取顯示出來,{{item.title}}為資料繫結(data binding)用來將保持網頁上資料同步。
ng-model :  用來建立quantity與{{item.price * item.quantity | currency}} 的關係,當我們改變物品的數量同時也會改變總價。

MVC

  • Model View Controller (MVC)
    MVC架構在1970提出,模型Model(M)-檢視View(V)-控制Controller(C)三種介面分開,讓程式可以各司其職也讓開發人員可以分工合作,以達到一個較好的開發效率。

    檔案: ex1.html
    <html ng-app="myApp">
    <head>
         <script src="angular.js"></script>
      </head>
         <body >
              <div ng-controller='HelloController'>
                   <p>{{greeting.text}}, World</p>
              </div>
         </body>
    <script>
      
         var myApp = angular.module('myApp',[]);
         myApp.controller('HelloController', HelloController);
    </script>
    </html>
    檔案:controllers.js
    function HelloController($scope) {
         $scope.greeting = { text: 'Hello' };
    }
    說明:
    我們定義HelloController顯示文字為Hello,當載完整個網頁後,Angular框架會根據控制器載入內容物件,結果顯示為 Hello, World。但是除了把controller獨立出來寫成JS檔外,還有另一種寫法為

    方法二:

    var myApp = angular.module('myApp',[]);
    myApp.controller('HelloController', function($(scope){
             $scope.greeting = { text: 'Hello' };
    });





AngularJS介紹


AngularJS由Google 打造的前端 JavaScript 框架,與其他JS框架(ExtJSBackboneJSEmberJSKnockoutJS)
不同,他可以直接延伸現有的 HTML 架構。以下有幾點關注的概念必須了解,對往後要使用AngularJS框架開發應用
網頁會更為快速:

  1. 前端網頁MVC架構:
    在AngularJS將前端AngularJS為控制器 (Controllers) 、檢視 (Views)與模組 (module),控制器可以用來切換不同
    檢視畫面其內容搭配模組 (module) 與 相依性注入 (Dependency Injection) 來實做。當前端網頁也切割為MVC
    架構表示我們可以自由的抽離這些實做,但是也會使開發人員學習複雜度增加。
     
  2. 資料聯結(Data Binding)
    資料繫結很多JS框架都有此功能,我們必須了解單向資料繫結(One-way Data-Binding)雙向資料繫結(Two-
    way Data Binding)
    兩種,單向資料繫結產生檢視之前,將模組與模板先做合併的動作,但是如果有經過一些操
    做改變了模型資料內容,但是檢視上模型並不會改變造成不同步的狀況發生。
    雙向資料繫結改善單向的缺點,不管使用者在網頁上做了甚麼操作,AngularJS都會去偵查檢視的改變,同步去更
    新模型的資料內容。
  3. 相依注入(Dependency Injection,DI)
    相依注入是AngularJS 一個強項,它的目地讓程式的組件切割的更加清楚,主要它利用design pattern的方法來將
    模型靈活的使用,深入了解可以參考Dependency Injection。
  4. 指示指令(Directives)
    在HTML中觸發JavaScript行為的參數,舉例來說
    ex1: <html ng-app="myApp">
    ex2: <div ng-controller='HelloController'>
    ex3: <div ng-repeat='item in items'>

2015年4月14日

Java good part


套件(package)

我們知道在Java語法中,套件語法只要在前面宣告package的關鍵字並依照個人不同需求去
規劃套件的位置,今天我們就深入探討package語法的作用,我們知道套件的命名會影響整
理專案開發和日後的維護系統工作,易讀且統一的套件命名方式,讓人容易理解且易工作。
我們通常會以公司別為命名方式,例如Sun公司為com.sun,Apple公司為com.apple以此類
推。其次為系統層實務上依專案大小來規劃,例如Sun的人資系統為com.sun.hr或是Sun人資
系統中出勤系統com.sun.hr.pd。 最後一層為技術層依使用的框架或是技術來區分,例如Sun
人資系統使用MVC開發: model: com.sun.hr.model、com.sun.hr.view, com.sun.hr.controoler來
規劃。

匯入(import)

在JAVA中不同的套件之間,要互相引用時我們可以利用import來載入裡面的類別。

import com.sun.hr.utility.*               => 載入utility底下的class類別
import com.sun.hr.utility.salaryUtil   => 只載入salaryUtil的類別

不管是*還是salaryUtil編譯器會只會對有用到的類別參考使用,所既使載入全部以不會影響執
行效能,建議開發程式只需要載入用到的類別,以方便日後維護工作。


套件與存取控制

利用package套件系統只要可以建立不同的命名空間(namespace)來組合系統不同組件,當我
宣告不同修飾子(private、protected和public)分別是由嚴謹權限控制到鬆散權限控制。

修飾子 class extend 相同package下 不同package下
private V X X X
protected V V V M (需要繼承才可以)
public V V V V
defult V X V V

V: 支援  X:不支援  M:需要特殊條件才知援

 

套件與存取控制

當我們宣告命名空間為com.hp.hr.utility,實際上在檔案目錄中為 com/hp/hr/utility 的路徑,

package  com.hp.hr.utility    =>  com/hp/hr/utility (檔案系統)


 

2015年1月26日

Gradle(9)- 品質保證


我們需要利用一些工具來保持程式的穩定,好的程式是容易維護、花費的成本比較低。本章介紹一些工具可以搭配Gralde來達到公司的軟體政策並制定一些標準。例如Checkstyle, JDepend, PMD, FindBugs, CodeNarc, and Sonar。




(1) Checkstyle plugin




在Gradle腳本可以載入checkstyle,當它執行build任務時,check 任務也會執行,

2015年1月25日

Gradle(8) 最後一哩路-發佈版本

通常在Java專案會把程式打包為JAR、ZIP檔或是其他檔案,在Gradle中打包程式任務為build<configurationName>且上傳的任務為upload<configurationName>。我們定義

(1) 版本庫上傳

  • jar檔上傳

apply plugin: 'java'
archivesBaseName = 'sample'
version = '1.0'

repositories {
    flatDir {
        name 'uploadRep'
        dirs   'upload'
    }
}

uploadArchives {
        repositories {
       
       //檔案上傳的設定環境為uploadRep
        add project.repositories.uploadRep
     
        //額外jar上傳目的檔
        flatDir {
            dirs 'C:\\libs'
        }
    }
}

  • Maven版本上傳

apply plugin: 'java'
apply plugin: 'maven'

archivesBaseName = 'sample'
group =  ‘com.sample’
version = '1.0'

uploadArchives {
     repositories {
         mavenDeployer {
            repository(‘C:\\libs’)
        
     }
}

(2)打包檔案
在通常我們開發網頁程式,會將JAVA專案打包成Web application Archive (WAR) or Enterprise Archive (EAR)。如果對Web開發不了解請您參考
Gossip@openhome
Gradle網頁架構預設

  • src/main/webapp/WEB-INF  環境配置檔(web.xml)
  • src/main/resources    資源架構
  • src/main/                   class架構
  • 打包WAR檔

Gradle任務War方法用來將Java專案打包成war檔,

war屬性或方法

說明

webInf 用來定義WEB-INF的內容,
範例:
webInf {
         //將resources裡的文件複製到WEB-INF
         from 'src/main/resources’
}
classpath 如果為jar或是zip檔會自動複製到WEB-INF/lib中,其他檔案就複製到WEB-INF/classes
範例:
classpath sourceSets.main.runtimeClasspath
classpath fileTree('libs')
webXml 用來定義web.xml
 

使用WAR pluging的預設環境來打包war檔,會比較開發。

apply plugin: 'war'
version = '1.0'

repositories {
      mavenCentral()
}

configurations {
     extraLibs
    }

dependencies {
      providedCompile 'javax.servlet:servlet-api:3.0'
      providedRuntime 'webcontainer:logging:1.0'
      extraLibs 'sample:lib:2.1'
}

war {
      classpath configuration.extraLibs
      webXml = file('src/main/webXml/web-dev.xml')
      baseName = 'gradle-webapp'
}