My studying notes for Java,Ruby,Ajax and other any interesting things.

星期五, 二月 13, 2009

公交换算算法-java

/**  

公交换乘一站的算法思想:  

(注意:车次信息、站点信息、公交信息是等价的都是以HashMap的形式存储信息)  

* 1.从数据库中获得所有公交信息存储到ArrayList,每个具体信息的元数据有三个:  

公交车次、公交站点、该公交站点距离该公交车次的始发站点的站数,具体信息用HashMap保存  

* 2.然后把公交信息数据进行结构化,把所有公交站点抽出,再把每一个站点对应的所有车次抽出  

与其一一对应,单一的车次信息用HashMap存储,站点对应的所有车次信息用ArrayList存储,  

所有的站点有经过站点的车次信息用HashMap存储  

* 3.根据查询要求,分别从结构化以后的公交信息数据中找到,经过出发地的所有车次,经过目的地  

的所有车次,然后在分别遍历每个车次,筛选出符合要求的中转站点,筛选规则是:每查询出一个  

站点时,得到该站点距离该站点对应车次的始发站的站数,如果这个站数小于查询站点距离该车次的始  

发站的站数,那么就符合规则,便把该站点信息保存到符合站点的ArrayList中,反之亦然  

* 4.分别得到查询条件中出发地和目的地的中转站点信息(中转站点信息存储在ArrayList中),然  

后遍历两个中转站点信息的集合,得到最终的具体中转信息(最终中转信息也是用ArrayList存储)  

*/    

import java.sql.Connection;   

import java.sql.DriverManager;   

import java.sql.ResultSet;   

import java.sql.ResultSetMetaData;   

import java.sql.SQLException;   

import java.sql.Statement;   

import java.util.ArrayList;   

import java.util.Iterator;   

import java.util.List;   

import java.util.HashMap;   

import java.util.Map;   

  

public class T {   

  private String start = null;// 出发地   

  

  private String whither = null;// 目标地   

  

  private List schedule = null;// 用于缓存列车时刻表。   

  

  private HashMap<String, ArrayList> stationsOfLine = null// 所有公交线路,每个list存储该线路经过的所有车站。   

  

  private HashMap<String, ArrayList> linesOfStation = null;// 所有车站,每个list中存储通过该车站的所有车次。   

  

  // private ArrayList <String> startLine = new ArrayList <String>();//   

  // 途经出发地的所有车次。   

  // private ArrayList <String> whitherLine = new ArrayList <String>();//   

  // 途经目的地的所有车次。   

  private ArrayList<Map> firLineStaList = new ArrayList<Map>();   

  

  private ArrayList<Map> secLineStaList = new ArrayList<Map>();   

  

  public T(String start, String whither) {   

    this.start = start;   

    this.whither = whither;   

    try {   

      this.schedule = this.executeQuery("select busLine,up,stationNo from bus_stations");   

    } catch (Exception e) {   

      // TODO Auto-generated catch block   

      System.out.println("读取数据库出错");   

      e.printStackTrace();   

    }   

    stationsOfLine = this.getStationsOfLine();   

    linesOfStation = this.getLinesOfStation();   

  }   

  

  private HashMap<String, ArrayList> getStationsOfLine() {   

    HashMap map = new HashMap();// 用于 临时存储从schedule中取出的HashMap.   

    ArrayList<Map> line = null;// 每个list存储一个车次的相关车站信息。   

    String buffer = "a";// 缓存站名。   

    String temp = null;// 临时存储每次迭代取出的站名,用于与buffer站名比较。   

    HashMap<String, ArrayList> stationsGroupByLine = new HashMap<String, ArrayList>();// 存储以车次分组後的车站的list   

    Iterator it = schedule.iterator(); // 迭代器   

    while (it.hasNext()) {   

      map = (HashMap) it.next();   

      temp = (String) map.get("busLine");   

      if (stationsGroupByLine.containsKey(temp)) {   

        line = stationsGroupByLine.get(temp);   

        buffer = (String) ((Map) line.get(0)).get("busLine");   

      }   

      if (buffer.equals(temp)) {   

        line.add(map);// 将同一车次的车站放入一个list   

      } else {   

        if (line != null && !line.isEmpty()) {   

          stationsGroupByLine.put(buffer, line);// 将由车次分组后的车站构成的list存入一个map   

        }   

        line = new ArrayList<Map>(); // line重新引用一个新构造的list,以供存储同一车站的车次。   

        line.add(map);// 将同一车次的车站放入刚刚构造的空list   

      }   

      buffer = temp;// 缓存当前操作的车次。   

    }   

    return stationsGroupByLine;   

  }   

  

