简单的web三层架构系统【第二版】

 

昨天写了 web三层架构的第一版,准确的说是三层架构的前期,顶多算是个二层架构,要慢慢完善。

 

第一版里,程序虽说能运行起来,但是有一个缺陷,就是里面的SQL语句,是使用的拼接字符进行执行。这样安全系数很低,如果有心人的话,可能会SQL注入,重新拼接字符,然后篡改我们的数据库内容,导致不可挽回的损失。

 

在第二版本,也就是这一版里,我对原来的SQL语句进行了重构,使用带参数的SQL语句对数据库进行操作,这样做的好处是,无论用户输入的是什么格式的字符,SQL语句都会原封不动的把这些字符写入到数据库中,这样就避免了有心人对字符进行拼接,导致数据库出错。

 

下面我用另一个小例子来说明防止SQL注入的核心代码,在最后会给出我重构过的第一版程序,也就是今天要写第二版程序:

 

这是DAO类中的insert方法:

 1         public bool insert(string name, string sex, string salary)
 2         {
 3             bool flag = false;
 4 
 5             SqlParameter[] paras = new 6             {
 7                 new SqlParameter("@name", name),
 8                 new SqlParameter("@sex", sex),
 9                 new SqlParameter("@salary", salary)
10             };
11 
12             string sql = "insert into person ([name], sex, salary) values (@name, @sex, @salary)";
13 
14             if (sq.ExecuteNonQuery(sql, paras) > 0)    //把SQL语句和SQL参数同时传入SQLHelper的ExecuteNonQuery中执行。
15             {                   //16                 flag = true;
17             }
18 
19             return flag;
20    }

 

这是SQLHelper类中的ExecuteNonQuery方法:

 1         public int ExecuteNonQuery(string sql, SqlParameter[] paras)
 2         {
 3             int result;
 4 
 5             cmd = new SqlCommand(sql, getcon());    //创建SQLcommand对象cmd
 6 
 7             cmd.Parameters.AddRange(paras);         //在SQLcommand对象cmd中,添加参数。
 8                               //上面的这一句注释,是自己的理解,如果理解错了,请在评论区帮忙指正一下,先谢过。
 9             result = cmd.ExecuteNonQuery();         //然后执行对象cmd,其中已经包含了SQL语句和要用的参数
10 
11             return result;
12       }

 

上面是一个小例子,创建了一张表,然后向表里的 NAME SEX SALARY 三个字段中添加内容。

 

 

 

下面是第二版web三层架构程序:

 

