[转载]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阅读(724)

[转载]总结一下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阅读(1093)

[转载]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阅读(1148)

[转载]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阅读(815)

[转载]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阅读(1023)

[转载]搞清如何使用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阅读(954)

[转载]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阅读(1685)

转载实现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编辑中的效果还差的有点远。

[转载]短链接算法收集与分析

mikel阅读(1119)

[转载]短链接算法收集与分析 – Cocowool – 博客园.

短链接就不说了,大家已经都清楚了,如下所示就是短链接:

新浪微博     http://t.cn/SVpONM

腾讯微博     http://url.cn/302yor

Yun.io         http://d.yun.io/PNri2v

短链接的好处:1、内容需要;2、用户友好;3、便于管理。

如何实现呢,大概有三个步骤:

1、定义一个URL映射算法,可以将长的URL映射成短字符串;

2、使用一个存储(数据库?NoSQL?)来存储完成的映射;

3、实现自己的URL映射算法;

一般来说,第三步是我们比较头疼的,如何将一个长的URL字符串,映射成一个较短的字符串呢。我总结了三种办法:

普通实现

我想以前大家学习过十进制和二进制的互相转换,或者十进制和十六进制的互相转换,那么为了更短,我们可以使用62进制,对于一个数字ID进行转码,转换成一个短字符串。

这种做法的缺点是没有办法保证所有链接都是固定的位数的长度,而且在高并发的情况下,如何保证能够快速分发是个问题。

具体实现方法:

/**
* 利用62进制对数字ID进行短链接编码,缺点不能保证每个短链接是固定长度
*
* @author  wanshiqiang<wangshiqiang@360.cn>
* @param integer $integer
* @param string $base
*/
private function getShortenedURLFromID ($integer, $base = ALLOWED_CHARS)
{
$length = strlen($base);
while($integer > $length – 1)
{
$out = $base[fmod($integer, $length)] . $out;
$integer = floor( $integer / $length );
}
return $base[$integer] . $out;
}
/**
* 对62进制编码的短链接进行解码
*
* @author  wangshiqiang<wangshiqiang@360.cn>
* @param string $string
* @param string $base
*/
private function getIDFromShortenedURL ($string, $base = ALLOWED_CHARS)
{
$length = strlen($base);
$size = strlen($string) – 1;
$string = str_split($string);
$out = strpos($base, array_pop($string));
foreach($string as $i => $char)
{
$out += strpos($base, $char) * pow($length, $size – $i);
}
return $out;
}

文艺实现

算法描述:使用6个字符来表示短链接,我们使用ASCII字符中的’a’-‘z’,’0′-‘5’,共计32个字符做为集合。每个字符有32种状态,六个字符就可以表示32^6(1073741824),那么如何得到这六个字符,描述如下:

对 传入的长URL进行Md5,得到一个32位的字符串,这个字符串变化很多,是16的32次方,基本上可以保证唯一性。将这32位分成四份,每一份8个字 符,这时机率变成了16的8次方,是4294967296,这个数字碰撞的机率也比较小啦,关键是后面的一次处理。我们将这个8位的字符认为是16进制整 数,也就是1*(‘0x’.$val),然后取0-30位,每5个一组,算出他的整数值,然后映射到我们准备的32个字符中,最后就能够得到一个6位的短 链接地址。

PHP实现如下:

function shorten( $long_url )
{
$base32 = “abcdefghijklmnopqrstuvwxyz012345″;
$hex = md5( $long_url );
$hexLen = strlen( $hex );
$subHexLen = $hexLen / 8;
$output = array();
for( $i = 0; $i < $subHexLen; $i++ )
{
$subHex = substr( $hex, $i * 8, 8 );
$subHex = 0x3FFFFFFF & ( 1 * (‘0x’ . $subHex ) );

$out = ”;

for( $j = 0; $j < 6; $j++ )
{
$val = 0x0000001F & $int;
$out .= $base32[$val];
$int = $int >> 5;
}
$output[] = $out;
}
return $output;
}

二逼实现

下面这个函数使用了纯随机的方式来生成一个短链接,虽然我们可以通过查询操作来确保不重复使用短链接,可是… 这样真的靠谱吗~~

