zoukankan      html  css  js  c++  java
  • 项目架构开发:展现层(上)

    上次我们创建了项目的服务层,服务层在业务逻辑简单,或项目运行初期不是很容易体现出他的价值;传送门:项目架构开发:服务层(上)

    服务层专门处理非业务逻辑的一些功能,比如缓存、异常处理、组织多个应用逻辑等;这次我们搭建最上层的展现层,用到的知识面包括以下:

    asp.net mvc5 + bootstrap + autofac + AutoMapper

    这次我们没有用服务层,而是直接调用应用逻辑层接口方法,其实对小项目来说,这样已经足够了;服务层我们下次再讲吧

    现在开始吧!

    1、创建MVC + UnitTest

    先搭建个框架,网上找的后台模板

     2、ViewModel

     UI的数据载体最好新建一个viewmodel,这样就不用依赖DTO或PO,因为页面上显示的数据实体一般比较大,会封装比DTO多的多的属性

    LoginUserViewModel.cs

     1 using Infrastructure.Common;
     2 using System;
     3 using System.Collections.Generic;
     4 
     5 namespace Presentation.MVC.Models
     6 {
     7     public class LoginUserViewModel
     8     {
     9         public int RowNumber { get; set; }
    10 
    11         public Guid Id { get; set; }
    12         public string LoginName { get; set; }
    13         public short? IsEnabled { get; set; }
    14         public DateTime? CreateTime { get; set; }
    15     }
    16 
    17     public class LoginUserListViewModel
    18     {
    19         public List<LoginUserViewModel> Items { get; set; }
    20     }
    21 
    22     public class LoginUserPageViewModel : PageViewModelBase
    23     {
    24         public List<LoginUserViewModel> Items { get; set; }
    25     }
    26 }

    PageViewModelBase.cs (这个是分页时候用的,如上边标红实体)

     1 using Infrastructure.Common;
     2 
     3 namespace Presentation.MVC.Models
     4 {
     5     public class PageViewModelBase
     6     {
     7         public bool IsFirst { get; set; }
     8         public bool IsLast { get; set; }
     9 
    10         public Page Page { get; set; }
    11         public int Total { get; set; }
    12         public int TotalPage
    13         {
    14             get
    15             {
    16                 return (Total % Page.PageSize) == 0 ? Total / Page.PageSize : (Total / Page.PageSize) + 1;
    17             }
    18         }
    19 
    20         public int PrePage
    21         {
    22             get
    23             {
    24                 if (Page.PageIndex == 1)
    25                 {
    26                     IsFirst = true;
    27                     return 1;
    28                 }
    29                 else
    30                 {
    31                     IsFirst = false;
    32                     return Page.PageIndex - 1;
    33                 }
    34             }
    35         }
    36         public int NextPage
    37         {
    38             get
    39             {
    40                 if (Page.PageIndex == TotalPage)
    41                 {
    42                     IsLast = true;
    43                     return TotalPage;
    44                 }
    45                 else
    46                 {
    47                     IsLast = false;
    48                     return Page.PageIndex + 1;
    49                 }
    50             }
    51         }
    52     }
    53 }

     3、映射

     主要是DTO映射成ViewModel,这里我们用的是AutoMapper

    AutoMapperConfiguration.cs,AutoMapper用法很简单,引用他,然后像下边代码那样写,然后再应用启动的时候加载

     1 using AutoMapper;
     2 using Business.ReverseDDD.Model;
     3 using Presentation.MVC.Models;
     4 
     5 namespace Presentation.MVC.Mappings
     6 {
     7     public class AutoMapperConfiguration
     8     {
     9         public static void Configure()
    10         {
    11             Mapper.CreateMap<LoginUser, LoginUserViewModel>();
    12
    13         }
    14     }
    15 }

    Global.asax.cs

    1 protected void Application_Start()
    2         {
    3             AreaRegistration.RegisterAllAreas();
    4             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    5             RouteConfig.RegisterRoutes(RouteTable.Routes);
    6             BundleConfig.RegisterBundles(BundleTable.Bundles);
    7 
    8             AutoMapperConfiguration.Configure();
    9         }

    4、视图

    为了方便,CURD都在一个页面实现了

      1 @model Presentation.MVC.Models.LoginUserPageViewModel
      2 @{
      3     ViewBag.Title = "Index";
      4     Layout = "~/Views/Shared/_Bootstrap.cshtml";
      5 }
      6 
      7 <div class="container">
      8     <h2></h2>
      9     <div class="panel panel-default">
     10         <div class="panel-heading">
     11             <h4 class="panel-title">
     12                 <a data-toggle="collapse" data-parent="#accordion"
     13                    href="#collapseOne" id="actionType">
     14                     新增用户
     15                 </a>
     16             </h4>
     17         </div>
     18         <div id="collapseOne" class="panel-collapse collapse">
     19             <div class="panel-body">
     20 
     21                 @using (Html.BeginForm("Add", "LoginUser", null, FormMethod.Post, new { @id = "formLoginUser", @class = "form-horizontal", role = "form" }))
     22                 {
     23                     @Html.AntiForgeryToken()
     24 
     25                     <div class="form-group">
     26                         <label for="firstname" class="col-sm-2 control-label">登录名</label>
     27                         <div class="col-sm-10">
     28                             <input type="text" class="form-control" name="LoginName" id="LoginName"
     29                                    placeholder="请输入登录账户名" />
     30                         </div>
     31                     </div>
     32                     <div class="form-group">
     33                         <label for="lastname" class="col-sm-2 control-label">登录密码</label>
     34                         <div class="col-sm-10">
     35                             <input type="text" class="form-control" name="Password" id="Password"
     36                                    placeholder="请输入登录密码" />
     37                         </div>
     38                     </div>
     39                     <div class="form-group">
     40                         <div class="col-sm-offset-2 col-sm-10">
     41                             <div class="checkbox">
     42                                 <label>
     43                                     <input type="checkbox" name="IsEnabled" id="IsEnabled" value="1" /> 是否有效
     44                                 </label>
     45                             </div>
     46                         </div>
     47                     </div>
     48 
     49                     <div class="form-group">
     50                         <div class="col-sm-offset-2 col-sm-10">
     51                             <input type="hidden" name="Id" id="Id" />
     52                             <button type="submit" class="btn btn-default">提交</button>
     53                         </div>
     54                     </div>
     55                 }
     56 
     57             </div>
     58         </div>
     59     </div>
     60 
     61 
     62     <h4>用户列表</h4>
     63     <table id="list" class="table table-striped table-bordered table-hover table-condensed">
     64         <thead>
     65             <tr>
     66                 <th>序号</th>
     67                 <th>登录名</th>
     68                 <th>是否有效</th>
     69                 <th>创建时间</th>
     70                 <th>操作</th>
     71             </tr>
     72         </thead>
     73         <tbody>
     74             @foreach (var item in Model.Items)
     75             {
     76                 <tr>
     77                     <td>@item.RowNumber</td>
     78                     <td>@item.LoginName</td>
     79                     <td>@item.IsEnabled</td>
     80                     <td>@item.CreateTime</td>
     81                     <td>
     82                         <button type="button" class="btn btn-link btn-xs" key="@item.Id" action="edit">修改</button>
     83                         <button type="button" class="btn btn-link btn-xs" key="@item.Id" action="delete">删除</button>
     84                     </td>
     85                 </tr>
     86             }
     87         </tbody>
     88     </table>
     89 
     90     <ul class="pagination">
     91         <li><a href="/LoginUsers/@Model.PrePage">&laquo;</a></li>
     92         @for (int index = 1; index <= Model.TotalPage; index++)
     93         {
     94             if (Model.Page.PageIndex == index)
     95             {
     96                 <li class="active"><a href="/LoginUsers/@index">@index</a></li>
     97             }
     98             else
     99             {
    100                 <li><a href="/LoginUsers/@index">@index</a></li>
    101             }
    102         }
    103         <li><a href="/LoginUsers/@Model.NextPage">&raquo;</a></li>
    104     </ul>
    105 
    106     <script type="text/javascript">
    107         $(function () {
    108             $(".btn-link").click(function () {
    109                 var obj = $(this);
    110                 var key = obj.attr("key");
    111                 if (key == undefined || key == null || key == "") return;
    112 
    113                 var action = obj.attr("action");
    114 
    115                 if (action == "delete") {
    116                     CreateDeleteWindow(function () {
    117                         location.href = "/LoginUser/Delete/" + key;
    118                     });
    119                 }
    120 
    121                 if (action == "edit") {
    122                     $.ajax({
    123                         url: "/LoginUser/Edit/" + key,
    124                         type: "GET",
    125                         dataType: 'json',
    126                         success: function (result) {
    127                             $("#Id").val(result.Id);
    128                             $("#LoginName").val(result.LoginName);
    129                             if (result.IsEnabled == 1) $("#IsEnabled").attr("checked", "true");
    130                             else $("#IsEnabled").removeAttr("checked");
    131 
    132                             $('#collapseOne').collapse('show');
    133                             $("#formLoginUser").attr("action", "/LoginUser/Edit");
    134                             $("#actionType").html("修改用户");
    135                         },
    136                         error: function (e) {
    137                             alert(e);
    138                         }
    139                     });
    140                 }
    141             });
    142 
    143         });
    144     </script>
    145 
    146 </div>

    其实也没什么特别的就是用了Bootstrap美化页面样式,对Bootstrap不懂的请点击这里

    5、控制器

    LoginUserController.cs

     1 using AutoMapper;
     2 using Business.DTO.Request;
     3 using Business.ReverseDDD.IApplication;
     4 using Infrastructure.Common;
     5 using LingExtensions;
     6 using Presentation.MVC.Models;
     7 using System;
     8 using System.Collections.Generic;
     9 using System.Web.Mvc;
    10 
    11 namespace Presentation.MVC.Controllers
    12 {
    13     public class LoginUserController : Controller
    14     {
    15         private ILoginUserApplication loginUserApplication;
    16 
    17         public LoginUserController(ILoginUserApplication loginUserApplication)
    18         {
    19             this.loginUserApplication = loginUserApplication;
    20         }
    21 
    22         [Route("LoginUsers/{PageIndex=1}")]
    23         public ActionResult Index(string PageIndex)
    24         {
    25             Page page = new Page();
    26             page.PageIndex = PageIndex.ToInt(1);
    27 
    28             var model = new LoginUserPageViewModel();
    29             var soure = this.loginUserApplication.GetPage(page, w => w.OrderByDescending(t => t.CreateTime));
    30 
    31             model.Items = Mapper.Map<List<LoginUserViewModel>>(soure.Item2);
    32             model.Total = soure.Item1;
    33             model.Page = page;
    34 
    35             return View(model);
    36         }
    37 
    38         [HttpPost]
    39         [ValidateAntiForgeryToken] 
    40         public ActionResult Add(LoginUserCURequest entity)
    41         {
    42             this.loginUserApplication.Add(new LoginUserCURequest()
    43             {
    44                 Id = Guid.NewGuid(),
    45                 LoginName = entity.LoginName,
    46                 Password = entity.Password,
    47                 IsEnabled = entity.IsEnabled
    48             });
    49 
    50             return RedirectToAction("Index");
    51         }
    52 
    53         [HttpGet]
    54         public ActionResult Delete(string id)
    55         {
    56             this.loginUserApplication.Delete(Guid.Parse(id));
    57 
    58             return RedirectToAction("Index");
    59         }
    60 
    61         [HttpGet]
    62         public ActionResult Edit(Guid id)
    63         {
    64             var soure = this.loginUserApplication.Get(id);
    65 
    66             return Json(soure, JsonRequestBehavior.AllowGet);
    67         }
    68 
    69         [HttpPost]
    70         [ValidateAntiForgeryToken]
    71         public ActionResult Edit(LoginUserCURequest entity)
    72         {
    73             this.loginUserApplication.Update(new LoginUserCURequest()
    74             {
    75                 Id = entity.Id,
    76                 LoginName = entity.LoginName,
    77                 Password = entity.Password,
    78                 IsEnabled = entity.IsEnabled
    79             });
    80 
    81             return RedirectToAction("Index");
    82         }
    83     }
    84 }

    都是演示CURD的功能,大家不要在意这些细节。。

    看标红的地方,意思是将soure.Item2(是Tuple<int, IEnumerable<LoginUser>>类型)转换成List<LoginUserViewModel>

    这就是AutoMapper的用法

    还有是这里没有依赖具体应用逻辑组件的,只依赖了业务逻辑接口using Business.ReverseDDD.IApplication;

    这个是为了解耦,而且对分层并行开发很有用,项目前端后端开发都不用依赖谁开发完才能往下继续;

    控制器我们用的是依赖注入Autofac组件:

     6、UnitTest

    LoginUserControllerTest.cs, 记得也要Mapping哦

    测试通过了

    7、UI,我们来看看界面功能

     7.1 新增用户

    用户新增成功,列表正常显示数据

    7.2 修改数据

    修改成功

    7.3 分页正常

    至此,展现层完成了

    8、完整项目架构如下

  • 相关阅读:
    Dubbo服务者消费者提供者案例实现
    spring核心组件
    spring为什么要注入接口
    小菜鸡进阶之路_Second week之元组、列表、集合、字典对比.
    小菜鸡进阶之路-First week
    光学公式推到——(物象位置) 1/u+1/v=1/f
    C#问题——调用事件时其他信息: 未将对象引用设置到对象的实例。
    工业相机全局曝光和卷帘曝光的区别
    相机加接圈的作用和缺点
    C#——数组维度/行数/列数/长度区别
  • 原文地址:https://www.cnblogs.com/lanxiaoke/p/6540431.html
Copyright © 2011-2022 走看看