SQLhelper助手类:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 
  7 using System.Data;
  8 using System.Data.SqlClient;
  9 using System.Configuration;
 10 
 11 namespace DAL
 12 {
 13     public class SQLHelper
 14     {
 15         SqlCommand cmd = null;
 16 
 17         public string strcon()
 18         {
 19             string strcon = ConfigurationManager.ConnectionStrings["strcon"].ConnectionString;
 20 
 21             return strcon;
 22         }
 23 
 24         public SqlConnection getcon()
 25         {
 26             SqlConnection con = new SqlConnection(strcon());
 27 
 28             if (con.State == ConnectionState.Closed)
 29             {
 30                 con.Open();
 31             }
 32 
 33             return con;
 34         }
 35 
 36         #region 执行增删改查的SQL语句
 37         /// <summary>
 38         /// 执行增删改查的SQL语句
 39         /// </summary>
 40         /// <param name="sql">要执行的SQL</param>
 41         /// <returns>返回执行SQL语句后影响的行数</returns>
 42         public int ExecuteNonQuery(string sql)
 43         {
 44             int res;
 45 
 46             try
 47             {
 48                 cmd = new SqlCommand(sql, getcon());
 49 
 50                 res = cmd.ExecuteNonQuery();
 51             }
 52             catch (Exception ex)
 53             {
 54                 throw ex;
 55             }
 56             finally
 57             {
 58                 if (getcon().State == ConnectionState.Open)
 59                 {
 60                     getcon().Close();
 61                 }
 62             }
 63 
 64             return res;
 65         }
 66         #endregion
 67 
 68         #region 执行带参数的增删改SQL语句
 69         /// <summary>
 70         /// 执行带参数的增删改SQL语句
 71         /// </summary>
 72         /// <param name="sql">要执行的SQL语句</param>
 73         /// <param name="paras">传入的参数</param>
 74         /// <returns>返回受影响的行数</returns>
 75         public int ExecuteNonQuery(string sql, SqlParameter[] paras)//上下两个ExecuteNonQuery因为使用了方法的重载,其中参数不同,所以虽说都在调用ExecuteNonQuery,但是传递的参数的个数不同,系统会自动识别用哪一个ExecuteNonQuery方法。
 76         {
 77             int res;
 78 
 79             cmd = new SqlCommand(sql, getcon());//  1  
 80 
 81             cmd.Parameters.AddRange(paras);//  2  
 84 
 85             res = cmd.ExecuteNonQuery();
 86 
 87             return res;
 88         }
 89         #endregion
 90 
 91         #region 执行传入的SQL查询语句
 92         /// <summary>
 93         /// 执行传入的SQL查询语句
 94         /// </summary>
 95         /// <param name="sql">要执行的查询SQL</param>
 96         /// <returns>返回查询SQL语句的数据集</returns>
 97         public DataTable ExecuteQuery(string sql)
 98         {
 99             DataTable dt = new DataTable();
100 
101             //创建一个SqlCommand对象cmd,让其连接数据库,并指向sql语句。//自己理解,如果不对的话请在评论区指正,先谢过。
102             cmd = new SqlCommand(sql, getcon());
103 
104             //执行cmd连接的数据库.使用using后在执行完毕后,直接关闭sdr。不需要写sdr.closed.
105             using (SqlDataReader sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))//如果使用 CommandBehavior.CloseConnection 参数,那么在代码的结尾处就不需要写 getcon().Close(),他会直接关闭。
106             {
107                 dt.Load(sdr);// Load 这种方法适合于SqlDataReader。如果是SqlDataAdapter,则会用到 Fill 方法。
108             }
109 
110             return dt;
111         }
112         #endregion
113 
114         #region 执行传入带参数的SQL查询语句
115         /// <summary>
116         ///  执行传入带参数的SQL查询语句
117         /// </summary>
118         /// <param name="sql">要执行的SQL语句</param>
119         /// <param name="paras">传入的参数</param>
120         /// <returns>返回查询的数据集</returns>
121         public DataTable ExecuteQuery(string sql, SqlParameter[] paras)
122         {
123             DataTable dt = new DataTable();
124 
125             cmd = new SqlCommand("sql", getcon());
126 
127             cmd.Parameters.AddRange(paras);
128 
129             using (SqlDataReader sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
130             {
131                 dt.Load(sdr);
132             }
133 
134             return dt;
135         }
136         #endregion
137     }
138 }

 

 

