NO END FOR LEARNING

Writing blog if you feel tired | 学海无涯 苦写博客

开始!AngularJS!(一)- 刚刚开始

| Comments

看这样一个例子:

1
2
3
4
5
6
<body ng-app>
    <div ng-controller="textLengthLimitController">
        <textarea ng-model="text"></textarea> <span></span>
        <input type="button" ng-disabled="!hasValidLength()" value="send" />
    </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
var MAX_LENGTH = 10;

function textLengthLimitController($scope) {

    $scope.remaining = function () {
        return MAX_LENGTH - $scope.text.length;
    };

    $scope.hasValidLength = function () {
        return $scope.remaining() >= 0;
    };

}

代码的功能是告诉用户还可输入多少字符,当字符超过限制,将发送按钮灰掉。在jsFiddle里运行该代码,http://jsfiddle.net/benweizhu/cbcn995m/

这里做了几件事情:
1.定义页面(HTML页面)
2.定义期待行为(remaining()和ng-disabled)
3.定义行为发生的逻辑(MAX_LENGTH - $scope.text.length和$scope.remaining() >= 0)

剩下最复杂的事情:对DOM元素的操作,交给了AngularJS来做。

引用AngularJS官方文档对AngularJS的介绍:

“AngularJS是一个开发动态Web应用的框架。它让你可以使用HTML作为模板语言并且可以通过扩展的HTML语法来使应用组件更加清晰和简洁。它的创新之处在于,通过数据绑定和依赖注入减少了大量代码,而这些都在浏览器端通过JavaScript实现,能够和任何服务器端技术完美结合。”

就像文档介绍的那样,HTML本身是静态文档,是很好的声明式语言,但对于构建动态的web应用,却无能为力。

针对这类问题,通常的解决办法是:通过JavaScript对HTML的DOM结构进行修改。比如,jQuery。

而AngularJS另辟蹊径,通过扩展HTML的语法来拉近静态Web和动态Web之间的距离。

“Angular是建立在这样的信念之上的:即声明式的代码用在构建用户界面和组装软件组件时更好,而命令式的代码更擅长展现业务逻辑。”

AngularJS将应用逻辑与DOM操作解耦,让开发人员不用去担心去前端视图模型(View Model)改变,从而大大提高代码的可测试性。

AngularJS试图去实现一个完整的前端解决方案:

1.构建一个CRUD应用时可能用到的所有技术:数据绑定、基本模板指令、表单验证、路由、深度链接、组件重用、依赖注入
2.可测试性:单元测试、端到端测试、模拟对象(mocks)、测试工具

在一个以用户体验,多平台(Web和移动)为核心的现代应用时代,单页应用以前端+API成为了Web应用的开发的趋势:

1.对于内容的改动不需要加载整个页面
2.对服务器压力很小,消耗更少的带宽,与面向服务的架构更好地结合
3.多平台使用相同的API,减少后台逻辑的重复开发

AngularJS给现代Web应用开发带来曙光,让我们一起认认真真学习AngularJS。

参考资料:

1.《精通AngularJS》
2.http://www.ngnice.com/docs/guide/introduction
3.http://www.csdn.net/article/2012-12-10/2812658-Single-Page-Applications

Gradle Jetty和Gradle Watch插件实现热部署

| Comments

Jetty插件

Jetty插件提供两个重要方法:jettyRun和jettyRunWar。

jettyRun会将一个已暴露(解包的)的web应用部署到嵌入式Jetty Web容器中。它不需要将web应用打包成一个war文件,目的是为了节省部署时间。

jettyRunWar正好相反,是将一个War包部署到Web容器中。

jettyRun的好处是,你可以改变静态文件和JSP文件,而不需要重新启动服务器。

但是即便如此,对于日常开发还是不方便,因为开发过程中改动最多的其实是Java文件和资源配置文件,所以真正需要的是热部署

jettyRun的Gradle API文档中有这么一句话:Once started, the web container can be configured to run continuously, scanning for changes in the project and automatically performing a hot redeploy when necessary. This allows the developer to concentrate on coding changes to the project using their IDE of choice and have those changes immediately and transparently reflected in the running web container, eliminating development time that is wasted on rebuilding, reassembling and redeploying.

这句话简单总结就是Jetty提供实现热部署的特性,开发人员只需要专注于编写代码,减少重新构建,重新组装和重新部署所浪费的时间。

