[转载]Delphi编译/链接过程

mikel阅读(1072)

[转载]Delphi编译/链接过程 – 瓢虫Monster – 博客园.

下面展示了Delphi是怎样编译源文件,并且把它们链接起来,最终形成可执行文件。

0061

当Delphi编译项目(Project)时,将编译项目源文件、窗体单元和其他相关单元,在这个过程中将会发生好几件事情:

首 先,Object Pascal编译器把项目单元编译为二进制对象文件,然后资源编辑器将把诸如程序图标、窗体文件等资源编译成二进制资源文件,接着链接开始起作用;链接器 根据编译器产生的二进制文件,依项目需要增加一些库文件,并把这些文件综合在一起产生最终的可执行文件。

编译、创建和链接

每当点击Run按钮时,Delphi都会编译和链接程序,但它只编译改动过的单元。Delphi能知道哪个个文件已改动,哪个文件没有改到。

绝大部分时间中,我们都想看一看改变后的程序运行结果,在这种情况下,就需要点击Run按钮,程序将被编译、链接和执行。但有时候可能不想运行程序,比如只想编译程序,看一看有没有什么错误。

当默认创建一个Application时(工程文件名DRP默认为Project1),在Delphi的主菜单Project下,则有以下几个菜单选项:

0075

1、Syntax check Project1 选项, 它能让Delphi编译工程,并且报出任何错误和警告,这时检查代码错误最快的方法,Delphi只编译工程,而不执行链接,Syntax check选项的目的就是尽快检查代码的语法错误,因为链接阶段需要占额外的时间,Syntax check忽略了这一步。界面如下:

0076

2、Compile Project1 选项,就像Syntax check一样,它用来编译从最近一次编译后改动过的任何单元。它需要执行链接,因此比Syntax check 选项所占的时间稍长一点,当需要只编译和链接程序而不运行时就可以用Compile 选项。界面如下:

0077

默认情况下,该Compile选项不会显示编译状态对话框,通过主菜单【Tools | Environment Option】对话框中打开“Preferences”选项卡,在Compiling and running组合框中勾选“Show compiler progress”选项即可打开编译状态对话框,如下:

0079

Delphi编译工程的速度非常快,故一般不需要编译状态对话框,实际上,编译状态对话框增加了编译时间,因为编译状态对话框中显示信息是占用时间的。

3、Build project1 选项,占的时间最长,这个选项编译工程中的每一个单元,不管这个单元是否有改动,当编译完所有单元后,Delphi链接整个工程,并生成Project1.exe可执行文件。

不 管选择哪种方式编译工程,如果发现了错误,Code Editor 将会出现在顶级窗口,并且Code Editor 底部的信息窗口将会显示错误和警告清单。Code Editor 会把第一处出错的代码行加亮,当成功进行语法检查、编译、链接和创建后,就可以通过选择Run按钮来运行程序。

编译并建立其他Delphi程序

在Delphi中,大部分情况都是编写基于VCL的应用程序。但有时也要编写其他类型的应用程序。点击主菜单【File | New | Other..】可以看到Delphi支持的其他类型应用程序,如下:

0080

DLL Wizard,将创建动态链接库(DLL)

Console Application,Win32控制台应用程序是一种32位程序,它在Windows的DOS模式下运行。任何不需要图形接口的应用程序基本上都适合控制台应用程序。

[转载]Java网页数据采集器实例教程[中篇-数据存储]

mikel阅读(992)

[转载]Java网页数据采集器实例教程[中篇-数据存储] – SoFlash – 博客园.

简介:

作为全球运用最广泛的语言,Java 凭借它的高效性,可移植性(跨平台),代码的健壮性以及可强大的可扩展性,深受广大应用程序开发者的喜爱. 作为一门强大的开发语言,正则表达式在其中的应用当然是必不可少的,而且正则表达式的掌握能力也是那些高级程序员的开发功底之体现,做一名合格的网站开发 的程序员(尤其是做前端开发),正则表达式是必备的.

最近,由于一些需要,用到了java和正则,做了个的足球网站的 数据采集程序,由于是第一次做关于java的html页面数据采集,必然在网上查找了很多资料,但是发现运用如此广泛的java在使用正则做html采集 方面的(中文)文章是少之又少,都是简单的谈了下java正则的概念,没有真正用在实际网页html采集,所以实例教程更是寥寥无几(虽然java有它自 己的Html Parser,而且十分强大),但个人觉得作为如此深入人心的正则表达式,理应有其相关的java实例教程,而且应该很多很全.于是在完成java版的 html数据采集程序之后,本人便打算写个关于正则表达式在java上的html页面采集,以便有相关兴趣的读者更好的学习.

本期概述:

上期我们讲到了html页面的数据采集,为了方便我们今后来调用收集到的数据,这期我们要讲讲如何做数据存储(MySQL数据库).

数据采集页面 http://www.footballresults.org/league.php?all=1&league=EngPrem

关于Java操作MySQL

在使用java 操作MySQL数据库之前 我们需要在项目文件中导入 一个jar包(mysql-connector-java-5.1.18-bin)

可以在MySql官网下载 http://www.mysql.com/downloads/connector/j/

如何在java项目中导入jar包?

请看这个 http://blog.csdn.net/justinavril/article/details/2783182

关于MySql数据库

如果是初学者 想使用MySql数据库的话 可以去这里 http://www.apachefriends.org/zh_cn/xampp.html 下载 XAMPP 套装

XAMPP(Apache+MySQL+PHP+PERL)是一个功能强大的建 XAMPP 软件站集成软件包, 而且一键式安装, 无需修改配置文件,非常好用.

好了 需要准备的事宜都完成了 我们开始写代码

打开MySql数据库 创建数据库 和表 (拷贝如下代码 到mysql里直接执行即可)

创建MySql数据库

创建好后 我们来看看数据库结构


数据库弄好了 我们开始实施java代码

这里简单介绍下各个类以及类所包含的方法

DataStorage类 以及包含的 dataStore()方法 用于数据收集和存储

DataStorage类

  1 import java.io.BufferedReader;
  2 import java.io.IOException;
  3 import java.io.InputStreamReader;
  4 import java.net.URL;
  5 
  6 public class DataStorage {
  7 
  8     public void dataStore() {
  9         // 首先用一个字符串 来装载网页链接
 10         String strUrl = "http://www.footballresults.org/league.php?all=1&league=EngPrem";
 11         
 12         String sqlLeagues = "";
 13         try {
 14             // 创建一个url对象来指向 该网站链接 括号里()装载的是该网站链接的路径
 15             // 更多可以看看 http://wenku.baidu.com/view/8186caf4f61fb7360b4c6547.html
 16             URL url = new URL(strUrl);
 17             // InputStreamReader 是一个输入流读取器 用于将读取的字节转换成字符
 18             // 更多可以看看 http://blog.sina.com.cn/s/blog_44a05959010004il.html
 19             InputStreamReader isr = new InputStreamReader(url.openStream(),
 20                     "utf-8"); // 统一使用utf-8 编码模式
 21             // 使用 BufferedReader 来读取 InputStreamReader 转换成的字符
 22             BufferedReader br = new BufferedReader(isr);
 23             String strRead = ""; // new 一个字符串来装载 BufferedReader 读取到的内容
 24 
 25             // 定义3个正则 用于获取我们需要的数据
 26             String regularDate = "(\\d{1,2}\\.\\d{1,2}\\.\\d{4})";
 27             String regularTwoTeam = ">[^<>]*</a>";
 28             String regularResult = ">(\\d{1,2}-\\d{1,2})</TD>";
 29 
 30             //创建 GroupMethod类的对象 gMethod 方便后期调用其类里的 regularGroup方法
 31             GroupMethod gMethod = new GroupMethod();
 32             //创建DataStructure数据结构 类的对象   用于数据下面的数据存储
 33             DataStructure ds = new DataStructure();
 34             //创建MySql类的对象 用于执行MySql语句
 35             MySql ms = new MySql();
 36             int i = 0; // 定义一个i来记录循环次数 即收集到的球队比赛结果数
 37             int index = 0; // 定义一个索引 用于获取分离 2个球队的数据 因为2个球队正则是相同的
 38             // 开始读取数据 如果读到的数据不为空 则往里面读
 39             while ((strRead = br.readLine()) != null) {
 40                 /**
 41                  * 用于捕获日期数据
 42                  */
 43                 String strGet = gMethod.regularGroup(regularDate, strRead);
 44                 // 如果捕获到了符合条件的 日期数据 则打印出来
 45                 
 46                 if (!strGet.equals("")) {
 47                     //System.out.println("Date:" + strGet);
 48                     //将收集到的日期存在数据结构里
 49                     ds.date = strGet;
 50                     // 这里索引+1 是用于获取后期的球队数据
 51                     ++index; // 因为在html页面里 源代码里 球队数据是在刚好在日期之后
 52                 }
 53                 /**
 54                  * 用于获取2个球队的数据
 55                  */
 56                 strGet = gMethod.regularGroup(regularTwoTeam, strRead);
 57                 if (!strGet.equals("") && index == 1) { // 索引为1的是主队数据
 58                     // 通过subtring方法 分离出 主队数据
 59                     strGet = strGet.substring(1, strGet.indexOf("</a>"));
 60                     //System.out.println("HomeTeam:" + strGet); // 打印出主队
 61                     //将收集到的主队名称 存到 数据结构里
 62                     ds.homeTeam = strGet;
 63                     index++; // 索引+1之后 为2了
 64                  // 通过subtring方法 分离出 客队
 65                 } else if (!strGet.equals("") && index == 2) { // 这里索引为2的是客队数据
 66                     strGet = strGet.substring(1, strGet.indexOf("</a>"));
 67                     //System.out.println("AwayTeam:" + strGet); // 打印出客队
 68                     //将收集到的客队名称 存到数据结构里
 69                     ds.awayTeam = strGet;
 70                     index = 0;  //收集完客队名称后 需要将索引还原 用于收集下一条数据的主队名称
 71                 }
 72                 /**
 73                  * 用于获取比赛结果
 74                  */
 75                 strGet = gMethod.regularGroup(regularResult, strRead);
 76                 if (!strGet.equals("")) {
 77                     // 这里同样用到了substring方法 来剔除'<' 和 "</TD>" 标签 来获取我们想要的比赛结果
 78                     strGet = strGet.substring(1, strGet.indexOf("</TD>"));
 79                     //System.out.println("Result:" + strGet);
 80                     ds.result = strGet; //将收集到的比赛结果存到数据结构里
 81                     //System.out.println();
 82                     
 83                     //MySql插入语句
 84                     sqlLeagues = "INSERT INTO Premiership values(\""
 85                             + ds.date + "\"," + "\"" + ds.homeTeam
 86                             + "\"," + "\"" + ds.awayTeam + "\","+ "\"" + ds.result + "\")";
 87                     //调用MySql类的datatoMySql()方法 来执行 MySql插入语句
 88                     ms.datatoMySql(sqlLeagues);
 89                     i++; //每插入完一条记录 i+1;
 90                     System.out.println("第"+i+"条数据插入成功");
 91                 }
 92             }
 93             // 当读完数据后 记得关闭 BufferReader
 94             br.close();
 95             //System.out.println("共收集到" + i + "条比赛记录");// 打印出循环次数
 96             //当数据存储完成后 打印出 收集球队记录数
 97             System.out.println("数据存储完毕,共插入数据库"+i+"条记录");
 98         } catch (IOException e) {
 99             // 如果出错 抛出异常
100             e.printStackTrace();
101         }
102     }
103 }