  private HashMap getLinesOfStation() {   

    HashMap map = new HashMap();// 用于 临时存储从schedule中取出的HashMap.   

    ArrayList<Map> station = null;// 每个list存储一个经过该车站的相关车次信息。   

    String buffer = "a";// 缓存车次。   

    String temp = null;// 临时存储每次迭代取出的车次,用于与buffer车次比较。   

    HashMap<String, ArrayList> linesGroupBystation = new HashMap<String, ArrayList>();// 存储以车站分组後的车次的list   

    Iterator it = schedule.iterator(); // 迭代器   

    while (it.hasNext()) {   

      map = (HashMap) it.next();   

      temp = (String) map.get("up");   

      if (linesGroupBystation.containsKey(temp)) {   

        // station存储temp车次对应的站点信息   

        station = linesGroupBystation.get(temp);   

        // station中取出已经放入linesGroupBystation车站信息,缓存改车站的名字   

        // 与刚取出的Map中存储到车站信息进行比较   

        buffer = (String) ((Map) station.get(0)).get("up");   

      }   

      if (buffer.equals(temp)) {   

        // 如果station中几经存在该站点信息,那么,本站和station中存储到是同一站,所以   

        // 将同一车次的车站放入一个list   

        station.add(map);   

      } else {   

        if (station != null && !station.isEmpty()) {   

          // 将由车次分组后的车站构成的list存入一个map   

          linesGroupBystation.put(buffer, station);   

        }   

        // line重新引用一个新构造的list,以供存储经过另一车站的所有车次   

        station = new ArrayList<Map>();   

        station.add(map);// 将同一车次的车站放入刚刚构造的空list   

      }   

      buffer = temp;// 缓存当前操作的车次。   

    }   

    return linesGroupBystation;   

  }   

  

  /**  

   * 站点筛选规则:把符合规则的站点添分别放入  

   *   

   * @param startSta  

   * @param whitherSta  

   */  

  private void getStationsInLine(String startSta, String whitherSta) {   

    // 获得经过初始站点的所有公交车次   

    ArrayList firTrainLine = linesOfStation.get(startSta);   

    // 获得经过所有目的站点的公交车次   

    ArrayList secTrainLine = linesOfStation.get(whitherSta);   

    ArrayList station;   

    HashMap line = null;   

    int transferStaNo = 0;   

    // String stationName = null;   

    String trainNo = "";   

    if (firTrainLine != null) {   

      Iterator firIt = firTrainLine.iterator();   

      while (firIt.hasNext()) {   

        // 取出一个存储车站信息HashMap   

        line = (HashMap) firIt.next();   

        // 取出车次信息   

        trainNo = (String) line.get("busLine");   

        transferStaNo = (Integer) line.get("stationNo");   

        // 取出车次trainNo经过的所有站点信息   

        station = stationsOfLine.get(trainNo);   

        Iterator it = station.iterator();   

        while (it.hasNext()) {   

          Map map = (Map) it.next();// trainNo's map.   

          int i = (Integer) map.get("stationNo");   

          // 筛选站点规则:如果该站点距离初始站点距离比出发站点的距离初始站点的距离大,那么就把该站点存储到   

          // firLineStaList,反之就做反车了,所以那些站点不必加入firLineStaList   

          if (i > transferStaNo) {   

            //   

            firLineStaList.add(map);   

          }   

        }   

      }   

    }   

    if (secTrainLine != null) {   

      Iterator secIt = secTrainLine.iterator();   

      while (secIt.hasNext()) {   

        line = (HashMap) secIt.next();   

        trainNo = (String) line.get("busLine");   

        transferStaNo = (Integer) line.get("stationNo");   

        station = stationsOfLine.get(trainNo);   

        Iterator it = station.iterator();   

        while (it.hasNext()) {   

          Map map = (Map) it.next();   

          int i = (Integer) map.get("stationNo");   

          if (i < transferStaNo) {   

            secLineStaList.add(map);   

          }   

        }   

      }   

    }   

  }   

  

  /**  

   * create date:2008-5-19 author:Administrator  

   *   

   * @return  

   */  

