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

來源:互聯網
上載者:User

一、引言

  本文將介紹如何把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的話,相信本文的分享可以是一個很好的參考。另外,關於架構的設計也可以參考我的另一個開源項目:OnlineStore和FastWorks。

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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.