net项目总结一(1)
中小型新闻发布系统
代码结构:分为实体层,数据层与接口,数据工厂层,业务逻辑层,公共层,UI层(由于图片上传实在麻烦,所以只上传少量而已),项目中用到了工厂模式,解耦BLL层和DLL层
1、登录功能,记住三天功能,basepage中统一验证
1、做验证码,利用自定义一般处理程序类来实现
2、利用cookie实现记住三天状态的功能,实现免登录功能(如果在公共环境不建议使用)
3、统一登录验证
4、实现统一错误页面处理 ,全局应用程序文件中的Application_Error()中实现
2、引入必要的js
3、
登陆页面中取消按钮的制作:
<td>
<input type="button" value="登录" onclick="login()" />
<input type="button" value="取消" onclick="resetfm()" />
</td>
//4.0 负责清除当前表单中的所有带有name属性的控件值
function resetfm() {
document.getElementById("form1").reset();
}
4、建立验证码
4.1实现验证码逻辑:
/// <summary>
/// 实现验证码生成的一般处理程序类,记得在web.config中按照iis集成和经典模式做相应的配置
/// 由于此类中要使用session,所以必须实现接口IRequiresSessionState
/// </summary>
public class Vcode : IHttpHandler, System.Web.SessionState.IRequiresSessionState
{
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
//实现验证码功能
//1.0 产生验证码字符串
string vcode = GetVcode(4);
//2.0 将验证码字符串存入session
context.Session[Keys.Vcode] = vcode;
//3.0 将验证码字符串以图片的形式响应给浏览器
using (Image img = new Bitmap(65, 25))
{
//3.0.1 定义一个画家
using (Graphics g = Graphics.FromImage(img))
{
//3.0.2 利用画家对象在图片上将验证码字符串画上去
g.Clear(Color.White);
g.DrawRectangle(Pens.Red, 0, 0, img.Width - 1, img.Height - 1);
g.DrawString(vcode, new Font("黑体", 16, FontStyle.Bold | FontStyle.Strikeout), new SolidBrush(Color.Blue), 4, 4);
}
//3.0.3 利用图片的save方法将图片流保存到outputstream中
img.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
Random r = new Random();
private string GetVcode(int num)
{
string[] arrcode = { "a", "b", "c", "d", "4", "2", "3" };
int arrLeng = arrcode.Length;
string res = string.Empty;
for (int i = 0; i < num; i++)
{
res += arrcode[r.Next(arrLeng)];
}
return res;
}
}
4.2写好了验证码的类,那么需要在配置文件中添加配置
<system.webServer>
<handlers>
<add name="vcode" path="*.vcode" verb="*" type="EMS12.Site.admin.Vcode" />
</handlers>
</system.webServer>
4.3验证码调用示例
<td>
<input type="text" id="vcode" name="vcode" />
<img id="imgvcode" style="cursor: pointer" src="vcode.vcode" alt="验证码" height="25px" width="65px" />
</td>
4.4验证码点击替换(注意此时的math.random的用法)
//2.0 点击验证码图片的时候进行新的请求
$("#imgvcode").click(function () {
reflushvcode();
});
function reflushvcode() {
//this.src = "vcode.vcode?rid=" + Math.random(); //js的写法
$("#imgvcode").attr("src", "vcode.vcode?rid=" + Math.random()); //JQ的写法
}
5、利用ajax进行登陆验证。
5.1 //3.0 利用jquery ajax实现登录处理过程
function login() {
//1.0 获取表单form1中的所有带有name属性的参数的键值对
var parms = $("#form1").serialize(); //uname=?&pwd=?&vcode=?
//2.0 利用$.post方法将parms参数提交给 /actions/admin/login.ashx
$.post("/actions/admin/login.ashx", parms, function (ajaxobj) {
if (ajaxobj.status == "1") {
msgbox.showMsgErr(ajaxobj.msg, function () {
// 刷新页面
//window.location = window.location;
//刷新验证码
reflushvcode();
});
} else {
//登录成功
msgbox.showMsgOk(ajaxobj.msg, function () {
window.location = "index.aspx";
});
}
}, "json")
}
5.2接着开始撰写登陆验证一般处理程序(处理步骤是什么?)
using EMS12.BusinessLogicLayer;
using EMS12.Entity;
using EMS12.Common;//需要的是里面的key,一段加密验证
/// <summary>
/// login 的摘要说明
/// </summary>
public class login : BaseHandler, System.Web.SessionState.IRequiresSessionState //继承两个接口,第二个接口来实现session
{
public override void SubPR()
{
Response.ContentType = "text/plain";
try
{
//开始登录逻辑编写
//1.0 接收参数
string uname = Request.Form["uname"];
string pwd = Request.Form["pwd"];
string vcode = Request.Form["vcode"];
//2.0 验证码的合法性验证
string vcodeFromSession = string.Empty;
if (Session[Keys.Vcode] != null)
{
vcodeFromSession = Session[Keys.Vcode].ToString();
}
if (string.IsNullOrEmpty(vcode)
|| vcode.Equals(vcodeFromSession, StringComparison.OrdinalIgnoreCase) == false)
{
WriteError("验证码错误");
// Response.End(); //此时会将当前处理现场强制终止,一定会抛出一个异常
return;
}
//3.0 验证用户名和密码的合法性
if (string.IsNullOrEmpty(uname) || string.IsNullOrEmpty(pwd))
{
WriteError("用户名或者密码不能为空");
return;
}
string md5pwd = Kits.MD5Entry(pwd);
UserInfoEntity entity = UserInfo_BLLSub.Login(uname, md5pwd);
if (entity == null)
{
WriteError("用户名或者密码错误");
return;
}
//4.0 将用户实体存入session[uinfo]
Session[Keys.uinfo] = entity;
//5.0 将ajaxobj对象序列化成json字符串返回
WriteSuncess("登录成功,正在跳转到首页....");
}
catch (Exception ex)
{
WriteError(ex.Message);
}
}
}
6.附加的kits。就是common下的加密验证
using System.Text.RegularExpressions;
/// <summary>
/// 帮助类
/// </summary>
public class Kits
{
/// <summary>
/// 判断当前字符串是否为一个数字
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static bool IsInt(string str)
{
int res = 0;
return int.TryParse(str, out res);
}
/// <summary>
/// 判断当前字符串是否为一个数字
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static bool IsNumber(string str)
{
//Regex reg = new Regex("^[0-9]+$");
Regex reg = new Regex("^\\d+$");
return reg.IsMatch(str);
}
/// <summary>
/// 将明文加密成md5格式的密文
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string MD5Entry(string str)
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "md5");
}
/// <summary>
/// 负责将对象序列化成json字符串
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string ToJsonString(object obj)
{
System.Web.Script.Serialization.JavaScriptSerializer jsor = new System.Web.Script.Serialization.JavaScriptSerializer();
return jsor.Serialize(obj);
}
/// <summary>
/// 负责将json字符串反序列化成对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="jsonstr"></param>
/// <returns></returns>
public static T DeserializeFromJsonString<T>(string jsonstr)
{
System.Web.Script.Serialization.JavaScriptSerializer jsor = new System.Web.Script.Serialization.JavaScriptSerializer();
return jsor.Deserialize<T>(jsonstr);
}
}
7.附加的BaseHandler,相当于父类
using EMS12.Common;
/// <summary>
/// 负责封装上下文中的相关属性
/// </summary>
public abstract class BaseHandler : IHttpHandler
{
#region 1.0 封装上下文中的相关属性
protected HttpContext Context
{
get
{
return HttpContext.Current;
}
}
protected HttpRequest Request
{
get
{
return this.Context.Request;
}
}
protected HttpResponse Response
{
get
{
return this.Context.Response;
}
}
protected HttpSessionState Session
{
get
{
return Context.Session;
}
}
#endregion
#region 2.0 封装ajax相关请求的方法和对象
AjaxObj obj = new AjaxObj();
/// <summary>
/// 成功返回统一调用
/// </summary>
/// <param name="msg"></param>
protected void WriteSuncess(string msg)
{
obj.status = Estatus.suncess;
obj.msg = msg;
Response.Write(Kits.ToJsonString(obj));
}
/// <summary>
/// 成功返回统一调用
/// </summary>
/// <param name="msg"></param>
/// <param name="data"></param>
protected void WriteSuncess(string msg, object data)
{
obj.status = Estatus.suncess;
obj.msg = msg;
obj.datas = data;
Response.Write(Kits.ToJsonString(obj));
}
/// <summary>
/// 统一进行错误异常信息的返回
/// </summary>
/// <param name="msg"></param>
protected void WriteError(string msg)
{
obj.status = Estatus.error;
obj.msg = msg;
Response.Write(Kits.ToJsonString(obj));
}
#endregion
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
// 什么都不做,只是调用一下子类中实现的抽象方法
SubPR();
}
public abstract void SubPR();
}
8.分析用户名和密码验证中,生成代码并没有那么应该怎么去做的逻辑。首先,我们想到去用new出BLL来。找到UserInfoBLLSub.cs,里面并没有提供任何函数,但是他继承于父类UserInfo_BLLSub : UserInfoBLLBase,在BusinessLogicLayerBase每个都有对应的父类。里面实现了全部的基本方法
看到方法:
/// <summary>
/// 得到 userinfo 数据实体
/// </summary>
/// <param name="user_id">user_id</param>
/// <returns>userinfo 数据实体</returns>
public static UserInfoEntity Get_UserInfoEntity(int user_id)
{
// Validate input
if(user_id<0)
return null;
// Use the dal to get a record
return _dal.Get_UserInfoEntity(user_id);
}
这里面只有通过id来获得实体而已。所以我们需要自己去写这个方法
步骤1:去接口层(IUserInfoDALSub.cs)定义一个接口:
那么我们先来看到接口层IUserInfoDALSub.cs
/// <summary>
/// 数据层 dbo.UserInfo 接口。
/// </summary>
public interface IUserInfoDataAccessLayer:IUserInfoDataAccessLayerBase
{
//发现还是继承了父类,接着我们去查看父类
}
父类:IUserInfoDAL(这个只是文件名,但是定义的接口名称是随意的,所以不要看错了
接口约定了我们基本的增删查改的方法
public interface IUserInfoDataAccessLayerBase
{
#region 基本方法
/// <summary>
/// 向数据库中插入一条新记录。
/// </summary>
/// <param name="_UserInfoModel">UserInfo实体</param>
/// <returns>新插入记录的编号</returns>
int Create_UserInfoInsert(UserInfoEntity _UserInfoModel);
/// <summary>
/// 向数据库中插入一条新记录。带事务
/// </summary>
/// <param name="sp">事务对象</param>
/// <param name="_UserInfoModel">UserInfo实体</param>
/// <returns>新插入记录的编号</returns>
int Create_UserInfoInsert(SqlTransaction sp,UserInfoEntity _UserInfoModel);
/// <summary>
/// 向数据表UserInfo更新一条记录。
/// </summary>
/// <param name="_UserInfoModel">_UserInfoModel</param>
/// <returns>影响的行数</returns>
int Create_UserInfoUpdate(UserInfoEntity _UserInfoModel);
/// <summary>
/// 向数据表UserInfo更新一条记录。带事务
/// </summary>
/// <param name="sp">事务对象</param>
/// <param name="_UserInfoModel">_UserInfoModel</param>
/// <returns>影响的行数</returns>
int Create_UserInfoUpdate(SqlTransaction sp,UserInfoEntity _UserInfoModel);
/// <summary>
/// 删除数据表UserInfo中的一条记录
/// </summary>
/// <param name="user_id">user_id</param>
/// <returns>影响的行数</returns>
int Create_UserInfoDelete(int user_id);
/// <summary>
/// 删除数据表UserInfo中的一条记录,带事务
/// </summary>
/// <param name="sp">事务对象</param>
/// <param name="user_id">user_id</param>
/// <returns>影响的行数</returns>
int Create_UserInfoDelete(SqlTransaction sp,int user_id);
/// <summary>
/// 根据UserInfo返回的查询DataRow创建一个UserInfoEntity对象
/// </summary>
/// <param name="row">row</param>
/// <returns>UserInfo对象</returns>
UserInfoEntity Populate_UserInfoEntity_FromDr(DataRow row);
/// <summary>
/// 得到 userinfo 数据实体
/// </summary>
/// <param name="user_id">user_id</param>
/// <returns>userinfo 数据实体</returns>
UserInfoEntity Get_UserInfoEntity(int user_id);
/// <summary>
/// 得到数据表UserInfo所有记录
/// </summary>
/// <returns>数据实体</returns>
IList< UserInfoEntity> Get_UserInfoAll();
/// <summary>
/// 检测是否存在根据主键
/// </summary>
/// <param name="user_id">user_id</param>
/// <returns>是/否</returns>
bool IsExistUserInfo(int user_id);
#endregion
}
于是,我们开始定义验证用户名和密码的接口:
/// <summary>
/// 数据层 dbo.UserInfo 接口。
/// </summary>
public interface IUserInfoDataAccessLayer:IUserInfoDataAccessLayerBase
{
UserInfoEntity GetUserInfo(string uname, string md5pwd);
}
步骤2:定义好接口之后,那么这个接口由谁去实现呢?其实,接口的父类,已经由DAL去实现了,可以查看UserInfoDAL.CS
我们查看的是EMS12.DataAccessLayer下的DataAccessLayer下的UserInfoDAL.CS,就是父类了
/// <summary>
/// 数据层实例化接口类 dbo.UserInfo.
/// </summary>
public partial class UserInfoDataAccessLayer : IUserInfoDataAccessLayer
{
里面实现了所有接口定义的方法
}
同时,我们要知道这里的DAL跟BLL不同,BLL中的之类是直接去继承父类的, public class UserInfo_BLLSub : UserInfoBLLBase,
但是,DAL不是用之类去做的,而是用partial来形成共同代码,只是分开而已。public partial class UserInfoDataAccessLayer : IUserInfoDataAccessLayer,因为它是实现接口的。
于是我们在DAL中去实现这个接口:
/// <summary>
/// 数据层实例化接口类 dbo.UserInfo.
/// </summary>
public partial class UserInfoDataAccessLayer : IUserInfoDataAccessLayer
{
public UserInfoEntity GetUserInfo(string uname, string md5pwd)
{
UserInfoEntity _obj = null;
SqlParameter[] _param ={
new SqlParameter("@uname",SqlDbType.VarChar),
new SqlParameter("@md5pwd",SqlDbType.VarChar)
};
_param[0].Value = uname;
_param[1].Value = md5pwd;
string sqlStr = "select top 1 * from UserInfo where u_name =@uname and u_pwd = @md5pwd ";
using (SqlDataReader dr = SqlHelper.ExecuteReader(Conn.SqlConn, CommandType.Text, sqlStr, _param))
{
while (dr.Read())
{
_obj = Populate_UserInfoEntity_FromDr(dr);
}
}
return _obj;
}
}
步骤3:那么DAL实现了之后呢,开始BLL的实现,那么要实现什么呢?
/// <summary>
/// 登录方法
/// </summary>
/// <param name="uname"></param>
/// <param name="md5pwd"></param>
/// <returns></returns>
public static UserInfoEntity Login(string uname, string md5pwd)
{
return _dal.GetUserInfo(uname, md5pwd);
}
#endregion
步骤4:开始校验
UserInfoEntity entity = UserInfo_BLLSub.Login(uname, md5pwd);
if (entity == null)
{
WriteError("用户名或者密码错误");
return;
}
步骤五:由于受到工厂模式的作用,反射等,所以全部归结到UI层中被调用
怎么限制到的呢?是在web.config配置的
<configuration>
<connectionStrings>
<add name="conn" connectionString="server=.;database=kyprint;uid=sa;pwd=master;"/>
</connectionStrings>
<appSettings>
<!--表示在工厂中要通过此配置获取DAL层程序集并且反射出其中的类的对象-->
<add key="Dal" value="EMS12.DataAccessLayer" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<handlers>
<add name="vcode" path="*.vcode" verb="*" type="EMS12.Site.admin.Vcode" />
</handlers>
</system.webServer>
</configuration>
9、后台管理中心首页菜单的制作
<%=menus %>
直接用上定义好的字符串,再在后台处理这个字符串
/// <summary>
/// 负责存放从menus表中查询出数据以后动态拼装成li标签代码
/// </summary>
public System.Text.StringBuilder menus = new System.Text.StringBuilder(200);
protected void Page_Load(object sender, EventArgs e)
{
InitMenus();
}
private void InitMenus()
{
//1.0 查询数据表menus以集合的形式返回
IList<MenusEntity> list = Menus_BLLSub.Get_MenusAll();
//2.0 遍历 集合,生成1级菜单
if (list.Any()) //判断集合有没有数据的方法
{
foreach (MenusEntity item in list)
{
//判断当前数据是否是一级菜单并且状态为正常
if (item.m_parent_mid < 0 && item.m_status == (int)ENums.EState.Normal)
{
menus.AppendLine("<li class=\"level1\">" + item.m_name + "</li>");
//3.0 遍历 集合,生成2级菜单
GenSubMenus(item.m_id, list);
}
}
}
}
net项目总结一(1)的更多相关文章
- Fis3前端工程化之项目实战
Fis3项目 项目目录结构: E:. │ .gitignore │ fis-conf.js │ index.html │ package.json │ README.md │ ├─material │ ...
- 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新
本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...
- 最近帮客户实施的基于SQL Server AlwaysOn跨机房切换项目
最近帮客户实施的基于SQL Server AlwaysOn跨机房切换项目 最近一个来自重庆的客户找到走起君,客户的业务是做移动互联网支付,是微信支付收单渠道合作伙伴,数据库里存储的是支付流水和交易流水 ...
- Hangfire项目实践分享
Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...
- Travis CI用来持续集成你的项目
这里持续集成基于GitHub搭建的博客为项目 工具: zqz@ubuntu:~$ node --version v4.2.6 zqz@ubuntu:~$ git --version git versi ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新
上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...
- Angular企业级开发(5)-项目框架搭建
1.AngularJS Seed项目目录结构 AngularJS官方网站提供了一个angular-phonecat项目,另外一个就是Angular-Seed项目.所以大多数团队会基于Angular-S ...
- 【分享】标准springMVC+mybatis项目maven搭建最精简教程
文章由来:公司有个实习同学需要做毕业设计,不会搭建环境,我就代劳了,顺便分享给刚入门的小伙伴,我是自学的JAVA,所以我懂的.... (大图直接观看显示很模糊,请在图片上点击右键然后在新窗口打开看) ...
- ABP入门系列(2)——通过模板创建MAP版本项目
一.从官网创建模板项目 进入官网下载模板项目 依次按下图选择: 输入验证码开始下载 下载提示: 二.启动项目 使用VS2015打开项目,还原Nuget包: 设置以Web结尾的项目,设置为启动项目: 打 ...
随机推荐
- Kafka学习总结
Kafka学习总结 参考资料: 1.http://kafka.apachecn.org/, kafka官方文档 2.https://www.cnblogs.com/likehua/p/3999538. ...
- java中将数字的字符串表示转化为数字
int a = new Integer("1234").intValue() 或 int b = Integer.parseInt("1234") System ...
- 在Centos7下安装Python+Selenium+Firefox学习环境
Selenium 一自动化测试工具.它支持 Chrome,Safari,Firefox 等主流界面式浏览器,如果你在这些浏览器里面安装一个 Selenium 的插件,那么便可以方便地实现Web界面的测 ...
- 【bzoj1087】互不侵犯King 状态压缩dp
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1087 [题解] 用f[i][j][k]表示前i行放了j个棋子且第i行的状态为k的方案数. ...
- 温(Xue)习排序算法
最近忙着找工作,虽然排序算法用得到的情况不多,但不熟悉的话心里始终还是感觉没底. 于是今天给温习了其中的四个排序算法(与其说是温习,不如说是学习...因为感觉自己好像从来木有掌握过它们...) 一.选 ...
- 综合:bool类型 命名空间 输入输出
----------siwuxie095 题目要求: 使用一个函数找出一个整型数组中的最大值或最小值 注意: 1.直接书写 cin cout endl, ...
- java替换特殊字符串
开始想到String.replaceFirst(regex, replacement)和String.replaceAll(regex, replacement); 但特殊字符没替换成功. 用法:St ...
- asdfadsf
bool is_r_value(int &&) { return true; } bool is_r_value(const int &) { return false; } ...
- linux下mysql开启远程访问权限及防火墙开放3306端口(mysql开放host访问权限)
开启mysql的远程访问权限默认mysql的用户是没有远程访问的权限的,因此当程序跟数据库不在同一台服务器上时,我们需要开启mysql的远程访问权限.主流的有两种方法,改表法和授权法.相对而言,改表法 ...
- macOS 10.13 安装Virtualbox失败
macOS 10.13 安装Virtualbox失败 Enviroment macOS: 10.13 High Sierra virtualBox: 5.1.28 Problem descriptio ...