eclipse之JRebel热部署

每次修改java文件都需要重启tomcat,最近实在是不堪其扰,果断决定再次折腾一下JRebel来实现热启动,从eclipse marketplace下载的这个插件都是14天的试用期,试用期过了之后就不能在使用了,今天重新捣鼓了一下,终于激活了,以后妈妈再也不用担心我不停的重启tomcat了。

  1. Help > Install New Software中输入
    http://update.zeroturnaround.com/update-site-archive/update-site-6.4.2.RELEASE/。

enter description here

  1. 点击next进入下一步,根据提示一步步安装即可。
  2. 安装成功后help里面就可以看见JRebel Configuration和JRebel Activation
  3. enter description here
  4. 激活
    这里下载破解文件到本地。解压,把压缩包里的:jrebel.jar和jreble.lic两个文件,覆盖到Eclipse安装目录下plugins文件夹下的org.zeroturnaround.eclipse.embedder_6.2.2.RELEASE-201507291337文件夹下所有包含jrebel.jar的子文件夹中。
    加载license文件,然后重启Eclipse。即可看见显示JRebel activated。

enter description here

重启后,查看Eclipse>Window>Preferences会发现,多了一个JRebel的目录。

enter description here
点击JRebel Configuration即可看见:

enter description here
激活成功。

eclipse工程报错

工程导入eclipse中老有报错,经过各种折腾发现是java的原工程默认编译版本与eclipse环境下的编译版本不同。在工程根目录的.setting目录下的org.eclipse.wst.common.project.facet.core.prefs.xml文件中
enter description here
原文件为:
enter description here

修改为
enter description here
并且修改工程的编译版本
enter description here
统一使用JRE1.7版本

hibernate之翻页的实现

pageSize:每页记录数
pageNow:当前页码

@Override
public List<Uploadinfo> onePage(int pageNow, int pageSize,String type) {
    // TODO Auto-generated method stub
    String sql;
    if("picture".equals(type)){
         sql = "from Uploadinfo where picturepath1 <> '' and picturepath1 <> 'picture/meizhaopian.png' order by dataTime desc";

    }else{
        sql="from Uploadinfo order by dataTime desc";
    }
    Query query = itemDaoImpl.getQuery(sql);
    //设置起始页
    query.setFirstResult((pageNow - 1) * pageSize);
    //设置每页最大记录数
    query.setMaxResults(pageSize);
    List<Uploadinfo> infolist = query.list();
    return infolist;
}

index.jsp
bootstrap中的分页组件

<nav style="text-align: center">
    <ul class="pagination" id="pageUl"></ul>
</nav>

index.js

$(window).load(function() {
    ////获取记录条数
    queryAll("rest/Uploadinfo/totlePages");
});
function queryAll(url){
    $.ajax({
        type : "post",
        url :  url,
        dataType : "text",
        data:{
             "type":""
        },
        success : function(msg) {
            var pages = Math.ceil(msg/5); 
            var element = $('#pageUl');//对应下面ul的ID  
            var options = { 
                size:"normal",
                alignment:"center",
                bootstrapMajorVersion:3,  
                currentPage: 1,//当前页面  
                numberOfPages: 5,//一页显示几个按钮(在ul里面生成5个li)  
                totalPages: pages, //总页数  
                itemTexts: function(type, page, current) { //修改显示文字
                    switch (type) {
                    case "first":
                        return "第一页";
                    case "prev":
                        return "上一页";
                    case "next":
                        return "下一页";
                    case "last":
                        return "最后一页";
                    case "page":
                        return page;
                    }
                }, 
                onPageClicked: function (event, originalEvent, type, page) { 
                    //换页,下一页
                    paginator(page);
                },
            }  
            //分页启动
           element.bootstrapPaginator(options); 
           paginator(1);
        }
    });
}
function paginator(pageNow) {
    $.ajax({
        type : "post",
        url :  "rest/Uploadinfo/onePageData",
        dataType : "json",
        data:{
            "pageNow":pageNow,
            "pageSize":5,
            "type":""
        },
        success : function(arrData) {
            console.dir(arrData)
            var str="";
            var name;
//            for (i = (page - 1) * 5; i < page * 5; i++) {
            for(var i=0; i<arrData.length; i++){
                    var pictureUrl = arrData[i].picturepath1;
                    var param = "content.jsp?id="+ arrData[i].id;
                    var content = arrData[i].content;
                    var s = content.substr(0, 7);        
                    if(arrData[i].telephone==""){
                        name="匿名用户"
                    }
                    else{
                        name=arrData[i].telephone;
                    }
                    str += '<div class="wz"><h3 style="width:95%;"><a href="'
                        + param
                        + '" title="'
                        + arrData[i].telephone
                        + ""
                        + '">'
                        + s
                        + "..."
                        + '</a></h3><dl><dt>'
                        + '<a href="'
                        + param
                        + '"  style="margin-top: 0px;" title="阅读全文"><img src="'
                        + pictureUrl
                        + '" width="200" height="123" alt=""></a></dt><dd>'
                        + '<p class="dd_text_1">'
                        + arrData[i].content
                        + '</p><p class="dd_text_2">'
                        + '    <span class="left author" >'
                        + name
                        + '</span><span class="left sj" style="padding-left:80px;">'
                        + arrData[i].dataTime
                        + '</span>'
                        + '<span class="left yd"><a href="'
                        + param
                        + '"  title="阅读全文" style="margin-left: auto";>阅读全文</a></span>'
                        + '<div class="clear"></div></p></dd><div class="clear"></div></dl></div>';

                    $('#infolist').html(''); 
                    $('#infolist').append(str);
                }
            }
    });
}