但问题是,官方文档上写了这句话后,就不了了之了,没有说怎么做。我们都试过,默认配置是不会实现热部署的,那么应该怎么做呢?

两个属性:

reload The reload mode, which is either “automatic” or “manual”.

scanIntervalSeconds The interval in seconds between scanning the web app for file changes. If file changes are detected, the web app is reloaded. Only relevant if reload is set to “automatic”. Defaults to 0, which disables automatic reloading.

读完上面两段,说明默认scanIntervalSeconds的配置是不支持自动重新载入变化文件的。

试一把,把它改为支持:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apply plugin: 'jetty'
apply plugin: 'idea'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.springframework:spring-webmvc:4.0.6.RELEASE'
}

jettyRun {
    reload = "automatic"
    scanIntervalSeconds = 1
}

然后运行gradle jettyRun启动jetty容器,修改Java类,然后去页面验证变化,结果是没有变化。为什么?

原来,jetty监听的是build目录下的class文件变化,而不是源代码变化,也就说源代码内容改变了,但class文件没有变化,那么不会自动触发jetty重载变化文件,那么该怎么办?最简单粗暴的解决方案就是另起一个命令行窗口,手动运行一次gradle compileJava命令。

没错,这个方法是行得通的。但仍然不是最好的解决方案。我查了下,到目前为止,官方没有给出正式的解决方案,但是该特性是在GradleWare的To-Do-List上的,预计以后应该会有。

Gradle Watch

那么,唯一的办法只有借助第三方的插件来协助Jetty插件,一起实现热部署了,gradle-watch(日本人写的,因为上面的饿提交记录全是日文的)。 https://github.com/bluepapa32/gradle-watch-plugin

gradle watch的作用是监听某种类型的文件的变化,包括添加,删除和修改,然后执行预定义的任务。

使用起来很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
apply plugin: 'jetty'
apply plugin: 'idea'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.springframework:spring-webmvc:4.0.6.RELEASE'
}

jettyRun {
    reload = "automatic"
    scanIntervalSeconds = 1
}

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.bluepapa32:gradle-watch-plugin:0.1.3'
    }
}

apply plugin: 'watch'

watch {
    java {
        files files('src/main/java')
        tasks 'compileJava'
    }
}

配置watch闭包,什么文件发生变化后就执行什么任务(好像它没有提供默认配置,所以需要手动显示的配置)。

在启动了gradle jettyRun之后,开启另一个窗口运行gradle watch。一次Java文件变化的输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
:watch
Starting............ OK

--------------------------------------------------------------------------------
Sun Jul 27 15:36:51 CST 2014

File "src/main/java/me/zeph/springmvc/jrebel/controller/HelloJRebelController.java" was changed.

-----------------------------------------------------
:compileJava

BUILD SUCCESSFUL

Total time: 0.954 secs
Building > :watch

可见,成功的更新了Java的class文件到build目录。刷新一次页面,就可以查看变化了。

那么对于资源文件呢?比如,我使用了Spring,需要改变Spring的Bean配置文件,同样可以。

1
2
3
4
5
6
7
8
9
10
watch {
    java {
        files files('src/main/java')
        tasks 'compileJava'
    }
    resources {
        files fileTree(dir: 'src/main/resources', include: '**/*.xml')
        tasks 'processResources'
    }
}

输出结果如下:

1
2
3
4
5
6
7
8
9
10
11
--------------------------------------------------------------------------------
Sun Jul 27 15:56:39 CST 2014

File "src/main/resources/applicationContextService.xml" was changed.

--------------------------------------------------------------------------------
:processResources

BUILD SUCCESSFUL

Total time: 0.501 secs

是不是很爽,这样是不是就再也不用重启服务器了,开发速度瞬间提升好几万战斗力。

加一句,该插件同样支持properties文件的改变,与XML一样配置。

好吧,就到这里,我觉得热部署也算的上某种自动化开发的一部分,至少他们的目的一样,提升开发效率,得到快速反馈,希望这篇文章对大家有所帮助。

参考资料:

1.http://forums.gradle.org/gradle/topics/hot_deploy_with_jetty_plugins_jettyrun

2.http://www.gradle.org/docs/current/dsl/org.gradle.api.plugins.jetty.JettyRun.html

3.https://github.com/bluepapa32/gradle-watch-plugin