[转载]使用NVelocity快速实现Flexigrid

mikel阅读(1304)

[转载]使用NVelocity快速实现Flexigrid – Ariel Lu – 博客园.

自从去年偶然间发现Flexigrid这款JQuery的表格控件,就被它深深地吸引住了,华丽的外表、强大的功能、灵活的扩展性,最关键的是它不臃肿。如果追求功能强大,倒不如去使用ExtJs了。前段时间园友华磊给出了Flexigrid的ASP.NET解决方案,但我觉得封装成用户控件丧失了灵活性,而且它不再是一个客户端控件,不能按照我们的想法去随心所欲地操纵它。

既 然我们想保持它在前端的灵活性,只有另辟蹊径,从其它方面着手去简化工作。每次使用它,在后台获取数据,转成JSON格式也是一个比较繁琐的工作,有没有 一种方案能简化这些步骤,每次只需通过简单的配置和一两条SQL语句就能达到我们想要的效果呢?答案当然是肯定的。于是我想到了用模板引擎 NVelcity来实现这个方案。只要能把Flexigrid异步请求的参数能在SQL语句中使用,就可以解决这个问题了。

于是我们需要一个通用的WebService方法来接受、处理Flexigrid的参数:首先处理Flexigrid本身在获取数据的时候用的六个参数,代码如下:

//处理FlexiGrid的参数
//$page  第几页
//$rp  每页的条数
//$sortname  排序字段
//$sortorder  排序方向
string[] flexiGridParameters = { "page", "rp", "sortname", "sortorder", 
                                   "query", "qtype" };
Dictionary<string, object> parameters = new Dictionary<string, object>();
foreach (string flexiGridParameter in flexiGridParameters)
{
    string valueOfFlexiGridParameter = Context.Request.Params[flexiGridParameter];
    if (!string.IsNullOrEmpty(valueOfFlexiGridParameter))
    {
        parameters.Add(flexiGridParameter, valueOfFlexiGridParameter);
    }
}

有时候除了默认的这几个参数,我们还需要一些自定义的参数,为了方便处理,自定义参数需以”param_”开头:

//加入自定义参数,以 "param_" 开头
foreach (string userDefinedParameterName in Context.Request.Params.AllKeys
    .Where(o => o.StartsWith("param_")))
{
    parameters.Add(userDefinedParameterName,
        Context.Request.Params[userDefinedParameterName]);
}

另外page和rp为别表示页数和每页的条数,而我们需要的是起始条数和结束条数:

//将page和rp两个参数转成整数,再加入下面两个参数,方便写sql语句
//$startIndex  开始的行号
//$endIndex  结束的行号
int page = 1;
if (parameters.ContainsKey("page") && parameters.ContainsKey("rp"))
{
    page = Convert.ToInt32(parameters["page"]);
    int rp = Convert.ToInt32(parameters["rp"]);
    parameters["page"] = page;
    parameters["rp"] = rp;
    parameters.Add("startIndex", (page - 1) * rp + 1);
    parameters.Add("endIndex", page * rp);
}

好了,需要的参数都有了,剩下的工作就是如果写出一条用上上述参数的SQL语句并且动态地去解析它,在这里我选择了模板引擎NVelcity(本文中使用的是Castle的1.1版,这里有详细介绍)。现在我们要使用模板语言返回一个我们需要的数据结构,模板中定义如下:

#*
* 已有参数说明
$page  第几页
$rp  每页的条数
$sortname  排序字段
$sortorder  排序方向
$startIndex  开始的行号
$endIndex  结束的行号
$param_xxxx  自定义参数,xxxx为任意字符串

* 需要返回的数据结构说明
$result.rowsSql  获取数据的sql语句(必须有)
$result.totalSql  分页时取数据总数的sql语句(分页时必须有)
$result.id  FlexiGrid中的行id所对应的字段名(需要行id时指定,不指定时行id为空)
*#

这个时候又出现新的问题了,很多情况下SQL语句是一段很长的文本,而模板语言不支持换行,写在一行中可阅读性很差,显然是不符合要求的。这个时候就需要扩展一个模板语言中解析字符串的函数,把SQL语句写在另一个文本文件中,在模板中使用这个方法就可以啦。

static object ReadFileContent(object[] parameters)
{
    if (parameters.Length < 1)
    {
        return string.Empty;
    }
    DirectoryInfo info = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory
        + NVelocityConstants.TEMPLATE_DIRECTORY);
    FileInfo[] files = info.GetFiles(parameters[0].ToString(),
        SearchOption.AllDirectories);
    if (files.Length > 0)
    {
        string content = File.ReadAllText(files[0].FullName);
        List<string> argList = new List<string>();
        if (!string.IsNullOrEmpty(content))
        {
            for (int i = 1; i < parameters.Length; i++)
            {
                argList.Add(parameters[i] != null ?
                    parameters[i].ToString() : string.Empty);
            }
        }
        if (argList.Count > 0)
        {
            string[] ps = argList.ToArray();
            content = string.Format(content, ps);
        }
        return content;
    }
    return string.Empty;
}

回到刚才的WebService方法中,使用NVelocity解析刚才的模板:

//解析模板,取回FlexiGrid所需的sql语句,result类型为KeyValueObject
//$result.rowsSql  获取数据的sql语句(必须有)
//$result.totalSql  分页时取数据总数的sql语句(分页时必须有)
//$result.id  FlexiGrid中的行id所对应的字段名(需要行id时指定,不指定时行id为空)
NVelocityHelper velocity = new NVelocityHelper();
//注入工具类和参数
velocity.Add("helper", new HelperDuck());
foreach (string parameterName in parameters.Keys)
    velocity.Add(parameterName, parameters[parameterName]);
//得到模板执行结果
object result = velocity.GetResultFromVm(templateFileName);
if (result is KeyValueObject)
{
    KeyValueObject keyValueResult = (KeyValueObject)result;
    string rowsSql = string.Format("{0}", keyValueResult.GetInvoke("rowsSql"));
    string totalSql = string.Format("{0}", keyValueResult.GetInvoke("totalSql"));
    string id = string.Format("{0}", keyValueResult.GetInvoke("id"));

现在SQL语句已经有了,执行它,并序列化成JSON结构:

DataTable dt = Utils.ExecuteTable(rowsSql);
List<FlexiGridRow> rows = new List<FlexiGridRow>();
foreach (DataRow dr in dt.Rows)
{
    rows.Add(new FlexiGridRow()
    {
        id = dt.Columns.Contains(id) ? string.Format("{0}", dr[id]) : string.Empty,
        cell = Utils.DbObjectArrToCsStringArr(dr.ItemArray)
    });
}
int total = -1;
if (!string.IsNullOrEmpty(totalSql))
    total = Convert.ToInt32(Utils.ExecuteTable(totalSql).Rows[0][0]);

object flexiGridResult = new
{
    page = page,
    total = total > -1 ? total : rows.Count,
    rows = rows
};
Context.Response.Write(new JavaScriptSerializer().Serialize(flexiGridResult));

至此准备工作就全部完成了,下面我们通过一个示例来看一下效果如何:

1.首先新建一个文本文件用来存放SQL语句:

SELECT CompanyName, ContactName, ContactTitle, Address, City, Phone FROM (
    SELECT 
    ROW_NUMBER() OVER (ORDER BY {0} {1}) ROW,
    CompanyName, ContactName, ContactTitle, Address, City, Phone
    FROM Customers
) A where Row between {2} and {3}

2.添加一个NVelocity模板,用来获取我们想要的SQL语句

#set($result = $helper.createkeyvalueobject())
#set($result.rowsSql = $helper.readfilecontent("FlexiGrid_获取数据.sql", 
$sortname, $sortorder, $startIndex, $endIndex))
#set($result.totalSql = "SELECT COUNT(*) FROM Customers")
#set($result.id = "CompanyName")

3.前端调用