onePageData中调用onePage方法来实现分页。

java

//获取记录条数
@RequestMapping(value = "/totlePages", method = RequestMethod.POST)
@ResponseBody
public int totlePages(@RequestParam("type") String type) {
    List<Uploadinfo> itemList = itemServiceImpl.totalPage(type);
    int size = itemList.size();
    return size;
}

Struts2之ModelDriven接口实现登陆及退出

当用POST方式提交表单,提交的数据量大时,action中定义各种数据,并实现get/set请求就显得过于臃肿,改用Struts2的ModelDriven接口来获取用户提交的HTTP请求,只需要定义相应的Model,Struts2框架会自动将用户提交的HTTP信息赋给相应的Model。
对项目中的LoginAction进行修改,采用ModelDriven方式。

LoginModel

首先,系统采用电话+密码的登陆方式,建立对应的LoginModel.java。

public class LoginModel {
    private String telephone;
    private String password;

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

LoginAction

表单提交的action继承ModelDriven接口,实现getter方法,重载execute方法。

@ParentPackage(value = "json-default")
@Controller
@Action(value = "/loginAction2", results = { @Result(name = "success", type = "redirect", location = "/index.jsp"),
        @Result(name = "input", type = "redirect", location = "/login.html"),
        @Result(name = "error", type = "redirect", location = "/login.html") }, exceptionMappings = {
                @ExceptionMapping(exception = "java.lang.Exception", result = "error") })
public class LoginAction2 extends BaseAction implements ModelDriven<LoginModel> {

    private static final long serialVersionUID = 1L;

    @Resource
    private IUserService userManagerImpl;
    private LoginModel login = new LoginModel();

    @Override
    public LoginModel getModel() {
        // TODO Auto-generated method stub
        return login;
    }

    // 重载
    public String execute() throws Exception {
        String password = login.getPassword();
        String telephone = login.getTelephone();
        if (password != null && !"".equals(password)) {
            // password = MD5.MD5Encode(password);
        }
        if (telephone == null || telephone == "" || password == null || password == "")
            return INPUT;
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(telephone, password);
        token.setRememberMe(true);// 记住我

        try {
            // 登录,即进行身份验证操作
            subject.login(token);// 调用 myRealm的 doGetAuthenticationInfo方法
            String telephone2 = (String) subject.getPrincipal();// 登陆成功就可以这样子拿到用户名了
            User user = userManagerImpl.queryByTel(telephone2);
            subject.getSession().setAttribute("uname", user.getName());
        } catch (UnknownSessionException uae) {
            subject.getSession().setAttribute("myerror", "登录异常!");
            return ERROR;
        } catch (UnknownAccountException ex) {
            subject.getSession().setAttribute("myerror", "用户名不存在!");
            return INPUT;
        } catch (IncorrectCredentialsException ice) {
            subject.getSession().setAttribute("myerror", "密码错误!");
            return INPUT;
        } catch (LockedAccountException lae) {
            subject.getSession().setAttribute("myerror", "登录异常!");
            return INPUT;
        } catch (AuthenticationException e) {
            subject.getSession().setAttribute("myerror", "用户登录失败!");
            return INPUT;
        }
        return SUCCESS;
    }

