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);

                    }

                }

            }

        }

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。