[转载]Android学习系列(1)--为App签名(为apk签名)

mikel阅读(758)

[转载]Android学习系列(1)–为App签名(为apk签名) – 谦虚的天下 – 博客园.

写博客是一种快乐,前提是你有所写,与人分享,是另一种快乐,前提是你有舞台展示,博客园就是这样的舞台。
这篇文章是Android开发人员的必备知识,是我特别为大家整理和总结的,不求完美,但是有用。

1.签名的意义
为了保证每个应用程序开发商合法ID,防止部分开放商可能通过使用相同的Package Name来混淆替换已经安装的程序,我们需要对我们发布的APK文件进行唯一签名,保证我们每次发布的版本的一致性(如自动更新不会因为版本不一致而无法安装)。

2.签名的步骤
a.创建key
b.使用步骤a中产生的key对apk签名

3.具体操作

方法一: 命令行下对apk签名(原理)
创建key,需要用到 keytool.exe (位于jdk1.6.0_24\jre\bin目录下),使用产生的key对apk签名用到的是jarsigner.exe (位于jdk1.6.0_24\bin目录下),把上两个软件所在的目录添加到环境变量path后,打开cmd输入

D:\>keytool -genkey -alias demo.keystore -keyalg RSA -validity 40000 -keystore demo.keystore
/*说明:-genkey 产生密钥
-alias demo.keystore 别名 demo.keystore
-keyalg RSA 使用RSA算法对签名加密
-validity 40000 有效期限4000天
-keystore demo.keystore */
D:\>jarsigner -verbose -keystore demo.keystore -signedjar demo_signed.apk demo.apk demo.keystore
/*说明:-verbose 输出签名的详细信息
-keystore  demo.keystore 密钥库位置
-signedjar demor_signed.apk demo.apk demo.keystore 正式签名,三个参数中依次为签名后产生的文件demo_signed,要签名的文件demo.apk和密钥库demo.keystore.*/

注意事项:Android工程的bin目录下的demo.apk默认是已经使用Debug用户签名的,所以不能使用上述步骤对此文件再次签名。正确步骤应该是:在工程点击右键->Anroid Tools-Export Unsigned Application Package导出的apk采用上述步骤签名。

方法二:使用Eclipse导出带签名的apk
Eclipse直接能导出带签名的最终apk,非常方便,推荐使用,步骤如下:
第一步:导出。

第二步:创建密钥库keystore,输入密钥库导出位置和密码,记住密码,下次Use existing keystore会用到。

第三步:填写密钥库信息,填写一些apk文件的密码,使用期限和组织单位的信息。

第四步:生成带签名的apk文件,到此就结束了。

第五步:如果下次发布版本的时候,使用前面生成的keystore再签名。


第六步:Next,Next,结束!

方法三:使用IntelliJ IDEA导出带签名的apk
方法步骤基本和Eclipse相同,大概操作路径是:菜单Tools->Andrdoid->Export signed apk。

4.签名之后,用zipalign(压缩对齐)优化你的APK文件。
未签名的apk不能使用,也不能优化。签名之后的apk谷歌推荐使用zipalign.exe(位于Android-sdk-windows\tools目录下)工具对其优化:

D:\>zipalign -v 4 demo_signed.apk final.apk

如上,zipalign能够使apk文件中未压缩的数据在4个字节边界上对齐(4个字节是一个性能很好的值),这样android系统就可以使用mmap()(请自行查阅这个函数的用途)函数读取文件,可以在读取资源上获得较高的性能,
PS:在4个字节边界上对齐的意思就是,一般来说,是指编译器吧4个字节作为一个单位来进行读取的结果,这样的话,CPU能够对变量进行高效、快速的访问(较之前不对齐)。

5.签名对你的App的影响。
你不可能只做一个APP,你可能有一个宏伟的战略工程,想要在生活,服务,游戏,系统各个领域都想插足的话,你不可能只做一个APP,谷歌建议你把你所有的APP都使用同一个签名证书。
使用你自己的同一个签名证书,就没有人能够覆盖你的应用程序,即使包名相同,所以影响有:
1) App升级。 使用相同签名的升级软件可以正常覆盖老版本的软件,否则系统比较发现新版本的签名证书和老版本的签名证书不一致,不会允许新版本安装成功的。
2) App模块化。android系统允许具有相同的App运行在同一个进程中,如果运行在同一个进程中,则他们相当于同一个App,但是你可以单独对他们升级更新,这是一种App级别的模块化思路。
3) 允许代码和数据共享。android中提供了一个基于签名的Permission标签。通过允许的设置,我们可以实现对不同App之间的访问和共享,如下:

AndroidManifest.xml:<permission android:protectionLevel="normal" />

其中protectionLevel标签有4种值:normal(缺省 值),dangerous, signature,signatureOrSystem。简单来说,normal是低风险的,所有的App不能访问和共享 此App。dangerous是高风险的,所有的App都能访问和共享此App。signature是指具有相同签名的App可以访问和共享此App。 signatureOrSystem是指系统image中App和具有相同签名的App可以访问和共享此App,谷歌建议不要使用这个选项,因为签名就足 够了,一般这个许可会被用在在一个image中需要共享一些特定的功能的情况下。
最后,请一定要记得保管好你的签名证书的两个密码,两个密码都不要告诉任何人,也不要把你的密钥库拷贝给别人,包括我!

[转载]利用FlexPaper实现Word、PPT、PDF在线浏览

mikel阅读(1249)

[转载]利用FlexPaper实现Word、PPT、PDF在线浏览 – php mysql 足迹 – 博客园.

今天在百度文库看文件时想着有没有可以在线看电子书的插件或源码呢?到网上搜索下发现了FlexPaper,下载下来,找了一些资料,折腾一番,出的效果还不错,就是将中文文档转换成swf文件时卡住了,先作个记录,以后有空再研究了。

FlexPaper是 一个开源轻量级的在浏览器上显示各种文档的组件,被设计用来与PDF2SWF一起使用, 使在Flex中显示PDF成为可能,而这个过程并无需PDF软件环境的支持。它可以被当做Flex的库来使用.另外也可以通过将一些例如Word、PPT 等文档转成PDF,然后实现在线浏览。