    public String logout() throws Exception {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            subject.logout(); // session 会销毁,在SessionListener监听session销毁,清理权限缓存
        }
        return INPUT;
    }
}

注意subject.getSession().setAttribute(arg0, arg1);shiro的seeion,可以在login.jsp页面获取到错误类型。

<%
    Object error = session.getAttribute("myerror"); 
    if(error==null)
        error=" ";
 %>
 <form action="login.action">
    ...
    <label style="color:red"><%=error%></label>
    <div class="form-group">
        <input type="text" name="telephone" class="email"
            placeholder="请输入电话" autocomplete="off" required="required" />
    </div>
    <div class="form-group ">
        <input type="password" name="password" class="password"
            placeholder="请输入密码" autocomplete="off" required="required" />
    </div>
    ...
</form>

LogoutAction

注销账号退出系统,可以在LoginAction中添加一个logout方法,直接调用loginAction!logout.action,或者重新写一个Action

@ParentPackage(value = "json-default")
@Controller
public class LogoutAction extends BaseAction {

    private static final long serialVersionUID = 1L;

    @Action(value = "/logoutAction", results = { 
            @Result(name = "success", type = "redirect", location = "/login.jsp"),
            @Result(name = "error", type = "redirect", location = "/index.jsp") }, exceptionMappings = {
                    @ExceptionMapping(exception = "java.lang.Exception", result = "error") })
    public String logout() throws Exception {
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            subject.logout(); // session 会销毁,在SessionListener监听session销毁,清理权限缓存
        }
        return SUCCESS;
    }
}

调用logoutAction.action即可。

grunt + bower

[TOC]

入门

Grunt是JavaScript 任务运行器。对于需要重复执行的任务,例如压缩、编译、单元测试等,这种自动化工具可以减少你的工作量,使你的工作更轻松
Grunt和 Grunt 插件是通过 npm 安装并管理的。Grunt 0.4.x 必须配合Node.js >= 0.8.0版本使用。;奇数版本号的 Node.js 被认为是不稳定的开发版。

安装

npm install grunt --save-dev

后面的 –save-dev 参数是说,把这个插件信息,同时添加到 package.json 的 devDependencies 中:
enter description here

由于grunt仅在开发阶段使用,所以使用 –save-dev 。如果是运行时使用的,则用 –save。
命令行下使用grunt:

npm install -g grunt-cli

-g 是说把grunt-cli安装成全局工具。输入以下命令测试:
enter description here

并且已经有一份配置好package.json 和 Gruntfile 文件的项目了,至此grunt环境安装好,可以在项目中使用了

主要文件

一个grunt项目需要两个文件:package.json和Gruntfile.js,前者用于nodejs包管理,比如grunt插件安装,后者是grunt配置文件,配置任务或者自定义任务。

package.json

package.json应当放置于项目的根目录中,与Gruntfile在同一目录中,并且应该与项目的源代码一起被提交。在上述目录(package.json所在目录)中运行npm install将依据package.json文件中所列出的每个依赖来自动安装适当版本的依赖。

下面列出了几种为你的项目创建package.json文件的方式:

npm init/grunt-init
  1. 大部分 grunt-init 模版都会自动创建特定于项目的package.json文件。
  2. npm init命令会创建一个基本的package.json文件。
  3. 复制下面的案例,并根据需要做扩充,参考此说明.
{
  "engines": {
    "node": ">= 0.10.0"
  },
  "devDependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-concat": "~0.4.0",
    "grunt-contrib-copy": "^1.0.0",
    "grunt-contrib-jshint": "~0.10.0",
    "grunt-contrib-nodeunit": "~0.4.1",
    "grunt-contrib-uglify": "~0.5.0",
    "grunt-contrib-watch": "~0.6.1"
  }
}

Gruntfile

Gruntfile.js 或 Gruntfile.coffee 文件是有效的 JavaScript 或 CoffeeScript 文件,应当放在你的项目根目录中,和package.json文件在同一目录层级,并和项目源码一起加入源码管理器。
为grunt创建配置文件Gruntfile.js,安装grunt-init

# 安装grunt-init
npm install grunt-init -g

# 下载grunt模板
git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile

# 生成Gruntfile
grunt-init gruntfile

