Curllion 的个人资料curllion照片日志列表更多 工具 帮助

curllion

MSN SPACES太慢了,我的博客搬家了 http://hi.baidu.com/curllion

Zhang Curllion

职业
地点
在我青春年少的时候,
有个女孩愿意为我去死,
她意志坚定地对我说:
你再缠着我,我就死给你看。
在我穷困潦倒的时候,
有个女人愿和我共赴黄泉,
她斩钉截铁地对我说:
你再不还钱,我就和你同归如尽!
My msn id : curllion@hotmail.com
感谢访问!
请稍候...
很抱歉,您输入的评论太长。请缩短您的评论。
您没有输入任何内容,请重试。
很抱歉,我们当前无法添加您的评论。请稍后重试。
若要添加评论,需要您的家长授予您相应权限。请求权限
您的家长禁用了评论功能。
很抱歉,我们当前无法删除您的评论。请稍后重试。
您已超过了一天之内允许提供的评论数上限。请在 24 小时后重试。
因为我们的系统表明您可能在向其他用户提供垃圾评论,您的帐户已禁用了评论功能。如果您认为我们错误地禁用了您的帐户,请联系 Windows Live 支持部门
完成下面的安全检查,您提供评论的过程才能完成。
您在安全检查中键入的字符必须与图片或音频中的字符一致。
Anika发表:
Hello,
I´m back. It was so wonderful in america!
12 月 15 日
庄梅发表:
你女儿很漂亮很可爱  我也有个儿子  现在有22个月了
12 月 8 日
晶晶发表:
谢谢你的支持~呵呵
10 月 29 日
2006/12/21

女儿1岁半

我女儿1岁半了,晚上老是哭个不停.
有一次她奶奶问她:你看看,这么晚了,还有谁在哭?
她说:有!
奶奶又问:你说,还有谁?
我女儿说:艾艾.---艾艾就是她自己
 
2006/7/19

一看就明白的线程的例子

在VS2005(dotnet2.0)中测试通过
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace test
{
    public partial class Form1 : Form
    {
        //声明一个委托,这个委托将会在两个地方用到
        public delegate void TimerStartHandle(string t);
        //用新定义的委托定义一个本Form的事件OnTimerStart,其实在这里不要理解为事件,理解为委托的一个实例更合适。
        public event TimerStartHandle OnTimerStart;
        public Form1()
        {
            InitializeComponent();
        }
        /// <summary>
        /// 改变标签的文本,
        /// </summary>
        /// <param name="t"></param>
        private void setLableText(String t)
        {
            this.label1.Text = t;
        }
        /// <summary>
        /// 在主线程的基础上,执行一个委托,这一步在dotnet2.0中必不可少
        /// 因为不能在别的线程中来修改主线程创建的控件的属性
        /// </summary>
        /// <param name="t"></param>
        private void setLableTextThread(String t)
        {
            this.BeginInvoke(new TimerStartHandle(this.setLableText), new object[] { t });
        }
        /// <summary>
        /// 线程池要执行的委托参数
        /// </summary>
        /// <param name="info"></param>
        private void StartTimer(object info)
        {
            do
            {
                //执行事件委托,所以在线程中每执行一次StartTimer,就会触发一次OnTimerStart事件。
                //从而会执行this.setLableTextThread中的语句
                //而在this.setLableTextThread中,又会执行一个委托,即:setLableText
                //这样就避开了在非主线程中修改由主线程创建的控件的问题
                this.OnTimerStart(System.DateTime.Now.ToString("hh:mm:ss"));
                Thread.Sleep(1000);
            }
            while (true);
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            //指定响应的事件
            this.OnTimerStart += new TimerStartHandle(this.setLableTextThread);
            //由线程池来执行this.StartTimer。这时会依次执行this.setLableTextThread,setLableText
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartTimer));
            //或创建一个线程
            //Thread thr = new Thread(this.StartTimer);
            //thr.Start();
        }
    }
}
 