目前FlexPaper最新版是1.4.1,可以到官网Google Project下载

解压后有一个FlexPaperViewer.html demo文件,和一个Debug文件FlexPaperViewer_Debug.html,这两个文件很好的展示了FlexPaper的用法,以下搜集了FlexPaper的一些参数和函数供大家参考,结合这些参数和函数很容易就可以应用FlexPaper

参数列表

参数名称

参数值及说明

CursorToolsVisible

(True/False)

FitPageOnLoad

(True/False)

FitWidthOnLoad

(True/False)

FullScreenAsMaxWindow

(True/False)

FullScreenVisible

(True/False)

NavToolsVisible

(True/False)

PrintEnabled

(True/False)

PrintToolsVisible

(True/False)

ProgressiveLoading

(True/False)

Scale

SearchToolsVisible

(True/False)

StartAtPage

SwfFile

ViewModeToolsVisible

(True/False)

ZoomInterval

ZoomTime

ZoomToolsVisible

(True/False)

ZoomTransition

事件与函数

函数名称

函数说明

gotoPage (Number pageNumber)

跳转到指定页

fitWidth()

设置为宽度模式视图

fitHeight()

设置为高度模式视图

loadSwf (String swffile)

加载一个新的swf文件到浏览器中

getCurrPage()

获取当前页码

nextPage()

跳转到下一页

prevPage ()

跳转到上一页

Zoom (Number factor)

按系数缩放

searchText (String text)

搜索文字

switchMode (String mode)

变换视图模式;参数值可为(“Portrait”, “Two Page”, “Tile”)

printPaper ()

打印加载的文档

事件名称

事件说明

onDocumentLoaded ()

文档加载完成后触发

onDocumentLoadedError (String errorMessage)

加载文档出错时候触发

onProgress (Number bytesloaded, Number bytestotal)

文档正在加载的时候触发

onCurrentPageChanged (Number pagenumber)

页面改变时触发

onExternalLinkClicked (String link)

当用户点击外部链接的时候触发

将各种文档转换成swf文件是关键,从官网和其它资料都是介绍用SwfTools工具将pdf文件换成swf文件,在windows下可以使用以下命令行

C:\SWFTools\pdf2swf.exe Paper.pdf -o Paper.swf -T 9 -f

Paper.pdf转换成Paper.swf,当然也可以用它的UI工具

但问题就来了,转换英文文档是可以的,但是中文就不行了会出现乱码,后来在网上找了一些方法,但折腾了一番没成功,以后有时间再研究,大家有兴趣可以参考以下的资料来研究下:使用xpdf来处理中文PDF文档

[转载]存储过程 vs ORM 性能大比拼

mikel阅读(1053)

[转载]存储过程 vs ORM 性能大比拼 – fish-li – 博客园.

其实早就准备好这个测试项目了,一直还忘记了写出来。今天又完善了一下测试用例,打算把它贴出来。

我是一个比较喜欢使用存储过程的人,自然经常会写很多存储过程。 但现在连MS也在关注ORM了,而且还做了二个了,所以也不得不了解一下了。 同时也为了检验一下自己写的通用数据访问层的性能,所以就写了个性能测试程序来将存储过程与ORM的性能做个比较, 当然了,也把我的通用数据访问层与原生的Ado.net的性能做了一番比较。

点击此处下载完整源代码

要测试比较的数据访问方式

这个测试程序提供了5种数据访问的方式来做进行测试。

1. FishWebLib-自动加载实体。(使用我的通用数据访问层,加载实体时,使用反射)

2. FishWebLib-手工加载实体。(使用我的通用数据访问层,加载实体时,无反射)

3. Ado.net直接调用存储过程

4. LINQ-TO-SQL

5. Entity Framework

说明一下,
第一种方式,我想有些人一看到反射就会想到性能差。这里我只想补充一句,反射的性能差不差,要看你如何去写,性能差不差要看结果。
另外,前三种方式全都采用调用存储过程的方式来进行测试。
后二者嘛,都属于ORM工具,就直接使用它们所提供的动态生成SQL语句的方式来进行测试。

停一下,为什么没有采用直接发出SQL语句的方式来进行测试??
好吧,我来解释一下:的确可能有些人喜欢在C#中使用SQL语句的方式来操作数据库,这里就又可以为了二种方式了:
1. 采用SQL语句,并且采用参数的方式。我种做法本身是没有问题的,只是我不喜欢在C#代码中混着一堆SQL语句,看起来代码不清爽。 而且SQL语句放在C#中也没有语法着色的提示,写错了也不知道,并且不方便在数据库的一些工具中测试运行, 如果后期想优化语句,还得重新编译程序,再部署,太麻烦了。所以我不喜欢。
2. 拼接SQL语句。这种方式嘛,我真的不想评价它。

以上二种采用SQL语句的方式,不管如何,肯定快不过存储过程!,所以这里就不提供这种方式了。

比较哪些操作?

一般说来,数据库类的应用程序,操作数据库也就那么几种方式,增,删,改,查询分页列表,获取单个对象。 所以本次测试也就测试这5个方面。我想应该是很有代表性的。

再来看看实体类的定义吧(表结构与实体类对应,就不贴图了)

public class Customer
{
    public int CustomerID { get; set; }
    public string CustomerName { get; set; }
    public string ContactName { get; set; }
    public string Address { get; set; }
    public string PostalCode { get; set; }
    public string Tel { get; set; }
}

分页的搜索参数

class QueryParam
{
    public string SearchWord = "上";
    public int PageIndex = 1;
    public int PageSize = 20;
    public int TotalRecords;
}

至于C#的测试代码嘛,我就挑2种出来,其它的完整代码及存储过程,您可以下载压缩包,打开项目来看。

1. FishWebLib-自动加载实体 的测试代码


// 为了避免打开关闭连接的额外的时间,这里的所有操作全部放在一个连接中。

