Seajs

[摘要]前端模块化开发的价值

link

恼人的命名冲突

看不懂,也没必要深究历史,略过

烦琐的文件依赖

使用 Sea.js 来解决

使用 Sea.js,在书写文件时,需要遵守 CMD (Common Module Definition)模 块定义规范。

一个文件就是一个模块。

前面例子中的 util.js

1
2
3
4
5
6
7
8
9
10
11
var org = {};
org.CoolSite = {};
org.CoolSite.Utils = {};

org.CoolSite.Utils.each = function (arr) {
  // 实现代码
};

org.CoolSite.Utils.log = function (str) {
  // 实现代码
};

变成:

1
2
3
4
5
6
7
8
9
define(function(require, exports) {
  exports.each = function (arr) {
    // 实现代码
  };

  exports.log = function (str) {
    // 实现代码
  };
});

通过 exports 就可以向外提供接口。这样,dialog.js 的代码变成:

1
2
3
4
5
6
7
define(function(require, exports) {
  var util = require('./util.js');

  exports.init = function() {
    // 实现代码
  };
});

所以: define API

关键部分到了!我们通过 require('./util.js') 就可以拿到 util.js 中通过 exports 暴露的接口。

这里的 require 可以认为是 Sea.js 给 JavaScript 语言增加的一个 语法关键字,通过 require 可以获取其他模块提供的接口。

类似于 css 中的:

1
2
3
4
@import url("base.css");

#id { ... }
.class { ... }

Sea.js 增加的 require 语法关键字,就如 CSS 文件中的 @import 一样,给我们的源码赋予了依赖引入功能。

如果你是后端开发工程师,更不会陌生。Java、Python、C# 等等语言,都有 include、import 等功能。JavaScript 语言本身也有类似功能,但目前还处于草案阶段,需要等到 ES6 标准得到主流浏览器支持后才能使用。

这样,在页面中使用 dialog.js 将变得非常简单。

1
2
3
4
5
6
<script src="sea.js"></script>
<script>
seajs.use('dialog', function(Dialog) {
  Dialog.init(/* 传入配置 */);
});
</script>

首先要在页面中引入 sea.js 文件,这一般通过页头全局把控,也方便更新维护。

想在页面中使用某个组件时,只要通过 seajs.use 方法调用。

所以: seajs.use API

好好琢磨以上代码,我相信你已经看到了 Sea.js 带来的两大好处:

  1. 通过 exports 暴露接口。这意味着不需要命名空间了,更不需要全局变量。这是一种彻底的命名冲突解决方案。

  2. 通过 require 引入依赖。这可以让依赖内置,开发者只需关心当前模块的依赖,其他事情 Sea.js 都会自动处理好。对模块开发者来说,这是一种很好的 关注度分离,能让程序员更多地享受编码的乐趣。

[摘要] 5 分钟上手 Sea.js

目录结构