DataStructure类 以及包含的 DataStructure()方法 简单的数据结构 用于数据临时性的存储

DataStructure类

 1 //创建一个数据结构类来 装载收集到的数据
 2 // DataStructure为构造函数 可以直接调用类 对象来使用其中的数据字段
 3 public class DataStructure { 
 4     //定义数据字段
 5     public String homeTeam;
 6     public String awayTeam;
 7     public String date;
 8     public String result;
 9     //空方法 用于 在DataStorage类里 来调用其数据字段
10     public DataStructure(){}
11     
12 }

GroupMethod类 以及包含的  regularGroup()方法 用于正则匹配html 源代码上的数据

GroupMethod类

 1 import java.util.regex.Matcher;
 2 import java.util.regex.Pattern;
 3 
 4 public class GroupMethod {
 5     // 传入2个字符串参数 一个是pattern(我们使用的正则) 另一个matcher是html源代码
 6     public String regularGroup(String pattern, String matcher) {
 7         Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
 8         Matcher m = p.matcher(matcher);
 9         if (m.find()) { // 如果读到
10             return m.group();// 返回捕获的数据
11         } else {
12             return ""; // 否则返回一个空值
13         }
14     }
15 }

MySql类 以及包含的 datatoMySql() 方法 用于执行SQL插入语句 将临时存储在数据结构里的数据 插入到MySql数据库中

MySql类

 1 import java.sql.Connection;
 2 import java.sql.DriverManager;
 3 import java.sql.SQLException;
 4 import java.sql.Statement;
 5 
 6 /**
 7  * @MySql类用于实施MySql查询语句
 8  */
 9 public class MySql {
10   
11     //定义MySql驱动,数据库地址,数据库用户名 密码, 执行语句和数据库连接  
12     public String driver = "com.mysql.jdbc.Driver";
13     public String url = "jdbc:mysql://127.0.0.1:3306/htmldatacollection";
14     public String user = "root";
15     public String password = "root";
16     public Statement stmt = null;
17     public Connection conn = null;
18     
19     //创建一个插入数据的方法
20     public void datatoMySql(String insertSQl) {
21 
22         try {
23             try {
24                 Class.forName(driver).newInstance();
25             } catch (Exception e) {
26                 System.out.println("Unable to find the local driver");
27                 e.printStackTrace();
28             }
29             //创建连接
30             conn = DriverManager.getConnection(url, user, password);
31             //创建一个 Statement 对象来将 SQL 语句发送到数据库
32             stmt = conn.createStatement();
33         } catch (SQLException e) {
34             e.printStackTrace();
35         }
36         try {
37             //执行SQL 插入语句
38             stmt.executeUpdate(insertSQl);
39         } catch (SQLException e) {
40             e.printStackTrace();
41         }
42         try {
43             //执行完 停止执行语句
44             stmt.close();
45             //执行完关闭数据库连接
46             conn.close();
47         } catch (SQLException e) {
48             e.printStackTrace();
49         }
50     }
51 }

Main 主函数 用于数据输出

Main主函数

1 public class Main {
2     public static void main(String[] args) {
3          //在主函数里调用DataStorage类里的dataStore()方法
4         DataStorage ds = new DataStorage();
5         ds.dataStore();
6     }
7 }

好了 下面我们来执行下 看看结果

数据采集页面 http://www.footballresults.org/league.php?all=1&league=EngPrem

Html页面截图-初始阶段

MySql数据库截图-初始阶段

Html页面截图-结束阶段

MySql数据库截图-结束阶段

一共收集到 189条记录

MySql数据库显示 189 行数据


附上源代码下载

http://files.cnblogs.com/longwu/htmlDataStorage.zip

[转载]ASP.NET MVC把字符串格式化成URL的方法

mikel阅读(918)

[转载]ASP.NET MVC把字符串格式化成URL的方法 – 兔纸 – 博客园.

ASP.NET MVC把字符串格式化成URL的方法

ASP.NET MVC中URL Routing是一个很好的规范URL的方法.但有时候您也许会需要把指定的字符串格式化成正常和安全的URL.我们都知道,一般域名注册的要求是只能有 数字.字母和横线的,而我们常常会用到数据库中的信息作为Url中的一部分比如定位到文章作者页面的时候,常常会把作者的名字包含进去.

假如作者的名字叫tu zhi. 作者信息页面的URL假设是这样:<a href=”http://www.cnblogs.com/tu zhi”>兔纸</a>,其中tu zhi是从数据中取得的作者名称.

如果我们请求这条链接的时候,我们发现跳转后的地址是这样的:http://www.cnblogs.com/tu%20zhi 这样URL就会显得非常的不美观,也显得不规范.我们的目标是把它转换成http://www.cnblogs.com/tu-zhi 如果您说这也没什 么啊?我看%20就比较好看, 那么当作者姓名为tu&zhi的时候是什么情况呢? 有兴趣的话您可以试试看,闲话不多说了,直接进入正题.

对这种字符串的处理方法很简单,一个方法足矣:

        /// <summary> 
        /// 转换成url 
        /// </summary> 
        /// <param name="text">文本</param>
        /// <returns>url字符</returns> 
        public static string ToUrlName(this string text)
        {
            if (text == null)
                throw new Exception("Can't Url convert a null string.");  //为空时不能转换
            var result = text.Trim().Replace(" ", "-");  //转换
            var replacer = new Regex(@"[^\w\-]", RegexOptions.Compiled);  //正则表达式
            result = replacer.Replace(result, "").ToLower();
            return result;
        }

调用的时候就可以这样:

string author = Strings.ToUrlName("tu zhi");

好了,这篇文章到此就结束了,希望对您有一点小小的帮助. 下篇文章会介绍一些自定义的HtmlHelper扩展.如果您感兴趣可以继续关注兔纸的文章.

[转载]总结一下ERP .NET程序员必须掌握的.NET技术

mikel阅读(726)

[转载]总结一下ERP .NET程序员必须掌握的.NET技术,掌握了这些技术工作起来才得心应手 – James Li – 博客园.