using( FishDbContext db = new FishDbContext(false) ) {
    Customer customer = new Customer();
    customer.CustomerName = Guid.NewGuid().ToString();
    customer.ContactName = "ccccccccccc";
    customer.PostalCode = "123456";
    customer.Address = "aaaaaaaaaaaaaaaaaaaaaaaa";
    customer.Tel = "12345678";

    // Add
    FishBLLHelper.CallSpExecuteNonQuery(db, "InsertCustomer", customer);

    customer.ContactName = Guid.NewGuid().ToString();
    customer.PostalCode = "430076";
    customer.Address = "湖北武汉";
    customer.Tel = "87654321";

    // Update
    FishBLLHelper.CallSpExecuteNonQuery(db, "UpdateCustomer", customer);

    // Get One
    Customer ccc = FishBLLHelper.CallSpGetDataItem<Customer>(db, "GetCustomerById", null, customer.CustomerID);

    if( ccc == null || ccc.Tel != customer.Tel )    // 检验查询结果
        throw new Exception("call GetCustomerById failed.");

    // Delete
    FishBLLHelper.CallSpExecuteNonQuery(db, "DeleteCustomer", null, customer.CustomerID);

    // 分页查询:要求不仅取到列表,还要知道符合条件的记录数。
    QueryParam param = new QueryParam();
    List<Customer> list = FishBLLHelper.CallSpGetDataItemList<Customer>(db, "GetCustomerList", param);
    int recCount = param.TotalRecords;
}

4. LINQ-TO-SQL 的测试代码

using( MyNorthwindDataContext db = new MyNorthwindDataContext() ) {
    db.Connection.Open();

    Customer customer = new Customer();
    customer.CustomerName = Guid.NewGuid().ToString();
    customer.ContactName = "ccccccccccc";
    customer.PostalCode = "123456";
    customer.Address = "aaaaaaaaaaaaaaaaaaaaaaaa";
    customer.Tel = "12345678";

    // Add
    db.Customer.InsertOnSubmit(customer);
    db.SubmitChanges();

    customer.ContactName = Guid.NewGuid().ToString();
    customer.PostalCode = "430076";
    customer.Address = "湖北武汉";
    customer.Tel = "87654321";

    // Update
    db.SubmitChanges();

    // Get One
    Customer ccc = db.Customer.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();

    if( ccc == null || ccc.Tel != customer.Tel )    // 检验查询结果
        throw new Exception("call Get One failed.");

    // Delete
    db.Customer.DeleteOnSubmit(ccc);
    db.SubmitChanges();

    // 分页查询:要求不仅取到列表,还要知道符合条件的记录数。
    MyDataItem.QueryParam parm = new MyDataItem.QueryParam();
    var query = from cust in db.Customer
                where cust.CustomerName.Contains(parm.SearchWord)
                select cust;

    int recCount = query.Count();
    List<Customer> list = query.Skip(parm.PageIndex * parm.PageSize).Take(parm.PageSize).ToList();
}

测试环境及结果

我的测试机器配置(ThinkPad SL510):Core2 T6670 2.2GHz, 4G内存
操作系统:Wiondow server 2003 SP2
数据库:Sql Server 2005 Express SP4

由于以前听说MSDE有并发限制,我想现在的2005 Express版应该也会有限制,所以只开了2个线程。而且由于不想在测试时等太久,所以测试次数也就选了1000次, 有点少,如果您有兴趣自己来试试,可以下载压缩包,里面有完整的代码。

一般说来,应用程序在第一次连接数据库时会慢一些,由于听说.net中有所谓的连接池的概念, 所以本测试程序在运行测试前,会根据线程的数量创建相应数量的连接,然后关闭它们,就算是给连接池做好了准备。
而且每次的测试结果只取程序启动后第一次的运行结果。

贴测试结果:

让人意外的是:Entity Framework比IINQ-TO-SQL慢了不少。比“Ado.net直接调用存储过程”就差更远了。

存储过程还是没让我失望,仍然是我最信赖的技术。所以呢,如果您想让程序有更好的性能,还是建议使用存储过程, 我想这也是为什么即使那些ORM工具一方面可以动态生成SQL,却仍然要支持调用存储过程的原因,在性能面前没有任何技术能取代存储过程!

当然了,如果某些小的项目,或者不经常执行的逻辑中,或者准确的说:对性能要求不高的地方,使用ORM也行吧。
我想有些人在性能面前又会扯到缓存,的确缓存可以在某些时候改善性能,因此,可能会说:我有缓存,存储过程不需要也很好啊。 但是,我也想说:我用存储过程,再加上缓存,会不会更快呢?

说到存储过程,让我想到一件难忘记的事: 今年早些时候去汉庭面试时,最后遇到一位“牛人”,当时我刚提到存储过程,没想到就听到对方的一堆对于存储过程的批评, 最后还说出一句很雷人的话:“存储过程只适合做点小项目!”, 哎,我当时真想说:“你去看看Sharepoint,TFS,看看人家微软用了多少存储过程!”

我知道,在这个世上的确存在一些存储过程的反对者。但是,我上家公司所有做开发的同事,全是支持存储过程的,当然了,他们也都会写存储过程, 问他们存储过程好不好,他们可以说出一大堆存储过程的优点。那些反对者所谓的缺点,在他们看来,并不认为是缺点,这里也就不想列举了。

我呢,只想说二句话:
1. 不会存储过程的人,建议去学学存储过程,学习肯定是有代价的,尤其是不同的数据库的存储过程语法不一样。
2. 会存储过程的人,可以去看看ORM,不用太投入,了解一下它们就好。

在这个测试程序项目中,还有一个问题未能解决,Entity Framework支持POCO的方式来使用(放在目录EFPOCO),我也写了相应的代码, 但项目中同时存在使用Entity Framework设计器生成的代码(放在目录EF), 当运行Entity Framework POCO的代码时,会出现异常“找不到“WinFormApp.EF.Customer”的概念模型类型”。 这二种方式单独运行时(在项目中排除另一个目录),是没有任何问题的,总之就是不能混用这二种方式。
如果谁知道原因,请帮我修改一下。 只要把目录EFPOCO加入到项目中,然后取消注释TestFactory.cs中的一些代码就可以重现异常了。在此先谢谢了。