jQuery(document).ready(function () {
    var maiheight = document.documentElement.clientHeight;
    var w = jQuery("#ptable").width() - 3;
    var otherpm = 150; //GridHead,toolbar,footer,gridmargin
    var gh = maiheight - otherpm;

    var option = {
        height: gh, //flexigrid插件的高度,单位为px
        width: w,
        url: "WebService/CommonWebService.asmx/GetFlexiGridDataByTemplate",
        colModel: [
            { display: "公司名称", name: "CompanyName", width: 200, sortable: true },
            { display: "联系人名称", name: "ContactName", width: 120, sortable: true },
            { display: "标题", name: "ContactTitle", width: 150, sortable: false },
            { display: "地址", name: "Address", width: 250, sortable: true, hide: true },
            { display: "城市", name: "City", width: 100, sortable: true },
            { display: "电话", name: "Phone", width: 100, sortable: true }
        ],
        params: [
            { name: "templateFileName", value: "FlexiGrid_获取数据.htm" }
        ],
        buttons: [
              { name: "Add", displayname: "新增", onpress: toolbarItem_onclick },
              { name: "Delete", displayname: "删除", onpress: toolbarItem_onclick }
        ],
        sortname: "CompanyName",
        sortorder: "asc",
        title: "联系人列表",
        usepager: true,
        useRp: false,
        //rp: 5,
        rowbinddata: true,
        showcheckbox: true,
        rowhandler: rowEditHandler,
        selectedonclick: false,
        singleselected: true,
        //gridClass: "flexigrid"
        gridClass: "bbit-grid"
    };
    var grid = jQuery("#curtomerGrid").flexigrid(option);
});

怎么样,是不是很简单。最后让我们看看效果如何?

image

注:本文使用的Flexigrid为园友假正经哥哥修改过的版本,数据库使用的Northwind。

全部代码

[转载]javascript 实现单击和双击并存

mikel阅读(958)

[转载]javascript 实现单击和双击并存 – 功夫 熊猫 – 博客园.

在我们进行网页开发的过程中经常会遇到这么一个问题,为一个链接注册双击事件,或者让一个按钮或者其他元素上面同时注册单击或者双击事件,这时候我 们发现网页中的双击事件似乎永远都不会起作用,原因是当我们点击一次的时候,就被超链接或者单击事件截获了,本文描述了一个如何解决这个技术问题的具体方 法。本解决方案的实现原理是,单击事件和双击事件都调用同一个方法,我们根据两次鼠标点击的间隔事件来判断到底是单击还是双击事件。单击事件来临的时候先 不调用,等一小段时间,过了这段时间,如果没有下一次单击来临就开始调用单击对应的操作,如果有下一次点击就调用双击。
详细描述请参加下面代码清单:
< HTML>
< HEAD>
< TITLE> JavaScript 实现单击和双击并存 < /TITLE>
< META NAME=” Generator” CONTENT=” EditPlus” >
< META NAME=” Author” CONTENT=” http://www.javabiz.cn/” >
< META NAME=” Keywords” CONTENT=” ” >
< META NAME=” Description” CONTENT=” ” >
< /HEAD>

< BODY>
< SCRIPT LANGUAGE=” JavaScript” >
< !–
var dcTime=250;       // doubleclick time
var dcDelay=100;     // no clicks after doubleclick
var dcAt=0;               // time of doubleclick
var savEvent=null; // save Event for handling doClick().
var savEvtTime=0;   // save time of click event.
var savTO=null;       // handle of click setTimeOut

function showMe(txt) {
document.forms[0].elements[0].value += txt;
}

function handleWisely(which) {
switch (which) {
case ” click” :
savEvent = which;
d = new Date();
savEvtTime = d.getTime();
savTO = setTimeout(” doClick(savEvent)” , dcTime);
break;
case ” dblclick” :
doDoubleClick(which);
break;
default:
}
}

function doClick(which) {
if (savEvtTime – dcAt < = 0) {
return false;
}
showMe(” 单击” );
}

function doDoubleClick(which) {
var d = new Date();
dcAt = d.getTime();
if (savTO != null) {
savTO = null;
}
showMe(” 双击” );
}

//–>
< /SCRIPT>

< p>
< a href=” javascript:void(0)”
onclick=” handleWisely(event.type)”
ondblclick=” handleWisely(event.type)”
style=” color: blue; font-family: arial; cursor: hand” >
点击一下看看结果:
< /a>
< /p>

< form>
< table>
< tr>
< td valign=” top” >
事件模式: < textarea rows=” 4″ cols=” 60″ wrap=” soft” > < /textarea>
< /td>
< /tr>
< tr>

< td valign=” top” >
< input type=” Reset” >
< /td>
< /tr>
< /table>
< /form>
< /BODY>
< /HTML>

[转载]趋势畅想-搭载android系统的智能数码相机

mikel阅读(1345)

[转载]趋势畅想-搭载android系统的智能数码相机 – SkyD – 斯克迪亚(徐明璐)个人博客 – 博客园.

引言

image虽然当下的智能手机都具备拍照功能,但相比主流卡片数码相机而言,手机的拍照功能都还显得很小儿科,如高速连拍、手动白平衡、1厘米微距、广角等功能都鲜有实现,成像效果与同成像分辨率的卡片机相比也差很多,更不要说与专业级相机相比了。

而另一方面,数码相机虽然硬件强悍,但软件方面仍处于各自为政的混乱局面,各家独立开发自己的系统,而用户也只能默然使用厂家开发的这些功能,想按自己的需求对其进行定制、再开发,是几乎不可能的。

趋势

鉴于Android系统的火爆,很多手机以外的设备也都开始或考虑开始使用这一通用系统。对于数码相机领域而言,Android系统应该是一个足以引发智能革命的契机…

智能相机?有什么不同吗?

image首先它应当搭载一个如Android这样的通用的操作系统,可以使用其中的通用软件,并且由厂商编写出硬件调用API,供开发者开发专用软件。(不是说装了android系统的相机就是智能相机,没有公开具有可编程性的硬件API,再强的系统、镜头或其他硬件也是白搭)

其次其应具备互联网访问能力,这样才能有效地利用android菜市场一类的AppStroe,也可以更便捷地通过网络分享照片或是利用云计算。这方面需要加入wifi或是3G模块。

再有,GPS定位、电子罗盘、重力感应、加速感应等智能手机常见的传感器对智能数码相机也有很大作用,这些是多多益善的,且GPS定位与重力感应在现有数码相机中已经有存在先例了。

此外,蓝牙模块能增进交互效率,并为外接扩展设备提供方便。

简单说:它应当具备现有主流智能手机除了电话、短信功能以外的一切功能。

如果再拥有红外线拍摄功能及红外线补光灯,那就更美妙了。

智能数码相机能做什么不一样的事?

刚买到手的智能数码相机并不能比普通数码相机做更多事情,因为厂商仅仅是将其搭载了android系统,并为之写好了硬件调用API,然后内置了拍照、录像、相册等几个基本程序而已,你需要从菜市场搞来应用,或是基于API开发自己的应用,才能让它变得强大起来。

image使用现有的android应用

你可以在第一时间将现存的各种应用安装到智能数码相机中,以扩展你的相机功能,这些相关应用例如:相册、SNS社区分享、微博、云存储、视频分享、旅行足迹、LOMO效果拍照、拍照面部扭曲恶搞、大头贴、后期照片处理、条码扫描等等。

当然,其他不太相关的应用也可以拿来把玩,比如GPS导航地图、录音机、天气什么的实用程序,或是游戏、装B软件之类的也没问题。

全新开发的专属应用

