首頁 > web前端 > js教程 > 主體

如何使用AngularJs打造權限管理系統【簡易型】_AngularJS

WBOY
發布: 2016-05-16 09:00:21
原創
2419 人瀏覽過

一、引言

  本文將介紹如何把angularjs應用到實際專案中。這篇文章將使用angularjs來打造一個簡易的權限管理系統。下面不多說,直接進入主題。

二、整體架構設計介紹

  先看下整個專案的架構設計圖:

  從上圖可以看出整個專案的一個整體結構,接下來,我來詳細介紹了專案的整體架構:

  採用asp.net web api來實作rest 服務。這樣的實現方式,已達到後端服務的公用、分別部署和更好地擴展。 web層依賴應用服務接口,並使用castle windsor實作依賴注入。

顯示層(使用者ui)

  顯示層採用了angularjs來實作的spa頁面。所有的頁面資料都是非同步載入和局部刷新,這樣的實作將會有更好的使用者體驗。

應用層(application service)

  angularjs透過http服務去請求web api來取得數據,而web api的實作則是呼叫應用層來請求資料。

基礎架構層

  基礎架構層包括倉儲的實作和一些公用方法的實作。

  倉儲層的實作採用ef code first的方式來實現的,並使用ef migration的方式來建立資料庫和更新資料庫。

  lh.common層實作了一些公用的方法,如日誌幫助類別、表達式樹擴充等類別的實作。

領域層

  領域層主要實現了此專案的所有領域模型,其中包括領域模型的實作和倉儲介面的定義。

  介紹完整體結構外,接下來將分別介紹此專案的後端服務實作與web前端的實作。

三、後端服務實作

  後端服務主要採用asp.net web api來實現後端服務,並且採用castle windsor來完成依賴注入。

  這裡拿權限管理中的使用者管理來介紹rest web api服務的實作。

提供使用者資料的rest服務的實作:

public class usercontroller : apicontroller
 {
  private readonly iuserservice _userservice;
  public usercontroller(iuserservice userservice)
  {
   _userservice = userservice;
  }
  [httpget]
  [route("api/user/getusers")]
  public outputbase getusers([fromuri]pageinput input)
  {
   return _userservice.getusers(input);
  }
  [httpget]
  [route("api/user/userinfo")]
  public outputbase getuserinfo(int id)
  {
   return _userservice.getuser(id);
  }
  [httppost]
  [route("api/user/adduser")]
  public outputbase createuser([frombody] userdto userdto)
  {
   return _userservice.adduser(userdto);
  }
  [httppost]
  [route("api/user/updateuser")]
  public outputbase updateuser([frombody] userdto userdto)
  {
   return _userservice.updateuser(userdto);
  }
  [httppost]
  [route("api/user/updateroles")]
  public outputbase updateroles([frombody] userdto userdto)
  {
   return _userservice.updateroles(userdto);
  }
  [httppost]
  [route("api/user/deleteuser/{id}")]
  public outputbase deleteuser(int id)
  {
   return _userservice.deleteuser(id);
  }
  [httppost]
  [route("api/user/deleterole/{id}/{roleid}")]
  public outputbase deleterole(int id, int roleid)
  {
   return _userservice.deleterole(id, roleid);
  }
 }
登入後複製

  從上面程式碼實作可以看出,user rest 服務依賴與iuserservice接口,並且也沒有像傳統的方式將所有的業務邏輯放在web api實作中,而是將具體的一些業務實作封裝到對應的在應用層中,rest api只負責呼叫對應的應用層中的服務。這樣設計好處有:

rest 服務部依賴與應用層接口,使得職責分離,將應用層服務的實例化交給單獨的依賴注入容器去完成,而rest服務只負責調用對應應用服務的方法來獲取資料。採用依賴介面而不依賴與特定類別的實現,使得類別與類別之間低耦合。 rest服務內不包括具體的業務邏輯實作。這樣的設計可以讓服務更能分離,如果你後期想用wcf來實作rest服務的,這樣就不需要重複在wcf的rest服務類別中重複寫一篇web api中的邏輯了,這時候完全可以呼叫應用服務的介面方法來實作wcf rest服務。所以將業務邏輯實作抽到應用程式服務層去實現,這樣的設計將使得rest 服務職責更單一,rest服務實作更容易擴展。

  使用者應用服務的實作:

public class userservice : baseservice, iuserservice
 {
  private readonly iuserrepository _userrepository;
  private readonly iuserrolerepository _userrolerepository;
  public userservice(iuserrepository userrepository, iuserrolerepository userrolerepository)
  {
   _userrepository = userrepository;
   _userrolerepository = userrolerepository;
  }
  public getresults<userdto> getusers(pageinput input)
  {
   var result = getdefault<getresults<userdto>>();
   var filterexp = buildexpression(input);
   var query = _userrepository.find(filterexp, user => user.id, sortorder.descending, input.current, input.size);
   result.total = _userrepository.find(filterexp).count();
   result.data = query.select(user => new userdto()
   {
    id = user.id,
    createtime = user.creationtime,
    email = user.email,
    state = user.state,
    name = user.name,
    realname = user.realname,
    password = "*******",
    roles = user.userroles.take(4).select(z => new baseentitydto()
    {
     id = z.role.id,
     name = z.role.rolename
    }).tolist(),
    totalrole = user.userroles.count()
   }).tolist();
   return result;
  }
  public updateresult updateuser(userdto user)
  {
   var result = getdefault<updateresult>();
   var existuser = _userrepository.findsingle(u => u.id == user.id);
   if (existuser == null)
   {
    result.message = "user_not_exist";
    result.statecode = 0x00303;
    return result;
   }
   if (ishassamename(existuser.name, existuser.id))
   {
    result.message = "user_name_has_exist";
    result.statecode = 0x00302;
    return result;
   }
   existuser.realname = user.realname;
   existuser.name = user.name;
   existuser.state = user.state;
   existuser.email = user.email;
   _userrepository.update(existuser);
   _userrepository.commit();
   result.issaved = true;
   return result;
  }
  public createresult<int> adduser(userdto userdto)
  {
   var result = getdefault<createresult<int>>();
   if (ishassamename(userdto.name, userdto.id))
   {
    result.message = "user_name_has_exist";
    result.statecode = 0x00302;
    return result;
   }
   var user = new user()
   {
    creationtime = datetime.now,
    password = "",
    email = userdto.email,
    state = userdto.state,
    realname = userdto.realname,
    name = userdto.name
   };
   _userrepository.add(user);
   _userrepository.commit();
   result.id = user.id;
   result.iscreated = true;
   return result;
  }
  public deleteresult deleteuser(int userid)
  {
   var result = getdefault<deleteresult>();
   var user = _userrepository.findsingle(x => x.id == userid);
   if (user != null)
   {
    _userrepository.delete(user);
    _userrepository.commit();
   }
   result.isdeleted = true;
   return result;
  }
  public updateresult updatepwd(userdto user)
  {
   var result = getdefault<updateresult>();
   var userentity =_userrepository.findsingle(x => x.id == user.id);
   if (userentity == null)
   {
    result.message = string.format("当前编辑的用户“{0}”已经不存在", user.name);
    return result;
   }
   userentity.password = user.password;
   _userrepository.commit();
   result.issaved = true;
   return result;
  }
  public getresult<userdto> getuser(int userid)
  {
   var result = getdefault<getresult<userdto>>();
   var model = _userrepository.findsingle(x => x.id == userid);
   if (model == null)
   {
    result.message = "use_not_exist";
    result.statecode = 0x00402;
    return result;
   }
   result.data = new userdto()
   {
    createtime = model.creationtime,
    email = model.email,
    id = model.id,
    realname = model.realname,
    state = model.state,
    name = model.name,
    password = "*******"
   };
   return result;
  }
  public updateresult updateroles(userdto user)
  {
   var result = getdefault<updateresult>();
   var model = _userrepository.findsingle(x => x.id == user.id);
   if (model == null)
   {
    result.message = "use_not_exist";
    result.statecode = 0x00402;
    return result;
   }
   var list = model.userroles.tolist();
   if (user.roles != null)
   {
    foreach (var item in user.roles)
    {
     if (!list.exists(x => x.role.id == item.id))
     {
      _userrolerepository.add(new userrole { roleid = item.id, userid = model.id });
     }
    }
    foreach (var item in list)
    {
     if (!user.roles.exists(x => x.id == item.id))
     {
      _userrolerepository.delete(item);
     }
    }
    _userrolerepository.commit();
    _userrepository.commit();
   }
   result.issaved = true;
   return result;
  }
  public deleteresult deleterole(int userid, int roleid)
  {
   var result = getdefault<deleteresult>();
   var model = _userrolerepository.findsingle(x => x.userid == userid && x.roleid == roleid);
   if (model != null)
   {
    _userrolerepository.delete(model);
    _userrolerepository.commit();
   }
   result.isdeleted = true;
   return result;
  }
  public bool exist(string username, string password)
  {
   return _userrepository.findsingle(u => u.name == username && u.password == password) != null;
  }
  private bool ishassamename(string name, int userid)
  {
   return !string.isnullorwhitespace(name) && _userrepository.find(u=>u.name ==name && u.id != userid).any();
  }
  private expression<func<user, bool>> buildexpression(pageinput pageinput)
  {
   expression<func<user, bool>> filterexp = user => true;
   if (string.isnullorwhitespace(pageinput.name))
    return filterexp;
   switch (pageinput.type)
   {
    case 0:
     filterexp = user => user.name.contains(pageinput.name) || user.email.contains(pageinput.name);
     break;
    case 1:
     filterexp = user => user.name.contains(pageinput.name);
     break;
    case 2:
     filterexp = user => user.email.contains(pageinput.name);
     break;
   }
   return filterexp;
  }
 }