personDAO员工操作类:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading.Tasks;
  6 
  7 using System.Data;
  8 using System.Data.SqlClient;
  9 
 10 namespace DAL
 11 {
 12     public class personDAO
 13     {
 14         SQLHelper sq = null;
 15 
 16         public personDAO()
 17         {
 18             sq = new SQLHelper();
 19         }
 20 
 21         #region 增加员工信息
 22         /// <summary>
 23         /// 增加员工信息
 24         /// </summary>
 25         /// <param name="name">要添加的员工姓名</param>
 26         /// <param name="sex">要添加的员工性别</param>
 27         /// <param name="salary">要添加的员工工资</param>
 28         /// <returns>返回真假值:如果是真显示添加成功,如果是假显示添加失败</returns>
 29         public bool insert(string name, string sex, string salary)
 30         {
 31             bool flag = false;
 32 
 33             SqlParameter[] paras = new SqlParameter[]
 34             {
 35                 new SqlParameter("@name", name),
 36                 new SqlParameter("@sex", sex),
 37                 new SqlParameter("@salary", salary)
 38             };
 39 
 40             string sql = "insert into person ([name], sex, salary) values (@name, @sex, @salary)";//记住,添加参数的时候,不需要 双引号 或是 单引号。
 41 
 42             if (sq.ExecuteNonQuery(sql, paras) > 0)//把sql语句和所用到参数数组,一起传送到 ExecuteNonQuery 中去执行。
 43             {
 44                 flag = true;
 45             }
 46 
 47             return flag;
 48         }
 49         #endregion
 50 
 51         #region 删除员工信息
 52         /// <summary>
 53         /// 删除员工信息
 54         /// </summary>
 55         /// <param name="id">要删除员工的id</param>
 56         /// <returns>返回真假值:如果是真显示删除成功,如果是假显示删除失败</returns>
 57         public bool delete(string id)
 58         {
 59             bool flag = false;
 60 
 61             SqlParameter[] paras = new SqlParameter[]
 62             {
 63                 new SqlParameter("@id", id)
 64             };
 65 
 66             string sql = "delete from person where id = @id";//记住,添加参数的时候,不需要 双引号 或是 单引号。
 67 
 68             if (sq.ExecuteNonQuery(sql, paras) > 0)
 69             {
 70                 flag = true;
 71             }
 72 
 73             return flag;
 74         }
 75         #endregion
 76 
 77         #region 更改员工信息
 78         /// <summary>
 79         /// 更改员工信息
 80         /// </summary>
 81         /// <param name="id">要更改的员工编号</param>
 82         /// <param name="name">要更改的员工姓名</param>
 83         /// <param name="sex">要更改的员工性别</param>
 84         /// <param name="salary">要更改的员工工资</param>
 85         /// <returns>返回真假值:如果是真显示更改成功,如果是假显示更改失败</returns>
 86         public bool update(string id, string name, string sex, string salary)
 87         {
 88             bool flag = false;
 89 
 90             SqlParameter[] paras = new SqlParameter[]//创建参数数组
 91             {
 92                 new SqlParameter("@id", id),//我的理解:对参数数组赋值
 93                 new SqlParameter("@name", name),
 94                 new SqlParameter("@sex", sex),
 95                 new SqlParameter("@salary", salary)
 96             };
 97 
 98             //使用参数数组
 99             string sql = "update person set [name] = @id, sex = @name, salary = @sex where id = salary";//记住,添加参数的时候,不需要 双引号 或是 单引号。
100 
101             if (sq.ExecuteNonQuery(sql, paras) > 0)
102             {
103                 flag = true;
104             }
105 
106             return flag;
107         }
108         #endregion
109 
110         #region 判断员工姓名是否重复
111         /// <summary>
112         /// 判断员工姓名是否重复
113         /// </summary>
114         /// <param name="name">要进行判断的员工姓名</param>
115         /// <returns>返回真假值:如果是真代表重复,如果是假进行添加</returns>
116         public bool repeat(string name)
117         {
118             bool flag = false;
119 
120             SqlParameter[] paras = new SqlParameter[]
121             {
122                 new SqlParameter("@name", name)
123             };
124 
125             string sql = "select * from person where [name] = @name";//记住,添加参数的时候,不需要 双引号 或是 单引号。
126 
127             #region 下面这样写的话,还要重新建立一张虚拟表,如果直接用下面的方法,进行行数的判断就不需要建立。
128             //DataTable dt = sq.ExecuteQuery(sql);
129 
130             //if (dt.Rows.Count > 0)//dt.Rows.Count 这个方法是检查返回的虚拟表中是不是有数据,如果有的话则行数不为零。如果没有的话则行数为零。
131             //{
132             //    flag = true;
133             //}
134             #endregion
135 
136             if (sq.ExecuteQuery(sql, paras).Rows.Count > 0)//dt.Rows.Count 这个方法是检查返回的虚拟表中是不是有数据,如果有的话则行数不为零。如果没有的话则行数为零。
137             {
138                 flag = true;
139             }
140 
141             return flag;
142         }
143         #endregion
144     }
145 }

 

 

上面就是重构的第一版的代码,也就是第二版,其中如果有错误的地方,请在评论区帮忙指正。

 

posted on 2014-12-28 13:11  ultrastrong  阅读(534)  评论(0编辑  收藏  举报