点击此处下载完整源代码

[转载]存储过程 vs ORM 性能大比拼

mikel阅读(1483)

[转载]存储过程 vs ORM 性能大比拼 – fish-li – 博客园.

其实早就准备好这个测试项目了,一直还忘记了写出来。今天又完善了一下测试用例,打算把它贴出来。

我是一个比较喜欢使用存储过程的人,自然经常会写很多存储过程。 但现在连MS也在关注ORM了,而且还做了二个了,所以也不得不了解一下了。 同时也为了检验一下自己写的通用数据访问层的性能,所以就写了个性能测试程序来将存储过程与ORM的性能做个比较, 当然了,也把我的通用数据访问层与原生的Ado.net的性能做了一番比较。

点击此处下载完整源代码

要测试比较的数据访问方式

这个测试程序提供了5种数据访问的方式来做进行测试。

1. FishWebLib-自动加载实体。(使用我的通用数据访问层,加载实体时,使用反射)

2. FishWebLib-手工加载实体。(使用我的通用数据访问层,加载实体时,无反射)

3. Ado.net直接调用存储过程

4. LINQ-TO-SQL

5. Entity Framework

说明一下,
第一种方式,我想有些人一看到反射就会想到性能差。这里我只想补充一句,反射的性能差不差,要看你如何去写,性能差不差要看结果。
另外,前三种方式全都采用调用存储过程的方式来进行测试。
后二者嘛,都属于ORM工具,就直接使用它们所提供的动态生成SQL语句的方式来进行测试。

停一下,为什么没有采用直接发出SQL语句的方式来进行测试??
好吧,我来解释一下:的确可能有些人喜欢在C#中使用SQL语句的方式来操作数据库,这里就又可以为了二种方式了:
1. 采用SQL语句,并且采用参数的方式。我种做法本身是没有问题的,只是我不喜欢在C#代码中混着一堆SQL语句,看起来代码不清爽。 而且SQL语句放在C#中也没有语法着色的提示,写错了也不知道,并且不方便在数据库的一些工具中测试运行, 如果后期想优化语句,还得重新编译程序,再部署,太麻烦了。所以我不喜欢。
2. 拼接SQL语句。这种方式嘛,我真的不想评价它。

以上二种采用SQL语句的方式,不管如何,肯定快不过存储过程!,所以这里就不提供这种方式了。

比较哪些操作?

一般说来,数据库类的应用程序,操作数据库也就那么几种方式,增,删,改,查询分页列表,获取单个对象。 所以本次测试也就测试这5个方面。我想应该是很有代表性的。

再来看看实体类的定义吧(表结构与实体类对应,就不贴图了)

public class Customer
{
    public int CustomerID { get; set; }
    public string CustomerName { get; set; }
    public string ContactName { get; set; }
    public string Address { get; set; }
    public string PostalCode { get; set; }
    public string Tel { get; set; }
}

分页的搜索参数

class QueryParam
{
    public string SearchWord = "上";
    public int PageIndex = 1;
    public int PageSize = 20;
    public int TotalRecords;
}

至于C#的测试代码嘛,我就挑2种出来,其它的完整代码及存储过程,您可以下载压缩包,打开项目来看。

1. FishWebLib-自动加载实体 的测试代码


// 为了避免打开关闭连接的额外的时间,这里的所有操作全部放在一个连接中。

using( FishDbContext db = new FishDbContext(false) ) {
    Customer customer = new Customer();
    customer.CustomerName = Guid.NewGuid().ToString();
    customer.ContactName = "ccccccccccc";
    customer.PostalCode = "123456";
    customer.Address = "aaaaaaaaaaaaaaaaaaaaaaaa";
    customer.Tel = "12345678";

    // Add
    FishBLLHelper.CallSpExecuteNonQuery(db, "InsertCustomer", customer);

    customer.ContactName = Guid.NewGuid().ToString();
    customer.PostalCode = "430076";
    customer.Address = "湖北武汉";
    customer.Tel = "87654321";

    // Update
    FishBLLHelper.CallSpExecuteNonQuery(db, "UpdateCustomer", customer);

    // Get One
    Customer ccc = FishBLLHelper.CallSpGetDataItem<Customer>(db, "GetCustomerById", null, customer.CustomerID);

    if( ccc == null || ccc.Tel != customer.Tel )    // 检验查询结果
        throw new Exception("call GetCustomerById failed.");

    // Delete
    FishBLLHelper.CallSpExecuteNonQuery(db, "DeleteCustomer", null, customer.CustomerID);

    // 分页查询:要求不仅取到列表,还要知道符合条件的记录数。
    QueryParam param = new QueryParam();
    List<Customer> list = FishBLLHelper.CallSpGetDataItemList<Customer>(db, "GetCustomerList", param);
    int recCount = param.TotalRecords;
}

4. LINQ-TO-SQL 的测试代码

using( MyNorthwindDataContext db = new MyNorthwindDataContext() ) {
    db.Connection.Open();

    Customer customer = new Customer();
    customer.CustomerName = Guid.NewGuid().ToString();
    customer.ContactName = "ccccccccccc";
    customer.PostalCode = "123456";
    customer.Address = "aaaaaaaaaaaaaaaaaaaaaaaa";
    customer.Tel = "12345678";

    // Add
    db.Customer.InsertOnSubmit(customer);
    db.SubmitChanges();

    customer.ContactName = Guid.NewGuid().ToString();
    customer.PostalCode = "430076";
    customer.Address = "湖北武汉";
    customer.Tel = "87654321";

    // Update
    db.SubmitChanges();

    // Get One
    Customer ccc = db.Customer.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();

    if( ccc == null || ccc.Tel != customer.Tel )    // 检验查询结果
        throw new Exception("call Get One failed.");

    // Delete
    db.Customer.DeleteOnSubmit(ccc);
    db.SubmitChanges();

    // 分页查询:要求不仅取到列表,还要知道符合条件的记录数。
    MyDataItem.QueryParam parm = new MyDataItem.QueryParam();
    var query = from cust in db.Customer
                where cust.CustomerName.Contains(parm.SearchWord)
                select cust;

    int recCount = query.Count();
    List<Customer> list = query.Skip(parm.PageIndex * parm.PageSize).Take(parm.PageSize).ToList();
}