根据需要回答问题,或者使用默认值,将得到Gruntfile.js文件
运行grunt-init gruntfile时,总报错,折腾好久才明白,被网上的这些资料误导了,~是Linux下表示当前目录的参数,如果用~/.grunt-init/gruntfile下载地址时,在windows环境下应该是:grunt-init <PATH>,PATH是template.js所在路径。

grunt-init ~\.grunt-init\gruntfile

然后再根据提示生成gruntfile.js文件。
Gruntfile由以下几部分构成:

“wrapper” 函数
项目与任务配置
加载grunt插件和任务
自定义任务

grunt-bower-task

bower只负责把依赖下载到本地的 bower_components 目录,并不负责把它们拷贝到我们项目中实际使用的地方,比如 public/js/lib 目录下。为了实现这样的功能,我们还需要另一个插件的帮助:

npm install grunt-bower-task --save-dev

根目录下运行:

# bower具体安装使用请查看《bower》一文
npm install bower 
# 将grunt与bower完美结合
grunt bower

运行结果:
enter description here

Express.js

[TOC]

Express安装

  1. 全局安装express,express作为命令被安装到了系统中

    1
    npm install -g express
  2. 查看express版本

    1
    express -V
  3. 使用express命令创建工程,并支持ejs

    1
    2
    > express -e nodejsDemo
    > cd nodejs-demo && npm install//安装依赖
  4. 模板项目建立成功,启动模板项目

    1
    node app.js
  5. 通过node启动程序,每次代码修改都需要重新启动。 有一个工具supervisor,每次修改代码后会自动重启,会我们开发省很多的时间

    1
    npm install -g supervisor
  6. 再次启动服务

    1
    supervisor app.js

设置静态文件目录

项目使用bower来管理各个插件包,所以在项目中需要将bower_components设置为静态资源的根目录。express默认的静态文件目录为public下,也可以设置多个静态文件目录。

1
2
3
//设定静态文件路径
app.use(express.static(path.join(__dirname, 'public')));
app.use('/bower_components', express.static(path.join(__dirname,'/bower_components')));

如果不使用path.join()方法则可以直接使用字符串相加

1
app.use('/bower_components', express.static(__dirname+'/bower_components'));

文件访问

  1. 首先,require加载路由

    1
    2
    3
    var routes = require('./routes/index');
    var users = require('./routes/users');
    var table = require('./routes/table');
  2. 设置访问URI

    1
    2
    3
    4
    app.use('/', routes);
    app.use('/index', routes);
    app.use('/users', users);
    app.use('/table', table);
  3. 访问地址

    1
    2
    3
    4
    http://localhost:3000
    http://localhost:3000/index
    http://localhost:3000/users
    http://localhost:3000/table
  4. routes路由文件中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    router.get('/', function(req, res, next) {
    res.render('index', { title: 'aa' });
    });

    router.get('/', function(req, res, next) {
    res.render('users', { title: 'users' });
    })

    router.get('/', function(req, res, next) {
    res.render('table', { title: '部门111' });
    })

上面第一块代码意思是,get请求根目录则调用views文件夹中的index模板,并且传入参数title为“aa”,这个title就可以在模板文件中直接使用。

设置html引擎

  1. 先对app.js做如下修改,再将view中页面改为.html
    1
    2
    3
    4
    var ejs = require('ejs');
    再将app.set('view engine', 'ejs'); 变成
    app.engine('.html', ejs.__express);
    app.set('view engine', 'html');

若不修改view中页面,当引擎改为html引擎时,则将routes路由中的.ejs渲染写全文件名,如:

1
2
3
router.get('/', function(req, res, next) {
res.render('users.ejs', { title: 'users' });
})

若渲染文件原本就是.html文件则可以不用写后缀名。并且.html文件中依然可以写<%=title%>这种类似的语法

  1. 静态路由
    添加主页路由
app.get('/', function(req, res) {
   res.sendfile('./views/index.html');
});

//路径参数获取
app.get('/:name', function(req, res) {
    var fileName = req.params.name;
    //console.log('./views/'+fileName);
    res.sendFile(fileName);
});
  1. 配置supervisor热部署NodeJS
//安装
npm install -g supervisor

配置,在WebStorm中选择要Run–Edit Configurations

Working directory选择项目目录(supervisor会监控此目录内所有文件的改变自动重启)
enter description here

bower

[TOC]

bower使用