  private ArrayList<Map> checkCrossLine() {   

    ArrayList<Map> crossLineList = new ArrayList<Map>();// 相交线路的集合,即是所有的换乘方法的集合   

    ArrayList<Map> lsStart = firLineStaList;// 经过起点站的所有车次的经停站站信息。   

    ArrayList<Map> lsEnd = secLineStaList;// 经过目的站的所有车次的经停站站信息。   

    if (lsStart != null && !lsStart.isEmpty() && lsEnd != null && !lsEnd.isEmpty()) {   

      for (Map<String, String> mapStart : lsStart) {   

        for (Map<String, String> mapEnd : lsEnd) {   

          if (IsInTheSameCity(mapStart.get("up"), mapEnd.get("up"))) {   

            // 将相交线路信息存入crossLine,存储某一个具体的换乘方法   

            Map<String, String> crossLine = new HashMap<String, String>(40.8f);   

            // 把第一次要做到车次放如crossLine   

            crossLine.put("firstLine", mapStart.get("busLine"));   

            // 把要换乘的车次放入到crossLine   

            crossLine.put("secondLine", mapEnd.get("busLine"));   

            // 把中转站点放入到crossLine   

            crossLine.put("transferSta", mapEnd.get("up"));   

            // crossLine.put("transferSta",(String)startInf.get("up"));   

            // 将包含相交线路信息的HashMap存入List   

            // 也即是把具体某个换乘方法放入crossLineList   

            crossLineList.add(crossLine);   

          } else {   

            continue;   

          }   

        }   

      }   

    } else {   

      crossLineList = null;   

    }   

    return crossLineList;   

  }   

  

  private boolean IsInTheSameCity(String station1, String station2) {   

    if (station1.contains(station2) || station2.contains(station1)) {   

      // System.out.println(station1+"#########"+station2);   

      return true;   

    } else {   

      return false;   

    }   

  }   

  

  public ArrayList<Map> getSchemaOfTransfer() {   

    this.getStationsInLine(this.start, this.whither);   

    return this.checkCrossLine();   

  }   

  

  public static void main(String[] args) {   

    T tb = new T("前门""天安门西");   

    // tb.getSchemaOfTransfer();   

    for (Map map : tb.getSchemaOfTransfer()) {   

      System.out.println(map);   

      System.out.println("您好,您可以先乘坐 " + map.get("firstLine") +  " + map.get("transferSta")   

          + 然后换乘 " + map.get("secondLine") + 便可到达,不要错过站吆 ");   

    }   

    // System.out.println(tb.secLineStaList.size());   

  }   

  

  private Connection getConnection() {   

    Connection con = null;   

    String url = "jdbc:mysql://127.0.0.1:3306/souwhat?autoReconnect=true&useUnicode=true&characterEncoding=GBK&mysqlEncoding=GBK";   

    String user = "root";   

    String psWord = "";   

    try {   

      Class.forName("com.mysql.jdbc.Driver");   

    } catch (ClassNotFoundException e) {   

      // TODO Auto-generated catch block   

      e.printStackTrace();   

      System.out.println("The Exception at load the Driver");   

    }   

    try {   

      con = DriverManager.getConnection(url, user, psWord);   

    } catch (SQLException e) {   

      // TODO Auto-generated catch block   

      e.printStackTrace();   

      System.out.println("The Exception at creat the connection");   

    }   

    return con;   

  }   

  

  private void closeConnection(Connection conn) throws Exception {   

    if (conn != null) {   

      conn.close();   

    }   

  }   

  

  private List executeQuery(String sql) throws Exception {   

    // System.out.println("executeQuery(sql): " + sql);   

    List list = new ArrayList();   

    Connection conn = null;   

    Statement stmt = null;   

    ResultSet rs = null;   

    try {   

      conn = getConnection();   

      stmt = conn.createStatement();   

      System.out.println(sql);   

      rs = stmt.executeQuery(sql);   

      ResultSetMetaData rsmd = rs.getMetaData();   

      while (rs.next()) {   

        Map map = new HashMap();   

        for (int i = 1; i <= rsmd.getColumnCount(); i++) {   

          // 每一行所有列存入HashMap   

          map.put(rsmd.getColumnName(i), rs.getObject(i));   

        }   

        // 所有行存入List   

        list.add(map);   

      }   

    } catch (Exception e) {   

      System.out.println("数据库查询出错!");   

      e.printStackTrace();   

    } finally {   

      if (rs != null)   

        rs.close();   

      closeConnection(conn);   

    }   

    return list;   

  }   

}  

