糊言乱语

志未半斤, 才无八两. 有苦有乐, 糊涂过活。
posts - 25, comments - 7, trackbacks - 0, articles - 42
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2007年8月12日

image

posted @ 2008-07-11 11:25 Stanley Sun 阅读(327) | 评论 (0)编辑 收藏

众所周知在计算机中所有的数据都是以二进制的方式存储的。不管是int,String,float等等不同的数据类型,最终都会保存为01的形式。那么为什么要使用这种方式储存数据呢?

因为计算机是一种电子设备,由复杂的电子元器件组合而成,一个电子元器件有带电和不带电两种状态,通常我们将带电状态表示为数值1,不带电状态表示为数值0,多个这样的元器件的组合可以表示更多状态,也就是可以表示更多的数据,如000表示0,001表示1,010表示2,011表示3,依此类推,111表示 7,一个元器件可表示一位(bit)数据,这种表示数据的方式就叫二进制。
在实际的电子设备中,我们将8个这样的元器件形成一个单元,这样的单元叫一个字节(byte),一个字节能表示多少个数呢?表示数值的范围是0-255。
一个字节由8个二进位组成,其中最右边的一位称为“最低有效位”或“最低位”,最左边的一位称为“最高有效位”或“最高位”。每一个二进位的值是0或1。

二进制计数的缺点:书写太长,容易出错,一般计算机的数据位数都是4的整数倍,所以,在计算机里通常采用16进制计数法。用数字可以表示各种信息,计算机里只有数值,当你在内存中看到一个数值时,这个数值可能代表各种意义,生活中的数值也可以代表其他意义,如1234可以代表密码,存款额,电报信息,根据上下线索,我们就能够知道这数值代表的意义

 

但是在Java中到底是如何去保存数据的呢?下面我就以int数据类型为例说明Java的方式。

大家都知道在Java中规定1 int = 4 byte, 1 byte = 8 bit。以此推理那么1个int在计算机中就是以4 * 8 = 32位(bit)的方式存储的。而又由于java中的int是属于有符号类型(Java中不存在unsigned类型),所以32位的高一位是符号位,由此可以推理出int的储存大小区间

Integer.MAX_VALUE = 2147483647(十进制) = 1111111 11111111 11111111 11111111(二进制)
Integer.MIN_VALUE = -2147483648(十进制) = 10000000 00000000 00000000 00000000(二进制)

