从零开始编写自己的C#框架(19)——Web层后端权限模块
不知不觉本系统写了快三个月了,最近写页面的具体功能时感觉到有点吃力,很多地方如果张嘴来讲的话可以说得很细,很全面,可写成文字的话,就不太会写了,有些地方想讲得清晰的话,得用多几倍的文字+实例+变化中的图片才能表达得清楚,而写这些又太费时间了,近段时间又特忙,所以只能是尽力而为,希望大家自行研究,如果有什么地方不明白的,发发评论或邮件给我,我再重新详细讲解。
说回正题,对于页面访问权限以及每个按键的权限控制,很久以前用过好几种不同的方法,比如为每个控件分配名称或编码,然后在写代码时绑定这些值,又比如用XML来配置制权限等方法。这些方法都比较麻烦,而且由于都是使用编码方法,开发时需要一个个进行绑定,容易出错。经过后来不断的完善,最后完成了本系统所采用的页面控件注册管理来绑定控件权限(如有雷同,纯属巧合,哈哈...),首先创建菜单,并绑定好对应的文件(页面),然后将系统要用到的名称添加到公用标识库中,跟着在页面控件权限管理页面对各个页面控件进行绑定(只需要点击鼠标即可),通过职位(角色)来赋于不同的操作权限,只需要设置好管理员的职位,那么该管理员就拥有他所绑定的角色的全部权限了。
如下面的说明
首先在后端注册菜单(菜单绑定页面)
创建公用页面权限标识,待用
为需要绑定页面控件权限的菜单页面绑定操作控件(左列为上图录入的公共控件名称,右列为已绑定的页面控件,只需要点击鼠标就可以轻松绑定)
创建好部门
在不同部门创建相应的职位(角色)
为不同角色设置菜单与页面控件操作权限
开发说明:(主要讲讲与上一章中不同的内容)
1、PagePowerSignPublicList.aspx.cs 公用页面控件权限标识列表管理文件
这个页面是比较经典的普通列表页面,比较代码,有以下一些地方和菜单页面不一样的
#region 加载数据
/// <summary>读取数据</summary>
public override void LoadData()
{
//设置排序
if (sortList == null)
{
Sort(null);
} //绑定Grid表格
bll.BindGrid(Grid1, Grid1.PageIndex + , Grid1.PageSize, null, sortList);
} #endregion
对于排序函数的调用,菜单页面是有层次感列表,所以要自定义排序函数,而对于正常的列表,我们直接调用父类的Sort(null)函数即可
绑定Grid表格也与菜单页面调用的不一样,bll.BindGrid()函数使用的是参数中需要添加当前在第几页,每个页面显示多少行,null是条件参数,后面会详细解释它怎么使用,最后一个参数是排序规则参数
另外,Delete()删除函数也使用批量删除功能,不过会在删除前进行检查,发现指定记录不能删除时,则弹出提示是那个Id的记录无法删除,大家自行比较一下两个列表文件就明白了。
2、PagePowerSignPublicEdit.aspx.cs公用页面控件权限标识编辑文件
这个文件要注意的地方是Save()函数
#region 保存
/// <summary>
/// 数据保存
/// </summary>
/// <returns></returns>
public override string Save()
{
string result = string.Empty;
int id = ConvertHelper.Cint0(hidId.Text); try
{
#region 数据验证 if (string.IsNullOrEmpty(txtCName.Text.Trim()))
{
return txtCName.Label + "不能为空!";
}
var sName = StringHelper.Left(txtCName.Text, );
if (PagePowerSignPublicBll.GetInstence().Exist(x => x.CName == sName && x.Id != id))
{
return txtCName.Label + "已存在!请重新输入!";
}
if (string.IsNullOrEmpty(txtEName.Text.Trim()))
{
return txtEName.Label + "不能为空!";
}
var sEname = StringHelper.Left(txtEName.Text, );
if (PagePowerSignPublicBll.GetInstence().Exist(x => x.EName == sEname && x.Id != id))
{
return txtEName.Label + "已存在!请重新输入!";
} #endregion #region 赋值
//定义是否更新标识——即当前记录的名称是否改变了
bool isUpdate = false; //获取实体
var model = new PagePowerSignPublic(x => x.Id == id); //判断是否有改变名称
if (id > && (sName != model.CName || sEname != model.EName))
{
isUpdate = true;
} //设置名称
model.CName = sName;
//设置英文名称
model.EName = sEname;
#endregion //----------------------------------------------------------
//存储到数据库
PagePowerSignPublicBll.GetInstence().Save(this, model); //判断是否需要同步更新关联表字段
if (isUpdate)
{
//调用更新函数,同步更新对应的所有记录
PagePowerSignBll.GetInstence().UpdateValue_For_PagePowerSignPublic_Id(this, model.Id, PagePowerSignTable.CName, model.CName, PagePowerSignTable.EName, model.EName);
}
}
catch (Exception e)
{
result = "保存失败!"; //出现异常,保存出错日志信息
CommonBll.WriteLog(result, e);
} return result;
}
#endregion
在函数中,大家可以找到下面这些代码
//定义是否更新标识——即当前记录的名称是否改变了
bool isUpdate = false; //判断是否有改变名称
if (id > && (sName != model.CName || sEname != model.EName))
{
isUpdate = true;
} //判断是否需要同步更新关联表字段
if (isUpdate)
{
//调用更新函数,同步更新对应的所有记录
PagePowerSignBll.GetInstence().UpdateValue_For_PagePowerSignPublic_Id(this, model.Id, PagePowerSignTable.CName, model.CName, PagePowerSignTable.EName, model.EName);
}
这是用于我们修改A表记录的名称时,同步修改其他关联表引用了这个记录名称字段的所有记录
为什么要这么处理呢?大家在看数据字典的数据库结构时,会发现很多表与其他表关联时,不单将其他表的Id引用了过来,还将这个Id对应的名称也引用了,这种操作方式使我们在编写查询语句时,几乎可以做到不用多表关联,因为我们想要显示的内容已经在查询的表中存在了,这样处理后,我们在修改相关表的名称时,就必须同步修改关联表中的名称,对于这些关联表名称的修改,我们的T4模板也生成了相应的函数,如:UpdateValue_For_表名_Id()函数,然后直接按上面代码编写方法实现就可以了。
3、UseLogList.aspx.cs用户操作日志管理文件
这个文件要注意的是InquiryCondition()函数
/// <summary>
/// 查询条件
/// </summary>
/// <returns></returns>
private List<ConditionHelper.SqlqueryCondition> InquiryCondition()
{
var wheres = new List<ConditionHelper.SqlqueryCondition>(); //如果Id有值时,即表示查询的是指定管理员的操作日志
if (_id != )
{
wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.Where, LoginLogTable.Manager_Id, Comparison.Equals, _id));
} //起始时间
if (!string.IsNullOrEmpty(dpStart.Text.Trim()))
{
wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.And, LoginLogTable.AddDate, Comparison.GreaterOrEquals, StringHelper.FilterSql(dpStart.Text)));
//终止时间
if (!string.IsNullOrEmpty(dpEnd.Text.Trim()))
{
wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.And, LoginLogTable.AddDate, Comparison.LessOrEquals, StringHelper.FilterSql(dpEnd.Text)));
}
} //ip地址
if (!string.IsNullOrEmpty(txtIp.Text.Trim()))
{
wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.And, LoginLogTable.Ip, Comparison.Equals, StringHelper.FilterSql(txtIp.Text)));
}
//登录备注信息
if (!string.IsNullOrEmpty(txtloginfo.Text.Trim()))
{
wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.And, LoginLogTable.Notes, Comparison.Like, "%" + StringHelper.FilterSql(txtloginfo.Text) + "%"));
} return wheres;
}
这是查询条件函数,ConditionHelper.SqlqueryCondition这个类是自定义封装条件类
它的构造函数(public SqlqueryCondition(ConstraintType ctype, string columnname, Comparison cparsion, object value, bool isParentheses = false))一共有5个参数,其中4个为必填参数
第一个参数ConstraintType ctype为查询的类型,主要是ConstraintType.Where、ConstraintType.And、ConstraintType.Or三种。
如果有多个条件时,ConstraintType.Where只能放在最前面,且只能有一个条件使用这个参数,一般都很少用它。
ConstraintType.And指的是当前参数与前面参数的关系是And关系
ConstraintType.Or通常情况下指的是当前参数与前面参数的关系是Or关系
第二个参数string columnname是条件列字段名称
第三个参数Comparison cparsion是表达式,使用Comparison.X来设置,根据需求设置==、>、>=、<、<=、like、in、not in......
第四个参数object value是条件值,如果是in与not in表达式时,条件值必须为数据类型,比如:string[]、int[]、object[]等
第五个参数bool isParentheses是加左括号,而右括号使用new ConditionHelper.SqlqueryCondition()或new ConditionHelper.SqlqueryCondition(Comparison.CloseParentheses)来添加,然后in或not in表达式时,必须紧跟着右括号
例子1:
(A<2 Or A>= 10) And B=100
var wheres = new List<ConditionHelper.SqlqueryCondition>(); wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.Where, "A", Comparison.LessThan, , true)); wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.Or, "A", Comparison.GreaterOrEquals, )); wheres.Add(new ConditionHelper.SqlqueryCondition()); wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.And, "B", Comparison.Equals, ));
例子2:
A == 2 And B in arr And C like 'abc%' (in查询必须加左右括号)
var wheres = new List<ConditionHelper.SqlqueryCondition>(); wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.Where, "A", Comparison.Equals, ));
//加左括号
wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.And, "B", Comparison.In, arr, true));
//加右括号
wheres.Add(new ConditionHelper.SqlqueryCondition()); wheres.Add(new ConditionHelper.SqlqueryCondition(ConstraintType.And, "C", Comparison.Like, "abc%"));
这个封装类最终会生成SubSonic3.0底层调用的条件参数,经过测试发现,SubSonic3.0底层调用的条件参数只支持单括号,不支持括号的嵌套,多重嵌套后最终生成的也只是单括号且会出错,所以多重嵌套括号时,最好使用其它方法来实现,比如Linq、存储过程、SQL语句拼接等。
4、小结
本次更新的代码功能比如多,已将部门、职位、公用页面控件权限标识、页面控件权限管理、在线用户列表、用户登陆日志、用户操作日志、错误日志等功能都已完成了,同时也对在线用户相关类和函数进行了优化处理。
内容看起来好像挺多了,其实都是对之前所写的模板函数以及其他公共函数的调用,这么多页面查看cs代码时可以发现,里面的内容都差不多,都是很格式化的东西,如果你尝试过用这些已完成的模板页面添加新功能,就可以发现很简单,开发也很迅速。
至于每个页面如何去实现,接下来就不必再像之前那样讲得很细致了,会针对一些特殊功能或函数的调用进行解说,往细讲也只能从逻辑层的各个函数应用来说起,所以就不再罗嗦一一细说,代码中有大量的注释,大家慢慢研究吧。
最好附上几张页面的效果图
由于框架不是非常成熟,很多朋友不是用来学习而是直接用到项目中,但不熟悉框架引起不少小问题,所以停止提供下载,有需要学习的可以到群共享里下,不便之处敬请谅解。
版权声明:
本文由AllEmpty原创并发布于博客园,欢迎转载,未经本人同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。如有问题,可以通过1654937@qq.com 联系我,非常感谢。
发表本编内容,只要主为了和大家共同学习共同进步,有兴趣的朋友可以加加Q群:327360708 ,大家一起探讨。
更多内容,敬请观注博客:http://www.cnblogs.com/EmptyFS/
从零开始编写自己的C#框架(19)——Web层后端权限模块的更多相关文章
- Web层后端权限模块
从零开始编写自己的C#框架(19)——Web层后端权限模块 不知不觉本系统写了快三个月了,最近写页面的具体功能时感觉到有点吃力,很多地方如果张嘴来讲的话可以说得很细,很全面,可写成文字的话,就不太 ...
- 从零开始编写自己的C#框架(18)——Web层后端权限模块——菜单管理
从本章开始,主要讲解的是页面中对框架相关功能的调用方法,比如列表页面(又分为有层次感列表和普通列表).编辑页面.多标签页面等,只要熟悉了这些函数的使用方法,那么开发起来就会很便捷了. 1.如图先创建菜 ...
- 从零开始编写自己的C#框架(1)——前言
记得十五年前自学编程时,拿着C语言厚厚的书,想要上机都不知道要用什么编译器来执行书中的例子.十二年前在大学自学ASP时,由于身边没有一位同学和朋友学习这种语言,也只能整天混在图收馆里拼命的啃书.而再后 ...
- 从零开始编写自己的C#框架 ---- 系列文章
目录: 从零开始编写自己的C#框架(1)——前言从零开始编写自己的C#框架(2)——开发前的准备工作从零开始编写自己的C#框架(3)——开发规范从零开始编写自己的C#框架(4)——文档编写说明从零开始 ...
- 从零开始编写自己的C#框架(17)——Web层后端首页
后端首页是管理员登陆后进入的第一个页面,主要是显示当前登陆用户信息.在线人数.菜单树列表.相关功能按键和系统介绍.让管理员能更方便的找到息想要的内容. 根据不同系统的需要,首页会显示不同的内容,比如显 ...
- 从零开始编写自己的C#框架(15)——Web层后端登陆功能
对于一个后端管理系统,最重要内容之一的就是登陆页了,无论是安全验证.用户在线记录.相关日志记录.单用户或多用户使用帐号控制等,都是在这个页面进行处理的. 1.在解决方案中创建一个Web项目,并将它设置 ...
- 从零开始编写自己的C#框架(8)——后台管理系统功能设计
还是老规矩先吐下槽,在规范的开发过程中,这个时候应该是编写总体设计(概要设计)的时候,不过对于中小型项目来说,过于规范的遵守软件工程,编写太多文档也会拉长进度,一般会将它与详细设计合并到一起来处理,所 ...
- 从零开始编写自己的C#框架(25)——网站部署
导航 1.关掉访问保护 2.发布网站 3.复制网站到服务器 4.添加新网站 5.设置网站访问权限 6.设置文件夹访问权限 7.控制可更新文件夹执行权限 8.设置“应用程序池”.net版本与模式 9.附 ...
- 从零开始编写自己的C#框架(25)——网站部署 【转】
服务器安全部署文档 目录1. 前言.. 3 2. 部署环境.. 3 2.1 服务器环境信息.. 3 3. 磁盘阵列配置.. 4 4. 安装操作系统.. ...
随机推荐
- Tcp/ip 报文解析
在编写网络程序时,常使用TCP协议.那么一个tcp包到底由哪些东西构成的呢?其实一个TCP包,首先需要通过IP协议承载,而IP报文,又需要通过以太网传送.下面我们来看看几种协议头的构成 一 .Ethe ...
- 让姑姑不再划拳 码农也要有原则 : SOLID via C#
“姑娘,别这样.我们是有原则的.” “一个有原则的程序猿是不会写出 “摧毁地球” 这样的程序的,他们会写一个函数叫 “摧毁行星”而把地球当一个参数传进去.” “对,是时候和那些只会滚键盘的麻瓜不同了, ...
- 回首经典的SQL Server 2005
原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com SQL Server是我使用时间最长的数据库,算起来已经有10年了.上世纪90年代,微软在软件开发的所有领域高歌猛 ...
- 快速搭建springmvc+spring data jpa工程
一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...
- 在Windows上编译和调试CoreCLR
生成CoreCLR - Windows篇 本文的唯一目的就是让你运行Hello World 运行环境 Window 7+ Visual studio 2015 确保C++ 工具已经被安装,默认是不安装 ...
- .Net语言 APP开发平台——Smobiler学习日志:手机应用的TextTabBar快速实现方式
参考页面: http://www.yuanjiaocheng.net/webapi/create-crud-api-1-put.html http://www.yuanjiaocheng.net/we ...
- Docker与CI持续集成/CD
背景 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制 ...
- Java之多态(二)
package test05;import test06.Car1;public class DuoTai_Test02 { /**多个对象,一个形态 * Tiger.Lion.Snake → Ani ...
- jira的插件开发流程实践
怎么开头呢,由于自己比较懒,博客一直不怎么弄,以后克己一点,多传点自己遇到的问题和经历上来,供自己以后记忆,也供需要的小伙伴少走点弯路吧 最近公司项目需要竞标一个运维项目,甲方给予了既定的几种比较常用 ...
- EntityFramework 6 + Mysql 生成POCOs
问题 使用EDMX文件 EF Power Tools参数不正确的解决方法 对于"异常来自 HRESULT:0x80070057 (E_INVALIDARG)",有方法说" ...