登入後複製

  這裡應用服務層其實還可以進一步的優化,實現代碼層級的讀寫分離,定義ireadonlyservice接口和iwriteservie接口,並且把寫操作可以採用泛型方法的方式抽像到baseservice中去實現。這樣一些增刪改作業實現公用,之所以可以將這裡操作實現公用,是因為這些操作都是非常類似的,無非是操作的實體不一樣罷了。其實這樣的實現在我另一個開源專案中已經用到:onlinestore.大家可以參考這個自行去實現。

  倉儲層的實作:

  用戶應用服務也沒有直接依賴與特定的倉儲類,同樣也是依賴其介面。對應的用戶倉儲類別的實作如下:

public class baserepository<tentity> : irepository<tentity>
  where tentity :class , ientity
 {
  private readonly threadlocal<usermanagerdbcontext> _localctx = new threadlocal<usermanagerdbcontext>(() => new usermanagerdbcontext());
  public usermanagerdbcontext dbcontext { get { return _localctx.value; } }
  public tentity findsingle(expression<func<tentity, bool>> exp = null)
  {
   return dbcontext.set<tentity>().asnotracking().firstordefault(exp);
  }
  public iqueryable<tentity> find(expression<func<tentity, bool>> exp = null)
  {
   return filter(exp);
  }
  public iqueryable<tentity> find(expression<func<tentity, bool>> expression, expression<func<tentity, dynamic>> sortpredicate, sortorder sortorder, int pagenumber, int pagesize)
  {
   if (pagenumber <= 0)
    throw new argumentoutofrangeexception("pagenumber", pagenumber, "pagenumber must great than or equal to 1.");
   if (pagesize <= 0)
    throw new argumentoutofrangeexception("pagesize", pagesize, "pagesize must great than or equal to 1.");
   var query = dbcontext.set<tentity>().where(expression);
   var skip = (pagenumber - 1) * pagesize;
   var take = pagesize;
   if (sortpredicate == null)
    throw new invalidoperationexception("based on the paging query must specify sorting fields and sort order.");
   switch (sortorder)
   {
    case sortorder.ascending:
     var pagedascending = query.sortby(sortpredicate).skip(skip).take(take);
     return pagedascending;
    case sortorder.descending:
     var pageddescending = query.sortbydescending(sortpredicate).skip(skip).take(take);
     return pageddescending;
   }
   throw new invalidoperationexception("based on the paging query must specify sorting fields and sort order.");
  }
  public int getcount(expression<func<tentity, bool>> exp = null)
  {
   return filter(exp).count();
  }
  public void add(tentity entity)
  {
   dbcontext.set<tentity>().add(entity);
  }
  public void update(tentity entity)
  {
   dbcontext.entry(entity).state = entitystate.modified;
  }
  public void delete(tentity entity)
  {
   dbcontext.entry(entity).state = entitystate.deleted;
   dbcontext.set<tentity>().remove(entity);
  }
  public void delete(icollection<tentity> entitycollection)
  {
   if(entitycollection.count ==0)
    return;
   dbcontext.set<tentity>().attach(entitycollection.first());
   dbcontext.set<tentity>().removerange(entitycollection);
  }
  private iqueryable<tentity> filter(expression<func<tentity, bool>> exp)
  {
   var dbset = dbcontext.set<tentity>().asqueryable();
   if (exp != null)
    dbset = dbset.where(exp);
   return dbset;
  }
  public void commit()
  {
   dbcontext.savechanges();
  }
 }
public class userrepository :baserepository<user>, iuserrepository
 {
 }
登入後複製

四、angularjs前端實作

  web前端的實作就是採用angularjs來實現,並且採用模組化開發模式。具體web前端的程式碼結構如下圖所示:

app/images // 存放web前端使用的图片资源
app/styles // 存放样式文件
app/scripts // 整个web前端用到的脚本文件
    / controllers // angularjs控制器模块存放目录
    / directives // angularjs指令模块存放目录
    / filters // 过滤器模块存放目录
    / services // 服务模块存放目录
   / app.js // web前端程序配置模块(路由配置)
app/modules // 项目依赖库,angular、bootstrap、jquery库
app/views // angularjs视图模板存放目录
登入後複製

  使用angularjs開發的web應用程式的程式碼之間的呼叫層次和後端基本上一致,也是視圖頁面-》控制器模組-》服務模組-》web api服務。

  且web前端css和js資源的載入採用了bundle的方式來減少請求資源的次數,從而加快頁面載入時間。具體bundle類別的配置:

public class bundleconfig
 {
  // for more information on bundling, visit http://go.microsoft.com/fwlink/?linkid=301862
  public static void registerbundles(bundlecollection bundles)
  {
   //类库依赖文件
   bundles.add(new scriptbundle("~/js/base/lib").include(
     "~/app/modules/jquery-1.11.2.min.js",
     "~/app/modules/angular/angular.min.js",
     "~/app/modules/angular/angular-route.min.js",
     "~/app/modules/bootstrap/js/ui-bootstrap-tpls-0.13.0.min.js",
     "~/app/modules/bootstrap-notify/bootstrap-notify.min.js"
     ));
   //angularjs 项目文件
   bundles.add(new scriptbundle("~/js/angularjs/app").include(
     "~/app/scripts/services/*.js",
     "~/app/scripts/controllers/*.js",
     "~/app/scripts/directives/*.js",
     "~/app/scripts/filters/*.js",
     "~/app/scripts/app.js"));
   //样式
   bundles.add(new stylebundle("~/js/base/style").include(
     "~/app/modules/bootstrap/css/bootstrap.min.css",
     "~/app/styles/dashboard.css",
     "~/app/styles/console.css"
     ));
  }
 }
登入後複製

  首頁 index.cshtml

<!DOCTYPE html>
<html ng-app="LH">
<head>
 <meta name="viewport" content="width=device-width" />
 <title>简易权限管理系统Demo</title>
 @Styles.Render("~/js/base/style")
 @Scripts.Render("~/js/base/lib")
</head>
<body ng-controller="navigation">
 <nav class="navbar navbar-inverse navbar-fixed-top">
  <div class="container-fluid">
   <div class="navbar-header">
    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
     <span class="sr-only">Toggle navigation</span>
     <span class="icon-bar"></span>
     <span class="icon-bar"></span>
     <span class="icon-bar"></span>
    </button>
    <a class="navbar-brand" href="/">简易权限管理系统Demo</a>
   </div>
   <div class="navbar-collapse collapse">
    <ul class="nav navbar-nav navbar-left">
     <li class="{{item.isActive?'active':''}}" ng-repeat="item in ls">
      <a href="#{{item.urls[0].link}}">{{item.name}}</a>
     </li>
    </ul>
    <div class="navbar-form navbar-right">
     <a href="@Url.Action("UnLogin", "Home", null)" class="btn btn-danger">
      {{lang.exit}}
     </a>
    </div>
   </div>
  </div>
 </nav>
 <div class="container-fluid">
  <div class="row">
   <div class="col-sm-3 col-md-2 sidebar">
    <ul class="nav nav-sidebar">
     <li class="{{item.isActive?'active':''}}" ng-repeat="item in urls"><a href="#{{item.link}}">{{item.title}}</a></li>
    </ul>
   </div>
   <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
    <div ng-view></div>
   </div>
  </div>
 </div>
 @Scripts.Render("~/js/angularjs/app")
</body>
</html>
登入後複製

五、運行效果

  介紹完前後端的實作之後,接下來讓我們來看看整個專案的運作效果:

六、總結

  到此,本文的所有內容都介紹完了,儘管本文的angularjs的應用項目還有很多完善的地方,例如沒有緩衝的支持、沒有實現讀寫分離,沒有對一些api進行壓力測試等。但angularjs在實際專案中的應用基本上是這樣的,大家如果在專案中有需要用到angularjs,正好你們公司的後台又是.net的話,相信本文的分享可以是一個很好的參考。另外,關於架構的設計也可以參考我的另一個開源專案:onlinestorefastworks

以上所述是小編給大家介紹的使用angularjs打造權限管理系統的方法,希望對大家有幫助!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板