前端的包管理器。
Bower是基于Git之上的包管理工具,提供的包的源头都是Git库(多数在Github上,并非所有)。能够通过Bower下载的包,在其Git库下都会有一个bower.json文件。
我们在bower上下载的包,大部分都是包的源代码库,有一大堆没有编译或者构建过的半成品文件,对于我们使用来说比较多余。为了只获取我们需要的文件,经常使用的工具是Grunt,一种任务运行器,常被用作前端项目构建工具,使用bower的项目几乎没有不使用Grunt或其他类似工具的。
bower只负责把依赖下载到本地的bower_components目录,并不负责把它们拷贝到我们项目中实际使用的地方,比如public/js/lib目录下。

为了实现这样的功能,我们还需要另一个插件的帮助:

npm install grunt-bower-task --save-dev

首先在Gruntfile中添加

grunt.loadNpmTasks('grunt-bower-task');

然后在grunt.initConfig({…})参数中,添加相应的配置项:

bower: {
    install: {
      options: {
        targetDir: './public/js/lib',
        layout: 'byComponent',
        install: true,
        verbose: false,
        cleanTargetDir: false,
        cleanBowerDir: false,
        bowerOptions: {}
      }
    }
  }

这里指定拷贝的目标目录为public/js/lib,且文件按照模块分成单个目录(byComponent)。如果想把所有的js放在同一个目录,所有的css文件放在同一个目录,则使用byType

安装

npm install -g bower

-g表示全局安装
npm是nodejs的默认包管理器

常用的插件

bower install jquery#1.11.1 –save
bower install bootstrap –save
bower install bootstrap-table –save
bower install font-awesome -save
bower install d3 –save
bower install jqueryui –save
bower install datatables#1.10.2 –save
bower install echarts –save
bower install moment –save
bower install backbone –save
bower install seajs –save
bower install requirejs -save
bower install angular -save

download 方式

# 已注册的包,使用简写即可
$ bower install jquery
# GitHub 上的项目,使用名称即可
$ bower install desandro/masonry
# GitHub上的项目
$ bower install git://github.com/user/package.git
# 直接通过 URL 下载
$ bower install http://example.com/script.js

参数:

-F, –force-latest: 不管冲突问题强制使用最新版本
-p, –production: 安装生产环境的库,不安装开发环境所需的文件
-S, –save: 将安装的包信息保存到项目的 bower.json 依赖配置中
-D, –save-dev: 将已安装的包信息保存到项目开发环境的 bower.json 依赖中

命令

bower init

创建bower.json文件。
在命令行中进入项目根目录,输入bower init,根据提示输入一些项目基本信息,或者直接回车或空格,会生成一个bower.json文件,用来保存该项目的配置
enter description here

bower help

帮助命令
enter description here

bower install/uninstall

包的管理

bower install jquery
bower uninstall jquery

包的更新,修改bower.json中的dependencies参数后执行如下命令:

bower update 

bower会动更新包的版本
上述命令完成以后,你会在你刚才创建的目录下看到一个bower_components的文件夹,其中目录包含所有安装的插件如下:
enter description here

–save参数

bower install jquery --save

其中–save参数是保存配置到你的bower.json,你会发现bower.json文件已经多了一行:

"dependencies": {
   "jquery": "~2.1.4"
 }

bower list

查看项目所安装的所有包。
enter description here
查看本地缓存包

bower cache list

查找相关包
比如,需要搜索bootstrap相关的插件:

bower search bootstrap

enter description here

bower info

包的信息
比如我们想要查找jquery都有哪些个版本,输入如下命令:

bower info jquery

如下图说所示:
enter description here

enter description here

查看库的url

bower lookup jquery

查看库的主页

bower home jquery

注册

先在github上创建资源库,将本地工程通过git push origin master上传,然后注册:

bower register 工程名 github地址

之后就可以通过bower install来安装了。

bower.json

bower.json是bower的主配置文件,里面有几个主要参数,可以通过bower init来生成