上面的代码在VS2003中编译后可以运行,其实在vs2003(dotnet1.1)还有一个简单得多:
...
 
        private void Form1_Load(object sender, EventArgs e)
        {
            //指定响应的事件
            this.OnTimerStart += new TimerStartHandle(this.setLableTextThread);
            //由线程池来执行this.StartTimer。这时会依次执行this.setLableTextThread,setLableText
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.StartTimer));
            //或创建一个线程
            //Thread thr = new Thread(this.StartTimer);
            //thr.Start();
        }
 
        private void StartTimer(object info)
        {
            do
            {
                this.label1.Text = System.DateTime.Now.ToString("hh:mm:ss");
                Thread.Sleep(1000);
            }
            while (true);
        }
...
2006/4/18

能横向翻页的动态交叉查询存储过程

-----------------------------------按经销售商列出报销汇总交叉表,没有必要按状态来筛-------------------------------------
CREATE PROCEDURE schmreimburse_bydealer
@depid nvarchar(10),
@rstime datetime,
@retime datetime,
@pagesize int,   --输入每页的记录数
@currentpage int,    --输入当前页 ,0为起始页
@totalpages int output, --返回总页数
@newcpage int output --返回新的当前页 ,0为起始页
AS
declare @current as int --定义当前记录的位置
declare @total as int --定义记录总条数
declare @i as int --定义循环变量
set @total =(SELECT COUNT(DISTINCT emsdealer.jxname)
             FROM emsreimburse LEFT OUTER JOIN
                   emsmperform ON emsreimburse.porno = emsmperform.orno LEFT OUTER JOIN
                   emsdealer RIGHT OUTER JOIN
                   emswldw ON emsdealer.jxid = emswldw.jxid ON
                   emsmperform.wlid = emswldw.wlid
             WHERE (emsreimburse.reidate between @rstime and @retime) AND (emsdealer.depid = @depid)
             )
set @totalpages = ceiling(cast(@total as float)/ @pagesize)
if @currentpage < @totalpages
begin
   if @currentpage < 0
   begin
      set @newcpage = 0
   end
   else
   begin
      set @newcpage = @currentpage
   end
end
else
begin
   set @newcpage = @totalpages - 1
end
set @current =@newcpage * @pagesize + 1
--区域编号的临时变量
declare @jxname as nvarchar(50)
--存储用游标生成的SQL语句,4000字符是nvarchar类型的极限
declare @tmpsql as nvarchar(4000)
set @tmpsql = ''
--声明一个游标用来从表中循环读取所有的区域名称
declare c cursor scroll
for SELECT  emsdealer.jxname
    FROM emsreimburse LEFT OUTER JOIN
         emsmperform ON emsreimburse.porno = emsmperform.orno LEFT OUTER JOIN
         emsdealer RIGHT OUTER JOIN
         emswldw ON emsdealer.jxid = emswldw.jxid ON emsmperform.wlid = emswldw.wlid
    WHERE (emsreimburse.reidate between @rstime and @retime) AND (emsdealer.depid = @depid)
    GROUP BY emsdealer.jxname
    ORDER BY emsdealer.jxname
set @i = 0    
open c
--读取第一条记录
fetch absolute @current from c into @jxname
 --如果上一FETCH语句成功运行
