• jetty-maven-plugin静态文件保存不了

    起因

    为maven项目配置jetty-maven-plugin插件,以jetty:run方式运行,会出现静态文件保存不了的问题。原因是jetty内存映射文件来缓存静态文件. 解决方法是将jetty内存映射参数取消掉.

    解决

    • 找webdefault.xml文件
      在下面路径找到webdefault.xml文件
    C:\Users\Administrator\.m2\repository\org\eclipse\jetty\jetty-webapp\9.2.6.v20141205
    

    如果安装了jetty服务器,在它的etc目录下也可以取到webdefault.xml文件

    • useFileMappedBuffer参数值改为false
      webdefault.xml配置
    <init-param>
      <param-name>useFileMappedBuffer</param-name>
      <param-value>false</param-value>
    </init-param>
    
    • 新增defaultsDescriptor配置项
    <plugin>  
        <groupId>org.eclipse.jetty</groupId>  
        <artifactId>jetty-maven-plugin</artifactId>  
        <version>9.2.6.v20141205</version>  
        <configuration>
            <scanIntervalSeconds>0</scanIntervalSeconds>
            <webAppSourceDirectory>${basedir}/WebRoot</webAppSourceDirectory>
            <webApp>  
                <contextPath>/</contextPath>
                <war>${project.build.directory}/${project.build.finalName}.war</war>
                <!-- jetty9.2.6的defaultsDescriptor在<webApp>里,早期版本在<configuration>或者<webAppConfig>里 -->
                <defaultsDescriptor>${basedir}/WebRoot/resources/webdefault.xml</defaultsDescriptor>
            </webApp>
        </configuration>
    </plugin>
    
    • webdefault.xml加载是否成功
      控制台输出如下,表示加载了webdefualt.xml
    [INFO] Web defaults = .... /WebRoot/resources/webdefault.xml
    

    感受

    上面方法虽然可以解决问题,但是很不好用. 如果jetty-maven-plugin能设计个开发模式设置,在易用性上会有更大提升.

    参考资料

  • PTY allocation request failed on channel 0 是什么意思?

    描述

    在测试ssh与git的连接状况时出现

    ➜  ~  ssh git@github.com
    PTY allocation request failed on channel 0
    Hi miaoyin! You've successfully authenticated, but GitHub does not provide shell access.
    Connection to github.com closed.
    

    提示含义

    PTY allocation request failed on channel 0
    

    上面表示分配PTY失败。PTY指伪终端. 它可以让用户,像在本地shell终端操作一样的操作远程机器. 可以加上参数-T,表示仅建立数据通道.

    设置参数-T

    ➜  ~ ssh -T git@github.com
    Hi miaoyin! You've successfully authenticated, but GitHub does not provide shell access.
    

    某些情况下-T很有用,如将ssh作为数据通道.

  • WARN:oejsh.ContextHandler:Aliased resource 错误

    在为maven项目配置了jetty-maven-plugin插件,以jetty:run方式运行之后,控制台出现

    2014-12-13 10:30:58.531:WARN:oejsh.ContextHandler:Aliased resource: file:/D:/Workspaces/MyEclipse%2010/PKPlatform_bg/WebRoot/pkBg/js/pgManage.js~=
    file:/D:/Workspaces/MyEclipse%2010/PKPlatform_bg/WebRoot/pkBg/js/pgManage.js
    

    发现引用路径中,多了个斜杠,去掉就可以了

    <script type="text/javascript" src="//js/pgManage.js"></script>
    
  • 让网站在浏览器标签上显示小图标

    • 制作宽高均为32像素的小图表,完成后存储为ico格式

    • 添加到页面中

    <link rel="shortcut ico" type="image/x-icon" href="/imsages/favicon.ico">
    
  • chrome跳到daohang.114so.cn

    昨天选好喜欢的名字, 注册了个cn域名,今天审核通过. 有点小高兴. 先配置好域名解析. 然后设置好github的CNAME文件. 域名解析是即刻生效,github的CNAME要等会儿了. 拿着域名在chrome上访问,直接调到http://daohang.114so.cn/ ,在IE上却一切正常. 试了各种方法还是不行,只有在后面随便加个参数先.

  • 在自己的网页中调用搜索引擎

    示例

    下面是常见示例,先动手试试

    <meta charset="UTF-8" />
    <body>
        <!-- 调用google搜索 -->
        <form method=get action="http://www.google.com/search"  target="_blank">
            <!-- input的中name必须为q,否则提交失败,返回google首页-->
            <input type=text name=q size=40 maxlength=255 >
            <!--input type=hidden name=sitesearch value="yongqing.is-programmer.com"-->
            <input type=submit name=btnG value="谷歌搜索">
        </form>
    
        <!-- 调用baidu搜索 -->
        <form action="http://www.baidu.com/baidu" target="_blank">
            <!-- input的中name必须为word,否则提交失败,返回baidu首页-->
            <input type=text name=word size=40>
            <!--input type=hidden name=si value="yongqing.is-programmer.com"-->
            <input type="submit" value="百度搜索">
        </form>
        <!-- 调用yahoo搜索-->
        <form action="http://www.yahoo.com.cn/search">
            <input type=text name="p">
            <!--input type=hidden name=vs value="yongqing.is-programmer.com"-->
            <input type="submit" value="Yahoo 搜索">
        </form>
    </body>
    

    调用google的参数

    发现还可以传递其它参数,它们有什么作用?

    <!–Google站内搜索–>
    <form method=get action=”http://www.google.com/search”>
        <input type=text name=q>
        <input type=submit name=btnG value=”Google 搜索”>
        <input type=hidden name=sitesearch value=”yongqing.is-programmer.com”>
        <input type=hidden name=hl value=zh-CN>
        <input type=hidden name=ie value=utf-8>
        <input type=hidden name=oe value=utf-8>
    </form>
    
    • name="q": 搜索的字符串
    • name="sitesearch": 指定要搜索的网站.
    • name="hl": 以指定语言显示搜索结果. 比如"zh-CN", "zh-TW", "en"
    • name="ie": 指明搜索网页的编码,默认是UTF-8.
    • name="oe": 以指定编码显示搜索结果,默认是UTF-8.
    • name="safe"
    • name="newwindow"

    仔细看google首页的源码,发现也用这样的调用方式.
    如果想要搜索指定网站的网页,google比较好用,比较适合方在个人博客中,作为搜索工具
    百度、yahoo就不介绍了,有兴趣可以研究下.

  • 修改jinja2模板中变量标识符

    使用webpy时,修改jinja2变量标识

    重写webpy包中的template.py文件中的render_jinja类.

    class my_render_jinja:
        """Rendering interface to Jinja2 Templates
    
        Example:
    
            render= render_jinja('templates')
            render.hello(name='jinja2')
        """
        def __init__(self, *a, **kwargs):
            extensions = kwargs.pop('extensions', [])
            globals = kwargs.pop('globals', \{\})
    
            from jinja2 import Environment, FileSystemLoader
            self._lookup = Environment(loader=FileSystemLoader(*a, **kwargs), extensions=extensions)
            # 添加下面两句代码,修改标识符
            self._lookup.variable_start_string = '\{\{ '
            self._lookup.variable_end_string = ' \}\}'
            self._lookup.globals.update(globals)
    
        def __getattr__(self, name):
            # Assuming all templates end with .html
            path = name + '.html'
            t = self._lookup.get_template(path)
            return t.render
    

    有其它方式吗?

    jinja2的变量标识符可以通过以下方式访问到,但是无法被修改

    # 可以通过以下方式访问
    import jinja2
    jinja2.defaults.VARIABLE_START_STRING
    jinja2.defaults.VARIABLE_END_STRING
    jinja2.environment.VARIABLE_START_STRING
    jinja2.environment.VARIABLE_END_STRING
    
    # 使用以下方式赋值均无效
    jinja2.defaults.VARIABLE_START_STRING = '\{\{ '
    jinja2.defaults.VARIABLE_END_STRING = ' \}\}'
    jinja2.environment.VARIABLE_START_STRING = '\{\{ '
    jinja2.environment.VARIABLE_END_STRING = ' \}\}'
    

    为什么无效?

    原因是导入jinja2时,执行了jinja2包中的init.py文件,而init.py中导入Environment对象
    Environment对象的构造函数init(variable_start_string=VARIABLE_START_STRING,variable_end_string=VARIABLE_END_STRING,...)有默认值
    默认值在Environment被导入时,已经固定,之后无法被修改
    所以使用赋值的方式无效

    了解原因后,可以找到另外一种方法,在import前设置

    __docformat__ = 'restructuredtext en'
    __version__ = '2.7.2'
    
    # high level interface
    # 在此处添加下面三句代码
    import defaults
    defaults.VARIABLE_START_STRING = '\{\{ '
    defaults.VARIABLE_END_STRING = ' \}\}'
    from jinja2.environment import Environment, Template
    
    # loaders
    from jinja2.loaders import BaseLoader, FileSystemLoader, PackageLoader, \
         DictLoader, FunctionLoader, PrefixLoader, ChoiceLoader, \
         ModuleLoader
    ```python
    
  • angularjs过滤器(number)

    用来精确浮点数(指定小数点位数).

    在html中用法

    
    

    在js中用法

    $filter('number')(number, fractionSize)
    

    参数

    • number 待精确的数字
    • factionSize(可选) 小数点后精确位数,默认值是3.(默认情况下保留的小数位数小于等于3. 比如: 1234-->1234;1234.56789-->1234.568;1234.56-->1234.56)
      ##例子
    <!doctype html>
    <html ng-app='demo'>
    <meta charset='utf-8'>
    <body>
    <div ng-controller="ExampleController">
      输入数字: <input ng-model='val'><br>
      <!-- 默认格式 -->
      默认格式: <span id='number-default'></span><br>
      <!-- factionSize=0 -->
      保留0位: <span></span><br>
      <!--factionSize大于小数点位数 -->
      保留10位: <span></span><br>
      <!-- factionSize小于小数点位数-->
      保留2位: <span></span>
    </div>
    
    <script src="/static/lib/angular/angular.js"></script>
    <script src="/static/lib/angular-resource/angular-resource.min.js"></script>
    <script>
        var app = angular.module('demo', ['ngResource'])
        .controller('ExampleController', function($scope) {
            $scope.val = 1234.56789;
        });
    </script>
    </body>
    </html>
    

    显示结果

    输入数字: 1,234.56789
    默认格式: 1,234.568
    保留0位: 1,235
    保留10位: 1,234.5678900000
    保留2位: 1,234.57
    
  • 判断端口通不通的几种方法

    通常使用"telnet ip port"判断端口通不通. 有其它方法吗?先看下面的几种方法

    准备环境

    启动一个web服务器,提供端口.

    [wyq@localhost ~]$ python -m SimpleHTTPServer 8080
    Serving HTTP on 0.0.0.0 port 8080 ...
    

    用其它web服务器提供端口也一样,由于python比较方便,这里就用它

    用telnet判断

    telnet是windows标准服务,可以直接用;如果是linux机器,需要安装telnet.

    用法: telnet ip port

    先用telnet连接不存在的端口

    [wyq@localhost ~]$ telnet localhost 9000
    Trying 127.0.0.1...
    telnet: connect to address 127.0.0.1: Connection refused
    

    直接提示连接被拒绝

    再连接上面提供的端口

    [wyq@localhost ~]$ telnet localhost 8080
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    

    看到"Connected to localhost." 可以知道连接成功了.

    后台服务器有什么反映?

    [wyq@localhost monitor]$ python -m SimpleHTTPServer 8080
    Serving HTTP on 0.0.0.0 port 8080 ...
    

    没有任何反映

    此时telnet停住了,随便输入一个字符"a",然后回车

    [wyq@localhost ~]$ telnet localhost 8080
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    a
    <head>
    <title>Error response</title>
    </head>
    <body>
    <h1>Error response</h1>
    <p>Error code 400.
    <p>Message: Bad request syntax ('a').
    <p>Error code explanation: 400 = Bad request syntax or unsupported method.
    </body>
    Connection closed by foreign host.
    

    再看服务器

    [wyq@localhost monitor]$ python -m SimpleHTTPServer 8080
    Serving HTTP on 0.0.0.0 port 8080 ...
    127.0.0.1 - - [22/Aug/2014 07:15:16] code 400, message Bad request syntax ('a')
    127.0.0.1 - - [22/Aug/2014 07:15:16] "a" 400 -
    

    上面是linux环境下telnet连接一个web服务端口的情况.

    用ssh判断

    ssh是linux的标准配置并且最常用,可以用来判断端口吗?

    用法: ssh -v -p port username@ip
    -v 调试模式(会打印日志).
    -p 指定端口
    usernmae可以随意

    连接不存在端口

    [wyq@localhost ~]$ ssh -v -p 9000 wyq@localhost
    OpenSSH_6.4, OpenSSL 1.0.1e-fips 11 Feb 2013
    debug1: Reading configuration data /home/wyq/.ssh/config
    debug1: Reading configuration data /etc/ssh/ssh_config
    debug1: /etc/ssh/ssh_config line 51: Applying options for *
    debug1: Connecting to localhost [127.0.0.1] port 9000.
    debug1: connect to address 127.0.0.1 port 9000: Connection refused
    ssh: connect to host localhost port 9000: Connection refused
    

    "Connection refused"表示端口不可用

    连接存在的端口

    [wyq@localhost ~]$ ssh -v -p 8080 wyq@localhost
    OpenSSH_6.4, OpenSSL 1.0.1e-fips 11 Feb 2013
    debug1: Reading configuration data /home/wyq/.ssh/config
    debug1: Reading configuration data /etc/ssh/ssh_config
    debug1: /etc/ssh/ssh_config line 51: Applying options for *
    debug1: Connecting to localhost [127.0.0.1] port 8080.
    debug1: Connection established.
    debug1: identity file /home/wyq/.ssh/id_rsa type 1
    debug1: identity file /home/wyq/.ssh/id_rsa-cert type -1
    debug1: identity file /home/wyq/.ssh/id_dsa type -1
    debug1: identity file /home/wyq/.ssh/id_dsa-cert type -1
    debug1: identity file /home/wyq/.ssh/id_ecdsa type -1
    debug1: identity file /home/wyq/.ssh/id_ecdsa-cert type -1
    debug1: Enabling compatibility mode for protocol 2.0
    debug1: Local version string SSH-2.0-OpenSSH_6.4
    debug1: ssh_exchange_identification: <head>
    
    debug1: ssh_exchange_identification: <title>Error response</title>
    
    debug1: ssh_exchange_identification: </head>
    
    debug1: ssh_exchange_identification: <body>
    
    debug1: ssh_exchange_identification: <h1>Error response</h1>
    
    debug1: ssh_exchange_identification: <p>Error code 400.
    
    debug1: ssh_exchange_identification: <p>Message: Bad request syntax ('SSH-2.0-OpenSSH_6.4').
    
    debug1: ssh_exchange_identification: <p>Error code explanation: 400 = Bad request syntax or unsupported method.
    
    debug1: ssh_exchange_identification: </body>
    
    ssh_exchange_identification: Connection closed by remote host
    

    "Connection established" 表示已经连上端口

    服务器输出

    [wyq@localhost ~]$ python -m SimpleHTTPServer 8080
    Serving HTTP on 0.0.0.0 port 8080 ...
    127.0.0.1 - - [22/Aug/2014 13:32:55] code 400, message Bad request syntax ('SSH-2.0-OpenSSH_6.4')
    127.0.0.1 - - [22/Aug/2014 13:32:55] "SSH-2.0-OpenSSH_6.4" 400 -
    

    用wget判断

    wget是linux下的下载工具,需要先安装.

    用法: wget ip:port

    连接不存在的端口

    [wyq@localhost ~]$ wget localhost:9000
    --2014-08-22 13:36:42--  http://localhost:9000/
    正在解析主机 localhost (localhost)... 127.0.0.1
    正在连接 localhost (localhost)|127.0.0.1|:9000... 失败:拒绝连接。
    

    连接存在的端口

    [wyq@localhost ~]$ wget localhost:8080
    --2014-08-22 13:37:22--  http://localhost:8080/
    正在解析主机 localhost (localhost)... 127.0.0.1
    正在连接 localhost (localhost)|127.0.0.1|:8080... 已连接。
    已发出 HTTP 请求,正在等待回应... 200 OK
    长度:2770 (2.7K) [text/html]
    正在保存至: “index.html”
    
    100%[======================================>] 2,770       --.-K/s 用时 0s      
    
    2014-08-22 13:37:22 (105 MB/s) - 已保存 “index.html” [2770/2770])
    

    总结

    提供端口服务,则使用了tcp协议,上面是以web服务器为例。如果服务器是更简单的tcp服务器,三个工具同样适用.
    三个工具的共同点是:1.以tcp协议为基础;2.能访问指定端口. 遵循这两点可以找到很多工具.
    在windows下使用telnet比较方便,linux下个人就比较喜欢用wget.

  • angularjs指令名是怎么回事?

    疑惑

    查了很多资料,对指令名的介绍都是一笔带过,只说是驼峰形式. 但是在实际使用时,经常遇到定义的指令名与指令标签对应不上的情况. 对指令名就感到非常疑惑. 定义时指令名是一种形式,使用时又是一种形式,两者怎么关联对应的?

    找不到资料,自己查查angular源码,一探究竟.

    分析源码

    首先在angular.js文件,找到解析指令名的代码

    switch(nodeType) {
      case 1: /* Element */
        // use the node name: <directive>
        //此处是解析标签形式的指令
        addDirective(directives,
            directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
    
        // iterate over the attributes
        for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
                 j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
          var attrStartName = false;
          var attrEndName = false;
    
          attr = nAttrs[j];
          if (!msie || msie >= 8 || attr.specified) {
            name = attr.name;
            value = trim(attr.value);
    
            // support ngAttr attribute binding
            ngAttrName = directiveNormalize(name);
            if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
              name = snake_case(ngAttrName.substr(6), '-');
            }
    
            var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
            if (ngAttrName === directiveNName + 'Start') {
              attrStartName = name;
              attrEndName = name.substr(0, name.length - 5) + 'end';
              name = name.substr(0, name.length - 6);
            }
    
            //此处是解析属性形式的指令名
            nName = directiveNormalize(name.toLowerCase());
            attrsMap[nName] = name;
            if (isNgAttr || !attrs.hasOwnProperty(nName)) {
                attrs[nName] = value;
                if (getBooleanAttrName(node, nName)) {
                  attrs[nName] = true; // presence means true
                }
            }
            addAttrInterpolateDirective(node, directives, value, nName);
            addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
                          attrEndName);
          }
        }
    

    上面一处是解析标签形式的指令名,调用了directiveNormalize(nodeName_(node).toLowerCase())
    另一处是解析属性形式的指令名,调用了directiveNormalize(name.toLowerCase())
    两处都使用了toLowerCase()
    所以解析指令的第一步:将指令名转为小写.

    继续看directiveNormalize()函数

    var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
    /**
     * Converts all accepted directives format into proper directive name.
     * All of these will become 'myDirective':
     *   my:Directive
     *   my-directive
     *   x-my-directive
     *   data-my:directive
     *
     * Also there is special case for Moz prefix starting with upper case letter.
     * @param name Name to normalize
     */
    function directiveNormalize(name) {
      return camelCase(name.replace(PREFIX_REGEXP, ''));
    }
    
    

    它使用用了name.replace(PREFIX_REGEXP, ''),它的作用是去掉x和data开始的前缀 所以解析指令的 第二步:去掉以x-和data-开头的前缀(例如 x- x: x_ data- data: data_ 忽略大小写)

    再继续看camelCase()函数

    var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
    var MOZ_HACK_REGEXP = /^moz([A-Z])/;
    var jqLiteMinErr = minErr('jqLite');
    
    /**
     * Converts snake_case to camelCase.
     * Also there is special case for Moz prefix starting with upper case letter.
     * @param name Name to normalize
     */
    function camelCase(name) {
      return name.
        replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
          return offset ? letter.toUpperCase() : letter;
        }).
        replace(MOZ_HACK_REGEXP, 'Moz$1');
    }
    

    使用了两个replace替换字符,第二个replace不用管,重点看第一个replace,它是什么作用?

    把它拿出来看看

    var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
    function camelCase(name) {
      return name.
        replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
          console.log("_:" + _)
          console.log("separator:" + separator)
          console.log("letter:" + letter)
          return offset ? letter.toUpperCase() : letter;
        }).
    }
    console.log("----my-directive")
    console.log(camelCase(my-directive));
    
    console.log("----mydirective")
    console.log(camelCase(my-directive));
    
    console.log("----mydirectiveworld")
    console.log(camelCase(my-directive));
    /*
    输出内容
    ----my-directive
    _:-d
    separator:-d
    letter:d
    myDirective
    
    ----mydirective
    mydirective
    
    ----mydirectiveworld
    mydirectiveworld
    */
    

    可以看到第一个replace作用是生成驼峰指令名 所以解析指令的第三步:根据分割符(: - _)标记,将字符转换为驼峰形式

    关于replace函数的说明,可以看看这篇文章 http://yongqing.is-programmer.com/posts/56305.html

    更多指令名与指令对应的示例

    以分割符"-"为例
    mymenu --> mymenu   正确
    mymenu --> myMenu   错误
    mymenu --> my-Menu  错误
    
    myMenu --> my-Menu  正确
    myMenu --> myMenu   错误
    myMenu --> mymenu   错误
    
    MyMenu --> x-MyMenu 正确
    MyMenu --> MyMenu   错误
    MyMenu --> mymenu   错误
    
    myProductsMenu --> my-Products-Menu   正确
    myProductsMenu --> myProductsMenu     错误
    myProductsMenu --> my-ProductsMenu    错误
    

    总结

    指令的匹配过程
    1. 将指令名转换为小写.
    2. 去掉以x-和data-开头的前缀(例如 x- x: x_ data- data: data_ 忽略大小写) 3. 根据分割符(: - _),转换为驼峰形式
    其实只要注意一点: 匹配过程以定义时的指令名为准,分割符是用来标识驼峰的(angular没有能力识别单词,分割符的一个作用是标识驼峰).