1
2
3
4
5
6
7
8
9
10
examples/
  |-- sea-modules      存放 seajs、jquery 等文件,这也是模块的部署目录
  |-- static           存放各个项目的 js、css 文件
  |     |-- hello
  |     |-- lucky
  |     `-- todo
  `-- app              存放 html 等文件
        |-- hello.html
        |-- lucky.html
        `-- todo.html

我们从 hello.html 入手,来瞧瞧使用 Sea.js 如何组织代码。

在页面中加载模块

1
2
3
4
5
6
7
8
9
10
// seajs 的简单配置
seajs.config({
  base: "../sea-modules/",
  alias: {
    "jquery": "jquery/jquery/1.10.1/jquery.js"
  }
})

// 加载入口模块
seajs.use("../static/hello/src/main")

seajs.config API seajs.use API

模块代码

这个小游戏有两个模块 spinning.js 和 main.js,遵循统一的写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 所有模块都通过 define 来定义
define(function(require, exports, module) {

  // 通过 require 引入依赖
  var $ = require('jquery');
  var Spinning = require('./spinning');

  // 通过 exports 对外提供接口
  exports.doSomething = ...

  // 或者通过 module.exports 提供整个接口
  module.exports = ...

});

[摘要] API 快速参考

seajs.config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
seajs.config({

  // 设置路径,方便跨目录调用
  paths: {
    'arale': 'https://a.alipayobjects.com/arale',
    'jquery': 'https://a.alipayobjects.com/jquery'
  },

  // 设置别名,方便调用
  alias: {
    'class': 'arale/class/1.0.0/class',
    'jquery': 'jquery/jquery/1.10.1/jquery'
  }

});

更多配置项请参考:#262

seajs.use

1
2
3
4
5
6
7
8
9
10
11
12
13
// 加载一个模块
seajs.use('./a');

// 加载一个模块,在加载完成时,执行回调
seajs.use('./a', function(a) {
  a.doSomething();
});

// 加载多个模块,在加载完成时,执行回调
seajs.use(['./a', './b'], function(a, b) {
  a.doSomething();
  b.doSomething();
});

更多配置项请参考:#260

define

用来定义模块。Sea.js 推崇一个模块一个文件,遵循统一的写法:

1
2
3
4
5
define(function(require, exports, module) {

  // 模块代码

});

也可以手动指定模块 id 和依赖,详情请参考:#242 require, exports 和 module 三个参数可酌情省略,具体用法如下。

require

require 用来获取指定模块的接口。

1
2
3
4
5
6
7
8
define(function(require) {

  // 获取模块 a 的接口
  var a = require('./a');

  // 调用模块 a 的方法
  a.doSomething();
});

注意,require 只接受字符串直接量作为参数,详细约定请阅读:#259

require.async

用来在模块内部异步加载一个或多个模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
define(function(require) {

  // 异步加载一个模块,在加载完成时,执行回调
  require.async('./b', function(b) {
    b.doSomething();
  });

  // 异步加载多个模块,在加载完成时,执行回调
  require.async(['./c', './d'], function(c, d) {
    c.doSomething();
    d.doSomething();
  });

});

详细说明请参考:#242

exports

用来在模块内部对外提供接口。

1
2
3
4
5
6
7
8
9
define(function(require, exports) {

  // 对外提供 foo 属性
  exports.foo = 'bar';

  // 对外提供 doSomething 方法
  exports.doSomething = function() {};

});

详细说明请参考:#242

Begin Ios Development

开始 iOS 开发

iOS 开发环境

  • MapKit
  • WebKit
  • StoreKit
  • MediaPlayer
  • Social
  • CoreData

Model-View-Controller(MVC)

使用 Xcode

storyboard 文件

XCode 界面

  • Utilities
  • UIKit

创建一个 iOS 应用

Jasig Cas Server Cacerts

由于 SSO 域名切换成好记的域名,需要重新生成证书,并导入:

删除 Client 中曾导入的旧的证书

先找到 CAS Client 部署服务器的 存储 所有信任证书(cacerts) 的位置:/usr/local/jdk/jre/lib/security/cacerts

从中删除原来导入的 cacert。 注: 之前 这里取的别名是 smalllove,这次 重新取个好记的名字 ssoalpha

1
[dianping@host_214-74 security]$ keytool -delete -trustcacerts -alias smalllove -keystore /usr/local/jdk/jre/lib/security/cacerts -storepass changeit

Server 重新生成证书

1
keytool -genkey -alias ssoalpha -keyalg RSA -storepass changeit  -keystore ~/keys/.keystore -validity 3600
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[dianping@host_214-124 ~]$ keytool -genkey -alias ssoalpha -keyalg RSA -storepass changeit  -keystore ~/keys/.keystore -validity 3600
您的名字与姓氏是什么?
  [Unknown]:  sso.a.alpha.dp
您的组织单位名称是什么?
  [Unknown]:  ssoalpha
您的组织名称是什么?
  [Unknown]:  ssoalpha
您所在的城市或区域名称是什么?
  [Unknown]:  ssoalpha
您所在的州或省份名称是什么?
  [Unknown]:  ssoalpha
该单位的两字母国家代码是什么
  [Unknown]:  CN
CN=sso.a.alpha.dp, OU=ssoalpha, O=ssoalpha, L=ssoalpha, ST=ssoalpha, C=CN 正确吗?
  [否]:  y

输入<ssoalpha>的主密码
    (如果和 keystore 密码相同,按回车):
[dianping@host_214-124 ~]$

JBOSS 配置 SSL

因为重新生成了 keystore,而 JBoss 的 SSL 配置有一部分需要用到 keystore 文件。

JBoss 配置 SSL 需要动到的文件: $JBOSS_HOME/server/default/deploy/jboss-web.deployer/server.xml

其中的 keystoreFile 的位置是:$JBOSS_HOME/server/default/conf/server.keystore

这个 keystore 就是生成证书时生成的。

1
2
3
4
5
6
7
8
9
10
11
12
<!-- Define a SSL HTTP/1.1 Connector on port 8443
     This connector uses the JSSE configuration, when using APR, the
     connector should be using the OpenSSL style configuration
     described in the APR documentation -->

<Connector port="8443" address="${jboss.bind.address}"
            protocol="HTTP/1.1" SSLEnabled="true"
           maxThreads="150" scheme="https" secure="true"
           clientAuth="false" sslProtocol="TLS"
           keystoreFile="${jboss.server.home.dir}/conf/server.keystore"
           keystorePass="changeit"
           />

特别注意下:

1
同样的war在tomcat下运行是没有问题的,但在jboss下却包上面的异常。这说明正常情况下HibernatePersistence 应该能转换成PersistenceProvider,不能转换的原因就是这两个类是由不同的加载器加载的。搜索jboss classloader查找解决方案,设置server\default\deploy\JBoss-web.deploy\META-INF\JBoss-service.xml 文件中的<attribute name="UseJBossWebLoader">true</attribute>.

Server 导出证书

1
2
[dianping@host_214-124 keys]$ keytool -export -file ~/keys/ssoalpha.crt -alias ssoalpha -keystore ~/keys/.keystore -storepass changeit
保存在文件中的认证 </home/dianping/keys/ssoalpha.crt>

使用 SCP 工具从 server 下载证书

注意写成完整路径:

1
2
scp -P 58422 dianping@192.168.214.124:$1 $2
copy-from-alpha-cas-server /home/dianping/keys/ssoalpha.crt .

使用 SCP 工具把证书上传到 client 部署机器

1
2
scp -P 58422 $1 dianping@192.168.214.74:$2
copy-to-alpha-employee-port ./ssoalpha.crt /home/dianping/keys/.

client 导入证书

1
2
3
4
5
6
7
8
9
10
11
12
[dianping@host_214-74 keys]$ keytool -import -keystore /usr/local/jdk/jre/lib/security/cacerts -file ./ssoalpha.crt -alias ssoalpha
输入keystore密码:
所有者:CN=sso.a.alpha.dp, OU=ssoalpha, O=ssoalpha, L=ssoalpha, ST=ssoalpha, C=CN
签发人:CN=sso.a.alpha.dp, OU=ssoalpha, O=ssoalpha, L=ssoalpha, ST=ssoalpha, C=CN
序列号:52ccbfcc
有效期: XXX
证书指纹:
     XXX
     签名算法名称:SHA1withRSA
     版本: X
信任这个认证? [否]:  y
认证已添加至keystore中

A Intro to Ionic & AngularJS

Phonegap

Phonegap 到底是什么?

Gradle Installation on Mac OS X

Installation

refer link

看文档发现了一个好玩的东西:

For Un*x users

You need a GNU compatible tool to unzip Gradle, if you want the file permissions to be properly set. We mention this as some zip front ends for Mac OS X don’t restore the file permissions properly.

权限要正确被设置,注意下。

ENVIRONMENT VARIABLES

add GRADLE_HOME/bin to PATH.

TEST INSTALLATION

gradle -v

Build Scripts Basics

basic concepts: projects and tasks.

below is the build.gradle of JakeWharton/hugo. Take is as a start to learn gradle.

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
34
35
36
37
38
39
40
allprojects {
  buildscript {
    repositories {
      mavenCentral()
    }
  }

  dependencies {
    repositories {
      mavenCentral()
    }
  }

  group = GROUP
  version = VERSION_NAME

  apply plugin: 'maven'
}

task wrapper(type: Wrapper) {
  gradleVersion = '1.8'
}

task cleanExample(type: Exec) {
  executable = 'gradle'
  workingDir = project.file('hugo-example')
  args = [ 'clean' ]
}

task assembleExample(type: Exec) {
  executable = 'gradle'
  workingDir = project.file('hugo-example')
  args = [ 'assemble' ]
}

task installExample(type: Exec) {
  executable = 'gradle'
  workingDir = project.file('hugo-example')
  args = [ 'installDebug' ]
}

Resources for Starting Phonegap

起步 phonegap 的一些文章和资源:

  • 前端 f2e 的框架和学习资源
  • JavaScript 的框架和学习资源
  • Phonegap 的文档和一些工具
  • apple 开发者的一些准备工作

phonegap

resources:

使用的是 ionic 提供的 seed project,所以不需要使用 phonegap 的 create 指令。

1
2
$ phonegap build ios # Build the App
$ phonegap install android # Test the App on an Emulator or Device

更新 App,但是貌似没有我想的效果:

$ phonegap platform update android $ phonegap platform update ios

该文章中其他部分: – 添加插件 – 使用 phonegap build

框架

  • ionic
  • angularjs

AngularJS 的学习资源参见一个 github repo : jmcunningham/AngularJS-Learning

工具

  • phonegap build

    – firebase

Git Brune Stale Branchs

Some Cheating Parts When Use Spring Test With Junit

refer section:

  1. why test not run
  2. spring-test breaks in Junit 4.5

Use gist.el

github repo

gist buffer:

1
2
3
4
5
g : reload the gist list from server
e : edit current gist description
k : delete current gist
+ : add a file to the current gist
- : remove a file from the current gist

in-place edition. While viewing a gist file buffer, you can:

1
2
C-x C-s : save a new version of the gist
C-x C-w : rename some file

Functions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
gist-list - Lists your gists in a new buffer. Use arrow keys
to browse, RET to open one in the other buffer.

gist-region - Copies Gist URL into the kill ring.
With a prefix argument, makes a private gist.

gist-region-private - Explicitly create a private gist.

gist-buffer - Copies Gist URL into the kill ring.
With a prefix argument, makes a private gist.

gist-buffer-private - Explicitly create a private gist.

gist-region-or-buffer - Post either the current region, or if mark
is not set, the current buffer as a new paste at gist.github.com .
Copies the URL into the kill ring.
With a prefix argument, makes a private paste.

gist-region-or-buffer-private - Explicitly create a gist from the
region or buffer.

Things About Tomcat SSL Certification and CAS(SAML)

这里是对Tomcat配置证书(生成/导出/导入)的 spike 总结。也不一定是总结 啦。

会总结哪些方面呢?

  1. keytool 相关的命令和作用;
  2. Tomcat 的 SSL 配置;
  3. 什么是证书?
  4. 服务端和客户端都在本地的配置(开发配置);
  5. 服务端部署在其他域名上;
  6. etc.

目前想到的几个问题: – ~/.keystore,为什么 client 会找这个文件?

  • self-signed certificate

CAS Java Client 配置 SAML 1.1

在 client 需要添加这些依赖:

  • cas-client-core-3.1.3.jar
  • commons-codec-1.4.jar
  • commons-logging-1.1.jar
  • opensaml-1.1.jar
  • xmlsec-1.4.0.jar
  • log4j-1.2.15.jar

关于版本,core的话,目前最新的是 3.2。opensaml肯定使用 1.1,因为是 SAML1.1 协议。

其他几个包是什么呢?不需要深入了解,从名称猜测,commons-codec 提供了一 些 encode,decode 方法。xmlsec 应该是安全的XML。

cas-client-core http://mvnrepository.com/artifact/org.jasig.cas

commons-codec http://mvnrepository.com/artifact/commons-codec/commons-codec

opensaml http://mvnrepository.com/artifact/org.opensaml/opensaml/1.1

xmlsec http://mvnrepository.com/artifact/org.apache.santuario/xmlsec

Tomcat 配置 SSL

关于 Tomcat 配置 SSL

什么是 SSL?

主要参考文章 SSL简介

SSL(Server Socket Layer)

SSL(Server Socket Layer)是一种保证网络上的两个节点进行安全通信的协议。IETF(Internet Engineering Task Force)组织对SSL作了标准化,制订了RFC2246规范,并将其称为TLS(Transport Layer Security)。从技术上讲,目前TLS 1.0与TLS 3.0的差别非常微小。

从引用看出一个经常看到的术语:TLS,就是标准化的 SSL 通信协议。换句话说, TLS 是基于 SSL 开发的。准确地说,TLS 1.0 替代了 SSL 2.0,并且 TLS 1.0 和 SSL 3.0 的差别不大,但不能忽操作。

这方面的参考链接:

  1. SSL versus TLS – What’s the difference?

  2. TLS vs. SSL

  3. SSL/TLS 协议详解

SSL和TLS建立在TCP/IP协议的基础上,一些应用层协议,如HTTP和IMAP协议都可 以采用SSL来保证通信的安全。建立在SSL协议上的HTTP被称为HTTPS协议。HTTP 使用的默认端口为80,而HTTPS使用的默认端口为443。

协议层 协议
应用层 HTTP、IMAP、NNTP、Telnet、FTP等
安全套接字层 SSL、TLS
传输层 TCP
网络层 IP

SSL采用加密技术来实现安全通信,保证通信数据的保密性和完整性,并且保证 通信双方可以验证对方的身份。

SSL 中的证书

除了对数据通信进行加密外,SSL还采用了身份认证机制,确保通信双方都可以 验证对方的真实身份。

SSL通过安全证书来证明客户或服务器的身份。当客户通过安全的连接和服务器 通信时,服务器会先向客户出示它的安全证书,这个证书声明该服务器是安全的, 而且的确是这个服务器。每一个证书在全球范围内都是唯一的,其他非法服务器 无法假冒原始服务器的身份。可以把安全证书比做电子身份证。

获取安全证书是一件麻烦的事情。一些服务器会向客户出示自己的安全证书,但 另一方面,为了扩大客户群并且便于客户访问,许多服务器不要求客户出示安全 证书。在某些情况下,服务器也会要求客户出示安全证书,以便核实客户的身份, 这主要用于B2B(Business to Business)事务中。

获取安全证书有两种方式,一种方式是从权威机构购买证书,还有一种方式是创建自我签名的证书。

1 从权威机构获得证书

安全证书可以有效地保证通信双方身份的可信性。安全证书采用加密技术制作而 成,他人几乎无法伪造。安全证书由国际权威的证书机构(Certificate Authority,CA)如VeriSign(www.verisign.com)和Thawte(www.thawte.com) 颁发,它们保证了证书的可信性。申请安全证书时,必须支付一定的费用。一个 安全证书只对一个IP地址有效,如果用户的系统环境中有多个IP,那么必须为每 个IP地址购买安全证书。

2 创建自我签名证书

在某些场合,通信双方只关心数据在网络上可以安全传输,并不需要对对方进行 身份验证,在这种情况下,可以创建自我签名(self-assign)的证书,比如通 过SUN公司提供的keytool工具就可以创建这样的证书。

即,只需要数据加密传输,而不需要额外的一层身份校验。

使用 keytool 工具

这方面的参考文章很多。

对于 .Net,请参考: Yale CAS + .net Client 实现 SSO(1)

对于 Java,请参考: CAS实现单点登录(SSO)经典完整教程

这里唯一需要注意的一点是:生成证书时,要求输入名称和姓氏(First Name and Last Name)时,需要输入部署 cas server 的计算机名,比如: pieux-macbook-pro.local 或者 tech-w-xishanshan。在后面的配置 cas client 的 Authentication Filter 和 Validation Filter 时,配置的服务器 地址应该也是以计算机名开头,不要使用 localhost 或者 ip:

1
2
3
4
5
6
7
8
9
10
11
<init-param>
    <param-name>casServerLoginUrl</param-name>
    <param-value>https://pieux-macbook-pro.local:8443/cas/login</param-value>
</init-param>
...
<filter-name>CAS Validation Filter</filter-name>
<filter-class>org.jasig.cas.client.validation.Saml11TicketValidationFilter</filter-class>
<init-param>
    <param-name>casServerUrlPrefix</param-name>
    <param-value>https://pieux-macbook-pro.local:8443/cas</param-value>
</init-param>

自我签名证书在开发中的注意事项

如果 cas server 和 cas client 都部署在相同的机器上(一般是开发过程中), 那如果你按照上面和上面提到的参考文章的步骤,就应该不会有错误了。

但是,有一个大坑。如果 cas server 和 cas client 不是部署在一台机器上, 你很有可能会遇到一个异常是:

1
sun.security.validator.ValidatorException: PKIX path building failed:

The problem here is that the CAS client does not trust the certificate presented by the CAS server; most often this occurs because of using a self-signed certificate on the CAS server.

该问题一般是 cas client 不信任 cas server 展示的证书,而且绝大多数情况 下(按我目前遇到的,就是所有情况下),是 cas server 向 client 展示的是 self-signed certificate。

而且,使用SAML11的时候会报错(难道是SAML11也需要检验证书的真实性?), 使用CAS20就不会报错。因为按理说,SSL可以不需要证书,只利用加密通信的特 性。这块持续挖掘下。

那怎么解决这个问题呢?很简单,让 client 信任 server 的证书就行了。把 server 端生成的证书拷贝到 client 端部署的机器上,然后用 keytool 工具导 入到 client 机器 JDK 的 cacerts 里。

SSL握手通信过程

主要参考文章 SSL握手通信过程

暂时先不了解。

什么是 .keystore 文件?