{
  "name": "Angular",
  "authors": [
    "chen1218chen <cc.2008.com@163.com>"
  ],
  "description": "",
  "main": "",
  "license": "MIT",
  "homepage": "https://github.com/chen1218chen/Angular",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "angular": "^1.5.6",
    "bootstrap": "^3.3.6",
    "jquery": "^2.2.4",
    "requirejs": "^2.2.0",
    "bootstrap-table": "^1.10.1",
    "react": "^15.1.0",
    "font-awesome": "^4.6.3",
    "jquery-confirm": "^2.6.0",
    "jquery-ui": "^1.11.4",
    "bootstrap3-dialog": "bootstrap-dialog#^1.35.1"
  },
  "exportsOverride": {
    "angular": {
      "": "*.min.js"
    },
    "bootstrap": {
      "js": "dist/js/*.min.js",
      "css": "dist/css/*.min.css",
      "fonts": "dist/fonts/*.*"
    },
     "bootstrap3-dialog": {
      "js": "dist/js/*.min.js",
      "css": "dist/css/*.min.css"
    },
    "bootstrap-table": {
      "js": "dist/*.min.js",
      "locale": "dist/locale/bootstrap-table-zh-CN.min.js",
      "extensions": [
        "dist/extensions/export/*.min.js",
        "dist/extensions/editable/*.min.js",
        "dist/extensions/angular/*.min.js"
      ],
      "css": "dist/*.min.css"
    },
    "font-awesome": {
      "css": "css/*.min.css",
      "fonts": "fonts/*.*"
    },
    "jquery": {
      "": "dist/jquery.min.js"
    },
    "react": {
      "": "*.min.js"
    },
    "requirejs": {
      "": "require.js"
    },
    "jquery-ui": {
      "": "*.min.js"
    },
    "jquery-confirm": {
      "": "*.min.js"
    }
  }
}

dependencies: 依赖的软件包运行bower install 即可下载安装这些插件包
exportsOverride: 通过bower下载的插件的路径与真实项目中的不一致,需要这个参数来设置每个包复制的文件及路径。与grunt配合使用gruntfile.js中

    bower: {
    install: {
      options: {
        targetDir: 'WebContent/lib',
        layout: 'byComponent',
        install: true,
        verbose: false,
        cleanTargetDir: false,
        cleanBowerDir: false,
        bowerOptions: {}
      }
    }
  }
grunt.loadNpmTasks('grunt-bower-task');

之后,运行grunt bower即可完成复制
enter description here

Angular

[TOC]

初识Angular

angular是一种MVVM前端框架,解决了前后端代码的耦合性,可以分开开发部署;这样使得程序模块化高,可维护性高,灵活性高;可测试性,单元测试方便

模块化

AngularJS 也是遵循 AMD 的。

var app = angular.module('app', [
    'moduleA',
    'moduleB',
]);
app.controller('MainCtrl', [
    '$scope',
     function ($scope) {
}]);

对相同的类型归类:

var services = angular.module('services',[]);
services.service('MyService', function(){
  //service code
});

var controllers = angular.module('controllers',['services']);
controllers.controller('MyCtrl', function($scope, MyService){
    //controller code
});

var app = angular.module('app',['controllers', 'services']);

核心概念

  • 双向绑定:MVVM模型,view和model双向绑定,一方改变,另一方也会跟着变化。
  • scope:view和controller之间的纽带,作为数据模型model,监听model的变化。每个angular-app只有一个rootScope,也存在childScope,每个childScope都会有parentScope和childScope,原型方式继承。
  • controller:规范的angular中,controller中不出现任何DOM操作,controller仅仅是改变scope上的数据即可。
  • view: angular会利用DOM树,经过complie再和scope数据结合,呈现给用户。

angular应用入口

添加ng-app属性或者angular.bootstrap(element,[‘模块名’])启动。ng-app属性可以没有值,angular会默认创建一个。
ng-model指令的值挂在$scope对象上。

angular + requirejs

<div ng-controller="myCtrl">
    <span>{{title}}</span>
</div>

requirejs.config({
    paths : {
        angular : 'angular/angular'
    },
    shim : {
        angular : {
            exports : 'angular'
        },
    }
})
define([ 'angular' ], function( angular) {
    var title = angular.module("myApp", []);
    title.controller('myCtrl', function($scope) {
        $scope.title = "主页";
    });
    //手动启用angular
    angular.element(document).ready(function() {
        angular.bootstrap(document, [ 'myApp' ]);
    });
});

注意:不能添加ng-app属性,采用手动启动angularjs应用

异步加载注册controller/directive/filter/service