测试环境及结果

我的测试机器配置(ThinkPad SL510):Core2 T6670 2.2GHz, 4G内存
操作系统:Wiondow server 2003 SP2
数据库:Sql Server 2005 Express SP4

由于以前听说MSDE有并发限制,我想现在的2005 Express版应该也会有限制,所以只开了2个线程。而且由于不想在测试时等太久,所以测试次数也就选了1000次, 有点少,如果您有兴趣自己来试试,可以下载压缩包,里面有完整的代码。

一般说来,应用程序在第一次连接数据库时会慢一些,由于听说.net中有所谓的连接池的概念, 所以本测试程序在运行测试前,会根据线程的数量创建相应数量的连接,然后关闭它们,就算是给连接池做好了准备。
而且每次的测试结果只取程序启动后第一次的运行结果。

贴测试结果:

让人意外的是:Entity Framework比IINQ-TO-SQL慢了不少。比“Ado.net直接调用存储过程”就差更远了。

存储过程还是没让我失望,仍然是我最信赖的技术。所以呢,如果您想让程序有更好的性能,还是建议使用存储过程, 我想这也是为什么即使那些ORM工具一方面可以动态生成SQL,却仍然要支持调用存储过程的原因,在性能面前没有任何技术能取代存储过程!

当然了,如果某些小的项目,或者不经常执行的逻辑中,或者准确的说:对性能要求不高的地方,使用ORM也行吧。
我想有些人在性能面前又会扯到缓存,的确缓存可以在某些时候改善性能,因此,可能会说:我有缓存,存储过程不需要也很好啊。 但是,我也想说:我用存储过程,再加上缓存,会不会更快呢?

说到存储过程,让我想到一件难忘记的事: 今年早些时候去汉庭面试时,最后遇到一位“牛人”,当时我刚提到存储过程,没想到就听到对方的一堆对于存储过程的批评, 最后还说出一句很雷人的话:“存储过程只适合做点小项目!”, 哎,我当时真想说:“你去看看Sharepoint,TFS,看看人家微软用了多少存储过程!”

我知道,在这个世上的确存在一些存储过程的反对者。但是,我上家公司所有做开发的同事,全是支持存储过程的,当然了,他们也都会写存储过程, 问他们存储过程好不好,他们可以说出一大堆存储过程的优点。那些反对者所谓的缺点,在他们看来,并不认为是缺点,这里也就不想列举了。

我呢,只想说二句话:
1. 不会存储过程的人,建议去学学存储过程,学习肯定是有代价的,尤其是不同的数据库的存储过程语法不一样。
2. 会存储过程的人,可以去看看ORM,不用太投入,了解一下它们就好。

在这个测试程序项目中,还有一个问题未能解决,Entity Framework支持POCO的方式来使用(放在目录EFPOCO),我也写了相应的代码, 但项目中同时存在使用Entity Framework设计器生成的代码(放在目录EF), 当运行Entity Framework POCO的代码时,会出现异常“找不到“WinFormApp.EF.Customer”的概念模型类型”。 这二种方式单独运行时(在项目中排除另一个目录),是没有任何问题的,总之就是不能混用这二种方式。
如果谁知道原因,请帮我修改一下。 只要把目录EFPOCO加入到项目中,然后取消注释TestFactory.cs中的一些代码就可以重现异常了。在此先谢谢了。

点击此处下载完整源代码

[转载]android源代码下载目录(包含十五个开源项目)

mikel阅读(997)

[转载]android源代码下载目录(包含十五个开源项目) – qixiinghaitang – 博客园.

数量 目录
1 android源代码下载:一个图片浏览器的源码
2 android源码下载:天气预报源码
3 Android版通讯录(ExpandableListView)
4 android源代码: 开源音乐播放器
5 3D 正方体,触摸旋转,照片贴图,ANDROID的源代码
6 冒险游戏——胜利大逃亡源码另附ppt详解
7 Android学习代码,并附上豆瓣网for android项目工程
8 android Toast大全(五种情形)建立属于你自己的Toast
9 Android股票软件源代码下载
10 人人网 Android 客户端的源代码
11 facebook 客户端 Android源码下载
12 一个gallery写的类似UC桌面的menubar
13 Android源代码(国外的一个开源项目 在线音频文件播放)
14 一个游戏的源代码—netscramble
15 Android 游戏源代码下载:棋牌游戏——中国象棋人机对弈

[转载]我们的故事墙--一切为了可视化

mikel阅读(1160)

[转载]我们的故事墙–一切为了可视化 – 横刀天笑的技术空间 – 博客园.

几乎所有讲敏捷的书或者说使用了敏捷软件开发的团队都会拿出一个用户故事墙来说事。我们也有一面墙,如下所示:

20110408021

用手机拍的,不是很清晰。不过能大致看出分栏。

可能有人要说,现在都二十几世纪了,还用这么落后的手段管理,累不累啊。Project干啥吃的,Excel,Word和PowerPoint都哪儿去了,比这好用多了吧。

其实不然,且听我细细道来。

墙的可见性

这么一面墙就放到团队低头不见抬头见的地儿,所以可见性非常高。你早晨来上班的时候从墙面前经过,可能会引起你驻足一会儿,你编写代码的时候抬起头,你又看到了这面墙,或许你会发现什么问题。下班了,猛一回头,还是那面墙默默的注视着你。

比 起传统的计划管理工具,墙的可视化程度要高得多了。使用PPT制作出精美的项目计划,使用Project做出精确到小时的资源安排,但那又怎样,几乎是在 项目开始的时候项目经理将这些文件发给大家的时候大家才会看看,或者项目中开会的时候项目经理将这些文件往投影仪上一投感觉倍儿有气派,最后看这些文件的 人聊聊无几,真的我没有欺骗你。而且大家都喜欢将自己的硬盘填得满满的,到最后要找到这几个文件甚至要动用全盘搜索,那么谁还去看这些文件?只留下项目经 理在那儿意淫而已。