这才是最激动人心的,也是智能数码相机的存在理由,让我们来设想一下会有什么牛X应用出现吧:

  1. 手持全景拍摄
    通过手持相机,按住快门,以自己为中心转动,使相机形成弧形移动轨迹,在此期间相机会快速连拍,在拍摄后自动合成为全景图。(这种功能在索尼相机中已经实现)
  2. 3D拍摄
    手持相机,按住快门,以拍摄物为中心移动相机为弧形轨迹,拍摄后由程序合成为3D图像格式文件。
  3. 定时自动拍摄
    让相机按时从待机中醒来进行拍摄,拍摄后再恢复待机状态。
    这个应用比较广,例如:
    拍摄某风景在24小时中的变化;
    记录种子萌发过程;
    定时拍摄你的人气小店,并自动发布到网上直播给网友看;
    记录你家庭的每一个温馨的早晨;
    放在镜子前记录你每天的面容变化(减肥效果观测∩_∩);
    定时定点偷拍对面楼美女换衣服(≧▽≦);
    出去玩时把相机挂在脖子上,垂在胸前,然后设定间隔1分钟自动拍摄,然后就尽情的玩吧,回来后整理照片就好;
    如果挂在背后出门,还能观测路人的回头率,芙蓉姐姐必备!
    对于一些特殊行业和岗位,可以要求职员佩戴相机,采用定时+随机拍摄的组合形式,全程记录它们的工作快照,并每日提交给公司,以监督他们是否在工作中有违规或不法行为(例如快递货品检验员、送货员、保安、城管、警察);
    绑在大龄大象身上,结合GPS寻找传说中的大象坟场!
  4. imageHDR拍摄
    关于HDR的说明,可以参看百科:http://baike.baidu.com/view/74850.htm
    简言之,就是通过一张曝光过度的照片和一张曝光不足的照片合成为一个更逼真的照片,合成后的照片保留了高光和暗处的各种细节,所以比常规拍摄出的照片信息更丰富、也更逼真、更具感染力。
    现在HDR的实现方法普遍都是手动拍摄一张曝光不足照片和一张曝光过度照片(有时还需要一张正常曝光的照片),然后再拿到电脑上进行后期合成。其缺陷就是 手动拍摄多次很麻烦,且不用三脚架的情况下,多次取景内容很难完全相同(需要经过 拍摄>审阅>改曝光度>再拍摄 这样多番操作,再拍摄的取景范围肯定有所出入了),还要等到后期合成后才能看到最终效果。
    而通过可编程的智能数码相机,HDR拍摄就是小菜一碟了,只需让程序驱动相机以不同曝光值连拍两张照片,再一合成就搞定了。
  5. 合影闭眼修正
    合影时经常会出现闭眼现象,尤其是人多的情况下,即使拍多张也会出现不是这个闭眼就是那个闭眼的现象。
    让程序来进行简单修正吧,只需长按快门,相机就会快速连拍,拍摄结束后程序会依靠相机的面部识别API自动甄选出没有人闭眼的照片,如果没有的话就进行一下合成互补,输出最终成像。
  6. 模拟景深
    此功能也是索尼卡片相机已经实现的功能,主要就是为了弥补卡片机难以实现背景虚化效果而设计的,原理很简单,就是快速连拍一张正常照片和一张全模糊照片,然后分析焦点,将非焦点部分与模糊照片合成。
  7. 报警器
    利用镜头监视取景(夜间需要红外功能支持),利用麦克风监听环境,一旦有达到一定级别的动静即发出警报,或远程报警并提交成像。(相机:白天拍照,晚上还得盯梢,还让不让活了~杯具)
  8. image远程监视
    类似监控摄像头的功能,但不同的是其可移动性,它将通过网络发送监控图像到控制端。
    这种移动性就带来了更多可能,比如警察、侦探、记者或是怪蜀黍在各种环境盗摄,或者生物学家用于监视动物在巢穴内的活动等。(动物:靠,老子也中木马了!)
  9. 远程对话。通过智能数码相机的镜头、麦克风、喇叭及网络访问功能,实现远程对话是很容易的,这样你就可以把它作为一个远程通话或指挥设备。
  10. 图像内容识别、分析及采集
    通过对取景器中的图像进行分析,获取有用的部分进行处理、存储,以采集所需的信息。
    其应用场景如:
    在路口、收费站等重要位置采集过往车辆的车牌号,将其识别为文本,再将采集时间值一并存入数据库,供警方进行案件调查时快速检索可疑车辆的行驶路径;
    在街道、银行、车站、医院采集行人的面部特征,将其录入数据库,并与通缉犯照片比对,发现类似时及时通知警方;
    在银行柜台前自动记录取款人的面部特征提供给警方使用;
    在某路段上空放置,鸟瞰监测该路段的车流量及拥堵状况或是行人密集度,也可以在监测到重大事故时第一时间报警以启动快速救援,还可用来监测能见度及其他天气状况;
    监测水流速、水位、水色、水质;
    放在汽车上,捕捉并解析路上的各种交通指示牌,显示给司机,避免因没注意看指示牌而走错路、错过高速出口、超速行驶(也可以用来识别路口有没有警察!嘿嘿!);
    回头客检测系统,放在柜台前,对客户面部进行分析,与过往数据进行比对,如果曾经来过本店甚至其他连锁分店,则会向店员提示,并显示过往造访记录甚至是消 费记录,让店员特别注意服务态度(反之也可以用来实现黑名单功能,比如用以在促销活动中杜绝车轮排队者,有这样的功能的话,iPhone4货源就难以被黄 牛党控制了!);
    餐厅满意度统计,扫描并识别顾客的面部表情,统计他们在餐厅中的愉悦程度,用作改善服务效果的参考数据;
    统计街头行人的服装品牌覆盖率;
    抓拍过往行人,自动分析面部特征,以过滤恐龙,只抓拍美女(咩哈哈哈哈,《街头美女宝典》即将出版)。

说到这里,你是不是已经感到所谓的智能数码相机已经不像相机了~,但其实你的智能手机早已不是手机了^^。

而接下来呢,智能数码相机还可以变得更BT一些:

扩展外设

不知道大家有没有使用过索尼的PartyShot智能跟拍底座:

image

介绍视频:http://www.sonystyle.com.cn/products/cyber-shot/partyshot/index.htm

它起初是被用于解决“拍照者总是无法出现在照片中”的遗憾而设计的,它可带动相机进行360°横向旋转,以及一定角度的垂直俯仰,通过相机的面部识 别功能追踪人脸,自动构图,捕捉家庭生活或聚会场景的自然瞬间,这样再不需要某一成员专司拍照,且被拍照者的表情也不会再像以前那样僵硬。

而如果将这类东西的API也提供出来供程序员开发使用,智能相机能做的事情就更多更酷了!

比如上面说过的手持全景拍摄功能,就可以改良为自动全景拍摄,因为手持相机水平移动还是容易出现上下偏移或者抖动等情况,且快速连拍耗电多,还会导 致后期处理耗时长,而交给程序控制自动跟拍底座拍摄就简单多了:把它拧在三脚架上,设置自动全景,它就可以自动每旋转30°拍摄一张照片,然后将拍到的几 张照片完美地组合在一起,拼成全景图。这样360°环状全景图拍摄起来也毫不费力,甚至穹状全景图都能很好地拍出来呢。

而在内容识别时,更可以更好地追踪感兴趣的目标,以获取更清晰的图源和更多信息。

远程监控时,可以由远程控制端调整旋转角度,以避免监控盲区。

另外在交互方面,相机由一块砖型物体变成了可动的玩意,可以进行简单的点头、摇头之类的交互,比如在合影时,如果某人没笑,相机就会摇头以表示不满,是不是也很有意思呢^^

这玩意要是再长两条腿就更好了!你就可以编程让它成为神圣的狗仔队员,追踪拍摄你宝宝的生活瞬间,并自动调整与宝宝的距离,防止被吃掉:)

还有什么顾虑?

以上的愿景应该是大家都希望实现的吧,但是目前貌似还没有哪家厂商开始行动起来,我不认为他们是因没有想到这些才没采取行动,尤其是对一些大厂来说,大多都是有所顾虑才没有开展智能相机的研发吧。

我能想到的最大的阻碍就是成本和能源两个方面:

升格为智能相机,首先就是要推翻现有的所有软件及部分硬件,进行革命性改造,且改换和追加的硬件成本都比较高,仅硬件部分应该就会提升成本千元上 下。但个人感觉,这种程度的增幅,作为消费者我觉得可以接受,比如索尼旗舰卡片机由现在的2000多涨到3000多,而可以拥有那么激动人心的应用,并且 我自己也可以对其进行功能定制开发的话,我觉得还是很值的。

能源问题上,上述应用中很多都需要较大的电量消耗,数码相机厂商应当加速在能源上的研发和改造,才能适应智能相机的需求。我认为在这方面首先就是应 当让相机都支持直流供电,这是最简单最有效的方案,能解决各种定点拍摄应用的用电需求;接着应该考虑采取外接供电装置、双源交替供电、混合能源供电等方 式,让用户可以在户外更容易地补充电量。

突破这两个问题,应该没什么太充分的理由不去研发智能相机、抢占新时代先机了吧。

