diff --git a/.docs/README.md b/.docs/README.md
new file mode 100644
index 00000000..c7aaa452
--- /dev/null
+++ b/.docs/README.md
@@ -0,0 +1,2 @@
+BlogCore官方文档仓库地址已经迁移到:
+https://gitee.com/laozhangIsPhi/Blog.Core.E-Book
\ No newline at end of file
diff --git a/.docs/contents/.vuepress/config.js b/.docs/contents/.vuepress/config.js
deleted file mode 100644
index 18d62a61..00000000
--- a/.docs/contents/.vuepress/config.js
+++ /dev/null
@@ -1,45 +0,0 @@
-module.exports = {
- title: 'Blog.Core',
- description: 'Hello, 欢迎使用前后端分离之 ASP.NET Core 后端全家桶框架!',
- base : '/.doc/',
- head: [
- ['link', {
- rel: 'icon',
- href: `/favicon.ico`
- }]
- ],
- dest: './contents/.vuepress/dist',
- ga: '',
- evergreen: true,
- themeConfig: {
- nav: [
- { text: '首页', link: '/' },
- { text: '指南', link: '/guide/' },
- { text: '更新日志', link: '/Update/' },
- { text: '参与贡献', link: '/Contribution/' },
- { text: '社区', link: '/QQ/' },
- { text: '接口API', link: 'http://apk.neters.club' },
- { text: '管理后台', link: 'http://vueadmin.neters.club' },
- { text: 'Github', link: 'https://github.com/anjoy8/Blog.Core' },
- ],
- sidebarDepth: 2,
- sidebar: {
- '/guide/': getGuideSidebar('Guide'),
- }
- }
-}
-
-function getGuideSidebar (groupA) {
- return [
- {
- title: groupA,
- collapsable: false,
- children: [
- '',
- 'getting-started',
- 'function-sheet',
- 'cheat-sheet'
- ]
- }
- ]
- }
\ No newline at end of file
diff --git a/.docs/contents/.vuepress/public/bcvphomelogo.png b/.docs/contents/.vuepress/public/bcvphomelogo.png
deleted file mode 100644
index e1bf0f79..00000000
Binary files a/.docs/contents/.vuepress/public/bcvphomelogo.png and /dev/null differ
diff --git a/.docs/contents/.vuepress/public/favicon.ico b/.docs/contents/.vuepress/public/favicon.ico
deleted file mode 100644
index 68062fe0..00000000
Binary files a/.docs/contents/.vuepress/public/favicon.ico and /dev/null differ
diff --git a/.docs/contents/Contribution/README.md b/.docs/contents/Contribution/README.md
deleted file mode 100644
index c76b03c6..00000000
--- a/.docs/contents/Contribution/README.md
+++ /dev/null
@@ -1,71 +0,0 @@
-# 贡献
-
-
-欢迎一起完善文档,
-参与打赏的小可爱名单如下(单位:元),你们的贡献是我继续的动力:
-(2020年6月15日 20点52分)
-
-
-|序号|微信昵称|助力值|备注|
-|-|-|-|-|
-|01|排 * * 瓜|100||
-|02|船 * * 长|100||
-|03|二 * * 生|1||
-|04||1|未留微信号|
-|05|旭 * * 光|10||
-|06||12.66|未留微信号|
-|07|Ro * * st|10||
-|08|陈 * * 朝|10||
-|09|勇 * * 勇|10||
-|10|袁 * * 嘉|10||
-|11|En * * us|20||
-|12|风 * * 在|18||
-|13|林 * * 杰|10||
-|14|枫 * * 叶|10||
-|15|火 * * 鸟 |50||
-|16|阿 * * 福|10||
-|17||20|未留微信号|
-|18|Er * * or|100|未留微信号|
-|19|陶 * * ve|20||
-|20|熊 * * 育|50||
-|21|点 * * 痕|20||
-|22|夏 * * 目|20||
-|23|CL * * L|50||
-|24|rm * * rf|100||
-|25|Je * * ca|30|搜不到微信号|
-|26|W * * 生|50||
-|27|鹏 * * 郎|20||
-|28|ws * * ai|10||
-|29|逐 * * 梦|20||
-|30|Jo * * aH|10||
-|31|Do * * n|10||
-|32|灰 * * 白|50||
-|33|Ne * * er|100||
-|34|Ar * * as|10||
-|35|吉 * * 祥|36||
-|36|ma * * y|10||
-|37|Yu * * ic|30||
-|38|亡 * * 死|30||
-|39|板 * * 根|20||
-|40|-- * * -|100|未留微信号|
-|41|t * * |20||
-|42|王 * * 聪 |10|未留微信号|
-|43|哈 * * 方|50||
-|44|le * * on|30||
-
-
-
-
-
-
-## 参与贡献的开源项目
-
-如果帮忙以前完善文档,可以在这里留下你的开源项目,做推广。
-
-```
-1、https://github.com/GeorGeWzw/Sukt.Core(作者:kawhi)
-2、https://github.com/wmowm/Gourd(作者:提伯斯)
-3、https://github.com/GeorGeWzw/Destiny.Core.Flow(作者:大黄瓜|kawhi)备注:重写的Identity的用户角色
-
-
-```
\ No newline at end of file
diff --git a/.docs/contents/QQ/README.md b/.docs/contents/QQ/README.md
deleted file mode 100644
index 69b509cb..00000000
--- a/.docs/contents/QQ/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-## QQ 群
-
-
-
-
-
-## 微信公众号
-
-
-
-
diff --git a/.docs/contents/README.md b/.docs/contents/README.md
deleted file mode 100644
index e7e1b123..00000000
--- a/.docs/contents/README.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-home: true
-heroImage: /bcvphomelogo.png
-actionText: 快速上手 →
-actionLink: /guide/
-features:
-- title: 详尽的文档
- details: 通过详细的文章和视频讲解,将知识点各个击破,入门ASP.Net Core不再难
-- title: 强大的社区
- details: 通过 QQ 群,和数千位同业大佬一起切磋交流。
-- title: 丰富的内容
- details: 框架涵盖ASP.Net Core开发中常见的基本知识点,不仅适合初学者入门,同时也适用于企业级别的开发。
-footer: MIT Licensed | Copyright © 2018-2020-老张的哲学
----
\ No newline at end of file
diff --git a/.docs/contents/Update/README.md b/.docs/contents/Update/README.md
deleted file mode 100644
index 022d0098..00000000
--- a/.docs/contents/Update/README.md
+++ /dev/null
@@ -1,100 +0,0 @@
-
-## 更新日志
-
-### 2020-06-22
-
-> 重要项目更新:将服务扩展和自定义中间件封装单独一层 `Blog.Core.Extensions` 更解耦。
-
-
-### 2020-06-08
-
-> 简单项目更新:生成数据库表结构的时候,利用反射机制,自动生成固定命名空间 `Blog.Core.Model.Models` 下的全部实体.
-> 同时判断表是否存在,如果存在下次不再重复生成。
-
-
-### 2020-06-06
-
-项目更新:更新项目模板 `Update Blog.Core.Webapi.Template.2.1.0.nupkg` [1a726f8](https://github.com/anjoy8/Blog.Core/commit/1a726f890e527c978982071462e82db4478632f0),更新项目即可 。
-> 1、配置内容展示到控制台;
-> 2、简化封装 `Startup.cs` 类文件;
-> 3、`DbFirst` 模式支持多库模式;
-> 4、`Log4net` 讲异常和 `Info` 分开;
-> 5、修复 `BlogLogAop` 偶尔卡顿问题;
-> 6、将生成种子数据和任务调度功能,封装到中间件;
-> 7、获取当前项目在服务器中的运行信息;
-> 8、删除所有的不需要的 `using` 指令;
-
-
-
-
-### 2020-05-29
-项目启动开启 `QuzrtzNet` 调度任务,并且在 `Admin` 后台管理中配置操作界面;
-> 内容更新:封装生成种子数据的入口方法;
-
-
-
-### 2020-05-12
-修复:支持多库模式下,生成项目模板代码 `DbFirstController` [102c6d6](https://github.com/anjoy8/Blog.Core/commit/102c6d6bfcafd06bf5241844759dea5e7a6815da)
-> 注意:`T4` 模板不能此功能,一次只能一个数据库,且只能 `SqlServer`
-
-
-### 2020-05-07
-> 重大内容更新:更新项目模板 `Update Blog.Core.Webapi.Template.2.1.0.nupkg` [7f64fde](https://github.com/anjoy8/Blog.Core/commit/7f64fde5507f7a8572372dcadb6af5110bd37d68)
-
-
-### 2020-05-06
-> 重大内容更新:优化Log4Net使用方案,完美配合 `NetCore` 官方的 `ILogger`, [ecaffb6](https://github.com/anjoy8/Blog.Core/commit/ecaffb66bdf10a90c087d01e6e817e54f23a97d4)
-
-
-### 2020-05-01
-
-> 重要内容更新:配合Admin全部完成按钮级别权限,更新初始化种子数据
-
-### 2020-04-27
-
-增加功能:配合前端Admin,增加页面 `KeepAlive` 功能;
-增加功能:增加 `Sql` 语句查询Demo,支持返回 `DataTable`;
-
-
-### 2020-04-25
-
-增加功能:`Http api` 接口调用,满足微服务需求
-> 重要内容更新:优化 `Appsettings.app()` 方法,通过官方 `IConfiguration` 接口来获取DBS连接字符串;
-> 优化 `BlogLogAOP.cs`
-
-
-### 2020-04-15
-
-> 重大内容更新:更新项目模板 `Update Blog.Core.Webapi.Template.1.11.30.nupkg`
-
-
-### 2020-04-14
-> 重大内容更新:主分支,可以通过配置,一键切换JWT和Ids4认证授权模式
-
-
-### 2020-03-30
-> 重大内容更新:统一所有接口返回格式
-
-
-### 2020-03-25
-增加功能:支持读写分离(目前是三种模式:单库、多库、读写分离)
-> 重大BUG更新:系统登录接口,未对用户软删除进行判断,现已修复
-> API: /api/login/GetJwtToken3
-> Code: await _sysUserInfoServices.Query(d => d.uLoginName == name && d.uLoginPWD == pass && d.tdIsDelete == false);
-
-
-
-### 2020-03-18
-增加功能:创建 Quartz.net 任务调度服务
-
-
-### 2020-01-09
-增加功能:项目迁移到IdentityServer4,统一授权认证中心
-
-
-### 2020-01-05
-增加功能:设计一个简单的中间件,可以查看所有已经注入的服务
-
-
-### 2020-01-04
-增加功能:Ip限流,防止过多刷数据
diff --git a/.docs/contents/guide/README.md b/.docs/contents/guide/README.md
deleted file mode 100644
index 1a4930b2..00000000
--- a/.docs/contents/guide/README.md
+++ /dev/null
@@ -1,89 +0,0 @@
-# J 介绍
-
-最新的前后端完全分离框架【 ASP.NET Core 3.1 Api + Vue 2.x + ele】。
-ASP.NET Core 3.1 教程,前后端分离的后端接口,vue教程的姊妹篇。
-BCVP(Blog.Core&Vue Project)开箱即用的企业级前后端分离【 .NET Core3.1 Api + Vue 2.x + RBAC】权限框架。
-
-## 你能得到什么?
-1、从 0 到 1 快速入门 ASP.NET Core 框架。
-2、掌握开发中的常用知识点,为跨平台、微服务打好基础。
-3、下载即用,简单高效开发属于自己公司项目,配置简单,功能完善。
-
-
-
-## 功能与进度
-
-- [√] 采用仓储+服务+接口的形式封装框架;
-- [√] 使用Swagger做api文档;
-- [√] 使用MiniProfiler做接口性能分析;
-- [√] 使用Automapper做Dto处理;
-- [√] 接入SqlSugar ORM,封装数据库操作;
-- [√] 项目启动,自动生成seed种子数据;
-- [√] 提供五种日志输出;
-- [√] 支持自由切换多种数据库,Sqlite/SqlServer/MySql/PostgreSQL/Oracle;
-- [√] 异步async/await开发;
-- [√] 支持事务;
-- [√] AutoFac接入做依赖注入;
-- [√] 支持AOP切面编程;
-- [√] 支持CORS跨域;
-- [√] 支持T4代码模板,自动生成每层代码;
-- [√] 支持一键创建自己项目;
-- [√] 封装 JWT 自定义策略授权;
-- [√] 使用Log4Net日志框架+自定义日志输出;
-- [√] 使用SingleR推送日志信息到管理后台;
-- [√] 搭配前端Blog项目,vue开发;
-- [√] 搭配一个Admin管理后台,用vue+ele开发;
-- [√] IdentityServer4 认证;
-- [√] API 限速;
-- [√] 作业调度 Quartz.net;
-- [√] Sqlsugar 读写分离;
-- [ ] Redis 队列;
-- [ ] 支付;
-- [ ] 数据部门权限;
-
-
-
-## 它是如何工作的?
-
-这是一个基于 ASP.NET Core 3.1 的 api 项目,配合搭建 VUE 实现前后端分离工程。
-
-**************************************************************
-系统环境
-
-> windows 10、SQL server 2012、Visual Studio 2017、Windows Server 2008 R2
-
-后端技术:
-
-> 1、ASP.NET Core 3.1 API
- 2、Swagger 前后端文档说明,基于RESTful风格编写接口
- 3、Repository + Service 仓储模式编程
- 4、Async和Await 异步编程
- 5、CORS 简单的跨域解决方案
- 6、AOP基于切面编程技术
- 7、Autofac 轻量级IoC和DI依赖注入
- 8、Vue 本地代理跨域方案,Nginx跨域代理
- 9、JWT权限验证
-10、Filter 过滤器
-11、Middleware 中间件
-12、AutoMapper 自动对象映射
-13、Redis
-
-
-数据库技术
-
-> SqlSugar 轻量级ORM框架,CodeFirst
- T4 模板生成框架结构
- 支持SqlServer、Mysql、Sqlite、Oracle、Pgql数据库
- 支持多库操作
-
-
-
-
-前端技术
-
-> Vue 2.x 框架全家桶 Vue2 + VueRouter2 + Webpack + Axios + vue-cli + vuex
-ElementUI 基于Vue 2.0的组件库
-Nuxt.js服务端渲染SSR
-
-
-
diff --git a/.docs/contents/guide/cheat-sheet.md b/.docs/contents/guide/cheat-sheet.md
deleted file mode 100644
index c99b5398..00000000
--- a/.docs/contents/guide/cheat-sheet.md
+++ /dev/null
@@ -1,580 +0,0 @@
-# Z 主要知识点
-
-
-
-## AOP
-
-本项目多处采用面向切面编程思想——AOP,除了广义上的过滤器和中间件以外,主要通过动态代理的形式来实现AOP编程思想,主要的案例共有四个,分别是:
-1、服务日志AOP;
-2、服务InMemory缓存AOP;
-3、服务Redis缓存AOP;
-4、服务事务AOP;
-
-
-具体的代码可以在 `Blog.Core\Blog.Core\AOP` 文件夹下查看。
-
-与此同时,多个AOP也设置了阀门来控制是否开启,具体的可以查看 `appsettings.json` 中的:
-
-```
- "AppSettings": {
- "RedisCachingAOP": {
- "Enabled": false,
- "ConnectionString": "127.0.0.1:6319"
- },
- "MemoryCachingAOP": {
- "Enabled": true
- },
- "LogAOP": {
- "Enabled": false
- },
- "TranAOP": {
- "Enabled": false
- },
- "SqlAOP": {
- "Enabled": false
- }
- },
-
-```
-
-## Appsettings
-
-整个系统通过一个封装的操作类 `Appsettings.cs` 来控制配置文件 `appsettings.json` 文件,
-操作类地址在:`\Blog.Core.Common\Helper` 文件夹下。
-具体的使用方法是:
-
-```
-Appsettings.app(new string[] { "AppSettings", "RedisCachingAOP", "Enabled" })
-
-// 里边的参数,按照 appsettings.json 中设置的层级顺序来写,可以获取到指定的任意内容。
-
-```
-
-
-
-## AspNetCoreRateLimit
-
-系统使用 `AspNetCoreRateLimit` 组件来实现ip限流:
-1、添加 `nuget` 包:
-```
-
-```
-
-2、注入服务 `IpPolicyRateLimitSetup.cs`
-```
-services.AddIpPolicyRateLimitSetup(Configuration);
-```
-
-3、配置中间件
-```
- // Ip限流,尽量放管道外层
- app.UseIpRateLimiting();
-```
-
-4、配置数据
-
-具体的内容,自行百度即可
-```
- "IpRateLimiting": {
- "EnableEndpointRateLimiting": true,
- "StackBlockedRequests": false,
- "RealIpHeader": "X-Real-IP",
- "ClientIdHeader": "X-ClientId",
- "HttpStatusCode": 429,//返回状态码
- "GeneralRules": [//规则,结尾一定要带*
- {
- "Endpoint": "*",
- "Period": "1m",
- "Limit": 120
- },
- {
- "Endpoint": "*:/api/blog*",
- "Period": "1m",
- "Limit": 30
- }
- ]
-
- }
-```
-
-
-
-## Async-Await
-
-整个系统采用 async/await 异步编程,符合主流的开发模式,
-特别是对多线程开发很友好。
-
-
-
-## Authorization-Ids4
-
-本系统 v2.0 版本(目前的系统已经集成 `ids4` 和 `jwt`,并且可以自由切换),已经支持了统一授权认证,和 `blog` 项目、`Admin` 项目、`DDD` 项目等一起,使用一个统一的认证中心。
-
-具体的代码参考:`.\Blog.Core\Extensions` 文件夹下的 `Authorization_Ids4Setup.cs` ,注意需要引用指定的 `nuget` 包,核心代码如下:
-
-```
- //【认证】
- services.AddAuthentication(o =>
- {
- o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
- o.DefaultChallengeScheme = nameof(ApiResponseHandler);
- o.DefaultForbidScheme = nameof(ApiResponseHandler);
- })
- // 2.添加Identityserver4认证
- .AddIdentityServerAuthentication(options =>
- {
- options.Authority = Appsettings.app(new string[] { "Startup", "IdentityServer4", "AuthorizationUrl" });
- options.RequireHttpsMetadata = false;
- options.ApiName = Appsettings.app(new string[] { "Startup", "IdentityServer4", "ApiName" });
- options.SupportedTokens = IdentityServer4.AccessTokenValidation.SupportedTokens.Jwt;
- options.ApiSecret = "api_secret";
-
- })
-
-
-```
-
-### 如何在Swagger中配置Ids4?
-很简单,直接在 `SwaggerSetup.cs` 中直接接入 `oauth、Implicit` 即可:
-
-```
- //接入identityserver4
- c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
- {
- Type = SecuritySchemeType.OAuth2,
- Flows = new OpenApiOAuthFlows
- {
- Implicit = new OpenApiOAuthFlow
- {
- AuthorizationUrl = new Uri($"{Appsettings.app(new string[] { "Startup", "IdentityServer4", "AuthorizationUrl" })}/connect/authorize"),
- Scopes = new Dictionary {
- {
- "blog.core.api","ApiResource id"
- }
- }
- }
- }
- });
-
-```
-
-然后在 `IdentityServer4` 项目中,做指定的修改,配置 `8081` 的回调地址:
-
-```
- new Client {
- ClientId = "blogadminjs",
- ClientName = "Blog.Admin JavaScript Client",
- AllowedGrantTypes = GrantTypes.Implicit,
- AllowAccessTokensViaBrowser = true,
-
- RedirectUris =
- {
- "http://vueadmin.neters.club/callback",
- // 这里要配置回调地址
- "http://localhost:8081/oauth2-redirect.html"
- },
- PostLogoutRedirectUris = { "http://vueadmin.neters.club" },
- AllowedCorsOrigins = { "http://vueadmin.neters.club" },
-
- AllowedScopes = {
- IdentityServerConstants.StandardScopes.OpenId,
- IdentityServerConstants.StandardScopes.Profile,
- "roles",
- "blog.core.api"
- }
- },
-
-```
-
-然后再 `Swagger` 中,配置登录授权:
-
-
-
-
-## Authorization-JWT
-
-如果你不想使用 `IdentityServer4` 的话,也可以使用 `JWT` 认证,同样是是`Blog.Core\Blog.Core\Extensions` 文件夹下的 `AuthorizationSetup.cs` 中有关认证的部分:
-
-```
- 1.添加JwtBearer认证服务
-.AddJwtBearer(o =>
-{
- o.TokenValidationParameters = tokenValidationParameters;
- o.Events = new JwtBearerEvents
- {
- OnAuthenticationFailed = context =>
- {
- // 如果过期,则把<是否过期>添加到,返回头信息中
- if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
- {
- context.Response.Headers.Add("Token-Expired", "true");
- }
- return Task.CompletedTask;
- }
- };
-})
-
-```
-
-
-## AutoMapper
-
-使用 `AutoMapper` 组件来实现 `Dto` 模型的传输转换,具体的用法,可以查看:
-`Blog.Core\Blog.Core\Extensions` 文件夹下的 `AutoMapperSetup.cs` 扩展类,
-通过引用 `AutoMapper` 和 `AutoMapper.Extensions.Microsoft.DependencyInjection` 两个 `nuget` 包,并设置指定的 `profile` 文件,来实现模型转换控制。
-
-```
-// 比如如何定义:
- public class CustomProfile : Profile
- {
- ///
- /// 配置构造函数,用来创建关系映射
- ///
- public CustomProfile()
- {
- CreateMap();
- CreateMap();
- }
- }
-
-
-// 比如如何使用
-models = _mapper.Map(blogArticle);
-
-```
-
-具体的查看项目中代码即可。
-
-
-
-
-## CORS
-
-在线项目使用的是 `nginx` 跨域代理,但是同时也是支持 `CORS` 代理:
-1、注入服务 `services.AddCorsSetup();` 具体代码 `Blog.Core\Blog.Core\Extensions` 文件夹下的 `CorsSetup.cs` 扩展类;
-2、配置中间件 `app.UseCors("LimitRequests");` ,要注意中间件顺序;
-3、配置自己项目的前端端口,通过在 `appsettings.json` 文件中配置自己的前端项目 `ip:端口` ,来实现跨域:
-
-```
- "Startup": {
- "Cors": {
- "IPs": "http://127.0.0.1:2364,http://localhost:2364,http://localhost:8080,http://localhost:8021,http://localhost:1818"
- }
- },
-
-```
-
-
-## DI-AutoFac
-
-项目使用了依赖注入,除了原生的依赖注入以外,更多的使用的是第三方组件 `Autofac` :
-1、引用依赖包:
-```
-
-
-
-```
-主要是第一个 `nuget` 包,下边的是为了实现动态代理 `AOP` 操作;
-
-2、项目之间采用引用解耦的方式,通过反射来注入服务层和仓储层的程序集 `dll` 来实现批量注入,更方便,以后每次新增和修改 `Service` 层和 `Repository` 层,只需要 `F6` 编译一下即可,具体代码查看 `Startup.cs`:
-
-```
-
-
- // 注意在CreateDefaultBuilder中,添加Autofac服务工厂
- public void ConfigureContainer(ContainerBuilder builder)
- {
- var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
- //builder.RegisterType().As();
-
-
- #region 带有接口层的服务注入
-
-
- var servicesDllFile = Path.Combine(basePath, "Blog.Core.Services.dll");
- var repositoryDllFile = Path.Combine(basePath, "Blog.Core.Repository.dll");
-
- if (!(File.Exists(servicesDllFile) && File.Exists(repositoryDllFile)))
- {
- throw new Exception("Repository.dll和service.dll 丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查 bin 文件夹,并拷贝。");
- }
-
-
-
- // AOP 开关,如果想要打开指定的功能,只需要在 appsettigns.json 对应对应 true 就行。
- var cacheType = new List();
- if (Appsettings.app(new string[] { "AppSettings", "RedisCachingAOP", "Enabled" }).ObjToBool())
- {
- builder.RegisterType();
- cacheType.Add(typeof(BlogRedisCacheAOP));
- }
- if (Appsettings.app(new string[] { "AppSettings", "MemoryCachingAOP", "Enabled" }).ObjToBool())
- {
- builder.RegisterType();
- cacheType.Add(typeof(BlogCacheAOP));
- }
- if (Appsettings.app(new string[] { "AppSettings", "TranAOP", "Enabled" }).ObjToBool())
- {
- builder.RegisterType();
- cacheType.Add(typeof(BlogTranAOP));
- }
- if (Appsettings.app(new string[] { "AppSettings", "LogAOP", "Enabled" }).ObjToBool())
- {
- builder.RegisterType();
- cacheType.Add(typeof(BlogLogAOP));
- }
-
- // 获取 Service.dll 程序集服务,并注册
- var assemblysServices = Assembly.LoadFrom(servicesDllFile);
- builder.RegisterAssemblyTypes(assemblysServices)
- .AsImplementedInterfaces()
- .InstancePerDependency()
- .EnableInterfaceInterceptors()//引用Autofac.Extras.DynamicProxy;
- .InterceptedBy(cacheType.ToArray());//允许将拦截器服务的列表分配给注册。
-
- // 获取 Repository.dll 程序集服务,并注册
- var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
- builder.RegisterAssemblyTypes(assemblysRepository)
- .AsImplementedInterfaces()
- .InstancePerDependency();
-
- #endregion
-
- #region 没有接口层的服务层注入
-
- //因为没有接口层,所以不能实现解耦,只能用 Load 方法。
- //注意如果使用没有接口的服务,并想对其使用 AOP 拦截,就必须设置为虚方法
- //var assemblysServicesNoInterfaces = Assembly.Load("Blog.Core.Services");
- //builder.RegisterAssemblyTypes(assemblysServicesNoInterfaces);
-
- #endregion
-
- #region 没有接口的单独类 class 注入
-
- //只能注入该类中的虚方法
- builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love)))
- .EnableClassInterceptors()
- .InterceptedBy(cacheType.ToArray());
-
- #endregion
-
-
- // 这里和注入没关系,只是获取注册列表,请忽略
- tsDIAutofac.AddRange(assemblysServices.GetTypes().ToList());
- tsDIAutofac.AddRange(assemblysRepository.GetTypes().ToList());
- }
-
-```
-
-3、然后 `Program.cs` 中也要加一句话:` .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //<--NOTE THIS `
-
-
-
-## DI-NetCore
-
-除了主要的 `Autofac` 依赖注入以外,也减少的使用了原生的依赖注入方式,很简单,比如这样的:
-```
-
- services.AddSingleton();
- // 注入权限处理器
- services.AddScoped();
- services.AddSingleton(permissionRequirement);
-```
-
-
-## Filter
-
-项目中一共有四个过滤器
-```
-1、GlobalAuthorizeFilter.cs —— 全局授权配置,添加后,就可以不用在每一个控制器上添加 [Authorize] 特性,但是3.1版本好像有些问题,【暂时放弃使用】;
-2、GlobalExceptionFilter.cs —— 全局异常处理,实现 actionContext 级别的异常日志收集;
-3、GlobalRoutePrefixFilter.cs —— 全局路由前缀公约,统计在路由上加上前缀;
-4、UseServiceDIAttribute.cs —— 测试注入,【暂时无用】;
-```
-文件地址在 `.\Blog.Core\Filter` 文件夹下,其中核心的是 `2` 个,重点使用的是 `1` 个 —— 全局异常错误日志 `GlobalExceptionsFilter`:
-通过注册在 `MVC` 服务 `services.AddControllers()` 中,实现全局异常过滤:
-```
- services.AddControllers(o =>
- {
- // 全局异常过滤
- o.Filters.Add(typeof(GlobalExceptionsFilter));
- // 全局路由权限公约
- //o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention());
- // 全局路由前缀,统一修改路由
- o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name)));
- })
-```
-
-
-
-## Framework
-
-项目采用 `服务+仓储+接口` 的多层结构,使用依赖注入,并且通过解耦项目,较完整的实现了 `DIP` 原则:
-高层模块不应该依赖于底层模块,二者都应该依赖于抽象。
-抽象不应该依赖于细节,细节应该依赖于抽象。
-
-同时项目也封装了:
-`CodeFirst` 初始化数据库以及数据;
-`DbFirst` 根据数据库(支持多库),生成多层代码,算是简单代码生成器;
-其他功能,[核心功能与进度](http://apk.neters.club/.doc/guide/#%E5%8A%9F%E8%83%BD%E4%B8%8E%E8%BF%9B%E5%BA%A6)
-
-
-
-
-## Log
-
-通过集成 `Log4Net` 组件,完美配合 `NetCore` 官方的 `ILogger` 接口,实现对日志的管控,引用 `nuget` 包 `Microsoft.Extensions.Logging.Log4Net.AspNetCore`:
-Program.cs
-```
- webBuilder
- .UseStartup()
- .ConfigureLogging((hostingContext, builder) =>
- {
- //该方法需要引入Microsoft.Extensions.Logging名称空间
- builder.AddFilter("System", LogLevel.Error); //过滤掉系统默认的一些日志
- builder.AddFilter("Microsoft", LogLevel.Error);//过滤掉系统默认的一些日志
-
- //添加Log4Net
- //var path = Directory.GetCurrentDirectory() + "\\log4net.config";
- //不带参数:表示log4net.config的配置文件就在应用程序根目录下,也可以指定配置文件的路径
- //需要添加nuget包:Microsoft.Extensions.Logging.Log4Net.AspNetCore
- builder.AddLog4Net();
- });
-
-```
-
-然后直接在需要的地方注入使用,比如在控制器中
-` public UserController(ILogger logger)`
-
-然后就可以使用了。
-
-> 注意:日志 其实是分为两部分的:
-> netcore输出(控制台、输出窗口等) 和 `ILogger` 持久化
-> 两者对应配置也不一样,就比如上边的过滤,是针对日志持久化的,如果想要对控制台进行控制,需要配置 `appsettings.json` 中的 `Logging` 节点
-
-
-## MemoryCache
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-
-## Middleware
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-## MiniProfiler
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-
-## publish
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-
-
-## Redis
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-## Repository
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-## SeedData
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-## SignalR
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-## SqlSugar
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-## SqlSugar-Codefirst&DataSeed
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-## SqlSugar-SqlAOP
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-## Swagger
-
-精力有限,还是更新中...
-如果你愿意帮忙,可以直接在GitHub中,提交pull request,
-我会在后边的贡献者页面里,列出你的名字和项目地址做推广
-## T4
-
-项目集成 `T4` 模板 `.\Blog.Core.FrameWork` 层,目的是可以一键生成项目模板代码。
-1、需要在 `DbHelper.ttinclude` 中配置连接数据库连接字符串;
-2、针对每一层的代码,就去指定的 `.tt` 模板,直接 `CTRL+S` 保存即可;
-
-> 注意,目前的代码是 `SqlServer` 版本的,其他数据库版本的,可以去群文件查看。
-
-
-## Test-xUnit
-
-项目简单使用了单元测试,通过 `xUnit` 组件,具体的可以查看 `Blog.Core.Tests` 层相关代码。
-目前单元测试用例还比较少,大家可以自行添加。
-
-
-## Temple-Nuget
-
-本项目封装了 `Nuget` 自定义模板,你可以根据这个模板,一键创建自己的项目名,具体的操作,可以双击项目根目录下的 `CreateYourProject.bat` ,可以参考 [#如何项目重命名](http://apk.neters.club/.doc/guide/getting-started.html#%E5%A6%82%E4%BD%95%E9%A1%B9%E7%9B%AE%E9%87%8D%E5%91%BD%E5%90%8D)
-
-同时,你也可以再 `Nuget` 管理器中,搜索到:
-
-
-
-
-## UserInfo
-
-
-项目中封装了获取用户信息的代码:
-在 `.\Blog.Core.Common\HttpContextUser` 文件夹下 `AspNetUser.cs` 实现类和 `IUser.cs` 接口。
-
-如果使用,首先需要注册相应的服务,参见:`.\Blog.Core\Extensions` 文件夹下的 `HttpContextSetup.cs`;
-然后,就直接在控制器构造函数中,注入接口 `IUser` 即可;
-
-> `注意`:
-> 1、如果要想获取指定的服务,必须登录,也就是必须要在 `Header` 中传递有效 `Token` ,这是肯定的。
-> 2、如果要获取用户信息,一定要在中间件 `app.UseAuthentication()` 之后(不要问为什么),控制器肯定在它之后,所以能获取到;
-> 3、`【并不是】`一定需要添加 `[Authorize]` 特性,如果你加了这个特性,可以直接获取,但是如果不加,可以从我的 `AspNetUser.cs` 方法中,有一个直接从 `Header` 中解析的方法 `List GetUserInfoFromToken(string ClaimType);`:
-
-```
- public string GetToken()
- {
- return _accessor.HttpContext.Request.Headers["Authorization"].ObjToString().Replace("Bearer ", "");
- }
-
- public List GetUserInfoFromToken(string ClaimType)
- {
-
- var jwtHandler = new JwtSecurityTokenHandler();
- if (!string.IsNullOrEmpty(GetToken()))
- {
- JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(GetToken());
-
- return (from item in jwtToken.Claims
- where item.Type == ClaimType
- select item.Value).ToList();
- }
- else
- {
- return new List() { };
- }
- }
-
-```
diff --git a/.docs/contents/guide/function-sheet.md b/.docs/contents/guide/function-sheet.md
deleted file mode 100644
index 88e87d20..00000000
--- a/.docs/contents/guide/function-sheet.md
+++ /dev/null
@@ -1,471 +0,0 @@
-# H 核心功能一览表
-
-## 一、表结构解析
-
-`Blog.Core` 项目共包含四部分的数据库表结构,分别是:用户角色管理部分、接口菜单权限管理部分、博客文章管理部分、以及其他不重要部分。
-> 注意:目前不提供与维护数据库数据,直接通过 `SeedData` 生成种子数据;
-
-### 1、用户角色管理部分[必须]
-主要是三个表:分别对应用户表(sysUserInfo)、角色表(Role)、用户角色关系表(UserRole)。
-
-
-
-
-
-### 2、接口菜单权限管理部分[必须]
-
-主要是四个表:分别对应接口表(Module)、菜单表(Permission)、接口菜单关系表(ModulePermission)暂时没用到、角色接口菜单关系表(RoleModulePermission)。
-
-
-
-
-
-
-### 3、博客文章管理部分[可选]
-主要是三个表:分别对应博客表(BlogArticle)、Bug专题表(Topic)、Bug内容表(TopicDetail)。
-
-
-
-
-
-
-### 4、其他不重要部分
-
-主要是三个表:分别对应Job调度表(TasksQz)、密码库表(PasswordLib)、操作日志表(OperateLog)、广告表(Advertisement)、公告表(Guestbook)。
-
-
-
-
-
-
-
-
-## 二、日志记录
-
-本框架涵盖了不同领域的日志记录,共五个,分别是:
-
-1、全局异常日志
-
- 开启方式:无需操作。
- 文件路径:web目录下,Log/GlobalExcepLogs_{日期}.log。
- 功能描述:记录项目启动后出现的所有异常日志,不包括中间件中异常。
-
-
-2、IP 请求日志
-
- 开启方式:无需操作。
- 文件路径:web目录下,Log/RequestIpInfoLog.log。
- 功能描述:记录项目启动后客户端请求的ip和接口信息。
- 举例来说:
- {"Ip":"xxx.xx.xx.x","Url":"/api/values","Datetime":"2020-01-06 18:02:19","Date":"2020-01-06","Week":"周一"}
-
-
-3、全部请求与响应日志
-
- 开启方式:appsettings.json -> Middlewar -> RequestResponseLog 节点为true。
- 文件路径:web目录下,Log/RequestIpInfoLog.log。
- 功能描述:记录项目启动后客户端所有的请求和响应日志,包括url参数、body以及相应json。
-
-
-4、服务层请求响应AOP日志
-
- 开启方式:appsettings.json -> AppSettings -> LogAOP 节点为true。
- 文件路径:web目录下,Log/AOPLog.log。
- 功能描述:记录项目启动请求api后,所有的service层日志,包括方法名、参数、响应结果或用户(非必须)。
-
-
-5、数据库操作日志
-
- 开启方式:appsettings.json -> AppSettings -> SqlAOP 节点为true。
- 文件路径:web目录下,Log/SqlLog.log。
- 功能描述:记录项目启动请求api并访问service后,所有的db操作日志,包括Sql参数与Sql语句。
- 举例来说:
- --------------------------------
- 1/6/2020 6:13:04 PM|
- 【SQL参数】:@bID0:1
- 【SQL语句】:SELECT `bID`,`bsubmitter`,`btitle`,`bcategory`,`bcontent`,`btraffic`,`bcommentNum`,`bUpdateTime`,`bCreateTime`,`bRemark`,`IsDeleted` FROM `BlogArticle` WHERE ( `bID` = @bID0 )
-
-
- ## 三、控制台信息展示
-
-
-
-
-
- ## 四、Nginx一览表
-
-
-
-```
-#user nobody;
-worker_processes 1;
-
-#error_log logs/error.log;
-#error_log logs/error.log notice;
-#error_log logs/error.log info;
-
-#pid logs/nginx.pid;
-events {
- worker_connections 1024;
-}
-
-http {
- include mime.types;
- default_type application/octet-stream;
- server_names_hash_bucket_size 64;
-
- #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
- # '$status $body_bytes_sent "$http_referer" '
- # '"$http_user_agent" "$http_x_forwarded_for"';
-
- #access_log logs/access.log main;
- sendfile on;
- #tcp_nopush on;
-
- #keepalive_timeout 0;
- keepalive_timeout 600;
- proxy_read_timeout 600;
- proxy_send_timeout 600;
-
- proxy_buffer_size 128k;
- proxy_buffers 32 32k;
- proxy_busy_buffers_size 128k;
-
- #gzip on;
-
- ######################################################################
- server {
- listen 80;
- server_name www.neters.club;
-
- #charset koi8-r;
-
- #access_log logs/host.access.log main;
- location / {
- root C:\code\Code\Neters\home;
- index index.html index.htm;
- }
- }
-
- server {
- listen 80;
- server_name neters.club;
-
- #charset koi8-r;
-
- #access_log logs/host.access.log main;
- location / {
- root C:\code\Code\Neters\home;
-
- index index.html index.htm;
- }
- }
-
- server {
- listen 80;
- server_name ids.neters.club;
- rewrite ^(.*)$ https://$host$1 permanent;#把http的域名请求转成https,第二种写法在此节的末端
-
- #charset koi8-r;
-
- #access_log logs/host.access.log main;
- location / {
- #proxy_pass http://localhost:5004;
- root html;
- index index.html index.htm;
- }
- }
-
- server {
- listen 443 ssl;
- server_name ids.neters.club; #网站域名,和80端口保持一致
- ssl on;
- ssl_certificate 1_ids.neters.club_bundle.crt; #证书公钥
- ssl_certificate_key 2_ids.neters.club.key; #证书私钥
- ssl_session_cache shared:SSL:1m;
- ssl_session_timeout 5m;
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
- ssl_ciphers ECDH:AESGCM:HIGH:!RC4:!DH:!MD5:!3DES:!aNULL:!eNULL;
- ssl_prefer_server_ciphers on;
-
- error_page 497 https://$host$uri?$args;
-
- location / {
- proxy_pass http://localhost:5004;
- proxy_redirect off;
- proxy_set_header Host $http_host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
- proxy_set_header Cookie $http_cookie;
- #proxy_cookie_path
- chunked_transfer_encoding off;
- }
- }
-
- server {
- listen 80;
- server_name apk.neters.club;
-
- #charset koi8-r;
-
- #access_log logs/host.access.log main;
- location / {
- root html;
- proxy_pass http://localhost:8081;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection keep-alive;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_cache_bypass $http_upgrade;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
- index index.html index.htm;
- }
-
- location /.doc/ {
- proxy_pass http://docs.neters.club/;
- }
- }
-
- server {
- listen 80;
- server_name docs.neters.club;
-
- location / {
- root C:\code\Code\Blog.Core\.docs\contents\.vuepress\dist;
- index index.html index.htm;
- }
- }
-
- server {
- listen 80;
- server_name vueadmin.neters.club;
-
- location / {
- try_files $uri $uri/ /index.html;
- root C:\code\Code\Blog.Admin\distis;
- #proxy_pass http://localhost:2364;
- index index.html index.htm;
- }
-
- location /api/ {
- rewrite ^.+apb/?(.*)$ /$1 break;
- include uwsgi_params;
- proxy_pass http://localhost:8081;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- #proxy_set_header Connection "upgrade";
- #proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
-
- location /api2/ {
- rewrite ^.+apb/?(.*)$ /$1 break;
- include uwsgi_params;
- proxy_pass http://localhost:8081;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
-
- location /images/ {
- include uwsgi_params;
- proxy_pass http://localhost:8081;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- #proxy_set_header Connection "upgrade";
- #proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
- location /.doc/ {
- proxy_pass http://docsadmin.neters.club/;
- }
-
- error_page 404 /404.html;
-
- # redirect server error pages to the static page /50x.html
- #
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root html;
- }
- }
-
- server {
- listen 80;
- server_name docsadmin.neters.club;
-
- location / {
- root C:\code\Code\Blog.Admin\.doc\contents\.vuepress\dist;
- index index.html index.htm;
- }
- }
-
-
- server {
- listen 80;
- server_name ddd.neters.club;
- location / {
- proxy_pass http://localhost:4773;
- index index.php index.html index.htm;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection keep-alive;
- proxy_set_header Host $host;
- proxy_cache_bypass $http_upgrade;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
-
- }
- }
-
-
- server {
- listen 80;
- server_name ask.neters.club;
-
- #charset koi8-r;
-
- #access_log logs/host.access.log main;
- location / {
- root html;
- proxy_pass http://localhost:5020;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- #proxy_set_header Connection "upgrade";
- #proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- index index.html index.htm;
- }
- }
-
-
- server {
- listen 80;
- server_name vueblog.neters.club;
-
- location / {
- try_files $uri $uri/ /index.html;
- root C:\code\Code\Blog.Vue\dist;
- index index.html index.htm;
- }
-
-
- location /api {
- rewrite ^.+apb/?(.*)$ /$1 break;
- include uwsgi_params;
- proxy_pass http://localhost:8081;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
-
-
- location /images {
- include uwsgi_params;
- proxy_pass http://localhost:8081;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
-
- error_page 404 /404.html;
-
- # redirect server error pages to the static page /50x.html
- #
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root html;
- }
- }
-
- upstream nodenuxt {
- server 127.0.0.1:3089; # nuxt 项目监听PC端端口
- keepalive 64;
- }
- server {
- listen 80;
- server_name tibug.neters.club;
-
- location / {
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "upgrade";
- proxy_set_header Host $host;
- proxy_set_header X-Nginx-Proxy true;
- proxy_cache_bypass $http_upgrade;
- proxy_pass http://nodenuxt;
- }
-
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root html;
- }
- }
-
- server {
- listen 80;
- server_name jwt.neters.club;
-
- location / {
- root C:\code\Code\jwttoken;
- index index.html index.htm;
- }
-
- error_page 404 /404.html;
-
- # redirect server error pages to the static page /50x.html
- #
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root html;
- }
- }
-}
-
-```
-> 这里说明下,我的 `Nginx` 文件中,`Ids4` 项目强制使用 `Https` ,采用的是直接跳转,这也是一个办法,当然还有第二种办法(感谢 `tibos`):
-```
-server {
- listen 80;
- server_name admin.wmowm.com;
- location / {
- proxy_pass http://localhost:9002;
- index index.php index.html index.htm;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection keep-alive;
- proxy_set_header Host $host;
- proxy_cache_bypass $http_upgrade;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
-
- }
-}
-
-server {
- listen 443 ssl;#监听443端口(https默认端口)
- server_name admin.wmowm.com; #填写绑定证书的域名
- ssl_certificate /etc/nginx/conf.d/key/admin.wm.crt;#填写你的证书所在的位置
- ssl_certificate_key /etc/nginx/conf.d/key/admin.wm.key;#填写你的key所在的位置
- ssl_session_timeout 5m;
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置
- ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照这个套件配置
- ssl_prefer_server_ciphers on;
- location / {
- proxy_pass http://localhost:9002;
- index index.php index.html index.htm;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection keep-alive;
- proxy_set_header Host $host;
- proxy_cache_bypass $http_upgrade;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- }
-
-}
-```
\ No newline at end of file
diff --git a/.docs/contents/guide/getting-started.md b/.docs/contents/guide/getting-started.md
deleted file mode 100644
index 0ffdf56a..00000000
--- a/.docs/contents/guide/getting-started.md
+++ /dev/null
@@ -1,117 +0,0 @@
-# K 快速上手
-注意
-
-请确保你的 `Visual Studio 2019` 版本 >= `16.4`。
-
-
-## 下载
-Github(国际) 下载 [https://github.com/anjoy8/Blog.Core](https://github.com/anjoy8/Blog.Core)
-
-Gitee(国内) 下载 [https://gitee.com/laozhangIsPhi/Blog.Core](https://gitee.com/laozhangIsPhi/Blog.Core)
-
-
-## 编译与运行
-1、拿到项目后,双击 `Blog.Core.sln` 解决方案;
-2、首先 `F6` 编译,看是否有错误;
-3、然后 `F5` 运行,调起 `8081` 端口,浏览器查看效果;
-4、因为系统默认的是 `sqlite` 数据库,如果你想换其他数据库,请看下边;
-5、注意:本系统是直接自动生成数据库和数据的,不用手动创建数据库;
-
-
-
-
-## CodeFirst 与 DbFirst
-1、项目同时支持两个常见开发模式:`CodeFirst` 和 `DbFirst`;
-2、首先 如果你是第一次下载我的项目,肯定是想要浏览效果和直接使用对应的权限相关的内容,这个时候肯定需要用到数据库表结构,那就肯定需要 `CodeFirst` ,只需要在`appsettings.json` 里配置好数据库连接字符串(下文会说到如何配置),就能正确运行;
-3、浏览器查看效果,或者配合 `Admin` 项目查看效果后,如果感觉项目可行,并打算在此基础上二次开发,那肯定会在你刚刚创建的数据库种去创建新的表结构,这个时候就需要使用 `DbFirst` 模式,来生成四层项目问题:Model+Service+Repository等;
-4、你可以使用T4模板,但是我更建议使用 `/api/DbFirst/GetFrameFiles` 接口来生成,不仅支持多种类型的数据库,还支持同时多库模式的输出;
-5、如果你不想用我的表结构和实体类,在项目启动的时候,把配置文件的 `SeedDBEnabled`节点设置成False即可,然后配置对应的你自己的数据库连接字符串,比如是商城的,然后使用 `/api/DbFirst/GetFrameFiles` 接口来生成你的数据库四层类文件;
-
-
-
-## 如何配置数据库连接字符串
-
-1、打开 `Blog.Core` 项目下的 `appsettings.json` 文件;
-2、修改 `DBS` 字节内容,配置对应的连接字符串,注意`DBType`对应不同的数据库类型;
-3、把你想要运行的数据库 `Enabled` 为 `true` 即可,其他都要设置 `false`;
-4、然后 `MainDB` 设置为下边你使用的指定 `ConnId`:
-
-```
- "MainDB": "WMBLOG_MSSQL", //当前项目的主库,所对应的连接字符串的Enabled必须为true
- "MutiDBEnabled": false, //是否开启多库
- "DBS": [
- {
- "ConnId": "WMBLOG_SQLITE",
- "DBType": 2,// sqlite数据库
- "Enabled": true,// 设置为true,启用1
- "Connection": "WMBlog.db" //只写数据库名就行
- },
- {
- "ConnId": "WMBLOG_MSSQL",
- "DBType": 1,// sqlserver数据库
- "Enabled": true,// 设置为true,启用2
- "Connection": "Server=.;Database=WMBlogDB;User ID=sa;Password=123;",
- "ProviderName": "System.Data.SqlClient"
- },
- {
- "ConnId": "WMBLOG_MYSQL",
- "DBType": 0,// mysql
- "Enabled": false,// false 不启用
- "Connection": "Server=localhost; Port=3306;Stmt=; Database=wmblogdb; Uid=root; Pwd=456;"
- },
- {
- "ConnId": "WMBLOG_ORACLE",
- "DBType": 3,// Oracle
- "Enabled": false,// 不启用
- "Connection": "Provider=OraOLEDB.Oracle; Data Source=WMBlogDB; User Id=sss; Password=789;"
- }
- ],
-```
-
-
-5、如果你想多库操作,需要配置
-```
- a:MainDB 设置为主库的 ConnId;
- b:MutiDBEnabled设置为true,
- c:把下边想要连接的多个连接字符串都设置为true
-```
-
-## 如何配置项目端口号
-1、在 `Blog.Core` 层下的 `program.cs` 文件中,将 `8081`端口,修改为自己想要的端口号;
-2、或者在 `launchSettings.json` 中设置;
-
-## 如何项目重命名
-1、双击项目根目录下的 `CreateYourProject.bat` 批处理文件;
-2、根据提示,输入自己想要的项目名称即可;
-3、在根目录会有一个 `.1YourProject` 文件夹,里边即你的项目;
-
-
-## 新增实体模块后如何迁移到数据库
-1、在 `Blog.Core.Model` 项目目录下的 `Seed` 文件夹下,找到 `DBSeed` 类;
-2、根据提示,找到生成table的地方 `myContext.CreateTableByEntity`;
-3、添加进去你新增的实体类,当然也可以用下边的单独写法;
-4、编译项目,没错后,运行,则数据库更新完毕;
-
-
-## 新增实体,如何进行增删改查CURD操作
-1、随便找一个含有业务逻辑的 `controller` 参考一下即可;
-2、主要 `api` 是通过 `Service` 服务层提供业务逻辑;
-3、然后服务层通过 `Repository` 仓储层封装持久化操作;
-4、每一个表基本上对应一个仓储类,基本的操作都封装到了 `BaseRepository.cs` 基类仓储中;
-5、添加完业务逻辑,记得要 `F6` 重新编译一下,因为项目间引用解耦了;
-6、项目已经自动注入了,直接在控制器使用对应的服务层接口就行: `IxxxxService` ;
-
-
-## 新增数据库表,如何反向生成四层文件
-1、可以通过 `T4` 模板来生成,在 `Blog.Core.FrameWork` 层,使用方法: [9757999.html](https://www.cnblogs.com/laozhang-is-phi/p/9757999.html#autoid-4-3-0) ;
-> 注意:这种方案,目前默认的只能是 `SqlServer` ,其他类型的数据库,可以看上边文章中的代码,或者群文件里对应的代码。
-
-2、也可以通过 `Sqlsugar` 所带的方法来实现 `DbFirst`,具体查看 `Controller` 层下的 `DbFirstController.cs`;
-
-3、总体操作过程,可以参考我的视频:[av77612407](https://www.bilibili.com/video/av77612407?p=2) ;
-
-
-## 发布与部署
-1、双击项目根目录下的 `Blog.Core.Publish.bat`批处理文件;
-2、执行完成后,根目录会有一个`.PublishFiles` 文件夹,就是发布后的项目;
-
diff --git a/.docs/package.json b/.docs/package.json
deleted file mode 100644
index 3f0483bf..00000000
--- a/.docs/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "BCVP",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "keywords": [],
- "author": "",
- "license": "ISC"
-}
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..dd84ea78
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..bbcbbe7d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 00000000..3df0ef21
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,70 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ master ]
+ schedule:
+ - cron: '32 13 * * 2'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'csharp', 'javascript' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
+ # Learn more about CodeQL language support at https://git.io/codeql-language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v2
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
index b72c6aa6..f11fee1f 100644
--- a/.github/workflows/dotnetcore.yml
+++ b/.github/workflows/dotnetcore.yml
@@ -12,6 +12,12 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 3.1.100
+ dotnet-version: 8.0.x
- name: Build with dotnet
run: dotnet build --configuration Release
+ - name: Build image
+ run: docker build -f "Dockerfile" --force-rm -t laozhangisphi/apkimg .
+ - name: Log into registry
+ run: echo "${{ secrets.ACCESS_TOKEN }}" | docker login -u laozhangisphi --password-stdin
+ - name: Push image
+ run: docker push laozhangisphi/apkimg
diff --git a/.gitignore b/.gitignore
index 9a7ee7a9..99804f89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,9 @@ bld/
# Visual Studio 2017 auto generated files
Generated\ Files/
+# Visual Studio Code
+.vscode
+
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
@@ -351,3 +354,9 @@ Blog.Core/WMBlog.db
.docs/contents/.vuepress/dist/*
Blog.Core/Blog.Core*.xml
Blog.Core.Api/WMBlog.db
+Blog.Core.Api/wwwroot/ui/
+Blog.Core.Api/Logs
+*.db
+/Blog.Core.Api/WMBlog.db-journal
+.docs/.vuepress/dist/
+Blog.Core.Api/wwwroot/Temp/Sessions
diff --git a/.template.config/Blog.Core.Webapi.Template.2.1.0.nupkg b/.template.config/Blog.Core.Webapi.Template.2.5.2.nupkg
similarity index 55%
rename from .template.config/Blog.Core.Webapi.Template.2.1.0.nupkg
rename to .template.config/Blog.Core.Webapi.Template.2.5.2.nupkg
index 758cff1e..1e04c646 100644
Binary files a/.template.config/Blog.Core.Webapi.Template.2.1.0.nupkg and b/.template.config/Blog.Core.Webapi.Template.2.5.2.nupkg differ
diff --git a/Blog.Core.AdminMvc/Blog.Core.AdminMvc.csproj b/Blog.Core.AdminMvc/Blog.Core.AdminMvc.csproj
deleted file mode 100644
index 92605c5a..00000000
--- a/Blog.Core.AdminMvc/Blog.Core.AdminMvc.csproj
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- netcoreapp3.1
-
-
-
diff --git a/Blog.Core.AdminMvc/Program.cs b/Blog.Core.AdminMvc/Program.cs
deleted file mode 100644
index c2d51ead..00000000
--- a/Blog.Core.AdminMvc/Program.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Hosting;
-
-namespace Blog.Core.AdminMvc
-{
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
-
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- });
- }
-}
diff --git a/Blog.Core.AdminMvc/Properties/launchSettings.json b/Blog.Core.AdminMvc/Properties/launchSettings.json
deleted file mode 100644
index e554d003..00000000
--- a/Blog.Core.AdminMvc/Properties/launchSettings.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:51491",
- "sslPort": 0
- }
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "Blog.Core.AdminMvc": {
- "commandName": "Project",
- "launchBrowser": true,
- "applicationUrl": "http://localhost:5000",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- }
- }
-}
diff --git a/Blog.Core.AdminMvc/Startup.cs b/Blog.Core.AdminMvc/Startup.cs
deleted file mode 100644
index 70dbdc7c..00000000
--- a/Blog.Core.AdminMvc/Startup.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-
-namespace Blog.Core.AdminMvc
-{
- public class Startup
- {
- /**
- *┌──────────────────────────────────────────────────────────────┐
- *│ 描 述:当前项目为空,只是模拟一个MVC客户端
- *│ 作 者:anson zhang
- *└──────────────────────────────────────────────────────────────┘
- */
- // This method gets called by the runtime. Use this method to add services to the container.
- // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
- public void ConfigureServices(IServiceCollection services)
- {
- }
-
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseRouting();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapGet("/", async context =>
- {
- await context.Response.WriteAsync("Hello World!");
- });
- });
- }
- }
-}
diff --git a/Blog.Core.AdminMvc/appsettings.json b/Blog.Core.AdminMvc/appsettings.json
deleted file mode 100644
index d9d9a9bf..00000000
--- a/Blog.Core.AdminMvc/appsettings.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
- }
- },
- "AllowedHosts": "*"
-}
diff --git a/Blog.Core.Api/.config/dotnet-tools.json b/Blog.Core.Api/.config/dotnet-tools.json
new file mode 100644
index 00000000..98091c92
--- /dev/null
+++ b/Blog.Core.Api/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-ef": {
+ "version": "6.0.8",
+ "commands": [
+ "dotnet-ef"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Blog.Core.Api.csproj b/Blog.Core.Api/Blog.Core.Api.csproj
index d1541067..8bc327ab 100644
--- a/Blog.Core.Api/Blog.Core.Api.csproj
+++ b/Blog.Core.Api/Blog.Core.Api.csproj
@@ -1,83 +1,122 @@
-
+
+ Exe
+ enable
+
+ Linux
+ true
+ default
+
- Exe
+
+ ..\Blog.Core.Api\Blog.Core.xml
+ 1701;1702;1591
+
- netcoreapp3.1
-
- OutOfProcess
- Linux
-
+
+ ..\Blog.Core\Blog.Core.xml
+ 1701;1702;1591
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- ..\Blog.Core.Api\Blog.Core.xml
- 1701;1702;1591
-
+
+
+
+
+
+
+
+
-
- ..\Blog.Core\Blog.Core.xml
- 1701;1702;1591
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
+ Always
+
+
+ PreserveNewest
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ Always
+
+
+ Always
+
+
-
-
-
+
+
+
-
-
- Always
-
-
+
+
+
+
+
-
-
- Always
-
-
-
-
+
\ No newline at end of file
diff --git a/Blog.Core.Api/Blog.Core.Model.xml b/Blog.Core.Api/Blog.Core.Model.xml
index a4bcc65f..00b4c5be 100644
--- a/Blog.Core.Api/Blog.Core.Model.xml
+++ b/Blog.Core.Api/Blog.Core.Model.xml
@@ -4,6 +4,88 @@
Blog.Core.Model
+
+
+ 无任何权限
+
+
+
+
+ 自定义权限
+
+
+
+
+ 本部门
+
+
+
+
+ 本部门及以下
+
+
+
+
+ 仅自己
+
+
+
+
+ 所有
+
+
+
+
+ 以下model 来自ids4项目,多库模式,为了调取ids4数据
+ 角色表
+
+
+
+
+ 排序
+
+
+
+
+ 是否激活
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+ 以下model 来自ids4项目,多库模式,为了调取ids4数据
+ 用户表
+
+
这是爱
@@ -44,11 +126,95 @@
返回信息
+
+
+ 开发者信息
+
+
返回数据集合
+
+
+ 返回成功
+
+ 消息
+
+
+
+
+ 返回成功
+
+ 消息
+ 数据
+
+
+
+
+ 返回失败
+
+ 消息
+
+
+
+
+ 返回失败
+
+ 消息
+ 数据
+
+
+
+
+ 返回消息
+
+ 失败/成功
+ 消息
+ 数据
+
+
+
+
+ 状态码
+
+
+
+
+ 操作是否成功
+
+
+
+
+ 返回信息
+
+
+
+
+ 返回数据集合
+
+
+
+
+ 用户访问趋势日志
+
+
+
+
+ 用户
+
+
+
+
+ 次数
+
+
+
+
+ 更新时间
+
+
广告图片
@@ -135,95 +301,180 @@
逻辑删除
-
+
- 留言表
+ 评论
-
- 博客ID
-
+
+
+ 博客文章 评论
-
- 创建时间
-
+
+
+ 部门表
-
- 手机
-
+
+
+ Desc:部门关系编码
+ Default:
+ Nullable:True
-
- qq
-
+
+
+ Desc:部门名称
+ Default:
+ Nullable:True
-
- 留言内容
-
+
+
+ Desc:负责人
+ Default:
+ Nullable:True
-
- ip地址
-
+
+
+ Desc:排序
+ Default:
+ Nullable:True
-
- 是否显示在前台,0否1是
-
+
+
+ Desc:部门状态(0正常 1停用)
+ Default:0
+ Nullable:True
-
+
- 菜单与按钮关系表
+ Desc:删除标志(0代表存在 2代表删除)
+ Default:0
+ Nullable:True
-
-
- 获取或设置是否禁用,逻辑上的删除,非物理删除
-
+
+
+ Desc:创建者
+ Default:
+ Nullable:True
+
-
+
- 菜单ID
+ Desc:创建时间
+ Default:
+ Nullable:True
-
+
- 按钮ID
+ Desc:更新者
+ Default:
+ Nullable:True
-
+
- 创建ID
+ Desc:更新时间
+ Default:
+ Nullable:True
-
+
- 创建者
+ 用户团队表
-
+
- 创建时间
+ ID
-
+
- 修改ID
+ HttpContext.TraceIdentifier 事件链路ID(获取或设置一个唯一标识符,用于在跟踪日志中表示此请求。)
-
+
- 修改者
+ 时间
-
-
- 修改时间
-
+
+
+ 线程
+
+
+
+
+ 等级
+
+
+
+
+ 记录器
+
+
+
+
+ 日志类型
+
+
+
+
+ 数据类型
+
+
+
+
+ 错误信息
+
+
+
+
+ 异常
+
+
+
+ 博客ID
+
+
+
+
+ 创建时间
+
+
+
+
+ 手机
+
+
+
+
+ qq
+
+
+
+
+ 留言内容
+
+
+
+
+ ip地址
+
+
+
+
+ 是否显示在前台,0否1是
+
+
@@ -235,11 +486,6 @@
获取或设置是否禁用,逻辑上的删除,非物理删除
-
-
- 父ID
-
-
名称
@@ -420,16 +666,6 @@
按钮事件
-
-
- 上一级菜单(0表示上一级无菜单)
-
-
-
-
- 接口api
-
-
排序
@@ -440,6 +676,11 @@
菜单图标
+
+
+ 菜单图标新
+
+
菜单描述
@@ -510,6 +751,17 @@
排序
+
+
+ 自定义权限的部门ids
+
+
+
+
+ 权限范围
+ -1 无任何权限;1 自定义权限;2 本部门;3 本部门及以下;4 仅自己;9 全部;
+
+
是否激活
@@ -555,21 +807,6 @@
获取或设置是否禁用,逻辑上的删除,非物理删除
-
-
- 角色ID
-
-
-
-
- 菜单ID
-
-
-
-
- api ID
-
-
创建ID
@@ -600,766 +837,2570 @@
修改时间
-
+
- 用户信息表
+ 状态
+ 中立字段,某些表可使用某些表不使用
-
+
- 用户ID
+ 中立字段,某些表可使用某些表不使用
+ 逻辑上的删除,非物理删除
+ 例如:单据删除并非直接删除
-
+
- 登录账号
+ 中立字段
+ 是否内置数据
-
+
- 登录密码
+ 创建ID
-
+
- 真实姓名
+ 创建者
-
+
- 状态
+ 创建时间
-
+
- 备注
+ 修改ID
-
+
- 创建时间
+ 更新者
-
+
- 更新时间
+ 修改日期
-
-
- 最后登录时间
-
-
-
+
+
+ 数据版本
+
+
+
+
+ 软删除 过滤器
+
+
+
+
+ 系统租户表
+ 根据TenantType 分为两种方案:
+ 1.按租户字段区分
+ 2.按租户分库
+
+
+
+ 注意:
+ 使用租户Id方案,无需配置分库的连接
+
+
+
+
+ 名称
+
+
+
+
+ 租户类型
+
+
+
+
+ 数据库/租户标识 不可重复
+ 使用Id方案,可无需配置
+
+
+
+
+ 主机
+ 使用Id方案,可无需配置
+
+
+
+
+ 数据库类型
+ 使用Id方案,可无需配置
+
+
+
+
+ 数据库连接
+ 使用Id方案,可无需配置
+
+
+
+
+ 状态
+
+
+
+
+ 备注
+
+
+
+
+ 用户信息表
+
+
+
+
+ 登录账号
+
+
+
+
+ 登录密码
+
+
+
+
+ 真实姓名
+
+
+
+
+ 状态
+
+
+
+
+ 部门
+
+
+
+
+ 备注
+
+
+
+
+ 创建时间
+
+
+
+
+ 更新时间
+
+
+
+
+ 关键业务修改时间
+
+
+
+
+ 最后异常时间
+
+
+
错误次数
-
+
+
+ 登录账号
+
+
+
+
+ 租户Id
+
+
+
+
+ 任务日志表
+
+
+
+
+ 任务ID
+
+
+
+
+ 任务耗时
+
+
+
+
+ 执行结果(0-失败 1-成功)
+
+
+
+
+ 运行时间
+
+
+
+
+ 结束时间
+
+
+
+
+ 执行参数
+
+
+
+
+ 异常信息
+
+
+
+
+ 异常堆栈
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+ 任务名称
+
+
+
+
+ 任务分组
+
+
+
+
+ 任务计划表
+
+
+
+
+ 任务名称
+
+
+
+
+ 任务分组
+
+
+
+
+ 任务运行时间表达式
+
+
+
+
+ 任务所在DLL对应的程序集名称
+
+
+
+
+ 任务所在类
+
+
+
+
+ 任务描述
+
+
+
+
+ 执行次数
+
+
+
+
+ 开始时间
+
+
+
+
+ 结束时间
+
+
+
+
+ 触发器类型(0、simple 1、cron)
+
+
+
+
+ 执行间隔时间, 秒为单位
+
+
+
+
+ 循环执行次数
+
+
+
+
+ 已循环次数
+
+
+
+
+ 是否启动
+
+
+
+
+ 执行传参
+
+
+
+
+ 创建时间
+
+
+
+
+ 任务内存中的状态
+
+
+
+
+ 业务数据
+ 多租户 (Id 隔离)
+
+
+
+
+ 无需手动赋值
+
+
+
+
+ 名称
+
+
+
+
+ 金额
+
+
+
+
+ 多租户-多表方案 业务表 子表
+
+
+
+
+ 多租户-多表方案 业务表
+
+
+
+
+ 名称
+
+
+
+
+ 金额
+
+
+
+
+ 多租户-多库方案 业务表
+ 公共库无需标记[MultiTenant]特性
+
+
+
+
+ 名称
+
+
+
+
+ 金额
+
+
+
+
+ Tibug 类别
+
+
+
+
+ Tibug 博文
+
+
+
+
+ 用户跟角色关联表
+
+
+
+
+ 获取或设置是否禁用,逻辑上的删除,非物理删除
+
+
+
+
+ 创建ID
+
+
+
+
+ 创建者
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改ID
+
+
+
+
+ 修改者
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 公司ID
+
+
+
+
+ 公司名称
+
+
+
+
+ 公司IP
+
+
+
+
+ 公司备注
+
+
+
+
+ api地址
+
+
+
+
+ 是否激活
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 微信公众号唯一标识
+
+
+
+
+ 微信公众号名称
+
+
+
+
+ 微信账号
+
+
+
+
+ 微信名称
+
+
+
+
+ 应用ID
+
+
+
+
+ 应用秘钥
+
+
+
+
+ 公众号推送token
+
+
+
+
+ 验证秘钥(验证消息是否真实)
+
+
+
+
+ 微信公众号token过期时间
+
+
+
+
+ 备注
+
+
+
+
+ 是否激活
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 推送ID
+
+
+
+
+ 来自谁
+
+
+
+
+ 推送IP
+
+
+
+
+ 推送客户
+
+
+
+
+ 推送用户
+
+
+
+
+ 推送模板ID
+
+
+
+
+ 推送内容
+
+
+
+
+ 推送时间
+
+
+
+
+ 推送状态(Y/N)
+
+
+
+
+ 备注
+
+
+
+
+ 推送OpenID
+
+
+
+
+ 推送微信公众号
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 主键id,ticket
+
+
+
+
+ 需要绑定的公司
+
+
+
+
+ 需要绑定的员工id
+
+
+
+
+ 需要绑定的员工昵称
+
+
+
+
+ 创建时间
+
+
+
+
+ 关联的公众号
+
+
+
+
+ 是否已使用
+
+
+
+
+ 使用时间
+
+
+
+
+ 关联的微信用户id
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 来自哪个公众号
+
+
+
+
+ 绑定公司id
+
+
+
+
+ 绑定员工id
+
+
+
+
+ 绑定微信id
+
+
+
+
+ 绑定微信联合id
+
+
+
+
+ 绑定时间
+
+
+
+
+ 更新时间
+
+
+
+
+ 备注
+
+
+
+
+ 是否已解绑
+
+
+
+
+ 上次绑定微信id
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+
+
+
+
+
+ 文件ID
+
+
+
+
+ 文件名称
+
+
+
+
+ 文件大小
+
+
+
+
+ 文件类型
+
+
+
+
+ 文件拓展名
+
+
+
+
+ 文件位置
+
+
+
+
+ 文件上传时间
+
+
+
+
+ 文件备注
+
+
+
+
+ 创建者id
+
+
+
+
+ 创建人
+
+
+
+
+ 创建时间
+
+
+
+
+ 修改者id
+
+
+
+
+ 修改人
+
+
+
+
+ 修改时间
+
+
+
+
+ 部门表
+
+
+
+
+ 上一级(0表示无上一级)
+
+
+
+
+ 接口API地址信息表
+ 父类
+
+
+
+
+ 父ID
+
+
+
+
+ 路由菜单表
+
+
+
+
+ 上一级菜单(0表示上一级无菜单)
+
+
+
+
+ 接口api
+
+
+
+
+ 按钮跟权限关联表
+ 父类
+
+
+
+
+ 角色ID
+
+
+
+
+ 菜单ID
+
+
+
+
+ api ID
+
+
+
+
+ ID
+ 泛型主键Tkey
+
+
+
+
+ 用户信息表
+
+
+
+
+ Id
+ 泛型主键Tkey
+
+
+
+
+ Tibug 博文
+
+
+
+
+ 用户跟角色关联表
+ 父类
+
+
+
+
+ 用户ID
+
+
+
+
+ 角色ID
+
+
+
+
+ 通用分页信息类
+
+
+
+
+ 当前页标
+
+
+
+
+ 总页数
+
+
+
+
+ 数据总数
+
+
+
+
+ 每页大小
+
+
+
+
+ 返回数据
+
+
+
+
+ 所需分页参数
+ 作者:胡丁文
+ 时间:2020-4-3 20:31:26
+
+
+
+
+ 当前页
+
+
+
+
+ 每页大小
+
+
+
+
+ 排序字段(例如:id desc,time asc)
+
+
+
+
+ 查询条件( 例如:id = 1 and name = 小明)
+
+
+
+
+ 无权限
+
+
+
+
+ 找不到指定资源
+
+
+
+
+ 找不到指定资源
+
+
+
+
+ 数据库读取类型
+
+
+
+
+ 表格数据,支持分页
+
+
+
+
+ 返回编码
+
+
+
+
+ 返回信息
+
+
+
+
+ 记录总数
+
+
+
+
+ 返回数据集
+
+
+
+
+ 租户模型接口
+
+
+
+
+ 租户Id
+
+
+
+
+ 标识 多租户 的业务表
+ 默认设置是多库
+ 公共表无需区分 直接使用主库 各自业务在各自库中
+
+
+
+
+ 租户隔离方案
+
+
+
+
+ Id隔离
+
+
+
+
+ 库隔离
+
+
+
+
+ 表隔离
+
+
+
+
+ 广告类
+
+
+
+
+ 分类ID
+
+
+
+
+ 创建时间
+
+
+
+
+ 广告图片
+
+
+
+
+ 广告标题
+
+
+
+
+ 广告链接
+
+
+
+
+ 备注
+
+
+
+
+ 博客信息展示类
+
+
+
+
+
+
+
+
+ 创建人
+
+
+
+
+ 博客标题
+
+
+
+
+ 摘要
+
+
+
+
+
+ 上一篇
+
+
+
+
+ 上一篇id
+
+
+
+
+ 下一篇
+
+
+
+
+ 下一篇id
+
+
+
+ 类别
+
+
+
+
+ 内容
+
+
+
+
+
+ 访问量
+
+
+
+
+ 评论数量
+
+
+
+ 修改时间
+
+
+
+
+
+ 创建时间
+
+
+
+ 备注
+
+
+
+
+
+ Type Description balabala
+
+
+
+
+ 留言信息展示类
+
+
+
+ 留言表
+
+
+
+
+ 博客ID
+
+
+
+
+ 创建时间
+
+
+
+
+ 手机
+
+
+
+
+ qq
+
+
+
+
+ 留言内容
+
+
+
+
+ ip地址
+
+
+
+
+ 是否显示在前台,0否1是
+
+
+
+
+
+ 商户号
+
+
+
+
+ 柜台号
+
+
+
+
+ 分行号
+
+
+
+
+ 集团商户信息
+
+
+
+
+ 交易码
+
+
+
+
+ 商户类型
+
+
+
+
+ 终端编号 1
+
+
+
+
+ 终端编号 2
+
+
+
+
+ 订单号
+
+
+
+
+ 码信息(一维码、二维码)
+
+
+
+
+ 订单金额,单位:元
+
+
+
+
+ 商品名称
+
+
+
+
+ 备注 1
+
+
+
+
+ 备注 2
+
+
+
+
+ 分账信息一
+
+
+
+
+ 分账信息二
+
+
+
+
+ 子商户公众账号 ID
+
+
+
+
+ 返回信息位图
+
+
+
+
+ 实名支付
+
+
+
+
+ 商品详情
+
+
+
+
+ 订单优惠标记
+
+
+
+
+ 公钥
+
+
+
+
+ 请求地址
+
+
+
+
+ 是否删除空值
+
+
+
+
+ 退款参数
+
+
+
+
+ 订单ID
+
+
+
+
+ 商品名称
+
+
+
+
+ 支付金额(小数点最多两位)
+
+
+
+
+ 二维码/条码信息
+
+
+
+
+ 备注信息1
+
+
+
+
+ 备注信息2
+
+
+
+
+ 订单参数
+
+
+
+
+ 订单号
+
+
+
+
+ 退款金额
+
+
+
+
+ 退款流水号(可选)
+
+
+
+
+ 退款返回消息
+
+
+
+
+ 序列号
+
+
+
+
+ 商户号
+
+
+
+
+ 交易码
+
+
+
+
+ 返回码
+
+
+
+
+ 返回码说明
+
+
+
+
+ 语言
+
+
+
+
+ 订单信息
+
+
+
+
+ 订单信息
+
+
+
+
+ 订单号
+
+
+
+
+ 支付金额
+
+
+
+
+ 退款金额
+
+
+
+
+ 备注1
+
+
+
+
+ 备注2
+
+
+
+
+ 退款返回结果消息
+
+
+
+
+ 订单号
+
+
+
+
+ 支付金额
+
+
+
+
+ 退款金额
+
+
+
+
+ 序列号
+
+
+
+
+ 商户号
+
+
+
+
+ 交易码
+
+
+
+
+ 返回码
+
+
+
+
+ 返回码说明
+
+
+
+
+ 语言
+
+
+
+
+ 支付结果dto
+
+
+
+
+ 支付结果
+ Y:成功
+ N:失败
+ U:不确定
+ Q:待轮询
+
+
+
+
+ 订单ID
+
+
+
+
+ 支付金额
+
+
+
+
+ 二维码类型
+ 1:龙支付
+ 2:微信
+ 3:支付宝
+ 4:银联
+
+
+
+
+ 等待时间-轮询等待时间
+
+
+
+
+ 全局事件跟踪号-建行交易流水号
+
+
+
+
+ 错误码
+
+
+
+
+ 错误信息
+
+
+
+
+ 验证签名-防止伪造攻击
+
+
+
+
+ 返回支付结果
+
+
+
+
+ 发起的订单ID
+
+
+
+
+ 返回支付的金额
+
+
+
+
+ 返回支付的类型 1:龙支付 2:微信 3:支付宝 4:银联
+
+
+
+
+ 返回建行的流水号
+
+
+
+
+ 错误代码
+
+
+
+
+ 错误信息
+
+
+
+
+ 实现IJob的类
+
+
+
+
+ 命名空间
+
+
+
+
+ 类名
+
+
+
+
+ 备注
+
+
+
+
+ 服务器VM
+
+
+
+
+ 环境变量
+
+
+
+
+ 系统架构
+
+
+
+
+ ContentRootPath
+
+
+
+
+ WebRootPath
+
+
+
+
+ .NET Core版本
+
+
+
+
+ 内存占用
+
+
+
+
+ 启动时间
+
+
+
+
+ 菜单展示model
+
+
+
+
+ 调度任务触发器信息实体
+
+
+
+
+ 任务ID
+
+
+
+
+ 任务名称
+
+
+
+
+ 任务分组
+
+
+
+
+ 触发器ID
+
+
+
+
+ 触发器名称
+
+
+
+
+ 触发器分组
+
+
+
+
+ 触发器状态
+
+
+
+
+ 用来测试 RestSharp Get 请求
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 用来测试 RestSharp Post 请求
+
+
+
+
+ 留言排名展示类
+
+
+
+ 博客ID
+
+
+
+
+
+ 评论数量
+
+
+
+ 博客标题
+
+
+
+
- 登录账号
+ 微信接口消息DTO
+ 作者:胡丁文
+ 时间:2020-03-25
-
+
- 任务计划表
+ 微信公众号ID(数据库查询)
-
+
- 任务名称
+ 错误代码
-
+
- 任务分组
+ 错误信息
-
+
- 任务运行时间表达式
+ token
-
+
- 任务所在DLL对应的程序集名称
+ 过期时间(秒)
-
+
- 任务所在类
+ 用户关注数
-
+
- 任务描述
+ 获取用户数量
-
+
- 执行次数
+ 获取用户OpenIDs
-
+
- 开始时间
+ 下一个关注用户
-
+
- 结束时间
+ 微信消息模板列表
-
+
- 触发器类型(0、simple 1、cron)
+ 微信菜单
-
+
- 执行间隔时间, 秒为单位
+ 二维码票据
-
+
- 是否启动
+ 二维码过期时间
-
+
- 执行传参
+ 二维码地址
-
+
- 创建时间
+ 关注状态
+
+
+
+
+ 用户微信ID
-
+
- Tibug 类别
+ 昵称
-
+
- Tibug 博文
+ 性别
-
+
- 用户跟角色关联表
+ 语言
-
-
- 获取或设置是否禁用,逻辑上的删除,非物理删除
-
+
+
+ 城市
+
-
+
- 用户ID
+ 省份
-
+
- 角色ID
+ 城市
-
+
- 创建ID
+ 头像地址
-
+
- 创建者
+ 微信推送消息Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:16:16
-
+
- 创建时间
+ 推送关键信息
-
+
- 修改ID
+ 推送卡片消息Dto
-
+
- 修改者
+ 微信推送消息Dto
+ 作者:胡丁文
+ 时间:2020-11-23 16:29:05
-
+
- 修改时间
+ 推送关键信息
-
+
- ID
+ 推送卡片消息Dto
-
+
- 通用分页信息类
+ 消息模板dto(如何填写数据,请参考微信模板即可)
+ 作者:胡丁文
+ 时间:2020-4-1 09:32:16
-
+
- 当前页标
+ 消息模板
-
+
- 总页数
+ 标题
-
+
- 数据总数
+ 标题颜色(颜色代码都必须为#开头的16进制代码)
-
+
- 每页大小
+ 内容1
-
+
- 返回数据
+ 内容1颜色
-
+
- 无权限
+ 内容2
-
+
- 找不到指定资源
+ 内容2颜色
-
+
- 找不到指定资源
+ 内容3
-
+
- 异步添加种子数据
+ 内容3颜色
-
-
-
-
+
- 生成Model层
+ 内容4
- sqlsugar实例
- 数据库链接ID
- 数据库表名数组,默认空,生成所有表
-
-
-
+
- 生成IRepository层
+ 内容4颜色
- sqlsugar实例
- 数据库链接ID
-
- 数据库表名数组,默认空,生成所有表
-
-
+
- 生成 IService 层
+ 内容5
- sqlsugar实例
- 数据库链接ID
-
- 数据库表名数组,默认空,生成所有表
-
-
+
- 生成 Repository 层
+ 内容5颜色
- sqlsugar实例
- 数据库链接ID
-
- 数据库表名数组,默认空,生成所有表
-
-
+
- 生成 Service 层
+ 备注信息
- sqlsugar实例
- 数据库链接ID
-
- 数据库表名数组,默认空,生成所有表
-
-
+
- 功能描述:根据数据库表生产Model层
- 作 者:Blog.Core
+ 备注信息颜色
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
- 是否序列化
-
+
- 功能描述:根据数据库表生产IRepository层
- 作 者:Blog.Core
+ 跳转连接
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
-
+
- 功能描述:根据数据库表生产IServices层
- 作 者:Blog.Core
+ 获取微信菜单DTO,用于存放具体菜单内容
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
-
+
- 功能描述:根据数据库表生产 Repository 层
- 作 者:Blog.Core
+ 获取微信菜单DTO
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
-
+
- 功能描述:根据数据库表生产 Services 层
- 作 者:Blog.Core
+ 按钮列表(最多三个)
-
- 数据库链接ID
- 实体类存放路径
- 命名空间
- 生产指定的表
- 实现接口
-
-
+
- 根据模板内容批量生成文件
+ 微信OpenID列表Dto
- 类文件字符串list
- 生成路径
- 文件名格式模板
-
+
- 连接字符串
- Blog.Core
+ 推送详细数据
+ 作者:胡丁文
+ 时间:2020-4-8 09:16:16
-
+
- 连接字符串
- Blog.Core
+ 推送给微信所需Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:16:16
-
+
- 数据库类型
- Blog.Core
+ 推送微信用户ID
-
+
- 数据连接对象
- Blog.Core
+ 推送的模板ID
-
+
- 数据库上下文实例(自动关闭连接)
- Blog.Core
+ 推送URL地址
-
+
- 功能描述:构造函数
- 作 者:Blog.Core
+ 推送的数据
-
+
- 功能描述:获取数据库处理对象
- 作 者:Blog.Core
+ 微信keyword所需Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:18:08
- 返回值
-
+
- 功能描述:获取数据库处理对象
- 作 者:Blog.Core
+ 内容
- db
- 返回值
-
+
- 功能描述:根据实体类生成数据库表
- 作 者:Blog.Core
+ 文字颜色
- 是否备份表
- 指定的实体
-
+
- 功能描述:根据实体类生成数据库表
- 作 者:Blog.Core
+ 图文链接标题
- 是否备份表
- 指定的实体
-
+
- 功能描述:获得一个DbContext
- 作 者:Blog.Core
+ 图文描述
-
-
+
- 功能描述:设置初始化参数
- 作 者:Blog.Core
+ 访问URL
- 连接字符串
- 数据库类型
-
+
- 功能描述:创建一个链接配置
- 作 者:Blog.Core
+ 图片URL
- 是否自动关闭连接
- 是否夸类事务
- ConnectionConfig
-
+
- 功能描述:获取一个自定义的DB
- 作 者:Blog.Core
+ 图片mediaID
- config
- 返回值
-
+
- 功能描述:获取一个自定义的数据库处理对象
- 作 者:Blog.Core
+ 推送模拟消息Dto
+ 作者:胡丁文
+ 时间:2020-4-24 14:52:44
- sugarClient
- 返回值
-
+
- 功能描述:获取一个自定义的数据库处理对象
- 作 者:Blog.Core
+ 当前选中的微信公众号
- config
- 返回值
-
+
- 表格数据,支持分页
+ 当前选中的操作集合
-
+
- 返回编码
+ 当前选中的绑定还是订阅
-
+
- 返回信息
+ 当前选中的微信客户
-
+
- 记录总数
+ 当前选中的消息类型
-
+
- 返回数据集
+ 当前选中要发送的用户
-
+
- 广告类
+ 文本消息
-
+
- 分类ID
+ 图片消息
-
+
- 创建时间
+ 语音消息
-
+
- 广告图片
+ 视频消息
-
+
- 广告标题
+ 链接消息
-
+
- 广告链接
+ 文字消息
-
+
- 备注
+ 视频标题
-
+
- 博客信息展示类
+ 视频封面mediaID
-
+
-
+ 视频mediaID
-
- 创建人
-
+
+
+ 语音mediaID
-
- 博客标题
-
+
+
+ 微信二维码预装发送信息dto
-
- 摘要
-
+
+
+ 微信二维码预装具体消息
-
+
- 上一篇
+ 微信二维码预装信息DTO
-
+
- 上一篇id
+ 返回给调用者的Dto
+ 作者:胡丁文
+ 时间:2020-4-8 09:52:06
-
+
- 下一篇
+ 微信公众号ID
-
+
- 下一篇id
+ 公司代码
-
- 类别
-
+
+
+ 数据
-
- 内容
-
+
+
+ 微信消息模板Dto
-
+
- 访问量
+ 微信推送所需信息(公司版本)
+ 作者:胡丁文
+ 时间:2020-4-8 09:04:36
-
+
- 评论数量
+ 微信公众号ID
-
- 修改时间
-
+
+
+ 公司代码
-
+
- 创建时间
+ 用户id
-
- 备注
-
+
+
+ 用户昵称
-
+
- 留言信息展示类
+ 微信推送所需信息(OpenID版本)
+ 作者:胡丁文
+ 时间:2020-11-23 16:27:29
-
- 留言表
-
+
+
+ 微信公众号ID
-
- 博客ID
-
+
+
+ 微信OpenID
-
- 创建时间
-
+
+
+ 微信验证Dto
+ 作者:胡丁文
+ 时间:2020-4-1 21:34:07
+
+
+
+
+ 微信公众号唯一标识
-
- 手机
-
+
+
+ 验证成功后返回给微信的字符串
-
- qq
-
+
+
+ 签名
-
- 留言内容
-
+
+
+ 时间戳
-
- ip地址
-
+
+
+ 随机数
-
- 是否显示在前台,0否1是
-
+
+
+ 微信XmlDto
+ 作者:胡丁文
+ 时间:2020-4-3 20:31:26
+
+
+
+
+ 微信公众号唯一表示
-
+
- 服务器VM
+ 微信开发者
+
+
+
+
+ 来自谁
+
+
+
+
+ 创建时间
-
+
- 环境变量
+ 消息类型
+
+
+
+
+ 文字内容
+
+
+
+
+ 消息ID
-
+
- 系统架构
+ 消息事件
+
+
+
+
+ 事件key值
+
+
+
+
+ 图片地址
-
+
- ContentRootPath
+ 多媒体ID
-
+
- WebRootPath
+ 格式
-
+
- .NET Core版本
+ 语音失败
-
+
- 内存占用
+ 缩略媒体ID
-
+
- 启动时间
+ 地理位置维度
-
+
- 菜单展示model
+ 地理位置经度
-
+
- 用来测试 RestSharp Get 请求
+ 地图缩放大小
-
+
-
+ 地理位置信息
-
+
-
+ 消息标题
-
+
- 用来测试 RestSharp Post 请求
+ 消息描述
-
+
- 留言排名展示类
+ 消息链接
-
- 博客ID
-
+
+
+ 二维码的ticket,可用来换取二维码图片
-
+
- 评论数量
+ 地理位置纬度
-
- 博客标题
-
+
+
+ 地理位置经度
+
+
+
+
+ 地理位置精度
diff --git a/Blog.Core.Api/Blog.Core.xml b/Blog.Core.Api/Blog.Core.xml
index d3c21686..0ed61c91 100644
--- a/Blog.Core.Api/Blog.Core.xml
+++ b/Blog.Core.Api/Blog.Core.xml
@@ -9,12 +9,12 @@
博客管理
-
+
构造函数
-
+
@@ -26,14 +26,14 @@
-
+
获取博客详情
-
+
获取详情【无权限】
@@ -67,7 +67,7 @@
-
+
删除博客
@@ -88,29 +88,58 @@
- 获取 整体框架 文件
+ 获取 整体框架 文件(主库)(一般可用第一次生成)
- 根据数据库表名 生成整体框架
- 仅针对通过CodeFirst生成表的情况
+ 获取仓储层和服务层(需指定表名和数据库)
+
+ 数据库链接名称
+ 需要生成的表名
+
+
+
+
+ 获取实体(需指定表名和数据库)
+
+ 数据库链接名称
+ 需要生成的表名
+
+
+
+
+ 获取控制器(需指定表名和数据库)
+
+ 数据库链接名称
+ 需要生成的表名
+
+
+
+
+ DbFrist 根据数据库表名 生成整体框架,包含Model层(一般可用第一次生成)
数据库链接名称
需要生成的表名
-
+
+
+ 获取权限部分Map数据(从库)
+ 迁移到新库(主库)
+
+
+
+
- 获取权限部分Map数据
- 生成到tsb文件
+ 权限数据库导出tsv
-
+
- 保存数据到数据库
+ 权限数据库导出excel
@@ -130,19 +159,17 @@
图片管理
-
+
下载图片(支持中文字符)
-
-
+
- 上传图片,多文件,可以使用 postman 测试,
- 如果是单文件,可以 参数写 IFormFile file1
+ 上传图片,多文件
-
+
@@ -150,7 +177,7 @@
登录管理【无权限】
-
+
构造函数注入
@@ -159,6 +186,7 @@
+
@@ -209,12 +237,25 @@
+
+
+ swagger登录
+
+
+
+
+
+
+ weixin登录
+
+
+
接口管理
-
+
获取全部接口api
@@ -236,13 +277,20 @@
-
+
删除一条接口
+
+
+ 导入多条接口信息
+
+
+
+
服务器配置信息
@@ -255,12 +303,66 @@
+
+
+ 建行聚合支付类
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+ 被扫支付
+
+
+
+
+
+
+ 被扫支付
+
+
+
+
+
+
+ 支付结果查询-轮询
+
+
+
+
+
+
+ 支付结果查询-轮询
+
+
+
+
+
+
+ 退款
+
+
+
+
+
+
+ 退款
+
+
+
+
菜单管理
-
+
构造函数
@@ -268,19 +370,22 @@
+
+
-
+
获取菜单
+
-
+
查询树形 Table
@@ -302,7 +407,7 @@
-
+
获取菜单树
@@ -310,16 +415,23 @@
-
+
+
+ 获取路由树
+
+
+
+
+
获取路由树
-
+
- 通过角色获取菜单【无权限】
+ 通过角色获取菜单
@@ -331,13 +443,26 @@
-
+
删除菜单
+
+
+ 导入多条菜单信息
+
+
+
+
+
+
+ 系统接口菜单同步接口
+
+
+
角色管理
@@ -365,7 +490,7 @@
-
+
删除角色
@@ -394,27 +519,73 @@
-
+
+
+ 删除一个任务
+
+
+
+
+
启动计划任务
-
+
停止一个计划任务
-
+
+
+ 暂停一个计划任务
+
+
+
+
+
+
+ 恢复一个计划任务
+
+
+
+
+
重启一个计划任务
+
+
+ 获取任务命名空间
+
+
+
+
+
+ 立即执行任务
+
+
+
+
+
+
+ 获取任务运行日志
+
+
+
+
+
+ 任务概况
+
+
+
类别管理【无权限】
@@ -455,7 +626,7 @@
-
+
获取详情【无权限】
@@ -476,27 +647,36 @@
-
+
删除 bug
+
+
+ 测试事务在AOP中的使用
+
+
+
+
用户管理
-
+
构造函数
-
+
+
+
@@ -515,21 +695,21 @@
令牌
-
+
添加一个用户
-
+
更新用户与角色
-
+
删除用户
@@ -541,12 +721,13 @@
用户角色关系
-
+
构造函数
+
@@ -564,7 +745,7 @@
-
+
新建用户角色关系
@@ -577,19 +758,23 @@
Values控制器
-
+
- ValuesController
+ 测试Rabbit消息队列发送
-
-
-
-
-
-
-
-
-
+
+
+
+ 测试Rabbit消息队列订阅
+
+
+
+
+ 测试SqlSugar二级缓存
+ 可设置过期时间
+ 或通过接口方式更新该数据,也会离开清除缓存
+
+
@@ -597,6 +782,21 @@
+
+
+ 测试Redis消息队列
+
+
+
+
+
+
+ 测试RabbitMQ事件总线
+
+
+
+
+
Get(int id)方法
@@ -643,28 +843,17 @@
-
-
- 测试http请求 RestSharp Get
-
-
-
-
-
- 测试http请求 RestSharp Post
-
-
-
测试多库连接
-
+
- 测试http请求 WebApiClient Get
+ 测试Fulent做参数校验
+
@@ -680,69 +869,794 @@
-
+
- 自定义路由 /api/{version}/[controler]/[action]
+ 测试接入Apollo获取配置信息
-
+
- 分组名称,是来实现接口 IApiDescriptionGroupNameProvider
+ 通过此处的key格式为 xx:xx:x
-
+
- 自定义路由构造函数,继承基类路由
+ 获取雪花Id
-
+
-
+
- 自定义版本+路由构造函数,继承基类路由
+ 测试缓存
-
-
+
-
+
- Summary:全局路由权限公约
- Remarks:目的是针对不同的路由,采用不同的授权过滤器
- 如果 controller 上不加 [Authorize] 特性,默认都是 Permission 策略
- 否则,如果想特例其他授权机制的话,需要在 controller 上带上 [Authorize],然后再action上自定义授权即可,比如 [Authorize(Roles = "Admin")]
+ 雪花Id To DateTime
+
+
-
+
- 全局权限过滤器【无效】
+ WeChatCompanyController
-
+
- 全局异常错误日志
+ 构造函数
+
+
+
+
+
+ 获取
+ 分页条件
+
-
+
- 自定义返回格式
+ 获取(id)
-
-
+ 主键ID
-
+
- 生产环境的消息
+ 添加
+
-
+
- 开发环境的消息
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
-
+
- 全局路由前缀公约
+ WeChatConfigController
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ 微信公众号管理
+
+
+
+
+ 构造函数
+
+
+
+
+
+
+ 更新Token
+
+
+
+
+
+
+ 刷新Token
+
+
+
+
+
+
+ 获取模板
+
+
+
+
+
+
+ 获取菜单
+
+
+
+
+
+
+ 更新菜单
+
+
+
+
+
+
+ 获取订阅用户(所有)
+
+
+
+
+
+
+ 入口
+
+
+
+
+
+
+ 获取订阅用户
+
+
+
+
+
+
+
+ 获取一个绑定员工公众号二维码
+
+ 消息
+
+
+
+
+ 推送卡片消息接口
+
+ 卡片消息对象
+
+
+
+
+ 推送卡片消息接口
+
+ 卡片消息对象
+
+
+
+
+ 推送文本消息
+
+ 消息对象
+
+
+
+
+ 通过绑定用户获取微信用户信息(一般用于初次绑定检测)
+
+ 信息
+
+
+
+
+ 用户解绑
+
+ 消息
+
+
+
+
+ WeChatPushLogController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ WeChatSubController
+
+
+
+
+ 构造函数
+
+
+
+
+
+ 获取
+
+ 分页条件
+
+
+
+
+ 获取(id)
+
+ 主键ID
+
+
+
+
+ 添加
+
+
+
+
+
+ 更新
+
+
+
+
+
+ 删除
+
+
+
+
+
+ 批量删除
+
+
+
+
+
+ 查询树形 Table
+
+ 父节点
+ 关键字
+
+
+
+
+ 获取部门树
+
+
+
+
+
+
+ 服务管理
+
+
+
+
+ INacosNamingService
+
+
+
+
+
+
+
+
+
+
+ 系统实例是否启动完成
+
+
+
+
+
+ 获取Nacos 状态
+
+
+
+
+
+ 服务上线
+
+
+
+
+
+ 服务下线
+
+
+
+
+
+ SignalR测试
+
+
+
+
+ 向指定用户发送消息
+
+
+
+
+
+
+
+ 向指定角色发送消息
+
+
+
+
+
+
+
+ 分表demo
+
+
+
+
+ 分页获取数据
+
+
+
+
+
+
+
+
+
+
+ 根据ID获取信息
+
+
+
+
+
+
+ 添加一条测试数据
+
+
+
+
+
+
+ 修改一条测试数据
+
+
+
+
+
+
+ 根据id删除数据
+
+
+
+
+
+
+ SqlSugar 相关测试
+
+
+
+
+ SqlSugar 相关测试
+
+
+
+
+ 测试建表后,SqlSugar缓存
+
+
+
+
+
+ 缓存管理
+
+
+
+
+ 缓存管理
+
+
+
+
+ 获取全部缓存
+
+
+
+
+
+ 获取缓存
+
+
+
+
+
+ 新增
+
+
+
+
+
+ 删除全部缓存
+
+
+
+
+
+ 删除缓存
+
+
+
+
+
+ 数据库管理
+
+
+
+
+ 获取库配置
+
+
+
+
+
+ 获取表信息
+
+ 配置Id
+ 读取类型
+
+
+
+
+ 获取表字段
+
+ 表名
+ ConfigId
+ 读取类型
+
+
+
+
+ 编辑表备注
+
+
+
+
+
+ 编辑列备注
+
+
+
+
+
+ 动态建表 CURD
+
+
+
+
+ 动态type
+
+
+
+
+
+ 动态type 继承BaseEntity
+
+
+
+
+
+ 测试建表
+
+
+
+
+
+ 测试查询
+
+
+
+
+
+ 测试写入
+
+
+
+
+
+ 多租户-多库方案 测试
+
+
+
+
+ 获取租户下全部业务数据
+
+
+
+
+
+ 新增数据
+
+
+
+
+
+ 多租户-Id方案 测试
+
+
+
+
+ 获取租户下全部业务数据
+
+
+
+
+
+ 新增业务数据
+
+
+
+
+
+ 多租户-多表方案 测试
+
+
+
+
+ 获取租户下全部业务数据
+
+
+
+
+
+ 新增数据
+
+
+
+
+
+ 租户管理
+
+
+
+
+ 获取全部租户
+
+
+
+
+
+ 获取租户信息
+
+
+
+
+
+ 新增租户信息
+ 此处只做演示,具体要以实际业务为准
+
+
+
+
+
+ 修改租户信息
+ 此处只做演示,具体要以实际业务为准
+
+
+
+
+
+ 删除租户
+ 此处只做演示,具体要以实际业务为准
+
+
+
+
+
+ 枚举测试
+
+
+
+
+ 获取学生信息
+
+ 学生类型
+
+
+ 学生信息
+
+
+
+ 学生类型
+
+
+
+
+ 小学生
+
+
+
+
+ 中学生
+
+
+
+
+ 大学生
+
+
+
+
+ 学生姓名
+
+
+
+
+ 学生年龄
+
+
+
+
+ 学生类型
+
+
+
+
+ Summary:全局路由权限公约
+ Remarks:目的是针对不同的路由,采用不同的授权过滤器
+ 如果 controller 上不加 [Authorize] 特性,默认都是 Permission 策略
+ 否则,如果想特例其他授权机制的话,需要在 controller 上带上 [Authorize],然后再action上自定义授权即可,比如 [Authorize(Roles = "Admin")]
+
+
+
+
+ 全局权限过滤器【无效】
+
+
+
+
+ 全局异常错误日志
+
+
+
+
+ 自定义返回格式
+
+
+
+
+
+
+
+ 生产环境的消息
+
+
+
+
+ 开发环境的消息
+
+
+
+
+ 全局路由前缀公约
+
+
+
+
+ 自定义路由 /api/{version}/[controler]/[action]
+
+
+
+
+ 分组名称,是来实现接口 IApiDescriptionGroupNameProvider
+
+
+
+
+ 自定义路由构造函数,继承基类路由
+
+
+
+
+
+ 自定义版本+路由构造函数,继承基类路由
+
+
+
+
diff --git a/Blog.Core.Api/Controllers/BaseApiController.cs b/Blog.Core.Api/Controllers/BaseApiController.cs
new file mode 100644
index 00000000..97a938ea
--- /dev/null
+++ b/Blog.Core.Api/Controllers/BaseApiController.cs
@@ -0,0 +1,88 @@
+using Blog.Core.Model;
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+
+namespace Blog.Core.Controllers
+{
+ public class BaseApiController : Controller
+ {
+ [NonAction]
+ public MessageModel Success(T data, string msg = "成功")
+ {
+ return new MessageModel()
+ {
+ success = true,
+ msg = msg,
+ response = data,
+ };
+ }
+
+ // [NonAction]
+ //public MessageModel Success(T data, string msg = "成功",bool success = true)
+ //{
+ // return new MessageModel()
+ // {
+ // success = success,
+ // msg = msg,
+ // response = data,
+ // };
+ //}
+ [NonAction]
+ public MessageModel Success(string msg = "成功")
+ {
+ return new MessageModel()
+ {
+ success = true,
+ msg = msg,
+ response = null,
+ };
+ }
+
+ [NonAction]
+ public MessageModel Failed(string msg = "失败", int status = 500)
+ {
+ return new MessageModel()
+ {
+ success = false,
+ status = status,
+ msg = msg,
+ response = null,
+ };
+ }
+
+ [NonAction]
+ public MessageModel Failed(string msg = "失败", int status = 500)
+ {
+ return new MessageModel()
+ {
+ success = false,
+ status = status,
+ msg = msg,
+ response = default,
+ };
+ }
+
+ [NonAction]
+ public MessageModel> SuccessPage(int page, int dataCount, int pageSize, List data,
+ int pageCount, string msg = "获取成功")
+ {
+ return new MessageModel>()
+ {
+ success = true,
+ msg = msg,
+ response = new PageModel(page, dataCount, pageSize, data)
+ };
+ }
+
+ [NonAction]
+ public MessageModel> SuccessPage(PageModel pageModel, string msg = "获取成功")
+ {
+ return new MessageModel>()
+ {
+ success = true,
+ msg = msg,
+ response = pageModel
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/BlogController.cs b/Blog.Core.Api/Controllers/BlogController.cs
index 3468646c..d0e9a235 100644
--- a/Blog.Core.Api/Controllers/BlogController.cs
+++ b/Blog.Core.Api/Controllers/BlogController.cs
@@ -1,7 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.Linq.Expressions;
-using System.Threading.Tasks;
+using System.Linq.Expressions;
+using System.Text.RegularExpressions;
using Blog.Core.Common.Helper;
using Blog.Core.IServices;
using Blog.Core.Model;
@@ -10,7 +8,7 @@
using Blog.Core.SwaggerHelper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Logging;
+using Serilog;
using StackExchange.Profiling;
using static Blog.Core.Extensions.CustomApiVersion;
@@ -21,20 +19,18 @@ namespace Blog.Core.Controllers
///
[Produces("application/json")]
[Route("api/Blog")]
- [Authorize]
- public class BlogController : Controller
+ public class BlogController : BaseApiController
{
- readonly IBlogArticleServices _blogArticleServices;
+ public IBlogArticleServices _blogArticleServices { get; set; }
private readonly ILogger _logger;
///
/// 构造函数
///
- ///
///
- public BlogController(IBlogArticleServices blogArticleServices, ILogger logger)
+ ///
+ public BlogController(ILogger logger)
{
- _blogArticleServices = blogArticleServices;
_logger = logger;
}
@@ -48,9 +44,6 @@ public BlogController(IBlogArticleServices blogArticleServices, ILogger
///
[HttpGet]
- [AllowAnonymous]
- //[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
- //[ResponseCache(Duration = 600)]
public async Task>> Get(int id, int page = 1, string bcategory = "技术博文", string key = "")
{
int intPageSize = 6;
@@ -79,18 +72,7 @@ public async Task>> Get(int id, int page = 1
}
}
- return new MessageModel>()
- {
- success = true,
- msg = "获取成功",
- response = new PageModel()
- {
- page = page,
- dataCount = pageModelBlog.dataCount,
- data = pageModelBlog.data,
- pageCount = pageModelBlog.pageCount,
- }
- };
+ return SuccessPage(pageModelBlog);
}
@@ -100,15 +82,11 @@ public async Task>> Get(int id, int page = 1
///
///
[HttpGet("{id}")]
+ //[Authorize(Policy = "Scope_BlogModule_Policy")]
[Authorize]
- public async Task> Get(int id)
+ public async Task> Get(long id)
{
- return new MessageModel()
- {
- msg = "获取成功",
- success = true,
- response = await _blogArticleServices.GetBlogDetails(id)
- };
+ return Success(await _blogArticleServices.GetBlogDetails(id));
}
@@ -119,69 +97,54 @@ public async Task> Get(int id)
///
[HttpGet]
[Route("DetailNuxtNoPer")]
- [AllowAnonymous]
- public async Task> DetailNuxtNoPer(int id)
+ public async Task> DetailNuxtNoPer(long id)
{
_logger.LogInformation("xxxxxxxxxxxxxxxxxxx");
- return new MessageModel()
- {
- msg = "获取成功",
- success = true,
- response = await _blogArticleServices.GetBlogDetails(id)
- };
+ Log.Information("yyyyyyyyyyyyyyyyy");
+ return Success(await _blogArticleServices.GetBlogDetails(id));
}
[HttpGet]
[Route("GoUrl")]
- [AllowAnonymous]
- public async Task GoUrl(int id)
+ public async Task GoUrl(long id = 0)
{
var response = await _blogArticleServices.QueryById(id);
if (response != null && response.bsubmitter.IsNotEmptyOrNull())
{
- response.btraffic += 1;
- await _blogArticleServices.Update(response);
- return Redirect(response.bsubmitter);
+ string Url = @"^http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?$";
+ if (Regex.IsMatch(response.bsubmitter, Url))
+ {
+ response.btraffic += 1;
+ await _blogArticleServices.Update(response);
+ return Redirect(response.bsubmitter);
+ }
+
}
- return null;
+ return Ok();
}
[HttpGet]
[Route("GetBlogsByTypesForMVP")]
- [AllowAnonymous]
public async Task>> GetBlogsByTypesForMVP(string types = "", int id = 0)
{
if (types.IsNotEmptyOrNull())
{
- var blogs = await _blogArticleServices.Query(d => d.bcategory != null && types.Contains(d.bcategory) && d.IsDeleted == false);
- return new MessageModel>()
- {
- msg = "获取成功",
- success = true,
- response = blogs
- };
+ var blogs = await _blogArticleServices.Query(d => d.bcategory != null && types.Contains(d.bcategory) && d.IsDeleted == false, d => d.bID, false);
+ return Success(blogs);
}
-
- return new MessageModel>() { };
+ return Success(new List() { });
}
[HttpGet]
[Route("GetBlogByIdForMVP")]
- [AllowAnonymous]
- public async Task> GetBlogByIdForMVP(int id = 0)
+ public async Task> GetBlogByIdForMVP(long id = 0)
{
if (id > 0)
{
- return new MessageModel()
- {
- msg = "获取成功",
- success = true,
- response = await _blogArticleServices.QueryById(id)
- };
+ return Success(await _blogArticleServices.QueryById(id));
}
-
- return new MessageModel() { };
+ return Success(new BlogArticle());
}
///
@@ -196,15 +159,9 @@ public async Task> GetBlogByIdForMVP(int id = 0)
//和上边的版本控制以及路由地址都是一样的
[CustomRoute(ApiVersions.V2, "Blogtest")]
- [AllowAnonymous]
public MessageModel V2_Blogtest()
{
- return new MessageModel()
- {
- msg = "获取成功",
- success = true,
- response = "我是第二版的博客信息"
- };
+ return Success("我是第二版的博客信息");
}
///
@@ -213,24 +170,24 @@ public MessageModel V2_Blogtest()
///
///
[HttpPost]
+ //[Authorize(Policy = "Scope_BlogModule_Policy")]
+ [Authorize]
public async Task> Post([FromBody] BlogArticle blogArticle)
{
- var data = new MessageModel();
-
- blogArticle.bCreateTime = DateTime.Now;
- blogArticle.bUpdateTime = DateTime.Now;
- blogArticle.IsDeleted = false;
- blogArticle.bcategory = "技术博文";
+ if (blogArticle.btitle.Length > 5 && blogArticle.bcontent.Length > 50)
+ {
- var id = (await _blogArticleServices.Add(blogArticle));
- data.success = id > 0;
- if (data.success)
+ blogArticle.bCreateTime = DateTime.Now;
+ blogArticle.bUpdateTime = DateTime.Now;
+ blogArticle.IsDeleted = false;
+ blogArticle.bcategory = "技术博文";
+ var id = (await _blogArticleServices.Add(blogArticle));
+ return id > 0 ? Success(id.ObjToString()) : Failed("添加失败");
+ }
+ else
{
- data.response = id.ObjToString();
- data.msg = "添加成功";
+ return Failed("文章标题不能少于5个字符,内容不能少于50个字符!");
}
-
- return data;
}
@@ -244,21 +201,11 @@ public async Task> Post([FromBody] BlogArticle blogArticle)
[Authorize(Permissions.Name)]
public async Task> AddForMVP([FromBody] BlogArticle blogArticle)
{
- var data = new MessageModel();
-
blogArticle.bCreateTime = DateTime.Now;
blogArticle.bUpdateTime = DateTime.Now;
blogArticle.IsDeleted = false;
-
var id = (await _blogArticleServices.Add(blogArticle));
- data.success = id > 0;
- if (data.success)
- {
- data.response = id.ObjToString();
- data.msg = "添加成功";
- }
-
- return data;
+ return id > 0 ? Success(id.ObjToString()) : Failed("添加失败");
}
///
/// 更新博客信息
@@ -271,7 +218,6 @@ public async Task> AddForMVP([FromBody] BlogArticle blogArt
[Authorize(Permissions.Name)]
public async Task> Put([FromBody] BlogArticle BlogArticle)
{
- var data = new MessageModel();
if (BlogArticle != null && BlogArticle.bID > 0)
{
var model = await _blogArticleServices.QueryById(BlogArticle.bID);
@@ -284,17 +230,13 @@ public async Task> Put([FromBody] BlogArticle BlogArticle)
model.bcontent = BlogArticle.bcontent;
model.btraffic = BlogArticle.btraffic;
- data.success = await _blogArticleServices.Update(model);
- if (data.success)
+ if (await _blogArticleServices.Update(model))
{
- data.msg = "更新成功";
- data.response = BlogArticle?.bID.ObjToString();
+ return Success(BlogArticle?.bID.ObjToString());
}
}
-
}
-
- return data;
+ return Failed("更新失败");
}
@@ -307,22 +249,19 @@ public async Task> Put([FromBody] BlogArticle BlogArticle)
[HttpDelete]
[Authorize(Permissions.Name)]
[Route("Delete")]
- public async Task> Delete(int id)
+ public async Task> Delete(long id)
{
- var data = new MessageModel();
if (id > 0)
{
var blogArticle = await _blogArticleServices.QueryById(id);
- blogArticle.IsDeleted = true;
- data.success = await _blogArticleServices.Update(blogArticle);
- if (data.success)
+ if (blogArticle == null)
{
- data.msg = "删除成功";
- data.response = blogArticle?.bID.ObjToString();
+ return Failed("查询无数据");
}
+ blogArticle.IsDeleted = true;
+ return await _blogArticleServices.Update(blogArticle) ? Success(blogArticle?.bID.ObjToString(), "删除成功") : Failed("删除失败");
}
-
- return data;
+ return Failed("入参无效");
}
///
/// apache jemeter 压力测试
@@ -331,15 +270,9 @@ public async Task> Delete(int id)
///
[HttpGet]
[Route("ApacheTestUpdate")]
- [AllowAnonymous]
public async Task> ApacheTestUpdate()
{
- return new MessageModel()
- {
- success = true,
- msg = "更新成功",
- response = await _blogArticleServices.Update(new { bsubmitter = $"laozhang{DateTime.Now.Millisecond}", bID = 1 })
- };
+ return Success(await _blogArticleServices.Update(new { bsubmitter = $"laozhang{DateTime.Now.Millisecond}", bID = 1 }), "更新成功");
}
}
}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs b/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs
index 5cf404e4..553dee75 100644
--- a/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs
+++ b/Blog.Core.Api/Controllers/DbFirst/DbFirstController.cs
@@ -1,7 +1,7 @@
using Blog.Core.Common;
using Blog.Core.Common.DB;
+using Blog.Core.Common.Seed;
using Blog.Core.Model;
-using Blog.Core.Model.Seed;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
@@ -15,7 +15,7 @@ namespace Blog.Core.Controllers
//[Authorize(Permissions.Name)]
public class DbFirstController : ControllerBase
{
- private readonly SqlSugarClient _sqlSugarClient;
+ private readonly SqlSugarScope _sqlSugarClient;
private readonly IWebHostEnvironment Env;
///
@@ -23,12 +23,12 @@ public class DbFirstController : ControllerBase
///
public DbFirstController(ISqlSugarClient sqlSugarClient, IWebHostEnvironment env)
{
- _sqlSugarClient = sqlSugarClient as SqlSugarClient;
+ _sqlSugarClient = sqlSugarClient as SqlSugarScope;
Env = env;
}
///
- /// 获取 整体框架 文件
+ /// 获取 整体框架 文件(主库)(一般可用第一次生成)
///
///
[HttpGet]
@@ -36,17 +36,19 @@ public MessageModel GetFrameFiles()
{
var data = new MessageModel() { success = true, msg = "" };
data.response += @"file path is:C:\my-file\}";
- var isMuti = Appsettings.app(new string[] { "MutiDBEnabled" }).ObjToBool();
+ var isMuti = BaseDBConfig.IsMulti;
if (Env.IsDevelopment())
{
- BaseDBConfig.MutiConnectionString.Item1.ToList().ForEach(m =>
+ data.response += $"Controller层生成:{FrameSeed.CreateControllers(_sqlSugarClient)} || ";
+
+ BaseDBConfig.ValidConfig.ForEach(m =>
{
- _sqlSugarClient.ChangeDatabase(m.ConnId.ToLower());
- data.response += $"库{m.ConnId}-Model层生成:{FrameSeed.CreateModels(_sqlSugarClient, m.ConnId, isMuti)} || ";
- data.response += $"库{m.ConnId}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, m.ConnId, isMuti)} || ";
- data.response += $"库{m.ConnId}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, m.ConnId, isMuti)} || ";
- data.response += $"库{m.ConnId}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, m.ConnId, isMuti)} || ";
- data.response += $"库{m.ConnId}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, m.ConnId, isMuti)} || ";
+ _sqlSugarClient.ChangeDatabase(m.ConfigId.ToString().ToLower());
+ data.response += $"库{m.ConfigId}-Model层生成:{FrameSeed.CreateModels(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
+ data.response += $"库{m.ConfigId}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
+ data.response += $"库{m.ConfigId}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
+ data.response += $"库{m.ConfigId}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
+ data.response += $"库{m.ConfigId}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, m.ConfigId.ToString(), isMuti)} || ";
});
// 切回主库
@@ -62,8 +64,7 @@ public MessageModel GetFrameFiles()
}
///
- /// 根据数据库表名 生成整体框架
- /// 仅针对通过CodeFirst生成表的情况
+ /// 获取仓储层和服务层(需指定表名和数据库)
///
/// 数据库链接名称
/// 需要生成的表名
@@ -73,15 +74,96 @@ public MessageModel GetFrameFilesByTableNames([FromBody]string[] tableNa
{
ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
- var isMuti = Appsettings.app(new string[] { "MutiDBEnabled" }).ObjToBool();
+ var isMuti = BaseDBConfig.IsMulti;
+ var data = new MessageModel() { success = true, msg = "" };
+ if (Env.IsDevelopment())
+ {
+ data.response += $"库{ConnID}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+ ///
+ /// 获取实体(需指定表名和数据库)
+ ///
+ /// 数据库链接名称
+ /// 需要生成的表名
+ ///
+ [HttpPost]
+ public MessageModel GetFrameFilesByTableNamesForEntity([FromBody] string[] tableNames, [FromQuery] string ConnID = null)
+ {
+ ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
+
+ var isMuti = BaseDBConfig.IsMulti;
+ var data = new MessageModel() { success = true, msg = "" };
+ if (Env.IsDevelopment())
+ {
+ data.response += $"库{ConnID}-Models层生成:{FrameSeed.CreateModels(_sqlSugarClient, ConnID, isMuti, tableNames)}";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+ return data;
+ }
+ ///
+ /// 获取控制器(需指定表名和数据库)
+ ///
+ /// 数据库链接名称
+ /// 需要生成的表名
+ ///
+ [HttpPost]
+ public MessageModel GetFrameFilesByTableNamesForController([FromBody] string[] tableNames, [FromQuery] string ConnID = null)
+ {
+ ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
+
+ var isMuti = BaseDBConfig.IsMulti;
var data = new MessageModel() { success = true, msg = "" };
if (Env.IsDevelopment())
{
+ data.response += $"库{ConnID}-Controllers层生成:{FrameSeed.CreateControllers(_sqlSugarClient, ConnID, isMuti, tableNames)}";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+ return data;
+ }
+ ///
+ /// DbFrist 根据数据库表名 生成整体框架,包含Model层(一般可用第一次生成)
+ ///
+ /// 数据库链接名称
+ /// 需要生成的表名
+ ///
+ [HttpPost]
+ public MessageModel GetAllFrameFilesByTableNames([FromBody]string[] tableNames, [FromQuery]string ConnID = null)
+ {
+ ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
+
+ var isMuti = BaseDBConfig.IsMulti;
+ var data = new MessageModel() { success = true, msg = "" };
+ if (Env.IsDevelopment())
+ {
+ _sqlSugarClient.ChangeDatabase(ConnID.ToLower());
+ data.response += $"Controller层生成:{FrameSeed.CreateControllers(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ data.response += $"库{ConnID}-Model层生成:{FrameSeed.CreateModels(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
data.response += $"库{ConnID}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
data.response += $"库{ConnID}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
data.response += $"库{ConnID}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
data.response += $"库{ConnID}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, ConnID, isMuti, tableNames)} || ";
+ // 切回主库
+ _sqlSugarClient.ChangeDatabase(MainDb.CurrentDbConnId.ToLower());
}
else
{
@@ -91,5 +173,7 @@ public MessageModel GetFrameFilesByTableNames([FromBody]string[] tableNa
return data;
}
+
+
}
}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/DbFirst/MigrateController.cs b/Blog.Core.Api/Controllers/DbFirst/MigrateController.cs
index 8b535fb6..7865cc69 100644
--- a/Blog.Core.Api/Controllers/DbFirst/MigrateController.cs
+++ b/Blog.Core.Api/Controllers/DbFirst/MigrateController.cs
@@ -1,14 +1,20 @@
-using Blog.Core.IRepository.UnitOfWork;
+using Blog.Core.Common.Helper;
using Blog.Core.IServices;
using Blog.Core.Model;
using Blog.Core.Model.Models;
+using Magicodes.ExporterAndImporter.Core;
+using Magicodes.ExporterAndImporter.Excel;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
using System.Threading.Tasks;
+using Blog.Core.Repository.UnitOfWorks;
namespace Blog.Core.Controllers
{
@@ -17,33 +23,182 @@ namespace Blog.Core.Controllers
//[Authorize(Permissions.Name)]
public class MigrateController : ControllerBase
{
- private readonly IUnitOfWork _unitOfWork;
+ private readonly IUnitOfWorkManage _unitOfWorkManage;
private readonly IRoleModulePermissionServices _roleModulePermissionServices;
+ private readonly IUserRoleServices _userRoleServices;
+ private readonly IRoleServices _roleServices;
+ private readonly IPermissionServices _permissionServices;
+ private readonly IModuleServices _moduleServices;
+ private readonly IDepartmentServices _departmentServices;
+ private readonly ISysUserInfoServices _sysUserInfoServices;
private readonly IWebHostEnvironment _env;
- public MigrateController(IUnitOfWork unitOfWork, IRoleModulePermissionServices roleModulePermissionServices, IWebHostEnvironment env)
+ public MigrateController(IUnitOfWorkManage unitOfWorkManage,
+ IRoleModulePermissionServices roleModulePermissionServices,
+ IUserRoleServices userRoleServices,
+ IRoleServices roleServices,
+ IPermissionServices permissionServices,
+ IModuleServices moduleServices,
+ IDepartmentServices departmentServices,
+ ISysUserInfoServices sysUserInfoServices,
+ IWebHostEnvironment env)
{
- _unitOfWork = unitOfWork;
+ _unitOfWorkManage = unitOfWorkManage;
_roleModulePermissionServices = roleModulePermissionServices;
+ _userRoleServices = userRoleServices;
+ _roleServices = roleServices;
+ _permissionServices = permissionServices;
+ _moduleServices = moduleServices;
+ _departmentServices = departmentServices;
+ _sysUserInfoServices = sysUserInfoServices;
_env = env;
}
+
///
- /// 获取权限部分Map数据
- /// 生成到tsb文件
+ /// 获取权限部分Map数据(从库)
+ /// 迁移到新库(主库)
///
///
[HttpGet]
- public async Task> GetRMPMaps()
+ public async Task> DataMigrateFromOld2New()
{
var data = new MessageModel() { success = true, msg = "" };
+ var filterPermissionId = 122;
if (_env.IsDevelopment())
{
- // 获取数据,当然,你可以做个where查询
- var rmps = await _roleModulePermissionServices.GetRMPMaps();
- var rmpSerializeStr = JsonConvert.SerializeObject(rmps);
- // 将序列化的json生成到tsv文件
- var roleModulePermissions = JsonConvert.DeserializeObject>(rmpSerializeStr);
+ try
+ {
+ var apiList = await _moduleServices.Query(d => d.IsDeleted == false);
+ var permissionsAllList = await _permissionServices.Query(d => d.IsDeleted == false);
+ var permissions = permissionsAllList.Where(d => d.Pid == 0).ToList();
+ var rmps = await _roleModulePermissionServices.GetRMPMaps();
+ List pms = new();
+
+ // 当然,你可以做个where查询
+ rmps = rmps.Where(d => d.PermissionId >= filterPermissionId).ToList();
+
+ InitPermissionTree(permissions, permissionsAllList, apiList);
+
+ var actionPermissionIds = permissionsAllList.Where(d => d.Id >= filterPermissionId).Select(d => d.Id).ToList();
+ List filterPermissionIds = new();
+ FilterPermissionTree(permissionsAllList, actionPermissionIds, filterPermissionIds);
+ permissions = permissions.Where(d => filterPermissionIds.Contains(d.Id)).ToList();
+
+ // 开启事务,保证数据一致性
+ _unitOfWorkManage.BeginTran();
+
+ // 注意信息的完整性,不要重复添加,确保主库没有要添加的数据
+
+ // 1、保持菜单和接口
+ await SavePermissionTreeAsync(permissions, pms);
+
+ long rid = 0;
+ long pid = 0;
+ long mid = 0;
+ long rpmid = 0;
+
+ // 2、保存关系表
+ foreach (var item in rmps)
+ {
+ // 角色信息,防止重复添加,做了判断
+ if (item.Role != null)
+ {
+ var isExit = (await _roleServices.Query(d => d.Name == item.Role.Name && d.IsDeleted == false)).FirstOrDefault();
+ if (isExit == null)
+ {
+ rid = await _roleServices.Add(item.Role);
+ Console.WriteLine($"Role Added:{item.Role.Name}");
+ }
+ else
+ {
+ rid = isExit.Id;
+ }
+ }
+
+ pid = (pms.FirstOrDefault(d => d.PidOld == item.PermissionId)?.PidNew).ObjToLong();
+ mid = (pms.FirstOrDefault(d => d.MidOld == item.ModuleId)?.MidNew).ObjToLong();
+ // 关系
+ if (rid > 0 && pid > 0)
+ {
+ rpmid = await _roleModulePermissionServices.Add(new RoleModulePermission()
+ {
+ IsDeleted = false,
+ CreateTime = DateTime.Now,
+ ModifyTime = DateTime.Now,
+ ModuleId = mid,
+ PermissionId = pid,
+ RoleId = rid,
+ });
+ Console.WriteLine($"RMP Added:{rpmid}");
+ }
+
+ }
+
+
+ _unitOfWorkManage.CommitTran();
+
+ data.success = true;
+ data.msg = "导入成功!";
+ }
+ catch (Exception)
+ {
+ _unitOfWorkManage.RollbackTran();
+
+ }
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+
+
+ ///
+ /// 权限数据库导出tsv
+ ///
+ ///
+ [HttpGet]
+ public async Task> SaveData2TsvAsync()
+ {
+ var data = new MessageModel() { success = true, msg = "" };
+ if (_env.IsDevelopment())
+ {
+
+ JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
+ {
+ DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
+ };
+
+ // 取出数据,序列化,自己可以处理判空
+ var SysUserInfoJson = JsonConvert.SerializeObject(await _sysUserInfoServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "SysUserInfo.tsv"), SysUserInfoJson, Encoding.UTF8);
+
+ var DepartmentJson = JsonConvert.SerializeObject(await _departmentServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Department.tsv"), DepartmentJson, Encoding.UTF8);
+
+ var rolesJson = JsonConvert.SerializeObject(await _roleServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Role.tsv"), rolesJson, Encoding.UTF8);
+
+ var UserRoleJson = JsonConvert.SerializeObject(await _userRoleServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "UserRole.tsv"), UserRoleJson, Encoding.UTF8);
+
+
+ var permissionsJson = JsonConvert.SerializeObject(await _permissionServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Permission.tsv"), permissionsJson, Encoding.UTF8);
+
+
+ var modulesJson = JsonConvert.SerializeObject(await _moduleServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Modules.tsv"), modulesJson, Encoding.UTF8);
+
+
+ var rmpsJson = JsonConvert.SerializeObject(await _roleModulePermissionServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "RoleModulePermission.tsv"), rmpsJson, Encoding.UTF8);
+
+
data.success = true;
data.msg = "生成成功!";
@@ -59,43 +214,50 @@ public async Task> GetRMPMaps()
///
- /// 保存数据到数据库
+ /// 权限数据库导出excel
///
///
[HttpGet]
- public MessageModel SaveDataToDb()
+ public async Task> SaveData2ExcelAsync()
{
var data = new MessageModel() { success = true, msg = "" };
if (_env.IsDevelopment())
{
- // 取出json数据,反序列化
- var rmpSerializeStr = "";
- var roleModulePermissions = JsonConvert.DeserializeObject>(rmpSerializeStr);
- try
+ JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
{
- _unitOfWork.BeginTran();
+ DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
+ };
- foreach (var item in roleModulePermissions)
- {
- // 添加角色,返回rid
- var role = item.Role;
- // 添加菜单,返回mid
- var module = item.Module;
- // 添加接口,返回pid
- var permission = item.Permission;
+ // 取出数据,序列化,自己可以处理判空
+ IExporter exporter = new ExcelExporter();
+ var SysUserInfoList = await _sysUserInfoServices.Query(d => d.IsDeleted == false);
+ var result = await exporter.ExportAsByteArray(SysUserInfoList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "SysUserInfo.xlsx"), result);
- // 添加关系表
+ var DepartmentList = await _departmentServices.Query(d => d.IsDeleted == false);
+ var DepartmentResult = await exporter.ExportAsByteArray(DepartmentList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "Department.xlsx"), DepartmentResult);
- }
+ var RoleList = await _roleServices.Query(d => d.IsDeleted == false);
+ var RoleResult = await exporter.ExportAsByteArray(RoleList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "Role.xlsx"), RoleResult);
- _unitOfWork.CommitTran();
- }
- catch (Exception)
- {
- _unitOfWork.RollbackTran();
- }
+ var UserRoleList = await _userRoleServices.Query(d => d.IsDeleted == false);
+ var UserRoleResult = await exporter.ExportAsByteArray(UserRoleList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "UserRole.xlsx"), UserRoleResult);
+
+ var PermissionList = await _permissionServices.Query(d => d.IsDeleted == false);
+ var PermissionResult = await exporter.ExportAsByteArray(PermissionList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "Permission.xlsx"), PermissionResult);
+ var ModulesList = await _moduleServices.Query(d => d.IsDeleted == false);
+ var ModulesResult = await exporter.ExportAsByteArray(ModulesList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "Modules.xlsx"), ModulesResult);
+
+ var RoleModulePermissionList = await _roleModulePermissionServices.Query(d => d.IsDeleted == false);
+ var RoleModulePermissionResult = await exporter.ExportAsByteArray(RoleModulePermissionList);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.excel", "RoleModulePermission.xlsx"), RoleModulePermissionResult);
data.success = true;
@@ -110,5 +272,88 @@ public MessageModel SaveDataToDb()
return data;
}
+ private void InitPermissionTree(List permissionsTree, List all, List apis)
+ {
+ foreach (var item in permissionsTree)
+ {
+ item.Children = all.Where(d => d.Pid == item.Id).ToList();
+ item.Module = apis.FirstOrDefault(d => d.Id == item.Mid);
+ InitPermissionTree(item.Children, all, apis);
+ }
+ }
+
+ private void FilterPermissionTree(List permissionsAll, List actionPermissionId, List filterPermissionIds)
+ {
+ actionPermissionId = actionPermissionId.Distinct().ToList();
+ var doneIds = permissionsAll.Where(d => actionPermissionId.Contains(d.Id) && d.Pid == 0).Select(d => d.Id).ToList();
+ filterPermissionIds.AddRange(doneIds);
+
+ var hasDoIds = permissionsAll.Where(d => actionPermissionId.Contains(d.Id) && d.Pid != 0).Select(d => d.Pid).ToList();
+ if (hasDoIds.Any())
+ {
+ FilterPermissionTree(permissionsAll, hasDoIds, filterPermissionIds);
+ }
+ }
+
+ private async Task SavePermissionTreeAsync(List permissionsTree, List pms, long permissionId = 0)
+ {
+ var parendId = permissionId;
+
+ foreach (var item in permissionsTree)
+ {
+ PM pm = new PM();
+ // 保留原始主键id
+ pm.PidOld = item.Id;
+ pm.MidOld = (item.Module?.Id).ObjToLong();
+
+ long mid = 0;
+ // 接口
+ if (item.Module != null)
+ {
+ var moduleModel = (await _moduleServices.Query(d => d.LinkUrl == item.Module.LinkUrl)).FirstOrDefault();
+ if (moduleModel != null)
+ {
+ mid = moduleModel.Id;
+ }
+ else
+ {
+ mid = await _moduleServices.Add(item.Module);
+ }
+ pm.MidNew = mid;
+ Console.WriteLine($"Moudle Added:{item.Module.Name}");
+ }
+ // 菜单
+ if (item != null)
+ {
+ var permissionModel = (await _permissionServices.Query(d => d.Name == item.Name && d.Pid == item.Pid && d.Mid == item.Mid)).FirstOrDefault();
+ item.Pid = parendId;
+ item.Mid = mid;
+ if (permissionModel != null)
+ {
+ permissionId = permissionModel.Id;
+ }
+ else
+ {
+ permissionId = await _permissionServices.Add(item);
+ }
+
+ pm.PidNew = permissionId;
+ Console.WriteLine($"Permission Added:{item.Name}");
+ }
+ pms.Add(pm);
+
+ await SavePermissionTreeAsync(item.Children, pms, permissionId);
+ }
+ }
+
+
+ }
+
+ public class PM
+ {
+ public long PidOld { get; set; }
+ public long MidOld { get; set; }
+ public long PidNew { get; set; }
+ public long MidNew { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/Blog.Core.Api/Controllers/DepartmentController.cs b/Blog.Core.Api/Controllers/DepartmentController.cs
new file mode 100644
index 00000000..faf1f850
--- /dev/null
+++ b/Blog.Core.Api/Controllers/DepartmentController.cs
@@ -0,0 +1,215 @@
+using Blog.Core.Common.Helper;
+using Blog.Core.Controllers;
+using Blog.Core.IServices;
+using Blog.Core.Model;
+using Blog.Core.Model.Models;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json;
+using System.Linq.Expressions;
+using System.Text;
+
+namespace Blog.Core.Api.Controllers
+{
+ [Route("api/[controller]/[action]")]
+ [ApiController]
+ [Authorize(Permissions.Name)]
+ public class DepartmentController : BaseApiController
+ {
+ private readonly IDepartmentServices _departmentServices;
+ private readonly IWebHostEnvironment _env;
+
+ public DepartmentController(IDepartmentServices departmentServices, IWebHostEnvironment env)
+ {
+ _departmentServices = departmentServices;
+ _env = env;
+ }
+
+ [HttpGet]
+ public async Task>> Get(int page = 1, string key = "", int intPageSize = 50)
+ {
+ if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key))
+ {
+ key = "";
+ }
+
+ Expression> whereExpression = a => true;
+
+ return new MessageModel>()
+ {
+ msg = "获取成功",
+ success = true,
+ response = await _departmentServices.QueryPage(whereExpression, page, intPageSize)
+ };
+
+ }
+
+ [HttpGet("{id}")]
+ public async Task> Get(string id)
+ {
+ return new MessageModel()
+ {
+ msg = "获取成功",
+ success = true,
+ response = await _departmentServices.QueryById(id)
+ };
+ }
+
+ ///
+ /// 查询树形 Table
+ ///
+ /// 父节点
+ /// 关键字
+ ///
+ [HttpGet]
+ [AllowAnonymous]
+ public async Task>> GetTreeTable(long f = 0, string key = "")
+ {
+ List departments = new List();
+ var departmentList = await _departmentServices.Query(d => d.IsDeleted == false);
+ if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key))
+ {
+ key = "";
+ }
+
+ if (key != "")
+ {
+ departments = departmentList.Where(a => a.Name.Contains(key)).OrderBy(a => a.OrderSort).ToList();
+ }
+ else
+ {
+ departments = departmentList.Where(a => a.Pid == f).OrderBy(a => a.OrderSort).ToList();
+ }
+
+ foreach (var item in departments)
+ {
+ List pidarr = new() { };
+ var parent = departmentList.FirstOrDefault(d => d.Id == item.Pid);
+
+ while (parent != null)
+ {
+ pidarr.Add(parent.Id);
+ parent = departmentList.FirstOrDefault(d => d.Id == parent.Pid);
+ }
+
+ pidarr.Reverse();
+ pidarr.Insert(0, 0);
+ item.PidArr = pidarr;
+
+ item.hasChildren = departmentList.Where(d => d.Pid == item.Id).Any();
+ }
+
+
+ return Success(departments, "获取成功");
+ }
+
+ ///
+ /// 获取部门树
+ ///
+ ///
+ ///
+ [HttpGet]
+ public async Task> GetDepartmentTree(long pid = 0)
+ {
+ var departments = await _departmentServices.Query(d => d.IsDeleted == false);
+ var departmentTrees = (from child in departments
+ where child.IsDeleted == false
+ orderby child.Id
+ select new DepartmentTree
+ {
+ value = child.Id,
+ label = child.Name,
+ Pid = child.Pid,
+ order = child.OrderSort,
+ }).ToList();
+ DepartmentTree rootRoot = new DepartmentTree
+ {
+ value = 0,
+ Pid = 0,
+ label = "根节点"
+ };
+
+ departmentTrees = departmentTrees.OrderBy(d => d.order).ToList();
+
+
+ RecursionHelper.LoopToAppendChildren(departmentTrees, rootRoot, pid);
+
+ return Success(rootRoot, "获取成功");
+ }
+
+ [HttpPost]
+ public async Task> Post([FromBody] Department request)
+ {
+ var data = new MessageModel();
+
+ var id = await _departmentServices.Add(request);
+ data.success = id > 0;
+ if (data.success)
+ {
+ data.response = id.ObjToString();
+ data.msg = "添加成功";
+ }
+
+ return data;
+ }
+
+ [HttpPut]
+ public async Task> Put([FromBody] Department request)
+ {
+ var data = new MessageModel();
+ data.success = await _departmentServices.Update(request);
+ if (data.success)
+ {
+ data.msg = "更新成功";
+ data.response = request?.Id.ObjToString();
+ }
+
+ return data;
+ }
+
+ [HttpDelete]
+ public async Task> Delete(long id)
+ {
+ var data = new MessageModel();
+ var model = await _departmentServices.QueryById(id);
+ model.IsDeleted = true;
+ data.success = await _departmentServices.Update(model);
+ if (data.success)
+ {
+ data.msg = "删除成功";
+ data.response = model?.Id.ObjToString();
+ }
+
+
+ return data;
+ }
+
+ [HttpGet]
+ [AllowAnonymous]
+ public async Task> SaveData2Tsv()
+ {
+ var data = new MessageModel() { success = true, msg = "" };
+ if (_env.IsDevelopment())
+ {
+
+ JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
+ {
+ DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
+ };
+
+ var rolesJson = JsonConvert.SerializeObject(await _departmentServices.Query(d => d.IsDeleted == false), microsoftDateFormatSettings);
+ FileHelper.WriteFile(Path.Combine(_env.WebRootPath, "BlogCore.Data.json", "Department_New.tsv"), rolesJson, Encoding.UTF8);
+
+ data.success = true;
+ data.msg = "生成成功!";
+ }
+ else
+ {
+ data.success = false;
+ data.msg = "当前不处于开发模式,代码生成不可用!";
+ }
+
+ return data;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/ImgController.cs b/Blog.Core.Api/Controllers/ImgController.cs
index 8359ef8d..5ba85388 100644
--- a/Blog.Core.Api/Controllers/ImgController.cs
+++ b/Blog.Core.Api/Controllers/ImgController.cs
@@ -1,11 +1,6 @@
-using System;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Blog.Core.Model;
+using Blog.Core.Model;
+using Blog.Core.Model.ViewModels;
using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Blog.Core.Controllers
@@ -16,20 +11,28 @@ namespace Blog.Core.Controllers
[Route("api/[controller]")]
[ApiController]
[Authorize]
- public class ImgController : Controller
+ public class ImgController : BaseApiController
{
+
+ private readonly IWebHostEnvironment _env;
+
+ public ImgController(IWebHostEnvironment webHostEnvironment)
+ {
+ _env = webHostEnvironment;
+ }
+
+
// GET: api/Download
///
/// 下载图片(支持中文字符)
///
- ///
///
[HttpGet]
[Route("/images/Down/Pic")]
- public FileStreamResult DownImg([FromServices]IWebHostEnvironment environment)
+ public FileStreamResult DownImg()
{
string foldername = "";
- string filepath = Path.Combine(environment.WebRootPath, foldername, "测试下载中文名称的图片.png");
+ string filepath = Path.Combine(_env.WebRootPath, foldername, "测试下载中文名称的图片.png");
var stream = System.IO.File.OpenRead(filepath);
string fileExt = ".jpg"; // 这里可以写一个获取文件扩展名的方法,获取扩展名
//获取文件的ContentType
@@ -42,76 +45,84 @@ public FileStreamResult DownImg([FromServices]IWebHostEnvironment environment)
}
///
- /// 上传图片,多文件,可以使用 postman 测试,
- /// 如果是单文件,可以 参数写 IFormFile file1
+ /// 上传图片,多文件
///
- ///
+ ///
///
[HttpPost]
[Route("/images/Upload/Pic")]
- public async Task> InsertPicture([FromServices]IWebHostEnvironment environment)
+ public async Task> InsertPicture([FromForm]UploadFileDto dto)
{
- var data = new MessageModel();
- string path = string.Empty;
- string foldername = "images";
- IFormFileCollection files = null;
-
- try
- {
- files = Request.Form.Files;
- }
- catch (Exception)
- {
- files = null;
- }
-
- if (files == null || !files.Any()) { data.msg = "请选择上传的文件。"; return data; }
+
+ if (dto.file == null || !dto.file.Any()) return Failed("请选择上传的文件。");
//格式限制
var allowType = new string[] { "image/jpg", "image/png", "image/jpeg" };
+
+ var allowedFile = dto.file.Where(c => allowType.Contains(c.ContentType));
+ if (!allowedFile.Any()) return Failed("图片格式错误");
+ if (allowedFile.Sum(c => c.Length) > 1024 * 1024 * 4) return Failed("图片过大");
- string folderpath = Path.Combine(environment.WebRootPath, foldername);
+ string foldername = "images";
+ string folderpath = Path.Combine(_env.WebRootPath, foldername);
if (!Directory.Exists(folderpath))
{
Directory.CreateDirectory(folderpath);
}
-
- if (files.Any(c => allowType.Contains(c.ContentType)))
+ foreach (var file in allowedFile)
{
- if (files.Sum(c => c.Length) <= 1024 * 1024 * 4)
- {
- //foreach (var file in files)
- var file = files.FirstOrDefault();
- string strpath = Path.Combine(foldername, DateTime.Now.ToString("MMddHHmmss") + file.FileName);
- path = Path.Combine(environment.WebRootPath, strpath);
-
- using (var stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
- {
- await file.CopyToAsync(stream);
- }
-
- data = new MessageModel()
- {
- response = strpath,
- msg = "上传成功",
- success = true,
- };
- return data;
- }
- else
+ string strpath = Path.Combine(foldername, DateTime.Now.ToString("MMddHHmmss") + Path.GetFileName(file.FileName));
+ var path = Path.Combine(_env.WebRootPath, strpath);
+
+ using (var stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
- data.msg = "图片过大";
- return data;
+ await file.CopyToAsync(stream);
}
}
- else
+ var excludeFiles = dto.file.Except(allowedFile);
+
+ if (excludeFiles.Any())
{
- data.msg = "图片格式错误";
- return data;
+ var infoMsg = $"{string.Join('、', excludeFiles.Select(c => c.FileName))} 图片格式错误";
+ return Success(null, infoMsg);
}
+
+ return Success(null, "上传成功");
+
}
+
+ [HttpGet]
+ [Route("/images/Down/Bmd")]
+ [AllowAnonymous]
+ public FileStreamResult DownBmd(string filename)
+ {
+ if (string.IsNullOrEmpty(filename))
+ {
+ return null;
+ }
+ // 前端 blob 接收,具体查看前端admin代码
+ string filepath = Path.Combine(_env.WebRootPath, Path.GetFileName(filename));
+ if (System.IO.File.Exists(filepath))
+ {
+ var stream = System.IO.File.OpenRead(filepath);
+ //string fileExt = ".bmd";
+ //获取文件的ContentType
+ var provider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
+ //var memi = provider.Mappings[fileExt];
+ var fileName = Path.GetFileName(filepath);
+
+ HttpContext.Response.Headers.Add("fileName", fileName);
+
+ return File(stream, "application/octet-stream", fileName);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
// POST: api/Img
[HttpPost]
public void Post([FromBody] object formdata)
diff --git a/Blog.Core.Api/Controllers/LoginController.cs b/Blog.Core.Api/Controllers/LoginController.cs
index 67cb4cad..5b40773d 100644
--- a/Blog.Core.Api/Controllers/LoginController.cs
+++ b/Blog.Core.Api/Controllers/LoginController.cs
@@ -1,10 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.IdentityModel.Tokens.Jwt;
-using System.Linq;
-using System.Security.Claims;
-using System.Threading.Tasks;
-using Blog.Core.AuthHelper;
+using Blog.Core.AuthHelper;
using Blog.Core.AuthHelper.OverWrite;
using Blog.Core.Common.Helper;
using Blog.Core.IServices;
@@ -12,8 +6,11 @@
using Blog.Core.Model.ViewModels;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using Blog.Core.Common.Swagger;
+
namespace Blog.Core.Controllers
{
@@ -23,14 +20,14 @@ namespace Blog.Core.Controllers
[Produces("application/json")]
[Route("api/Login")]
[AllowAnonymous]
- public class LoginController : Controller
+ public class LoginController : BaseApiController
{
readonly ISysUserInfoServices _sysUserInfoServices;
readonly IUserRoleServices _userRoleServices;
readonly IRoleServices _roleServices;
readonly PermissionRequirement _requirement;
private readonly IRoleModulePermissionServices _roleModulePermissionServices;
-
+ private readonly ILogger _logger;
///
/// 构造函数注入
@@ -40,17 +37,22 @@ public class LoginController : Controller
///
///
///
- public LoginController(ISysUserInfoServices sysUserInfoServices, IUserRoleServices userRoleServices, IRoleServices roleServices, PermissionRequirement requirement, IRoleModulePermissionServices roleModulePermissionServices)
+ ///
+ public LoginController(ISysUserInfoServices sysUserInfoServices, IUserRoleServices userRoleServices,
+ IRoleServices roleServices, PermissionRequirement requirement,
+ IRoleModulePermissionServices roleModulePermissionServices, ILogger logger)
{
this._sysUserInfoServices = sysUserInfoServices;
this._userRoleServices = userRoleServices;
this._roleServices = roleServices;
_requirement = requirement;
_roleModulePermissionServices = roleModulePermissionServices;
+ _logger = logger;
}
#region 获取token的第1种方法
+
///
/// 获取JWT的方法1
///
@@ -63,13 +65,12 @@ public async Task> GetJwtStr(string name, string pass)
{
string jwtStr = string.Empty;
bool suc = false;
- //这里就是用户登陆以后,通过数据库去调取数据,分配权限的操作
+ //这里就是用户登录以后,通过数据库去调取数据,分配权限的操作
var user = await _sysUserInfoServices.GetUserRoleNameStr(name, MD5Helper.MD5Encrypt32(pass));
if (user != null)
{
-
- TokenModelJwt tokenModel = new TokenModelJwt { Uid = 1, Role = user };
+ TokenModelJwt tokenModel = new TokenModelJwt {Uid = 1, Role = user};
jwtStr = JwtHelper.IssueJwt(tokenModel);
suc = true;
@@ -100,7 +101,7 @@ public MessageModel GetJwtStrForNuxt(string name, string pass)
{
string jwtStr = string.Empty;
bool suc = false;
- //这里就是用户登陆以后,通过数据库去调取数据,分配权限的操作
+ //这里就是用户登录以后,通过数据库去调取数据,分配权限的操作
//这里直接写死了
if (name == "admins" && pass == "admins")
{
@@ -117,9 +118,10 @@ public MessageModel GetJwtStrForNuxt(string name, string pass)
{
jwtStr = "login fail!!!";
}
+
var result = new
{
- data = new { success = suc, token = jwtStr }
+ data = new {success = suc, token = jwtStr}
};
return new MessageModel()
@@ -129,8 +131,8 @@ public MessageModel GetJwtStrForNuxt(string name, string pass)
response = jwtStr
};
}
- #endregion
+ #endregion
///
@@ -142,29 +144,30 @@ public MessageModel GetJwtStrForNuxt(string name, string pass)
[HttpGet]
[Route("JWTToken3.0")]
public async Task> GetJwtToken3(string name = "", string pass = "")
+
{
string jwtStr = string.Empty;
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(pass))
- {
- return new MessageModel()
- {
- success = false,
- msg = "用户名或密码不能为空",
- };
- }
+ return Failed("用户名或密码不能为空");
pass = MD5Helper.MD5Encrypt32(pass);
- var user = await _sysUserInfoServices.Query(d => d.uLoginName == name && d.uLoginPWD == pass && d.tdIsDelete == false);
+ var user = await _sysUserInfoServices.Query(d =>
+ d.LoginName == name && d.LoginPWD == pass && d.IsDeleted == false);
if (user.Count > 0)
{
var userRoles = await _sysUserInfoServices.GetUserRoleNameStr(name, pass);
//如果是基于用户的授权策略,这里要添加用户;如果是基于角色的授权策略,这里要添加角色
- var claims = new List {
+ var claims = new List
+ {
new Claim(ClaimTypes.Name, name),
- new Claim(JwtRegisteredClaimNames.Jti, user.FirstOrDefault().uID.ToString()),
- new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
+ new Claim(JwtRegisteredClaimNames.Jti, user.FirstOrDefault().Id.ToString()),
+ new Claim("TenantId", user.FirstOrDefault().TenantId.ToString()),
+ new Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.DateToTimeStamp()),
+ new Claim(ClaimTypes.Expiration,
+ DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString())
+ };
claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
@@ -186,23 +189,22 @@ orderby item.Id
}
var token = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);
- return new MessageModel()
- {
- success = true,
- msg = "获取成功",
- response = token
- };
+ return Success(token, "获取成功");
}
else
{
- return new MessageModel()
- {
- success = false,
- msg = "认证失败",
- };
+ return Failed("认证失败");
}
}
+ [HttpGet]
+ [Route("GetJwtTokenSecret")]
+ public async Task> GetJwtTokenSecret(string name = "", string pass = "")
+ {
+ var rlt = await GetJwtToken3(name, pass);
+ return rlt;
+ }
+
///
/// 请求刷新Token(以旧换新)
///
@@ -215,25 +217,29 @@ public async Task> RefreshToken(string token =
string jwtStr = string.Empty;
if (string.IsNullOrEmpty(token))
- {
- return new MessageModel()
- {
- success = false,
- msg = "token无效,请重新登录!",
- };
- }
+ return Failed("token无效,请重新登录!");
var tokenModel = JwtHelper.SerializeJwt(token);
- if (tokenModel != null && tokenModel.Uid > 0)
+ if (tokenModel != null && JwtHelper.customSafeVerify(token) && tokenModel.Uid > 0)
{
var user = await _sysUserInfoServices.QueryById(tokenModel.Uid);
- if (user != null)
+ var value = User.Claims.SingleOrDefault(s => s.Type == JwtRegisteredClaimNames.Iat)?.Value;
+ if (value != null && user.CriticalModifyTime > value.ObjToDate())
+ {
+ return Failed("很抱歉,授权已失效,请重新授权!");
+ }
+
+ if (user != null && !(value != null && user.CriticalModifyTime > value.ObjToDate()))
{
- var userRoles = await _sysUserInfoServices.GetUserRoleNameStr(user.uLoginName, user.uLoginPWD);
+ var userRoles = await _sysUserInfoServices.GetUserRoleNameStr(user.LoginName, user.LoginPWD);
//如果是基于用户的授权策略,这里要添加用户;如果是基于角色的授权策略,这里要添加角色
- var claims = new List {
- new Claim(ClaimTypes.Name, user.uLoginName),
- new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ObjToString()),
- new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString()) };
+ var claims = new List
+ {
+ new Claim(ClaimTypes.Name, user.LoginName),
+ new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ObjToString()),
+ new Claim(JwtRegisteredClaimNames.Iat, DateTime.Now.DateToTimeStamp()),
+ new Claim(ClaimTypes.Expiration,
+ DateTime.Now.AddSeconds(_requirement.Expiration.TotalSeconds).ToString())
+ };
claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
//用户标识
@@ -241,20 +247,11 @@ public async Task> RefreshToken(string token =
identity.AddClaims(claims);
var refreshToken = JwtToken.BuildJwtToken(claims.ToArray(), _requirement);
- return new MessageModel()
- {
- success = true,
- msg = "获取成功",
- response = refreshToken
- };
+ return Success(refreshToken, "获取成功");
}
}
- return new MessageModel()
- {
- success = false,
- msg = "认证失败!",
- };
+ return Failed("认证失败!");
}
///
@@ -268,7 +265,8 @@ public async Task> RefreshToken(string token =
///
[HttpGet]
[Route("jsonp")]
- public void Getjsonp(string callBack, long id = 1, string sub = "Admin", int expiresSliding = 30, int expiresAbsoulute = 30)
+ public void Getjsonp(string callBack, long id = 1, string sub = "Admin", int expiresSliding = 30,
+ int expiresAbsoulute = 30)
{
TokenModelJwt tokenModel = new TokenModelJwt
{
@@ -295,5 +293,54 @@ public string Md5Password(string password = "")
{
return MD5Helper.MD5Encrypt32(password);
}
+
+ ///
+ /// swagger登录
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Route("/api/Login/swgLogin")]
+ public async Task SwgLogin([FromBody] SwaggerLoginRequest loginRequest)
+ {
+ if (loginRequest is null)
+ {
+ return new {result = false};
+ }
+
+ try
+ {
+ var result = await GetJwtToken3(loginRequest.name, loginRequest.pwd);
+ if (result.success)
+ {
+ HttpContext.SuccessSwagger();
+ HttpContext.SuccessSwaggerJwt(result.response.token);
+ return new {result = true};
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Swagger登录异常");
+ }
+
+ return new {result = false};
+ }
+
+ ///
+ /// weixin登录
+ ///
+ ///
+ [HttpGet]
+ [Route("wxLogin")]
+ public dynamic WxLogin(string g = "", string token = "")
+ {
+ return new {g, token};
+ }
+ }
+
+ public class SwaggerLoginRequest
+ {
+ public string name { get; set; }
+ public string pwd { get; set; }
}
}
\ No newline at end of file
diff --git a/Blog.Core.Api/Controllers/ModuleController.cs b/Blog.Core.Api/Controllers/ModuleController.cs
index a7ad5e58..3b286808 100644
--- a/Blog.Core.Api/Controllers/ModuleController.cs
+++ b/Blog.Core.Api/Controllers/ModuleController.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Linq.Expressions;
-using System.Threading.Tasks;
+using System.Linq.Expressions;
using Blog.Core.Common.HttpContextUser;
using Blog.Core.IServices;
using Blog.Core.Model;
@@ -16,12 +14,12 @@ namespace Blog.Core.Controllers
[Route("api/[controller]/[action]")]
[ApiController]
[Authorize(Permissions.Name)]
- public class ModuleController : ControllerBase
+ public class ModuleController : BaseApiController
{
readonly IModuleServices _moduleServices;
readonly IUser _user;
-
+
public ModuleController(IModuleServices moduleServices, IUser user)
{
_moduleServices = moduleServices;
@@ -36,24 +34,30 @@ public ModuleController(IModuleServices moduleServices, IUser user)
///
// GET: api/User
[HttpGet]
- public async Task>> Get(int page = 1, string key = "")
+ public async Task>> Get(int page = 1, string key = "", int pageSize = 50)
{
if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key))
{
key = "";
}
- int intPageSize = 50;
- Expression> whereExpression = a => a.IsDeleted != true && (a.Name != null && a.Name.Contains(key));
+ Expression> whereExpression = a => a.IsDeleted != true && ((a.Name != null && a.Name.Contains(key) || (a.LinkUrl != null && a.LinkUrl.Contains(key))));
- var data = await _moduleServices.QueryPage(whereExpression, page, intPageSize, " Id desc ");
+ PageModel data = new PageModel();
- return new MessageModel>()
+ if (page == -1)
+ {
+ var modules = await _moduleServices.Query(whereExpression, " Id desc ");
+ data.data = modules;
+ }
+ else
{
- msg = "获取成功",
- success = data.dataCount >= 0,
- response = data
- };
+ data = await _moduleServices.QueryPage(whereExpression, page, pageSize, " Id desc ");
+ }
+
+
+ return Success(data, "获取成功");
+
}
@@ -73,20 +77,11 @@ public string Get(string id)
[HttpPost]
public async Task> Post([FromBody] Modules module)
{
- var data = new MessageModel();
-
module.CreateId = _user.ID;
module.CreateBy = _user.Name;
-
var id = (await _moduleServices.Add(module));
- data.success = id > 0;
- if (data.success)
- {
- data.response = id.ObjToString();
- data.msg = "添加成功";
- }
+ return id > 0 ? Success(id.ObjToString(), "添加成功") : Failed();
- return data;
}
///
@@ -98,18 +93,22 @@ public async Task> Post([FromBody] Modules module)
[HttpPut]
public async Task> Put([FromBody] Modules module)
{
- var data = new MessageModel();
- if (module != null && module.Id > 0)
- {
- data.success = await _moduleServices.Update(module);
- if (data.success)
- {
- data.msg = "更新成功";
- data.response = module?.Id.ObjToString();
- }
- }
-
- return data;
+ //var data = new MessageModel();
+ //if (module != null && module.Id > 0)
+ //{
+ //data.success = await _moduleServices.Update(module);
+ //if (data.success)
+ //{
+ // data.msg = "更新成功";
+ // data.response = module?.Id.ObjToString();
+ //}
+
+ // }
+
+ //return data;
+ if (module == null || module.Id <= 0)
+ return Failed("缺少参数");
+ return await _moduleServices.Update(module) ? Success(module?.Id.ObjToString(), "更新成功") : Failed();
}
///
@@ -119,22 +118,56 @@ public async Task> Put([FromBody] Modules module)
///
// DELETE: api/ApiWithActions/5
[HttpDelete]
- public async Task> Delete(int id)
+ public async Task> Delete(long id)
{
- var data = new MessageModel();
- if (id > 0)
+ if (id <= 0)
+ return Failed("缺少参数");
+ var userDetail = await _moduleServices.QueryById(id);
+ if (userDetail == null)
+ return Failed("信息不存在");
+
+ userDetail.IsDeleted = true;
+ return await _moduleServices.Update(userDetail) ? Success(userDetail?.Id.ObjToString(), "删除成功") : Failed("删除失败");
+
+ //var data = new MessageModel();
+ //if (id > 0)
+ //{
+ // var userDetail = await _moduleServices.QueryById(id);
+ // userDetail.IsDeleted = true;
+ // data.success = await _moduleServices.Update(userDetail);
+ // if (data.success)
+ // {
+ // data.msg = "删除成功";
+ // data.response = userDetail?.Id.ObjToString();
+ // }
+ //}
+ //return data;
+ }
+
+ ///
+ /// 导入多条接口信息
+ ///
+ ///
+ ///
+ // POST: api/User
+ [HttpPost]
+ public async Task> BatchPost([FromBody] List modules)
+ {
+ string ids = string.Empty;
+ int sucCount = 0;
+
+ for (int i = 0; i < modules.Count; i++)
{
- var userDetail = await _moduleServices.QueryById(id);
- userDetail.IsDeleted = true;
- data.success = await _moduleServices.Update(userDetail);
- if (data.success)
+ var module = modules[i];
+ if (module != null)
{
- data.msg = "删除成功";
- data.response = userDetail?.Id.ObjToString();
+ module.CreateId = _user.ID;
+ module.CreateBy = _user.Name;
+ ids += (await _moduleServices.Add(module));
+ sucCount++;
}
}
-
- return data;
+ return ids.IsNotEmptyOrNull() ? Success(ids, $"{sucCount}条数据添加成功") : Failed();
}
}
}
diff --git a/Blog.Core.Api/Controllers/MonitorController.cs b/Blog.Core.Api/Controllers/MonitorController.cs
index 0b31ab31..d707d497 100644
--- a/Blog.Core.Api/Controllers/MonitorController.cs
+++ b/Blog.Core.Api/Controllers/MonitorController.cs
@@ -1,31 +1,38 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
+using Blog.Core.Common;
using Blog.Core.Common.Helper;
using Blog.Core.Common.LogHelper;
using Blog.Core.Hubs;
+using Blog.Core.IServices;
using Blog.Core.Model;
using Blog.Core.Model.ViewModels;
using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
+using Newtonsoft.Json;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Text;
+using Blog.Core.Extensions.Middlewares;
namespace Blog.Core.Controllers
{
[Route("api/[Controller]/[action]")]
[ApiController]
[AllowAnonymous]
- public class MonitorController : Controller
+ public class MonitorController : BaseApiController
{
private readonly IHubContext _hubContext;
private readonly IWebHostEnvironment _env;
+ private readonly IApplicationUserServices _applicationUserServices;
+ private readonly ILogger _logger;
- public MonitorController(IHubContext hubContext, IWebHostEnvironment env)
+ public MonitorController(IHubContext hubContext, IWebHostEnvironment env,
+ IApplicationUserServices applicationUserServices, ILogger logger)
{
- _hubContext = hubContext;
- _env = env;
+ _hubContext = hubContext;
+ _env = env;
+ _applicationUserServices = applicationUserServices;
+ _logger = logger;
}
///