一般情况下我们会将项目所用到的controller/directive/filter/sercive预先加载完再初始化AngularJS模块,但是当项目比较复杂的情况下,应该是打开对应的界面才加载对应的controller等资源,但是AngularJS一旦初始化,之后加载的controller/directive/filter/sercive是不会自动注册到模块上的。用AngularJS + ui-router + RequireJS来构建项目应该是比较常见的,所以我就基于这个条件来看看如何解决这个问题。
参考:
AngularJS + ui-router + RequireJS异步加载注册controller/directive/filter/service

Services

Service vs Factory

angular之Service vs Factory一文。

$http服务

$http 是 AngularJS 中的一个核心服务,用于读取远程服务器的数据。

var app = angular.module('myApp', []);
app.controller('siteCtrl', function($scope, $http) {
  $http.get("http://www.runoob.com/try/angularjs/data/sites.php")
  .success(function (response) {$scope.names = response.sites;});
});

$timeout 服务

AngularJS $timeout 服务对应了 JS window.setTimeout 函数。

两秒后显示信息:

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $timeout) {
    $scope.myHeader = "Hello World!";
    $timeout(function () {
        $scope.myHeader = "How are you today?";
    }, 2000);
});

$interval 服务

每两秒显示信息:

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $interval) {
    $scope.theTime = new Date().toLocaleTimeString();
    $interval(function () {
        $scope.theTime = new Date().toLocaleTimeString();
    }, 1000);
});

自定义服务

创建一个名为test的服务

app.service('test', function() {
    this.myFunc = function (x) {
        return x.toString(16);
    }
});

控制器myCtrl中调用

app.controller('myCtrl', function($scope, test) {
    $scope.hex = test.myFunc(255);
});

过滤器myFormat中的使用

app.filter('myFormat',['hexafy', function(hexafy) {
    return function(x) {
        return hexafy.myFunc(x);
    };
}]);

Directive指令

扩展html语言,类似于React的组件

var app = angular.module("myApp", []);
app.directive("runoobDirective", function() {
    return {
        template : "<h1>自定义指令!</h1>"
    };
});
//以下两种方式调用都可以
<runoob-directive></runoob-directive>
<div runoob-directive></div>

类名调用

app.directive("runoobDirective", function() {
    return {
        restrict : "C",
        template : "<h1>自定义指令!</h1>"
    };
});
<div class="runoob-directive"></div>

注释调用

app.directive("runoobDirective", function() {
    return {
        restrict : "M",
        replace : true,
        template : "<h1>自定义指令!</h1>"
    };
})

注意: 需要在该实例添加 replace 属性, 否则评论是不可见的。
注意: 必须设置 restrict 的值为 “M” 才能通过注释来调用指令。

restrict

restrict 值可以是以下几种:

  • E 作为元素名使用
  • A 作为属性使用
  • C 作为类名使用
  • M 作为注释使用

插件

1. angularAMD

RequireJS+AngularJS
angularAMD is an utility that facilitates the use of RequireJS in AngularJS applications supporting on-demand loading of 3rd party modules such as angular-ui.
angularAMD是作者@ marcoslin使用 RequireJS + AngularJS开发的前端mvvm框架,因此你可以使用它快速创建一款Web App.它特别适合快速开发SPA应用。

2. angularUI

AngularJS 的UI增强指令集。包含的模块有:
UI-Utils
UI-Modules
UI-Alias
UI-Bootstrap
NG-Grid
UI-Router
IDE Plugins
GSoC

UI-Router与ngRoute

ngRoute是用AngularJS框架的核心部分
ui-router是一个社区库、第三方模块,它是用来提高完善ngroute路由功能的,功能非常强大。它支持一切正常ngroute也可以做许多额外的功能。

3. Angular UI Bootstrap

UI Bootstrap 是由 AngularJS UI 团队编写的纯 AngularJS 实现的 Bootstrap 组件。

4. Mobile Angular UI

Mobile Angular UI是一个类似jQuery Mobile的移动UI框架

CommonJS,AMD模块化规范

[TOC]

模块化开发依然成为前端开发的主流,我们需要做的就是将不同的模块组织起来。最有名的前端模块管理器即requireJS,采用AMD标准。除此之外的其他模块管理器各有特色。

模块化规范

CommonJS