结语

我相信,通过智能相机的发展,会大幅推动计算机图像识别领域技术的发展,为将来的机器人时代做重要铺垫。

让我们一起来等待见证这令人亢奋的变革吧。

[转载]在最新的Eclipse 3.6 上配置 Java ME 的开发环境! - 勿以善小而为之,勿以恶小而不为 - 博客园

mikel阅读(965)

[转载]在最新的Eclipse 3.6 上配置 Java ME 的开发环境! – 勿以善小而为之,勿以恶小而不为 – 博客园.

首先需要的下载文件有如下:

JDK 1.6\6.0 在SUN公司里直接可以下载到

WTK 2.5.2 手机模拟器,下载地址:http://cds-esd.sun.com/ESD37/JSCDL/sun_java_wireless_toolkit/2.5.2-ml/sun_java_wireless_toolkit-2_5_2-ml-windows.exe?AuthParam=1286288946_7f2743a432fbe7654fae5e86f2d016a9&TicketId=B%2Fw5lh6IT1NMSBdGP1RalgDj&GroupName=CDS&FilePath=/ESD37/JSCDL/sun_java_wireless_toolkit/2.5.2-ml/sun_java_wireless_toolkit-2_5_2-ml-windows.exe&File=sun_java_wireless_toolkit-2_5_2-ml-windows.exe

Eclipse 3.6 下载地址:http://download.actuatechina.com/eclipse/technology/epp/downloads/release/helios/SR1/eclipse-java-helios-SR1-win32.zip

Eclipseme 开发插件下载:http://nchc.dl.sourceforge.net/project/eclipseme/eclipseme/1.7.9/eclipseme.feature_1.7.9_site.zip

在安装依次安装到 Eclipse (这个开源的开发IDE,也是绿色版的,所在在下载解压后能直接打开应用)后,在安装Eclipseme时解压此开发插件,打开Eclipse开发软件, 在点击菜单“help” -》Install New SoftWare,选择“Add”按钮,如图:

在跳出的添加对话框里,点击“Archive…”按钮,按照提示选择当前你解压Eclipseme目录路径,一般都是根目录,里面有SITE.XML安装索引文件,如图操作:

再按“OK”确认后,开始安装步骤,在碰到安装对话框时,基本都是“Next”一路按下去,如果出现提示是否继续安装时,确定继续安装,这样手机的 开发环境基础配置完整了,这次主要说明了Eclipseme的安装与以前的不同,希望准备用Eclipse 3.6 开发手机软件的初学者有所帮助!

[转载]VS 2010 和 .NET 4.0 系列之《ASP.NET 4以及ASP.NET MVC 2中对输出进行HTML编码的新句法》篇

mikel阅读(892)

[转载]VS 2010 和 .NET 4.0 系列之《ASP.NET 4以及ASP.NET MVC 2中对输出进行HTML编码的新句法》篇-Scott Guthrie 博客中文版.

【原文地址】 New <%: %>Syntax for HTML Encoding Output in ASP.NET 4 (and ASP.NET MVC 2)
【原文发表日期】 Tuesday, April 06, 2010 11:57 PM

除了写博客外,我现在还使用Twitter发短贴和共享链接。请通过twitter.com/scottgu跟随我。

这是我针对即将发布的VS 2010 和 .NET 4所撰写的 贴子系列的第十九篇。

今天的贴子讨论ASP.NET 4中引进的一个很小,但非常有用的新句法特性,即能自动到代码片段中对输出进行HTML编码的功能。这有助于保护你的应用和网站免受跨站脚本攻击(XSS)和HTML注入攻击,而且允许你使用一个非常简洁的句法来实现。

HTML编码

跨 站脚本注入(XSS)和HTML编码攻击是网站和应用频受其害的2个最常见的安全问题。它们是在黑客找到方法,把客户端脚本或HTML标识注入网页,然后 这些网页被访问网站的其他访问者浏览时发生的。这可以用来糟蹋一个网站,以及允许黑客运行客户端代码来偷窃cookie数据或者利用用户在网站上的身份做 坏事。

帮助减少跨站脚本攻击的一个方法是确保网页上显示的输出是被HTML编码过了的,这帮助确保任何由终端用户输入或修改过的内容无法在向网页输出时含有象<script> 或 <img>这样的元素。

今天是如何对内容进行HTML编码的

ASP.NET 应用(特别是那些使用ASP.NET MVC的应用)经常依赖使用 <%= %> 代码片段表达式来显示输出。开发人员今天经常在这些表达式内使用Server.HtmlEncode() 或 HttpUtility.Encode()辅助方法在显示输出之前对输出进行HTML编码。这可以用象下面这样的代码来实现:

image

虽然这正常工作,但有2个小缺点:

  1. 有点冗长
  2. 开发人员经常忘了调用Server.HtmlEncode方法,而且没有简单的方法可以对整个应用来核实其用法

新的代码片段句法: <%: %>

在ASP.NET 4中,我们引进了一个新的代码表达式句法,<%:  %>,象<%= %>一样显示输出,但在显示前,会对输出自动进行HTML编码。这免掉了象上面例子那样显式地对内容进行HTML编码的需要,你只要编写象下面这样 更为简洁的代码即可实现完全一样的事:

image

我们选择 <%: %> 句法,是因为很容易快速地替换现有的 <%= %> 代码段实例,它还允许你轻松地在你的代码库查询 <%= %> 元素,发现并核实任何你在应用中没有使用HTML编码的地方,以确保其行为之正确性。

避免双重编码

虽然对内容进行HTML编码通常是个好的最佳实践,但有时你输出的内容就是HTML或者已经编码过了,在这样的情形下,你不想要再做HTML编码。

ASP.NET 4 引进了一个新的 IHtmlString接口 (以及一个具体实现: HtmlString),你可以将其在类型上实现,来表示它的值用来显示HTML时,已经恰当地编码过了(或者已经检查过了),因此它的值不该再作HTML编码了。<%: %>代码片段句法会检查内中代码表达式的值是否实现了IHtmlString 接 口,如果实现了的话,就不再对其输出进行HTML编码。这允许开发人员避免需要每每做决定是用<%= %> 还是用 <%: %>代码片段,而你总可以使用<%: %>代码片段,然后让已经HTML编码过了的任何属性或数据类型实现 IHtmlString接口。

在 <%: %> 中使用ASP.NET MVC HTML辅助方法

举一个这个HTML编码替换机制非常有用的实际例子,考虑一下你在ASP.NET MVC中使用HTML辅助方法的场景。这些辅助方法一般返回HTML。例如,Html.TextBox()辅助方法返回象 <input type=”text”/> 这样的标识。在ASP.NET MVC 2中,这些辅助方法现在默认返回HtmlString类型,表明返回的字符串内容显示是安全的,<%: %>不必再编码了。

这允许你将这些方法在 <%= %> 代码块中:

image

以及 <%: %> 代码块中使用:

image

在上面两种情形中,从辅助方法返回的HTML内容是作为HTML在客户端显示的, <%: %> 会避免做双重编码。

这 允许你在应用中默认使用 <%: %> 代码片段,而不是<%= %>代码块。如果你要是固执(hardcore)的话,你甚至可以创建一个编译规则,在应用中查询 <%= %> 用例,如果发现,将其标记为出错,来强制HTML编码总是发生。

ASP.NET MVC 2 视图的脚手架(Scaffolding)

在 你使用VS 2010 (或者免费的 Visual Web Developer 2010 Express版本)建造ASP.NET MVC 2应用时,你会发现使用“添加视图”对话框生成的视图在输出任何内容时,现在是默认使用 <%: %> 代码块的。例如,下面,我为 Article 对象生成了一个简单的“编辑”视图。注意其中标签,文本框和验证消息的三个 <%: %> 代码片段用例(都是使用HTML辅助方法输出的):

image

结语

新的 <%: %> 句法 提供了一个简洁的方式来自动对内容进行HTML编码,并将其显示为输出。它允许你减少代码的冗长,可以轻松地检查/核实整个网站上的内容都是HTML编码过了的。这可以帮助你的应用免受跨站脚本注入(XSS)和HTML注入攻击。

希望本文对你有所帮助,

Scott

