• 手把手撸套框架-Victory框架1.0 详解


    目录

    其实Victory框架1.0 在8月份就完成了,整个9月份都没有更新博客,主要还是因为松懈了。

    所以,趁着国庆节的放假的时间把博客给更新一下,1.0总的来说算不得一个成熟的产品,但是拿来开发我们公司这种企业内部项目基本算够用。

    废话不多说,直接上代码讲解:

    https://github.com/demon28/Victory.Template1.0

    代码拉下来之后,可以将框架打包成项目模板。这样用起来就方便了

     直接下一步,下一步完成就好!

    创建项目的时候 就可以直接用了,但是这个有个缺点,就是不能把整个解决方案打包,只能单个类库或项目打包成模板。

    好吧,这是个插曲。回归到正题,讲讲Victory框架1.0

    ============================================华丽的分割线===========================================

    关于Victory的技术选项如下:

     .net  Core 3.1  + FreeSql + Jquery + Bootstarp +Vue +AdminLte

    关于技术选型的问题后面再吐槽吧,先来看看 分层

    DataAccess : 数据访问层,跟数据库进行交互的操作都在这里面。现在没要求全部用表达式树的方式 去写,允许写Sql。

    Entity: 通用层,主要用户放实体Model,也就是说 DTO全部在这里,另外还放一些通用的类,比如工具类等。

    Facade: 业务层,也就是传统的BLL层。 复杂逻辑业务都在这一层。尤其多表操作,调用三方接口,流程操作等。

    App: 应用层, 如果是客户端App应用(IOS,安卓,小程序) 的话,这一层就是接口层。

    说白了,还是传统的MVC分层,但是为什么不叫DAL,BLL层呢? 其实就是为了跟别的框架不一样一点,所以另外取个名字。

    这里里面会看到DataAccess 和 Entity 都有一个 CodeGenerator文件夹,这个文件夹是 放 代码生成器生成的文件的。

    关于代码生成器可以看另外一篇博客: https://www.cnblogs.com/demon28/p/13333791.html

    我们只需要 将项目打包成 项目模板,然后 新建项目,替换项目名字就可以了。

    ==============================================华丽的分割线===================================

    现在每一层 都可以使用代码生成器生成代码,也就是说只要建好表,增删查改全部可以由代码生成器,生成。两分钟即可完成一张表单。

    这里把 代码生成器的模板贴一下:

    Da层,生成数据访问类:

    //DA  v1.1
    //2020-7-31
    //Near
    
    
    using System;
    using System.Collections.Generic;
    using System.Linq.Expressions;
    using System.Text;
    using Victory.Core.Extensions;
    using Victory.Core.Models;
    using YH.EAM.DataAccess;
    using YH.EAM.Entity.CodeGenerator;
    using YH.EAM.Entity.Enums;
    using YH.EAM.Entity.Model;
    using YH.EAM.Entity.Tool;
    
    namespace  @ViewBag.NameSpace
    {
    
        /// <summary>
        ///   @Model.Comment
        ///</summary>
        public class @(Model.Name)_Da : FreeSql.BaseRepository<@(Model.Name)>
        {
    
            public @(Model.Name)_Da() : base(DataAccess.DbContext.Db, null, null)
            {
    
            }
    
    
            public List<@(Model.Name)> ListByWhere(string keyword, ref PageModel page) {
    
                var data =this.Select;
    
                if(!string.IsNullOrEmpty(keyword))
                {
                  //  data= data.Where(s => s.Name.Contains(keyword) || s.Workid.Contains(keyword) );
                }
    
                page.TotalCount = data.Count().ToInt();
              
    
                var list = data.Page(page.PageIndex, page.PageSize)
                    .OrderBy(s => s.Createtime)
                    .ToList();
    
                return list;
            }
    
    
        }
    
    }

    Entity层生成model:

    //----------------
    //DA  v1.1
    //2020-7-31
    //Near
    //---------------
    
    using FreeSql.DataAnnotations;
    using System;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Text;
    
    
    namespace @ViewBag.NameSpace
    {
        /// <summary>
        ///  @Model.Comment
        ///</summary>
        public class   @Model.Name
        {
    
           public @(Model.Name)()
           {
          
           }
    
        @foreach (var item in @Model.Columns)
        {
            @:///<summary>
            @:///描述:@(item.Comment)
            @:///</summary>
            @if (@Model.PrimaryKey.Columns[0].Name == @item.Name)
            {
            @:[Column(IsIdentity = true, IsPrimary = true)]
            }
            @:public @item.PrimativeTypeName @item.CaseCamelName { get; set; }
           
            
    
          }
    
        }
     }

    Contorller 类生成模板,生成控制器:

    //控制器模板 v1.1
    //2020-7-31
    //Near
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Victory.Core.Controller;
    using YH.EAM.DataAccess.CodeGenerator;
    using YH.EAM.Entity.CodeGenerator;
    using YH.EAM.WebApp.Attribute;
    
    namespace @ViewBag.NameSpace
    {
    
        [Authorize]
        public class  @(Model.Name)Controller : TopControllerBase
        {
             [Right(PowerName = "访问")]
             public IActionResult Index()
            {
                return View();
            }
    
            [Right(PowerName = "查询")]
            [HttpPost]
            public IActionResult List(string keyword,int pageIndex,int pageSize)
            {
    
                PageModel page = new PageModel();
                page.PageIndex = pageIndex;
                page.PageSize = pageSize;
    
    
                 @(Model.Name)_Da da = new  @(Model.Name)_Da();
                var list = da.ListByWhere(keyword, ref page);
                return SuccessResultList(list,page);
            }
    
    
    
    
            [Right(PowerName = "添加")]
            [HttpPost]
            public IActionResult Add(@(Model.Name) model)
            {
    
                @(Model.Name)_Da da = new @(Model.Name)_Da();
                da.Insert(model);
                return SuccessMessage("添加成功!");
    
            }
    
    
            [Right(PowerName = "修改")]
            [HttpPost]
            public IActionResult Update(@(Model.Name) model)
            {
                @(Model.Name)_Da da = new @(Model.Name)_Da();
                da.Update(model);
                return SuccessMessage("成功!");
            }
    
    
            [Right(PowerName = "删除")]
            [HttpPost]
            public IActionResult Del(int id)
            {
                @(Model.Name)_Da da = new @(Model.Name)_Da();
    
                if (da.Delete(s => s.Id == id) > 0)
                {
                    return SuccessMessage("已删除!");
    
                }
                return FailMessage();
            }
        
        }
    
    }

    View生成前端代码:

    <!--
    DA  v1.1
    2020-7-31
    Near
    -->
    
    @@section Pageheader{
        <h1>
            <small> @Model.Name</small>
    
        </h1>
        <ol class="breadcrumb">
            <li><a href="#"><i class="fa fa-dashboard"></i> Home</a></li>
            <li class="active">@Model.Name</li>
        </ol>
    
    }
    
    
    
    <section class="content" id="tab">
        <div class="row">
    
            <!-- /.col -->
            <div>
                <div class="box box-primary">
                    <div class="box-header">
                        <h3 class="box-title">List</h3>
    
                        <div class="box-tools">
    
                         <div class="input-group input-group-sm hidden-xs  pull-right" style=" 200px;">
                                <input type="text" name="table_search" class="form-control pull-right" placeholder="Search" id="txt_Search" v-model="keywork" />
    
                                <div class="input-group-btn">
                                    <button type="button" class="btn btn-default "  v-on:click="Search()" id="btn_Search"><i class="fa fa-search"></i></button>
                                </div>
    
                            </div>
    
    
                            <div class="input-group input-group-sm  col-md-1 pull-right ml-1" style="margin-left:10px;">
                                <button type="button" class="btn btn-default pull-right"  v-on:click="ShowAdd()" id="btn_Search">添加</button>
                            </div>
    
                        </div>
                    </div>
                    <!-- /.box-header -->
                    <div class="box-body table-responsive no-padding">
    
    
                        <table class="table">
                            <tbody>
                                <tr>
    
                                 @foreach (var item in @Model.Columns)
                                 {
                                      <th>@(item.CaseCamelName)</th>
                                 }
    
                                 <th style="text-align:right">
                                        操作
                                 </th>
    
                                </tr>
    
                       
                                    <tr v-for="(item,index) in list">
                                         @foreach (var item in @Model.Columns)
                                         {
                                             @:<td> {{item.@item.CaseCamelName}}</td>
    
                                         }
    
                                        <td style="text-align:right">
    
                                            <button type="button" class="btn bg-purple  btn-xs" v-on:click="ShowUpdate(item)">修改</button>
                                            &nbsp;      &nbsp;
                                            <button type="button" class="btn bg-red btn-xs" v-on:click="Del(item)">删除</button>
                                        </td>
                                    </tr>
    
    
    
                            </tbody>
                        </table>
                    </div>
                    <!-- /.box-body -->
    
    
                    <div class="box-footer no-padding">
                        <div class="card-footer clearfix pull-left" style="margin-left:20px;margin-top:30px;margin-bottom:30px">
    
                        </div>
    
                        <div class="card-footer clearfix pull-right " style="margin-right:30px;margin-top:30px;margin-bottom:30px" id="div_page">
    
                            <zpagenav v-bind:page="pageModel.pageIndex" v-bind:page-size="pageModel.pageSize" v-bind:total="pageModel.TotalCount"
                                      v-bind:max-page="pageModel.ToTalPage" v-on:pagehandler="Init">
                            </zpagenav>
                        </div>
    
    
                        <!-- /.pull-right -->
                    </div>
                </div>
            </div>
    
    
        </div>
        <!-- /.col -->
        <!-- /.row -->
    
    
        <div class="modal fade" id="modal-default">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                        <h4 class="modal-title" id="txt_username"> @Model.Comment</h4>
                    </div>
                    <div class="modal-body">
    
    
                        <form class="form-horizontal">
    
    
                             @foreach (var item in @Model.Columns)
                             {
                                  <div class="form-group">
                                    <label for="txt_projectname" class="col-sm-3 control-label">@item.CaseCamelName:</label>
    
                                    <div class="col-sm-7">
                                        <input type="text" class="form-control" v-model="info.@item.CaseCamelName">
                                    </div>
                                 </div>
    
                             }
    
                        </form>
    
    
    
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-primary pull-right" v-on:click="Add()" v-if="operation=='add'">添 加</button>
                        <button type="button" class="btn btn-primary pull-right" v-on:click="Update()" v-if="operation=='update'">修 改</button>
    
                        <button type="button" class="btn btn-default pull-left" data-dismiss="modal">关 闭</button>
                    </div>
                </div>
                <!-- /.modal-content -->
            </div>
        </div>
    
    
    </section>
    
    
    
    
    @@section scripts{
    
        <script>
    
           var self;
           var vm = new Vue({
               el: "#tab",
               data: {
                   list: [],
                   pageModel: {
                        pageIndex: 1,
                        pageSize: 15,
                        TotalCount: 0,
                        ToTalPage: 0,
                    },
                   operation: "add",
                   info: {},
                   keywork: ""
               },
               created: function () {
                   self=this;
                   self.Init(1);
    
               },
               mounted: function () {
    
    
               },
               methods: {
    
                   Init(index) {
                      
    
                       AjaxPost({
                           url: "/@Model.Name/List",
                           type: "POST",
                           data: {
                                pageIndex: index,
                                pageSize: self.pageModel.pageSize,
                                keyword: self.keywork,
                           },
                           success: function (result) {
    
                           // console.log(JSON.stringify(result));
    
                               if (!result.Success) {
    
                                   alert_danger(result.Message);
                                   return;
                               }
                              
                                self.list = result.Content;
    
                                self.pageModel.pageIndex = result.PageIndex;
                                self.pageModel.pageSize = result.PageSize;
                                self.pageModel.TotalCount = result.TotalCount;
                                self.pageModel.ToTalPage = result.ToTalPage;
                           }
                       })
                   },
    
                   Del: function (item) {
    
                       bootbox.confirm("您确定删除该记录吗?", function (res) {
                           if (res) {
    
                               AjaxPost({
                                   url: "/@Model.Name/Del",
                                   type: "POST",
                                   data: {
                                       id: item.Id
                                   },
                                   success: function (result) {
    
                                       if (!result.Success) {
    
                                           alert_danger(result.Message);
                                           return;
                                       }
                                       alert_success("删除成功");
                                       self.Init(self.pageModel.pageIndex);
    
                                   }
                               })
                           }
                       });
    
    
    
                   },
                   Add: function () {
    
                       AjaxPost({
                           url: "/@Model.Name/Add",
                           type: "POST",
                           data: self.info,
                           success: function (result) {
    
                               if (!result.Success) {
    
                                   alert_danger(result.Message);
                                   return;
                               }
                               $('#modal-default').modal('hide');
                               alert_success(result.Message);
                                self.Init(self.pageModel.pageIndex);
    
                           }
                       })
                   },
                   Update: function () {
                       AjaxPost({
                           url: "/@Model.Name/Update",
                           type: "POST",
                           data: self.info,
                           success: function (result) {
    
                               if (!result.Success) {
    
                                   alert_danger(result.Message);
                                   return;
                               }
                               $('#modal-default').modal('hide');
                               alert_success(result.Message);
                               self.Init(self.pageModel.pageIndex);
    
                           }
                       })
    
                   },
                   ShowUpdate: function (item) {
                       this.operation = "update";
                       $('#modal-default').modal('show');
                       this.info = item;
    
                   },
                   ShowAdd() {
    
                       this.operation = "add";
                       this.info = {};
                       $('#modal-default').modal('show');
                       
                     
                   },
                    Search: function () {
                        self.Init(1);
                    },
                    EnterKeyup() {
                     
                        document.onkeypress = function (e) {
                            var keycode = document.all ? event.keyCode : e.which;
    
                            if (keycode == 13) {
                                self.Init(1);
                                return false;
                            }
                        };
                    },
                  
                  
               },
    
           });
    
    
        </script>
    
    }

    模板或多或少会有点不符合每个人的要求,所以代码生成器的 Template文件夹里可以自由添加或编辑模板,

    生成的前端主要是基于AdminLte 做的:https://adminlte.io/themes/AdminLTE/index2.html

    这个框架我用了很久了,一直觉得很漂亮,即便现在有AdminLte3 了但是 我还是觉得 AdminLte2 这一版好看。

    剩下值得一讲的重点就是权限。 

    如果有看上一篇关于 登录设计 的园友应该知道 我是有规划Victory1.1 的这里为什么要单独把1.0拎出来讲,主要就是因为权限设计的不同。

    1.0 是最常见的五张表做权限:

    用户表、

    用户与角色的中间表、

    角色表

    角色与权限的中间表

    权限表

    这种设计是最常见的,也是我觉得能满足大部分要求的,但是我们这种内部项目一般都会涉及到组织管理,所以必须要有用户组的参与,而且1.0的这种设计

    权限管控不到菜单,所以这才演化出来的1.1, 关于1.1下一篇再说。这里说一下 权限功能怎么用。

    其实非常简单 就两个步骤:

    1,在需要权限管控的Action上打上 过滤器 特性类。这个就回被管控了。

    需要 权限控制的 Contorller 必须在页面访问的 类上面打 特性类,也就如上图 的  Index 上面必须是要打的,这样控制器里面的Action会自动归类到控制器。

    也就是说,这些操作权限,是不需要自己手工往数据库里面去添加的。

    当然不需要权限控制的Action 就不要去打 特性类。

    关于权限设计详细的可以看这一篇文章: https://www.cnblogs.com/demon28/p/13560068.html

    ok,剩下的。我觉得也没什么好说的。数据库文件就在WebAPP 的DB 目录下,有难点的代码我都写了注释。过一下基本都能看懂。

    1.0主要 解决了 两个问题:一个是有框架用,另一个是 为后面扩展框架打下基础。

    =========================华丽的分割线==================================

    写在最后,1.0有很多不完善的地方比如: 菜单会自动折叠,登录界面不好看等等。

    但是对我来说,最大的问题有两个:

    1,不够纯粹,里面混合Jquery 和 Vue。 这里就分别对应了Bootstarp 和 Element-ui。

       本身可以只用Vue 或者 只用Jquery。 

    2,权限系统不能控制菜单,也不能给用户组添加角色权限。

    随意后续规划的是:  

    Victory 1.1 版本 解决 权限问题,基于RBAC-1 来做权限设计。

    Victory 2.0 版本 解决 前端混用,彻底放弃Jquery 全面Vue。

    但是做小型项目,我个人还是倾向于,直接1.0版本,即便有不完美的地方,可以基于1.0方案进行 修改。

    主要是权限设计,1.0权限 比较 经典。 而且小巧易满足需求。

    ok,就写到这里吧,有什么问题就在博客园留言吧。 必回!

    Github : 
    1.0源码:

    https://github.com/demon28/Victory.Template1.0

    代码生成器:

    https://github.com/demon28/Victory.CodeGenerator

  • 相关阅读:
    font-weight:bolder与设置数值的区别
    纯CSS3打造圆形菜单
    CSS Specificity
    控制页面内跳转
    解决Python操作MySQL中文乱码的问题
    字体图标font-awesome
    linux下安装使用MySQL 以及 python mysqldb 遇到的问题
    CocosCreator游戏开发(二)SocketIO简易教程
    CocosCreator游戏开发---菜鸟学习之路(一)资料整理
    2017已经接近尾声,然而我却什么都没干成
  • 原文地址:https://www.cnblogs.com/demon28/p/13762867.html
Copyright © 2020-2023  润新知