从毕业做.NET到现在,有好几年了,自认为只能是达到熟练的水平,谈不上精通。所以,总结一下,自己到底熟练掌握了哪些.NET方面的开发技术,以此对照,看看还有哪些不足,欢迎补充。

1 .NET Framework常见的API要熟练掌握。有些API可能需要多个类型配合使用,也有必要掌握。

IEntity2 clonedEntity = null;
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream memStream = new MemoryStream())
{
         formatter.Serialize(memStream, sourceEntity);
          memStream.Seek(0, SeekOrigin.Begin);
          clonedEntity = (IEntity2)formatter.Deserialize(memStream);
}

这个例子是.NET的深拷贝(deep copy)的实现,类似于这样的例子,还有很多。这些API的组合应用是需要掌握的。经过积累后,通常都会有自己的一个Utility类型库。

2 Linq to Object。虽然Linq to SQL已经被抛弃和遗忘,但是Linq to Object还真是一项很重要的技术。如果没有这项技术,数据的查找和操作的代码会被foreach充满,这样不容易维护,而且有很多代码都是 routine代码,可以省略的。

string[] names = { "Tom","Dick","Harry","Mary","Jay" };
IEnumerable<string> query =
                 from    n in names
      where   n.Contains ("a")  // Filter elements
      orderby n.Length          // Sort elements
      select  n.ToUpper( );     // Project each element

foreach (string name in query)
     Console.Write (name + "/");

同时,与Linq搭配的技术Lambda技术,可以简化很多代码,这也需要掌握,上面的例子用Lambda技术改写一下

string[] names = { "Tom","Dick","Harry","Mary","Jay" };
IEnumerable<string> query = names
      .Where   (n => n.Contains ("a"))
      .OrderBy (n => n.Length)
      .Select  (n => n.ToUpper( ));

foreach (string name in query)
     Console.Write (name + "|");

曾经有个非常流行的考试题目,考察委托的三种写法,举例如下所示

List<int> list = new List<int>();
list.AddRange(new int[] { 1, 5, 10, 20 ,33 });

//使用传统委托语法调用FindAll
Predicate<int> callback = new Predicate<int>(IsEvenNumber);
List<int> evenNumbers = list.FindAll(callback);

//使用匿名方法
List<int> evenNumbers = list.FindAll(
               delegate(int i)
                {
                    return (i % 2) == 0;
                });