我们要的就是不断地在你面前晃,晃到你都记得下来为止。

更好操作

有人说软件更好用,我可真的不信。现在Office套件一个个大得惊人,打开一个大文档慢的有点受不了(可能是我的电脑不好吧),然后操作也是麻烦的要死,经常找不着自己要的东东在哪儿。

对于这面墙呢,我们只需要把卡片从左移到右,就这么简单,下至三岁小孩,上至80岁的老太太都可以完成。轻松而快捷,就像过家家一样。

分栏里可有小窍门

别看这个分栏,里面可隐藏着一些小窍门的。看看上面那张图,第二行分为7栏:

准备开发->正在开发->准备测试->正在测试->测试人员已确认->已经秀给客户看->客户已接受

这七个分栏表示一个用户故事的生命周期,从左到右。

每一栏的大小也不是随便画画的,每个故事卡片都占有一定的空间,当一个分栏里卡片过满或者很不满的时候都是一些有用的信号。比如,这里如果准备开发的卡片太少了,那就表示业务分析人员要加把劲了,我们可以做的东西不多了,你再慢了我们可要去玩了啊。

而准备测试的那一栏很满的时候责表示:测试人员受不了了,你们开发的能不能慢点啊,或者派两个人过来帮我测试吧。等等这些都是非常有用的信息,而且一看就明了的事儿。

准备开发栏卡片在墙上从上到下的排列也不是瞎来的,每个卡片都有一个优先级。优先级高的表示客户最希望赶紧完成的,所以开发人员从这一栏拿卡去做的时候可不是随便拿的哦,你得按从上往下的顺序拿卡(要是想拿下面那张容易点的,你就等等吧,呵呵)。

看 到墙的最上端没?一个大红的Blocked标记在右侧。有的卡片因为某些事儿,比如正在开发的时候发现有的地方需求不明白,需要用户确认啊;或者正在测试 的时候发现了居然有地方没完成呢,这个就像线程被某些东西阻塞了一样,我们就把卡从对应的栏移动到它对应的上方。项目经理这个时候的作用就出现了,他将重 点关注这些被阻塞的卡,为嘛被阻塞了,他都要过来“管管闲事儿”。而且用这种方式还能很好的发现我这个卡是在哪个环节被拦住的,这也有利于跟踪。

卡片上也暗藏玄机

别看那一张小小的故事卡片,上面包含的信息可多了。

左上角是一个故事编号,一般项目应该有一个项目管理系统,里面记录着故事的详细信息,用什么到系统里去索引?就靠这个小编号。而且在向版本控制系统里提交代码时写注释也可以加上这个小编号,对日后查找有用的信息那可比文字搜索派用场多了。

右上角是一个故事点数,参见前一篇文章。

中间是用一句简单的话描述这个故事。为啥用一句话呢,还用那么大的笔写。嗯,用大字写就是为了写的内容少。一句话很容易记住,所以交流的时候也能更好的沟通。

左 下角画了很多正字,那是干啥的?那个表明这个卡片从准备开发移动到正在开发栏的时刻到现在已经过去了多少天了,一直记录到该卡片从正在开发栏移动到准备测 试栏。这个数据对于用来发现开发中的时间浪费是很有用的。比如估计的一个点的故事,咋现在开发了四天了呢?别人一看就会产生这么一个疑问,这样你就要跳起 来解释一下:靠,那个地方,部署太麻烦了,太消耗时间了。这样就有可能有人自告奋勇的来改善这个部署流程(我们就是在这么一步一步的改善中成长起来的)。

注意到没有,有的卡片右下角也有正字呢。呵呵,那是测试人员画的,作用同上。

唔,有的卡片上面还贴了小纸条,那是干啥的?小纸条上一般记录着这个故事划分了多少个任务(参见前一篇文章),在完成一个任务后开发人员会在任务后面画勾勾。

哎呀,我们的大头贴都上墙了。对,那个卡片上贴的照片就是正在这个故事上工作的开发人员,这样别人一走过去就知道某某某在干啥事儿,如果有啥问题可以找他去。而且这大头贴还能生出很多很多有意思的事情,对团队的融洽也很有帮助~~

一切为了可视化

好 了,小小的一面墙,甚至是小小的一个卡片记录的东西是不是真的很多?唔,还有很多东西这篇文章里还没记录呢。因为墙上画画很容易修改,你可以按照你的团队 需要来改进这面墙。总之就是要做到更好的可视化,反映出团队中的问题,能用一些明确的信号来表示出来,这真的比项目经理做的那个精美的PPT要高兴得多, 不信你也试试。

[转载]Excel 行列转换,并实现一行转多行

mikel阅读(964)

[转载]Excel 行列转换,并实现一行转多行 – Share – 博客园.

业务部门要给企业做一个报表转换,感觉不需要使用宏或程序也能完成。

研究了一下午,终于整出来了,感觉Excel是如此的强大,和大家分享一下。

源格式:

目标格式:

第1行的料件项次共有17个,料件项次下单耗,损耗率为空的不显示。

料号:=INDEX(亿泰兴!$C:$C,IF(MOD(ROW()-1,17)=0,(ROW()-1)/17+3,(ROW()-1)/17+4))

料件项号:=INDEX(亿泰兴!$E:$BT,1,(IF(MOD(ROW()-1,17)=0,17,MOD(ROW()-1,17))-1)*4+COLUMN()-1)

单耗:=INDEX(亿泰兴!$E:$BT,IF(MOD(ROW()-1,17)=0,(ROW()-1)/17+3,(ROW()-1) /17+4),(IF(MOD(ROW()-1,17)=0,17,MOD(ROW()-1,17))-1)*4+COLUMN()-2)

