目录

其实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="width: 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

手把手撸套框架-Victory框架1.0 详解的更多相关文章

  1. 手把手撸套框架-Victory框架1.1 详解

    目录 上一篇博客 Victory框架1.0 详解  有说道,1.0的使用过程中出现不少缺点,比如菜单不能折叠,权限没有权限组等等. 所以,我还是抽出时间在下班后,回到我的小黑屋里 完成了1.1的升级. ...

  2. ORM框架对比以及Mybatis配置文件详解

    ORM框架对比以及Mybatis配置文件详解 0.数据库操作框架的历程 (1) JDBC ​ JDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQL语句 ...

  3. Django框架 之 ORM查询操作详解

    Django框架 之 ORM查询操作详解 浏览目录 一般操作 ForeignKey操作 ManyToManyField 聚合查询 分组查询 F查询和Q查询 事务 Django终端打印SQL语句 在Py ...

  4. laravel框架的中间件middleware的详解

    本篇文章给大家带来的内容是关于laravel框架的中间件middleware的详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. laravel中间件是个非常方便的东西,能将一些逻辑 ...

  5. 百度大脑UNIT3.0详解之嵌入式对话理解技术

    相信很多人都体验过手机没有网时的焦虑,没有网什么也做不了.而机器人也会遇到这样的时刻,没有网或者网络环境不好的情况下,无法识别用户在说什么,也无法回复用户.在AIoT(AI+物联网)飞速普及的现在,智 ...

  6. 百度大脑UNIT3.0详解之知识图谱与对话

    如今,越来越多的企业想要在电商客服.法律顾问等领域做一套包含行业知识的智能对话系统,而行业或领域知识的积累.构建.抽取等工作对于企业来说是个不小的难题,百度大脑UNIT3.0推出「我的知识」版块专门为 ...

  7. 百度大脑UNIT3.0详解之数据生产工具DataKit

    在智能对话项目搭建的过程中,高效筛选.处理对话日志并将其转化为新的训练数据,是对话系统效果持续提升的重要环节,也是当前开发者面临的难题之一.为此百度大脑UNIT推出学习反馈闭环机制,提供数据获取.辅助 ...

  8. Hadoop框架:DataNode工作机制详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.工作机制 1.基础描述 DataNode上数据块以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是数据块元数据包括长度.校验.时 ...

  9. Laravel框架中的make方法详解

    为什么网上已经有这么多的介绍Laravel的执行流程了,Laravel的容器详解了,Laravel的特性了,Laravel的启动过程了之类的文章,我还要来再分享呢? 因为,每个人的思维方式和方向是不一 ...

随机推荐

  1. 我是怎样刚拿饿了么P7 offer,然后途虎一轮游的

    今年初拿了个饿了么P7的offer,于此同时大家顺便看看我怎么途虎一轮游的.废话不多说,直接上题吧. 一面 首先上来就是自我介绍,简单的说下自己的项目经验,涉及的技术栈之类的. 然后每一轮必问的问题来 ...

  2. codeblocks显示:不支持的16位应用程序 解决办法

    我是win10 64位系统,写c++运行就会显示不兼容16位应用程序.以前编出来的exe还能用,今天编出的就炸了. 试了用vs编译.vs能用. 试了网上找的各种解决方案, 360修复, 注册表, 重构 ...

  3. 免费领CRMEB移动社交电商系统源码与授权

    移动电商风起云涌,直播带货重塑销售模式,传统商业更是举步维艰,各行各业转型移动电商迫在眉睫,拥有一款好的移动社群社交电商系统成为众多企业与商家的心病! 你曾是否被那些劣质的移动电商系统搞得心力憔悴? ...

  4. 移动开发中如何整合HTML 5和原生代码

    移动开发中如何整合HTML 5和原生代码 https://blog.csdn.net/lvjin110/article/details/41038565

  5. 16_Python的包package

    1.包的概述 1.包是将模块一文件夹的组织形式进行分组管理的方法,一系列模块进行分类管理有利于防止命名冲突 2.包是一个包含多个模块的特色目录,目录下有一个特色的文件__init__.py 3.包的命 ...

  6. The relationship between Sonarcube coverage and code branch

    Once I was asked to enhance the sonarcube coverage of the class:‘jp.co.XXXXp.DltApiHttpRequestRetryH ...

  7. nginx模型概念和配置文件结构

    一. nginx模型概念: Nginx会按需同时运行多个进程: 一个主进程(master)和几个工作进程(worker),配置了缓存时还会有缓存加载器进程(cache loader)和缓存管理器进程( ...

  8. Spring-代理模式

    代理模式 目录 代理模式 1. 代理模式的分类 2. 静态代理 1. 角色分析 2. 代码步骤 3. 代理的好处 4. 进一步理解 3. 动态代理 1. 角色分析 2. 对动态代理的两个关键类的理解 ...

  9. Jenkins下Vue自动部署(二)

    1Jenkins配置 获取首次密码 sudo docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword 2 2.1J ...

  10. 登录SQL Server服务器时的服务器名称

    在本地访问Microsoft SQL Server 2008服务器时,首先就是要填写正确的服务器名称.经测试,该名称可以有多种写法,具体如下: 写法一: X\sqlexpress(X即计算机名) 写法 ...