手把手撸套框架-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="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>
<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">×</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 详解的更多相关文章
- 手把手撸套框架-Victory框架1.1 详解
目录 上一篇博客 Victory框架1.0 详解 有说道,1.0的使用过程中出现不少缺点,比如菜单不能折叠,权限没有权限组等等. 所以,我还是抽出时间在下班后,回到我的小黑屋里 完成了1.1的升级. ...
- ORM框架对比以及Mybatis配置文件详解
ORM框架对比以及Mybatis配置文件详解 0.数据库操作框架的历程 (1) JDBC JDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQL语句 ...
- Django框架 之 ORM查询操作详解
Django框架 之 ORM查询操作详解 浏览目录 一般操作 ForeignKey操作 ManyToManyField 聚合查询 分组查询 F查询和Q查询 事务 Django终端打印SQL语句 在Py ...
- laravel框架的中间件middleware的详解
本篇文章给大家带来的内容是关于laravel框架的中间件middleware的详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. laravel中间件是个非常方便的东西,能将一些逻辑 ...
- 百度大脑UNIT3.0详解之嵌入式对话理解技术
相信很多人都体验过手机没有网时的焦虑,没有网什么也做不了.而机器人也会遇到这样的时刻,没有网或者网络环境不好的情况下,无法识别用户在说什么,也无法回复用户.在AIoT(AI+物联网)飞速普及的现在,智 ...
- 百度大脑UNIT3.0详解之知识图谱与对话
如今,越来越多的企业想要在电商客服.法律顾问等领域做一套包含行业知识的智能对话系统,而行业或领域知识的积累.构建.抽取等工作对于企业来说是个不小的难题,百度大脑UNIT3.0推出「我的知识」版块专门为 ...
- 百度大脑UNIT3.0详解之数据生产工具DataKit
在智能对话项目搭建的过程中,高效筛选.处理对话日志并将其转化为新的训练数据,是对话系统效果持续提升的重要环节,也是当前开发者面临的难题之一.为此百度大脑UNIT推出学习反馈闭环机制,提供数据获取.辅助 ...
- Hadoop框架:DataNode工作机制详解
本文源码:GitHub·点这里 || GitEE·点这里 一.工作机制 1.基础描述 DataNode上数据块以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是数据块元数据包括长度.校验.时 ...
- Laravel框架中的make方法详解
为什么网上已经有这么多的介绍Laravel的执行流程了,Laravel的容器详解了,Laravel的特性了,Laravel的启动过程了之类的文章,我还要来再分享呢? 因为,每个人的思维方式和方向是不一 ...
随机推荐
- 抗疫复产,CDN助企业破局发展
摘要:CDN的任务就是要确保这条“互联网信息高速公路”的顺畅通行,避免因为拥塞而导致出行效率的降低. 在抗疫复产的过程中,云计算大放异彩.作为数字经济的流量底座,CDN为互联网海量汹涌的数据内容分发保 ...
- Combine 框架,从0到1 —— 3.使用 Subscriber 控制发布速度
本文首发于 Ficow Shen's Blog,原文地址: Combine 框架,从0到1 -- 3.使用 Subscriber 控制发布速度. 内容概览 前言 在发布者生产元素时消耗它们 使 ...
- WPF新手快速入门系列 1.布局
[概要] 该系列文章主要描述,新手如何快速上手做wpf开发.看过网上部分的教程,主要讲述的是介绍控件.这并没有问题,但是没有把自己的使用经验也完整的描述出来. 所以特此编写此系列文章希望能帮助到,因为 ...
- 力扣Leetcode 461. 汉明距离
给你一个数组 arr ,请你将每个元素用它右边最大的元素替换,如果是最后一个元素,用 -1 替换. 完成所有替换操作后,请你返回这个数组. 示例: 输入:arr = [17,18,5,4,6,1] 输 ...
- Kubernetes实战总结 - 阿里云ECS自建K8S集群
一.概述 详情参考阿里云说明:https://help.aliyun.com/document_detail/98886.html?spm=a2c4g.11186623.6.1078.323b1c9b ...
- 递推dp数位
1-n里有多少个1 #include <cstdio> #include <iostream> using namespace std; int main() { int n= ...
- 深入理解 IoC、DI
本文转载自博客:https://www.cnblogs.com/xinhuaxuan/p/6132372.html 1.控制反转:谁控制谁?控制什么?为何叫反转(对应于正向)?哪些方面反转了?为何需要 ...
- 跟着尚硅谷系统学习Docker-【day01】
day01-20200710 p1.基础知识 鲸鱼背上有一些集装箱 学习docker得基础知识 1.强制:熟悉Linux命令和相关背景知识 2.建议有maven和git的相关知识 ...
- C#中部分重点前端设置问题
背景 在工作及学习过程中经常会遇到一些奇怪的需求,这里便会记录我遇到的奇怪需求及解决方法. 内容 一.动态设置页面标题 1.前端设置 JS代码: document.title="这是一个标题 ...
- springboot2.x基础教程:动手制作一个starter包
上一篇博客介绍了springboot自动装配的原理.springboot本身有丰富的spring-boot-starter-xx集成组件,这一篇趁热打铁加深理解,我们利用springboot自动装配的 ...