星期六, 一月 31, 2009

电话号码显示处理方式

关于电话处理:
目前使用的加密/解密生成图片返回客户端显示的方式,在详情页需要显示电话的时候将电话通过加密程序生成一个字符串,然后传递给相应的处理程序,该处理程序解密字符串并声称对应的电话图片。
 
但是这样子缺点有两个:
1.加密解密速度较慢
2.图片服务器上面需要增加php模块,降低Nginx的处理效率
 
问题起因:
1.防止蜘蛛抓取用户的电话并缓存,导致用户在删除信息以后仍然可以在搜索引擎的缓存中查找到,导致用户隐私泄露
2.防拷贝。电话号码很容被拷贝粘贴,如果使用图片的方式可以防止用户的电话被人轻易拷贝利用
 
其他解决办法:
1.使用混淆码。在电话的数字间插入一些随机的隐藏的代码,可以防止蜘蛛抓取,同时也可以防止一部分拷贝操作
2.使用js写出电话号码,在显示电话的时候直接使用document.write去将电话号码写出。这种方式也可以避免蜘蛛抓取,但是无法防止拷贝操作。
 
如果在用户信息保密程度不是那么高的情况下,建议使用后两种方式,这两种方式可以大大降低服务器的加密解密以及图片生成的压力。

星期二, 一月 20, 2009