function random($length, $pool = ”) {
$random = ”;
if (empty($pool)) { $pool    = ‘abcdefghkmnpqrstuvwxyz’; $pool   .=
‘23456789’; }
srand ((double)microtime()*1000000);
for($i = 0; $i < $length; $i++) { $random .=
substr($pool,(rand()%(strlen ($pool))), 1); }
return $random;
}

Technorati 标签: ,,,

参考资料:

1、微博短地址原理解析

2、微博短域名原理及作用

3、Yours.org

4、Free PHP URL Shorten script that kicks ass

5、PHP Short Url Algorithm Implementation

6、Implement your own short URL

7、短网址算法初步汇总

8、Short Url 实现方式

[转载]认识aspx页面处理程序的页面生成关系和页面继承关系

mikel阅读(1019)

[转载]【认识aspx】页面处理程序【页面生成关系】【页面继承关系】 – DebugLZQ – 博客园.

对于 Web 开发来说,最重要的就是生成 HTML 页面,除了用流的方式一个字符一个字符地输出,有没有简单的方式来创建一个处理程序生成网页呢?

有!就是什么代码也不写的方式。当然,是我们自己不写,由程序生成。

对于网站开发来说,最常用的功能就是生成 HTML 网页,虽然通过处理程序再结合文本输出流,从理论上就可以生成任何网页,但是开发效率显然不容乐观。

为了从根本上解决这个主要的开发问题,ASP.NET 使用模板的方式来生成一个处理程序。模板的扩展名为 aspx ,通过一个内置的处理程序工厂 PageHandlerFactory 将 aspx 形式的模板编译生成处理程序代码,然后,将这个处理程序返回给 HttpApplication 完成请求的处理。aspx 形式的模板文件可以直接通过文本编辑器进行编辑,甚至可以通过 DreamWeaver 之类的网页设计软件进行排版,极大地提高了网站开发的效率,带来了网站开发技术的革命性升级。

ASP.NET 的系统配置文件中,已经进行了如下的配置,可以看到,对于扩展名为 aspx 的请求,将由 PageHandlerFactory 这个处理程序工厂进行处理,代码如下:

<add  path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True" />

这个类定义在命名空间 System.Web.UI 下,具体的定义如下:

public class PageHandlerFactory : IHttpHandlerFactory

aspx 模板文件与 Page 类和生成类之间的关系如图所示:

需要注意的是, aspx 模板的解析和代码生成仅仅出现在第一次处理的时候,以后的请求将直接使用已经编译生成的程序集,所以,这个处理过程并不会降低网站的处理速度。

对于一个 aspx 模板文件来说,一般情况下将对应存在一个同名的 cs 后台代码文件,其中定义了一个与页面同名的类,通过代码文件可以看到这个类派生自 Page 基的类。

PageHandlerFactory 通过 aspx 文件将生成两个类,一个为与后台代码中定义的类同名的部分类,这个部分类将与后台代码中定义的类在编译的时候合并为一个派生自 Page 的页面派生类。但是,在 ASP.NET 中,创建实际页面对象的类并不是这个类,而是生成的第二个类,一般情况下,这个类的名字为页面的名字后面加上下划线和 aspx。这才是实际创建页面对象的页面类。

例如,我们有一个页面文件  MyPage.aspx,那么,应该存在一个对应的后台代码文件 MyPage.aspx.cs 或者 MyPage.aspx.vb,其中定义了 MyPage 这个  Page 的派生类。

通过 PageHandlerFactory,MyPage.aspx 将生成两个类,部分类 MyPage 和 MyPage_aspx,其中,后台代码文件中的 MyPage 将和生成的部分类 MyPage 在编译的时候合并为一个完整的 MyPage 类定义,而 MyPage_aspx 则是从 MyPage 派生的一个页面类,用来创建实际的页面对象实例。它们之间的关系如下图所示:

由于页面处理程序是通过模板生成的,所以,大多数情况下,我们只要创建好这个 aspx 的模板就可以了,HttpApplication 会通过 PageHandlerFactory 创建这个生成的处理程序,然后使用这个处理程序完成服务器的处理任务。

现在,如果我们需要通过处理程序生成一个网页的话,只需要设计一个 aspx 的页面即可。

在一些特殊的情况下,我们需要创建一些生成 HTML 输出的程序,但是这些程序并不希望能够被客户端直接请求,那么,可以借助 PageParser 或者 BuildManager 通过 aspx 格式的模板来创建一个自定义的处理程序完成处理任务。