[转载]C#生成CHM文件(中级篇)

mikel阅读(1084)

[转载]C#生成CHM文件(中级篇) – Alexis – 博客园.

在上篇《C#生成CHM文件(入门篇)》中,我们利用微软自带的hhc.exe以编程的方式创建一个CHM文件,而且调用的是一个静态的HMTL文件。

在中篇中,实现以下几个目标
1.将在线的网页保存为CHM文件
2.我们将对我们进行编译的CHM文件进行反编译,使用的还是微软自带的一个exe(hh.exe)。
3.以编程的方式将CHM文件转换为Word

在中篇中,把界面稍微调整了下,如下图

一、将在线的网页保存为CHM文件
曾尝试直接使用网址来编译html文件,结果一直报错,于是就放弃了。现在实现的方法的思想是这样的:先将输入的url地址的网页保存到本地,然后利用 上一篇中的方法生成CHM文件。不过经测试,这样的效率还是比较低的,主要的花费在将htm文件下载到本地,如果带宽不够的话,将会很慢,不过总归是种方 法,大家如果有更好的解决方案,希望能告诉我。

 HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
 HttpWebResponse myResp = (HttpWebResponse)myReq.GetResponse();
 StreamReader respStream = new StreamReader(myResp.GetResponseStream(), Encoding.Default);
 string respStr = respStream.ReadToEnd();
 respStream.Close();
 FileStream fs = new FileStream(startPath+@"\test.htm"FileMode.Create, FileAccess.Write);
 StreamWriter sw = new StreamWriter(fs, Encoding.Default);
 sw.Write(respStr);
 sw.Close();
思路是将网页保存在本地的,startPath为项目所在路径。 大家可以以http://www.baidu.com/index.htm为例(注意要以htm或html为结尾),测试下,看看能不能正常将百度的首页保存到CHM文件中。
效果图是这样的:

二、反编译CHM
反编译CHM的方法同初篇中的利用Process类来进行。

代码

/// <summary>
/// 反编译CHM文件
/// </summary>
/// <param name=”CHMFile”>CHM文件名</param>
/// <returns>返回hhc文件名</returns>
/// <remarks>uses the <see cref=”DecompileChm”></see></remarks>
public string DecompileChm(string CHMFile)
{
string pathDir = Path.GetDirectoryName(CHMFile);//得到chm文件的绝对路径
pathDir = Path.Combine(pathDir, Path.GetFileNameWithoutExtension(CHMFile));
return DecompileChm(CHMFile, ref pathDir);
}
/// <summary>
/// 反编译CHM文件
/// </summary>
/// <param name=”CHMFile”>CHM文件名</param>
/// <param name=”FolderToPut”>反编译后的文件存放路径</param>
/// <returns>返回反编译后的hhc文件名</returns>
/// <remarks>使用hh.exe反编译</remarks>
public string DecompileChm(string CHMFile, ref string FolderToPut)
{
if ((!System.IO.File.Exists(CHMFile)))
{
throw new ArgumentException(CHMFile+文件不存在);
}
if ((!Directory.Exists(FolderToPut)))
{
FolderToPut
= FolderToPut.Replace( , _);
Directory.CreateDirectory(FolderToPut);
}
DirectoryInfo di
= new DirectoryInfo(FolderToPut);
if ((di.Name.Contains( )))
{
throw new ArgumentException(反编译的文件夹名不能包含空格);
}
string strD = null;
strD
= -decompile + di.FullName + + CHMFile;//反编译命令
Console.WriteLine(strD);
Process p
= Process.Start(hh.exe, strD);//调用hh.exe进行反编译

p.WaitForExit();
return Directory.GetFiles(FolderToPut, *.HHC)[0];
}

三、CHM文件转换为Word
接下来,我们来延伸下,利用反编译的文件,将CHM转换成Word文件。思路是这样的:利用反编译,得到hhc文件(hhc文件中包含htm或html文 件的文件名)和一大堆web页面(如果一开始编译进去的是一大堆的话,呵呵),创建一个word文件,将html文件插入到word中,下面以实例的方式 来实现。
为了方便代码管理,我创建了一个类库项目,命名为CHM2Word,里面主要实现将CHM文件反编译并将反编译的文件整合为Word。在CreateCHM项目中调用代码即可,另需要你的机器安装Office2003(对应,添加引用 ->COM->Microsoft Word 11.0 Object Library)或2007(对应,添加引用->COM->Microsoft Word 12.0 Object Library)。

代码

/// <summary>
/// 添加到word中
/// </summary>
/// <param name=”pathFileHHC”></param>
/// <param name=”saveAs”></param>
public void AddToWord(string pathFileHHC, string saveAs)
{
if (File.Exists(saveAs))
{
throw new Exception(word文件已经存在!);
}
Object Nothing
= System.Reflection.Missing.Value;
Microsoft.Office.Interop.Word.Application wApp
= (Microsoft.Office.Interop.Word.Application)this.Word();
Document wDoc
= wApp.Documents.Add(ref Nothing, ref Nothing, ref Nothing, ref Nothing);

if (wApp == null)
{
throw new Exception(转换失败);
}

try
{
string dirfile = “”;//目录位置
dirfile = Path.GetDirectoryName(pathFileHHC);//目录的绝对路径
string[] lines = File.ReadAllLines(pathFileHHC);//读取hhc所有的行,这是为了找出里面的htm或html文件

string quote = “” + (char)34;
long filenumber = 0;

//遍历每一行
foreach (string TextLine in lines)
{
string htmFile = null;

if (TextLine.IndexOf(.html, 0) > 0 || TextLine.IndexOf(.htm, 0) > 0)//如果这一行里面有.htm或者html.的字符串
{

#region 以下代码是获取htm或者html文件名

int endQuote = 0;
if (TextLine.IndexOf(.html, 0) > 0)
{
endQuote
= TextLine.IndexOf(quote, TextLine.IndexOf(.html, 0));
}
else
{
endQuote
= TextLine.IndexOf(quote, TextLine.IndexOf(.htm, 0));
}
int quoteLoop = 0;
quoteLoop
= endQuote 1;
while (TextLine.Substring(quoteLoop, 1) != quote)
{
quoteLoop
= quoteLoop 1;
}
htmFile
= TextLine.Substring(quoteLoop + 1, endQuote quoteLoop 1);//获取html文件的名字

#endregion

htmFile = dirfile + \\ + htmFile;

bool b = false;//是否存在html文件
try
{
b
= File.Exists(htmFile);
}
catch (Exception ex)
{
}
if ((!b))
{
continue;
}
//将文件插入到word中
wApp.Selection.InsertParagraphAfter();
filenumber
+= 1;
if (ProcessFile != null)
{
ProcessFile(
this, new ProcessFileEventArgs(htmFile, filenumber));
}
//InsertFile参数说明
//文件名: 必选的 String. 要被插入的文件名和路径。如果没有指定路径,Word默认为当前文件夹
//Range: 可选的 Object. 如果指定的文件时word, 参数为bookmark(书签). 如果文件为其他类型(如Excel工作表), 参数为指定的一个单元或区域,如 R1C1:R3C4
//确定是否转换 可选 Object.如果值为 True,则 word 应用程序将在插入非“ Word 文档”格式的文档时提示对转换进行确认。.
//链接:  可选 Object. 如果值为 True,则可用 INCLUDETEXT 域插入该文档。
//附件: 可选 Object. 为 True 时将该文件作为附件插入电子邮件消息中。
wApp.Selection.InsertFile(htmFile, ref Nothing, ref Nothing, ref Nothing, ref Nothing);
if ((filenumber % 10 == 0))
wDoc.Save();
}
}
wDoc.Save();
//保存word
wDoc.Close(ref Nothing, ref Nothing, ref Nothing);//关闭
wApp.Quit(ref Nothing, ref Nothing, ref Nothing);//释放

}
catch (Exception ex)
{
}
finally//释放对象
{
if ((wDoc != null))
{
Marshal.ReleaseComObject(wDoc);
wDoc
= null;
}

Marshal.ReleaseComObject(wApp);
wApp = null;
}
}

创建word对象

代码