//使用Lambda表达式
List<int> evenNumbers = list.FindAll(i => (i % 2) == 0);
(代码来自于LINQ之路 3:C# 3.0的语言功能(下)

3  .NET 4引入了新的并行编程库。这项技术不同于多线程技术,它是适应多核时代的需要。来看下面的例子程序

static double ParallelPi()
{
        double sum = 0.0;
        double step = 1.0 / (double)num_steps;
        object monitor = new object();
        Parallel.For(0, num_steps, () => 0.0, (i, state, local) =>
        {
            double x = (i + 0.5) * step;
            return local + 4.0 / (1.0 + x * x);
        }, local => { lock (monitor) sum += local; });
        return step * sum;
}

有了新面的Lambda表达式基础,这个例子也不难读懂。这是用并行库求PI的值。

.NET 4还引入了动态语言,如下的例子所示,Python的例子

ScriptRuntime py = Python.CreateRuntime();
//Dynamic feature only works on objects typed as 'dynamic'
dynamic helloworld = py.UseFile("helloworld.py");
Console.WriteLine("helloworld.py loaded!");

for (int i = 0; i < 1000; i++)
{
       Console.WriteLine(helloworld.welcome("Employee #{0}"), i);
}

//Python的代码
def welcome(name):
    return "Hello '" + name + "' from IronPython"

如果要改善.NET程序的性能,可以考虑使用.NET并行库。如果你在寻找脚本语言,可以寄宿到.NET中方便调用,这里的Python应该是一个 很好的开始。对于.NET框架直接内置的技术,必定会有大量的第三方工具,产品来对它做Enhancement或Extension,你可以找到很称手的 工具,为你的项目增加灵活性和改善性能。

4 ORM开发技术。可以选择NHibernate,也可以选择Entity Framework。ORM技术可以让你的代码专注于业务逻辑,大大简化数据访问代码的编码与调试。此外,ORM技术支持界面与逻辑分离,强类型的数据绑 定,这些好处,都可以给你的项目增加灵活性。比如保存客户的代码,用ORM技术写,是这样的

using (DataAccessAdapterBase adapter =GetDataAccessAdapter())
{
    try
    {
        adapter.StartTransaction(IsolationLevel.ReadCommitted, "SaveCustomer");
        adapter.SaveEntity(Customer, true, false);
        adapter.Commit();
    }
    catch
    {
        adapter.Rollback();
        throw;
    }
}

可不能小看了这几句,首先它是用代码生成器生成的,其次,对于增改数据库字段,这里不用作任何的修改,再次,界面的变动和业务逻辑的变动,也不会影响到这里。就这几项好处,可以节约大量的时间,让你专注于业务逻辑。

5  分布式的通讯技术。.NET Remoting和WCF,至少要掌握一项才行。

6  界面组件包。.NET 框架自带的界面控件虽然简单好用,但不够强大。所以,推荐你选购一套流行的界面控件,为你的项目增加可读性。虽然都是说界面不重要,逻辑重要,但是我们心 里也明白,界面看起来惨不忍睹,再好的逻辑和架构也也不会被客户接受。界面要做到简单,实用,说起起容易,做起来可相当不容易。这里可以选择的控件比较 多,Infragistics,Syncfusion,ComponentOne,都是很著名的控件供应商。

[转载]XmlAttribute与实体的转换和匹配方案(附源码)

mikel阅读(1094)

[转载]XmlAttribute与实体的转换和匹配方案(附源码) – JasenKin – 博客园.

一、前言

可扩 展标记语言 (XML) 是具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML是用来存储数据的,重在数据本身。本 文中的代码是几个月前整理的,最近几个月的时间很少写随笔,除了工作以外,主要还是忙于整理自己的框架。这篇随笔主要是针对于XML的特性 Attribute与实体之间的匹配与转换,其中的内容包括反射、XML以及LinqToXml,代码的内容也是想到什么就写什么,纯属练习下手感,仅供 参考。下一篇随笔将以另外的形式来转换Xml为对象实体,当然,也是以反射为主,和本随笔中的思路差不多,主要是XML的格式和解决方案不同而已。对于如 何将对象转换成Xml的话,主要还是看情况,仅仅转换简单的对象的话,直接反射就可以生成。对于复杂的对象的话,可以采用dynamic,树结构和递归算 法的方案来定制XML。

二、类图设计

该处的主要思路为:通过反射将与类名(类特性名称或者类名)的节点匹配,然后匹配属性(属性特性名称或者属性名称)值。反之,则遍历实体对象的属性,设置 相应的XML。本来还想细化一下匹配与转换操作的,但是该类的EA文件不知道放在哪里了,只有设计的截图还在,XO。相关类图设计如下:

PropertyAttribute主要设置属性的特性名称,用于转换过程设置属性的别名,同时匹配过程中匹配XML的特性与属性的名称。

ClassAttribute主要设置类的特性名称,用于转换过程设置类的别名,同时匹配过程中匹配XML的节点与类的名称。

StringExtension主要是字符串的扩展方法。

FuncDictionary主要转换字符串为特定类型的值。

XmlAttributeUtility主要转换实体对象为XML以及匹配XML为实体对象,其中还包括一些其他基本操作。

三、具体实现

先看下FuncDictionary,该类主要通过异步委托将字符串转换成相应的简单类型,所有实现围绕该类进行相关操作。FuncDictionary基本涵盖了C#中的所有简单类型,可以将字符串转换成这些简单类型。

主要方法为:public object DynamicInvoke(Type type, string arg),通过传入的类型和字符串值,可以转换成相应的Object值。属性Dictionary中涵盖了所有简单类型转换的委托操作。代码如下:
1 public class FuncDictionary
2 {
3 public static IDictionary<Type, Delegate> Dictionary
4 {
5 get;
6 private set;
7 }
8
9 static FuncDictionary()
10 {
11 if (FuncDictionary.Dictionary == null)
12 {
13 FuncDictionary.Dictionary = CreateDictionary();
14 }
15 }
16
17 public object DynamicInvoke(Type type, string arg)
18 {
19 if (type == null)
20 {
21 return null;
22 }
23
24 if (FuncDictionary.Dictionary == null)
25 {
26 FuncDictionary.Dictionary = CreateDictionary();
27 }
28
29 if (!FuncDictionary.Dictionary.ContainsKey(type))
30 {
31 return null;
32 }
33
34 Delegate action = FuncDictionary.Dictionary[type];
35
36 return action.DynamicInvoke(new object[] { arg });
37 }
38
39 public static IDictionary<Type, Delegate> CreateDictionary()
40 {
41 var dictionary = new Dictionary<Type, Delegate>();
42
43 dictionary.Add(typeof(string), new Func<stringstring>(p => p));
44 dictionary.Add(typeof(decimal), new Func<stringdecimal>(p => p.AsDecimal()));
45 dictionary.Add(typeof(DateTime), new Func<string, DateTime>(p => p.AsDateTime()));
46 dictionary.Add(typeof(float), new Func<stringfloat>(p => p.AsFloat()));
47 dictionary.Add(typeof(double), new Func<stringdouble>(p => p.AsDouble()));
48 dictionary.Add(typeof(int), new Func<stringint>(p => p.AsInt()));
49 dictionary.Add(typeof(byte), new Func<stringbyte>(p => p.AsByte()));
50 dictionary.Add(typeof(sbyte), new Func<stringsbyte>(p => p.AsSbyte()));
51 dictionary.Add(typeof(short), new Func<stringshort>(p => p.AsShort()));
52 dictionary.Add(typeof(ushort), new Func<stringushort>(p => p.AsUshort()));
53 dictionary.Add(typeof(uint), new Func<stringuint>(p => p.AsUint()));
54 dictionary.Add(typeof(long), new Func<stringlong>(p => p.AsLong()));
55 dictionary.Add(typeof(ulong), new Func<stringulong>(p => p.AsUlong()));
56 dictionary.Add(typeof(char), new Func<stringchar>(p => p.AsChar()));
57 dictionary.Add(typeof(bool), new Func<stringbool>(p => p.AsBool()));
58 dictionary.Add(typeof(Color), new Func<string, Color>(p => p.AsColor()));
59
60 return dictionary;
61 }
62 }

再看下XmlAttributeUtility类,该类主要包括转换和匹配操作。匹配主要为两种方案(主要逻辑为以下代码的72-183行):

1、通过XmlReader顺序读取来设置实体的值,主要方法为public static IList<T> Parse<T>(XmlReader reader) where T : new():

2、通过遍历XmlNodeList中的节点,依次遍历节点中的XmlAttribute设置实体的属性的值,主要方法为: public static IList<T> Parse<T>(XmlNodeList nodeList) where T : new()

1 public static IList<T> Parse<T>(string inputUri, string parentXPath) where T : new()
2 {
3 if (!File.Exists(inputUri) || string.IsNullOrWhiteSpace(parentXPath))
4 {
5 return new List<T>();
6 }
7
8 XmlDocument document = new XmlDocument();
9 document.Load(inputUri);
10
11 return Parse<T>(document, parentXPath);
12 }
13
14 public static IList<T> Parse<T>(XmlDocument document, string parentXPath) where T : new()
15 {
16 if (document == null || string.IsNullOrWhiteSpace(parentXPath))
17 {
18 return new List<T>();
19 }
20
21 XmlNode parentNode = document.DocumentElement.SelectSingleNode(parentXPath);
22
23 if (parentNode == null)
24 {
25 return new List<T>();
26 }
27
28 return Parse<T>(parentNode);
29 }
30
31 public static IList<T> Parse<T>(XmlNode parentNode) where T : new()
32 {
33 if (parentNode == null || !parentNode.HasChildNodes)
34 {
35 return new List<T>();
36 }
37
38 XmlNodeList nodeList = parentNode.ChildNodes;
39
40 return Parse<T>(nodeList);
41 }
42
43 public static IList<T> Parse<T>(XmlNodeList nodeList) where T : new()
44 {
45 if (nodeList == null || nodeList.Count == 0)
46 {
47 return new List<T>();
48 }
49
50 List<T> entities = new List<T>();
51 AddEntities<T>(nodeList, entities);
52
53 return entities;
54 }
55
56 public static IList<T> Parse<T>(string inputUri) where T : new()
57 {
58 if (!File.Exists(inputUri))
59 {
60 return new List<T>();
61 }
62
63 XmlReaderSettings settings = new XmlReaderSettings();
64 settings.IgnoreComments = true;
65 settings.IgnoreWhitespace = true;
66
67 XmlReader reader = XmlReader.Create(inputUri, settings);
68
69 return Parse<T>(reader);
70 }
71
72 public static IList<T> Parse<T>(XmlReader reader) where T : new()
73 {
74 if (reader == null)
75 {
76 return new List<T>();
77 }
78
79 reader.ReadStartElement();
80 string className = GetClassName<T>();
81 List<PropertyInfo> properties = typeof(T).GetProperties().ToList();
82 List<T> entities = new List<T>();
83 T entity = new T();
84
85 while (!reader.EOF)
86 {
87 if (!string.Equals(reader.Name, className) || !reader.IsStartElement())
88 {
89 reader.Read();
90 continue;
91 }
92
93 entity = new T();
94
95 if (!reader.HasAttributes)
96 {
97 entities.Add(entity);
98 reader.Read();
99 continue;
100 }
101
102 SetPropertyValue<T>(reader, properties, entity);
103 entities.Add(entity);
104 reader.Read();
105 }
106
107 reader.Close();
108
109 return entities;
110 }
152
153 private static void AddEntities<T>(XmlNodeList nodeList,
154 List<T> entities) where T : new()
155 {
156 string className = GetClassName<T>();
157 List<PropertyInfo> properties = typeof(T).GetProperties().ToList();
158 T entity = new T();
159
160 foreach (XmlNode xmlNode in nodeList)
161 {
162 XmlElement element = xmlNode as XmlElement;
163 if (element == null || !string.Equals(className, element.Name))
164 {
165 continue;
166 }
167
168 entity = new T();
169 if (!element.HasAttributes)
170 {
171 entities.Add(entity);
172 continue;
173 }
174
175 XmlAttributeCollection attributes = element.Attributes;
176 foreach (XmlAttribute attribute in attributes)
177 {
178 SetPropertyValue<T>(properties, entity, attribute.Name, attribute.Value);
179 }
180
181 entities.Add(entity);
182 }
183 }
184
185 private static void SetPropertyValue<T>(XmlReader reader,
186 List<PropertyInfo> properties, T entity) where T : new()
187 {
188 while (reader.MoveToNextAttribute())
189 {
190 SetPropertyValue<T>(properties, entity, reader.Name, reader.Value);
191 }
192 }
193
194 private static void SetPropertyValue<T>(List<PropertyInfo> properties,
195 T entity, string name, string value) where T : new()
196 {
197 foreach (var property in properties)
198 {
199 if (!property.CanWrite)
200 {
201 continue;
202 }
203
204 string propertyName = GetPropertyName(property);
205
206 if (string.Equals(name, propertyName))
207 {
208 FuncDictionary action = new FuncDictionary();
209 object invokeResult = action.DynamicInvoke(property.PropertyType, value);
210
211 property.SetValue(entity, invokeResult, null);
212 }
213 }
214 }
XmlAttributeUtility的转换操作相对来说比较简单,采用反射+LinqToXml转换操作就很简单了,主要实现方法为public static XElement Convert<T>(T entity) where T : new(),其他方法都是以该方法作为基础来进行操作。为什么用LinqToXml?主要原因是LinqToXml比Xml更方便,很多细节方面不需要考虑太多。代码如下:
1 public static string ConvertToString<T>(List<T> entities) where T : new()
2 {
3 List<XElement> elements = Convert<T>(entities);
4 if (elements == null || elements.Count == 0)
5 {
6 return string.Empty;
7 }
8
9 StringBuilder builder = new StringBuilder();
10 elements.ForEach(p => builder.AppendLine(p.ToString()));
11
12 return builder.ToString();
13 }
14
15 public static List<XElement> Convert<T>(List<T> entities) where T : new()
16 {
17 if (entities == null || entities.Count == 0)
18 {
19 return new List<XElement>();
20 }
21
22 List<XElement> elements = new List<XElement>();
23 XElement element;
24
25 foreach (var entity in entities)
26 {
27 element = Convert<T>(entity);
28 if (element == null)
29 {
30 continue;
31 }
32
33 elements.Add(element);
34 }
35
36 return elements;
37 }
38
39 public static string ConvertToString<T>(T entity) where T : new()
40 {
41 XElement element = Convert<T>(entity);
42 return element == nullstring.Empty : element.ToString();
43 }
44
45 public static XElement Convert<T>(T entity) where T : new()
46 {
47 if (entity == null)
48 {
49 return null;
50 }
51
52 string className = GetClassName<T>();
53 XElement element = new XElement(className);
54
55 List<PropertyInfo> properties = typeof(T).GetProperties().ToList();
56 string propertyName = string.Empty;
57 object propertyValue = null;
58
59 foreach (PropertyInfo property in properties)
60 {
61 if (property.CanRead)
62 {
63 propertyName = GetPropertyName(property);
64 propertyValue = property.GetValue(entity, null);
65 if (property.PropertyType.Name == Color)
66 {
67 propertyValue = ColorTranslator.ToHtml((Color)propertyValue);
68 }
69 element.SetAttributeValue(propertyName, propertyValue);
70 }
71 }
72
73 return element;
74 }

该类中还包括其他的一些操作,此处不再概述,详细参见源码。

四、单元测试

FuncDictionary 的单元测试必须涵盖所有类型的测试才能将代码覆盖率达到100%,此处只针对DateTime做正常测试、异常测试和空值测试(当然,对于其他类型的方 法,可能还需要做脚本测试,SQL注入测试等,这三种类型的测试是最基本的测试),主要测试代码如下:

1 [TestMethod()]
2 public void DynamicInvokeTest()
3 {
4 FuncDictionary target = new FuncDictionary();
5 Type type = typeof(DateTime);
6 string arg = new DateTime(201195181818).ToString();
7
8 DateTime result = (DateTime)target.DynamicInvoke(type, arg);
9 Assert.AreEqual(result.Year, 2011);
10 Assert.AreEqual(result.Month, 9);
11 Assert.AreEqual(result.Day, 5);
12 Assert.AreEqual(result.Hour, 18);
13 Assert.AreEqual(result.Minute, 18);
14 Assert.AreEqual(result.Second, 18);
15 }
16
17 [TestMethod()]
18 public void DynamicInvokeWithNullOrEmptyArgsTest()
19 {
20 FuncDictionary target = new FuncDictionary();
21
22 object result = target.DynamicInvoke(typeof(DateTime), null);
23 Assert.AreEqual((DateTime)result,DateTime.MinValue);
24
25 result = target.DynamicInvoke(typeof(DateTime), string.Empty);
26 Assert.AreEqual((DateTime)result, DateTime.MinValue);
27
28 result = target.DynamicInvoke(nullstring.Empty);
29 Assert.AreEqual(result, null);
30 }
31
32 [TestMethod()]
33 public void DynamicInvokeWithInvalidArgsTest()
34 {
35 FuncDictionary target = new FuncDictionary();
36
37 object result = target.DynamicInvoke(typeof(DateTime), w007);
38 Assert.AreEqual((DateTime)result, DateTime.MinValue);
39 }

其他代码的单元测试详细见源代码,也仅仅只做了些基本的测试,写测试比写代码费哥的时间,

五、总结

以上的代码仅仅是当时想着怎么实现就怎么写的,完全是随意而写。仅供参考,实战没有多大意义,纯粹练习下灵感和手感,增强对技术的敏感性而已,纯属娱乐。对于

<Lexer LexerName=”Name0″ FontColor=”#EE2BA9″ CreatedTime=”2011-10-25T21:16:18.7866084+08:00″ Count=”0″ Exist=”true” LineCommentPrefix=”LineCommentPrefix0″ StreamCommentPrefix=”StreamCommentPrefix0″ StreamCommentSuffix=”StreamCommentSuffix0″ />此类格式的Xml转换和匹配,以上的代码完全能够满足该需求。下一篇将讲述另外一种格式的匹配,不过也是通过反射和XmlReader来进行匹 配的。

今天也是2011年最后一天,明天就是2012年了,在此恭祝大家2012元旦快乐,新一年,日子顺心多平安;新一年,祝福多多又暖暖;新一年,愿望件件都圆满;新一年,幸福快乐早实现;新一年,元旦祝福围身边;玛雅终结之年到了,所以,为了拯救人类,一定要快乐哦!

源码下载:XmlAttribute转换和匹配源代码

[转载]T-SQL查询进阶--理解SQL SERVER中的分区表

mikel阅读(1153)

[转载]T-SQL查询进阶–理解SQL SERVER中的分区表 – CareySon – 博客园.

简介


分区表是在SQL SERVER2005之后的版本引入的特性。这个特性允许把逻辑上的一个表在物理上分为很多部分。而对于SQL SERVER2005之前版本,所谓的分区表仅仅是分布式视图,也就是多个表做union操作.

分区表在逻辑上是一个表,而物理上是多个表.这意味着从用户的角度来看,分区表和普通表是一样的。这个概念可以简单如下图所示:

1

而对于SQL SERVER2005之前的版本,是没有分区这个概念的,所谓的分区仅仅是分布式视图:

3

本篇文章所讲述的分区表指的是SQL SERVER2005之后引入的分区表特性.

为什么要对表进行分区


在回答标题的问题之前,需要说明的是,表分区这个特性只有在企业版或者开发版中才有,还有理解表分区的概念还需要理解SQL SERVER中文件和文件组的概念.

对表进行分区在多种场景下都需要被用到.通常来说,使用表分区最主要是用于:

  • 存档,比如将销售记录中1年前的数据分到一个专门存档的服务器中
  • 便于管理,比如把一个大表分成若干个小表,则备份和恢复的时候不再需要备份整个表,可以单独备份分区
  • 提高可用性,当一个分区跪了以后,只有一个分区不可用,其它分区不受影响
  • 提高性能,这个往往是大多数人分区的目的,把一个表分布到不同的硬盘或其他存储介质中,会大大提升查询的速度.

分区表的步骤


分区表的定义大体上分为三个步骤:

  1. 定义分区函数
  2. 定义分区构架
  3. 定义分区表

分区函数,分区构架和分区表的关系如下:

2

分区表依赖分区构架,而分区构架又依赖分区函数.值得注意的是,分区函数并不属于具体的分区构架和分区表,他们之间的关系仅仅是使用关系.

下面我们通过一个例子来看如何定义一个分区表:

假设我们需要定义的分区表结构如下:

4

第一列为自增列,orderid为订单id列,SalesDate为订单日期列,也就是我们需要分区的依据.

下面我们按照上面所说的三个步骤来实现分区表.

定义分区函数


分区函数是用于判定数据行该属于哪个分区,通过分区函数中设置边界值来使得根据行中特定列的值来确定其分区,上面例子中,我们可以通过SalesDate 的值来判定其不同的分区.假设我们想定义两个边界值(boundaryValue)进行分区,则会生成三个分区,这里我设置边界值分别为 2004-01-01和2007-01-01,则前面例子中的表会根据这两个边界值分成三个区:

5

在MSDN中,定义分区函数的原型如下:

CREATE PARTITION FUNCTION partition_function_name ( input_parameter_type )
AS RANGE [ LEFT | RIGHT ] 
FOR VALUES ( [ boundary_value [ ,...n ] ] ) 
[ ; ]

通过定义分区函数的原型,我们看出其中并没有具体涉及具体的表.因为分区函数并不和具体的表相绑定.上面原型中还可以看到Range left和right.这个参数是决定临界值本身应该归于“left”还是“right”:

6

下面我们根据上面的参数定义分区函数:

7

通过系统视图,可以看见这个分区函数已经创建成功

定义分区构架


定义完分区函数仅仅是知道了如何将列的值区分到了不同的分区。而每个分区的存储方式,则需要分区构架来定义.使用分区构架需要你对文件和文件组有点了解.

我们先来看MSDN的分区构架的原型:

CREATE PARTITION SCHEME partition_scheme_name
AS PARTITION partition_function_name
[ ALL ] TO ( { file_group_name | [ PRIMARY ] } [ ,...n ] )
[ ; ]

从原型来看,分区构架仅仅是依赖分区函数.分区构架中负责分配每个区属于哪个文件组,而分区函数是决定如何在逻辑上分区:

8

基于之前创建的分区函数,创建分区构架:

9

定义分区表


接下来就该创建分区表了.表在创建的时候就已经决定是否是分区表了。虽然在很多情况下都是你在发现已经表已经足够大的时候才想到要把表分区,但是分区表只能够在创建的时候指定为分区表。

10

为刚建立的分区表PartitionedTable加入5万条测试数据,其中SalesDate随机生成,从2001年到2010年随机分布.加入数据后,我们通过如下语句来看结果:

select convert(varchar(50), ps.name) as partition_scheme,
p.partition_number, 
convert(varchar(10), ds2.name) as filegroup, 
convert(varchar(19), isnull(v.value, ''), 120) as range_boundary, 
str(p.rows, 9) as rows
from sys.indexes i 
join sys.partition_schemes ps on i.data_space_id = ps.data_space_id 
join sys.destination_data_spaces dds
on ps.data_space_id = dds.partition_scheme_id 
join sys.data_spaces ds2 on dds.data_space_id = ds2.data_space_id 
join sys.partitions p on dds.destination_id = p.partition_number
and p.object_id = i.object_id and p.index_id = i.index_id 
join sys.partition_functions pf on ps.function_id = pf.function_id 
LEFT JOIN sys.Partition_Range_values v on pf.function_id = v.function_id
and v.boundary_id = p.partition_number - pf.boundary_value_on_right 
WHERE i.object_id = object_id('PartitionedTable')
and i.index_id in (0, 1) 
order by p.partition_number

可以看到我们分区的数据分布:

11

分区表的分割


分区表的分割。相当于新建一个分区,将原有的分区需要分割的内容插入新的分区,然后删除老的分区的内容,概念如下图:

假设我新加入一个分割点:2009-01-01,则概念如下:

12

通过上图我们可以看出,如果分割时,被分割的分区3内有内容需要分割到分区4,则这些数据需要被复制到分区4,并删除分区3上对应数据。

这种操作非常非常消耗IO,并且在分割的过程中锁定分区三内的内容,造成分区三的内容不可用。不仅仅如此,这个操作生成的日志内容会是被转移数据的4倍!

所以我们如果不想因为这种操作给客户带来麻烦而被老板爆菊的话…最好还是把分割点建立在未来(也就是预先建立分割点),比如2012-01-01。则分区3内的内容不受任何影响。在以后2012的数据加入时,自动插入到分区4.

分割现有的分区需要两个步骤:

1.首先告诉SQL SERVER新建立的分区放到哪个文件组

2.建立新的分割点

可以通过如下语句来完成:

13

如果我们的分割构架在定义的时候已经指定了NEXT USED,则直接添加分割点即可。

通过文中前面查看分区的长语句..再来看:

14

新的分区已经加入!

分区的合并


分区的合并可以看作分区分割的逆操作。分区的合并需要提供分割点,这个分割点必须在现有的分割表中已经存在,否则进行合并就会报错

假设我们需要根据2009-01-01来合并分区,概念如下:

15

只需要使用merge参数:

16

再来看分区信息:

17

这里值得注意的是,假设分区3和分区4不再一个文件组,则合并后应该存在哪个文件组呢?换句话说,是由分区3合并到分区4还是由分区4合并到分区3?这个 需要看我们的分区函数定义的是left还是right.如果定义的是left.则由左边的分区3合并到右边的分区4.反之,则由分区4合并到分区3:

18

总结


本文从讲解了SQL SERVER中分区表的使用方式。分区表是一个非常强大的功能。使用分区表相对传统的分区视图来说,对于减少DBA的管理工作来说,会更胜一筹!

[转载]Android之生成桌面快捷方式(一)

mikel阅读(818)

[转载]Android之生成桌面快捷方式(一) – 华德飞 – 博客园.

生成快捷方式有两种情况,一种是直接在桌面直接生成;一种是长按桌面,在弹出的快捷菜单中生成。

谈谈在桌面上直接生成。个人觉得这个比较爽快,既然都是快捷方式了干嘛还要再隐藏一层呢?当然喜欢桌面干净的就比较喜欢第二个了。

第一个是通过广播(Broadcast)的形式向Luncher发送请求生成快捷方式的。

在网上找到关于这方面的注册信息。

InstallShortcutReceiver的注册信息:

 <!--设置wallpapaer的activity -->
        <!-- Intent received used to install shortcuts from other applications -->
        <receiver
            android:name="com.android.launcher2.InstallShortcutReceiver"
            android:permission="com.android.launcher.permission.INSTALL_SHORTCUT">
            <intent-filter>
                <action android:name="com.android.launcher.action.INSTALL_SHORTCUT" />
            </intent-filter>
        </receiver>

可以看出,要在桌面上创建快捷方式就需要权限了:

android:permission="com.android.launcher.permission.INSTALL_SHORTCUT。

所以在我们的manifest.xml文件中,我们需要加入下面这段话:

<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>

下面就是代码层的实现:

假如我在一个activity中创建一个创建快捷方式的方法:createShortCut();

public void createShortCut(){
//创建快捷方式的Intent
                Intent shortcutintent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
                //不允许重复创建
                shortcutintent.putExtra("duplicate", false);
                //需要现实的名称
                shortcutintent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(R.string.shortcutname));
                //快捷图片
                Parcelable icon = Intent.ShortcutIconResource.fromContext(getApplicationContext(), R.drawable.icon);
                shortcutintent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon);
                //点击快捷图片,运行的程序主入口
                shortcutintent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent(getApplicationContext() , EnterActivity.class));
                //发送广播。OK
                sendBroadcast(shortcutintent);
}


