前言
寫這篇博客只是發表個人的看法,探討如何搭建高效實用的框架,有不完善的地方可以留言補充.
正文
說起業務邏輯大家並不陌生,不管是簡單易懂的三層架構,還是復雜的DDD,都脫離不了業務邏輯,從字面意思理解,無非就是處理一些業務規則,這里不深究這些文字游戲,重點來說說我們工作中業務邏輯與數據的交互.
這里拿三層框架來舉例,UI,BLL,DAL,我們習慣把程序這樣划分,很多猿友認為BLL有點累贅,很通用的做法是在UI里直接訪問DAL,在DAL里編寫sql,來實現一個功能,咋一看上去功能確實ok,做WEB開發的猿友都知道核心功能往往只有那么一兩個,其它大多數都是簡單的增刪改查(分頁),60%的時間花費在前端數據的填充,30%的時間花費在DAL編寫sql,有些遠見的猿友會考慮到后期的維護,代碼的復用...然而在天朝,死道友不死貧道,為了自己不加班,往往會導致后面接手你項目的人通宵加班,這些都是后話了,隨着項目的越來越大,后期的拓展,慢慢發現前面有很多是曾相識的功能,這時候就會糾結,是重構還是在原有上面修改,因為不存在BLL,只能去重構或修改DAL里的sql語句,后期讓別人去維護這個項目會更糟.
如何搭建高效實用的框架,讓自己用的爽,讓別人維護的舒服?這里回歸BLL,常規的BLL直接拿DAL的數據返回給UI,看起來很弱,但是也屬於業務邏輯的一部分,就好比哈巴狗跟藏獒一樣,都是犬類,所以我把BLL分成兩塊,代碼如下
1 #region ((((((((((((((((((((((數據操作)))))))))))))))))))))))))))) 2 3 /// <summary> 4 /// 公共的操作數據庫方法,不可改變 5 /// </summary> 6 /// <param name="dto">dto參數集合</param> 7 /// <param name="db">數據庫操作對象</param> 8 /// <returns></returns> 9 #region //////////////公共方法區////////////////////// 10 #region ================查詢====================== 11 public users GetModel(Dtb_Users dto,Database db = null) 12 { 13 return d_user.GetModel(dto,db); 14 } 15 public users GetModel(object id, Database db = null) 16 { 17 if (db == null) 18 { 19 return d_user.Get(id); 20 } 21 else 22 { 23 return d_user.Get(id, db); 24 } 25 } 26 public List<users> GetList(Dtb_Users dto, Database db = null) 27 { 28 return d_user.GetList(dto,db); 29 } 30 public DataTable GetTable(Dtb_Users dto, Database db = null) 31 { 32 return d_user.GetTable(dto,db); 33 } 34 35 public bool Exists(int id, Database db = null) 36 { 37 return d_user.Exists(id,db); 38 } 39 40 public int GetCount(Dtb_Users dto, Database db = null) 41 { 42 return d_user.GetCount(dto, db); 43 } 44 #endregion 45 46 #region ================修改====================== 47 public bool Edit(users m_user,Database db = null) 48 { 49 var res = d_user.Edit(m_user,db); 50 return res.ToBool(); 51 } 52 #endregion 53 54 #region ================添加====================== 55 public int Add(users m_user, Database db = null) 56 { 57 var res = d_user.Add(m_user,db); 58 return res.ToInt32(); 59 } 60 #endregion 61 62 #region ================刪除====================== 63 public bool Del(object id, Database db = null) 64 { 65 var res = d_user.Del(id,db); 66 return res.ToBool(); 67 } 68 #endregion 69 70 #endregion 71 72 73 /// <summary> 74 /// 拓展方法由sql語法拼接而成,不依賴dto,更加的精簡,聯合查詢,主表對象必須是此model 75 /// </summary> 76 /// <param name="dto">dto參數集合</param> 77 /// <param name="db">事務鎖</param> 78 /// <returns></returns> 79 #region //////////////拓展方法區////////////////////// 80 #region ================查詢====================== 81 82 #region ****************普通查詢********************** 83 84 /// <summary> 85 /// 查詢id 86 /// </summary> 87 /// <param name="userName">用戶名</param> 88 /// <param name="mobile">手機號</param> 89 /// <param name="db">數據庫操作對象</param> 90 /// <returns>id</returns> 91 public int GetById(string userName,string mobile,Database db = null) 92 { 93 if (db == null) db = this.db; 94 string sql = "select id from dsxy_users where user_name=@0 and mobile=@1"; 95 DataTable dt = db.QueryTable(sql,userName,mobile); 96 var res = dt.Rows[0][0]; 97 return res.ToInt32(); 98 } 99 /// <summary> 100 /// 查詢model 101 /// </summary> 102 /// <param name="userName">用戶名</param> 103 /// <param name="mobile">手機號</param> 104 /// <param name="db">數據庫操作對象</param> 105 /// <returns>m_user</returns> 106 public DataTable GetModel(string userName, string mobile, Database db = null) 107 { 108 if (db == null) db = this.db; 109 string sql = "select id from dsxy_users where user_name=@0 and mobile=@1"; 110 DataTable dt = db.QueryTable(sql, userName,mobile); 111 return dt; 112 } 113 #endregion 114 115 #region ################關聯查詢####################### 116 /// <summary> 117 /// 查詢用戶等級 118 /// </summary> 119 /// <param name="userName">用戶名</param> 120 /// <param name="mobile">手機號</param> 121 /// <param name="db">數據庫操作對象</param> 122 /// <returns>用戶等級</returns> 123 public string GetByGroup(string userName, string mobile, Database db = null) 124 { 125 if (db == null) db = this.db; 126 StringBuilder sb = new StringBuilder(); 127 sb.Append("select g.title from dsxy_users u "); 128 sb.Append("left join dsxy_user_groups g on u.group_id = g.id "); 129 sb.Append("where u.user_name = @0 and u.mobile = @1 "); 130 string sql = sb.ToString(); 131 DataTable dt = db.QueryTable(sql, userName,mobile); 132 var res = dt.Rows[0][0]; 133 return res.ToString(); 134 } 135 136 #endregion 137 138 #endregion 139 #region ================修改====================== 140 /// <summary> 141 /// 修改用戶郵箱 142 /// </summary> 143 /// <param name="userName">用戶名</param> 144 /// <param name="mobile">手機號</param> 145 /// <param name="email">新郵箱</param> 146 /// <param name="db">數據庫操作對象</param> 147 /// <returns>bool</returns> 148 public bool EditEmail(string userName, string mobile,string email, Database db = null) 149 { 150 if (db == null) db = this.db; 151 string sql = "update dsxy_users set email=@0 where user_name = @1 and mobile = @2 "; 152 var res = db.Execute(sql, email, userName, mobile); 153 return res.ToBool(); 154 } 155 156 /// <summary> 157 /// 修改用戶登錄時間 158 /// </summary> 159 /// <param name="id">用戶id</param> 160 /// <param name="db"></param> 161 /// <returns></returns> 162 public bool EditLoginTime(int id, Database db = null) 163 { 164 if (db == null) db = this.db; 165 string sql = "update dsxy_users set logintime=@0 where id=@1 "; 166 var res = db.Execute(sql, DateTime.Now, id); 167 return res.ToBool(); 168 } 169 #endregion 170 #region ================添加====================== 171 172 /// <summary> 173 /// 添加用戶(返回成功失敗) 174 /// </summary> 175 /// <param name="userName">用戶名</param> 176 /// <param name="mobile">手機號</param> 177 /// <param name="pwd">密碼</param> 178 /// <param name="db">數據庫操作對象</param> 179 /// <returns>用戶id</returns> 180 public bool AddUser(string userName, string mobile, string pwd, Database db = null) 181 { 182 if (db == null) db = this.db; 183 string sql = "insert into dsxy_users(user_name,mobile,password)values(@0,@1,@2) "; 184 var res = db.Execute(sql, userName, mobile,pwd); 185 return res.ToBool(); 186 } 187 188 #endregion 189 #region ================刪除====================== 190 /// <summary> 191 /// 刪除用戶 192 /// </summary> 193 /// <param name="userName">用戶名</param> 194 /// <param name="mobile">手機號</param> 195 /// <param name="db">數據庫操作對象</param> 196 /// <returns>bool</returns> 197 public bool Del(string userName, string mobile,Database db = null) 198 { 199 if (db == null) db = this.db; 200 string sql = "delete dsxy_users where user_name = @0 and mobile = @1 "; 201 var res = db.Execute(sql, userName, mobile); 202 return res.ToBool(); 203 } 204 #endregion 205 #endregion 206 207 #endregion 208 209 #region ((((((((((((((((((((((業務邏輯)))))))))))))))))))))))))))) 210 public string Login(string username, string userpwd, string code,string codes) 211 { 212 Validation vali = new Validation(); 213 var res = vali.v_login(username, userpwd, code, codes); 214 //記錄最近登錄時間,無ip驗證,單點登錄 215 return res; 216 } 217 218 219 public users Login(string username, string userpwd) 220 { 221 Common common = new Common(); 222 users m_user = d_user.GetModel(new Dsxy.DTO.Dtb_Users() { user_name = username, password = common.md5(userpwd) });//普通登錄 223 if (m_user == null) 224 { 225 m_user = d_user.GetModel(new Dsxy.DTO.Dtb_Users() { mobile = username, password = common.md5(userpwd) });//手機號碼登陸 226 } 227 if (m_user != null) 228 { 229 //保存用戶狀態 230 Cookies.OYY_TOKEN = Rule.CreateToken(m_user.id); 231 } 232 return m_user; 233 } 234 235 236 237 public string m_Login(string mobile, string model_code) 238 { 239 Validation vali = new Validation(); 240 var res = vali.v_m_login(mobile,model_code); 241 if (res == "1") 242 { 243 m_Login(mobile); 244 } 245 return res; 246 } 247 248 public users m_Login(string mobile) 249 { 250 users m_user = d_user.GetModel(new Dsxy.DTO.Dtb_Users() { mobile = mobile });//手機號登錄 251 if (m_user == null) 252 { 253 //這里只需注冊邏輯(委托) 254 Delegates.dg_register dg_reg = new Delegates.dg_register(register); 255 int userid = dg_reg(mobile); 256 m_user = GetModel(userid); 257 } 258 //保存用戶狀態 259 Cookies.OYY_TOKEN = Rule.CreateToken(m_user.id); 260 return m_user; 261 } 262 263 public string register(string username, string mobile, string code, string pwd, string pwds) 264 { 265 Validation vali = new Validation(); 266 var res = vali.v_register(username, mobile,code,pwd,pwds); 267 if (res == "1") 268 { 269 register(mobile); 270 } 271 return res; 272 } 273 274 /// <summary> 275 /// 注冊邏輯,返回用戶id 276 /// </summary> 277 /// <param name="mobile"></param> 278 /// <param name="username"></param> 279 /// <param name="pwd"></param> 280 /// <returns></returns> 281 public int register(string mobile,string username = null, string pwd = null) 282 { 283 users m_user = new users(); 284 m_user.group_id = 1; 285 Random r = new Random(); 286 var sjs = "oyy" + r.Next(1000, 9999).ToString(); 287 m_user.user_name = username.IsNull()?mobile:username; 288 m_user.password = pwd; 289 m_user.mobile = mobile; 290 m_user.nick_name = username.IsNull() ? sjs : username; 291 m_user.reg_time = DateTime.Now; 292 m_user.reg_ip = common.Utils.getIp(); 293 m_user.LoginTime = DateTime.Now; 294 var res = Add(m_user); 295 if (res.ToBool()) 296 { 297 //保存用戶狀態 298 Cookies.OYY_TOKEN = Rule.CreateToken(m_user.id); 299 } 300 return res; 301 } 302 public string retrievepwd(string mobile, string code, string pwd, string pwds) 303 { 304 Validation vali = new Validation(); 305 var res = vali.v_retrievepwd(mobile, code, pwd, pwds); 306 if (res == "1") 307 { 308 retrievepwd(mobile,pwd); 309 } 310 return res; 311 } 312 313 /// <summary> 314 /// 找回密碼邏輯 315 /// </summary> 316 /// <param name="mobile"></param> 317 /// <param name="pwd"></param> 318 /// <returns></returns> 319 public bool retrievepwd(string mobile,string pwd) 320 { 321 Common com = new Common(); 322 users m_user = GetModel(new Dtb_Users() { mobile = mobile }); 323 m_user.password = com.md5(pwd); 324 var res = Edit(m_user); 325 return res; 326 } 327 /// <summary> 328 /// 獲取用戶登錄對象,沒有則返回null 329 /// </summary> 330 /// <returns></returns> 331 public users GetUser() 332 { 333 Validation b_vali = new Validation(); 334 users m_user = b_vali.v_Authorization(); 335 return m_user; 336 } 337 #endregion
第一塊是數據操作,數據操作分兩個區域,公共方法區(封裝了操作DAL的一些公共方法,增刪改查 分頁 排序),拓展方法區(可以通過手動編寫sql來實現一些復雜的sql操作),這里的底層我使用的是PetaPoco,感興趣的可以去學習下,還是非常便捷的,DAL我根據PetaPoco進行了一些拓展,讓它能夠更友好的調用PetaPoco,新增了一個層DTO(一個參數列表,每個Model都有一個與它對應的DTO,BLL,DAL),為此我特意寫了一套簡單的生成模板代碼,可以根據表直接生成DTO,BLL,DAL,Model.
第二塊是業務邏輯,UI需要操作哪些數據,我們就寫對應的方法就可以了,這里的方法只是單純的訪問數據,遇到復雜邏輯注意要寫事務,在關聯的主表的BLL里面寫對應的方法,調用別的BLL里的一些邏輯方法,讓每個BLL職責單一
流程如下:UI調用BLL的業務邏輯function,BLL的業務邏輯function調用BLL的數據訪問function
當框架搭好之后(基本都是直接生成),工作的時間花費30%為前端,60%為業務邏輯,后期的拓展也只是新增業務邏輯里的function即可!