/// <summary>
/// 创建word对象
/// </summary>
/// <returns></returns>
public object Word()
{
Microsoft.Office.Interop.Word.Application WordApp;
try
{

//WordApp = new Microsoft.Office.Interop.Word.ApplicationClass();//如果是office2003和office2007用这样方法
WordApp = new Microsoft.Office.Interop.Word.Application();//如果是office2010,使用这个方法
}
catch (Exception e)
{
WordApp
= null;
}
return WordApp;
}

反编译导出类主要方法

代码

/// <summary>
/// feedback about processing
/// </summary>
public event EventHandler<ProcessFileEventArgs> ProcessFileIntoWord;//定义一个事件属性
private WordClass withEventsField_w = new WordClass();
/// <summary>
/// 通过这个类,我们可以转换为word,并且把事件传给调用者
/// </summary>
public WordClass w
{
get { return withEventsField_w; }
set
{
if (withEventsField_w != null)//如果不为null,撤销事件
{
withEventsField_w.ProcessFile
-= w_ProcessFile;
}
withEventsField_w
= value;
if (withEventsField_w != null)//如果不为null,注册
{
withEventsField_w.ProcessFile
+= w_ProcessFile;
}
}
}
/// <summary>
/// 主要函数:反编译、导出
/// </summary>
/// <param name=”ChmFile”>待反编译的CHM文件</param>
/// <param name=”DocFile”>word文件名</param>
/// <remarks>word文件一定不存在</remarks>
public void DecompileAndExport(string ChmFile, string DocFile)
{
try
{
Decompile d
= new Decompile();//实例化一个反编译类
string strHHC = d.DecompileChm(ChmFile);//获取hhc文件
w.AddToWord(strHHC, DocFile);//调用word类的添加到word中方法
}
catch (System.Runtime.InteropServices.COMException ex)
{
//throw new clsError(“Com exception:” + ex.Message, ErrorsOcurred.ComError);
}

}

我利用刚刚生成的baidu的CHM导出的word如图:

效果还是不错的,呵呵。如果你的CHM文件大的话,导出的时间可能会比较长一些。

PS:
1.如果你使用的是office2003或者office2007,需要修改类库项目下的WordClass类下Word方法,因为office2010的
Microsoft.Office.Interop.Word.ApplicationClass不再提供构造方法,而是提供Microsoft.Office.Interop.Word.Application()接口
2.如果在转换的工程中,始终没有反应,可以调试下,如果出现这样的错误,“因为没有打开的文档,所以这一命令无效”。

调试中不会弹出异常,但是将鼠标放到wApp对象中,查看的会发现那样的错误,原因是因为权限不够,可以采用如下方法解决:

运行dcomcnfg打开组件服务,依次展开”组件服务”->”计算机”->”我的电脑”->”DCOM配置”

找到”Microsoft Word应用程序”,右键打开属性对话框,
点击”标识”选项卡,点击”标识”标签,选择”交互式用户”(此设置可能对计算机安全存在威胁,如不设置可以解决问题就不设置,点”下列用户”,把管理员的用户administrator密码….正确填写进去也行)
点击”安全”选项卡,依次把”启动和激活权限”,”访问权限”,”配置权限”,都选择为自定义,然后依次点击它们的编辑,把everyone添加进去,并加入所有的权限…
OK,解决此问题!
如果你的office是2010或者你的系统版本较高的话,很有可能遇到这样的问题。我的电脑是windows7+office2010,就遇到了这样的问题。

3.在反编译和在线生成CHM的时候会生成一些临时文件,如果不及时删掉的话,会造成空间的浪费。我们自己可以写一个简单的删除程序,这个应该很简单,如果不会的,可以参考我以前项目中的代码,http://www.cnblogs.com/alexis/archive/2010/07/03/1770409.html

在下篇(应用篇)中,我将说说如何将这些技术运用到实际中。

[转载]PowerDesigner15官方正式版+注册补丁

mikel阅读(1037)

[转载]PowerDesigner15官方正式版+注册补丁,Java技术文章,Java系列教程,Java.

PowerDesigner15官方正式版+注册补丁

www.firnow.com    时间 : 2009-09-08  作者:匿名   编辑:小张 点击:  2302 [ 评论 ]

(1)软件介绍:
PowerDesigner是Sybase公司的CASE工具集,使用它可以方便地对管理信息系统进行分析设计,它几乎包括了数据库模型设计的全过程。利 用PowerDesigner可以制作数据流程图、概念数据模型、物理数据模型,可以生成多种客户端开发工具的应用程序,还可为数据仓库制作结构模型,也 能对团队设计模型进行控制。它可与许多流行的数据库设计软件,例如:PowerBuilder,Delphi,VB等相配合使用来缩短开发时间和使系统设 计更优化。

(2)官方下载:
目前 PowerDesigner 最新官方正式版本为 15.1.0.2850 ,謾軻提供官方下载地址:
主程序:PowerDesigner15_Evaluation.exe
http://download.sybase.com/eval/PowerDesigner/PowerDesigner15_Evaluation.exe
类库: PowerDesigner15_Library.zip
http://download.sybase.com/eval/PowerDesigner/PowerDesigner15_Library.zip
(2)注册(破解)方法:
1.点击以上链接到官方下载 PowerDesigner 15.1.0.2850 最新正式版并安装;
2.下载謾軻提供的注册补丁 pdflm15.dll [点击下载],然后替换原安装目录里的 pdflm15.dll 文件;
3.重启 PowerDesigner 15 即完成破解。

(3)破解说明:
对于 PowerDesigner15 的破解,网上盛传的方法是通过 pdflm15.dll + license.lic 破解补丁进行破解,然而謾軻亲自试验后发现这种方法其实只适用于 PowerDesigner12 的破解,用在 PowerDesigner15 身上则会出现如下错误提示:

diyblPic

错误提示1: PowerDesigner:pdshell15.exe-无法找到入口

无法定位程序输入点?SExceptionDialog_@@YAHPBDOJPB_WZZ于动态链接库PDCore15.dll上。

diyblPic

错误提示2: Sybase PowerDesigner(R)

Cannot load license management library(pdflm15)

针对这种现象,謾軻通过对 PowerDesigner15 的研究发现,官方加强了程序的保护措施,在动态链接库 PDCore15.dll 做了手脚,于是謾軻花了将近2个多小时的睡眠时间终于把 PowerDesigner15 破解出来,而且在只修改官方 pdflm15.dll 一个文件的情况下完成了注册效果,保持了软件原有的稳定性,废话少说,謾軻以图为证,希望对大家有所帮助:

diyblPic

官方原版为15天试用版

diyblPic

破解后为企业正式版

[转载]SQL Server 2008批量删除数据表

mikel阅读(1373)

[转载]SQL Server 2008批量删除数据表_飞宏风_百度空间.

测试数据
create table dbo.temptb_1 (id
int);
create table guest.temptb_2 (id
int);

打开隐式事务
SET IMPLICIT_TRANSACTIONS ON
执行动态删除
–定义一个变量

declare @SQL varchar(max);
set @SQL=;
select @sql=@sql+drop table +
–获取表名称,形如:dbo.temptb_***,escape ‘\’表示’\’为转义符号
QUOTENAME(SCHEMA_NAME([schema_id]))
+.+QUOTENAME([name])+;
from sys.tables where where is_ms_shipped =0 and [name] like temptb\_% escape \’
— select @sql;
EXEC(@sql);
检查删除是否正确
select * from sys.tables
正确,则提交事务,确认删除
commit tran
不正确,则回滚事务,取消删除
rollback tran
关闭隐式事务
SET IMPLICIT_TRANSACTIONS OFF

[转载]Asp.net MVC 2 + Castle + NHibernate 项目实战(1)

mikel阅读(1010)

[转载]Asp.net MVC 2 + Castle + NHibernate 项目实战(1) – Taven – 博客园.

本文将开始一步一步地使用ASP.NET MVC 2 + Castle + NHibernate 开发一个项目。

在开始之前,我先对这三个组件做一个简单的介绍:

ASP.NET MVC

它是微软提供的一个基于MVC标准的Web开发模式,其典型特点是有控制器和视图;在这之前,.NET下的Web开发模式大多是采用WebForm,其典型特点是服务端控件和后台触发事件;

NHibernate