损耗率:=INDEX(亿泰兴!$E:$BT,IF(MOD(ROW()-1,17)=0,(ROW()-1)/17+3,(ROW()-1) /17+4),(IF(MOD(ROW()-1,17)=0,17,MOD(ROW()-1,17))-1)*4+COLUMN()-2)

说明:index()函数为取一个数组中元素的引用,其中“单耗”与“损耗率”公式是相同。

亿泰兴!$C:$C:(亿泰兴)为源数据sheet名,从第1张图可看到料号列在C列,所以取C列为料号数组。

IF(MOD(ROW()-1,17)=0,(ROW()-1)/17+3,(ROW()-1)/17+4):

取当前行号是否能被17整除,因前3列是表头,所以需要从第4个元素开始读取。因目标格式中第一行是表头,所以是从行号第二行开始,需要Row()-1。

Column()是返回当前列号,Column()-2是因为单耗与损耗率是从第3列开始的。

具体请大家自行分析,下载地址:/Files/xiaobier/成品耗用明細.rar

[转载]jquery.bitmapcutter(图片裁剪插件) 与 jquery1.4.2 配合

mikel阅读(939)

[转载]jquery.bitmapcutter(图片裁剪插件) 与 jquery1.4.2 配合 – 此地民风淳朴,一心向善 – 博客园.

滚滚长江东逝水,浪花淘尽英雄, 听着苏山大叔的的歌,灵感来了。

在博问中问了许久的问题,一直没有人帮我解决,我郁闷,我压抑,我无奈,在经过三天的假期的等待,回答数依据保持为0。

于是今天来了,下了决定自己解决。

我到底是遇到了什么问题呢?

问题就是JQuery.bitmapcutter与JQuery1.4.2配合时,发现裁剪框无法移动。

JQuery.bitmapcutter:这个东东就是老外写的一个,可以实现异步上传头像,而且可以移动,旋转,载剪。(说心里话,老外真的是聪明,要是开发语言是中文的话,我其实也很聪明)。

为了解决问题,我默默的读了好些遍他的js原码,于是,于是,我………………………………………………..就这样。

(1)、下面代码是 jQuery.bitmapcutter中,装载裁剪的容器DIV ,要知道,他以前是没有id的,比如id=”cutterDiv” ,这个是我自己加的。

//cutter
var $cutter = $(‘<div id=”cutterDiv” class=”jQuery-bitmapcutter-cutter” >&nbsp</div>’)
.css(ps.cutterSize)
.css({
‘opacity’: .4,
‘left’: (ps.holderSize.width – ps.cutterSize.width) / 2,
‘top’: (ps.holderSize.height – ps.cutterSize.height) / 2
}).appendTo($holder);

(2)、我们在来看看代码事件绑定的代码块。你可以在jQuery.bitmapcutter 的js文件中找到。