CommonJS用在服务器端,是服务器模块化的一种规范,NodeJS是其具体实现。加载模块是同步的。由于NodeJS主要用于服务器的编程,加载的模块文件一般已经存在本地,所以加载起来很快,不用考虑异步加载问题,而前端浏览器需要从服务器加载模块,则必须异步加载,就需要AMD,CDM。
根据CommonJS规范,一个单独文件就是一个模块,加载模块使用require()方法,该方法读取一个文件并执行,最后返回exports对象。
CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}

  • require()用来引入外部模块;
  • exports对象用于导出当前模块的方法或变量,唯一的导出口;
  • module对象就代表模块本身,存储了模块的元信息。具体如下:
    • module.id——模块的ID。
    • module.dependencies——一个数组,存储了此模块依赖的所有模块的ID列表。
    • module.exports——与exports指向同一个对象。

AMD/CMD

用在浏览器端,异步加载
AMD:异步模块定义,是RequireJS在推广过程中对模块定义的规范化产出。先提出的
CMD:通用模块定义,是SeaJS (由玉伯-淘宝前端工程师提出)在推广过程中对模块定义的规范化产出
区别:

  1. 对于依赖的模块AMD是提前执行,CMD是延迟执行。不过RequireJS从2.0开始,也改成可以延迟执行(根据写法不同,处理方式不通过)。
  2. CMD推崇依赖就近,AMD推崇依赖前置。即SeaJS是懒执行,requireJS是预执行。
  • SeaJS只会在真正需要时才执行该模块,严格按照代码中require模块的顺序执行。
  • RequireJS中所有依赖的模块加载被提前并行执行了,执行的顺序不能保证。这个问题使用shim参数就可以解决了,shim里面配置好依赖。

官方的解释:SeaJS与RequireJS 的异同

//AMD 
define(['./a','./b'], function (a, b) { 

    //依赖一开始就写好 
    a.test(); 
    b.test(); 
}); 

//CMD 
define(function (requie, exports, module) { 

    //依赖可以就近书写 
    var a = require('./a'); 
    a.test(); 

    ... 
    //软依赖 
    if (status) { 

        var b = requie('./b'); 
        b.test(); 
    } 
}); 

SeaJS和 RequireJS中的define

define(id?, deps?, factory);

事实上SeaJS和RequireJS的define前两个参数的确一样。id都为字符串,都遵循 Module Identifiers。deps都是指依赖模块,类型都为数组。区别仅在于第三个参数factory,虽然类型也都是函数,但factory的参数意义却不同。
RequireJS中factory的参数有两种情况:

  1. factory实参和deps数组元素一一对应,数组元素有几个,factory实参个数就有几个。
define(['a', 'b'], function(a, b){
        // todo
});
  1. 固定为require,exports, module(modules/wrappings格式)。
define(function(require, exports, module){
    // todo
});

这种方式是RequireJS后期向 Modules/Wrappings 的妥协,即兼容了它。而SeaJS的define仅支持RequireJS的第二种写法:Modules/Wrappings。

SeaJS和 RequireJS中的require

SeaJS中“依赖”都需要使用require函数去获取,虽然SeaJS的define的第二个参数deps也有“依赖”的意思,但它是提供打包工具(SPM)用的。此外,SeaJS的require是作为参数传入匿名函数内的,RequireJS的require则是全局变量。

三种编写模块的模式

    define(function(require, exports, module) {
    var a = require('a'); //引入a模块
    var b = require('b'); //引入b模块

    var data1 = 1; //私有数据

    var func1 = function() { //私有方法
        return a.run(data1);
    }

    exports.data2 = 2; //公共数据

    exports.func2 = function() { //公共方法
        return 'hello';
    }
});

或者:

    define(function(require) {
    var a = require('a'); //引入a模块
    var b = require('b'); //引入b模块

    var data1 = 1; //私有数据

    var func1 = function() { //私有方法
        return a.run(data1);
    }

    return {
        data2: 2,
        func2: function() {
            return 'hello';
        }
    };
});

如果模块定义没有其它代码,只返回一个对象,还可以有如下简化写法:

define({
    data: 1,
    func: function() {
        return 'hello';
    }
})

这种写法适合定义纯JSON数据的模块。

模块化管理器

bower

主要用来进行模块的安装,升级和删除

npm install -g bower
bower install jquery
bower update jquery
bower uninstall jquery

具体内容详见bower一文中。

Grunt

前端开发利器,用来打包管理.js
具体详见grunt+bower 一文中。

browserify

Browserify 是目前最常用的 CommonJS 格式转换的工具。本身也是一个NodeJS模块,可以通过npm来安装。使用类似NodeJS的require的方式来组织浏览器的javascript端代码。

npm install -g browserify
|