它是一个ORM框架,使用Java的SSH做过项目开发的人就非常熟悉了,当前最新版本为NHibernate 3.0,听说完全支持Linq查询语句了,以前只支持HQL语句。

Castle

它是一个非常大的框架,包含IoC、MVC、ORM、AOP等,这次我只用到其IoC的功能。

关于IoC

IoC的英文是Inversion of Control,中文意思是控制反转,也有称其为Dependence Injection,中文意思是依赖注入,也就是DI;

除了Castle可以作IoC 外,还有著名的Spring.Net、Unity等,在我另外一个开源博客项目 http://rorowo.codeplex.com/ 中就用到了微软的Unity 2.0作为IoC。

好了,废话不多说,下面开始。

首先,第一步是创建一个解决方案,项目结构如下:

需要引用的DLL库文件,我们全部放在RoRoWo.Common.DependLib下:

根据表的结构,如图:

现在我们开始为表结构创建实体类,以BlogCategory表为例,我们根据该表的字段名称和数据类型创建一个POCO类,放在RoRoWo.Domain.Entities下,代码内容如下:

代码

namespace RoRoWo.Domain {

public class Blogcategory {
public Blogcategory() { }
public virtual int Cateid { get; set; }
public virtual IList<Blogarticle> Blogarticles { get; set; }
public virtual string Catename { get; set; }
public virtual int Parentid { get; set; }
public virtual int State { get; set; }
public virtual int Sortid { get; set; }
public virtual int Articlecount { get; set; }
public virtual System.DateTime Createtime { get; set; }
public virtual string Note { get; set; }
}
}

在这里,我推荐一个可以生成NHibernate映射对象代码的工具(开源的),项目地址:NHibernate Mapping Generator(它同时支持 hbm.xml文件的方式、Fluent Mapping方式、Castle ActiveRecord方式)

接下来,要为这个类创建一个映射关系,我这里使用配置文件的方式,但是正式项目推荐使用Fluent方式。我们创建一个XML文件,文件名为“Blogcategory.hbm.xml”,放在RoRoWo.Domain.Mappings下,内容如下:

代码

<?xml version=1.0 encoding=utf-8?>
<hibernatemapping assembly=RoRoWo.Domain namespace=RoRoWo.Domain xmlns=urn:nhibernate-mapping-2.2 defaultlazy=false>
<class name=Blogcategory table=BlogCategory>
<id name=Cateid column=CateID>
<generator class=native />
</id>
<property name=Catename column=CateName />
<property name=Parentid column=ParentID />
<property name=State column=State />
<property name=Sortid column=SortID />
<property name=Articlecount column=ArticleCount />
<property name=Createtime column=CreateTime />
<property name=Note column=Note />
</class>
</hibernatemapping>

这里就是一个典型的映射关系了,如果有一对多,多对多的表关系,也是在这个配置中进行维护。

创建这个XML后,还有个很重要的操作,就是将其设为“嵌入的资源” ,鼠标右键查看“Blogcategory.hbm.xml”文件属性,将“生成操作”项的“内容”改为“嵌入的资源”,如图:

到此,一个映射关系的实体就建立好了,下面我们就要来实现NHibernate对该表的增删改查操作了,我们把这些操作的实现放在RoRoWo.Data中。

注意,RoRoWo.Data需要添加对 “Castle.Core.dll” Castle.DynamicProxy2.dll NHibernate.dll RoRoWo.Domain 的引用。

在创建数据库操作类之前,我们需要创建一个 “SessionManager”类,它负责维护整个ORM中的上下文,这里我使用李永京的一个类,其代码如下:

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NHibernate;
using NHibernate.Cfg;

namespace RoRoWo.Data
{
public class SessionManager
{
private ISessionFactory _sessionFactory;
public SessionManager()
{
_sessionFactory = GetSessionFactory();
}
private ISessionFactory GetSessionFactory()
{
return (new Configuration()).Configure().BuildSessionFactory();
}
public ISession GetSession()
{
return _sessionFactory.OpenSession();
}
}
}

我们创建一个“BlogCategoryRespository.cs”文件,其代码如下:

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using RoRoWo.Domain;

namespace RoRoWo.Data
{
public class BlogCategoryRespository
{
private ISession _session;
public ISession Session
{
set
{
_session = value;
}
}

public BlogCategoryRespository(ISession session)
{
_session = session;
}

public Blogcategory GetById(int cateId)
{

return _session.Get<Blogcategory>(cateId);
}

public void Create(Blogcategory dto)
{
_session.Save(dto);
_session.Flush();
}

public int CreateAndReturn(Blogcategory dto)
{
int newid = (int)_session.Save(dto);
_session.Flush();
return newid;
}

/// <summary>
/// 使用事务
/// </summary>
/// <param name=”dto”></param>
/// <returns></returns>
public int CreateTransaction(Blogcategory dto)
{
using (ITransaction tx = _session.BeginTransaction())
{
try
{
int newId = (int)_session.Save(dto);
_session.Flush();
tx.Commit();
return newId;
}
catch (HibernateException)
{
tx.Rollback();
throw;
}
}
}

public void UpdateCustomer(Blogcategory dto)
{
_session.Update(dto);
_session.Flush();
}

public void SaveOrUpdate(IList<Blogcategory> dtos)
{
foreach (var c in dtos)
{
_session.SaveOrUpdate(c);
}
_session.Flush();
}

public void Delete(Blogcategory dto)
{
_session.Delete(dto);
_session.Flush();
}

public IList<Blogcategory> From()
{
//返回所有Blogcategory类的实例
return _session.CreateQuery(from Blogcategory)
.List<Blogcategory>();
}

public IList<int> Select()
{
//返回所有Blogcategory的CateId
return _session.CreateQuery(select c.CateId from Blogcategory c)
.List<int>();
}

public IList<Blogcategory> Where()
{
return _session.CreateQuery(from Blogcategory c where c.CateId=’3′)
.List<Blogcategory>();
}

public IList<Blogcategory> GetGreaterThan(int CateId)
{
//return _session.CreateQuery(“select from Blogcategory c where c.CateId > :cid”)
// .SetInt32(“cid”, CateId)
// .List<Blogcategory>();

return _session.CreateCriteria(typeof(Blogcategory))
.Add(Restrictions.Gt(CateId, CateId))
.List<Blogcategory>();

}

public IList<Blogcategory> CreateCriteria()
{
ICriteria crit = _session.CreateCriteria(typeof(Blogcategory));
crit.SetMaxResults(50);
IList<Blogcategory> blogcategorys = crit.List<Blogcategory>();
return blogcategorys;
}

public IList<Blogcategory> Narrowing()
{
IList<Blogcategory> blogcategorys = _session.CreateCriteria(typeof(Blogcategory))
.Add(Restrictions.Like(Catename, s%))
.Add(Restrictions.Between(Parentid, 1, 3))
.List<Blogcategory>();
return blogcategorys;
}

public IList<Blogcategory> Query()
{
Blogcategory dtoSample = new Blogcategory() { Catename = sss, Parentid = 0 };
return _session.CreateCriteria(typeof(Blogcategory))
.Add(Example.Create(dtoSample))
.List<Blogcategory>();
}

public IList<Blogcategory> UseQueryByExample_Get(Blogcategory dtoSample)
{
Example example = Example.Create(dtoSample)
.IgnoreCase()
.EnableLike()
.SetEscapeCharacter(&);
return _session.CreateCriteria(typeof(Blogcategory))
.Add(example)
.List<Blogcategory>();
}

}
}

该代码具有了对一个表的基本操作,现在我们就来创建一个单元测试,测试一下插入数据。

在创建插入操作时,我们要能使NHibernate正常工作,还需要创建一个配置文件,我们创建一个XML文件,文件名为“hibernate.cfg.xml”,放在RoRoWo.UnitTest下,其内容为:

代码