dragndrop: function(setting) {
var ps = $.fn.extend({
limited: {
lw: { min: 0, max: 100 },
th: { min: 0, max: 100 }
},
handler: null,
callback: function(e) { }
}, setting);

var dragndrop = {
drag: function(e) {
var d = e.data.d;
var p = {
left: Math.min(Math.max(e.pageX + d.left, ps.limited.lw.min), ps.limited.lw.max),
top: Math.min(Math.max(e.pageY + d.top, ps.limited.th.min), ps.limited.th.max),
target: d.target
};
ps.callback(p);
},
drop: function(e) {
$(“#cutterDiv”).unbind(‘mousemove’, dragndrop.drag).unbind(‘mouseup’, dragndrop.drop);
}
};

return this.each(function() {
if (ps.handler == null) { ps.handler = $(this) };
var handler = (typeof ps.handler == ‘string’ ? $(ps.handler) : ps.handler);
handler.bind(‘mousedown’, function(e) {
var data = {
target: $(this),
left: $(this).f(‘left’) – e.pageX,
top: $(this).f(‘top’) – e.pageY
};
$(“#cutterDiv”).bind(‘mousemove’, { d: data }, dragndrop.drag).bind(‘mouseup’, dragndrop.drop);
});
});
}

这个就是主要用来处理拖动裁剪框的移动的代码。(注意以下两行代码,这是我改造过的)

$(“#cutterDiv”).unbind(‘mousemove’, dragndrop.drag).unbind(‘mouseup’, dragndrop.drop);

$(“#cutterDiv”).bind(‘mousemove’, { d: data }, dragndrop.drag).bind(‘mouseup’, dragndrop.drop);

来看看上而两行代码的原型:

$().unbind(‘mousemove’, dragndrop.drag).unbind(‘mouseup’, dragndrop.drop);

$().bind(‘mousemove’, { d: data }, dragndrop.drag).bind(‘mouseup’, dragndrop.drop);

是的,他们的区别在于:我用了元素的id来锁定div,而前者没有用。

是作者写错了吗?当然不是,因为jquery1.4.2 和jquery1.3.1 中,元素选择器由1.3.1 – 1.4.2 发展的过程中,发生了变化。这就是原因喽!简单吧!作者还是很厉害的,js写的特别的好。赞一个。

终述一下:首先给裁剪框容器增加id,然后在事件绑定中,将元素的选定方式改为依靠id 来选择,你明白了吗?

来个截图:

好了,就写到这里了,谢谢大家的观赏。

我是百灵。

[转载]按后退键退出Android程序

mikel阅读(1081)

[转载]按后退键退出Android程序 – 追梦人 – 博客园.

主要的目的是按后退键的时候,让程序能够退出。

实现起来的思路:

1.捕获后退键被按了这个事件。

    @Override  
            public boolean onKeyDown(int keyCode, KeyEvent event)  {  
                if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {   
                //按下的如果是BACK,同时没有重复  
                  //DO SOMETHING      
                }  
      
                return super.onKeyDown(keyCode, event);  
            }   

2.在后退键被按的事件里退出程序

这里也有两种方式:直接退出程序,或者退出到主屏幕。

1)退出程序的方法有两种:

android.os.Process.killProcess(android.os.Process.myPid());

System.exit(0);    

我试了这两种方法,但是奇怪的是,在1.5模拟器下,程序确实被KILL了,但是马上Android又重新启动了程序。

另外还有一种方式,比较友好,可以释放资源,我觉得可行,就是实现起来麻烦一点,需要逐级退出,重写onResume()方法:

     @Override  
    protected void onResume() {  
        super.onResume();  
        if(mExiting){  
            finish();  
        }  
    }  

2)退出到主屏幕
这个比较简单,新建一个主屏幕的Intent就可以。

    Intent home = new Intent(Intent.ACTION_MAIN);   
        home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);   
        home.addCategory(Intent.CATEGORY_HOME);   
        startActivity(home);  

我最后采用了按后退键回到主屏幕的方式,实现代码如下:

@Override  
 public boolean onKeyDown(int keyCode, KeyEvent event) {  
  if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { // 按下的如果是BACK,同时没有重复  
   Intent home = new Intent(Intent.ACTION_MAIN);  
   home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
   home.addCategory(Intent.CATEGORY_HOME);  
   startActivity(home);  
  }  
  return super.onKeyDown(keyCode, event);  
 } 

[转载]ASP.NET MVC3 Razor视图引擎-基础语法

mikel阅读(941)

[转载]ASP.NET MVC3 Razor视图引擎-基础语法 – dotNetDR_ 深圳 点燃象征希望的烛光 – 博客园.

I:ASP.NET MVC3在Visual Studio 2010中的变化

在VS2010中新建一个MVC3项目可以看出与以往的MVC2发生了很明显的变化

image

1.ASP.NET MVC3必要的运行环境为.NET 4.0 (想在3.5用MVC3,没门!)
2.默认MVC3模板项目已集成

image

3.全新的Razor视图引擎
@{

ViewBag.Title = "Home Page";

}
<h2>@ViewBag.Message</h2>
To learn more about ASP.NET MVC visit

<a title="ASP.NET MVC Website" href="http://asp.net/mvc"></a>

<a title="ASP.NET MVC Website" href="http://asp.net/mvc">http://asp.net/mvc

</a>

<a title="ASP.NET MVC Website" href="http://asp.net/mvc"> </a>.

@ServerInfo.GetHtml()

4. 关于所有带”_”开头的文档

ASP.NET 4默认情况下会拒绝所有访问地址以”_”开头的_*.cshtml文档.关于*.cshtml文档,其实他是WebMatrix的一部分,稍后将会详细介绍该以”_”文档的使用说明.

例如访问 http://localhost:7985/_ViewPage1.cshtml

image

II:Razor视图引擎-基础语法

-基础-

所有以 @开头 或 @{ /* 代码体 */ }  (在@与{直接不得添加任何空格) 的部分代码都会被ASP.NET引擎进行处理.
在 @{ /*代码体*/ } 内的代码每一行都必须以”;”结束,如
@{
var i = 10;
var y = 20;
}
而 @xxx 则不需要以”;”作为结束符,如

@i 输出 10

@y; 输出 20;
代码区内字母分大小写.
字符类型常量必须用””括起例如: @{ string str = “my string”; }

-注意-

如需要在页面输出”@”字符
可以使用HTML ASCII编码&#64;
当然Razor也提供智能分析功能: 如果在@的前一个字符若是非空白字符,则ASP.NET不会对其进行处理

如:<p>text@i xx</p> 输出 text@i xx

单行语法:

@{ var I = 10; }
多行语法:

@{ 

    var I = 10;

    Var y = 20;

}

1. 使用局部变量,Razor不支持访问修饰符(public,private等,这个没任何意义)
在单行上定义局部变量
@{ var total = 7; }
@{ var myMessage = “Hello World”;}
在多行上定义局部变量

@{

    var greeting = "Welcome to our site!";

    var weekDay = DateTime.Now.DayOfWeek;

    var greetingMessage = greeting + " Today is: " + weekDay;

}

在上下文中使用变量

<p>The value of your account is: @total </p>

<p>The value of myMessage is: @myMessage</p>

注意:变量拼接输出

@{ var i = 10; }

text @i text

将输出 text 10 text
但是如果你想要输出 text10text 呢?

<p>text@{@i}text</p>即可

<p>text@i text</p> 将输出 text@i text

<p>text@itext</p> 将输出 text@itext

<p>text @itext</p> 将报错

如果是输出的是变量的方法名则不需要用@{}括住也可生效如:

text@i.ToString()text

使用变量对象可直接写: @var1 @var2 @myObject.xx

2. 使用逻辑处理

@{

    if (xx)

    {

    //do something

    }

    else

    {

    //do anything

    }

}

3. 在@{… }内部使用html标记

@{

    <p>text</P>

    <div>div1</div>

}

4. 在@{…}内部输出文本
利用@:进行单行输出:

@{

    @:This is some text

    @:This is text too

    @:@i 也可输出变量

}

利用进行多行输出:

@{

    <text>

        tomorrow is good

        some girl is nice

    </text>

}

5. 在@{…}内部使用注释

@{

    //单行注释

    var i = 10;

    //defg

}

 

    @* 多行注释 *@

    @* 

        多行注释

        多行注释 

    *@

 

 

@{

    @*

        多行注释

        多行注释 

    *@

    var i = 10;  @* asdfasf *@

}

 

<!-- 同时也可以使用C#默认的/* ... */ -->

 

@{

    /*

        多行注释 

    */

}

若在@{ … }内部使用注释,则会输出到页面之中,如果在内部使用@变量,则会被处理
@{


}
输出:

6. 类型转换
AsInt(), IsInt()
AsBool(),IsBool()
AsFloat(),IsFloat()
AsDecimal(),IsDecimal()
AsDateTime(),IsDateTime()
ToString()
例子:

@{

    var i = “10”;

}

 

<p> i = @i.AsInt() </p> <!-- 输出 i = 10 --> 

7. 使用循环

<!--方式1-->

@for (int i = 10; i < 11; i++)

{

    @:@i

}

<!--方式2-->

@{

    for (int i = 10; i < 11; i++)

    {

        //do something

    }

}

 

<!--while同理-->

到此结束!呼呼
声明: 本文版权归作者和博客园共有,转载必须保留此段声明。