[转载]搞清如何使用oAuth 1.0 & 1.0a

mikel阅读(1026)

[转载]搞清如何使用oAuth 1.0 & 1.0a – youxiachai – 博客园.

前言

看这篇博文的朋友,我建议先去了解一下什么是 oAuth 1.0 & 2.0的认证,对于,一些很基本的概念,各大提供该认证的网站应该说的很清楚了,这篇博文是比较细的说下,在oAuth 认证时遇到的问题,以及整个认证客户端api调用的过程

我说下,目前我知道的提供oAuth 认证的网站(墙外的这里就不提了),大家如果想补充的话,我非常欢迎.

oAuth 1.0 || 1.0a

豆瓣

http://www.douban.com/service/

腾讯

http://open.t.qq.com/home/

360开发者平台

http://open.app.360.cn/

网易开放平台

http://open.t.163.com/

搜狐开放平台

http://open.t.sohu.com/

oAuth 2.0

新浪微博

http://open.weibo.com/

百度链接

http://dev.baidu.com/connect/

人人网

http://dev.renren.com/

360开发者平台

http://open.app.360.cn/

以上是我知道是使用oAuth 认证的的开放平台,特别说一下,oAuth 1.0爆发了 一个漏洞,所以就会有个oAuth 1.0a的版本,至于oAuth 1.0 和 oAuth 2.0 的区别?自己百度一下吧.

