trackr: An AngularJS app with a Java 8 backend – Part II
该系列文章来自techdev
The Frontend
在本系列的第一部分我们已经描述RESTful端建立在Java 8和Spring。这一部分将介绍我们的第一个用 AngularJS建造的客户端应用程序。
我们使用trackr跟踪我们的工作时间,旅行费用和假期请求。因此我们需要两个基本的管理界面为所有实体以及高级输入表单。我们也想扩展中定义的安全端到我们的前端——如果REST服务禁止用户查看或编辑一个实体这些行为不应该是可见的。
测试和自动化的很大一部分我们的Java后端前端的我们想要这些功能。除了测试框架和测试运行器这意味着某种形式的构建和依赖关系管理。这应该是我们Gradle构建的一部分。
Bower
我将使用Bower来完成依赖关系管理。虽然使用相当简单,但我们不得不吐槽Bower,因为它失败构建的问题。一次一个git命令就失败了,还有一次我无法删除一些缓存文件夹。我真的希望他们改善一下在未来。每次我更改或添加一个依赖Gradle构建都容易失败。
另一个非常具体的问题是jQuery的依赖问题。jQuery仓库里jquery和jQuery两个,Bootstrap 依赖jquery,但是Bower 随机下载jquery和jQuery,文件夹结构的不一致导致构建失败不能运行,这个问题:https://github.com/bower/bower/issues/1118。现在我不想抱怨太多,也许是合理的,也许不是,但它打破了我的建立,一个依赖关系管理系统,是用于生产目的不能打破构建。
还有一个,不是Bower的问题,但使用它的时候出现了。增加错误的包。当一个包的build
目录是空的只有项目源码在里面。我们最终使用主分支和不是一个发布版本使用这种依赖性。
用Maven的依赖管理我从来没有这些问题。你添加一个依赖项,Maven下载它,它的工作原理。在我看来Bower需要更多的发展。
Grunt
我们使用Grunt来完成3个任务。执行JSHint,构建生产文件的源代码(比如最小化js文件)和执行测试。
Grunt工作真的很好。唯一的问题可能是任务的配置文档时不够的。但大多数任务都有一个良好的文档和/或一个示例配置文件,描述了所有的选项。
Running Bower and Grunt from within Gradle
在前一章我们用gradle配置过这个例子build.gradle
task gruntTest(type: Exec) {
workingDir 'src/main/webapp/WEB-INF/app'
executable = 'grunt'
args = ['test']
}
我们有一些这样的任务,只有执行命令,如grunt test
, npm install
等等。我真的很喜欢它,其他开发人员checkout项目(当然所有工具已经安装好了)只需要运行./gradlew build就有了一个WAR文件(node工具已经安装)。
The architecture
我们希望前端非常模块化,这样我们就可以与其他应用程序扩展它。这意味着我们实际上想要构建一个平台trackr仅仅是第一个应用程序。AngularJS已经附带支持模块。此外我们使用 RequireJS 来做Javascript依赖。这允许模块被集成在平台很少变化。因此我们的目录结构如下:
下面是一些示例代码展示应用程序加载:
/* app.js */
define(['angular', 'modules/shared/shared', 'modules/module1/module1', 'modules/module2/module2', function(angular) {
var app = angular.module('app', 'shared', 'module1', 'module2');
angular.element(document).ready(function() {
angular.bootstrap(document, ['app']); //If there's setup needed before the app runs.
});
}); /* modules/module1/module1.js */
define(['angular'], function(angular) {
var module1 = angular.module('module1', []);
//add controllers loaded by require, define routes, states etc.
return module1;
});
不是标准AngularJS路由通过$routeProvider我们使用https://github.com/angular-ui/ui-router 的$stateProvider。它允许嵌套状态和视图的应用程序真正有利于模块化的方法。每个模块可以定义自己的状态有自己的URL前缀,而不需要到处重写。
这是管理模块的状态配置摘录:
$stateProvider
.state('trackr.administration', {
url: '/administration',
views: {
'center@': {
templateUrl: 'src/modules/trackr/administration/administration.tpl.html'
}
},
needsAuthority: 'ROLE_SUPERVISOR'
})
.state('trackr.administration.projects', {
url: '/projects',
views: {
'center@': {
templateUrl: 'src/modules/trackr/administration/projects/list.tpl.html',
controller: 'trackr.administration.controllers.projects.list'
}
},
needsAuthority: 'ROLE_SUPERVISOR'
})
.state('trackr.administration.projects.edit', {
url: '/{id:[\\w\\.]+}',
views: {
'project': {
templateUrl: 'src/modules/trackr/administration/projects/edit.tpl.html',
controller: 'trackr.administration.controllers.projects.edit'
}
},
needsAuthority: 'ROLE_SUPERVISOR'
})
它定义了3个内部状态,最后一个trackr.administration.projects.edit将作为一个父状态的template的一个view,在url (/trackr)/administration/projects/projectId下被访问。
这个就是演示效果,点进project的时候,才会有编辑。您还可以看到该模块选择左边。早期阶段的布局是当我主要是发展的特性。
RequireJS方法可以把大量的文本的Javascript文件,特别是如果目录结构越来越复杂。起初,我发现这很讨厌,但我看了看一个典型的Java类。
你可能不认识他们了,因为IDE隐藏了他们,更有可能的是,你不用写他们,但他们在那,就是:import语句。唯一的差别就是RequireJS的import你的IDE没法帮你做。
我们的构建将append和最小化所有Javascript文件和加速加载在我们的生产环境。
Restangular
Restangular是一个angular module,它隐藏了$http和rest Service的交互。url的字符串操作可以使用流利的API,链接在一起的方法。下面是一个例子从我们employee-editing Controller。
var employeeBase = Restangular.one('employees', $stateParams.id); employeeBase.get().then(function(employee) {
$scope.employee = employee;
employee.one('credentials').get().then(function(credentials) { /* do something with credentials */ });
} $scope.deleteEmployee = function() {
employeeBase.remove().then(function() { /* redirect to some other page */ });
}
可以看到它的工作$http的promises一样。真的很直观和Spring-Data-Rest工作得很好。唯一的映射列表结果必须被配置在Restangular Spring-Data-Rest相匹配的方法。
Internationalization
我们使用angular-translate 来实现国际化,很直接,在大多数用例使用翻译过滤器。翻译可以异步服务或可以硬编码。
<thead>
<tr>
<th translate="VACATION_REQUEST.START_DATE"></th>
<th translate="VACATION_REQUEST.END_DATE"></th>
<th translate="VACATION_REQUEST.NUMBER_OF_DAYS"></th>
<th translate="VACATION_REQUEST.STATUE"></th>
<th translate="ACTIONS.ACTIONS"></th>
</tr>
</thead>
编辑:帕斯卡普雷在评论中指出最好尽量使用指令而不是过滤器。过滤器可以有负面影响性能。更改代码示例使用指令。
Security
后端实现一个非常严格的安全方法。trackr每个用户的角色分配和REST服务处理相关的权限。现在,在前端用户访问的所有代码。我想我们可以为员工和管理员提供不同的应用程序,但似乎太多的开销。毕竟前端不包含密码,只有必须的数据,最后将保护后端。
尽管如此,我们不希望用户看到的链接页面无法访问或能够编辑一个实体他们可以看到但例如PUT请求将被拒绝。所以我在一些地方添加额外的安全检查。
- 状态切换. A state can require a role to be accessed. Currently, if the user does not have the required role nothing will happen, but an error page is completely possible. (You can see this in the code for the
$stateProvider
above) - 用
has-authority
指令来隐藏元素. This can be used e.g. to hide the link to administration in the top menu for employees. - 我们使用click-to-edit的方法替换表单. The directive for that takes the role of the user into account, too.
如果正确使用这应该足以显示只允许trackr的内容给用户。如果用户想恶意行为他们肯定能够切换到一些state不允许,但最终剩下的后端将阻止他们访问数据。
这是一个has-authority的指令的例子
<ul class="nav navbar-nav">
<li ui-sref-active="active"><a href ui-sref="trackr.employee">{{ 'PAGES.EMPLOYEE.TITLE' | translate }}</a></li>
<li ui-sref-active="active" has-authority="ROLE_SUPERVISOR"><a href ui-sref="trackr.supervisor">{{ 'PAGES.SUPERVISOR.TITLE' | translate }}</a></li>
<li ui-sref-active="active" has-authority="ROLE_SUPERVISOR"><a href ui-sref="trackr.administration">{{ 'PAGES.ADMINISTRATION.TITLE' | translate }}</a></li>
</ul>
Testing
我们的后端有一个不错的测试覆盖率。虽然我已经写了一些较小的AngularJS应用我从未真正建立测试对他们来说,这是相当新的给我。我决定使用Karma 作为测试运行器,Jasmine作为一个测试框架。设置Karma与RequireJS管理文件是一个任务,需要一些时间和研究。
能够编写和执行测试后,下一个问题是:如何测试一个AngularJS应用程序,测试什么和如何编写代码让代码是可测试的。
让我们从第一个问题开始。AngularJS提供angular-mocks模拟一个真正的AngularJS环境测试。它允许您启动应用程序,使用测试和模拟中注入$http调用。
define(['angular-mocks', 'app'], function() {
describe('some test', function() {
beforeEach(module('app'));
beforeEach(inject(function($httpBackend) {
$httpBackend.whenGET(...);
}));
it('should do something', inject(function($httpBackend) { ... }));
});
});
这只是一个例子,没有真正的考验。很快,显然我必须做某些任务在每个测试中,像启动应用程序。因为我发现没有办法编写一些测试基类我想到不同的方法。有RequireJS证明是非常有用的。我只是写了一个文件,返回一个函数将执行所有基本的测试设置。在实际测试我不得不需要文件,执行功能和将设立我的测试。我做这个启动应用程序和模拟$httpBackend和一些数据。
接下来是:我们测什么?我还不是完全清楚。我开始与一些非常基本的测试,检查一些$scope变量的定义。我的想法是,禁止有人删除$scope仍可能需要。然后我开始测试检查如果HTTP请求时执行;angular-mocks帮助这里。我没有多少业务代码所以主要是集成测试。
接着是如何编写测试代码的问题。很容易访问$scope在测试,所以这可能是一个想法把$scope和测试它的一切。但是这个破坏了封装。有时你在一个控制器有一个helper函数,不该在$scope。所以我用这个模式:
/* controller.js */
angular.controller(['$scope', function($scope) {
var controller = this;
controller.foo = function(bar) {
//do stuff
}; $scope.baz = function() {
controller.foo('baz');
};
}]); /* controllerSpec.js */
describe('controller', function() {
var controller;
beforeEach(function() { /* set up controller and app */ });
it('should foo', function() {
var foo = controller.foo('bar');
expect(foo).toBe('bar');
});
});
我想时间会告诉我们如何提高我们的实际测试,但是一个好的基本设置。
Code coverage
IntelliJ IDEA有很大的代码覆盖率工具,我可以用Java运行测试。这对于Javascript也是可能的。我用Istanbul通过雅虎karma-coverage 任务。它不需要任何特殊的设置(只是激活和配置的输出目录报告)。我发现它很晚,这是一个很好的令人惊异的事物去发现我的覆盖率有多糟糕。经过一天的编写更多的测试我从这里
到这里
所以我仍然需要一个好方法来测试指令,但它确实暂时看起来很不错。
Istanbul甚至每个Javascript文件创建一个页面来指明多少行,分支和方法被覆盖。
Conclusion
RequireJS和AngularJS模块的组合允许一个真正模块化的程序是很好。与我们的Spring后端Restangular集成非常好。Karma,Jasmine和angular-mocks(和一些RequireJS)帮助建立一个测试环境中有许多方便的助手,让您专注于实际的测试。
我没有这么多像Bower与我所描述的经历。一个工具,break我的build而且没有明显的原因是很糟糕的。
请在评论中与我们分享你的经验!
我们刚刚开源了trackr所以你可以随便蹂躏它,你懂的。阅读完整的声明:http://blog.techdev.de/trackr-is-now-open-source/
trackr: An AngularJS app with a Java 8 backend – Part II的更多相关文章
- trackr: An AngularJS app with a Java 8 backend – Part III
这是最后我们对trackr系列的一部分.在过去的两的博文中,我们已经向您展示我们使用的工具和框架构建后端和前端.如果你错过了前面的帖子现在你可能会想读他们赶上来. Part I – The Backe ...
- trackr: An AngularJS app with a Java 8 backend – Part I
该系列文章来自techdev 我想分享在techdev公司开发的项目-trackr-的一些最新的见解.trackr是一个用来跟踪我们的工作时间,创建报告和管理请假的web应用程序.做这个程序的目的有两 ...
- trackr: An AngularJS app with a Java 8 backend – Part IV 实践篇
REST API对于前后端或后端与后端之间通讯是一个好的接口,而单页应用Single Page Applications (SPA)非常流行. 我们依然以trackr为案例,这是一个跟踪工作时间 请假 ...
- 2.1:你的第一个AngularJS App
本章,带你体验一个简单的开发流程,将一个静态的使用模拟数据的应用,变成具有AngularJS特性的动态web应用.在6-8章,作者将展示如何创建一个更复杂,更真实的AngularJS应用. 1.准备项 ...
- eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错? java.lang.ClassNotFoundException: com.branchitech.app.startup.AppStartupContextListener java.lang.ClassN
eclipse java项目中明明引入了jar包 为什么项目启动的时候不能找到jar包 项目中已经 引入了 com.branchitech.app 包 ,但时tomcat启动的时候还是报错?java. ...
- ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app
转载:http://bitoftech.net/2014/08/11/asp-net-web-api-2-external-logins-social-logins-facebook-google-a ...
- IOS IAP APP内支付 Java服务端代码
IOS IAP APP内支付 Java服务端代码 场景:作为后台需要为app提供服务,在ios中,app内进行支付购买时需要进行二次验证. 基础:可以参考上一篇转载的博文In-App Purcha ...
- APP接口自动化测试JAVA+TestNG(一)之框架环境搭建
前言 好久不曾写点啥,去年换到新公司组测试团队与培养建设花费大量时间与精力,终于架构成型与稳定有时间可以打打酱油了.很久没有总结点啥,提笔想写的内容太多,先放APP接口自动化的内容吧,这个估计大家比较 ...
- 微信APP支付(Java后台生成签名具体步骤)
public class PayCommonUtil { //定义签名,微信根据参数字段的ASCII码值进行排序 加密签名,故使用SortMap进行参数排序 public static String ...
随机推荐
- cocos2dx中的用户数据的管理
提供了专门的类:CCUserDefault用来管理,且提供了单例方法:sharedUserDefault() 1.会在默认路径cocos2d-x-2.2.3\projects\Hello\proj.w ...
- Valid format values for declare-styleable/attr tags[转]
http://chaosinmotion.com/blog/?p=179 reference string color dimension boolean integer float fraction ...
- 关于6410的sd卡和nandflash启动的区别
今天在公司我们队长问我个问题,关于cortex的sd启动流程和nandflash的启动流程,一下想不起来了,中午闲来无事就整理了整理当初6410的两种启动方式的区别.在这里写一下.有不对的请指点,我对 ...
- 在eclipse里的 flex 没有可视化的编辑
注:在4.7版本里去掉了可视化编辑器. 转自:http://3470973.blog.51cto.com/3460973/1135328 最近eclipse切换了一个工作空间,创建的flex项 ...
- 设计模式之原型模式(prototype)
原理:拷贝自身对象实际上就是调用的拷贝构造函数,注意事项是这里的拷贝是深拷贝,即需要拷贝指针所指的内容 #include <stdio.h> #include <memory> ...
- HDAO
dx11 hdao10.1 除了dx的sample竟然搜不到什么文档.... 估计去问别人也是让我继续看代码.. ---------------------------------------- 算法 ...
- jQuery+css+div一些值得注意的常用语句
一.div页面布局 一个好的页面布局很重要,这会让你写代码的时候层次分明: 以2列左侧固定右侧自适应宽度为例子: 这是HTML代码: <!DOCTYPE html PUBLIC "-/ ...
- unity3d android互调
unityPlayer = new AndroidJavaClass("com.xxx.xxx.MainActivity"); curActivity = unityPlayer. ...
- java poi导入EXCEL xls文件代码
/** * */ package com.bn.car.common.report.excel; import java.io.FileInputStream; import java.io.IOEx ...
- Android开发--使用真机进行USB调试程序
在android小程序的开发过程中,使用eclipse中的虚拟机进行程序开发速度较慢,用真机开发可以显著提高调试的速度. 这里我用的操作系统是win7专业版,手机型号HM1S: 进行USB调试的主要步 ...