现在我们知道了二进制的概念了,但是其实二进制我想我们想象的那么单纯的表示的,他们是不同的表现方式如:原码,反码,补码

  • 原码
    将最高位作为符号位(以0代表正,1代表负),其余各位代表数值本身的绝对值(以二进制表示)。
                为了简单起见,我们用1个字节来表示一个整数。
                +7的原码为: 00000111
                 -7的原码为: 10000111
  • 反码
          一个数如果为正,则它的反码与原码相同;一个数如果为负,则符号位为1,其余各位是对原码取反。
                为了简单起见,我们用1个字节来表示一个整数。
                +7的反码为: 00000111
                 -7的反码为: 11111000
  • 补码
        利用溢出,我们可以将减法变成加法。
        对于十进制数,如果从9得到结果5,可以用减法:
             9-4=5
          因为4+6=10,我们将6作为4的补数,将上式的减法改写为加法:
             9+6=15
          去掉高位1(也就是减去10),得到结果5。
          对于16进制数,如果从C得到结果5,可以用减法:
             C-7=5
          因为7+9=16,我们将9作为7的补数,将上式的减法改写为加法:
             C+9=15
          去掉高位1(也就是减去16),得到结果5。
          在计算机中,如果我们用1个字节表示一个数,一个字节有8位,超过8位就进1,在内存中情况为:
               1 00000000
        进位1被丢弃。
        一个数如果为正,则它的原码、反码、补码相同;一个数如果为负,则符号位为1,其余各位是对原码取反,然后整个数加1。
                为了简单起见,我们用1个字节来表示一个整数。
                +7的补码为: 00000111
                -7的补码为:第一步:11111000 (符号位为,其余各位取反)
                                      第二步:11111001 (整个数加1)
               +0的补码:00000000;
               -0的补码:11111111;(第一步)
                              100000000;(第二步)
    已知一个负数的补码,将其转换为十进制数,步骤:
          1、先对各位取反;
          2、将其转换为十进制数;
          3、加上负号,再减去1。
          例如:
          11111010,最高位为1,是负数,先对各位取反得00000101,转换为十进制数得5,加上负号得-5,再减1得-6。
  •  

    那么我们就知道了1与-1的二进制形式分别为0000000 00000000 00000000 00000001和11111111 11111111 11111111 11111111(Java中的数据是以补码的形式储存的)了。那么现在我们知道了数据是如何储存的了。那么计算机是如何利用这些数据进行计算的呢?我们知道在计算机的CPU中只有一个加法器,所有的运算都是需要它进行的。所以在计算机里所有的加减乘除都是转换成加法来进行运算的。那么它们是怎么转换的呢?下面我们介绍一下二进制的运算操作

  • 位运算符
    为了方便对二进制位进行操作,Java给我们提供了四个二进制位操作符:
    &          按位与
    |           按位或
    ^          按位异或
    ~          按位取反
  • 按位
        一个房间里有两个开关控制房间的灯的明暗。当两个开关同时处于打开状态时,灯才能亮。
         开关1                   开关2                         灯的状态
           关                         关                              暗
          开                          关                              暗
          关                          开                              暗
          开                          开                              亮
    结论:按位与,只有壹(1)壹(1)为1。
  • 按位
        一个房间里有两个开关控制房间的灯的明暗。当任何一个开关处于打开状态时,灯就能亮。
        开关1                     开关2                     灯的状态
           关                         关                              暗
          开                          关                              亮
          关                          开                              亮
          开                          开                              亮
    结论:按位或,只有零(0)零(0)为0。
  • 按位异或
        一个房间里有两个开关控制房间的灯的明暗。当两个开关处于不同状态时,灯就能亮。
       开关1                    开关2                       灯的状态
          关                          关                              暗
          开                          关                              亮
          关                          开                              亮
          开                          开                              暗
    结论:按位异或,只有零(0)壹(1)或壹(1)零(0)为1。
  • 按位取反
    结论:对二进制数按位取反,即0变成1,1变成0。
  • Java中有三个移位运算符
    左移:<<              (相当于 乘以2)
    带符号右移:>>     (相当于 除以2)
    无符号右移:>>>
      数            x                   x<<2                 x>>2              x>>>2
    17      00010001    00 01000100      00000100 01     00000100 01
    -17     11101111     11 10111100      11111011 11     00111011 11
  • posted @ 2008-06-14 15:25 Stanley Sun 阅读(1065) | 评论 (0)编辑 收藏

    概念:

    1.数字摘要:解决在安全的通信环境下,保证信息的唯一的一种方式。通常使用MD5/SHA-1等算法完成摘要。一般比如大家在网上下载软件光盘时都会看到一个MD5值就是起到这个数字摘要的作用。在网络的环境中发送者把消息和数字摘要一同发送给接收者,接收者使用发送者相同的算法对消息加密,看是否与发送者发送过来的数字摘要相同,如果相同就证明消息没有给篡改过。下面是一个最为简单的示例:

    import java.security.*;
    public class myDigest {
      public static void main(String[] args)  {
        myDigest my=new myDigest();
        my.testDigest();
      }
      public void testDigest()
      {
       try {
         String myinfo="我的测试信息";
        //java.security.MessageDigest alg=java.security.MessageDigest.getInstance("MD5");
          java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");
          alga.update(myinfo.getBytes());
          byte[] digesta=alga.digest();
          System.out.println("本信息摘要是:"+byte2hex(digesta));
          //通过某中方式传给其他人你的信息(myinfo)和摘要(digesta) 对方可以判断是否更改或传输正常
          java.security.MessageDigest algb=java.security.MessageDigest.getInstance("SHA-1");
          algb.update(myinfo.getBytes());
          if (algb.isEqual(digesta,algb.digest())) {
             System.out.println("信息检查正常");
           }
           else
            {
              System.out.println("摘要不相同");
             }
       }
       catch (java.security.NoSuchAlgorithmException ex) {
         System.out.println("非法摘要算法");
       }
      }
      public String byte2hex(byte[] b) //二行制转字符串
        {
         String hs="";
         String stmp="";
         for (int n=0;n<b.length;n++)
          {
           stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
           if (stmp.length()==1) hs=hs+"0"+stmp;
           else hs=hs+stmp;
           if (n<b.length-1)  hs=hs+":";
          }
         return hs.toUpperCase();
        }
    }
    

    2.电子签名:对数据信息的发生者身份的认定,它是一种抽象的概念而不是一种具体技术。实现电子签名的技术手段目前有多种,比如基于公钥密码技术的数字签名;或用一个独一无二的以生物特征统计学为基础的识别标识,例如手印、声音印记或视网膜扫描的识别;手书签名和图章的电子图象的模式识别;表明身份的密码代号(对称算法);基于量子力学的计算机等等。


    3.数字签名:所谓数字签名就是利用通过某种密码运算生成的一系列符号及代码组成电子密码进行"签名",来代替书写签名或印章,对于这种电子式的签名在技术上还可进行算法验证,其验证的准确度是在物理世界中与手工签名和图章的验证是无法相比的。一般实现数字签名的方法是通过生成的密钥对的私钥对用户生成的数字消息进行DSA(Digital Signature Algorithm (DSA)是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard))加密实现的。实现代码如下:

       */
     import java.security.*;
     import java.security.spec.*;
    public class testdsa {
      public static void main(String[] args) throws java.security.NoSuchAlgorithmException,java.lang.Exception {
            testdsa my=new testdsa();
            my.run();
      }
      public void run()
      {
      //数字签名生成密钥
      //第一步生成密钥对,如果已经生成过,本过程就可以跳过,对用户来讲myprikey.dat要保存在本地
      //而mypubkey.dat给发布给其它用户
       if ((new java.io.File("myprikey.dat")).exists()==false) {
           if (generatekey()==false) {
               System.out.println("生成密钥对败");
               return;
              };
            }
    //第二步,此用户
    //从文件中读入私钥,对一个字符串进行签名后保存在一个文件(myinfo.dat)中
    //并且再把myinfo.dat发送出去
    //为了方便数字签名也放进了myifno.dat文件中,当然也可分别发送
      try {
      java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("myprikey.dat"));
      PrivateKey myprikey=(PrivateKey)in.readObject();
      in.close();
     // java.security.spec.X509EncodedKeySpec pubX509=new java.security.spec.X509EncodedKeySpec(bX509);
     //java.security.spec.X509EncodedKeySpec pubkeyEncode=java.security.spec.X509EncodedKeySpec
      String myinfo="这是我的信息";    //要签名的信息
      //用私钥对信息生成数字签名
      java.security.Signature signet=java.security.Signature.getInstance("DSA");
      signet.initSign(myprikey);
      signet.update(myinfo.getBytes());
      byte[] signed=signet.sign();  //对信息的数字签名
      System.out.println("signed(签名内容)="+byte2hex(signed));
     //把信息和数字签名保存在一个文件中
      java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myinfo.dat"));
      out.writeObject(myinfo);
      out.writeObject(signed);
      out.close();
      System.out.println("签名并生成文件成功");
      }
      catch (java.lang.Exception e) {
        e.printStackTrace();
        System.out.println("签名并生成文件失败");
      };
      //第三步
      //其他人通过公共方式得到此户的公钥和文件
      //其他人用此户的公钥,对文件进行检查,如果成功说明是此用户发布的信息.
      //
      try {
       java.io.ObjectInputStream in=new java.io.ObjectInputStream(new java.io.FileInputStream("mypubkey.dat"));
       PublicKey pubkey=(PublicKey)in.readObject();
       in.close();
       System.out.println(pubkey.getFormat());
       in=new java.io.ObjectInputStream(new java.io.FileInputStream("myinfo.dat"));
       String info=(String)in.readObject();
       byte[] signed=(byte[])in.readObject();
       in.close();
      java.security.Signature signetcheck=java.security.Signature.getInstance("DSA");
      signetcheck.initVerify(pubkey);
      signetcheck.update(info.getBytes());
      if (signetcheck.verify(signed)) {
      System.out.println("info="+info);
       System.out.println("签名正常");
      }
      else  System.out.println("非签名正常");
      }
      catch (java.lang.Exception e) {e.printStackTrace();};
      }
      //生成一对文件myprikey.dat和mypubkey.dat---私钥和公钥,
      //公钥要用户发送(文件,网络等方法)给其它用户,私钥保存在本地
      public boolean generatekey()
      {
        try {
      java.security.KeyPairGenerator  keygen=java.security.KeyPairGenerator.getInstance("DSA");
     // SecureRandom secrand=new SecureRandom();
     // secrand.setSeed("tttt".getBytes()); //初始化随机产生器
     // keygen.initialize(576,secrand);     //初始化密钥生成器
      keygen.initialize(512);
      KeyPair keys=keygen.genKeyPair();
    //  KeyPair keys=keygen.generateKeyPair(); //生成密钥组
      PublicKey pubkey=keys.getPublic();
      PrivateKey prikey=keys.getPrivate();
      java.io.ObjectOutputStream out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("myprikey.dat"));
      out.writeObject(prikey);
      out.close();
      System.out.println("写入对象 prikeys ok");
      out=new java.io.ObjectOutputStream(new java.io.FileOutputStream("mypubkey.dat"));
       out.writeObject(pubkey);
       out.close();
       System.out.println("写入对象 pubkeys ok");
       System.out.println("生成密钥对成功");
       return true;
      }
      catch (java.lang.Exception e) {
       e.printStackTrace();
       System.out.println("生成密钥对失败");
       return false;
       };
      }
      public String byte2hex(byte[] b)
        {
         String hs="";
         String stmp="";
         for (int n=0;n<b.length;n++)
          {
           stmp=(java.lang.Integer.toHexString(b[n] & 0XFF));
           if (stmp.length()==1) hs=hs+"0"+stmp;
           else hs=hs+stmp;
           if (n<b.length-1)  hs=hs+":";
          }
         return hs.toUpperCase();
        }
    }    把他的公钥的信息及签名发给其它用户
    


    4.PKI(公钥基础设施):

    posted @ 2007-12-05 22:09 Stanley Sun 阅读(533) | 评论 (1)编辑 收藏

    安装完成之后打开window->show views-Task Repositories,界面如下图:


    在空白处右键点击add task repository添加知识库,如图:

    选中Jira,下一步:


    server中填写Jira的地址(http://ycfd.3322.org:88/jira),label随便填写,User ID和Password就是你在Jira上注册的帐号和密码了,填写完毕之后点Validate Setting,验证成功之后点完成即可。

    在添加完repository后,会弹出添加query界面。如图:

    选择create query using form后点击next,进入query设置界面,如图:


    在project中选中fms后点击finish。这样就完成了各项设置
    之后打开tasklist视图:window->show view->other->mylyn->task list

    点击OK,后打开task list视图,如图:


    在Task List中你可以看到你的项目中的问题和任务等,双击Task会显示该Task的详细情况:

    在Task List中还能新建Task并提交到Jira,这里就不多说了,大家自己尝试一下。

    posted @ 2007-12-03 16:38 Stanley Sun 阅读(1350) | 评论 (0)编辑 收藏

    mylyn是一款开源的基于eclipse开发平台的任务管理组件,可以制定自己的本地任务及在远程服务器(其中包括Bugzilla、Trac 和 JIRA等)中的远程任务。对于我们现在的项目,使用mylyn就可以方便我们直接的浏览在JIRA中的任务,而不必经常的登录JIRA平台了。提高了大家的工作效率。

    由于mylyn与在我们现在在项目中使用的eclipse开发平台中springide插件有冲突问题,所以首先大家需要把springide插件从eclipse中卸载。步骤如下:

    1.在eclipse安装目录下找到一个名为links的文件夹,在这个文件夹中删除Springide.link文件。

    2.启动eclipse,不过与平常不同的是需要在eclipse启动命令中加入-clean参数。可以直接加入到eclipse快捷方式的目标项中。

    此时eclipse会把springide插件卸载,之后我们就可以安装mylyn插件了。在开始安装mylyn之前,大家需要下载附件中的如下三个文件:mylyn-2.1-e3.3.zip,mylyn-2.1-extras.zip,springide_updatesite_2.0.1_v200708152145.zip

    步骤如下:

    1.设置本地插件归档:进入help->software updates->find and install菜单后,选择search for new features to install后点击next

    进入install界面,如下图:


    把下载的三个zip归档加入后,点击finish.

    2.在弹出的updates窗口中选中刚才加入的三个归档,并把springide->integrations->spring ide ajdt integrations去掉后,如下图:

    之后进入授权界面,选择i accept后next,如图:

    3.在弹出的verification窗口中点击install all开始安装,如图:

    之后提示是否重启eclipse,点击是。

    posted @ 2007-12-03 16:38 Stanley Sun 阅读(5508) | 评论 (0)编辑 收藏

    EJBCA是一个全功能的CA系统软件,它基于J2EE技术,并提供了一个强大的、高性能并基于组件的CA。EJBCA兼具灵活性和平台独立性,能够独立使用,也能和任何J2EE应用程序集成。 

    所需软件:

    1.jdk 1.5 下载地址:http://java.sun.com/

    2.jboss-4.2.0.GA 下载地址:http://www.jboss.com/

    3.jce_policy-1_5_0:下载地址:http://java.sun.com/

    4.apache-ant-1.7.0:http://ant.apache.org/

    5.oracle 10G:

    6.ojdbc14.jar:

    7.ejbca 3.4.5: 下载地址:http://ejbca.sourceforge.net

    安装步骤:

    1.安装jdk,jboss,ant,oracle,并把jce,jdbc解压分别解压到%JAVA_HOME%\jre\lib\security\与%JBOSS_HOME%\server\default\lib\。

    2.设置环境变量,我的配置为:

    ANT_HOME=C:\tool\ejbca\apache-ant-1.7.0-bin\apache-ant-1.7.0
    EJBCA_HOME=C:\tool\ejbca\ejbca_3_5_2\ejbca_3_5_2
    JBOSS_HOME=C:\tool\ejbca\jboss-4.2.0.GA\jboss-4.2.0.GA
    JAVA_HOME=C:\Program Files\Java\jdk1.6.0_03
    path=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;C:\tool\ejbca\apache-ant-1.7.0-bin\apache-ant-1.7.0\bin;C:\tool\ejbca\jboss-
    4.2.0.GA\jboss-4.2.0.GA\bin;C:\Program Files\Java\jdk1.6.0_03\bin
    classpath=C:\Program Files\Java\jdk1.6.0_03\lib\tools.jar

    3.在数据库中创建表空间并添加用户EJBCA,在ORACLE中的代码为:

      创建表空间:

      CREATE TABLESPACE EJBCA DATAFILE 'EJBCA.dbf' SIZE 100m ;

      创建用户:

    CREATE user EJBCA   identified by "EJBCA"   default tablespace USERS   temporary tablespace TEMP   profile DEFAULT;
    -- Grant/Revoke role privileges
    grant aq_administrator_role to EJBCA with admin option;
    grant dba to EJBCA with admin option;
    -- Grant/Revoke system privileges
    grant unlimited tablespace to EJBCA with admin option;

    4.删除所有的ejbca\adminweb中的jsp(%EJBCA_HOME%\src\adminweb*.jsp)中的

    <%@ page pageEncoding="ISO-8859-1"%>

      以解决中文乱码问题,下一步也是解决此类问题。 

    5.把%EJBCA_HOME%\conf\ejbca.properties.sample改名为ejbca.properties,并在ejbca.properties添加如下一行:

    web.contentencoding=GBK

    6.把%EJBCA_HOME%\conf\database.properties.sample改名为database.properties,并更改相应的数据库配置。如下是我的配置:

    datasource.jndi-name=EjbcaDS
    datasource.jndi-name-prefix=java:/
    database.name=oracle
    datasource.mapping=Oracle9i
    database.url=jdbc:oracle:thin:@127.0.0.1:1521:ORCL
    database.driver=oracle.jdbc.driver.OracleDriver
    database.username=ejbca
    database.password=ejbca

      注:datasource.mapping需要选择与oracle实际版本最接近的版本。 

    7.在%EJBCA_HOME%\bin中,通过cmd运行ant bootstrap。

    8.启动jboss,在%JBOSS_HOME%\bin,通过cmd运行run。

    9.在%EJBCA_HOME%\bin中,通过cmd运行ant install。

    10.关闭jboss,并在在%EJBCA_HOME%\bin中,通过cmd运行ant deploy。

    11.再次启动jboss,在%JBOSS_HOME%\bin,通过cmd运行run。

    13.导入在%EJBCA_HOME%\p12目录中superadmin.p12,默认密码为ejbca。

    注:在第7步时,如出现ANT失败,可能是由于ejbca的版本问题,推荐使用ejbca3.4.5。

    访问地址:http://localhost:8080/ejbca/

    posted @ 2007-12-03 16:33 Stanley Sun 阅读(1607) | 评论 (0)编辑 收藏

    一般在有着1年半以上的程序员基本上都是知道这个厉害的东西的,它对字符串处理的能力可以说是生猛无比。虽然大家都在使用(有时候在开发的Code中,有时候是在我们自己心爱的Editor里),但是我相信大部分人对这里禽兽的了解程度只是停留在会用的层次上。下面我对它进行一下详细的说明。

    正则表达式的“祖先”可以一直上溯至对人类神经系统如何工作的早期研究。Warren McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述这些神经网络。

    1956 年, 一位叫 Stephen Kleene 的美国数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题为“神经网事件的表示法”的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为“正则集的代数”的表达式,因此采用“正则表达式”这个术语。

    随后,发现可以将这一工作应用于使用Ken Thompson 的计算搜索算法的一些早期研究,Ken Thompson是Unix 的主要发明人。正则表达式的第一个实用应用程序就是 Unix 中的qed 编辑器。

    如他们所说,剩下的就是众所周知的历史了。从那时起直至现在正则表达式都是基于文本的编辑器和搜索工具中的一个重要部分。

    使用正则表达式
    在典型的搜索和替换操作中,必须提供要查找的确切文字。这种技术对于静态文本中的简单搜索和替换任务可能足够了,但是由于它缺乏灵活性,因此在搜索动态文本时就有困难了,甚至是不可能的。

    使用正则表达式,就可以:

    测试字符串的某个模式。例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式。这称为数据有效性验证。
    替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后可以全部将其删除,或者替换为别的文字。
    根据模式匹配从字符串中提取一个子字符串。可以用来在文本或输入字段中查找特定文字。
    例如,如果需要搜索整个 web 站点来删除某些过时的材料并替换某些HTML 格式化标记,则可以使用正则表达式对每个文件进行测试,看在该文件中是否存在所要查找的材料或 HTML 格式化标记。用这个方法,就可以将受影响的文件范围缩小到包含要删除或更改的材料的那些文件。然后可以使用正则表达式来删除过时的材料,最后,可以再次使用正则表达式来查找并替换那些需要替换的标记。

    许多种工具都支持正则表达式(文本编辑器、文字处理软件、系统工具、数据库引擎,等等),不过,要想充分挖掘正则表达式的能力,还是应当将它作为编程语言的一部分。例如Java、JScript、Visual Basic、VBScript、JavaScript、ECMAScript、C、C++、C#、elisp、Perl、Python、Tcl、Ruby、PHP、sed和awk。事实上,在一些用上述语言编写的程序中,正则表达式扮演了极其重要的角色。
    正则表达式能够得到众多语言和工具的支持是有原因的:它们极其有用。从较低的层面上来说,正则表达式描述的是一串文本(a chunk of text)的特征。大家可以用它来验证用户输入的数据,或者也可以用它来检索大量的文本。从较高的层面上来说,正则表达式容许用户掌控他们自己的数据——控制这些数据,让它们为自己服务。掌握正则表达式,就是掌握自己的数据。

    可见它的重要性,难怪每款编辑器和编程语言不同程度的实现了它,使得普通用户和开发人员受益不浅。

    posted @ 2007-11-07 23:02 Stanley Sun 阅读(423) | 评论 (1)编辑 收藏

     

    treeview 

    在开发B/S程序时,我们经常会使用到一些页面级的效果控件。比如:树形目录,ComboBox和一些其他的控件,由于这些控件的存在使得我们的程序异常的夺目。但是在开发这些控件的时候或多或少的都会比较麻烦。而大部分的程序员是使用发布的一些开源的JS控件来减轻工作量而且也使得自己的程序健壮。下面我介绍一个在开源社区中赫赫有名的树形控件:TreeView。

    首先介绍一下TreeView,TreeView原名是FolderTree,是一款比较早就出世的树形JS控件,当时是由个人开发的,之后由公司购买了。但是现在还可以免费使用。

    TreeView 有两个JS文件和一些资源文件组成。两个JS文件分别是:主要实现功能的ftiens4.js和实现多浏览器支持的ua.js文件。只有我们在开发的页面中加入如上两个文件的话就可以开发如上图所显示的树形目录了。代码如下:

    <html>

    <head>

    <script type="text/javascript" src="../treeview/ftiens4.js" ></script>

    <script type="text/javascript" src="../treeview/ua.js" ></script>

    <script type="text/javascript">

    //TreeView 环境变量

    BUILDALL = 0 //创建所有的节点对象 0:延时创建 1:立即创建
    GLOBALTARGET = 'R' //节点触发时的目标 'B':打开新窗口 'R':右边的Frame 'S':当前Frame 'T':当前浏览器窗口
    HIGHLIGHT = 0 //高亮显示当前选中的节点 0:不高亮显示 1:高亮显示
    HIGHLIGHT_BG = 'blue' //高亮显示的背景颜色
    HIGHLIGHT_COLOR = 'white' //高亮显示的颜色
    ICONPATH = '' //指定节点的显示图标,使用URL方式,而且必须用"/"结尾 如:http://www.x.com/y/
    PRESERVESTATE = 0 //保存TreeView的状态到Cookie中,当再次显示的时候会自动的回置状态 0:不保存 1:保存
    STARTALLOPEN = 0 //默认打开所有节点 0:只打开根节点 1:打开所以节点
    USEFRAMES = 1 //页面是否使用了Frame,注意:如果未使用Frame一定要设置此参数 0:未使用 1:使用了
    USEICONS = 1 //是否使用图标 0:不显示图标 1:显示图标
    USETEXTLINKS = 0 //节点文字是否为链接 0:否 1:是
    WRAPTEXT = 0 //节点显示超出一行时是否折行 0:不折行 1:折行

    foldersTree = gFld("test", "") //创建一个名为"test"的根节点
    foldersTree.treeID = "t1" //设置test节点的唯一编号为"t1"


    aux1 = insFld(foldersTree, gFld("Day of the week", "b.html")) //在根节点中加入一个名为"Day of the week"的子节点,当点击的时候打开b.html
    aux1.addChildren([["1","1.html"],["2","2.html"],["3","3.html"],["4","4.html"],["5","5.html"]])  //在aux1节点中连续加入1,2,3,4,5节点,并相应的打开1.html,2.html,3.html,4.html,5.html.

    aux2 = insFld(foldersTree, gLnk("R","Day of the week2", "b.html")) //在根节点中加入名为"Day of the week2"的节点,当点击的时候在右侧的frame中打开b.html
    aux3 = insDoc(foldersTree, gLnk("R","<input type=\"checkbox\">Day of the week3", "c.html")) //在根节点中加入名为"Day of the week3"并带有复选框的节点,当点击的时候在右侧的frame中打开c.html

    </script>

    </head>

    <body>

    <A style="font-size:7pt;text-decoration:none;color:silver" href="http://www.treemenu.net/" target=_blank>Javascript Tree Menu</A>

    <script type="text/javascript">

           initializeDocument();//构造TreeView

    </script>

    </body>

    </html>

    TreeView中主要的方法:

    gFld(Title, Link);//创建节点 例:gFld("Test A", "javascript:parent.op()")

    Argument

    Title
    Specifies the text that appears in the folder name. This text can include simple HTML tags, such as enclosing formatting tags (i, b, div, and so on). It can even include an img tag if you want to place a small icon in the node name, such as a "new!" icon for example.

    Link
    Specifies an optional URL. The URL can be a simple file name like demoFramesetRightFrame.html or a string with protocol, domain, path, and file name like http://www.treeview.net/treemenu/demopics/beenthere_europe.gif.

     

    gLnk(Target, Title, Link);//创建一个带有链接的节点 例:gLnk("B", "My File", http://www.mysite.com/MyFile.doc)

    Argument

    Target
    Configures the target location for the link. Specify one of the following values:
    "R": Open the document in the right frame (a frame named basefrm)
    "B": Open the document in a new window
    "T": Open the document in the current browser window, replacing the frameset if one exists
    "S": Open the document in the current frame, replacing the tree
    Note: This argument is case sensitive; make sure to use uppercase letters.

    Title
    Specifies the text that appears in the link. This text can include simple HTML tags, such as enclosing formatting tags (i, b, div, and so on). It can even include an img tag if you want to place a small icon in the node name, such as a "new!" icon for example.

    Link
    Specifies the URL of the document. This can be an absolute URL or a relative URL. Do not enter any other information in this string; adding a target parameter or an event handler will not work.

     

    insFld(Parent Folder, Child Folder); //在父节点中插入一个子节点 例:aux1 = insFld(foldersTree, gFld("Europe", "http..."))

    Argument

    Parent Folder
    Specifies the parent folder. That is, this argument specifies the folder node in which you want to place the other folder node.

    Child Folder
    Specifies the child folder. That is, this argument specifies the folder node that you want to place under the parent folder node.

     

    insDoc(Parent Folder, Document Node); //在节点中加入一个Dom对象 例:insDoc(aux2, gLnk("S", "Boston", "..."))

    Argument

    Parent Folder
    Specifies the parent folder. That is, this argument specifies the folder node in which you want to place the document node.

    Document Node
    Specifies the document node. That is, this argument specifies the document node that you want to place in the parent folder node

     

    更多的参考信息到 http://www.treeview.net/tv/instructions.asp

    posted @ 2007-11-07 17:59 Stanley Sun 阅读(7500) | 评论 (2)编辑 收藏

        在一年以前一个客户给我推荐一款文件管理软件,名叫Total Commander,以下简称totalcmd,据说在欧美国家相当的流行。当时给这个客户开发程序是需要打开很多个资源管理器,在这么多的管理器中相互的拷贝文件真是一件非常头疼的事情。借助totalcmd可以非常好的完成文件的管理,拷贝、删除,新建,乃至服务的管理等等。值得一提的就是totalcmd可以通过注入插件实现totalcmd本身不可以完成的功能,这也是它很大的一个亮点。

    在使用的一年多的totalcmd后,也有了一些自己的使用习惯和独爱的插件,我将罗列如下:
    使用习惯:
    1.把F2快捷键指定到cm_RenameOnly命令上。
    2.把Ctrl+G快捷键指定到cm_FocusCmdLine命令上。
    3.在开始菜单下建立一个功能,实现cm_SwitchHidSys功能,可以显示隐藏/系统文件。
    4.指定totalcmd只能运行一个实例。
    5.最小化到系统托盘里。
    6.编辑时默认打开的编辑器为ChoiceEditor。这个插件很难找。
    7.把快速查找定义为Letters with search dialog
    8.当改变驱动盘符的时候直接定位的驱动的根目录下

    独爱插件:
    1.Choice Editor:默认编辑选择器。
    2.File Redirector:临时目录,这个插件非常有用,强烈推荐。不过安装的时候需要下载一个msvcr70.dll的文件放到你的c:\windows\system32目录下。文件的下载地址:http://www.dll-files.com/dllindex/dll-files.shtml?msvcr70
    3.UnInstTC:集成在totalcmd中添加/删除程序,支持搜索。
    4.Office:可以通过Ctrl+Q快速查看Office系列软件格式。

    注:本人只是一个totalcmd的爱好者,而不是在此为他去大广告。

    posted @ 2007-10-31 11:07 Stanley Sun 阅读(660) | 评论 (0)编辑 收藏

     



            AutoSuggest是通过AJAX技术实现的一种类似于ComboBox之类的输入框,当输入一些提示字符后,AS会自动的把输入框中的Value通过AJAX发送到Server中,Server自定义的解析发送的数据,然后把返回数据通过XMLJSON方式返回到AS中。AS再根据Server返回的标准格式的数据构建出提示候选框,当用鼠标或键盘选中候选项后填充到输入框中。在写这篇手册的时候,AutoSuggest的最新版本是autosuggest_v2.1.3。基本的运行原理如上。

    AutoSuggest的主要的物理文件有:bsn.AutoSuggest_2.1.3.jsautosuggest_inquisitor.css。其他的还有一些图片资源文件,一个测试html与一个test.php的服务器段页面。结构如下:
        

    │ .DS_Store

    │ ._.DS_Store

    │ ._bsn.AutoSuggest_2.
    1.3.html

    │ ._test.php

    │ bsn.AutoSuggest_2.
    1.3.html

    │ test.php



    ├─css

    │ │ .DS_Store

    │ │ ._.DS_Store

    │ │ autosuggest_inquisitor.css

    │ │

    │ └─img_inquisitor

    │      │ .DS_Store

    │      │ ._.DS_Store

    │      │ ._as_pointer.gif

    │      │ ._hl_corner_bl.gif

    │      │ ._hl_corner_br.gif

    │      │ ._hl_corner_tl.gif

    │      │ ._hl_corner_tr.gif

    │      │ ._ul_corner_bl.gif

    │      │ ._ul_corner_br.gif

    │      │ ._ul_corner_tl.gif

    │      │ ._ul_corner_tr.gif

    │      │ as_pointer.gif

    │      │ hl_corner_bl.gif

    │      │ hl_corner_br.gif

    │      │ hl_corner_tl.gif

    │      │ hl_corner_tr.gif

    │      │ ul_corner_bl.gif

    │      │ ul_corner_br.gif

    │      │ ul_corner_tl.gif

    │      │ ul_corner_tr.gif

    │      │

    │      └─_source

    │              .DS_Store

    │              ._.DS_Store

    │              ._as_pointer.png

    │              ._li_corner.png

    │              ._ul_corner.png

    │              as_pointer.png

    │              li_corner.png

    │              ul_corner.png



    └─js

           .DS_Store

           ._.DS_Store

           ._bsn.AutoSuggest_2.
    1.3.js

           bsn.AutoSuggest_2.
    1.3.js

           bsn.AutoSuggest_2.
    1.3_comp.js


    AutoSuggest是一组JavaScript类库,其中主要的对象就是bsn.AutoSggest对象,基本的功能都是在这个对象中完成的。首先我们构建一个简单的示例:
        

    var options_xml = {

                                    script:
    function(input){return"suggestAction!userName.action?signer="+input; }//(1).带有传送数据的请求路径,其中input是输入框的value。

                                    varname:
    "input"//(2).储存输入框value的变量名

                                    delay:
    800//(3).发送请求的延时时间

                                    cache:
    false//(4).是否缓存

                                    noresults:
    "无符合的记录!",//(5).当没有符合的查询结果时的提示信息

                                    timeout:
    10000,//(6).候选框停留时间

                                    callback: 
    function(record){ document.getElementById("temp").value = record.value; } //(7).选择候选项后的回调函数

    }
    ;

    var as_xml = new bsn.AutoSuggest('signer', options_xml); //(8).创建autosuggest对象,并绑定一个输入框




    通过这样简单的方式我们就可以完成在页面中的autosuggest编码了。其中的参数表可以看下表:

    Property

    Type

    Default

    Description

    script

    String / Function

    -

    REQUIRED!
    Either: A string containing the path to the script that returns the results in XML format. (eg, "myscript.php?")
    Or: A function that accepts on attribute, the autosuggest field input as a string, and returns the path to the result script.

    varname

    String

    "input"

    Name of variable passed to script holding current input.

    minchars

    Integer

    1

    Length of input required before AutoSuggest is triggered.

    className

    String

    "autosuggest"

    Value of the class name attribute added to the generated ul.

    delay

    Integer

    500

    Number of milliseconds before an AutoSuggest AJAX request is fired.

    timeout

    Integer

    2500

    Number of milliseconds before an AutoSuggest list closes itself.

    cache

    Boolean

    true

    Whether or not a results list should be cached during typing.

    offsety

    Integer

    -5

    Vertical pixel offset from the text field.

    shownoresults

    Boolean

    true

    Whether to display a message when no results are returned.

    noresults

    String

    No results!

    No results message.

    callback

    Function

    A function taking one argument: an object

    {id:"1", value:"Foobar", info:"Cheshire"}

    json

    Boolean

    false

    Whether or not a results are returned in JSON format. If not, script assumes results are in XML.

    maxentries

    Integer

    25

    The maximum number of entries being returned by the script. (Should correspond to the LIMIT clause in the SQL query.)

    之后我们只要在我的服务器中解析传入的signer参数返回,如下格式的xml就可以了。当然也可以用JSON方式,不过我在这里就不在演示了。
        

    <results>

                                    
    <rs id="1" info="">Foobar</rs>

                                    
    <rs id="2" info="">Foobarfly</rs>

                                    
    <rs id="3" info="">Foobarnacle</rs>

    </results>


    AutoSuggest是比较方便的一种实现类Google Suggest的解决方式,提供的js文件也是比较精巧的,并提供的一个压缩后的js脚本文件只有8.33 KB大小。如果要查看其代码可以找到一个没有压缩的原始版本的源代码,其中的代码也是比较容易阅读,更改起来也是比较简单的。我会在以后写一篇《AutoSuggest代码解析》。

    更多信息可查阅 http://www.brandspankingnew.net/archive/2007/02/ajax_auto_suggest_v2.html

    posted @ 2007-10-19 18:17 Stanley Sun 阅读(2525) | 评论 (2)编辑 收藏

    在一般的项目中,数据库主键不会拥有业务逻辑。但是在一些数据库设计不是很严格的项目中还是会把拥护业务逻辑的字段作为主键使用,而且可能回事复合主键。 现在在一个项目我就遇到这情况。这个项目的数据访问框架使用的Hibernate框架,在对复合主键的映射是我遇到了一个Hibernate Bug。我使用的数据库是Oracle 8i。Hibernate Mapping如下:

    <composite-id name="id" class="InfoViewDetaillistId">

               <key-property

                  name="accountno"

                  column="ACCOUNTNO"

                  type="string"

               />

               <key-property

                  name="rlsdepid"

                  column="RLSDEPID"

                  type="string"

               />

               <key-property

                  name="sequenceno"

                  column="SEQUENCENO"

                  type="integer"

               />

               <key-property

                  name="ondate"

                  column="ONDATE"

                  type="date"

               />

    </composite-id>

    在这个复合主键中包括了四个拥有业务逻辑的字段,分别是帐号,中心号,序号,日期。问题就在Hibernate对日期类型的映射上,如使用上面的配置方法的话Hibernate在启动的时候就会报错。具体的解决方法是把
    <key-property

    name="ondate"

    column="ONDATE"

    type="date"

    />

    替换成

    <key-property name="ondate" type="date">

    <column name="ONDATE" not-null="true" sql-type="java.sql.Types.DATE"/>

    </key-property>

    Bug具体的原因我会在一会的文章中解释。

    posted @ 2007-10-09 12:57 Stanley Sun 阅读(309) | 评论 (0)编辑 收藏

    十月放假期间早晨本应该在家里舒服的床上呼呼大睡,十月中旬一个项目就要上线,无奈老板让所有的员工加班,自己却跑到埃及去度假。十一期间的交通果然是出奇的好,马路上零星点点的几个人头,公交车上一大片一大片的空位子。本应该用两个多小时路程却用了不到一个半小时就到了公司,到了公司连在这里住的的小伙还没有起床。
    无聊的打开笔记本,听听音乐,上上网,出奇的悠哉。呵呵,在哪里是在加班啊。跑到tss网站上看看(本人的英语不是很好,天天强迫自己看看英文网站来提高英文水平),无意中发现TSS里有一个地方是专门通过卡通的形式来演绎程序员生活中遇到的趣事。如果你身边有什么有趣的事情的话,还可以投稿给他们。

    posted @ 2007-10-04 09:27 Stanley Sun 阅读(177) | 评论 (0)编辑 收藏

    记忆里Java5发布离现在已经有了两三年了,虽然有不少的贴心的新特性。但是一直无法撼动J2SE 1.4在Java程序员心中的位置。在Java5发布的时候我也看过一些关于新特性的介绍,泛型、枚举、注释、foreach等。当时个人感觉其实除了foreach还算有点吸引眼球,其他的特性只是一种过度功能。对于泛型只是在Java编译器中做的手脚,而在JVM中是不支持的,有点想一个文字游戏。对于枚举,由于本人对这样的功能接触不多,所以就不妄加评价了。注释出现的目的主要是消除XML灾难,但是有无法达到XML不更改Class就可以改变配置。就是凭借的这些想法本人直到Java5发布后的两三年一直就没有碰过它,但是在最近的一个新项目中Java5新特性随处可见,我与其他的Programmer交流了一下发现现在这些新特性同样出现在他们的项目中。

    何解?难道大家已经不在乎使用的是一个空中楼阁式的特性,只要能够圆满的完成项目?可能Java5新特性有着我看不到的优点。

    posted @ 2007-09-26 22:16 Stanley Sun 阅读(191) | 评论 (0)编辑 收藏

    对于有本一族的现代人来说,本本为我们的工作提供了很大的方便,但是一般家中还是会用一台台式电脑为我们服务(更加倾向于服务器的作用)。那么如何方便的链接笔记本和家中的台式机一起上网呢。有的使用路由器的方式,这种方式固然高效但是对于家中没有路由的朋友来说就比较郁闷了。这里我介绍一种通过普通网线来对连两台电脑上网的方法。


    设备:

    1.准备一根于普通网线差不多的双机互连线,它不同的只是水晶头接口的排序方法不同,其他的材料都是一样的。

    2.需要有一台双网卡的台式电脑,我家里的磐正的8RDA3+主板,集成的双网卡。非常爽。

    方法:

    1. 把台式电脑的IP更改为192.168.0.1,这样当笔记本接入的时候,会默认的通过这个IP,去获取笔记本的IP。

    2. 把台式电脑的ADSL链接共享,连接的通道选择双机互连线接入的网卡。点击ADSL连接-->高级-->Internet连接共享中设置。

    3. 可能需要重启一下电脑。此时不用设置笔记本的IP地址,一般使用自动获取就行了。如果自己想设置可以把IP设置成192.168.0.*,网关为192.168.0.1,Dns服务器为192.168.0.1.

    注意:如果笔记本于台式电脑的IP不是一个网段的话,则无法共享上网。

    现在一切就设置好了,在台式电脑上打开ADSL连接后,笔记本就可以一起上网了,是不是非常方便。。。

    posted @ 2007-09-25 20:48 Stanley Sun 阅读(1170) | 评论 (0)编辑 收藏

    1 背景假设

    厦门央瞬公司是一家电子元器件设备供应商,其中有个ARM部门,专门负责ARM芯片的方案设计、销售,并在北京、上海各设立了一个办事处。对于工作日志,原先采用邮件方式发给经理,但是这种方式有个缺点,那就是不具备连续性,要看以前的日志必须一封一封邮件去查看,很麻烦。于是就想到利用 Subversion,让员工在自己电脑上编辑日志,然后利用svn传送回来,既方便员工自己编写日志,又方便对日志的归档处理,而且提交日志的时候只需要执行一下 svn update 即可,比发送邮件还要简单的多。

    • svn服务器相关信息

      • 服务器地址: 192.168.0.1
      • 服务器OS: MS Windows 2000 Server Edition 中文版
      • 代码库本地目录: D:\svn\arm
    • arm部门文档的目录结构如下:

      arm                 部门名称
      ├─diary           工作日志目录
      │  ├─headquarters    总部工作日志目录
      │  ├─beijing         北京办日志目录
      │  └─shanghai        上海办日志目录
      ├─ref             公司公共文件参考目录
      └─temp            临时文件目录
      
    • 人员情况

      • morson,公司总经理,其实他不必亲自看任何东西,就连部门经理们的每周总结都不一定看。但是为了表示对他的尊敬,以及满足一下他的权力欲,还是给他开放了"阅读所有文档"的权限
      • michael,arm事业部的部门经理,没事的时候喜欢弄点儿新技术,用svn来管理日志,就是他相处来的主意
      • scofield,北京办人员,老员工,为人油滑难管
      • lincon,上海办人员,老员工,大老实人一个
      • linda,总部协调员、秘书,文笔不错,长得也不错
      • rory,单片机技术员,技术支持
    • 访问权限需求分析

      • 允许总经理读取所有文件
      • 除部门经理外,所有其他人员,均只能看到本办事处人员工作日志
      • 不允许匿名访问
      • ref目录只允许经理和秘书写,对其他人只读
      • temp目录人人都可以写

    2 建立代码库

    在服务器 D:\svn 目录下,建立 arm 代码库,命令如下:

    D:\svn>svnadmin create arm
    

    在客户机 F:\temp 目录下,建立好上述目录结构

    用命令 F:\temp>svnimportarmsvn://192.168.0.1/arm 导入结构

    【注意点:关于导入时候的细微差别】

    3 编辑代码库基础配置文件

    编辑代码库 arm\conf\svnserve.conf 文件,如下:

    [general]
    password-db = passwd.conf
    anon-access = none
    auth-access = write
    authz-db = authz.conf
    

    4 管理用户帐号

    新建代码库 arm\conf\passwd.conf 文件,如下:

    [users]
    morson = ShowMeTheMoney
    michael = mysecretpassword
    scofield = hellolittilekiller
    lincon = asyouknows111
    rory = 8809117
    linda = IlikeWorldCup2006
    

    5 建立目录访问权限控制文件

    新建代码库 arm\conf\authz.conf 文件,内容如下:

    [groups]
    g_vip = morson
    g_manager = michael
    g_beijing = scofield
    g_shanghai = lincon
    g_headquarters = rory, linda
    g_docs = linda
    [arm:/]
    @g_manager = rw
    * = r
    [arm:/diary/headquarters]
    @g_manager = rw
    @g_headquarters = rw
    @g_vip = r
    * =
    [arm:/diary/beijing]
    @g_manager = rw
    @g_beijing = rw
    @g_vip = r
    * =
    [arm:/diary/shanghai]
    @g_manager = rw
    @g_shanghai = rw
    @g_vip = r
    * =
    [arm:/ref]
    @g_manager = rw
    @g_docs = rw
    * = r
    [arm:/temp]
    * = rw
    

    6 测试

    在服务器上,打开一个 DOS Prompt 窗口,输入如下指令:

    svn co svn://127.0.0.1/arm --no-auth-cache --username rory --password 8809117
    

    我们应该得到如下目录结构:

    arm
    ├─diary
    │  └─headquarters
    ├─ref
    └─temp
    

    然后修改ref目录下任意文件并提交,服务器将会报错"Access deni"

    深入

    本章将详细介绍前一章所涉及的两个配置文件, svnserve.conf 和 authz.conf,通过对配置逐行的描述,来阐明其中的一些细节含义。

    这里首先要注意一点,任何配置文件的有效配置行,都不允许存在前置空格,否则程序会无法识别。也就是说,如果你直接从本文的纯文本格式中拷贝了相关的配置行过去,需要手动将前置的4个空格全部删除。当然了,如果你觉得一下子要删除好多行的同样数目的前置空格是一件苦差使,那么也许 UltraEdit 的"Column Mode"编辑模式,可以给你很大帮助呢。

    1 svnserve.conf

    arm\conf\svnserve.conf 文件,是 svnserve.exe 这个服务器进程的配置文件,我们逐行解释如下。

    首先,我们告诉 svnserve.exe,用户名与密码放在 passwd.conf 文件下。当然,你可以改成任意的有效文件名,比如默认的就是 passwd:

    password-db = passwd.conf
    

    接下来这两行的意思,是说只允许经过验证的用户,方可访问代码库。那么哪些是"经过验证的"用户呢?噢,当然,就是前面说那些在 passwd.conf 文件里面持有用户名密码的家伙。这两行的等号后面,目前只允许 read write none 三种值,你如果想实现一些特殊的值,比如说"read-once"之类的,建议你自己动手改源代码,反正它也是自由软件:

    anon-access = none
    auth-access = write
    

    接下来就是最关键的一句呢,它告诉 svnserve.exe,项目目录访问权限的相关配置是放在 authz.conf 文件里:

    authz-db = authz.conf
    

    当然,svn 1.3.2 引入本功能的时候,系统默认使用 authz 而不是 authz.conf 作为配置文件。不过由于鄙人是处女座的,有着强烈的完美主义情结,看着 svnserve.conf 有后缀而 passwd 和 authz 没有就是不爽,硬是要改了。

    2 authz.conf 之用户分组

    arm\conf\authz.conf 文件的配置段,可以分为两类,``[group]`` 是一类,里面放置着所有用户分组信息。其余以 [arm:/] 开头的是另外一类,每一段就是对应着项目的一个目录,其目录相关权限,就在此段内设置。

    首先,我们将人员分组管理,以便以后由于人员变动而需要重新设置权限时候,尽量少改动东西。我们一共设置了5个用户分组,分组名称统一采用 g_ 前缀,以方便识别。当然了,分组成员之间采用逗号隔开:

    [groups]
    # 任何想要查看所有文档的非本部门人士
    g_vip = morson
    # 经理
    g_manager = michael
    # 北京办人员
    g_beijing = scofield
    # 上海办人员
    g_shanghai = lincon
    # 总部一般员工
    g_headquarters = rory, linda
    # 小秘,撰写文档
    g_docs = linda
    

    注意到没有, linda 这个帐号同时存在"总部"和"文档员"两个分组里面,这可不是我老眼昏花写错了,是因为 svnserve.exe 允许我这样设置。它意味着,这个家伙所拥有的权限,将会比他的同事 rory 要多一些,这样的确很方便。具体多了哪些呢?请往下看!

    3 authz.conf 之项目根目录

    接着,我们对项目根目录做了限制,该目录只允许arm事业部的经理才能修改,其他人都只能眼巴巴的看着:

    [arm:/]
    @g_manager = rw
    * = r
    
    • [arm:/] 表示这个目录结构的相对根节点,或者说是 arm 项目的根目录
    • 这里的 @ 表示接下来的是一个组名,不是用户名。你当然也可以将 @g_manager=rw 这一行替换成 michael=rw ,而表达的意义完全一样。
    • * 表示"除了上面提到的那些人之外的其余所有人",也就是"除了部门经理外的其他所有人",当然也包括总经理那个怪老头
    • * = r 则表示"那些人只能读,不能写"

    4 authz.conf 之项目子目录

    然后,我们要给总部人员开放日志目录的读写权限:

    [arm:/diary/headquarters]
    @g_manager = rw
    @g_headquarters = rw
    @g_vip = r
    * =
    
    • 我敢打赌,设计svn的家伙们,大部分都是在 unix/linux 平台下工作,所以他们总喜欢使用 / 来标识子目录,而完全忽视在 MS Windows 下是用 \ 来做同样的事情。所以这儿,为了表示 arm\diary\headquarters 这个目录,我们必须使用 [arm:/diary/headquarters] 这样的格式。
    • 这里最后一行的 *= 表示,除了经理、总部人员、特别人士之外,任何人都被禁止访问本目录。这一行是否可以省略呢?
    • 之所以这儿需要将 @g_vip=r 一句加上,就是因为存在上述这个解释。如果说你没有明确地给总经理授予读的权力,则他会和其他人一样,被 * 给排除在外。
    • 如果众位看官中间,有谁玩过防火墙配置的话,可能会感觉上述的配置很熟悉。不过这里有一点与防火墙配置不一样,那就是各个配置行之间,没有 先后顺序 一说。也就是说,如果我将本段配置的 *= 这一行挪到最前面,完全不影响整个配置的最终效果。
    • 请注意这儿,我们并没有给 arm\diary 目录设置权限,就直接跳到其子目录下进行设置了。我当然是故意这样的,因为我想在这儿引入"继承"的概念。
    • 权限具备继承性 任何子目录,均可继承其父目录的所有权限,除非它自己被明确设置了其他的权限。也就是说,在 arm 目录设置权限后, arm\diary 目录没有进行设置,就意味着它的权限与 arm 目录一样,都是只有经理才有权读写,其他人只能干瞪眼。
    • 【 * = 是否可以省略】【用例子引入覆盖】【单用户权限的继承问题】【父目录权限集成与全面覆盖问题】

    现在来看看

    好了,我们现在掌握了"继承"的威力,它让我们节省了不少敲键盘的时间。可是现在又有一个问题了,

    属性具备覆盖性质子目录若设置了属性,则完全覆盖父目录。

    5 authz.conf 的其他注意点

    1. 父目录的 r 权限,对子目录 w 权限的影响

    把这个问题专门提出来,是因为在1.3.1及其以前的版本里面,有个bug,即为了子目录的写权限,项目首目录必须具备读权限。因此现在使用了1.3.2版本,就方便了那些想在一个代码库存放多个相互独立的项目的管理员,来分配权限了。比如说央舜公司建立一个大的代码库用于存放所有员工日志,叫做 diary,而arm事业部只是其中一个部门,则可以这样做:

    [diary:/]
    @g_chief_manager = rw
    [diary:/arm]
    @g_arm_manager = rw
    @g_arm = r
    

    这样,对于所有arm事业部的人员来说,就可以将 svn://192.168.0.1/diary/arm 这个URL当作根目录来进行日常操作,而完全不管它其实只是一个子目录,并且当有少数好奇心比较强的人想试着 checkout 一下 svn://192.168.0.1/diary 的时候,马上就会得到一个警告"Access deni",哇,太酷了。

    1. 默认权限

    如果说我对某个目录不设置任何权限,会怎样?马上动手做个试验,将:

    [diary:/]
    @g_chief_manager = rw
    

    改成:

    [diary:/]
    # @g_chief_manager = rw
    

    这样就相当于什么都没有设置。在我的 svn 1.3.2 版本上,此时是禁止任何访问。也就是说,如果你想要让某人访问某目录,你一定要显式指明这一点。这个策略,看起来与防火墙的策略是一致的。

    1. 只读权限带来的一个小副作用

    若设置了:

    [arm:/diary]
    * = r
    

    则svnserve认为,任何人,都不允许改动diary目录,包括删除和改名,和新增。

    也就是说,如果你在项目初期创建目录时候,一不小心写错目录名称,比如因拼写错误写成 dairy,以后除非你改动 authz.conf 里面的这行设置,否则无法利用 svn mv 命令将错误的目录更正。

    改进

    1 对中文目录的支持

    上午上班的时候,Morson 来到 Michael 的桌子前面,说道:"你是否可以将我们的北京办、上海办目录,改成用中文的,看着那些拼音我觉得很难受?" Michael 心想,还好这两天刚了解了一些与 unicode 编码相关的知识,于是微笑地回答:"当然可以,你明天下午就可以看到中文目录名称了。"

    1. 使用 svn mv 指令,将原来的一些目录改名并 commit 入代码库,改名后的目录结构如下:

      arm
      ├─工作日志
      │  ├─总部人员
      │  ├─北京办
      │  └─上海办
      ├─公司公共文件参考目录
      └─临时文件存放处
      
    2. 修改代码库的 authz.conf 文件,将相应目录逐一改名

    3. 使用 UltraEdit 将 authz.conf 文件转换成不带 BOM 的 UTF-8 格式

      将配置文件转换成 UTF-8 格式之后,Subversion 就能够正确识别中文字符了。但是这里需要注意一点,即必须保证 UTF-8 文件不包含 BOM 。BOM 是 Byte Order Mark 的缩写,指 UNICODE 文件头部用于指明高低字节排列顺序的几个字符,通常是 FFFE ,而将之用 UTF-8 编码之后,就是 EFBBBF 。由于 UTF-8 文件本身不存在字节序问题,所以对 UTF-16 等编码方式有重大意义的 BOM,对于 UTF-8 来说,只有一个作用--表明这个文件是 UTF-8 格式。由于 BOM 会给文本处理带来很多难题,所以现在很多软件都要求使用不带 BOM 的 UTF-8 文件,特别是一些处理文本的软件,如 PHP、 UNIX 脚本文件等,svn 也是如此。

    目前常用的一些文本编辑工具中,MS Windows 自带的"记事本"里面,"另存为"菜单保存出来的 UTF-8 格式文件,会自动带上 BOM 。新版本 UltraEdit 提供了选项,允许用户选择是否需要 BOM,而老版本的不会添加 BOM。请各位查看一下自己常用的编辑器的说明文件,看看它是否支持这个功能。

    利用 UltraEdit ,我们可以将 BOM 去掉。方法是,首先利用"UTF-8 TO ASCII"菜单将文件转换成本地编码,通常是GB2312码,然后再使用"ASCII TO UTF-8(UNICODE Editing)"来转换到 UTF-8 即可。

    posted @ 2007-09-05 18:15 Stanley Sun 阅读(144) | 评论 (0)编辑 收藏

    Zoundry Blog Writer是一款非常不错的离线Blog编辑工具。本人在BlogJava中所以的文章基本上都是用它来编辑的,一下是对BlogJava的设置。

    新建Blog账户--> 选择你的Blog URL-->选择Blog类型为Custom MetaWeBlog API-->API的URL为http://www.blogjava.net:80/你的账户/services/metaweblog.aspx

    posted @ 2007-08-12 01:34 Stanley Sun 阅读(131) | 评论 (0)编辑 收藏