以上网站,我基本都比较过了,oAuth 2.0的操作简化了很多(墙外对这个oAuth2.0 支持得还是不错的),方便了很多,而且新浪那个例子写得很不错,所以,我这篇博文,并不打算说oAuth 2.0,因为,之前我还写了一个JQuery Mobile 的教程,打算做一个项目来贯通所有知识点,我选用的是豆瓣API,由于,豆瓣API提供的PHP框架实在够庞大,而且,我用的免费空间商肯定是不支持那个 框架,当然,最近,豆瓣上有人开源了一个PHP的豆瓣API框架,不过,等到我知道的时候,我已经把oAuth 部分的代码写好了,

这里,我就分享一下我使用oAuth 1.0 api 的经验

第一步: 获取未授权的Request Token

整个oAuth 最麻烦的的就是构建算法体系,豆瓣在这方面是直接给了一个开源库给我们参考

http://code.google.com/p/oauth/

腾 讯的文档有对整个算法的伪码解释,不过,我个人建议,还是下载开源库直接参考,我看了一下,国内的开放平台对签名的算法一般都支持HAMC-SHA1,有 些,例如腾讯就只支持HMAC-SHA1,所以,我个人建议,看HMAC-SHA1算法就足够了.我提供的开源库在最困难的签名算法部分都已经进行实现, 所以说,可以随便使用.

好了到编码部分:

oAuth 1.0a ,目前大部分的用oAuth 1.0 版本认证开放平台的用的版本

不 过,开源库里面用的还是oAuth 1.0 的标准对于callback 没有必要性的要求,所以代码在创建oAuthconsumer时构对callback 没有做强制要求,但是,我们现在的oAuth 1.0 在第一步中是就必须要求这个参数,我测试了一下,在腾讯开放平台中,不加callback参数是肯定访问不了,在豆瓣API中就算第一步没要求加 callback 即使加上了也没有关系.

用PHP代码实现 Request Token 的链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php require_once 'OAuth.php';
$request_token_url = ‘https://open.t.qq.com/cgi-bin/request_token’;
//从服务商获取的API KEY
$key = ‘xxxxxx’;
$secret = ‘sssss’;
$callback =’null’; //这个在oAuth 1.0标准中不强制要求,也是漏洞的所在,不过这个漏洞的成功率极低.. 在oAuth1.0 a 这个参数是必须的
//生成消费方
$consumer = new OAuthConsumer($key,$secret,$callback);
//生成签名用链接
$req_token_url = OAuthRequest::from_consumer_and_token($consumer,NULL,”GET”,$request_token_url);
//进行链接签名
$req_token_url->sign_request($sig_method,$consumer,NULL);
//打印出我们的链接
echo $req_token_url->to_url();
//进行链接签名
$req_token_url->sign_request($sig_method,$consumer,NULL);
//打印出我们的链接
echo $req_token_url->to_url();?>

这里还算比较简单的,如果是

豆瓣的返回信息:

oauth_token=xxxxxxx&oauth_token_secret=xxxxxxx

腾讯的返回信息:

oauth_token=xxxxxxx&oauth_token_secret=xxxxxxx&oauth_callback_confirmed=true

这里要记住的是oauth_token_secret 记得好好保存,因为在第三步的时候是必须的!

在第二步授权完毕后

在第三步要与授权的oauth_token组成新的消费方.

第二步:请求用户授权Request Token