while ((@@fetch_status = 0) and (@i < @pagesize))
begin
 set @tmpsql = @tmpsql + ',SUM(CASE emsdealer.jxname WHEN '''+ @jxname + ''' THEN emsreimburse.money ELSE 0 END) as ''' + @jxname + ''' '
 set @i = @i + 1
 fetch next from c into @jxname
end
close c
deallocate c
set @tmpsql = ' select emsmperform.fyid as 费用ID, emsexpenss.fyname as 费用类型 ' + @tmpsql +
      ' FROM emsexpenss RIGHT OUTER JOIN
      emsmperform ON emsexpenss.fyid = emsmperform.fyid RIGHT OUTER JOIN
      emsreimburse ON emsmperform.orno = emsreimburse.porno LEFT OUTER JOIN
      emsdealer RIGHT OUTER JOIN
      emswldw ON emsdealer.jxid = emswldw.jxid ON
      emsmperform.wlid = emswldw.wlid
WHERE (emsreimburse.reidate BETWEEN ''' + cast(@rstime as nvarchar(10)) + ''' AND ''' + cast(@retime as nvarchar(10)) + ''') AND
      (emsdealer.depid = ''' + @depid +  ''')
GROUP BY emsmperform.fyid, emsexpenss.fyname '
execute sp_executesql @tmpsql
--select @tmpsql as 'test'
GO
2006/1/18

C#中二进制运算在权限验证的应用

       在我的另一篇文章中[委托在权限验证中的应用](见我的blog: http://blog.csdn.net/curllion/http://spaces.msn.com/members/curllion)提到了一个函数ValidateAuthor,其实我以前见过这样实现的,就是一个权限用一个文本来表示,可能有“修改”、“填写”、“审核”、“删除”等等,这样,对于每个用户,在数据库中,都有一个字段,用来记录这样的权限,某用户权限值可能是“修改|删除|审核”,这样,在查找时,就会比较用户权限值中,有没有包括一个操作的名称。这样验证权限好办,但我弄不明白,权限的赋予与除去是如何实现的。每一个操作的权限值,用一个二进制数来表示,每个权限值,只能是(0),(10),(100),(1000),也就是说,是2的N次方,在MSSQL2000中,最大的
整数是bigint类型的,最大可以表示64种操作。当然,这个是远远不够的。所以可以给权限分组。比如,可分为文员,主管,经理,那么,我们最多可以分64个组,N0到N64组,第个组的权限值(rolevalue)就可以用2的N次方来表示,所以,可以表示64权限组了。这样,不同的用户,可能属于1个或是多个权限组,一个权限组,可能包括多个用户,同理,对于一个操作,可能会属于多个权限组,一个权限组,肯定要包括多个操作。
 
     先说说我的做法的主要思路:   
     如何记录一个权限呢,比如一个用户,他有一个权限值,最大可表示为2的64次方减1,所以,这个值有64个二进制位,那么,每一位要么是0,要么是1,所以,如果每一位表示一种权限的话,就可以表示64种权限了,因此,只要对指定的一位进行判断是0还是1,就可以验证用户的权限了。对于每一个操作的权限值,可以用一个二进制数来表示,每个权限值,只能是(0),(10),(100),(1000),也就是说,是2的N次方,在MSSQL2000中,最大的整数是bigint类型的,最大可以表示64种操作。当然,这个是远远不够的。所以可以给权限分组。比如,可分为文员,主管,经理,那么,我们最多可以分64个组,N0到N64组,第N个组的权限值(rolevalue)就可以用2的N-1次方来表示,所以,可以表示64个权限组了。这样,不同的用户,可以属于1个或是多个权限组,一个权限组,可能包括多个用户,同理,对于一个操作,可能会属于多个权限组,一个权限组,肯定要包括多个操作。因此,用户与操作是通过权限组联系以一起的。权限组与用户,与操作之间的对应关系,都是一对多的关系
现在说说用C#来实现,不是在SQL中实现。
在数据库中的表:
操作组:
opname     oprolevalue
填写             3            
修改             3
删除           11
提交             6
审核           12
权限组:
rolename  rolevalue
文员           1
主管           2
经理           4
总监           8
用户信息:
username userrolevalue
u1                5
在C#中:
Long userrolevalue ;//用户的权限值,根据他属于的权限组,这个值会不同
Long oprolevalue   ;//一个操作的权限值,根据他属于的权限组,这个值会不同
1、权限的赋予(或运算)
userrolevalue = userrolevalue | oprolevalue
      假设一个用户u1,他的初始权限值为0(00000000)。如果要指定他有经理的权限,经理的权限值为4(00000100),在第三个二进制位为1。很显然,userrolevalue =  0 | 4 ,值为4,如果u1要同时具有文员、主管、经理的权限呢,
userrolevalue = 0 | 1   00000000 | 00000001  = 00000001
userrolevalue = 1 | 2   00000001 | 00000010  = 00000011
userrolevalue = 3 | 4   00000011 | 00000100  = 00000111
这样,第1、2、3位都是1了,用 “或”的好处就是只改变指定位的值,如果用户已经有了该权限,再赋予一次,也不会出错,但是直接简单的用加法来做,这会出错了,如下:
userrolevalue = 7 | 4   00000111 | 00000100  = 00000111
2、权限的除去(求补、与运算)
userrolevalue = userrolevalue & (~oprolevalue)
      假设一个用户u1,他的初始权限值为7(00000111),说明他能做文员、主管、经理权限组所能作的所有操作。如果不想让他有主管权限组能作的操作呢,那么,就要把他的权限值变为00000101,而主管权限组的权限值是00000010,显然简单的用减法,肯定也是不行的,但是先对00000010作补运算,可以得到11111101,再同00000111作与运算,就得到了00000101,这样就只对第二位作了改变,不会影响到其它位,我们的目的也就达到了。对于一个操作,哪些权限组能操作它,也可以用与运算来做,不让某些权限组有些操作的权限,也可以先求补,再作与运算来解决。
3、权限的验证(与运算)
(userrolevalue & oprolevalue) != 0
      对于某用户,有没有某操作的权限,只要判断它们两个是不是属于同一个,或多个权限组就可以了,所以用与运算就最合适不过了。比如u1用户,他的权限值是5(文员组、经理组00000101),对于填写操作的权限值是00000011,说明对于文员组与主管组有填写的权限。因为 00000101 & 00000011 == 1。对于一个文员,他只属于文员组,他的权限值肯定是00000001了,对于提交操作0000110,因为00000101 &00000001 == 0,所以,他也就没有提交操作的权限了。
 
      此的验证方法,还可以用在菜单权限的验证上来。权限值还可以是Binary数据类型的,此类型的位数可以很大,因此可以用作不分权限组的情
况。
2006/1/17

委托在权限验证中的应用

      在开发中,我们希望一个窗体(或页面中)尽可能多地完成一些功能。比如,一个页面,可能即要做到能查询一批记录,还要做到用户能对这些记录进行审核、修改、删除。有时,我们会对菜单的权限进行控制,但菜单的权限控制只能限制权限不足的用户不能打开此窗口(WEB页面),而且,对于WEB页面,只控制了菜单,用户还是可以通过往地址栏输入地址来打开此页面的。
 
      如何对于同窗体中的不同功能进行权限控制呢?
 
      首先,我们明确要有多少种功能,假设有订货单的填写,查询,修改,删除,初审,复审,终审
我们先在数据库中建一个表,记录这7个操作。当然,还有其它内容的操作,也可以记录在此表中。
 
      然后建一个模板(窗体或是web页),这里用WEB页面来举例:
/// <summary>
/// 所有要求页面验证的页面的模板,可以执行页面验证及业务操作权限验证(用委托实现)
/// </summary>
namespace Leoas
{
/// <summary>
/// 使用委托来执行业务操作,同时来验证该操作的合法性
/// </summary>
public delegate void ExcProcEvent();
public class FormTemple : System.Web.UI.Page
{
 ......
 /// <summary>
 /// 在验证用户的业务操作权限后,再决定是否执行业务操作
 /// </summary>
 public event ExcProcEvent OnExcProc;
 protected void Page_Load(object sender, System.EventArgs e)
 {
  // 如果没有Session,则出错
  if(Session.Count == 0)
   Response.Redirect("/leoas/Errors.aspx?ErrID=7",true);
  //删除非本页所产生的临时Session
  this.SessionMutex(this.ToString());
  if(!IsPostBack)
  {
   //验证页面权限,仅仅限制菜单是没有用了,用户可以通过往地址栏输入地址来打开此页面的
   if(!Leoas.NoSqlMethod.ValidateAuthor(
    "rolevalue",
    Convert.ToUInt64(Leoas.NoSqlMethod.GetSelectedText("id",Session["s00001"].ToString(),"roleauthor",(System.Data.DataTable)Application["A00006"])),
    "pagename",
    this.ToString(),
    (System.Data.DataTable)Application["a00005"])
   )
   {
    Response.Redirect("/leoas/Errors.aspx?ErrID=6",true);
    Response.End();
   }
  }
 }
 /// <summary>
 /// 通过委托,来确定业务操作的执行
 /// </summary>
 /// <param name="proid">用户正在执行的操作</param>
 protected void ExcProc(string  proid)
 {
  //Leoas.NoSqlMethod.ValidateAuthor函数可以确定用户对某个操作是否有权限,其中session值保存了用户的ID,可以能过ID,由Leoas.NoSqlMethod.GetSelectedText来确定用户对应的权限值
  //总体思路是,用户有权限,则执行,没有就报错
  if(!Leoas.NoSqlMethod.ValidateAuthor("rolevalue",Convert.ToUInt64(Leoas.NoSqlMethod.GetSelectedText("id",Session["s00001"].ToString(),"roleauthor",(System.Data.DataTable)Application["A00006"])),"proid",proid,(System.Data.DataTable)Application["a00004"]))
  {
   string procname = Leoas.NoSqlMethod.GetSelectedText("proid",proid,"process",(System.Data.DataTable)Application["a00004"]);
   Response.Write("<script>window.alert('您没有\"" + procname + "\"操作的权限!\\n如确实需要,请与管理员联系!')</script>");
  }
  else
  {
   //执行委托
   this.OnExcProc();
  }
 }
...... 
}
}
 
最后就可以应用这个模板了,我们假设新建一个WEB页面,就可以从上面这个模板来继承:
namespace Leoas.EMS.Mbudget
{
 /// <summary>
 /// MbudgetAuditByDep 的摘要说明。
 /// </summary>
 public class MbudgetAuditByDep : Leoas.FormTemple
 {
  ......
  //重写
  new private void Page_Load(object sender, System.EventArgs e)
  {
   //调用基类的Page_Load,来验证用户对本页的访问权限
   base.Page_Load(sender,e);
   if(!IsPostBack)
   {
    this.BindData();
   }  
  }
  /// <summary>
  /// 取得主网格的数据源
  /// </summary>
  private void BindGrid_hz()
  {...}
    /// <summary>
  /// 取得明细网格数据
  /// </summary>
  private void BindGrid_mx()
  {...}
  /// <summary>
  /// 在汇总表中审核
  /// </summary>
  private void Audit_hz()
  {...}
  /// <summary>
  /// 在明细表中审核
  /// </summary>
  private void Audit_mx()
  {...}
  //响应[刷新]按钮click事件的总表的查询,其中,“00008”就是查询总表的操作的ID号,通过委托,
  //就会调用到Leoas.NoSqlMethod.ValidateAuthor函数,来比较用户对于“00008”这个操作是否有权限
  private void BT_refresh_Click(object sender, System.EventArgs e)
  {
   //查询之前,要先将表格的当前页设到第一页,因为有可能重新查询后,可能表的总页数会比当前页小
   this.DG_hz.CurrentPageIndex = 0;
   this.OnExcProc+=new ExcProcEvent(this.BindGrid_hz);
   this.ExcProc("00008");
   this.DG_mx.DataBind(); //清空明细表,防止误操作
  }
  //汇总表的翻页
  private void DG_hz_SelectedIndexChanged(object sender, System.EventArgs e)
  {
   this.OnExcProc+=new ExcProcEvent(this.BindGrid_mx);
   this.ExcProc("00008");
  }
  //在汇总表中审核,“00009”表示提交操作,“00010”表示审核操作
  private void BTAudit_hz_Click(object sender, System.EventArgs e)
  {
   if(this.DG_hz.Items.Count > 0)
   {
    this.OnExcProc+=new ExcProcEvent(this.Audit_hz);
    if(this.BTAudit_hz.Text == "提交")
     this.ExcProc("00009");
    else
     this.ExcProc("00010");
    this.BindGrid_hz();
    if(this.DG_mx.Items.Count > 0)
     this.BindGrid_mx();
   }
  }
  //明细表中的操作同上
  ...
  
 }
}
这样就可实现在WEB页面中对每个细节操作进行权限控制了。其实windows应用程序也是一样的,对于ValidateAuthor函数是如何验证权限的,可以看一下我其它的文章,我的blog是:http://spaces.msn.com/members/curllion
 
第 1 张,共 6 张