<?xml version=”1.0″ encoding=”utf-8″?>
<hibernate-configuration xmlns=”urn:nhibernate-configuration-2.2″ >
<session-factory>
<property name=”connection.driver_class”>NHibernate.Driver.SQLClientDriver</property>
<property name=”connection.connection_string”>
Data Source=.;Initial Catalog=RoRoWoDB;User ID=sa;Password=2010;
</property>
<property name=”adonet.batch_size”>10</property>
<property name=”show_SQL>true</property>
<property name=”dialect”>NHibernate.Dialect.MsSQL2005Dialect</property>
<property name=”use_outer_join”>true</property>
<property name=”command_timeout”>10</property>
<property name=”query.substitutions”>true 1, false 0, yes ‘Y’, no ‘N’</property>
<property name=”proxyfactory.factory_class”>
NHibernate.ByteCode.Castle.ProxyFactoryFactory,
NHibernate.ByteCode.Castle
</property>
<mapping assembly=”RoRoWo.Domain”/>
</session-factory>
</hibernate-configuration>

其中“Data Source=.;Initial Catalog=RoRoWoDB;User ID=sa;Password=2010;”是我的数据库连接,您可以改为您的。

现在我们添加一个单元测试(不明白如何添加的请参考相关资料),先测试插入方法,其代码如下:

代码

/// <summary>
///Create 的测试
///</summary>
[TestMethod()]
public void CreateTest()
{
SessionManager sessionManager = new SessionManager();
ISession session = sessionManager.GetSession();
BlogCategoryRespository target = new BlogCategoryRespository(session);
Blogcategory dto = new Blogcategory();

dto.Catename = 新分类 + new Random().Next(100000, 999999).ToString();
dto.Parentid = 0;
dto.State = 0;
dto.Createtime = DateTime.Now;

int newid = target.CreateAndReturn(dto);
Assert.IsTrue(newid > 0);
}

执行单元测试,可以通过测试,并且在数据库中已经成功插入了一条记录,结果完全正确;

我们接着对查询方法进行测试,我们将测试代码如下:

代码

/// <summary>
///GetById 的测试
///</summary>
[TestMethod()]
public void GetByIdTest()
{
SessionManager sessionManager = new SessionManager();
ISession session = sessionManager.GetSession();
BlogCategoryRespository target = new BlogCategoryRespository(session);
int cateId = 3;
Blogcategory actual;
actual = target.GetById(cateId);
Assert.AreEqual(cateId, actual.Cateid);

}

/// <summary>
///From 的测试
///</summary>
[TestMethod()]
public void FromTest()
{
SessionManager sessionManager = new SessionManager();
ISession session = sessionManager.GetSession();
BlogCategoryRespository target = new BlogCategoryRespository(session);
IList<Blogcategory> actual;
actual = target.From();
Assert.IsTrue(actual.Count > 0);

}

/// <summary>
///Select 的测试
///</summary>
[TestMethod()]
public void SelectTest()
{
SessionManager sessionManager = new SessionManager();
ISession session = sessionManager.GetSession();
BlogCategoryRespository target = new BlogCategoryRespository(session);
IList<int> actual;
actual = target.Select();
Assert.IsTrue(actual.Count > 0);
}

/// <summary>
///Where 的测试
///</summary>
[TestMethod()]
public void WhereTest()
{
SessionManager sessionManager = new SessionManager();
ISession session = sessionManager.GetSession();
BlogCategoryRespository target = new BlogCategoryRespository(session);

IList<Blogcategory> actual;
actual = target.Where();
Assert.IsTrue(actual.Count > 0);
}

/// <summary>
///GetGreaterThan 的测试
///</summary>
[TestMethod()]
public void GetGreaterThanTest()
{
SessionManager sessionManager = new SessionManager();
ISession session = sessionManager.GetSession();
BlogCategoryRespository target = new BlogCategoryRespository(session);
int CateId = 0; // TODO: 初始化为适当的值
IList<Blogcategory> actual;
actual = target.GetGreaterThan(CateId);
Assert.IsTrue(actual.Count > 0);

}

测试结果全部绿灯通过:

下一篇,我将谈谈如何配置一对多和多对多的表映射关系。

该例子的完整代码可以到开源平台下载,地址: http://rorowoproject.codeplex.com

文章中如有不足之处,望大家多指正

[转载]前端管窥:图片Sprite管理

mikel阅读(975)

[转载]前端管窥:图片Sprite管理 – BENNY CHIA! – 博客园.


Sprite 是每个前端工程师处理图片的基本技能。有些工程师昵称这项技能为“雪碧”,可见大家对这个东西的关爱程度。所谓图片的sprite技术,就是把网站用到的 小图片整合在一张比较大的“地图”上,然后在页面容器里对这张“地图”采用背景图片定位的方式来调用此处需要用到的那张小图片的位置。
Sprite的优势:
使用图片sprite技术的优势有三:一,减少针对图片的http请求 数,如果使用许多小图片的方式来组织页面,势必会造成加载页面的时候对每个图片文件形成一个http请求,如果使用sprite技术,则页面只需要对这些 小图片组成的大图进行一次请求即可,减小了网络负担。二,减小图片大小。使用sprite生成的大图其文件大小比其组成部分的小图片大小的总和要小,图片 越小,下载越快。且图片下载后所有在大图上的图片同时刷新出来,而不是每个图片分别刷新,网页的视觉整体性要好。三,便于图片管理。网页需要的各种尺寸的 icon图标和按钮图片等以整齐的顺序排列,便于图片修改和管理。
Sprite的劣势:
sprite的好处就是上面那些,不好之处也是有的,比如,如果你需要一 张背景透明的图片,众所周知IE6对png图片的支持不好,处理img图片尚有解决方法,处理背景平铺也有对策,但是处理一个sprite定位的背景图片 现在还没有好的解决方案。有些方案虽然能解决,但是对客户端造成的负担可以让你得不偿失。
这让我想到table和div之间的争论,有人做页面重 构工作,将一切table均使用div代替,事实是显示数据的表格还是table效果最好,非但数据表格,有些页面布局能够使用table简单解决,就不 必把问题复杂化。facebook和人人的弹窗就是用table写的,效果很好。
一些经验和建议:
现在在工作中,sprite图片越来越大,有的项目中sprite图片居然超 过1000px,这时我们就得去看看,这些组成sprite的小图片组织得是否合理。举例来看,google的logo图片下方充满了小图标,整个 google搜索页只用了这么一张28k大小的图片:

这么做对于google这种sprite基本不变,同时十分重视每1k图片大小的优化的网站来说,这么做有他的道理。但是在一般网站来说,我不建议 采用google的sprite排列方式,尤其不建议把logo做到sprite里。出于经常维护的需要,我们需要更好的图片维护,sprite最好能够 有一种规则,让你对其中每一个图标的位置都清清楚楚。

比如,利用PS的网格工具做参考,或者在PSD文件中建立一个框架图层,将网站各种尺寸的图标放在不同的横行,每个图标之间留出同样的尺寸,如果是 16px的icon,可以在每个16px的空间右边空出5px的距离放下一个图标,这样的话两个图标左边缘的距离就是21px,如果sprite左边第一 个icon的background-position为0 0的话,第10个icon的background-position就是-210px 0。这样你可以精确地知道每个图标的位置,今后调用图标只需要心算一下即可。


如果sprite图片的第一行放了16px的icon,第二行就可以用来安放24px的icon。如果sprite图片的宽度过大,也会对图片管理形成不便,这时候就可以把头一行的icon换行,放在24px的icon下方即可。
工作中还会碰到一种情况,做好的sprite图,优化得不是很好,出现了大的空隙,同时还有好多小图标放的地方不合适,想把这些图标移到空 隙里面去,这种工作岂不是要一个一个计算图标位置,麻烦可大了。我在这里给大家介绍个经验,开着css文件的同时开着excel,可以给你很大帮助。

如图,icon图标已经按照上面说的方法每21px安放一个,每个的位置我都很清楚,第一个图标的定位是-735px 0,第二个图标的定位是-756px 0。需要移动的图标在同一横行,图标数是23个。然后我把需要调整的icon整行剪切到图中另外一个位置,记下第一个图标在新位置的定位-63px -242px,第二个图标在新位置的定位是-84px -242px。于是把这两组数按图写进excel表里,并向下拉出共23行的等差数列,23个图标新旧位置的对应关系便出来了。然后在css中查找原来的 值并替换新值即可。如果找不到原来的值,说不定是原来在工作中为了处理特殊效果改变了正常的定位,后面做出“无”标记,单独处理就可以了。
总结
所以说,写好一个sprite对今后维护是多么重要的事情呵。下课~