这一步比较简单…上PHP代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
$authorize_url = “https://open.t.qq.com/cgi-bin/authorize”;
$oauth_token =’上一步中获取的oauth_token’;
//以下是可选参数,成功授权后带参数跳转到相应页面,具体参见服务商
//豆瓣>
$callback = ‘www.yourapp.com’;
//腾讯的
$wap =’’
//参数如有特殊字符需要urlEncode ,带链接的请求这步是必须的
$params = array();
$params[‘oauth_token’]=$oauth_token;
$params[‘callback’] = $callback; //根据自己的需要更改.
//生成用户授权链接
$url = $authorize_url.’?”.http_build_query($params);
echo $url;
?>

拷到浏览器就会跳转到授权页面

豆瓣的话,就是授权成功了

腾讯的话,还带了验证码,这个要认真阅读文档!!!!

第三步:使用授权后的Request Token换取Access Token

授权成功以后,如果是oAuth 1.0 就十分方便..直接用第一步获得的oauth_token 和 oauth_token_secret 组成一个oAuthToken 添加到第一步的那个null参数里面就可以取得那个用于获取access token 的链接

如果是用豆瓣的话你只需这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
require_once 'OAuth.php';
$access_token_url = ‘http://www.douban.com/service/auth/access_token’;
//从服务商获取的API KEY
$key = ‘xxxxxx’;
$secret = ‘sssss’;
// 第一步中获得的两个参数,确认在第二步中$oauth 获得授权以后才能够访问成功
$oauth = ‘xxxxx’;
$oauth_secret = ‘xxx’;
//生成 访问用的token
$token = new OAuthToken($oauth,$oauth_secret);
//生成消费方
$consumer = new OAuthConsumer($key,$secret);
//生成签名用链接$req_token_url = OAuthRequest::from_consumer_and_token($consumer,$token,”GET”,$request_token_url);
//进行链接签名
$req_token_url->sign_request($sig_method,$consumer,$token);
//打印出我们的链接
echo $req_token_url->to_url();
?>

拷到浏览器中,你就获取到我们用于访问用户资源的两个参数oauth_token 和 oauth_token_secret,豆瓣的话还会返回用户的ID.

腾讯的话,记得在授权的时候加上验证码,一样可以获得

对于Access Token 的期限.

一般而言,access token 的实效一般是用户取消授权才会失效,不过,听说也有有时效的,这个,我得去找找是哪家

总结

其实,这个认证各大服务商都提供了相应的SDK 让我们非常简单的使用他们提供的服务,只要填上APIKEY 剩下的就是客户授权的问题,要不是,豆瓣提供的PHP的 SDK,我准备用的空间商无法支持,我也懒得搞清楚是怎么认证的.oAuth 1.0 应该还能用很长一段时间,不过,oAuth 2.0 才是未来(墙外的基本都用 2.0 版本),听说,oAuth 2.0 在使用上简单了很多,看了一下新浪的的确如此,早知道,就不用豆瓣的了…哎….晚些时候,补上一个支持oAuth 1.0&1.0a 的demo,有或者直接看服务商的…

[转载]IIS启用Gzip的方法与优缺点分析

mikel阅读(957)

[转载]IIS启用Gzip的方法与优缺点分析 – Net之王 – 博客园.

现代的浏览器IE6和Firefox都支持客户端Gzip,也就是说,在服务器上的网页,传输之前,先使用Gzip压缩再传输给客户端,客户端接收之后由浏览器解压显示,这样虽然稍微占用了一些服务器和客户端的CPU,但是换来的是更高的带宽利用率。

现代的浏览器IE6和Firefox都支持客户端Gzip,也就是说,在服务器上的网页,传输之前,先使用Gzip压缩再传输给客户端,客户端接收 之后由浏览器解压显示,这样虽然稍微占用了一些服务器和客户端的CPU,但是换来的是更高的带宽利用率。对于纯文本来讲,压缩率是相当可观的。如果每个用 户节约50%的带宽,那么你租用来的那点带宽就可以服务多一倍的客户了。
IIS6已经内建了Gzip压缩的支持,可惜,没有设置更好的管理界面。所以要打开这个选项,还要费些功夫。
首先,如果你需要压缩静态文件(HTML),需要在硬盘上建一个目录,并给它“IUSR_机器名”这个用户的写权限。如果压缩动态文件 (PHP,asp,aspx)就不需要了,因为它的页面是每次都动态生成的,压缩完就放弃。然后在IIS管理器中,“网站”上面右键-属性,不是下面的某 个站点,而是整个网站。进入“服务”标签,选上启用动态内容压缩,静态内容压缩。
然后选中网站下面那个服务器扩展,新建一个服务器扩展。名字无所谓,下面的添加文件的路径是:
c:\windows\system32\inetsrv\gzip.dll,然后启用这个扩展。
这时候静态内容是可以压缩的,但是对于动态内容,aspx文件却不在压缩范围内。因为默认的可压缩文件并没有这个扩展名。而管理界面中你又找不到可以增加扩展名的地方,这时候只能去修改它的配置文件了。
在 c:\windows\system32\inetsrv\下面有个MetaBase.xml文件,可以用记事本打开,找到 IIsCompressionScheme,有三个相同名字的段,分别是deflate,gzip,Parameters,第三段不用管它,前两段有基本 相同的参数,在这两段的参数HcScriptFileExtensions下面都加上一行aspx,如果你有其它的动态程序要压缩,也加在这里。 HcDynamicCompressionLevel改成9,(0-10,9是性价比最高的一个)。
让Discuz速度再次提升 ——“开启IIS Gzip压缩”

以下方法将提升Discuz6.1压缩率0.33%,虽然很小,但对于一些访问量万以上的站点,将可能是一个速度上的飞跃(未尝试,所以是可能)。 这里之所以说Disczu6.1压缩率提升0.33%,因为以下测试是在Discuz6.1下进行的,其他的建站程序一样适用(但是,提升的百分比,就不 得而知了,欢迎大家测试)
注:通过提高压缩率,从而提升了用户浏览网站的速度。

【以下是实际的数据测试结果】
未开启任何Gzip时:

开启了Discuz6.1后台的Gzip压缩:

开启Windows2003 II6中Gzip压缩:

通过以上数据对比,似乎提高了 0.33% 不足以说明什么。个人觉得当是一个较大网站的时候(前提硬件满足),开启它会明显使速度提高。(提升速度的同时,就是牺牲系统资源,所以如果服务器的配置不是太好,需要调整相关参数)
以上数据来源于 http://www.pipeboost.com ,进入后在这个位置输入网址:

【如何配置II6中Gzip压缩?】
注:以下教程,部分不给予太多说明,只要按照以下配置,一般不会出现问题(由于自身在配置时,很顺利,如果有遇到问题,首先请详细核对步骤3次,如果都正确,依然问题存在的话,请回复告知)
如果你要进行测试或安装,请一个一个字认真阅读!

步骤一:
打开II6界面 > 选择“网站” > 右键属性 > 选择“服务”> 按照图中打钩
其中“临时目录的最大容量”与“临时目录”依据自身自行更改设置
特别注意,要给予临时目录 User权限(写入、修改、读取)

步骤二:
选择“Web服务扩展” > 在右侧空白处右“键新Web服务扩展” > 按照图输入相关
“设置扩展状态为可选”打钩
“添加文件”很可能由于每个人服务器配置不同,请自行搜索下(或者按照图中打入,看看是否存在)

步骤三:
开始 > 运行中输入 c:\windows\system32\inetsrv (如果错误,请按照图中输入)> 找到 MeteBase.xml
复制一份到桌面(并更改为 bak_MeteBase.xml),作为备份。