[fwd]Java Annotation入门

 
版权声明:本文可以自由转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:cleverpig(作者的Blog:http://blog.matrix.org.cn/page/cleverpig)
原文:[http://www.matrix.org.cn/resource/article/44/44048_Java+Annotation.html]http://www.matrix.org.cn/resource/article/44/44048_Java+Annotation.html[/url]
关键字:Java,annotation,标注
 

摘要:
本文针对java初学者或者annotation初次使用者全面地说明了annotation的使用方法、定义方式、分类。初学者可以通过以上的说明制作简单的annotation程序,但是对于一些高级的annotation应用(例如使用自定义annotation生成javabean映射xml文件)还需要进一步的研究和探讨。涉及到深入annotation的内容,作者将在后文《Java Annotation高级应用》中谈到。
 
同时,annotation运行存在两种方式:运行时、编译时。上文中讨论的都是在运行时的annotation应用,但在编译时的annotation应用还没有涉及,
 
一、为什么使用Annotation:
 
在JAVA应用中,我们常遇到一些需要使用模版代码。例如,为了编写一个JAX-RPC web service,我们必须提供一对接口和实现作为模版代码。如果使用annotation对远程访问的方法代码进行修饰的话,这个模版就能够使用工具自动生成。
另外,一些API需要使用与程序代码同时维护的附属文件。例如,JavaBeans需要一个BeanInfo Class与一个Bean同时使用/维护,而EJB则同样需要一个部署描述符。此时在程序中使用annotation来维护这些附属文件的信息将十分便利而且减少了错误。
 
二、Annotation工作方式:
 
在5.0 版之前的Java平台已经具有了一些ad hoc annotation机制。比如,使用transient修饰符来标识一个成员变量在序列化子系统中应被忽略。而@deprecated这个 javadoc tag也是一个ad hoc annotation用来说明一个方法已过时。从Java5.0版发布以来,5.0平台提供了一个正式的annotation功能:允许开发者定义、使用自己的annoatation类型。此功能由一个定义annotation类型的语法和一个描述annotation声明的语法,读取annotaion 的API,一个使用annotation修饰的class文件,一个annotation处理工具(apt)组成。
annotation并不直接影响代码语义,但是它能够工作的方式被看作类似程序的工具或者类库,它会反过来对正在运行的程序语义有所影响。annotation可以从源文件、class文件或者以在运行时反射的多种方式被读取。
当然annotation在某种程度上使javadoc tag更加完整。一般情况下,如果这个标记对java文档产生影响或者用于生成java文档的话,它应该作为一个javadoc tag;否则将作为一个annotation。
 
三、Annotation使用方法:
 
1。类型声明方式:
通常,应用程序并不是必须定义annotation类型,但是定义annotation类型并非难事。Annotation类型声明于一般的接口声明极为类似,区别只在于它在interface关键字前面使用"@"符号。
annotation 类型的每个方法声明定义了一个annotation类型成员,但方法声明不必有参数或者异常声明;方法返回值的类型被限制在以下的范围: primitives、String、Class、enums、annotation和前面类型的数组;方法可以有默认值。
 
下面是一个简单的annotation类型声明:
清单1:
    /**
     * Describes the Request-For-Enhancement(RFE) that led
     * to the presence of the annotated API element.
     */
    public @interface RequestForEnhancement {
        int    id();
        String synopsis();
        String engineer() default "[unassigned]";
        String date();    default "[unimplemented]";
    }
 

代码中只定义了一个annotation类型RequestForEnhancement。
 
2。修饰方法的annotation声明方式:
annotation 是一种修饰符,能够如其它修饰符(如public、static、final)一般使用。习惯用法是annotaions用在其它的修饰符前面。 annotations由"@+annotation类型+带有括号的成员-值列表"组成。这些成员的值必须是编译时常量(即在运行时不变)。
 
A:下面是一个使用了RequestForEnhancement annotation的方法声明:
清单2:
    @RequestForEnhancement(
        id       = 2868724,
        synopsis = "Enable time-travel",
        engineer = "Mr. Peabody",
        date     = "4/1/3007"
    )
    public static void travelThroughTime(Date destination) { ... }
 
 
 
B:当声明一个没有成员的annotation类型声明时,可使用以下方式:
清单3:
    /**
     * Indicates that the specification of the annotated API element
     * is preliminary and subject to change.
     */
    public @interface Preliminary { }
 
 
 
作为上面没有成员的annotation类型声明的简写方式:
清单4:
    @Preliminary public class TimeTravel { ... }
 
 
 
C:如果在annotations中只有唯一一个成员,则该成员应命名为value:
清单5:
    /**
     * Associates a copyright notice with the annotated API element.
     */
    public @interface Copyright {
        String value();
    }
 
 
 
更为方便的是对于具有唯一成员且成员名为value的annotation(如上文),在其使用时可以忽略掉成员名和赋值号(=):
清单6:
    @Copyright("2002 Yoyodyne Propulsion Systems")
    public class OscillationOverthruster { ... }
 
 
 
3。一个使用实例:
结合上面所讲的,我们在这里建立一个简单的基于annotation测试框架。首先我们需要一个annotation类型来表示某个方法是一个应该被测试工具运行的测试方法。
清单7:
    import java.lang.annotation.*;
 
    /**
     * Indicates that the annotated method is a test method.
     * This annotation should be used only on parameterless static methods.
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Test { }
 
 
 
值得注意的是annotaion类型声明是可以标注自己的,这样的annotation被称为"meta-annotations"。
 
在上面的代码中,@Retention(RetentionPolicy.RUNTIME)这个meta-annotation表示了此类型的 annotation将被虚拟机保留使其能够在运行时通过反射被读取。而@Target(ElementType.METHOD)表示此类型的 annotation只能用于修饰方法声明。
 
下面是一个简单的程序,其中部分方法被上面的annotation所标注:
清单8:
    public class Foo {
        @Test public static void m1() { }
        public static void m2() { }
        @Test public static void m3() {
            throw new RuntimeException("Boom");
        }
        public static void m4() { }
        @Test public static void m5() { }
        public static void m6() { }
        @Test public static void m7() {
            throw new RuntimeException("Crash");
        }
        public static void m8() { }
    }
 
Here is the testing tool:
 
    import java.lang.reflect.*;
 
    public class RunTests {
       public static void main(String[] args) throws Exception {
          int passed = 0, failed = 0;
          for (Method m : Class.forName(args[0]).getMethods()) {
             if (m.isAnnotationPresent(Test.class)) {
                try {
                   m.invoke(null);
                   passed++;
                } catch (Throwable ex) {
                   System.out.printf("Test %s failed: %s %n", m, ex.getCause());
                   failed++;
                }
             }
          }
          System.out.printf("Passed: %d, Failed %d%n", passed, failed);
       }
    }
 
 
 
这个程序从命令行参数中取出类名,并且遍历此类的所有方法,尝试调用其中被上面的测试annotation类型标注过的方法。在此过程中为了找出哪些方法被 annotation类型标注过,需要使用反射的方式执行此查询。如果在调用方法时抛出异常,此方法被认为已经失败,并打印一个失败报告。最后,打印运行通过/失败的方法数量。
下面文字表示了如何运行这个基于annotation的测试工具:
 
清单9:
    $ java RunTests Foo
    Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom
    Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash
    Passed: 2, Failed 2
 
 
 
四、Annotation分类:
 
根据annotation的使用方法和用途主要分为以下几类:
 
1。内建Annotation――Java5.0版在java语法中经常用到的内建Annotation:
@Deprecated用于修饰已经过时的方法;
@Override用于修饰此方法覆盖了父类的方法(而非重载);
@SuppressWarnings用于通知java编译器禁止特定的编译警告。
 
下面代码展示了内建Annotation类型的用法:
清单10:
package com.bjinfotech.practice.annotation;
 
/**
 * 演示如何使用java5内建的annotation
 * 参考资料:
 * http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html
 * http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html
 * http://mindprod.com/jgloss/annotations.html
 * @author cleverpig
 *
 */
import java.util.List;
 
public class UsingBuiltInAnnotation {
        //食物类
        class Food{}
        //干草类
        class Hay extends Food{}
        //动物类
        class Animal{
                Food getFood(){
                        return null;
                }
                //使用Annotation声明Deprecated方法
                @Deprecated
                void deprecatedMethod(){
                }
        }
        //马类-继承动物类
        class Horse extends Animal{
                //使用Annotation声明覆盖方法
                @Override
                Hay getFood(){
                        return new Hay();
                }
                //使用Annotation声明禁止警告
                @SuppressWarnings({"deprecation","unchecked"})
                void callDeprecatedMethod(List horseGroup){
                        Animal an=new Animal();
                        an.deprecatedMethod();
                        horseGroup.add(an);
                }
        }
}
 
 
 
2。开发者自定义Annotation:由开发者自定义Annotation类型。
下面是一个使用annotation进行方法测试的sample:
 
AnnotationDefineForTestFunction类型定义如下:
清单11:
package com.bjinfotech.practice.annotation;
 
import java.lang.annotation.*;
/**
 * 定义annotation
 * @author cleverpig
 *
 */
//加载在VM中,在运行时进行映射
@Retention(RetentionPolicy.RUNTIME)
//限定此annotation只能标示方法
@Target(ElementType.METHOD)
public @interface AnnotationDefineForTestFunction{}
 
 
 
测试annotation的代码如下:
 
清单12:
package com.bjinfotech.practice.annotation;
 
import java.lang.reflect.*;
 
/**
 * 一个实例程序应用前面定义的Annotation:AnnotationDefineForTestFunction
 * @author cleverpig
 *
 */
public class UsingAnnotation {
        @AnnotationDefineForTestFunction public static void method01(){}
       
        public static void method02(){}
       
        @AnnotationDefineForTestFunction public static void method03(){
                throw new RuntimeException("method03");
        }
       
        public static void method04(){
                throw new RuntimeException("method04");
        }
       
        public static void main(String[] argv) throws Exception{
                int passed = 0, failed = 0;
                //被检测的类名
                String className="com.bjinfotech.practice.annotation.UsingAnnotation";
                //逐个检查此类的方法,当其方法使用annotation声明时调用此方法
            for (Method m : Class.forName(className).getMethods()) {
               if (m.isAnnotationPresent(AnnotationDefineForTestFunction.class)) {
                  try {
                     m.invoke(null);
                     passed++;
                  } catch (Throwable ex) {
                     System.out.printf("测试 %s 失败: %s %n", m, ex.getCause());
                     failed++;
                  }
               }
            }
            System.out.printf("测试结果: 通过: %d, 失败: %d%n", passed, failed);
        }
}
 
 
 
3。使用第三方开发的Annotation类型
这也是开发人员所常常用到的一种方式。比如我们在使用Hibernate3.0时就可以利用Annotation生成数据表映射配置文件,而不必使用Xdoclet。
 
五、总结:
 
1。前面的文字说明了annotation的使用方法、定义方式、分类。初学者可以通过以上的说明制作简单的annotation程序,但是对于一些高级的 annotation应用(例如使用自定义annotation生成javabean映射xml文件)还需要进一步的研究和探讨。
 
2。同时,annotation运行存在两种方式:运行时、编译时。上文中讨论的都是在运行时的annotation应用,但在编译时的annotation应用还没有涉及,因为编译时的annotation要使用annotation processing tool。
 
涉及以上2方面的深入内容,作者将在后文《Java Annotation高级应用》中谈到。
 
六、参考资源:
・Matrix-Java开发者社区:http://www.matrix.org.cn
・http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html
・http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html
・http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html
・http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html
・作者的Blog:http://blog.matrix.org.cn/page/cleverpig

星期五, 十二月 19, 2008

[fwd]Vim对中文编码的支持

1、支持中文编码的基础

Vim要更好地支持中文编码需要两个特性:+multi_byte和+iconv,可以用|:version|命令检查当前使用的Vim是否支持,否则的话需要重新编译。

2、影响中文编码的设置项

Vim中有几个选项会影响对多字节编码的支持:

  • encoding(enc):encoding是Vim的内部使用编码,encoding的设置会影响Vim内部的Buffer、消息文字等。在Unix环境下,encoding的默认设置等于locale;Windows环境下会和当前代码页相同。在中文Windows环境下encoding的默认设置是cp936(GBK)。
  • fileencodings(fenc):Vim在打开文件时会根据fileencodings选项来识别文件编码,fileencodings可以同时设置多个编码,Vim会根据设置的顺序来猜测所打开文件的编码。
  • fileencoding(fencs) :Vim在保存新建文件时会根据fileencoding的设置编码来保存。如果是打开已有文件,Vim会根据打开文件时所识别的编码来保存,除非在保存时重新设置fileencoding。
  • termencodings(tenc):在终端环境下使用Vim时,通过termencoding项来告诉Vim终端所使用的编码。

3、Vim中的编码转换

Vim内部使用iconv库进行编码转换,如果这几个选项所设置的编码不一致,Vim就有可能会转换编码。打开已有文件时会从文件编码转换到encoding所设置的编码;保存文件时会从encoding设置的编码转换到fileencoding对应的编码。经常会看到Vim提示[已转换],这是表明Vim内部作了编码转换。终端环境下使用Vim,会从termencoding设置的编码转换到encoding设置的编码。

可以用|:help encoding-values|列出Vim支持的所有编码。

4、具体应用环境的设置

  • 只编辑GBK编码的文件

set fileencodings=cp936
set fileencoding=cp936
set encoding=cp936

  • 只编辑UTF-8编码的中文文件

set fileencodings=utf-8
set fileencoding=utf-8
set encoding=cp936 或者 set encoding=utf-8

  • 同时支持GBK和UTF-8编码

set fileencodings=ucs-bom,utf-8,cp936
set fileencoding=utf-8
set encoding=cp936 或者 set encoding=utf-8

  • 如果在终端环境下使用Vim,需要设置termencoding和终端所使用的编码一致。例如:

set termencoding=cp936 或者 set termencoding=utf-8

Windows记事本编辑UTF-8编码文件时会在文件头上加上三个字节的BOM:EFBBBF。如果fileencodings中设置ucs-bom的目的就是为了能够兼容用记事本编辑的文件,不需要的话可以去掉。Vim在保存UTF-8编码的文件时会去掉BOM。去掉BOM的最大好处是在Unix下能够使用cat a b>c来正确合并文件,这点经常被忽略。

5、FAQ

  1. 为什么在Vim中一次只能删除半个汉字?

    因为encoding设置错误,把encoding设置为cp936就可以解决此问题。在Unix环境下Vim会根据locale来设置默认的encoding,如果没有正确设置locale并且没有设置encoding就会一次只能删除半个汉字。

  2. VIM为什么不能输入繁体字?

    把euc-cn或者GB2312改为cp936就可以了。euc-cn是GB2312的别名,不支持繁体汉字。cp936是GBK的别名,是GB2312的超集,可以支持繁体汉字。

  3. VIM为什么提示不能转换?

    因为在编译Vim时没有加入iconv选项,重新编译Vim才能解决。

  4. 如何打开一个GBK编码的文件并另存为UTf-8编码?

    保存文件时运行命令|:set fileencoding=utf-8|就可以了。
     

星期二, 十二月 16, 2008

[Java]链接数据库的方式总结

1、Oracle8/8i/9i数据库(thin模式)
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url="jdbc:oracle:thin:@localhost:1521:orcl";
//orcl为数据库的SID
String user="test";
String password="test";
Connection conn= DriverManager.getConnection(url,user,password);
 
2、DB2数据库
Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance();
String url="jdbc:db2://localhost:5000/sample";
//sample为你的数据库名
String user="admin";
String password="";
Connection conn= DriverManager.getConnection(url,user,password);
 
3、Sql Server7.0/2000数据库
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb";
//mydb为数据库
String user="sa";
String password="";
Connection conn= DriverManager.getConnection(url,user,password);
 
4、Sybase数据库
Class.forName("com.sybase.jdbc.SybDriver").newInstance();
String url =" jdbc:sybase:Tds:localhost:5007/myDB";
//myDB为你的数据库名
Properties sysProps = System.getProperties();
SysProps.put("user","userid");
SysProps.put("password","user_password");
Connection conn= DriverManager.getConnection(url, SysProps);
 
5、Informix数据库
Class.forName("com.informix.jdbc.IfxDriver").newInstance();
String url =
"jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER=myserver;
user=testuser;password=testpassword";
//myDB为数据库名
Connection conn= DriverManager.getConnection(url);
 
6、MySQL数据库
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
String url ="jdbc:mysql://localhost/myDB?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1"
//myDB为数据库名
Connection conn= DriverManager.getConnection(url);
 
7、PostgreSQL数据库
Class.forName("org.postgresql.Driver").newInstance();
String url ="jdbc:postgresql://localhost/myDB"
//myDB为数据库名
String user="myuser";
String password="mypassword";
Connection conn= DriverManager.getConnection(url,user,password);

星期三, 八月 06, 2008

菜鸟编程的十大好习惯



假如你和我一样是一只正在学习编程的菜鸟,那么下面的十个好习惯与你共勉之。
  1、设计规划

  现在是模块化程序设计的天下,应用程序要实现的目标就是金字塔尖,进行程序设计规划的意义就在于,对构成金字塔的基础模块进行划分,规划得越详细,模块分工越明确,越容易明白下一步该做什么,这好比搭积木的游戏,你可以把你的积木块组合成各种各样的形状,但首先要熟悉每个积木块的功能。

  2、有备无患

  实战之前,先找几个样例程序研究研究,最起码明白怎么开头,怎么结尾,别打无准备之仗。

  3、葵花宝典

  做一份所用程序语言的精简列表,包括基本数据类型、各类运算符说明、基本语句结构、常用关键词(保留字)、常用函数(控件)说明等等。

  4、自由独立

  为你的应用程序建立一个单独的目录,这样既方便应用程序文件的管理,而且如果你要给程序搬“家”,卷起铺盖就可以走人了。

  5、见名知意

  程序再小,用的变量也不会少,变量起名应当见名知意是个老话题了,好处是显而易见的。推荐程序员使用“匈牙利命名法”,它会使你的起名工作变得轻而易举,而且相当专业。

  6、对称之美

  中国人讲究对称之美,用在编程里也很合适,如果程序里用到A循环嵌套B判断,B判断又包含C循环之类的结构,记着使用缩进法,让A:ENDDO对齐A:ENDDO,B:ENDIF对齐B:IF……诸如此类,依次缩进,总之对称就等于美观加易读。

  7、多加注解

  对程序中自定义的变量、函数、子程序加以功能性的注释说明,别嫌麻烦。如果过了三月五月,连自己写的东西都看不明白了,那才大麻烦。

  8、环境保护

  如果应用程序需要修改系统设置,记着应用开始前先保存设置,应用结束后要恢复设置,千万别污染环境。

  9、拿来主义

  一个人的力量是有限的,大家的力量是无限的,平时多看看《中国电脑教育报》,如果碰巧有好的经验,巧的方法,用得上的段子,不妨拿来。

  10、忍者无敌

  当你认为程序代码写的“百分百”正确,而程序编译执行百分百有毛病,你基本属于晕菜的时候,千万要忍,歇口气,重头来,别放弃!相信最终的胜利是属于你的!

星期二, 八月 05, 2008

PHP中使用GD生成水印图片



  header ("Content-type: image/png");

  $logoImage = ImageCreateFromPNG('test.png');

  $photoImage = ImageCreateFromJpeg('back.jpg');

  ImageAlphaBlending($photoImage, true);

  $logoW = ImageSX($logoImage);

  $logoH = ImageSY($logoImage);

  ImageCopy($photoImage, $logoImage, 0, 0, 0, 0, $logoW, $logoH);

  ImageJPEG($photoImage); // output to browser

  ImageDestroy($photoImage);

  ImageDestroy($logoImage);

发现PHP出奇的强大和简单.