[SQL]SQL SERVER行转列应用小结
一般的表结构大多会这么设计,通过关联查询就可以得出上面的数据(客运量就随便123了,非常时期以防恐怖分子)
不用说,大家也明白要得到下面的数据:
列数不多的话一般可以这样,也是网上比较经典的写法
Select 时间,
sum(case when 线路='5号线' then 客运量 end) As '5号线' ,
……
在SQL SERVER2005里可以用Pivot关键字来操作,如下:
declare @Str nvarchar(max)
set @str='select 时间'
select @str=@str+',['+线路+']' from #T group by 线路
set @str=@str+' FROM (
Select 时间, 客运量, 线路
FROM #T ) AS T
PIVOT ( sum(客运量) FOR 线路 IN
('
select @str=@str+'['+线路+'],' from #T group by 线路
set @str=left(@str,Len(@str)–1)
set @str=@str+ ')) AS thePivot
ORDER BY 时间'
declare @T1 table(date datetime,一号线 float,二号线 float, 五号线 float,十号线 float,十三号线 float,八通线 float,奥运支线 float ,机场线 float)
Insert INTO @T1 exec(@str)
Select * FROM @T1
drop table #T
上面的语句如果运行提示不支持pivot关键字的话(一般SQL2000库导入到SQL2005可能出现这问题),执行下这句:EXEC sp_dbcmptlevel 数据库名称 ,90
为了方便看,字段改成中文了,其中#T表的数据就是最上面第一张图的数据(只要基础数据源组织成这样的就行)
把处理后的数据存放在表变量@T1中(当然临时表也行),因为还要和其他表进行关联,导出一张大表,如下(表的部分列):
大致就这样吧
处理的方式应该还有其它的,仅供参考。
[Flex]Flash游戏开发必备书籍
看到7Yue的blog推荐游戏开发的书籍不由得转载下,最近比较关注flash游戏开发方面的,感觉岁数大了是该好好选择方向的时候了,不能在漫无目的的瞎忙了
现如今基于Flash/ActionScript进行网页游戏制作的需求和团队风声水起,游戏多种多样,有Social Game,休闲游戏,网页游戏,MMORPG游戏,目前参与到其中大大小小的制作团队数量呈直线上升趋势,本文不是为了评判各个制作团队的素质之高低的文 章,只是希望通过介绍一套针对Flash游戏设计开发制作的团队进行参考的书籍。这套书籍是经由国外同行推荐的一套集合,书的名字我就不打字输入了,上 图:
此 4本书籍能够帮助一个Flash设计开发团队快速建立其使用Flash和AS3技术制作游戏的理论基础和实用技术,但是这套书籍无法传授游戏开发共通的理 论和方法。从这4本书中,我们可以看到除了设计和数学是Flash游戏必不可少的基础之外,就是工具实战和AS3 API编程技巧。
感兴趣的可以从amazon.com上购买,请不要写什么外国书比中国书贵,英文书不如中文书好懂的评论,明白人都能算清楚这种学习投资和未来回报之间的一笔账。
[工具]WinToFlash – 从 U 盘安装 Windows
WinToFlash 是一个制作 U 盘系统盘的东西,支持 Windows XP, Windows 2003, Windows Vista, Windows 2008, Windows 7 系统,你可以不用光驱就能安装系统,节省了刻盘的成本,另外,对于没有光驱的小屏幕用户,非常实在;当然,对于向 @scavin 这样光驱坏掉的用户,也很强悍。@Appinn
还记得你上次打开电脑光驱是什么时候呢?随着网络带宽以及牛逼下载技术的实现,我们越来越少的使用光驱了。电影、电视剧的下载速度早以超过了街边盗 版商贩的速度,而如果遇到重装系统,还是需要拿出压箱底的系统盘,打开可能已经生锈的光驱 (@scavin 的光驱很可能就是长时间不用而造成了故障,总之现在读盘已经很是问题了)。
WinToFlash 将整个 Windows 系统安装盘拷贝进 U 盘中,并且制作成可以开机启动的系统盘,这样就能直接利用 U 盘来安装系统了。当然要想制作系统盘,大容量的 U 盘是必须的。怎么说也得 2GB 以上,而 Vista 和 Win7 最少也要 4GB 了。
WinToFlash 虽暂无中文版,但使用还是非常简单的。请注意备份 U 盘数据,制作 U 盘启动盘的过程会格式化 U 盘。详细使用步骤请见 重灌狂人 的文章:WinToFlash 自制可开机、可安装系统的“USB重灌随身碟”
[MVC] Oxite分析之Module
Oxite分析之Module
2009-09-08 00:16 by 韩安, 114 visits, 网摘, 收藏, 编辑
change set:42353
download :http://oxite.codeplex.com/SourceControl/ListDownloadableCommits.aspx
约定:在Oxite中,对实现了IOxiteModule接口的类称之为Module或模块。
在 某种角度上,可以将Oxite看成是由一个个Module构成的。Oxite项目Modules目录下的各个Module可以看做是系统模块,如 Oxite.Modules.Core.OxiteModule、Oxite.Modules.Membership.MembershipModule 等;而解决方案目录Modules下的各个Module可以看做是自定义Module,如Oxite.Blogs.BlogsModule、 Oxite.CMS.CMSModule。
一、IOxiteModule接口
每个Module都实现了IOxiteModule接口,下面看看IOxiteModule接口的定义:
1: public interface IOxiteModule
2: {
3: void Initialize();
4: void Unload();
5: void RegisterRoutes(RouteCollection routes);
6: void RegisterCatchAllRoutes(RouteCollection routes);
7: void RegisterFilters(IFilterRegistry filterRegistry);
8: void RegisterModelBinders(ModelBinderDictionary modelBinders);
9: void RegisterWithContainer();
10: }
由于目前Oxite官方文档几乎空白,而且又没正式发布,各个方法的作用分别是猜测如下:
RegisterWithContainer:向依赖注入容器注册Module所需的对象或实例;
Initialize:初始化Module(OxiteModule类和PluginsModule类)
RegisterFilters:注册自定义ActionFilter
RegisterModelBinders:注册自定义ModelBinders
RegisterRoutes:设置路由规则
RegisterCatchAllRoutes:作用未知
在“Oxite分析之初始化”一文中曾提到过,当Oxite初始化时,将会调用各个被加载的Module的除了Unload方法外的所有方法。而Unload方法将在Application_End方法中被间接调用用于清理一些资源。
具体查看LoadModules : IBootStrapperTask类的Execute方法:
1: OxiteConfigurationSection config = container.Resolve<OxiteConfigurationSection>();
2: IModulesLoaded modulesLoaded = this.container.Resolve<IModulesLoaded>();
3: RouteCollection routes = this.container.Resolve<RouteCollection>();
4: IFilterRegistry filterRegistry = this.container.Resolve<FilterRegistry>();
5: ModelBinderDictionary modelBinders = this.container.Resolve<ModelBinderDictionary>();
6: //...
7:
8: filterRegistry.Clear();
9:
10: modelBinders.Clear();
11:
12: //todo: (nheskew) get plugin routes registered on load in the right order instead of just clearing the routes before module init
13: routes.Clear();
14:
15: foreach (OxiteModuleConfigurationElement module in config.Modules)
16: {
17: IOxiteModule moduleInstance = modulesLoaded.Load(config, module);
18:
19: if (moduleInstance != null)
20: {
21: moduleInstance.RegisterWithContainer();
22: moduleInstance.Initialize();
23: moduleInstance.RegisterFilters(filterRegistry);
24: moduleInstance.RegisterModelBinders(modelBinders);
25:
26: this.container.RegisterInstance(modulesLoaded);
27:
28: //...
29: }
30: }
31:
32: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
33:
34: routes.LoadFromModules(modulesLoaded);
35:
36: routes.LoadCatchAllFromModules(modulesLoaded);
37:
这里需要注意各个方法的调用顺序,这一点可以查看PluginsModule的源码。我们一般会认为Initialize应该被最先调用,但 PluginsModule类的Initialize方法将会用到RegisterWithContainer方法中进行的某些配置,所以 RegisterWithContainer方法应该最新被调用。
二、IOxiteDataProvider
Module不一定要实现IOxiteDataProvider。当需要制定Module内部数据访问方式时,通过外部配置以及让Module实现IOxiteDataProvider可以达到。
另外,Oxite配置的灵活性使得Module也可以不实现IOxiteDataProvider接口,而新建一个类来实现。目前Oxite版本中实现在了Module本身中。
通过这样的配置,使得各个Module可以拥有自己特有的数据访问方式,甚至于每个Module可以放在不同的数据库或不同类型的数据库中。在数据访问上说,去除了与系统本身的耦合。
在“Oxite分析之初始化”一文中曾提到过web.config配置文件的自定义"oxite"配置节点。具体配置已经移至单独的Oxite.config,下面看看它的内容:
1: <oxite>
2: <connectionStrings>
3: <add name="Sql" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Oxite.Database;Integrated Security=true;"/>
4: <!--<add name="Sql" connectionString="Data Source=.\SQLEXPRESS;AttachDBFileName=|DataDirectory|Oxite.Database.mdf;Integrated Security=true;User Instance=true;"/>-->
5: </connectionStrings>
6: <dataProviders defaultConnectionString="Sql">
7: <add name="Membership" type="Oxite.Modules.Membership.MembershipModule, Oxite" category="LinqToSql" />
8: <add name="Tags" type="Oxite.Modules.Tags.TagsModule, Oxite" category="LinqToSql" />
9: <add name="Comments" type="Oxite.Modules.Comments.CommentsModule, Oxite" category="LinqToSql" />
10: <add name="Plugins" type="Oxite.Modules.Plugins.PluginsModule, Oxite" category="LinqToSql" />
11: <add name="Blogs" type="Oxite.Modules.Blogs.BlogsModule, Oxite.Blogs" category="LinqToSql" />
12: <add name="CMS" type="Oxite.Modules.CMS.CMSModule, Oxite.CMS" category="LinqToSql" />
13: <add name="Conferences" type="Oxite.Modules.Conferences.ConferencesModule, Oxite.Conferences" category="LinqToSql" />
14: <add name="Search" type="Oxite.Modules.Search.SearchModule, Oxite" category="LinqToSql" />
15: </dataProviders>
16: <modules>
17: <add name="AspNetCache" type="Oxite.Modules.AspNetCache.AspNetCacheModule, Oxite" />
18: <add name="Membership" type="Oxite.Modules.Membership.MembershipModule, Oxite" dataProvider="Membership" />
19: <add name="FormsAuthentication" type="Oxite.Modules.FormsAuthentication.FormsAuthenticationModule, Oxite" />
20: <add name="Core" type="Oxite.Modules.Core.OxiteModule, Oxite" />
21: <add name="Tags" type="Oxite.Modules.Tags.TagsModule, Oxite" dataProvider="Tags" />
22: <add name="Files" type="Oxite.Modules.Files.FilesModule, Oxite" />
23: <add name="Comments" type="Oxite.Modules.Comments.CommentsModule, Oxite" dataProvider="Comments" />
24: <add name="Plugins" type="Oxite.Modules.Plugins.PluginsModule, Oxite" dataProvider="Plugins" />
25: <add name="Blogs" type="Oxite.Modules.Blogs.BlogsModule, Oxite.Blogs" dataProvider="Blogs" />
26: <add name="CMS" type="Oxite.Modules.CMS.CMSModule, Oxite.CMS" dataProvider="CMS" />
27: <add name="Conferences" type="Oxite.Modules.Conferences.ConferencesModule, Oxite.Conferences" dataProvider="Conferences" enabled="false" />
28: <add name="Search" type="Oxite.Modules.Search.SearchModule, Oxite" dataProvider="Search" />
29: <add name="Site" type="OxiteSite.App_Code.Modules.OxiteSite.OxiteSiteModule" />
30: </modules>
31: </oxite>
modules节点下的元素,有的具有dataProvider属性(查看OxiteModuleConfigurationElement类的 DataProvider属性的定义)。比如name为"Search"的元素,dataProvider为"Search":
1: <add name="Search" type="Oxite.Modules.Search.SearchModule, Oxite" dataProvider="Search" />
其对应的是dataProviders节点下的name为"Search"的元素:
1: <add name="Search" type="Oxite.Modules.Search.SearchModule, Oxite" category="LinqToSql" />
接着请看ModulesLoaded类的Load方法:
1: public IOxiteModule Load(OxiteConfigurationSection config, OxiteModuleConfigurationElement module)
2: {
3: if (module == null || !module.Enabled) return null;
4:
5: foreach (OxiteDataProviderConfigurationElement dataProvider in config.Providers)
6: {
7: if (dataProvider.Name == module.DataProvider)
8: {
9: Type dataProviderType = Type.GetType(dataProvider.Type);
10:
11: if (dataProviderType == null)
12: throw new TypeLoadException(string.Format("Could not load type '{0}'.", dataProvider.Type));
13:
14: IOxiteDataProvider dataProviderInstance = container.Resolve(dataProviderType) as IOxiteDataProvider;
15:
16: if (dataProviderInstance != null)
17: dataProviderInstance.ConfigureProvider(config, dataProvider, container);
18:
19: break;
20: }
21: }
22:
23: //…
25: }
OxiteConfigurationSection config为整个oxite配置节点;OxiteModuleConfigurationElement module为oxite配置节点modules下的一个元素(比如name为"Search"的元素)
上 述代码的第5行开始,遍历oxite.config配置中的dataProviders节点下的dataProvider元素,如果元素的name值等于 module的dataProvider属性,通过dataProvider元素的type属性,获取类型。接着判断类型是否真的继承于 IOxiteDataProvier。如果是,调用类型的ConfigureProvider方法。
[MVC] Oxite分析之初始化
change set:42353
download :http://oxite.codeplex.com/SourceControl/ListDownloadableCommits.aspx
和一般的web程序一样,Oxite在第一次被访问时将进行初始化操作,即Oxite.OxiteApplication的 Application_Start方法。这些操作笼统来说包括两部分,一是设置依赖注入容器并将之存入应用程序状态中 (HttpApplicationState),二是通过依赖注入容器中的某些配置加载模块(Oxite分析之Module)。
这两部分的分析入口分别为Application_Start方法中的Application["container"] = setupContainer();和load();
一、设置依赖注入容器
注意力转移至setupContainer方法。该方法直接或间接将大批的对象和类型注册入依赖注入容器。
首先,将几个基础对象注册为单例。
1: parentContainer
2: .RegisterInstance((OxiteConfigurationSection)ConfigurationManager.GetSection("oxite"))
3: .RegisterInstance(new AppSettingsHelper(ConfigurationManager.AppSettings))
4: .RegisterInstance(RouteTable.Routes)
5: .RegisterInstance(System.Web.Mvc.ModelBinders.Binders)
6: .RegisterInstance(ViewEngines.Engines)
7: .RegisterInstance(HostingEnvironment.VirtualPathProvider);
OxiteConfigurationSectio类,自定义配置节点。其下目前有三个属 性:connectionStrings,dataProviders,moduls(可能会增加一个settings属性)。可以查看 OxiteSite项目下的oxite.confing文件直观的了解其结构。该配置基本上是针对Module的(Oxite分析之Module)。
Oxite几乎将所有东西都放置在一个个模块中,包括最核心的部分。比如设置自定义CollectionerFactiory、自定义 ControllerActionInvoker、自定义ViewEngines等在Oxite.Moduls.Core模块中进行。而moduls节点 就定义了Oxite系统包括哪些Module;
dataProviders定义了各个需要数据访问的Module的数据访问方式的分类(category属性),而在Module的具体定义中可以这个分类注入不同的Repository以达到各个模块可以单独使用不同的数据访问方式设置不同的数据库。
connectionStrings节点结构和站点配置web.config中的系统connectionStrings节点完全相同,这里之所以又进行 一次定义,是为了提供给dataProviders使用(dataProviders有个defaultConnectionString属性)。当 dataProviders下的元素未定义connectionString时,可以使用dataProviders节点的 defaultConnectionString属性对应的connectionStrings节点的元素的connectionString属性(真拗 口)。
AppSettingsHelper 类对ConfigurationManager.AppSettings 进行包装, 提供几个读取方法GetInt32、GetString等,用于读取web.config文件中的appSettings节点下的值。其实完全可以将这几 个读取方法放入NameValueCollectionExtensions类(Oxite已定义该类)。appSettings节点下,可以定义名称为 Oxite.InstanceName的值来指定Oxite实例,该值指导程序在数据库读取Oxite_Site表中的相应配置。还可以定义名称为 IsEmail、IsUrl等,值为正则表达式的元素。如果appSettings节点中没有定义这些元素,将会使用程序硬编码中的设置。
RouteTable.Routes,RouteCollection对象。System.Web.Routing中对其定义,稍微熟悉一点ASP.NET MVC应该清楚这是做什么的。
另外ModelBinders.Binders(Oxite分析之ModelBinders)、ViewEngines.Engines(Oxite分析之ViewEngines) 可以参看关于ASP.NET MVC方面的资料。
HostingEnvironment.VirtualPathProvider,HostingEnvironment 类的静态属性,其值是VirtualPathProvider类的对象。个人猜测可能会用在自定义ViewEngine中,不过目前Oxite版本中好像 还没地方用。
然后,将web.config中的connectionStrings和自定义节点”oxite”下的connectionStrings注册为单件。
1: foreach (ConnectionStringSettings connectionString in ConfigurationManager.ConnectionStrings)
2: parentContainer.RegisterInstance(connectionString.Name, connectionString.ConnectionString);
3:
4: foreach (ConnectionStringSettings connectionString in parentContainer.Resolve<OxiteConfigurationSection>().ConnectionStrings)
5: parentContainer.RegisterInstance(connectionString.Name, connectionString.ConnectionString);
将数据库连接字符串注册为单件,在构造数据库访问对象(或ORM,Linq to SQL、Entity Framework等)将会使用。
接着,两行咋看不太起眼的代码,实际上是进入Oxite核心的入口:
1: parentContainer
2: .RegisterInstance<IBootStrapperTask>("LoadModules", new LoadModules(parentContainer));
创建LoadModules对象,并注册为单例。LoadModules实现了IBootStrapperTask接口。
1: public interface IBootStrapperTask
2: {
3: void Execute(IDictionary<string, object> state);
4: void Cleanup(IDictionary<string, object> state);
5: }
在OxiteApplication的Application_Start调用私有方法load,load调用静态方法 Load。Load方法中,将从依赖注入容器中提取(ResolveAll)所有实现了IBootStrapperTask接口的类的对象,并调用 Execute方法(详情查看静态方法Load);在Application_End方法中,类似的将间接执行实现了IBootStrapperTask 接口的类的对象的Cleanup方法(详情查看私有方法unload)。当然,目前Oxite版本中只有一个LoadModules对象。
LoadModules类的主要代码:
1: public void Execute(IDictionary<string, object> state)
2: {
3: OxiteConfigurationSection config = container.Resolve<OxiteConfigurationSection>();
4: IModulesLoaded modulesLoaded = this.container.Resolve<IModulesLoaded>();
5: RouteCollection routes = this.container.Resolve<RouteCollection>();
6: IFilterRegistry filterRegistry = this.container.Resolve<FilterRegistry>();
7: ModelBinderDictionary modelBinders = this.container.Resolve<ModelBinderDictionary>();
8: IBackgroundServiceRegistry backgroundServicesRegistry = this.container.Resolve<IBackgroundServiceRegistry>();
9:
10: filterRegistry.Clear();
11:
12: modelBinders.Clear();
13:
14: //todo: (nheskew) get plugin routes registered on load in the right order instead of just clearing the routes before module init
15: routes.Clear();
16:
17: foreach (OxiteModuleConfigurationElement module in config.Modules)
18: {
19: IOxiteModule moduleInstance = modulesLoaded.Load(config, module);
20:
21: if (moduleInstance != null)
22: {
23: moduleInstance.RegisterWithContainer();
24: moduleInstance.Initialize();
25: moduleInstance.RegisterFilters(filterRegistry);
26: moduleInstance.RegisterModelBinders(modelBinders);
27:
28: this.container.RegisterInstance(modulesLoaded);
29:
30: //TODO: (erikpo) Move this into its own BootStrapper and spin up the appropriate executor classes and start them
31: IOxiteBackgroundService backgroundServices = moduleInstance as IOxiteBackgroundService;
32:
33: if (backgroundServices != null)
34: backgroundServices.RegisterBackgroundServices(backgroundServicesRegistry);
35: }
36: }
37:
38: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
39:
40: routes.LoadFromModules(modulesLoaded);
41:
42: routes.LoadCatchAllFromModules(modulesLoaded);
43:
44: container.RegisterInstance(filterRegistry);
45:
46: container.RegisterInstance(backgroundServicesRegistry);
47: }
48:
49: public void Cleanup(IDictionary<string, object> state)
50: {
51: container.Resolve<IModulesLoaded>().UnloadModules();
52:
53: //TODO: (erikpo) Loop through all background services running in the background and stop them
54: }
在这里我们暂时不去关心IBackgroundServiceRegistry、IFilterRegistry和FilterRegistry的定义,不过通过接口名称可以看出是和后台服务和ActionFilter相关的。
下面简单说说Oxite怎么实现Module(Oxite分析之Module)的插拔功能的。
Oxite中的Module都实现了IOxiteModule接口。当做好一个Module后(源码文件.cs或.vb等),直接复制到OxiteSet 的App_Code目录下,或者编译成dll复制到bin目录下并在依赖注入容器中进行注入,然后在oxite配置节点中进行配置即可。轻松实现 Module的插拔功能。
IModulesLoaded接口,从字面上看就是”已经加载的Module”,在Oxite中有一个实现:ModulesLoaded类,在依赖注入容 器中已经进行了注册:parentContainer.RegisterType<IModulesLoaded, ModulesLoaded>()
。该类的Load方法正是实现上述Module插拔功能。
Load方法中将找到的Module实例化,并将对象私有变量List<IOxiteModule> modules中,分别提供泛型和非泛型的GetModules方法供外部读取。当然,这种插拔功能如果完全可以自己另外实现一 个:parentContainer.RegisterType<IModulesLoaded, MyModulesLoaded>()。
然后再看看IOxiteModule接口。
IOxiteModule接口定义了7个方法:
1: public interface IOxiteModule
2: {
3: void Initialize();
4: void Unload();
5: void RegisterRoutes(RouteCollection routes);
6: void RegisterCatchAllRoutes(RouteCollection routes);
7: void RegisterFilters(IFilterRegistry filterRegistry);
8: void RegisterModelBinders(ModelBinderDictionary modelBinders);
9: void RegisterWithContainer();
10: }
11:
在LoadModules类的Execute方法中的,查看foreach循环:
foreach (XoohooModuleConfigurationElement module in container.Resolve<XoohooConfigurationSection>().Modules)
对oxite配置节点获取moduls节点的所有元素进行遍历。
IOxiteModule moduleInstance = modulesLoaded.Load(config, module);
ModulesLoaded类实例modulesLoaded的Load方法将Module进行实例化,返回IOxiteModule对象。如果正常返回 IOxiteModule对象,就调用如下四个方法: RegisterWithContainer
Initialize
RegisterFilters
RegisterModelBinders
接着:
this.container.RegisterInstance(modulesLoaded);
作用是将”已经加载的Module”注册为单例。
这句写在循环里,为什么不写在循环外面?
接下来的几句是关于后台服务的,略去。
跳出循环后:
1: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
2:
3: routes.LoadFromModules(modulesLoaded);
4:
5: routes.LoadCatchAllFromModules(modulesLoaded);
6:
第一句代码比较熟悉,排除axd文件的路由。
第二、三行代码,调用RouteCollection类型的扩展方法LoadFromModules和LoadCatchAllFromModules。 这两个方法实际上分别执行所有”已经加载的Module”的IModulesLoaded.LoadFromModules方法和 IModulesLoaded.LoadCatchAllFromModules。
这里有一个疑问,这两行代码为什么没有像调用ModulesLoaded类的RegisterWithContainer,Initialize,RegisterFilters,RegisterModelBinders这四个方法那样调用:
1: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
2:
3: foreach (OxiteModuleConfigurationElement module in config.Modules)
4: {
5: IOxiteModule moduleInstance = modulesLoaded.Load(config, module);
6:
7: if (moduleInstance != null)
8: {
9: moduleInstance.RegisterWithContainer();
10: moduleInstance.Initialize();
11: moduleInstance.RegisterFilters(filterRegistry);
12: moduleInstance.RegisterModelBinders(modelBinders);
13: moduleInstance.RegisterRoutes(routes);
14: moduleInstance.RegisterCatchAllRoutes(routes);
15:
16: this.container.RegisterInstance(modulesLoaded);
17: //...
18: }
19: }
20:
setupContainer方法接下来注册的类型,除非了ModulesLoaded,其他的目前还不能直接分析。
二、静态方法Load
静态方法Load在被load方法调用,load方法被Applaction_Start方法调用。也就是说,Load方法在站点第一次被访问时,就会被调用。
1: public static void Load(HttpContextBase context)
2: {
3: IEnumerable<IBootStrapperTask> tasks = ((IUnityContainer)context.Application["container"]).ResolveAll<IBootStrapperTask>();
4: bool bootStrappersLoaded = (bool)context.Application["bootStrappersLoaded"];
5: IDictionary<string, object> state = (IDictionary<string, object>)context.Application["bootStrapperState"];
6:
7: if (state == null)
8: {
9: context.Application["bootStrapperState"] = state = new Dictionary<string, object>();
10: }
11:
12: // If the tasks have been executed previously, call Cleanup on them to rollback any changes
13: // they caused.
14: if (bootStrappersLoaded)
15: {
16: foreach (IBootStrapperTask task in tasks)
17: {
18: task.Cleanup(state);
19: }
20: }
21:
22: foreach (IBootStrapperTask task in tasks)
23: {
24: task.Execute(state);
25: }
26:
27: context.Application["bootStrappersLoaded"] = true;
28: }
29:
Application["bootStrapperState"]保存一个状态值,指示站点时候已经初始化。
Application["bootStrappersLoaded"],可以查看后台服务的实现部分。
Load方法首先获取实现IBootStrapperTask接口并注册入依赖注入容器的所有实例并保存入局部变量 IEnumerable<IBootStrapperTask> tasks。通过之前的分析我们知道,目前tasks集合中也就只有一个对象:LoadModules对象。
state部分暂时略去,看下面的部分:
1: if (bootStrappersLoaded)
2: {
3: foreach (IBootStrapperTask task in tasks)
4: {
5: task.Cleanup(state);
6: }
7: }
8:
9: foreach (IBootStrapperTask task in tasks)
10: {
11: task.Execute(state);
12: }
13:
如果站点已经初始化首先进行清理操作,然后再重新执行。
如果需要在运行时候重新加载模块,在其他地方调用Load也是可以的,从而可以实现真正的Module热插拔。
文未校对。但不成为不被拍砖的的理由。
[JQuery]带闰年的日期校验正则表达式
JavaScript作为客户端脚本可以说无处不在,尤其是作为客户端的数据验证尤为重要。而对于数据有效性、合法性的验证,正则表达式起到了举足轻重的作用。现在我们就从时间校验来开始学习正则表达式的用法。
为什么要从时间验证的例子开始我们的正则表达之旅呢?首先,因为时间校验比较常用,尤其是日期的验证几乎是每个注册程序都要进行校验的;另外,日期函数相 对来说包含的涉及正则表达式的内容较少,其次字符单一除了数字之外,就是几个很有限的连接连接符号,正则逻辑简单。
预备知识:
1.为JavaScript增加函数:熟悉Java的人都是知道,Java所有的方法都是封装在类中的,那么JavaScript实际上类似(注意:我并 没有讨论JavaScript和Java的相关性,只是说道他们的相似性);JavaScript中所有的字符串操作实际上都是在String这个类中, 那么我们要为字符串增加一个日期校验的函数应该来怎么做呢?
类名.prototype.方法名 = function (){
/*语句块*/
}
比如我们为字符创类增加一个日期校验的方法IsDate:
String.prototype.IsDate=function(){
}
那么问题来了,这个字符串本身用什么来代表呢?数字面向对象的朋友很快就会想到this,对了就是它;
2.正则表达式的基本知识:
/ 标识正则表达式的开始位置和基础位置
^ 表示字符串的开始位置
$ 表示字符串的结束位置
| 或者
– 描述该字符串的是由(-)左右连个字符之间的所有字符构成
{n,m}有n到m个字符串组成
下面我们就开始日期校验函数的编写
首先我们分析一个完整日期的构成,比如2005-9-13
·年份是后4位数字构成
·月份是由1-12的数字构成
·日期是由1-31的数字构成
·年份可以被四整除为闰年
·2月的闰年为29天,否则为28天
·1、3、5、7、8、10、12每个月的为31天
·4、6、9、11每个月为30天
·如果日期或月份为各位数,那么十位也可以加上0
以上为我们分析的结果,那么根据我们的分析,我们先来构造自己的算法或者说方法。}
年份:能被四整除的了,那么能被4整除的数字都什么特征呢?这是个数学问题了,如果你想不出来,可以再去翻一翻小学的数学书。这里我可以个告诉你以为十位 数为0、2、4、6、8个位为0、4、8以及十位是1、3、5、7、9各位是26可以被四整除。前两位是由0到9的两位数字组成[0-9]{2},后两位 闰年[02468][048]或者是[13579][26],完整闰年就是将这些都连起来([0-9]{2}([02468][048])| ([13579][26]))那么非闰年呢?所有不能被4整除的就是,也就是把闰年的后两位反过来
月份:接下来我们来从最特殊的入手,也就是2月,而其他的月份则与是否闰年无关先来看一下闰年的2月;2月的写法可以使2也可以是02,在正则里应该是 [0]{0,1}[2]或者你也可以(2|02);还有大月(([0]{0,1}(1|3|5|7|8))|(10|12)、小月(([0]{0,1} (4|6))|11)
日期:2月闰年是1到29天,非闰年是1到28天,从正则来考虑,十位是0到2,各位是0到8或0到9组成,闰年:([0][1-9])|([1-2] [0-9],非闰年([0][1-9])|([1][0-9])|([2][0-8]),大月([0][1-9])|([1-2] [0-9])|30|31小月([0][1-9])|([1-2][0-9])|30
至此,我们的零部件已经制作完成,接下就是我们的组装过程,完整日期的合法性是怎么样子的呢?
闰年-2月-闰2月的的日期
或者
非闰年-2月-非闰2月的的日期
或者
年份-大月-大月日期
或者
年份-小月-小月日期
润2月完整日期:(([0-9]{2}([02468][048])|([13579][26])))(-)(2|02)(-)(([0][1-9])|([1-2][0-9]))
非润2月完整日期:(([0-9]{2}([02468][123579])|([13579][01345789])))(-)(2|02)(-)(([0][1-9])|([1][0-9])([2][0-8]))
大月完整日期:([0-9]{4})(-)((([0]{0,1}(1|3|5|7|8))|(10|12))(-)(([0][1-9])|([1-2][0-9])|30|31)
小月完整日期:([0-9]{4})(-)((([0]{0,1}(4|6))|11))(-)(([0][1-9])|([1-2][0-9])|30)
到这里我们的日期校验函数基本算是完工了,唯一要做的就是收尾工作了,把四个完整日期正则用|(或者)连起来,并且把它写到我们为String新增的函数中就算完工了:
String.prototype.IsDate=function(){
var regexp = /^((([0-9]{2}([02468][048])|([13579][26])))(-)(2|02)(-)(([0][1-9])|([1-2][0-9])))|((([0-9]{2}([02468][123579])|([13579][01345789])))(-)(2|02)(-)(([0][1-9])|([1][0-9])([2][0-8])))|(([0-9]{4})(-)((([0]{0,1}(1|3|5|7|8))|(10|12))(-)(([0][1-9])|([1-2][0-9])|30|31))|(([0-9]{4})(-)((([0]{0,1}(4|6))|11))(-)(([0][1-9])|([1-2][0-9])|30))$/g;
return regexp.test(this);
}
从现在开始我们就是这样来判断一个字符串是否为一个合法的日期了:
var strDate ="2005-2-29";
if(strDate.IsDate())
alert("这是一个正确的日期格式");
else
alert("日期格式错误");
[Report]增加的web打印控件 一次打印多份文档的方法
web打印一直是web管理系统的难点,事实证明,采用轻量级的dll控件来实现web打印,是比较理想的解决方案。
采用vc的ATL技术,结合IE的打印模版技术编写的webprint.dll,压缩打包生成dll后,文件下载只有80k左右,是轻量级的打印控件。最近主要实现了如下功能:
1、dll插件的功能修改
1.1增加打印url的属性
描述:当设置这个属性的值为一个url链接,然后再调用Print()函数做打印,就可以将url链接到的网页打印出来。
语法: webprint.printURL=[StringValue];
Webprint.Print(); 或 webprint.preview();
应用于:webprint对象
使用举例:
Webprint.InitPrint();
Webprint.printURL=”http://www.fcsoft.com.cn”;
Webprint.Preview(); //会查看到链接到的页面
注意:webprint是打印小插件的id.
1.2增加打印完成的状态属性
描述:当调用dll控件做打印文档的时候,文档处理完成,成功发送给打印机处理的时候,这个时候,此状态值会变成”over”;即用户在做打印文档的时候,可以通过回调判断这个属性的值来判断文档是否打印完成。
语法:webprint.state
使用举例:
Webprint.InitPrint();
Webprint.Print();
……此处需要使用回调来判断是否打印完成。
If (webprint.state==”over”){
Alert(“打印完成!”);
}
注意:webprint是打印小插件的id
1.3打印预览界面图片显示
原来:调用windows系统目录中的图片,当系统在vista上运行时,不能正常显示。
修改后:图片修改成独立调用的图片,在vista和windows系统上均可以正常显示。
1.4 页边距的设置
原来:在windows系统中设置页边距正常,在vista操作系统上设置会有问题
修改后:四个页边距在windows和vista上设置都没有问题。
1.5 出现无权限问题 :
原来:点击直接打印,后快速点 打印预览,会出现脚本错误,无权限。
修改后:没有这个现象了。
1.6 点击预览页面窗口的关闭后window.close()失效的问题
原来:在预览 页面直接点窗口 的关闭,然后页面的window.close()脚本运行会失效。
修改后:修改了这个问题。
1.7一次打印多份文档方式
利用在页面隐藏帧的方式,每个帧里面加载不同的页面,做一次点击打印多份文档的方式。
1.8打印预览或打印会出现安全问题提示
原来:提示信息为“该页包含潜在的安全隐患,是否继续”
修改后:不再出现此提示。
2、eprint自定义打印工具的升级
2.1 只首页打印,尾页打印,循环页打印
增加了只首页打印,只尾页打印,每页均打印的功能。例如有的文档标题只需要第一页打印,换页后不需要打印标题;有的只尾页需要打印一些落款或签名信息,其它页均不需要打印;有的需要每页都打印。
Webprint4.2中eprint自定义打印工具实现了此功能
设置界面:
在ep_band的属性中,增加打印设置选择项目:
首页打印
每页都打印
尾页打印
如下图所示
设置完成后,在相应的ep_band上放置的信息,就会按照预设置的方式来打印。
2.2 利用eprint一次打印多个模版的示例
利用webprint.dll的printState属性(打印完成后的状态)来做一次打印多份eprint模版的功能。
在实例页面中加如下代码,
//start 一次打印多份模版,将需要打印的模版名放到arr[]中********************************
var arr = new Array();
arr[0]= "sample001";
arr[1]= "sample002";
arr[2]= "sample003";
arr[3]= "sample004";
arr[4]= "sample005";
var iTime=0;
var iframeName = "_print_iframe";
function PrintAll(){
printNextJob(0);
}
function printNextJob(index){
if(iTime == 0 || window.frames(iframeName).oPrintCtl.printState == "over"){
if(iTime != 0) window.clearInterval(iTime);
if(index>=arr.length) {alert("打印完成!"); return;}
Printer.Print(arr[index],true);
document.getElementById(iframeName).onreadystatechange= function () {
if(document.getElementById(iframeName).readyState != "complete") return;
window.frames(iframeName).oPrintCtl.printState ="start";
iTime = window.setInterval("printNextJob("+(index+1)+")",500);
}
}
}
//end****************************************************************
调用printAll();函数后,就可以点击一次,打印5份模版对应的文档。
修改arr[n]=xxx; 达到打印各种不同模版的文档。
实例代码在:eprint for java"samples"samples.htm 页面 点击 一次打印多个
eprint for dotnet"samples"samples.htm 页面 点击 一次打印多个
[IIS]由一个案例引出SQL注入防范(WebKnight),补救(数据修复)的思考
前言
- 生产服务器的代码没有任何被改动过的迹象,排除服务器被入侵,代码被篡改的可能;
- 有病毒下载代码的部分,在数据库里真实看到了篡改迹象,可以排除ARP欺骗的可能;
- 同上,能确定网站被SQL注入攻击了,因为数据库被篡改了。
由于是被攻击后马上发现的现象,可以判断攻击此刻应该正在继续(后来检查的结果证明的确是这样),如何能尽快阻止攻击呢?我有2个思路(如果各位有更好的思路,期待您的指点):
- 马上找到含有SQL注入漏洞的程序,修复之;
- 马上增加一个应用程序防火墙(Application Firewall),从HTTP请求时就阻断攻击。
第一个思路几乎是不可能马上完成的任务,第二个思路还可行,因为前段时间上海天存信息技术有限公司曾提供给我们试用iWall应用防火墙(正式产品是收费的),还记得当时一位朋友提供给我的开源应用程序防火墙WebKnight,我信赖开源,所以我选择了后者。
如何在IIS6中安装WebKnight?
- 首先下载一份WebKnight,下载地址:http://aqtronix.com/?PageID=99#Download(注,这不是直接下载地址,点开后需要再点击WebKnight 2.2 (Release date: 2008.09.02),以防更新后各位朋友还下载旧的版本)
- 解压后有2个目录Setup、Source,其中Source是源码,我们这里只需要安装,进入Setup
- 进入Setup后还有2个目录:w32代表32位;x64代表64位;按照您服务器的操作系统来选择即可,我这里选x64(由于WebKnight的32位、64位文件结构完全相同,所以下面的内容完全适用与32位操作系统)
- 确保自己的每一个网站都运行在独立的应用程序池中;
- 在WebKnight的配置程序中
- 取消选择“Global Filter Capabilities”下的“Is Installed As Global Filter”
- 选择“Logging”下的“Per Process Logging”,这样每一个应用程序池的实例都会加载一个单独的WebKnight实例
- 确保Windows用户NETWORK SERVICE(或您设定的应用程序池的其他用户)有WebKnight文件夹的修改权限
- 拷贝第3步中x64文件夹中的所有文件到服务器上(如:F:\WebKnight\WebSite1\),注意:每一个网站均需要一个独立完整的WebKnight,不可共用
- 打开IIS Manager
- 在需要安装WebKnight的网站上点击右键 > 属性 > ISAPI filters
- 点击添加 > Filter Name随意,如(WebKnight),Excutable选择WebKnight目录下的WebKnight.dll(注意:要选网站所属的WebKnight目录,不要选错)
- 点击确定,完成安装
- 点击WebKnight目录中的Config.exe,具体配置方法见下一节,配置完成后再进行下一步,切记
- 在以上操作后,重新启动IIS(重启IIS其实可以避免,只需将配置WebKnight的网站的应用程序池停止再启动即可)
如何配置WebKnight
在WebKnight目录中(如:F:\WebKnight\WebSite1\),双击Config.exe开始配置,在弹出的Open Configuration对话框中,选择WebKnight.xml
- Scanning Engine 扫描引擎
- 无需更改默认配置
- Incident Response Handling 已发生攻击的处理
- 如果您希望有人攻击时看到的页面是WebKnight目录中的denied.htm,选择Response Directly即可;
- 如 果您希望有人攻击时看到的页面是您网站下的某个文件(如:http://www.xxx.com/Error/Denied.htm),选择 Response Redirect,并在下面的Response Redirect URL中填写您网站下文件的路径(如:/Error/Denied.htm)
- 如果您只希望记录攻击,但不希望中断用户的访问,您可以选择Response Log Only
- Logging 日志
- 如果日志量特别大,请取消选择Enabled,否则很有可能磁盘可用空间不知不觉就没有了,还有可能有比较严重的磁盘I/O性能问题
- 日志默认是存储在WebKnight目录下的LogFiles文件夹中,如果您想改变该路径,可以修改Log Directory的值
- WebKnight每天的日志是由不同文件存储的,默认保存28天的数据,您可以在Log Retention中修改该值
- Connection 连接
- 无需更改默认配置
- Authentication 安全认证
- 无需更改默认配置
- Request Limits 请求限制
- 取消选择Limit Content Length(Content-Length是header中的一个值,代表所请求元素的尺寸),我个人觉得这项没有必要选择,因为元素尺寸有可能很大
- 取消选择Limit URL(即限制URL的长度),原因同上,URL也可能很长
- 取消选择Limit Query String(即查询字符串的长度),原因同上,查询字符串也可能很长
- 取消选择Limit HTTP Version(即HTTP版本),我感觉没有必要限制HTTP版本,有可能会造成使用过旧版本浏览器的用户无法访问自己的网站
- 取消选择Use Max Headers(即限制Headers中各项的最大长度)。我一开始是选择了该项的,但在我的实践中,由于我们用了网站流量统计、广告合作代码等,导致Headers中的一些项超长,阻止了相当多的正常请求,所以我想干脆一劳永逸,取消选择了该项
- URL Scanning 网址扫描
- 取消选择RFC Compliant URL、RFC Compliant HTTP Url、Deny Url HighBitShellCode,勾选了这三项,很多不太标准的URL格式就会无法访问,比如包含中文的URL
- 取消选择Deny URL Backslash,因为我们网站中,“\”在URL里面也会用到
- 在URL Denied Sequences中,描述了拒绝请求的一些URL字符串,如果其中有您网站中正在使用的,可以删除,方法是选中要删除的项目,右键,点击Remove Selected
- Mapped Path 映射目录
- Use Allowed Paths,这项保持勾选,因为这项可以限制Web程序可以访问的服务器上的物理路径,我们需要做的只是在下面的Allowed Paths中添加上我们自己的网站物理路径,比如F:\WebSite1,添加方法是在任意项上点击右键 > Insert Item > 输入物理路径后,回车即可
- Requested File 被请求的文件
- 在Denied Files(拒绝请求的文件)中,去掉网站允许请求的文件,如:log.htm、logfiles
- 在Denied Extensions(拒绝请求的后缀名)中,去掉网站循序请求的后缀名,如:shtm
- Robots 蜘蛛程序
- 无需更改默认配置
- Headers 头信息
- Server Header中,可以修改Header中的Server字段的值,我觉得这个也可以改改,挺好玩的
- 为了防止组织合法的请求,取消勾选RFC Compliant Host Header、Use Denied Headers
- ContentType 内容类型
- 取消选择Use Allowed Content Types,若选中,则无法上传文件
- Cookie 这个就不需要翻译成中文了吧:)
- 无需更改默认配置
- User Agent 用户代理/客户端
- 取消勾选Deny User Agent Empty、Deny User Agent Non RFC,否则有部分合法访问会被拒绝
- Referrer 访问来路
- 取消选择Use Referrer Scanning,因为我觉得一个访问的来路可能不会有太严重的安全问题,还是为了尽量让合法的请求通过,我选择取消勾选该项
- Methods HTTP请求方法
- 无需更改默认配置
- Querystring 查询字符串
- 无需更改默认配置
- Global Filter Capabilities 全局过滤功能
- 取消勾选Is Installed As Global Filter,切记,该项一定要取消选择,否则WebKnight不能正产工作
- SQL Injection SQL 注入
- 无需更改默认配置
- Web Applications Web应用程序
- 勾选Allow File Uploads,否则上传文件的功能会失效
- 勾选Allow Unicode
- 勾选Allow ASP NET
- 如果您的网站需要支持ASP,勾选Allow ASP
- 同理,您的网站需要支持什么,请您自己选择需要勾选的项
修改后,记得通过菜单栏File > Save 来保存配置(或通过快捷键Ctrl+S),保存配置后,就可以重启IIS或应用程序池来启用WebKnight了
如何恢复被篡改的数据
2、如何恢复被篡改的数据
2 FROM disk='X:\BackupName.BAK' —备份文件的路径
3 WITH
4 file=1, —文件的编号
5 move '备份数据文件的逻辑名' TO 'X:\MSSQL\Data\物理文件名_Data.MDF', —数据库逻辑名 to 还原到的物理文件名
6 move '备份日志文件的逻辑名_Log' TO 'X:\MSSQL\Data\物理文件名_Log.LDF' —日志逻辑名 to 还原到的物理文件名
3、当还原成功后,执行下面的语句对数据进行恢复:
如何找到有漏洞的程序
[JQuery]Fckeditor使用手册
1. 新建一个编辑器
<script type="text/JavaScript" src="editor_path/fckeditor.js"></script>
Html:
<textarea id="content" name="content" style="width: 100%"></textarea>
JavaScript:
var oFCKeditor = new FCKeditor('content'); // content为textarea的id
oFCKeditor.BasePath = "../FCKeditor/"; // editor跟路径
oFCKeditor.Height = "100%"; // 高度度设置
oFCKeditor.Width = "100%"; // 宽度度度设置
oFCKeditor.ToolbarSet = "None"; // 工具条设置
oFCKeditor.Config["ToolbarStartExpanded"] = false; // 属性配置
oFCKeditor.ReplaceTextarea();
2. 操作编辑器
var oEditor = FCKeditorAPI.GetInstance('content ');
取得名字:
var editorName = oEditor.Name;
取得内容:
var content = oEditor.GetXHTML(true);
设置内容:
oEditor.SetHTML(‘html’);
插入内容到当前光标处:
oEditor.InsertHtml(‘html’);
更新内容到textarea:
oEditor.UpdateLinkedField();
要点:
Fckeditor所有方法和属性的第一个单词的首字母都是大写
3. 有用事件
编辑器加载完毕后会自动调用名字为FCKeditor_OnComplete的函数,并将自身作为参数传递进去,一般在FCKeditor_OnComplete函数初始化编辑器
{
// init code
alert(editorInstance.Name) ;
}