步骤四:
用文本等工具打开 MeteBase.xml > 搜索 Location =”/LM/W3SVC/Filters/Compression/gzip”
然后,你将看到如下代码(仔细核对下段落)
<IIsCompressionScheme Location =”/LM/W3SVC/Filters/Compression/deflate”
HcCompressionDll=”%windir%\system32\inetsrv\gzip.dll”
HcCreateFlags=”0″
HcDoDynamicCompression=”TRUE”
HcDoOnDemandCompression=”TRUE”
HcDoStaticCompression=”FALSE”
HcDynamicCompressionLevel=”0″
HcFileExtensions=”htm
html
txt”
HcOnDemandCompLevel=”10″
HcPriority=”1″
HcScriptFileExtensions=”asp
dll
exe”
>
</IIsCompressionScheme>
<IIsCompressionScheme Location =”/LM/W3SVC/Filters/Compression/gzip”
HcCompressionDll=”%windir%\system32\inetsrv\gzip.dll”
HcCreateFlags=”1″
HcDoDynamicCompression=”TRUE”
HcDoOnDemandCompression=”TRUE”
HcDoStaticCompression=”TRUE”
HcDynamicCompressionLevel=”0″
HcFileExtensions=”htm
html
txt”
HcOnDemandCompLevel=”10″
HcPriority=”1″
HcScriptFileExtensions=”asp
dll
exe”
>
</IIsCompressionScheme>
替换成:
<IIsCompressionScheme Location =”/LM/W3SVC/Filters/Compression/gzip”
HcCompressionDll=”%windir%\system32\inetsrv\gzip.dll”
HcCreateFlags=”1″
HcDoDynamicCompression=”TRUE”
HcDoOnDemandCompression=”TRUE”
HcDoStaticCompression=”TRUE”
HcDynamicCompressionLevel=”10″
HcFileExtensions=”html
css
js
htm
xml
txt”
HcOnDemandCompLevel=”10″
HcPriority=”1″
HcScriptFileExtensions=”php
dll”
>
</IIsCompressionScheme>
<IIsCompressionScheme Location =”/LM/W3SVC/Filters/Compression/deflate”
HcCompressionDll=”%windir%\system32\inetsrv\gzip.dll”
HcCreateFlags=”2″
HcDoDynamicCompression=”TRUE”
HcDoOnDemandCompression=”TRUE”
HcDoStaticCompression=”TRUE”
HcDynamicCompressionLevel=”10″
HcFileExtensions=”html
css
js
htm
xml
txt”
HcOnDemandCompLevel=”10″
HcPriority=”1″
HcScriptFileExtensions=”php
dll”
>
</IIsCompressionScheme>
红色部分为你要压缩的文件类型,请自行增加。上方为静态类文件,下方为动态类文件。
蓝 色部分为压缩等级,数值为 0-10 ,请自行根据服务器硬件等环境来做调试(可以先用文章开头时提到的网址,先测试并记录“未开启任何Gzip的数值”与“开启Discuz6.1后台 Gzip数值”,然后配置完成,再记录“开启IIS6下的Gzip时的数值”,3个就可以进行对比了)
然后请先保存到桌面,名为 MeteBase.xml

步骤五:
我的电脑 > 控制面板 > 管理工具 > 服务
找到 IIS Admin Service > 停止

步骤六:
回到找到 MeteBase.xml 的目录,删除它

步骤七:
在步骤四的最后,让大家保存到了桌面,现在我们剪切它。

步骤八:
回到刚才删除 MeteBase.xml 的地方,把从桌面剪切的粘贴进来

步骤九:
在步骤五中,我们停止了 IIS Admin Service 服务,现在,我们点启动它。(图与步骤五一样,所以请以实际的为准)

步骤十:
回到II6中,对其进行重启IIS

步骤十一:
进入Discuz6.1后台,关闭 Gzip 压缩(重要)
如果不关闭,压缩效果将会降低 0.33% (不关闭,则就是2个Gzip压缩了,而输出时,将优先使用Discuz6.1后台的,所以会下降,一定要关闭)

[转载]实现Flex的TextArea文本中关键字的高亮显示

mikel阅读(1693)

转载实现Flex的TextArea文本中关键字的高亮显示 – STF – 博客园.

最近做的Flex项目中有一个需求,要求在一个TextArea中输入文本时,当文本中出现SQL关键字(如select,from,where等)时,让这些关键字高亮显示。

经过一个下午的研究最终算是基本上实现了,实现的过程就是一个学习的过程。

前几天机器重装了系统,FlexBuilder要重新装,从官网上下了最新版的FlexBuilder4.6装到机器上,算是尝了鲜,不过感觉和4.5差别并不大。接下来便是一步步实现的过程了。

首先要知道使用TextArea的change事件和TextRange类可以动态更改TextArea部分文本的样式。

——————————————–
mx.controls.TextArea.change
当 TextArea 控件中的文本通过用户输入发生更改时分派。使用数据绑定或 ‏‏‎‎ActionScript 代码更改文本时不会引发此事件。

即使 Event.bubbles 属性的默认值是 true,该控件也会在 Event.bubbles 属性设置为 false 时分派此事件。

事件类型:
flash.events.Event.CHANGE
语言版本:
3.0
Player 版本:
Flash 9, AIR 1.1
产品版本:
Flex 3
——————————————–
mx.controls.textClasses.TextRange
TextRange 类提供在 Label、Text、TextArea、TextEditor 和 RichTextEditor 控件中选择和格式化文本范围的属性。
——————————————–
mx.controls.textClasses.TextRange.TextRange(owner:UIComponent, modifiesSelection:Boolean=false, beginIndex:int=-1, endIndex:int=-1)
创建提供文本控件内容子集的新 TextRange Object,包括格式化信息。
参数:
owner 包含文本的控件。此控件必须包含 textField 属性,或者像 RichTextEditor 控件一样包含 textArea属性。
modifiesSelection 是否选择范围中的文本。如果将此参数设置为 true 并且不指定与控件中文本相对应的起始或结束索引,则 Flex 将使用当前文本选项的起始或结束索引。如果此参数为 true,您省略了 beginIndexendIndex参数,并且不存在任何选项,则 TextRange 对象为空。
beginIndex 范围中第一个字符从零开始的索引。如果 modifiesSelection 参数为 false,并且您省略此参数或指定了一个负值,则范围将从第一个文本字符开始。
endIndex 范围中最后一个字符的位置从零开始的索引。如果 modifiesSelection 参数为 false,并且您省略此参数、指定了一个负值或指定的值超出文本结束范围,则范围将以最后一个文本字符结束。
语言版本:
3.0
Player 版本:
Flash 9, AIR 1.1
产品版本:
Flex 3

关键是如何让指定的关键字样式发生变化。首先想到了正则表达式,但由于对正则表达式并不熟悉,所以采取了截取这些字符串,当出现关键字时,更改关键字的样式。

HighlightKeywordTextArea.mxml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<mx:TextArea xmlns:fx="http://ns.adobe.com/mxml/2009" 
            xmlns:s="library://ns.adobe.com/flex/spark" 
            xmlns:mx="library://ns.adobe.com/flex/mx"
            change="textArea_change(event)" width="100%" height="100%" 
            creationComplete="textarea_creationCompleteHandler(event)">
    <fx:Declarations>
        <!-- 将非可视元素(例如服务、值对象)放在此处 -->
    </fx:Declarations>
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.controls.Alert;
            import mx.controls.textClasses.TextRange;
            import mx.events.FlexEvent;
            [Bindable]
            public var keyArray:ArrayCollection;
            
            [Bindable]
            public var keyColor:String = "red";
            
            private var tr:TextRange;
            
            private var crlf:String = String.fromCharCode(13);
            
            private var regEx:RegExp = new RegExp(crlf, "g");
            
            private function setKeyColor(num:int,key:String):void
            {
                var text :String = this.text.toUpperCase().replace(regEx," ");
                var str : String = text.substr(num,text.length);
                var strArray : Array = str.split(" ");
                var keyIndex : int = strArray.indexOf(key);
                
                if(keyIndex!=-1)
                {
                    if(keyIndex!=0)
                    {
                        for(var i:int;i< keyIndex;i++)
                        {
                            num += (strArray[i] as String).length+1;
                        }
                    }
                    
                    var length:int = key.length;
                    tr = new TextRange(this, false, num, num + length);
                    tr.color = keyColor;
                    
                    num += (length+1);
                    
                    if(num<text.length)
                    {
                        setKeyColor(num,key);
                    }
                }
            }
            
            private function addTextRange():void{
                try {
                    tr = new TextRange(this);
                    tr.color = "black";
                    tr.textDecoration = "normal";
                    tr.fontSize = 20;
                    for each(var key:String in keyArray)
                    {
                        setKeyColor(0,key);
                    }
                    
                } catch (err:RangeError) {
                    
                }
            }
            
            private function textArea_change(evt:Event):void {
                
                addTextRange();
            }
            
            protected function textarea_creationCompleteHandler(event:FlexEvent):void
            {
                addTextRange();
            }
            
        ]]>
    </fx:Script>
</mx:TextArea>

测试主程序HLKeyTaTest.mxml如下:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
               xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:components="com.stf.components.*">
    <fx:Declarations>
        <!-- 将非可视元素(例如服务、值对象)放在此处 -->
    </fx:Declarations>
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.controls.Alert;
            
            [Bindable]
            public var keyArray : ArrayCollection = new ArrayCollection(["AS","SELECT","FROM","WHERE","AND","OR"]);
            
        ]]>
    </fx:Script>
    <components:HighlightKeywordTextArea width="500" height="300"
        keyColor="red" keyArray="{keyArray}"
        text="select name as 姓名 from user_info where id='key'">
        
    </components:HighlightKeywordTextArea>
</s:Application>

测试效果如下:

还存在一些问题:

1.对于很长很长的文本,字符串截取比对效率有点低,有点卡。

2.对于SQL的语的处理还有点弱,比如在引号中如果出现SQL关键字时同样会高亮显示,要是实现SQL编辑中的效果还差的有点远。