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 群 - -群1 -群2 - - -## 微信公众号 - -公众号 - - 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` 中,配置登录授权: - -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` 管理器中,搜索到: -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)。 - -usermanager - - - -### 2、接口菜单权限管理部分[必须] - -主要是四个表:分别对应接口表(Module)、菜单表(Permission)、接口菜单关系表(ModulePermission)暂时没用到、角色接口菜单关系表(RoleModulePermission)。 - -permissionmanager - - - - -### 3、博客文章管理部分[可选] -主要是三个表:分别对应博客表(BlogArticle)、Bug专题表(Topic)、Bug内容表(TopicDetail)。 - -blogmanager - - - - -### 4、其他不重要部分 - -主要是三个表:分别对应Job调度表(TasksQz)、密码库表(PasswordLib)、操作日志表(OperateLog)、广告表(Advertisement)、公告表(Guestbook)。 - -othersmanager - - - - - - -## 二、日志记录 - -本框架涵盖了不同领域的日志记录,共五个,分别是: - -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; } /// @@ -35,21 +42,16 @@ public MonitorController(IHubContext hubContext, IWebHostEnvironment en [HttpGet] public MessageModel Server() { - return new MessageModel() + return Success(new ServerViewModel() { - msg = "获取成功", - success = true, - response = new ServerViewModel() - { - EnvironmentName = _env.EnvironmentName, - OSArchitecture = RuntimeInformation.OSArchitecture.ObjToString(), - ContentRootPath = _env.ContentRootPath, - WebRootPath = _env.WebRootPath, - FrameworkDescription = RuntimeInformation.FrameworkDescription, - MemoryFootprint = (Process.GetCurrentProcess().WorkingSet64 / 1048576).ToString("N2") + " MB", - WorkingTime = DateHelper.TimeSubTract(DateTime.Now, Process.GetCurrentProcess().StartTime) - } - }; + EnvironmentName = _env.EnvironmentName, + OSArchitecture = RuntimeInformation.OSArchitecture.ObjToString(), + ContentRootPath = _env.ContentRootPath, + WebRootPath = _env.WebRootPath, + FrameworkDescription = RuntimeInformation.FrameworkDescription, + MemoryFootprint = (Process.GetCurrentProcess().WorkingSet64 / 1048576).ToString("N2") + " MB", + WorkingTime = DateHelper.TimeSubTract(DateTime.Now, Process.GetCurrentProcess().StartTime) + }, "获取服务器配置信息成功"); } @@ -61,53 +63,218 @@ public MessageModel Server() [HttpGet] public MessageModel> Get() { - - _hubContext.Clients.All.SendAsync("ReceiveUpdate", LogLock.GetLogData()).Wait(); - - return new MessageModel>() + if (AppSettings.app(new string[] { "Middleware", "SignalRSendLog", "Enabled" }).ObjToBool()) { - msg = "获取成功", - success = true, - response = null - }; - } + _hubContext.Clients.All.SendAsync("ReceiveUpdate", "执行成功").Wait(); + } + return Success>(null, "执行成功"); + } [HttpGet] public MessageModel GetRequestApiinfoByWeek() { - return new MessageModel() - { - msg = "获取成功", - success = true, - response = LogLock.RequestApiinfoByWeek() - }; + //后续补充扩展Log + return Success(new RequestApiWeekView(), "成功"); } [HttpGet] public MessageModel GetAccessApiByDate() { - return new MessageModel() - { - msg = "获取成功", - success = true, - response = LogLock.AccessApiByDate() - }; + //return new MessageModel() + //{ + // msg = "获取成功", + // success = true, + // response = LogLock.AccessApiByDate() + //}; + + //后续补充扩展Log + return Success(new AccessApiDateView(), "获取成功"); } [HttpGet] public MessageModel GetAccessApiByHour() { - return new MessageModel() + //return new MessageModel() + //{ + // msg = "获取成功", + // success = true, + // response = LogLock.AccessApiByHour() + //}; + + //后续补充扩展Log + return Success(new AccessApiDateView(), "获取成功"); + } + + private List GetAccessLogsToday(IWebHostEnvironment environment) + { + List userAccessModels = new(); + //后续补充扩展Log + // var accessLogs = LogLock.ReadLog( + // Path.Combine(environment.ContentRootPath, "Log"), "RecordAccessLogs_", Encoding.UTF8, + // ReadType.PrefixLatest + // ).ObjToString(); + // try + // { + // return JsonConvert.DeserializeObject>("[" + accessLogs + "]"); + // } + // catch (Exception) + // { + // var accLogArr = accessLogs.Split("\n"); + // foreach (var item in accLogArr) + // { + // if (item.ObjToString() != "") + // { + // try + // { + // var accItem = JsonConvert.DeserializeObject(item.TrimEnd(',')); + // userAccessModels.Add(accItem); + // } + // catch (Exception) + // { + // } + // } + // } + // } + + return userAccessModels; + } + + private List GetAccessLogsTrend(IWebHostEnvironment environment) + { + List userAccessModels = new(); + //后续补充扩展Log + // var accessLogs = LogLock.ReadLog( + // Path.Combine(environment.ContentRootPath, "Log"), "ACCESSTRENDLOG_", Encoding.UTF8, + // ReadType.PrefixLatest + // ).ObjToString(); + // try + // { + // return JsonConvert.DeserializeObject>(accessLogs); + // } + // catch (Exception) + // { + // var accLogArr = accessLogs.Split("\n"); + // foreach (var item in accLogArr) + // { + // if (item.ObjToString() != "") + // { + // try + // { + // var accItem = JsonConvert.DeserializeObject(item.TrimStart('[').TrimEnd(']')); + // userAccessModels.Add(accItem); + // } + // catch (Exception) + // { + // } + // } + // } + // } + + return userAccessModels; + } + + [HttpGet] + public MessageModel GetActiveUsers([FromServices] IWebHostEnvironment environment) + { + var accessLogsToday = GetAccessLogsToday(environment).Where(d => d.BeginTime.ObjToDate() >= DateTime.Today); + + var Logs = accessLogsToday.OrderByDescending(d => d.BeginTime).Take(50).ToList(); + + accessLogsToday = accessLogsToday.Where(d => d.User != "").ToList(); + + var activeUsers = (from n in accessLogsToday + group n by new { n.User } + into g + select new ActiveUserVM + { + user = g.Key.User, + count = g.Count(), + }).ToList(); + + int activeUsersCount = activeUsers.Count; + activeUsers = activeUsers.OrderByDescending(d => d.count).Take(10).ToList(); + + //return new MessageModel() + //{ + // msg = "获取成功", + // success = true, + // response = new WelcomeInitData() + // { + // activeUsers = activeUsers, + // activeUserCount = activeUsersCount, + // errorCount = errorCountToday, + // logs = Logs, + // activeCount = GetAccessLogsTrend(environment) + // } + //}; + + return Success(new WelcomeInitData() { - msg = "获取成功", - success = true, - response = LogLock.AccessApiByHour() - }; + activeUsers = activeUsers, + activeUserCount = activeUsersCount, + errorCount = default, + logs = Logs, + activeCount = GetAccessLogsTrend(environment) + }, "获取成功"); } - } + [HttpGet] + public async Task> GetIds4Users() + { + List apiDates = new List(); + + if (_applicationUserServices.IsEnable()) + { + var users = await _applicationUserServices.Query(d => d.tdIsDelete == false); + + apiDates = (from n in users + group n by new { n.birth.Date } + into g + select new ApiDate + { + date = g.Key?.Date.ToString("yyyy-MM-dd"), + count = g.Count(), + }).ToList(); + + apiDates = apiDates.OrderByDescending(d => d.date).Take(30).ToList(); + } + + + if (apiDates.Count == 0) + { + apiDates.Add(new ApiDate() + { + date = "没数据,或未开启相应接口服务", + count = 0 + }); + } + //return new MessageModel() + //{ + // msg = "获取成功", + // success = true, + // response = new AccessApiDateView + // { + // columns = new string[] { "date", "count" }, + // rows = apiDates.OrderBy(d => d.date).ToList(), + // } + //}; + return Success(new AccessApiDateView + { + columns = new string[] { "date", "count" }, + rows = apiDates.OrderBy(d => d.date).ToList(), + }, "获取成功"); + } + } -} + public class WelcomeInitData + { + public List activeUsers { get; set; } + public int activeUserCount { get; set; } + public List logs { get; set; } + public int errorCount { get; set; } + public List activeCount { get; set; } + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/NacosController.cs b/Blog.Core.Api/Controllers/NacosController.cs new file mode 100644 index 00000000..e5223851 --- /dev/null +++ b/Blog.Core.Api/Controllers/NacosController.cs @@ -0,0 +1,140 @@ +using Blog.Core.Common.Helper; +using Blog.Core.Controllers; +using Blog.Core.Model; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Nacos.V2; + +namespace Blog.Core.Api.Controllers +{ + /// + /// 服务管理 + /// + [Produces("application/json")] + [Route("api/[Controller]/[action]")] + [Authorize(Permissions.Name)] + public class NacosController : BaseApiController + { + + #region 变量 + + /// + /// INacosNamingService + /// + private readonly INacosNamingService NacosNamingService; + + #endregion + + #region 重载 + /// + /// + /// + /// + public NacosController(INacosNamingService nacosNamingService) + { + NacosNamingService = nacosNamingService; + } + + #endregion + + + /// + /// 系统实例是否启动完成 + /// + /// + [HttpGet] + + public MessageModel CheckSystemStartFinish() + { + //********************* 用当前接口做基本健康检查 确定 基础服务 数据库 缓存都已正常启动***** + // 然后再进行服务上线 + var data = new MessageModel(); + // *************** 此处请求一下db 跟redis连接等 项目中简介 保证项目已全部启动 + data.success = true; + data.msg = "SUCCESS"; + return data; + + } + + + /// + /// 获取Nacos 状态 + /// + /// + [HttpGet] + public async Task> GetStatus() + { + var data = new MessageModel(); + var instances = await NacosNamingService.GetAllInstances(JsonConfigSettings.NacosServiceName); + if (instances == null || instances.Count == 0) + { + data.status = 406; + data.msg = "DOWN"; + data.success = false; + return data; + } + // 获取当前程序IP + var currentIp = IpHelper.GetCurrentIp(null); + bool isUp = false; + instances.ForEach(item => + { + if (item.Ip == currentIp) + isUp = true; + }); + // var baseUrl = await NacosNamingService.GetServerStatus(); + if (isUp) + { + data.status = 200; + data.msg = "UP"; + data.success = true; + return data; + } + else + { + data.status = 406; + data.msg = "DOWN"; + data.success = false; + return data; + } + } + + /// + /// 服务上线 + /// + /// + + [HttpGet] + public async Task> Register() + { + var data = new MessageModel(); + var instance = new Nacos.V2.Naming.Dtos.Instance() + { + ServiceName = JsonConfigSettings.NacosServiceName, + ClusterName = Nacos.V2.Common.Constants.DEFAULT_CLUSTER_NAME, + Ip = IpHelper.GetCurrentIp(null), + Port = JsonConfigSettings.NacosPort, + Enabled = true, + Weight = 100, + Metadata = JsonConfigSettings.NacosMetadata + }; + await NacosNamingService.RegisterInstance(JsonConfigSettings.NacosServiceName, Nacos.V2.Common.Constants.DEFAULT_GROUP, instance); + data.success = true; + data.msg = "SUCCESS"; + return data; + } + + /// + /// 服务下线 + /// + /// + [HttpGet] + public async Task> Deregister() + { + var data = new MessageModel(); + await NacosNamingService.DeregisterInstance(JsonConfigSettings.NacosServiceName, Nacos.V2.Common.Constants.DEFAULT_GROUP, IpHelper.GetCurrentIp(null), JsonConfigSettings.NacosPort); + data.success = true; + data.msg = "SUCCESS"; + return data; + } + } +} diff --git a/Blog.Core.Api/Controllers/PayController.cs b/Blog.Core.Api/Controllers/PayController.cs new file mode 100644 index 00000000..6c05c249 --- /dev/null +++ b/Blog.Core.Api/Controllers/PayController.cs @@ -0,0 +1,101 @@ +using Blog.Core.IServices; +using Blog.Core.Model; +using Blog.Core.Model.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Controllers +{ + /// + /// 建行聚合支付类 + /// + [Produces("application/json")] + [Route("api/Pay")] + [Authorize(Permissions.Name)] + public class PayController : Controller + { + private readonly ILogger _logger; + private readonly IPayServices _payServices; + /// + /// 构造函数 + /// + /// + /// + public PayController(ILogger logger, IPayServices payServices) + { + _logger = logger; + _payServices = payServices; + } + /// + /// 被扫支付 + /// + /// + /// + [HttpGet] + [Route("Pay")] + public async Task> PayGet([FromQuery]PayNeedModel payModel) + { + return await _payServices.Pay(payModel); + } + /// + /// 被扫支付 + /// + /// + /// + [HttpPost] + [Route("Pay")] + public async Task> PayPost([FromBody]PayNeedModel payModel) + { + return await _payServices.Pay(payModel); + } + /// + /// 支付结果查询-轮询 + /// + /// + /// + [HttpGet] + [Route("PayCheck")] + public async Task> PayCheckGet([FromQuery]PayNeedModel payModel) + { + return await _payServices.PayCheck(payModel, 1); + } + /// + /// 支付结果查询-轮询 + /// + /// + /// + [HttpPost] + [Route("PayCheck")] + public async Task> PayCheckPost([FromBody]PayNeedModel payModel) + { + return await _payServices.PayCheck(payModel, 1); + } + /// + /// 退款 + /// + /// + /// + [HttpGet] + [Route("PayRefund")] + public async Task> PayRefundGet([FromQuery]PayRefundNeedModel payModel) + { + return await _payServices.PayRefund(payModel); + } + /// + /// 退款 + /// + /// + /// + [HttpPost] + [Route("PayRefund")] + public async Task> PayRefundPost([FromBody]PayRefundNeedModel payModel) + { + return await _payServices.PayRefund(payModel); + } + + + + + + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/PermissionController.cs b/Blog.Core.Api/Controllers/PermissionController.cs index f0003530..ccdb3dc4 100644 --- a/Blog.Core.Api/Controllers/PermissionController.cs +++ b/Blog.Core.Api/Controllers/PermissionController.cs @@ -1,17 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Blog.Core.AuthHelper; +using Blog.Core.AuthHelper; using Blog.Core.AuthHelper.OverWrite; +using Blog.Core.Common; using Blog.Core.Common.Helper; using Blog.Core.Common.HttpContextUser; using Blog.Core.IServices; using Blog.Core.Model; using Blog.Core.Model.Models; +using Blog.Core.Repository.UnitOfWorks; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Security.Claims; namespace Blog.Core.Controllers { @@ -21,12 +21,14 @@ namespace Blog.Core.Controllers [Route("api/[controller]/[action]")] [ApiController] [Authorize(Permissions.Name)] - public class PermissionController : ControllerBase + public class PermissionController : BaseApiController { + readonly IUnitOfWorkManage _unitOfWorkManage; readonly IPermissionServices _permissionServices; readonly IModuleServices _moduleServices; readonly IRoleModulePermissionServices _roleModulePermissionServices; readonly IUserRoleServices _userRoleServices; + private readonly IHttpClientFactory _httpClientFactory; readonly IHttpContextAccessor _httpContext; readonly IUser _user; private readonly PermissionRequirement _requirement; @@ -38,15 +40,23 @@ public class PermissionController : ControllerBase /// /// /// + /// + /// /// /// /// - public PermissionController(IPermissionServices permissionServices, IModuleServices moduleServices, IRoleModulePermissionServices roleModulePermissionServices, IUserRoleServices userRoleServices, IHttpContextAccessor httpContext, IUser user, PermissionRequirement requirement) + public PermissionController(IPermissionServices permissionServices, IModuleServices moduleServices, + IRoleModulePermissionServices roleModulePermissionServices, IUserRoleServices userRoleServices, + IUnitOfWorkManage unitOfWorkManage, + IHttpClientFactory httpClientFactory, + IHttpContextAccessor httpContext, IUser user, PermissionRequirement requirement) { _permissionServices = permissionServices; + _unitOfWorkManage = unitOfWorkManage; _moduleServices = moduleServices; _roleModulePermissionServices = roleModulePermissionServices; _userRoleServices = userRoleServices; + this._httpClientFactory = httpClientFactory; _httpContext = httpContext; _user = user; _requirement = requirement; @@ -57,34 +67,19 @@ public PermissionController(IPermissionServices permissionServices, IModuleServi /// /// /// + /// /// // 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) { PageModel permissions = new PageModel(); - int intPageSize = 50; if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key)) { key = ""; } - #region 舍弃 - //var permissions = await _permissionServices.Query(a => a.IsDeleted != true); - //if (!string.IsNullOrEmpty(key)) - //{ - // permissions = permissions.Where(t => (t.Name != null && t.Name.Contains(key))).ToList(); - //} - ////筛选后的数据总数 - //totalCount = permissions.Count; - ////筛选后的总页数 - //pageCount = (Math.Ceiling(totalCount.ObjToDecimal() / intTotalCount.ObjToDecimal())).ObjToInt(); - //permissions = permissions.OrderByDescending(d => d.Id).Skip((page - 1) * intTotalCount).Take(intTotalCount).ToList(); - #endregion - - - - permissions = await _permissionServices.QueryPage(a => a.IsDeleted != true && (a.Name != null && a.Name.Contains(key)), page, intPageSize, " Id desc "); + permissions = await _permissionServices.QueryPage(a => a.IsDeleted != true && (a.Name != null && a.Name.Contains(key)), page, pageSize, " Id desc "); #region 单独处理 @@ -95,7 +90,7 @@ public async Task>> Get(int page = 1, string var permissionAll = await _permissionServices.Query(d => d.IsDeleted != true); foreach (var item in permissionsView) { - List pidarr = new List + List pidarr = new() { item.Pid }; @@ -133,12 +128,14 @@ public async Task>> Get(int page = 1, string #endregion - return new MessageModel>() - { - msg = "获取成功", - success = permissions.dataCount >= 0, - response = permissions - }; + //return new MessageModel>() + //{ + // msg = "获取成功", + // success = permissions.dataCount >= 0, + // response = permissions + //}; + + return permissions.dataCount >= 0 ? Success(permissions, "获取成功") : Failed>("获取失败"); } @@ -150,7 +147,7 @@ public async Task>> Get(int page = 1, string /// [HttpGet] [AllowAnonymous] - public async Task>> GetTreeTable(int f = 0, string key = "") + public async Task>> GetTreeTable(long f = 0, string key = "") { List permissions = new List(); var apiList = await _moduleServices.Query(d => d.IsDeleted == false); @@ -171,7 +168,7 @@ public async Task>> GetTreeTable(int f = 0, string foreach (var item in permissions) { - List pidarr = new List { }; + List pidarr = new() { }; var parent = permissionsList.FirstOrDefault(d => d.Id == item.Pid); while (parent != null) @@ -191,19 +188,13 @@ public async Task>> GetTreeTable(int f = 0, string } - return new MessageModel>() - { - msg = "获取成功", - success = permissions.Count >= 0, - response = permissions - }; - } - - // GET: api/User/5 - [HttpGet("{id}")] - public string Get(string id) - { - return "value"; + //return new MessageModel>() + //{ + // msg = "获取成功", + // success = true, + // response = permissions + //}; + return Success(permissions, "获取成功"); } /// @@ -215,20 +206,21 @@ public string Get(string id) [HttpPost] public async Task> Post([FromBody] Permission permission) { - var data = new MessageModel(); + //var data = new MessageModel(); permission.CreateId = _user.ID; permission.CreateBy = _user.Name; var id = (await _permissionServices.Add(permission)); - data.success = id > 0; - if (data.success) - { - data.response = id.ObjToString(); - data.msg = "添加成功"; - } + //data.success = id > 0; + //if (data.success) + //{ + // data.response = id.ObjToString(); + // data.msg = "添加成功"; + //} - return data; + + return id > 0 ? Success(id.ObjToString(), "添加成功") : Failed("添加失败"); } /// @@ -239,57 +231,55 @@ public async Task> Post([FromBody] Permission permission) [HttpPost] public async Task> Assign([FromBody] AssignView assignView) { - var data = new MessageModel(); - - try + if (assignView.rid > 0) { - if (assignView.rid > 0) + //开启事务 + try { - data.success = true; + var old_rmps = await _roleModulePermissionServices.Query(d => d.RoleId == assignView.rid); - var roleModulePermissions = await _roleModulePermissionServices.Query(d => d.RoleId == assignView.rid); - - var remove = roleModulePermissions.Where(d => !assignView.pids.Contains(d.PermissionId.ObjToInt())).Select(c => (object)c.Id); - data.success &= remove.Any() ? await _roleModulePermissionServices.DeleteByIds(remove.ToArray()) : true; + _unitOfWorkManage.BeginTran(); + await _permissionServices.Db.Deleteable(t => t.RoleId == assignView.rid).ExecuteCommandAsync(); + var permissions = await _permissionServices.Query(d => d.IsDeleted == false); + List new_rmps = new List(); + var nowTime = _permissionServices.Db.GetDate(); foreach (var item in assignView.pids) { - var rmpitem = roleModulePermissions.Where(d => d.PermissionId == item); - if (!rmpitem.Any()) - { - var moduleid = (await _permissionServices.Query(p => p.Id == item)).FirstOrDefault()?.Mid; - RoleModulePermission roleModulePermission = new RoleModulePermission() - { - IsDeleted = false, - RoleId = assignView.rid, - ModuleId = moduleid.ObjToInt(), - PermissionId = item, - }; - + var moduleid = permissions.Find(p => p.Id == item)?.Mid; + var find_old_rmps = old_rmps.Find(p => p.PermissionId == item); - roleModulePermission.CreateId = _user.ID; - roleModulePermission.CreateBy = _user.Name; - - data.success &= (await _roleModulePermissionServices.Add(roleModulePermission)) > 0; - - } - } + RoleModulePermission roleModulePermission = new RoleModulePermission() + { + IsDeleted = false, + RoleId = assignView.rid, + ModuleId = moduleid.ObjToLong(), + PermissionId = item, + CreateId = find_old_rmps == null ? _user.ID : find_old_rmps.CreateId, + CreateBy = find_old_rmps == null ? _user.Name : find_old_rmps.CreateBy, + CreateTime = find_old_rmps == null ? nowTime : find_old_rmps.CreateTime, + ModifyId = _user.ID, + ModifyBy = _user.Name, + ModifyTime = nowTime - if (data.success) - { - _requirement.Permissions.Clear(); - data.response = ""; - data.msg = "保存成功"; + }; + new_rmps.Add(roleModulePermission); } - + if (new_rmps.Count > 0) await _roleModulePermissionServices.Add(new_rmps); + _unitOfWorkManage.CommitTran(); + } + catch (Exception) + { + _unitOfWorkManage.RollbackTran(); + throw; } + _requirement.Permissions.Clear(); + return Success("保存成功"); } - catch (Exception) + else { - data.success = false; + return Failed("请选择要操作的角色"); } - - return data; } @@ -300,9 +290,9 @@ public async Task> Assign([FromBody] AssignView assignView) /// /// [HttpGet] - public async Task> GetPermissionTree(int pid = 0, bool needbtn = false) + public async Task> GetPermissionTree(long pid = 0, bool needbtn = false) { - var data = new MessageModel(); + //var data = new MessageModel(); var permissions = await _permissionServices.Query(d => d.IsDeleted == false); var permissionTrees = (from child in permissions @@ -328,14 +318,15 @@ orderby child.Id RecursionHelper.LoopToAppendChildren(permissionTrees, rootRoot, pid, needbtn); - data.success = true; - if (data.success) - { - data.response = rootRoot; - data.msg = "获取成功"; - } + //data.success = true; + //if (data.success) + //{ + // data.response = rootRoot; + // data.msg = "获取成功"; + //} - return data; + return Success(rootRoot, "获取成功"); + //return data; } /// @@ -344,29 +335,41 @@ orderby child.Id /// /// [HttpGet] - public async Task> GetNavigationBar(int uid) + public async Task> GetNavigationBar(long uid) { var data = new MessageModel(); - var uidInHttpcontext1 = 0; - var roleIds = new List(); + long uidInHttpcontext1 = 0; + var roleIds = new List(); // ids4和jwt切换 if (Permissions.IsUseIds4) { // ids4 uidInHttpcontext1 = (from item in _httpContext.HttpContext.User.Claims - where item.Type == "sub" - select item.Value).FirstOrDefault().ObjToInt(); + where item.Type == ClaimTypes.NameIdentifier + select item.Value).FirstOrDefault().ObjToLong(); + if (!(uidInHttpcontext1 > 0)) + { + uidInHttpcontext1 = (from item in _httpContext.HttpContext.User.Claims + where item.Type == "sub" + select item.Value).FirstOrDefault().ObjToLong(); + } roleIds = (from item in _httpContext.HttpContext.User.Claims - where item.Type == "role" - select item.Value.ObjToInt()).ToList(); + where item.Type == ClaimTypes.Role + select item.Value.ObjToLong()).ToList(); + if (!roleIds.Any()) + { + roleIds = (from item in _httpContext.HttpContext.User.Claims + where item.Type == "role" + select item.Value.ObjToLong()).ToList(); + } } else { // jwt - uidInHttpcontext1 = ((JwtHelper.SerializeJwt(_httpContext.HttpContext.Request.Headers["Authorization"].ObjToString().Replace("Bearer ", "")))?.Uid).ObjToInt(); - roleIds = (await _userRoleServices.Query(d => d.IsDeleted == false && d.UserId == uid)).Select(d => d.RoleId.ObjToInt()).Distinct().ToList(); + uidInHttpcontext1 = ((JwtHelper.SerializeJwt(_httpContext.HttpContext.Request.Headers["Authorization"].ObjToString().Replace("Bearer ", "")))?.Uid).ObjToLong(); + roleIds = (await _userRoleServices.Query(d => d.IsDeleted == false && d.UserId == uid)).Select(d => d.RoleId.ObjToLong()).Distinct().ToList(); } @@ -374,10 +377,11 @@ public async Task> GetNavigationBar(int uid) { if (roleIds.Any()) { - var pids = (await _roleModulePermissionServices.Query(d => d.IsDeleted == false && roleIds.Contains(d.RoleId))).Select(d => d.PermissionId.ObjToInt()).Distinct(); + var pids = (await _roleModulePermissionServices.Query(d => d.IsDeleted == false && roleIds.Contains(d.RoleId))).Select(d => d.PermissionId.ObjToLong()).Distinct(); if (pids.Any()) { var rolePermissionMoudles = (await _permissionServices.Query(d => pids.Contains(d.Id))).OrderBy(c => c.OrderSort); + var temp = rolePermissionMoudles.ToList().Find(t => t.Id == 87); var permissionTrees = (from child in rolePermissionMoudles where child.IsDeleted == false orderby child.Id @@ -394,6 +398,7 @@ orderby child.Id IsButton = child.IsButton.ObjToBool(), meta = new NavigationBarMeta { + icon = child.IconNew, requireAuth = true, title = child.Name, NoTabPage = child.IsHide.ObjToBool(), @@ -415,7 +420,6 @@ orderby child.Id }; permissionTrees = permissionTrees.OrderBy(d => d.order).ToList(); - RecursionHelper.LoopNaviBarAppendChildren(permissionTrees, rootRoot); data.success = true; @@ -431,20 +435,108 @@ orderby child.Id } /// - /// 通过角色获取菜单【无权限】 + /// 获取路由树 + /// + /// + /// + [HttpGet] + public async Task>> GetNavigationBarPro(long uid) + { + var data = new MessageModel>(); + + long uidInHttpcontext1 = 0; + var roleIds = new List(); + // ids4和jwt切换 + if (Permissions.IsUseIds4) + { + // ids4 + uidInHttpcontext1 = (from item in _httpContext.HttpContext.User.Claims + where item.Type == ClaimTypes.NameIdentifier + select item.Value).FirstOrDefault().ObjToLong(); + if (!(uidInHttpcontext1 > 0)) + { + uidInHttpcontext1 = (from item in _httpContext.HttpContext.User.Claims + where item.Type == "sub" + select item.Value).FirstOrDefault().ObjToLong(); + } + roleIds = (from item in _httpContext.HttpContext.User.Claims + where item.Type == ClaimTypes.Role + select item.Value.ObjToLong()).ToList(); + if (!roleIds.Any()) + { + roleIds = (from item in _httpContext.HttpContext.User.Claims + where item.Type == "role" + select item.Value.ObjToLong()).ToList(); + } + } + else + { + // jwt + uidInHttpcontext1 = ((JwtHelper.SerializeJwt(_httpContext.HttpContext.Request.Headers["Authorization"].ObjToString().Replace("Bearer ", "")))?.Uid).ObjToLong(); + roleIds = (await _userRoleServices.Query(d => d.IsDeleted == false && d.UserId == uid)).Select(d => d.RoleId.ObjToLong()).Distinct().ToList(); + } + + if (uid > 0 && uid == uidInHttpcontext1) + { + if (roleIds.Any()) + { + var pids = (await _roleModulePermissionServices.Query(d => d.IsDeleted == false && roleIds.Contains(d.RoleId))) + .Select(d => d.PermissionId.ObjToLong()).Distinct(); + if (pids.Any()) + { + var rolePermissionMoudles = (await _permissionServices.Query(d => pids.Contains(d.Id) && d.IsButton == false)).OrderBy(c => c.OrderSort); + var permissionTrees = (from item in rolePermissionMoudles + where item.IsDeleted == false + orderby item.Id + select new NavigationBarPro + { + id = item.Id, + name = item.Name, + parentId = item.Pid, + order = item.OrderSort, + path = item.Code == "-" ? item.Name.GetTotalPingYin().FirstOrDefault() : (item.Code == "/" ? "/dashboard/workplace" : item.Code), + component = item.Pid == 0 ? (item.Code == "/" ? "dashboard/Workplace" : "RouteView") : item.Code?.TrimStart('/'), + iconCls = item.Icon, + Func = item.Func, + IsHide = item.IsHide.ObjToBool(), + IsButton = item.IsButton.ObjToBool(), + meta = new NavigationBarMetaPro + { + show = true, + title = item.Name, + icon = "user"//item.Icon + } + }).ToList(); + + permissionTrees = permissionTrees.OrderBy(d => d.order).ToList(); + + data.success = true; + if (data.success) + { + data.response = permissionTrees; + data.msg = "获取成功"; + } + } + } + } + return data; + } + + /// + /// 通过角色获取菜单 /// /// /// [HttpGet] [AllowAnonymous] - public async Task> GetPermissionIdByRoleId(int rid = 0) + public async Task> GetPermissionIdByRoleId(long rid = 0) { - var data = new MessageModel(); + //var data = new MessageModel(); var rmps = await _roleModulePermissionServices.Query(d => d.IsDeleted == false && d.RoleId == rid); var permissionTrees = (from child in rmps orderby child.Id - select child.PermissionId.ObjToInt()).ToList(); + select child.PermissionId.ObjToLong()).ToList(); var permissions = await _permissionServices.Query(d => d.IsDeleted == false); List assignbtns = new List(); @@ -454,22 +546,29 @@ orderby child.Id var pername = permissions.FirstOrDefault(d => d.IsButton && d.Id == item)?.Name; if (!string.IsNullOrEmpty(pername)) { - assignbtns.Add(pername + "_" + item); + //assignbtns.Add(pername + "_" + item); + assignbtns.Add(item.ObjToString()); } } - data.success = true; - if (data.success) + //data.success = true; + //if (data.success) + //{ + // data.response = new AssignShow() + // { + // permissionids = permissionTrees, + // assignbtns = assignbtns, + // }; + // data.msg = "获取成功"; + //} + + return Success(new AssignShow() { - data.response = new AssignShow() - { - permissionids = permissionTrees, - assignbtns = assignbtns, - }; - data.msg = "获取成功"; - } + permissionids = permissionTrees, + assignbtns = assignbtns, + }, "获取成功"); - return data; + //return data; } /// @@ -485,6 +584,7 @@ public async Task> Put([FromBody] Permission permission) if (permission != null && permission.Id > 0) { data.success = await _permissionServices.Update(permission); + await _roleModulePermissionServices.UpdateModuleId(permission.Id, permission.Mid); if (data.success) { data.msg = "更新成功"; @@ -502,7 +602,7 @@ public async Task> Put([FromBody] Permission permission) /// // DELETE: api/ApiWithActions/5 [HttpDelete] - public async Task> Delete(int id) + public async Task> Delete(long id) { var data = new MessageModel(); if (id > 0) @@ -519,16 +619,180 @@ public async Task> Delete(int id) return data; } + + /// + /// 导入多条菜单信息 + /// + /// + /// + // POST: api/User + [HttpPost] + public async Task> BatchPost([FromBody] List permissions) + { + var data = new MessageModel(); + string ids = string.Empty; + int sucCount = 0; + + for (int i = 0; i < permissions.Count; i++) + { + var permission = permissions[i]; + if (permission != null) + { + permission.CreateId = _user.ID; + permission.CreateBy = _user.Name; + ids += (await _permissionServices.Add(permission)); + sucCount++; + } + } + + data.success = ids.IsNotEmptyOrNull(); + if (data.success) + { + data.response = ids; + data.msg = $"{sucCount}条数据添加成功"; + } + + return data; + } + + /// + /// 系统接口菜单同步接口 + /// + /// + [HttpGet] + public async Task>> MigratePermission(string action = "", string token = "", string gatewayPrefix = "", string swaggerDomain = "", string controllerName = "", long pid = 0, bool isAction = false) + { + var data = new MessageModel>(); + if (controllerName.IsNullOrEmpty()) + { + data.msg = "必须填写要迁移的所属接口的控制器名称"; + return data; + } + + controllerName = controllerName.TrimEnd('/').ToLower(); + + gatewayPrefix = gatewayPrefix.Trim(); + swaggerDomain = swaggerDomain.Trim(); + controllerName = controllerName.Trim(); + + using var client = _httpClientFactory.CreateClient(); + var Configuration = swaggerDomain.IsNotEmptyOrNull() ? swaggerDomain : AppSettings.GetValue("SystemCfg:Domain"); + var url = $"{Configuration}/swagger/V2/swagger.json"; + if (Configuration.IsNullOrEmpty()) + { + data.msg = "Swagger.json在线文件域名不能为空"; + return data; + } + if (token.IsNullOrEmpty()) token = Request.Headers.Authorization; + token = token.Trim(); + client.DefaultRequestHeaders.Add("Authorization", $"{token}"); + + var response = await client.GetAsync(url); + var body = await response.Content.ReadAsStringAsync(); + + var resultJObj = (JObject)JsonConvert.DeserializeObject(body); + var paths = resultJObj["paths"].ObjToString(); + var pathsJObj = (JObject)JsonConvert.DeserializeObject(paths); + + List permissions = new List(); + foreach (JProperty jProperty in pathsJObj.Properties()) + { + var apiPath = gatewayPrefix + jProperty.Name.ToLower(); + if (action.IsNotEmptyOrNull()) + { + action = action.Trim(); + if (!apiPath.Contains(action.ToLower())) + { + continue; + } + } + string httpmethod = ""; + if (jProperty.Value.ToString().ToLower().Contains("get")) + { + httpmethod = "get"; + } + else if (jProperty.Value.ToString().ToLower().Contains("post")) + { + httpmethod = "post"; + } + else if (jProperty.Value.ToString().ToLower().Contains("put")) + { + httpmethod = "put"; + } + else if (jProperty.Value.ToString().ToLower().Contains("delete")) + { + httpmethod = "delete"; + } + + var summary = jProperty.Value?.SelectToken($"{httpmethod}.summary")?.ObjToString() ?? ""; + + var subIx = summary.IndexOf("(Auth"); + if (subIx >= 0) + { + summary = summary.Substring(0, subIx); + } + + permissions.Add(new Permission() + { + Code = " ", + Name = summary, + IsButton = true, + IsHide = false, + Enabled = true, + CreateTime = DateTime.Now, + IsDeleted = false, + Pid = pid, + Module = new Modules() + { + LinkUrl = apiPath ?? "", + Name = summary, + Enabled = true, + CreateTime = DateTime.Now, + ModifyTime = DateTime.Now, + IsDeleted = false, + } + }); + } + + var modulesList = (await _moduleServices.Query(d => d.IsDeleted == false && d.LinkUrl != null)).Select(d => d.LinkUrl.ToLower()).ToList(); + permissions = permissions.Where(d => !modulesList.Contains(d.Module.LinkUrl.ToLower()) && d.Module.LinkUrl.Contains($"/{controllerName}/")).ToList(); + + + if (isAction) + { + foreach (var item in permissions) + { + List modules = await _moduleServices.Query(d => d.LinkUrl != null && d.LinkUrl.ToLower() == item.Module.LinkUrl); + if (!modules.Any()) + { + var mid = await _moduleServices.Add(item.Module); + if (mid > 0) + { + item.Mid = mid; + var permissionid = await _permissionServices.Add(item); + } + + } + } + data.msg = "同步完成"; + } + + data.response = permissions; + data.status = 200; + data.success = isAction; + + return data; + } } public class AssignView { - public List pids { get; set; } - public int rid { get; set; } + public List pids { get; set; } + public long rid { get; set; } } public class AssignShow { - public List permissionids { get; set; } + public List permissionids { get; set; } public List assignbtns { get; set; } } diff --git a/Blog.Core.Api/Controllers/RoleController.cs b/Blog.Core.Api/Controllers/RoleController.cs index ce6a9e6b..0b93e943 100644 --- a/Blog.Core.Api/Controllers/RoleController.cs +++ b/Blog.Core.Api/Controllers/RoleController.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using Blog.Core.Common.HttpContextUser; +using Blog.Core.Common.HttpContextUser; using Blog.Core.IServices; using Blog.Core.Model; using Blog.Core.Model.Models; @@ -14,7 +13,7 @@ namespace Blog.Core.Controllers [Route("api/[controller]/[action]")] [ApiController] [Authorize(Permissions.Name)] - public class RoleController : ControllerBase + public class RoleController : BaseApiController { readonly IRoleServices _roleServices; readonly IUser _user; @@ -45,12 +44,14 @@ public async Task>> Get(int page = 1, string key = var data = await _roleServices.QueryPage(a => a.IsDeleted != true && (a.Name != null && a.Name.Contains(key)), page, intPageSize, " Id desc "); - return new MessageModel>() - { - msg = "获取成功", - success = data.dataCount >= 0, - response = data - }; + //return new MessageModel>() + //{ + // msg = "获取成功", + // success = data.dataCount >= 0, + // response = data + //}; + + return Success(data, "获取成功"); } @@ -70,20 +71,11 @@ public string Get(string id) [HttpPost] public async Task> Post([FromBody] Role role) { - var data = new MessageModel(); - role.CreateId = _user.ID; role.CreateBy = _user.Name; - var id = (await _roleServices.Add(role)); - data.success = id > 0; - if (data.success) - { - data.response = id.ObjToString(); - data.msg = "添加成功"; - } + return id > 0 ? Success(id.ObjToString(), "添加成功") : Failed("添加失败"); - return data; } /// @@ -95,18 +87,22 @@ public async Task> Post([FromBody] Role role) [HttpPut] public async Task> Put([FromBody] Role role) { - var data = new MessageModel(); - if (role != null && role.Id > 0) - { - data.success = await _roleServices.Update(role); - if (data.success) - { - data.msg = "更新成功"; - data.response = role?.Id.ObjToString(); - } - } - - return data; + if (role == null || role.Id <= 0) + return Failed("缺少参数"); + + return await _roleServices.Update(role) ? Success(role?.Id.ObjToString(),"更新成功") : Failed("更新失败"); + + //var data = new MessageModel(); + //if (role != null && role.Id > 0) + //{ + // data.success = await _roleServices.Update(role); + // if (data.success) + // { + // data.msg = "更新成功"; + // data.response = role?.Id.ObjToString(); + // } + //} + //return data; } /// @@ -116,22 +112,28 @@ public async Task> Put([FromBody] Role role) /// // DELETE: api/ApiWithActions/5 [HttpDelete] - public async Task> Delete(int id) + public async Task> Delete(long id) { + var data = new MessageModel(); - if (id > 0) - { - var userDetail = await _roleServices.QueryById(id); - userDetail.IsDeleted = true; - data.success = await _roleServices.Update(userDetail); - if (data.success) - { - data.msg = "删除成功"; - data.response = userDetail?.Id.ObjToString(); - } - } - - return data; + //if (id > 0) + //{ + // var userDetail = await _roleServices.QueryById(id); + // userDetail.IsDeleted = true; + // data.success = await _roleServices.Update(userDetail); + // if (data.success) + // { + // data.msg = "删除成功"; + // data.response = userDetail?.Id.ObjToString(); + // } + //} + //return data; + + if (id <= 0) return Failed(); + var userDetail = await _roleServices.QueryById(id); + if (userDetail == null) return Success(null,"角色不存在"); + userDetail.IsDeleted = true; + return await _roleServices.Update(userDetail) ? Success(userDetail?.Id.ObjToString(), "删除成功") : Failed(); } } } diff --git a/Blog.Core.Api/Controllers/SignalRTestController.cs b/Blog.Core.Api/Controllers/SignalRTestController.cs new file mode 100644 index 00000000..16ba47f0 --- /dev/null +++ b/Blog.Core.Api/Controllers/SignalRTestController.cs @@ -0,0 +1,49 @@ +using Blog.Core.Controllers; +using Blog.Core.Hubs; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; + +namespace Blog.Core.Api.Controllers; + +/// +/// SignalR测试 +/// +[Route("api/[controller]/[action]")] +[ApiController] +[Authorize] +public class SignalRTestController : BaseApiController +{ + private readonly IHubContext _hubContext; + + public SignalRTestController(IHubContext hubContext) + { + _hubContext = hubContext; + } + + /// + /// 向指定用户发送消息 + /// + /// + /// + /// + [HttpPost] + public async Task SendMessageToUser(string user, string message) + { + await _hubContext.Clients.Group(user).ReceiveMessage(user, message); + return Ok(); + } + + /// + /// 向指定角色发送消息 + /// + /// + /// + /// + [HttpPost] + public async Task SendMessageToRole(string role, string message) + { + await _hubContext.Clients.Group(role).ReceiveMessage(role, message); + return Ok(); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/SplitDemoController.cs b/Blog.Core.Api/Controllers/SplitDemoController.cs new file mode 100644 index 00000000..f625b202 --- /dev/null +++ b/Blog.Core.Api/Controllers/SplitDemoController.cs @@ -0,0 +1,199 @@ +using Blog.Core.IServices; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Blog.Core.Repository.UnitOfWorks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Linq.Expressions; + +namespace Blog.Core.Api.Controllers +{ + /// + /// 分表demo + /// + [Route("api/[controller]/[action]")] + [ApiController] + [Authorize(Permissions.Name)] + public class SplitDemoController : ControllerBase + { + readonly ISplitDemoServices splitDemoServices; + readonly IUnitOfWorkManage unitOfWorkManage; + public SplitDemoController(ISplitDemoServices _splitDemoServices, IUnitOfWorkManage _unitOfWorkManage) + { + splitDemoServices = _splitDemoServices; + unitOfWorkManage = _unitOfWorkManage; + } + + /// + /// 分页获取数据 + /// + /// + /// + /// + /// + /// + /// + [HttpGet] + [AllowAnonymous] + public async Task>> Get(DateTime beginTime, DateTime endTime, int page = 1, string key = "", int pageSize = 10) + { + if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key)) + { + key = ""; + } + Expression> whereExpression = a => (a.Name != null && a.Name.Contains(key)); + var data = await splitDemoServices.QueryPageSplit(whereExpression, beginTime, endTime, page, pageSize, " Id desc "); + return MessageModel>.Message(data.dataCount >= 0, "获取成功", data); + } + + /// + /// 根据ID获取信息 + /// + /// + /// + [HttpGet] + [AllowAnonymous] + public async Task> GetById(long id) + { + var data = new MessageModel(); + var model = await splitDemoServices.QueryByIdSplit(id); + if (model != null) + { + return MessageModel.Success("获取成功", model); + } + else + { + return MessageModel.Fail("获取失败"); + } + } + + /// + /// 添加一条测试数据 + /// + /// + /// + [HttpPost] + [AllowAnonymous] + public async Task> Post([FromBody] SplitDemo splitDemo) + { + var data = new MessageModel(); + //unitOfWorkManage.BeginTran(); + var id = (await splitDemoServices.AddSplit(splitDemo)); + data.success = (id == null ? false : true); + try + { + if (data.success) + { + data.response = id.FirstOrDefault().ToString(); + data.msg = "添加成功"; + } + else + { + data.msg = "添加失败"; + } + } + catch (Exception) + { + throw; + } + finally + { + //if (data.success) + // unitOfWorkManage.CommitTran(); + //else + // unitOfWorkManage.RollbackTran(); + } + return data; + } + + /// + /// 修改一条测试数据 + /// + /// + /// + [HttpPut] + [AllowAnonymous] + public async Task> Put([FromBody] SplitDemo splitDemo) + { + var data = new MessageModel(); + if (splitDemo != null && splitDemo.Id > 0) + { + unitOfWorkManage.BeginTran(); + data.success = await splitDemoServices.UpdateSplit(splitDemo, splitDemo.CreateTime); + try + { + if (data.success) + { + data.msg = "修改成功"; + data.response = splitDemo?.Id.ObjToString(); + } + else + { + data.msg = "修改失败"; + } + } + catch (Exception) + { + throw; + } + finally + { + if (data.success) + unitOfWorkManage.CommitTran(); + else + unitOfWorkManage.RollbackTran(); + } + } + return data; + } + + /// + /// 根据id删除数据 + /// + /// + /// + [HttpDelete] + [AllowAnonymous] + public async Task> Delete(long id) + { + var data = new MessageModel(); + + var model = await splitDemoServices.QueryByIdSplit(id); + if (model != null) + { + unitOfWorkManage.BeginTran(); + data.success = await splitDemoServices.DeleteSplit(model,model.CreateTime); + try + { + data.response = id.ObjToString(); + if (data.success) + { + data.msg = "删除成功"; + } + else + { + data.msg = "删除失败"; + } + + } + catch (Exception) + { + throw; + } + finally + { + if (data.success) + unitOfWorkManage.CommitTran(); + else + unitOfWorkManage.RollbackTran(); + } + } + else + { + data.msg = "不存在"; + } + return data; + + } + } +} diff --git a/Blog.Core.Api/Controllers/SqlSugarTestController.cs b/Blog.Core.Api/Controllers/SqlSugarTestController.cs new file mode 100644 index 00000000..f43e32bf --- /dev/null +++ b/Blog.Core.Api/Controllers/SqlSugarTestController.cs @@ -0,0 +1,61 @@ +using System.Text; +using Blog.Core.Common.DB.Extension; +using Blog.Core.Controllers; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; + +namespace Blog.Core.Api.Controllers; + +/// +/// SqlSugar 相关测试 +/// +[Route("api/[controller]/[action]")] +[ApiController] +[AllowAnonymous] +public class SqlSugarTestController(ISqlSugarClient db) : BaseApiController +{ + /// + /// 测试建表后,SqlSugar缓存 + /// + /// + [HttpGet] + public MessageModel ClearDbTableCache() + { + var tableName = "BlogArticle_Test"; + + //先删除表 + try + { + db.DbMaintenance.DropTable(tableName); + db.ClearDbTableCache(); + } + catch + { + //Ignore + } + + StringBuilder sb = new StringBuilder(); + + //提前检查表是否存在,测试缓存 + sb.AppendLine($"表{tableName} 是否存在:{db.DbMaintenance.IsAnyTable(tableName)}"); + + //创建表 + db.CodeFirst.As(tableName).InitTables(); + sb.AppendLine($"表{tableName} 创建成功"); + + //检查表是否存在 + sb.AppendLine($"表{tableName} 是否存在:{db.DbMaintenance.IsAnyTable(tableName)}"); + + //清除缓存 + db.ClearDbTableCache(); + sb.AppendLine($"清除缓存后"); + + //检查表是否存在 + sb.AppendLine($"表{tableName} 是否存在:{db.DbMaintenance.IsAnyTable(tableName)}"); + + return Success(sb.ToString()); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/Systems/CacheManageController.cs b/Blog.Core.Api/Controllers/Systems/CacheManageController.cs new file mode 100644 index 00000000..ef276c17 --- /dev/null +++ b/Blog.Core.Api/Controllers/Systems/CacheManageController.cs @@ -0,0 +1,75 @@ +using Blog.Core.Common.Caches; +using Blog.Core.Common.Caches.Interface; +using Blog.Core.Controllers; +using Blog.Core.Model; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Api.Controllers.Systems; + +/// +/// 缓存管理 +/// +[Route("api/Systems/[controller]")] +[ApiController] +[Authorize(Permissions.Name)] +public class CacheManageController(ICaching caching) : BaseApiController +{ + /// + /// 获取全部缓存 + /// + /// + [HttpGet] + public MessageModel> Get() + { + return Success(caching.GetAllCacheKeys()); + } + + /// + /// 获取缓存 + /// + /// + [HttpGet("{key}")] + public async Task> Get(string key) + { + return Success(await caching.GetStringAsync(key)); + } + + /// + /// 新增 + /// + /// + [HttpPost] + public async Task Post([FromQuery] string key, [FromQuery] string value, [FromQuery] int? expire) + { + if (expire.HasValue) + await caching.SetStringAsync(key, value, TimeSpan.FromMilliseconds(expire.Value)); + else + await caching.SetStringAsync(key, value); + + return Success(); + } + + /// + /// 删除全部缓存 + /// + /// + [HttpDelete] + public MessageModel Delete() + { + caching.RemoveAll(); + return Success(); + } + + /// + /// 删除缓存 + /// + /// + [Route("{key}")] + [HttpDelete] + public async Task Delete(string key) + { + await caching.RemoveAsync(key); + return Success(); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/Systems/DataBaseController.cs b/Blog.Core.Api/Controllers/Systems/DataBaseController.cs new file mode 100644 index 00000000..1f7b3089 --- /dev/null +++ b/Blog.Core.Api/Controllers/Systems/DataBaseController.cs @@ -0,0 +1,192 @@ +using System.Diagnostics.CodeAnalysis; +using Blog.Core.Common; +using Blog.Core.Common.DB; +using Blog.Core.Controllers; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Blog.Core.Model.Systems.DataBase; +using Blog.Core.Model.Tenants; +using Mapster; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; + +namespace Blog.Core.Api.Controllers.Systems; + +/// +/// 数据库管理 +/// +[Route("api/Systems/[controller]/[action]")] +[ApiController] +[Authorize(Permissions.Name)] +public class DataBaseController : BaseApiController +{ + private readonly ISqlSugarClient _db; + + public DataBaseController(ISqlSugarClient db) + { + _db = db; + } + + [return: NotNull] + private ISqlSugarClient GetTenantDb(string configId) + { + if (!_db.AsTenant().IsAnyConnection(configId)) + { + var tenant = _db.Queryable().WithCache() + .Where(s => s.TenantType == TenantTypeEnum.Db) + .Where(s => s.ConfigId == configId) + .First(); + if (tenant != null) + { + _db.AsTenant().AddConnection(tenant.GetConnectionConfig()); + } + } + + var db = _db.AsTenant().GetConnectionScope(configId); + if (db is null) + { + throw new ApplicationException("无效的数据库配置"); + } + + return db; + } + + /// + /// 获取库配置 + /// + /// + [HttpGet] + public async Task>> GetAllConfig() + { + //增加多租户的连接 + var allConfigs = new List(BaseDBConfig.AllConfigs); + var tenants = await _db.Queryable().WithCache() + .Where(s => s.TenantType == TenantTypeEnum.Db) + .ToListAsync(); + if (tenants.Any()) + { + allConfigs.AddRange(tenants.Select(tenant => tenant.GetConnectionConfig())); + } + + var configs = await Task.FromResult(allConfigs); + return Success(configs.Adapt>()); + } + + /// + /// 获取表信息 + /// + /// 配置Id + /// 读取类型 + /// + [HttpGet] + public MessageModel> GetTableInfoList(string configId, + DataBaseReadType readType = DataBaseReadType.Db) + { + if (configId.IsNullOrEmpty()) + { + configId = MainDb.CurrentDbConnId; + } + + configId = configId.ToLower(); + + var provider = GetTenantDb(configId); + List data = null; + switch (readType) + { + case DataBaseReadType.Db: + data = provider.DbMaintenance.GetTableInfoList(false); + break; + case DataBaseReadType.Entity: + if (EntityUtility.TenantEntitys.TryGetValue(configId, out var types)) + { + data = types.Select(s => provider.EntityMaintenance.GetEntityInfo(s)) + .Select(s => new {Name = s.DbTableName, Description = s.TableDescription}) + .Adapt>(); + } + + break; + } + + + return Success(data); + } + + /// + /// 获取表字段 + /// + /// 表名 + /// ConfigId + /// 读取类型 + /// + [HttpGet] + public MessageModel> GetColumnInfosByTableName(string tableName, string configId = null, + DataBaseReadType readType = DataBaseReadType.Db) + { + if (string.IsNullOrWhiteSpace(tableName)) + return Failed>("表名不能为空"); + + if (configId.IsNullOrEmpty()) + { + configId = MainDb.CurrentDbConnId; + } + + configId = configId.ToLower(); + + List data = null; + var provider = GetTenantDb(configId); + switch (readType) + { + case DataBaseReadType.Db: + data = provider.DbMaintenance.GetColumnInfosByTableName(tableName, false) + .Adapt>(); + break; + case DataBaseReadType.Entity: + if (EntityUtility.TenantEntitys.TryGetValue(configId, out var types)) + { + var type = types.FirstOrDefault(s => s.Name == tableName); + data = provider.EntityMaintenance.GetEntityInfo(type).Columns.Adapt>(); + } + + break; + } + + + return Success(data); + } + + /// + /// 编辑表备注 + /// + /// + [HttpPut] + public MessageModel PutTableEditRemark([FromBody] EditTableInput input) + { + var provider = GetTenantDb(input.ConfigId); + if (provider.DbMaintenance.IsAnyTableRemark(input.TableName)) + { + provider.DbMaintenance.DeleteTableRemark(input.TableName); + } + + provider.DbMaintenance.AddTableRemark(input.TableName, input.Description); + return Success(); + } + + /// + /// 编辑列备注 + /// + /// + [HttpPut] + public MessageModel PutColumnEditRemark([FromBody] EditColumnInput input) + { + var provider = GetTenantDb(input.ConfigId); + if (provider.DbMaintenance.IsAnyColumnRemark(input.DbColumnName, input.TableName)) + { + provider.DbMaintenance.DeleteColumnRemark(input.DbColumnName, input.TableName); + } + + provider.DbMaintenance.AddColumnRemark(input.DbColumnName, input.TableName, input.ColumnDescription); + + return Success(); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/Systems/DynamicCodeFirstController.cs b/Blog.Core.Api/Controllers/Systems/DynamicCodeFirstController.cs new file mode 100644 index 00000000..37c84791 --- /dev/null +++ b/Blog.Core.Api/Controllers/Systems/DynamicCodeFirstController.cs @@ -0,0 +1,96 @@ +using Blog.Core.Common.DB.Extension; +using Blog.Core.Controllers; +using Blog.Core.Model; +using Blog.Core.Model.Models.RootTkey; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using NetTaste; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; +using SqlSugar; + +namespace Blog.Core.Api.Controllers.Systems; + +/// +/// 动态建表 CURD +/// +[Route("api/Systems/[controller]/[action]")] +[ApiController] +[Authorize(Permissions.Name)] +public class DynamicCodeFirstController : BaseApiController +{ + private readonly ISqlSugarClient _db; + + public DynamicCodeFirstController(ISqlSugarClient db) + { + _db = db; + } + + /// + /// 动态type + /// + /// + private Type GetDynamicType() + { + return _db.DynamicBuilder().CreateClass("DynamicTestTable") + //{table} 占位符会自动替换成表名 + .CreateIndex(new SugarIndexAttribute("idx_{table}_Code", "Code", OrderByType.Desc)) + .CreateProperty("Id", typeof(int), new SugarColumn() {IsPrimaryKey = true, IsIdentity = true}) + .CreateProperty("Code", typeof(string), new SugarColumn() {Length = 50}) + .CreateProperty("Name", typeof(string), new SugarColumn() {Length = 50}) + .WithCache() + .BuilderType(); + } + + /// + /// 动态type 继承BaseEntity + /// + /// + private Type GetDynamicType2() + { + return _db.DynamicBuilder().CreateClass("DynamicTestTable2", null, typeof(BaseEntity)) + //{table} 占位符会自动替换成表名 + .CreateIndex(new SugarIndexAttribute("idx_{table}_Code", "Code", OrderByType.Desc)) + .CreateProperty("Code", typeof(string), new SugarColumn() {Length = 50}) + .CreateProperty("Name", typeof(string), new SugarColumn() {Length = 50}) + .WithCache() + .BuilderType(); + } + + /// + /// 测试建表 + /// + /// + [HttpPost] + public MessageModel TestCreateTable() + { + var type = GetDynamicType(); + _db.CodeFirst.InitTables(type); + return Success(); + } + + /// + /// 测试查询 + /// + /// + [HttpGet] + public MessageModel TestQuery() + { + var type = GetDynamicType(); + return Success(_db.QueryableByObject(type).ToList()); + } + + /// + /// 测试写入 + /// + /// + [HttpPost] + public MessageModel TestInsert(string code, string name) + { + var type = GetDynamicType(); + var entity = Activator.CreateInstance(type); + type.GetProperty("Code")!.SetValue(entity, code); + type.GetProperty("Name")!.SetValue(entity, name); + _db.InsertableByObject(entity).ExecuteCommand(); + return Success(); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/TasksQzController.cs b/Blog.Core.Api/Controllers/TasksQzController.cs index ffaac634..887cfcfc 100644 --- a/Blog.Core.Api/Controllers/TasksQzController.cs +++ b/Blog.Core.Api/Controllers/TasksQzController.cs @@ -1,12 +1,14 @@ -using System; -using System.Linq.Expressions; -using System.Threading.Tasks; +using System.Linq.Expressions; +using System.Reflection; using Blog.Core.IServices; using Blog.Core.Model; using Blog.Core.Model.Models; +using Blog.Core.Model.ViewModels; +using Blog.Core.Repository.UnitOfWorks; using Blog.Core.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Quartz; namespace Blog.Core.Controllers { @@ -16,12 +18,16 @@ namespace Blog.Core.Controllers public class TasksQzController : ControllerBase { private readonly ITasksQzServices _tasksQzServices; + private readonly ITasksLogServices _tasksLogServices; private readonly ISchedulerCenter _schedulerCenter; + private readonly IUnitOfWorkManage _unitOfWorkManage; - public TasksQzController(ITasksQzServices tasksQzServices, ISchedulerCenter schedulerCenter) + public TasksQzController(ITasksQzServices tasksQzServices, ISchedulerCenter schedulerCenter, IUnitOfWorkManage unitOfWorkManage, ITasksLogServices tasksLogServices) { + _unitOfWorkManage = unitOfWorkManage; _tasksQzServices = tasksQzServices; _schedulerCenter = schedulerCenter; + _tasksLogServices = tasksLogServices; } /// @@ -43,14 +49,14 @@ public async Task>> Get(int page = 1, string key Expression> whereExpression = a => a.IsDeleted != true && (a.Name != null && a.Name.Contains(key)); var data = await _tasksQzServices.QueryPage(whereExpression, page, intPageSize, " Id desc "); - - return new MessageModel>() + if (data.dataCount > 0) { - msg = "获取成功", - success = data.dataCount >= 0, - response = data - }; - + foreach (var item in data.data) + { + item.Triggers = await _schedulerCenter.GetTaskStaus(item); + } + } + return MessageModel>.Message(data.dataCount >= 0, "获取成功", data); } /// @@ -62,15 +68,48 @@ public async Task>> Get(int page = 1, string key public async Task> Post([FromBody] TasksQz tasksQz) { var data = new MessageModel(); - + _unitOfWorkManage.BeginTran(); var id = (await _tasksQzServices.Add(tasksQz)); data.success = id > 0; - if (data.success) + try { - data.response = id.ObjToString(); - data.msg = "添加成功"; - } + if (data.success) + { + tasksQz.Id = id; + data.response = id.ObjToString(); + data.msg = "添加成功"; + if (tasksQz.IsStart) + { + //如果是启动自动 + var ResuleModel = await _schedulerCenter.AddScheduleJobAsync(tasksQz); + data.success = ResuleModel.success; + if (ResuleModel.success) + { + data.msg = $"{data.msg}=>启动成功=>{ResuleModel.msg}"; + } + else + { + data.msg = $"{data.msg}=>启动失败=>{ResuleModel.msg}"; + } + } + } + else + { + data.msg = "添加失败"; + } + } + catch (Exception) + { + throw; + } + finally + { + if (data.success) + _unitOfWorkManage.CommitTran(); + else + _unitOfWorkManage.RollbackTran(); + } return data; } @@ -86,44 +125,152 @@ public async Task> Put([FromBody] TasksQz tasksQz) var data = new MessageModel(); if (tasksQz != null && tasksQz.Id > 0) { + _unitOfWorkManage.BeginTran(); data.success = await _tasksQzServices.Update(tasksQz); - if (data.success) + try { - data.msg = "更新成功"; - data.response = tasksQz?.Id.ObjToString(); + if (data.success) + { + data.msg = "修改成功"; + data.response = tasksQz?.Id.ObjToString(); + if (tasksQz.IsStart) + { + var ResuleModelStop = await _schedulerCenter.StopScheduleJobAsync(tasksQz); + data.msg = $"{data.msg}=>停止:{ResuleModelStop.msg}"; + var ResuleModelStar = await _schedulerCenter.AddScheduleJobAsync(tasksQz); + data.success = ResuleModelStar.success; + data.msg = $"{data.msg}=>启动:{ResuleModelStar.msg}"; + } + else + { + var ResuleModelStop = await _schedulerCenter.StopScheduleJobAsync(tasksQz); + data.msg = $"{data.msg}=>停止:{ResuleModelStop.msg}"; + } + } + else + { + data.msg = "修改失败"; + } + } + catch (Exception) + { + throw; + } + finally + { + if (data.success) + _unitOfWorkManage.CommitTran(); + else + _unitOfWorkManage.RollbackTran(); } } - return data; } + /// + /// 删除一个任务 + /// + /// + /// + [HttpDelete] + public async Task> Delete(long jobId) + { + var data = new MessageModel(); + + var model = await _tasksQzServices.QueryById(jobId); + if (model != null) + { + _unitOfWorkManage.BeginTran(); + data.success = await _tasksQzServices.Delete(model); + try + { + data.response = jobId.ObjToString(); + if (data.success) + { + data.msg = "删除成功"; + var ResuleModel = await _schedulerCenter.StopScheduleJobAsync(model); + data.msg = $"{data.msg}=>任务状态=>{ResuleModel.msg}"; + } + else + { + data.msg = "删除失败"; + } + + } + catch (Exception) + { + throw; + } + finally + { + if (data.success) + _unitOfWorkManage.CommitTran(); + else + _unitOfWorkManage.RollbackTran(); + } + } + else + { + data.msg = "任务不存在"; + } + return data; + } /// /// 启动计划任务 /// /// /// [HttpGet] - public async Task> StartJob(int jobId) + public async Task> StartJob(long jobId) { var data = new MessageModel(); var model = await _tasksQzServices.QueryById(jobId); if (model != null) { - var ResuleModel = await _schedulerCenter.AddScheduleJobAsync(model); - if (ResuleModel.success) + _unitOfWorkManage.BeginTran(); + try { model.IsStart = true; data.success = await _tasksQzServices.Update(model); + data.response = jobId.ObjToString(); + if (data.success) + { + data.msg = "更新成功"; + var ResuleModel = await _schedulerCenter.AddScheduleJobAsync(model); + data.success = ResuleModel.success; + if (ResuleModel.success) + { + data.msg = $"{data.msg}=>启动成功=>{ResuleModel.msg}"; + + } + else + { + data.msg = $"{data.msg}=>启动失败=>{ResuleModel.msg}"; + } + } + else + { + data.msg = "更新失败"; + } } - if (data.success) + catch (Exception) { - data.msg = "启动成功"; - data.response = jobId.ObjToString(); + throw; + } + finally + { + if (data.success) + _unitOfWorkManage.CommitTran(); + else + _unitOfWorkManage.RollbackTran(); } } + else + { + data.msg = "任务不存在"; + } return data; - } /// /// 停止一个计划任务 @@ -131,27 +278,149 @@ public async Task> StartJob(int jobId) /// /// [HttpGet] - public async Task> StopJob(int jobId) + public async Task> StopJob(long jobId) { var data = new MessageModel(); var model = await _tasksQzServices.QueryById(jobId); if (model != null) { - var ResuleModel = await _schedulerCenter.StopScheduleJobAsync(model); - if (ResuleModel.success) + model.IsStart = false; + data.success = await _tasksQzServices.Update(model); + data.response = jobId.ObjToString(); + if (data.success) { - model.IsStart = false; - data.success = await _tasksQzServices.Update(model); + data.msg = "更新成功"; + var ResuleModel = await _schedulerCenter.StopScheduleJobAsync(model); + if (ResuleModel.success) + { + data.msg = $"{data.msg}=>停止成功=>{ResuleModel.msg}"; + } + else + { + data.msg = $"{data.msg}=>停止失败=>{ResuleModel.msg}"; + } } - if (data.success) + else + { + data.msg = "更新失败"; + } + } + else + { + data.msg = "任务不存在"; + } + return data; + } + /// + /// 暂停一个计划任务 + /// + /// + /// + [HttpGet] + public async Task> PauseJob(long jobId) + { + var data = new MessageModel(); + var model = await _tasksQzServices.QueryById(jobId); + if (model != null) + { + _unitOfWorkManage.BeginTran(); + try { - data.msg = "暂停成功"; + data.success = await _tasksQzServices.Update(model); data.response = jobId.ObjToString(); + if (data.success) + { + data.msg = "更新成功"; + var ResuleModel = await _schedulerCenter.PauseJob(model); + if (ResuleModel.success) + { + data.msg = $"{data.msg}=>暂停成功=>{ResuleModel.msg}"; + } + else + { + data.msg = $"{data.msg}=>暂停失败=>{ResuleModel.msg}"; + } + data.success = ResuleModel.success; + } + else + { + data.msg = "更新失败"; + } + } + catch (Exception) + { + throw; + } + finally + { + if (data.success) + _unitOfWorkManage.CommitTran(); + else + _unitOfWorkManage.RollbackTran(); } } + else + { + data.msg = "任务不存在"; + } return data; + } + /// + /// 恢复一个计划任务 + /// + /// + /// + [HttpGet] + public async Task> ResumeJob(long jobId) + { + var data = new MessageModel(); + var model = await _tasksQzServices.QueryById(jobId); + if (model != null) + { + _unitOfWorkManage.BeginTran(); + try + { + model.IsStart = true; + data.success = await _tasksQzServices.Update(model); + data.response = jobId.ObjToString(); + if (data.success) + { + data.msg = "更新成功"; + var ResuleModel = await _schedulerCenter.ResumeJob(model); + if (ResuleModel.success) + { + data.msg = $"{data.msg}=>恢复成功=>{ResuleModel.msg}"; + } + else + { + data.msg = $"{data.msg}=>恢复失败=>{ResuleModel.msg}"; + } + data.success = ResuleModel.success; + } + else + { + data.msg = "更新失败"; + } + } + catch (Exception) + { + throw; + } + finally + { + if (data.success) + _unitOfWorkManage.CommitTran(); + else + _unitOfWorkManage.RollbackTran(); + } + } + else + { + data.msg = "任务不存在"; + } + return data; } /// /// 重启一个计划任务 @@ -159,27 +428,120 @@ public async Task> StopJob(int jobId) /// /// [HttpGet] - public async Task> ReCovery(int jobId) + public async Task> ReCovery(long jobId) { var data = new MessageModel(); - var model = await _tasksQzServices.QueryById(jobId); if (model != null) { - var ResuleModel = await _schedulerCenter.ResumeJob(model); - if (ResuleModel.success) + + _unitOfWorkManage.BeginTran(); + try { model.IsStart = true; data.success = await _tasksQzServices.Update(model); + data.response = jobId.ObjToString(); + if (data.success) + { + data.msg = "更新成功"; + var ResuleModelStop = await _schedulerCenter.StopScheduleJobAsync(model); + var ResuleModelStar = await _schedulerCenter.AddScheduleJobAsync(model); + if (ResuleModelStar.success) + { + data.msg = $"{data.msg}=>停止:{ResuleModelStop.msg}=>启动:{ResuleModelStar.msg}"; + data.response = jobId.ObjToString(); + + } + else + { + data.msg = $"{data.msg}=>停止:{ResuleModelStop.msg}=>启动:{ResuleModelStar.msg}"; + data.response = jobId.ObjToString(); + } + data.success = ResuleModelStar.success; + } + else + { + data.msg = "更新失败"; + } } - if (data.success) + catch (Exception) { - data.msg = "重启成功"; - data.response = jobId.ObjToString(); + throw; + } + finally + { + if (data.success) + _unitOfWorkManage.CommitTran(); + else + _unitOfWorkManage.RollbackTran(); } } + else + { + data.msg = "任务不存在"; + } return data; } + /// + /// 获取任务命名空间 + /// + /// + [HttpGet] + public MessageModel> GetTaskNameSpace() + { + var baseType = typeof(IJob); + var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory; + var referencedAssemblies = System.IO.Directory.GetFiles(path, "Blog.Core.Tasks.dll").Select(Assembly.LoadFrom).ToArray(); + var types = referencedAssemblies + .SelectMany(a => a.DefinedTypes) + .Select(type => type.AsType()) + .Where(x => x != baseType && baseType.IsAssignableFrom(x)).ToArray(); + var implementTypes = types.Where(x => x.IsClass).Select(item => new QuartzReflectionViewModel { nameSpace = item.Namespace, nameClass = item.Name, remark = "" }).ToList(); + return MessageModel>.Success("获取成功", implementTypes); + } + + /// + /// 立即执行任务 + /// + /// + /// + [HttpGet] + public async Task> ExecuteJob(long jobId) + { + var data = new MessageModel(); + + var model = await _tasksQzServices.QueryById(jobId); + if (model != null) + { + return await _schedulerCenter.ExecuteJobAsync(model); + } + else + { + data.msg = "任务不存在"; + } + return data; + } + /// + /// 获取任务运行日志 + /// + /// + [HttpGet] + public async Task>> GetTaskLogs(long jobId, int page = 1, int pageSize = 10, DateTime? runTimeStart = null, DateTime? runTimeEnd = null) + { + var model = await _tasksLogServices.GetTaskLogs(jobId, page, pageSize, runTimeStart, runTimeEnd); + return MessageModel>.Message(model.dataCount >= 0, "获取成功", model); + } + /// + /// 任务概况 + /// + /// + [HttpGet] + public async Task> GetTaskOverview(long jobId, int page = 1, int pageSize = 10, DateTime? runTimeStart = null, DateTime? runTimeEnd = null, string type = "month") + { + var model = await _tasksLogServices.GetTaskOverview(jobId, runTimeStart, runTimeEnd, type); + return MessageModel.Message(true, "获取成功", model); + } + } } diff --git a/Blog.Core.Api/Controllers/Tenant/TenantByDbController.cs b/Blog.Core.Api/Controllers/Tenant/TenantByDbController.cs new file mode 100644 index 00000000..046f7f7b --- /dev/null +++ b/Blog.Core.Api/Controllers/Tenant/TenantByDbController.cs @@ -0,0 +1,50 @@ +using Blog.Core.Common.HttpContextUser; +using Blog.Core.Controllers; +using Blog.Core.IServices.BASE; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Api.Controllers.Tenant; + +/// +/// 多租户-多库方案 测试 +/// +[Produces("application/json")] +[Route("api/Tenant/ByDb")] +[Authorize] +public class TenantByDbController : BaseApiController +{ + private readonly IBaseServices _services; + private readonly IUser _user; + + public TenantByDbController(IUser user, IBaseServices services) + { + _user = user; + _services = services; + } + + /// + /// 获取租户下全部业务数据
+ ///
+ /// + [HttpGet] + public async Task>> GetAll() + { + var data = await _services.Query(); + return Success(data); + } + + /// + /// 新增数据 + /// + /// + [HttpPost] + public async Task Post(SubLibraryBusinessTable data) + { + await _services.Db.Insertable(data).ExecuteReturnSnowflakeIdAsync(); + + return Success(); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/Tenant/TenantByIdController.cs b/Blog.Core.Api/Controllers/Tenant/TenantByIdController.cs new file mode 100644 index 00000000..b015bc6d --- /dev/null +++ b/Blog.Core.Api/Controllers/Tenant/TenantByIdController.cs @@ -0,0 +1,49 @@ +using Blog.Core.Common.HttpContextUser; +using Blog.Core.Controllers; +using Blog.Core.IServices.BASE; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Api.Controllers.Tenant; + +/// +/// 多租户-Id方案 测试 +/// +[Produces("application/json")] +[Route("api/Tenant/ById")] +[Authorize] +public class TenantByIdController : BaseApiController +{ + private readonly IBaseServices _services; + private readonly IUser _user; + + public TenantByIdController(IUser user, IBaseServices services) + { + _user = user; + _services = services; + } + + /// + /// 获取租户下全部业务数据
+ ///
+ /// + [HttpGet] + public async Task>> GetAll() + { + var data = await _services.Query(); + return Success(data); + } + + /// + /// 新增业务数据 + /// + /// + [HttpPost] + public async Task Post([FromBody] BusinessTable data) + { + await _services.Db.Insertable(data).ExecuteReturnSnowflakeIdAsync(); + return Success(); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/Tenant/TenantByTableController.cs b/Blog.Core.Api/Controllers/Tenant/TenantByTableController.cs new file mode 100644 index 00000000..6c0b110e --- /dev/null +++ b/Blog.Core.Api/Controllers/Tenant/TenantByTableController.cs @@ -0,0 +1,57 @@ +using Blog.Core.Common.HttpContextUser; +using Blog.Core.Controllers; +using Blog.Core.IServices.BASE; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Api.Controllers.Tenant; + +/// +/// 多租户-多表方案 测试 +/// +[Produces("application/json")] +[Route("api/Tenant/ByTable")] +[Authorize] +public class TenantByTableController : BaseApiController +{ + private readonly IBaseServices _services; + private readonly IUser _user; + + public TenantByTableController(IUser user, IBaseServices services) + { + _user = user; + _services = services; + } + + /// + /// 获取租户下全部业务数据
+ ///
+ /// + [HttpGet] + public async Task>> GetAll() + { + //查询 + // var data = await _services.Query(); + + //关联查询 + var data = await _services.Db + .Queryable() + .Includes(s => s.Child) + .ToListAsync(); + return Success(data); + } + + /// + /// 新增数据 + /// + /// + [HttpPost] + public async Task Post(MultiBusinessTable data) + { + await _services.Db.Insertable(data).ExecuteReturnSnowflakeIdAsync(); + + return Success(); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/Tenant/TenantManagerController.cs b/Blog.Core.Api/Controllers/Tenant/TenantManagerController.cs new file mode 100644 index 00000000..90133fdb --- /dev/null +++ b/Blog.Core.Api/Controllers/Tenant/TenantManagerController.cs @@ -0,0 +1,87 @@ +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; + +namespace Blog.Core.Api.Controllers.Tenant; + +/// +/// 租户管理 +/// +[Produces("application/json")] +[Route("api/TenantManager")] +[Authorize] +public class TenantManagerController : BaseApiController +{ + private readonly ITenantService _services; + + public TenantManagerController(ITenantService services) + { + _services = services; + } + + + /// + /// 获取全部租户 + /// + /// + [HttpGet] + public async Task>> GetAll() + { + var data = await _services.Query(); + return Success(data); + } + + + /// + /// 获取租户信息 + /// + /// + [HttpGet("{id}")] + public async Task> GetInfo(long id) + { + var data = await _services.QueryById(id); + return Success(data); + } + + /// + /// 新增租户信息
+ /// 此处只做演示,具体要以实际业务为准 + ///
+ /// + [HttpPost] + public async Task Post(SysTenant tenant) + { + await _services.SaveTenant(tenant); + return Success(); + } + + /// + /// 修改租户信息
+ /// 此处只做演示,具体要以实际业务为准 + ///
+ /// + [HttpPut] + public async Task Put(SysTenant tenant) + { + await _services.SaveTenant(tenant); + return Success(); + } + + /// + /// 删除租户
+ /// 此处只做演示,具体要以实际业务为准 + ///
+ /// + [HttpDelete] + public async Task Delete(long id) + { + //是否删除租户库? + //要根据实际情况而定 + //例如直接删除租户库、备份租户库到xx + await _services.DeleteById(id); + return Success(); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/Test/EnumTestController.cs b/Blog.Core.Api/Controllers/Test/EnumTestController.cs new file mode 100644 index 00000000..29a85ac6 --- /dev/null +++ b/Blog.Core.Api/Controllers/Test/EnumTestController.cs @@ -0,0 +1,75 @@ +using System.ComponentModel; +using Blog.Core.Controllers; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Api.Controllers.Test; + +/// +/// 枚举测试 +/// +[Route("api/[Controller]/[Action]")] +[AllowAnonymous] +public class EnumTestController : BaseApiController +{ + /// + /// 获取学生信息 + /// + /// 学生类型 + /// + /// + /// 学生信息 + [HttpGet] + public Student GetStudent( StudentType studentType, StudentType? studentType2, List studentTypes) + { + return new Student + { + Name = "张三", + Age = 20, + Type = studentType + }; + } +} + +/// +/// 学生类型 +/// +[Description("学生类型")] +public enum StudentType +{ + /// + /// 小学生 + /// + [Description("小学生")] + PrimarySchool = 1, + + /// + /// 中学生 + /// + [Description("中学生")] + MiddleSchool = 2, + + /// + /// 大学生 + /// + [Description("大学生")] + University = 3 +} + +public class Student +{ + /// + /// 学生姓名 + /// + public string Name { get; set; } + + /// + /// 学生年龄 + /// + public int Age { get; set; } + + /// + /// 学生类型 + /// + public StudentType Type { get; set; } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/Test/SqlsugarTestController.cs b/Blog.Core.Api/Controllers/Test/SqlsugarTestController.cs new file mode 100644 index 00000000..774a9b12 --- /dev/null +++ b/Blog.Core.Api/Controllers/Test/SqlsugarTestController.cs @@ -0,0 +1,29 @@ +using Blog.Core.Common; +using Blog.Core.Controllers; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; + +namespace Blog.Core.Api.Controllers.Test; + +[Route("api/[Controller]/[Action]")] +[AllowAnonymous] +public class SqlsugarTestController : BaseApiController +{ + private readonly SqlSugarScope _db; + + public SqlsugarTestController(SqlSugarScope db) + { + _db = db; + } + + [HttpGet] + public async Task Get() + { + Console.WriteLine(App.HttpContext.Request.Path); + Console.WriteLine(App.HttpContext.RequestServices.ToString()); + Console.WriteLine(App.User?.ID); + await Task.CompletedTask; + return Ok(); + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/TopicController.cs b/Blog.Core.Api/Controllers/TopicController.cs index 1fe2d4a3..253f54ff 100644 --- a/Blog.Core.Api/Controllers/TopicController.cs +++ b/Blog.Core.Api/Controllers/TopicController.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Blog.Core.IServices; +using Blog.Core.IServices; using Blog.Core.Model; using Blog.Core.Model.Models; using Microsoft.AspNetCore.Authorization; @@ -46,7 +44,7 @@ public async Task>> Get() // GET: api/Topic/5 [HttpGet("{id}")] - public string Get(int id) + public string Get(long id) { return "value"; } @@ -59,13 +57,13 @@ public void Post([FromBody] string value) // PUT: api/Topic/5 [HttpPut("{id}")] - public void Put(int id, [FromBody] string value) + public void Put(long id, [FromBody] string value) { } // DELETE: api/ApiWithActions/5 [HttpDelete("{id}")] - public void Delete(int id) + public void Delete(long id) { } } diff --git a/Blog.Core.Api/Controllers/TopicDetailController.cs b/Blog.Core.Api/Controllers/TopicDetailController.cs index 264fe2df..374aca24 100644 --- a/Blog.Core.Api/Controllers/TopicDetailController.cs +++ b/Blog.Core.Api/Controllers/TopicDetailController.cs @@ -1,7 +1,4 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Blog.Core.Common.Helper; +using Blog.Core.Common.Helper; using Blog.Core.IServices; using Blog.Core.Model; using Blog.Core.Model.Models; @@ -45,7 +42,7 @@ public TopicDetailController(ITopicServices topicServices, ITopicDetailServices [AllowAnonymous] public async Task>> Get(int page = 1, string tname = "", string key = "", int intPageSize = 12) { - int tid = 0; + long tid = 0; if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key)) { @@ -59,7 +56,7 @@ public async Task>> Get(int page = 1, string if (!string.IsNullOrEmpty(tname)) { - tid = ((await _topicServices.Query(ts => ts.tName == tname)).FirstOrDefault()?.Id).ObjToInt(); + tid = ((await _topicServices.Query(ts => ts.tName == tname)).FirstOrDefault()?.Id).ObjToLong(); } @@ -84,7 +81,7 @@ public async Task>> Get(int page = 1, string // GET: api/TopicDetail/5 [HttpGet("{id}")] [AllowAnonymous] - public async Task> Get(int id) + public async Task> Get(long id) { var data = new MessageModel(); var response = id > 0 ? await _topicDetailServices.QueryById(id) : new TopicDetail(); @@ -157,7 +154,7 @@ public async Task> Update([FromBody] TopicDetail topicDetai /// // DELETE: api/ApiWithActions/5 [HttpDelete] - public async Task> Delete(int id) + public async Task> Delete(long id) { var data = new MessageModel(); if (id > 0) diff --git a/Blog.Core.Api/Controllers/TransactionController.cs b/Blog.Core.Api/Controllers/TransactionController.cs index b396f75f..9853d985 100644 --- a/Blog.Core.Api/Controllers/TransactionController.cs +++ b/Blog.Core.Api/Controllers/TransactionController.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Blog.Core.IRepository.UnitOfWork; -using Blog.Core.IServices; +using Blog.Core.IServices; using Blog.Core.Model; using Blog.Core.Model.Models; +using Blog.Core.Repository.UnitOfWorks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -17,12 +14,12 @@ public class TransactionController : ControllerBase { private readonly IPasswordLibServices _passwordLibServices; private readonly IGuestbookServices _guestbookServices; - private readonly IUnitOfWork _unitOfWork; + private readonly IUnitOfWorkManage _unitOfWorkManage; - public TransactionController(IUnitOfWork unitOfWork, IPasswordLibServices passwordLibServices, IGuestbookServices guestbookServices) + public TransactionController(IUnitOfWorkManage unitOfWorkManage, IPasswordLibServices passwordLibServices, IGuestbookServices guestbookServices) { - _unitOfWork = unitOfWork; + _unitOfWorkManage = unitOfWorkManage; _passwordLibServices = passwordLibServices; _guestbookServices = guestbookServices; } @@ -36,7 +33,7 @@ public async Task>> Get() { returnMsg.Add($"Begin Transaction"); - _unitOfWork.BeginTran(); + _unitOfWorkManage.BeginTran(); var passwords = await _passwordLibServices.Query(d => d.IsDeleted == false); returnMsg.Add($"first time : the count of passwords is :{passwords.Count}"); @@ -76,11 +73,11 @@ public async Task>> Get() returnMsg.Add($"first time : the count of guestbooks is :{guestbooks.Count}"); returnMsg.Add($" "); - _unitOfWork.CommitTran(); + _unitOfWorkManage.CommitTran(); } catch (Exception) { - _unitOfWork.RollbackTran(); + _unitOfWorkManage.RollbackTran(); var passwords = await _passwordLibServices.Query(); returnMsg.Add($"third time : the count of passwords is :{passwords.Count}"); @@ -98,11 +95,29 @@ public async Task>> Get() // GET: api/Transaction/5 [HttpGet("{id}")] - public async Task> Get(int id) + public async Task> Get(long id) { return await _guestbookServices.TestTranInRepository(); } + [HttpGet] + public async Task GetTestTranPropagation() + { + return await _guestbookServices.TestTranPropagation(); + } + + [HttpGet] + public async Task GetTestTranPropagationNoTran() + { + return await _guestbookServices.TestTranPropagationNoTran(); + } + + [HttpGet] + public async Task GetTestTranPropagationTran() + { + return await _guestbookServices.TestTranPropagationTran(); + } + // POST: api/Transaction [HttpPost] public void Post([FromBody] string value) @@ -111,15 +126,19 @@ public void Post([FromBody] string value) // PUT: api/Transaction/5 [HttpPut("{id}")] - public void Put(int id, [FromBody] string value) + public void Put(long id, [FromBody] string value) { } - // DELETE: api/ApiWithActions/5 + /// + /// 测试事务在AOP中的使用 + /// + /// + /// [HttpDelete("{id}")] - public async Task Delete(int id) + public async Task Delete(long id) { return await _guestbookServices.TestTranInRepositoryAOP(); } } -} +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/UserController.cs b/Blog.Core.Api/Controllers/UserController.cs index fa37fd1a..95137c8e 100644 --- a/Blog.Core.Api/Controllers/UserController.cs +++ b/Blog.Core.Api/Controllers/UserController.cs @@ -1,17 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using AutoMapper; using Blog.Core.AuthHelper.OverWrite; using Blog.Core.Common.Helper; using Blog.Core.Common.HttpContextUser; -using Blog.Core.IRepository.UnitOfWork; using Blog.Core.IServices; using Blog.Core.Model; using Blog.Core.Model.Models; +using Blog.Core.Model.ViewModels; +using Blog.Core.Repository.UnitOfWorks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; namespace Blog.Core.Controllers { @@ -21,31 +18,41 @@ namespace Blog.Core.Controllers [Route("api/[controller]/[action]")] [ApiController] [Authorize(Permissions.Name)] - public class UserController : ControllerBase + public class UserController : BaseApiController { - private readonly IUnitOfWork _unitOfWork; + private readonly IUnitOfWorkManage _unitOfWorkManage; readonly ISysUserInfoServices _sysUserInfoServices; readonly IUserRoleServices _userRoleServices; readonly IRoleServices _roleServices; + private readonly IDepartmentServices _departmentServices; private readonly IUser _user; + private readonly IMapper _mapper; private readonly ILogger _logger; /// /// 构造函数 /// - /// + /// /// /// /// + /// /// + /// /// - public UserController(IUnitOfWork unitOfWork, ISysUserInfoServices sysUserInfoServices, IUserRoleServices userRoleServices, IRoleServices roleServices, IUser user, ILogger logger) + public UserController(IUnitOfWorkManage unitOfWorkManage, ISysUserInfoServices sysUserInfoServices, + IUserRoleServices userRoleServices, + IRoleServices roleServices, + IDepartmentServices departmentServices, + IUser user, IMapper mapper, ILogger logger) { - _unitOfWork = unitOfWork; + _unitOfWorkManage = unitOfWorkManage; _sysUserInfoServices = sysUserInfoServices; _userRoleServices = userRoleServices; _roleServices = roleServices; + _departmentServices = departmentServices; _user = user; + _mapper = mapper; _logger = logger; } @@ -57,16 +64,17 @@ public UserController(IUnitOfWork unitOfWork, ISysUserInfoServices sysUserInfoSe /// // GET: api/User [HttpGet] - public async Task>> Get(int page = 1, string key = "") + public async Task>> Get(int page = 1, string key = "") { if (string.IsNullOrEmpty(key) || string.IsNullOrWhiteSpace(key)) { key = ""; } + int intPageSize = 50; - var data = await _sysUserInfoServices.QueryPage(a => a.tdIsDelete != true && a.uStatus >= 0 && ((a.uLoginName != null && a.uLoginName.Contains(key)) || (a.uRealName != null && a.uRealName.Contains(key))), page, intPageSize, " uID desc "); + var data = await _sysUserInfoServices.QueryPage(a => a.IsDeleted != true && a.Status >= 0 && ((a.LoginName != null && a.LoginName.Contains(key)) || (a.RealName != null && a.RealName.Contains(key))), page, intPageSize, " Id desc "); #region MyRegion @@ -74,26 +82,41 @@ public async Task>> Get(int page = 1, string // 这里可以封装到多表查询,此处简单处理 var allUserRoles = await _userRoleServices.Query(d => d.IsDeleted == false); var allRoles = await _roleServices.Query(d => d.IsDeleted == false); + var allDepartments = await _departmentServices.Query(d => d.IsDeleted == false); var sysUserInfos = data.data; foreach (var item in sysUserInfos) { - var currentUserRoles = allUserRoles.Where(d => d.UserId == item.uID).Select(d => d.RoleId).ToList(); + var currentUserRoles = allUserRoles.Where(d => d.UserId == item.Id).Select(d => d.RoleId).ToList(); item.RIDs = currentUserRoles; item.RoleNames = allRoles.Where(d => currentUserRoles.Contains(d.Id)).Select(d => d.Name).ToList(); + var departmentNameAndIds = GetFullDepartmentName(allDepartments, item.DepartmentId); + item.DepartmentName = departmentNameAndIds.Item1; + item.Dids = departmentNameAndIds.Item2; } data.data = sysUserInfos; + #endregion - return new MessageModel>() + return Success(data.ConvertTo(_mapper)); + } + + private (string, List) GetFullDepartmentName(List departments, long departmentId) + { + var departmentModel = departments.FirstOrDefault(d => d.Id == departmentId); + if (departmentModel == null) { - msg = "获取成功", - success = data.dataCount >= 0, - response = data - }; + return ("", new List()); + } + + var pids = departmentModel.CodeRelationship?.TrimEnd(',').Split(',').Select(d => d.ObjToLong()).ToList(); + pids.Add(departmentModel.Id); + var pnams = departments.Where(d => pids.Contains(d.Id)).ToList().Select(d => d.Name).ToArray(); + var fullName = string.Join("/", pnams); + return (fullName, pids); } // GET: api/User/5 @@ -114,9 +137,9 @@ public string Get(string id) /// [HttpGet] [AllowAnonymous] - public async Task> GetInfoByToken(string token) + public async Task> GetInfoByToken(string token) { - var data = new MessageModel(); + var data = new MessageModel(); if (!string.IsNullOrEmpty(token)) { var tokenModel = JwtHelper.SerializeJwt(token); @@ -125,13 +148,13 @@ public async Task> GetInfoByToken(string token) var userinfo = await _sysUserInfoServices.QueryById(tokenModel.Uid); if (userinfo != null) { - data.response = userinfo; + data.response = _mapper.Map(userinfo); data.success = true; data.msg = "获取成功"; } } - } + return data; } @@ -142,14 +165,14 @@ public async Task> GetInfoByToken(string token) /// // POST: api/User [HttpPost] - public async Task> Post([FromBody] sysUserInfo sysUserInfo) + public async Task> Post([FromBody] SysUserInfoDto sysUserInfo) { var data = new MessageModel(); sysUserInfo.uLoginPWD = MD5Helper.MD5Encrypt32(sysUserInfo.uLoginPWD); sysUserInfo.uRemark = _user.Name; - var id = await _sysUserInfoServices.Add(sysUserInfo); + var id = await _sysUserInfoServices.Add(_mapper.Map(sysUserInfo)); data.success = id > 0; if (data.success) { @@ -167,51 +190,68 @@ public async Task> Post([FromBody] sysUserInfo sysUserInfo) /// // PUT: api/User/5 [HttpPut] - public async Task> Put([FromBody] sysUserInfo sysUserInfo) + public async Task> Put([FromBody] SysUserInfoDto sysUserInfo) { // 这里使用事务处理 - var data = new MessageModel(); + + var oldUser = await _sysUserInfoServices.QueryById(sysUserInfo.uID); + if (oldUser is not { Id: > 0 }) + { + return Failed("用户不存在或已被删除"); + } + try { - _unitOfWork.BeginTran(); + if (sysUserInfo.uLoginPWD != oldUser.LoginPWD) + { + oldUser.CriticalModifyTime = DateTime.Now; + } - if (sysUserInfo != null && sysUserInfo.uID > 0) + _mapper.Map(sysUserInfo, oldUser); + + _unitOfWorkManage.BeginTran(); + // 无论 Update Or Add , 先删除当前用户的全部 U_R 关系 + var usreroles = (await _userRoleServices.Query(d => d.UserId == oldUser.Id)); + if (usreroles.Any()) { - if (sysUserInfo.RIDs.Count > 0) + var ids = usreroles.Select(d => d.Id.ToString()).ToArray(); + var isAllDeleted = await _userRoleServices.DeleteByIds(ids); + if (!isAllDeleted) { - // 无论 Update Or Add , 先删除当前用户的全部 U_R 关系 - var usreroles = (await _userRoleServices.Query(d => d.UserId == sysUserInfo.uID)).Select(d => d.Id.ToString()).ToArray(); - if (usreroles.Count() > 0) - { - var isAllDeleted = await _userRoleServices.DeleteByIds(usreroles); - } - - // 然后再执行添加操作 - var userRolsAdd = new List(); - sysUserInfo.RIDs.ForEach(rid => - { - userRolsAdd.Add(new UserRole(sysUserInfo.uID, rid)); - }); - - await _userRoleServices.Add(userRolsAdd); - + return Failed("服务器更新异常"); } + } - data.success = await _sysUserInfoServices.Update(sysUserInfo); - - _unitOfWork.CommitTran(); + // 然后再执行添加操作 + if (sysUserInfo.RIDs.Count > 0) + { + var userRolsAdd = new List(); + sysUserInfo.RIDs.ForEach(rid => { userRolsAdd.Add(new UserRole(oldUser.Id, rid)); }); - if (data.success) + var oldRole = usreroles.Select(s => s.RoleId).OrderBy(i => i).ToArray(); + var newRole = userRolsAdd.Select(s => s.RoleId).OrderBy(i => i).ToArray(); + if (!oldRole.SequenceEqual(newRole)) { - data.msg = "更新成功"; - data.response = sysUserInfo?.uID.ObjToString(); + oldUser.CriticalModifyTime = DateTime.Now; } + + await _userRoleServices.Add(userRolsAdd); + } + + data.success = await _sysUserInfoServices.Update(oldUser); + + _unitOfWorkManage.CommitTran(); + + if (data.success) + { + data.msg = "更新成功"; + data.response = oldUser.Id.ObjToString(); } } catch (Exception e) { - _unitOfWork.RollbackTran(); + _unitOfWorkManage.RollbackTran(); _logger.LogError(e, e.Message); } @@ -225,22 +265,22 @@ public async Task> Put([FromBody] sysUserInfo sysUserInfo) /// // DELETE: api/ApiWithActions/5 [HttpDelete] - public async Task> Delete(int id) + public async Task> Delete(long id) { var data = new MessageModel(); if (id > 0) { var userDetail = await _sysUserInfoServices.QueryById(id); - userDetail.tdIsDelete = true; + userDetail.IsDeleted = true; data.success = await _sysUserInfoServices.Update(userDetail); if (data.success) { data.msg = "删除成功"; - data.response = userDetail?.uID.ObjToString(); + data.response = userDetail?.Id.ObjToString(); } } return data; } } -} +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/UserRoleController.cs b/Blog.Core.Api/Controllers/UserRoleController.cs index 5225fbdc..693a68b8 100644 --- a/Blog.Core.Api/Controllers/UserRoleController.cs +++ b/Blog.Core.Api/Controllers/UserRoleController.cs @@ -1,7 +1,8 @@ -using System.Threading.Tasks; +using AutoMapper; using Blog.Core.IServices; using Blog.Core.Model; using Blog.Core.Model.Models; +using Blog.Core.Model.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -16,21 +17,24 @@ namespace Blog.Core.Controllers [Authorize(Permissions.Name)] public class UserRoleController : Controller { - readonly ISysUserInfoServices _sysUserInfoServices; - readonly IUserRoleServices _userRoleServices; - readonly IRoleServices _roleServices; + private readonly ISysUserInfoServices _sysUserInfoServices; + private readonly IUserRoleServices _userRoleServices; + private readonly IRoleServices _roleServices; + private readonly IMapper _mapper; /// /// 构造函数 /// /// /// + /// /// - public UserRoleController(ISysUserInfoServices sysUserInfoServices, IUserRoleServices userRoleServices, IRoleServices roleServices) + public UserRoleController(ISysUserInfoServices sysUserInfoServices, IUserRoleServices userRoleServices, IMapper mapper, IRoleServices roleServices) { - this._sysUserInfoServices = sysUserInfoServices; - this._userRoleServices = userRoleServices; - this._roleServices = roleServices; + _sysUserInfoServices = sysUserInfoServices; + _userRoleServices = userRoleServices; + _roleServices = roleServices; + _mapper = mapper; } @@ -42,13 +46,14 @@ public UserRoleController(ISysUserInfoServices sysUserInfoServices, IUserRoleSer /// /// [HttpGet] - public async Task> AddUser(string loginName, string loginPwd) + public async Task> AddUser(string loginName, string loginPwd) { - return new MessageModel() + var userInfo = await _sysUserInfoServices.SaveUserInfo(loginName, loginPwd); + return new MessageModel() { success = true, msg = "添加成功", - response = await _sysUserInfoServices.SaveUserInfo(loginName, loginPwd) + response = _mapper.Map(userInfo) }; } @@ -75,7 +80,7 @@ public async Task> AddRole(string roleName) /// /// [HttpGet] - public async Task> AddUserRole(int uid, int rid) + public async Task> AddUserRole(long uid, long rid) { return new MessageModel() { diff --git a/Blog.Core.Api/Controllers/ValuesController.cs b/Blog.Core.Api/Controllers/ValuesController.cs index bd81c87d..22d663e9 100644 --- a/Blog.Core.Api/Controllers/ValuesController.cs +++ b/Blog.Core.Api/Controllers/ValuesController.cs @@ -1,11 +1,11 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Threading.Tasks; -using AutoMapper; +using AutoMapper; +using Blog.Core.Common; using Blog.Core.Common.HttpContextUser; -using Blog.Core.Common.HttpRestSharp; -using Blog.Core.Common.WebApiClients.HttpApis; +using Blog.Core.Common.Https.HttpPolly; +using Blog.Core.Common.Option; +using Blog.Core.EventBus; +using Blog.Core.EventBus.EventHandling; +using Blog.Core.Extensions; using Blog.Core.Filter; using Blog.Core.IServices; using Blog.Core.Model; @@ -13,20 +13,28 @@ using Blog.Core.Model.ViewModels; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using RabbitMQ.Client; +using RabbitMQ.Client.Events; +using System.ComponentModel.DataAnnotations; +using System.Linq.Expressions; +using System.Text; +using Blog.Core.Common.Caches.Interface; +using Blog.Core.Common.Utility; namespace Blog.Core.Controllers { /// /// Values控制器 /// - [Route("api/[controller]")] + [Route("api/[controller]/[action]")] [ApiController] //[Authorize] //[Authorize(Roles = "Admin,Client")] //[Authorize(Policy = "SystemOrAdmin")] //[Authorize(PermissionNames.Permission)] [Authorize] - public class ValuesController : ControllerBase + public class ValuesController : BaseApiController { private IMapper _mapper; private readonly IAdvertisementServices _advertisementServices; @@ -34,39 +42,109 @@ public class ValuesController : ControllerBase private readonly IRoleModulePermissionServices _roleModulePermissionServices; private readonly IUser _user; private readonly IPasswordLibServices _passwordLibServices; - private readonly IBlogApi _blogApi; - private readonly IDoubanApi _doubanApi; readonly IBlogArticleServices _blogArticleServices; - - /// - /// ValuesController - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public ValuesController(IBlogArticleServices blogArticleServices, IMapper mapper, IAdvertisementServices advertisementServices, Love love, IRoleModulePermissionServices roleModulePermissionServices, IUser user, IPasswordLibServices passwordLibServices, IBlogApi blogApi, IDoubanApi doubanApi) + private readonly IHttpPollyHelper _httpPollyHelper; + private readonly IRabbitMQPersistentConnection _persistentConnection; + private readonly SeqOptions _seqOptions; + private readonly ICaching _cache; + + public ValuesController(IBlogArticleServices blogArticleServices, IMapper mapper, + IAdvertisementServices advertisementServices, Love love, + IRoleModulePermissionServices roleModulePermissionServices, IUser user, + IPasswordLibServices passwordLibServices, + IHttpPollyHelper httpPollyHelper, IRabbitMQPersistentConnection persistentConnection, + IOptions seqOptions, ICaching caching) { // 测试 Authorize 和 mapper - _mapper = mapper; - _advertisementServices = advertisementServices; - _love = love; + _mapper = mapper; + _advertisementServices = advertisementServices; + _love = love; _roleModulePermissionServices = roleModulePermissionServices; // 测试 Httpcontext _user = user; // 测试多库 _passwordLibServices = passwordLibServices; - // 测试http请求 - _blogApi = blogApi; - _doubanApi = doubanApi; // 测试AOP加载顺序,配合 return _blogArticleServices = blogArticleServices; + // 测试redis消息队列 + _blogArticleServices = blogArticleServices; + // httpPolly + _httpPollyHelper = httpPollyHelper; + _persistentConnection = persistentConnection; + _cache = caching; + _seqOptions = seqOptions.Value; } + + /// + /// 测试Rabbit消息队列发送 + /// + [HttpGet] + [AllowAnonymous] + public IActionResult TestRabbitMqPublish() + { + if (!_persistentConnection.IsConnected) + { + _persistentConnection.TryConnect(); + } + + _persistentConnection.PublishMessage("Hello, RabbitMQ!", exchangeName: "blogcore", + routingKey: "myRoutingKey"); + return Ok(); + } + + /// + /// 测试Rabbit消息队列订阅 + /// + [HttpGet] + [AllowAnonymous] + public IActionResult TestRabbitMqSubscribe() + { + if (!_persistentConnection.IsConnected) + { + _persistentConnection.TryConnect(); + } + + _persistentConnection.StartConsuming("myQueue"); + return Ok(); + } + + private async Task Dealer(string exchange, string routingKey, byte[] msgBody, + IDictionary headers) + { + await Task.CompletedTask; + Console.WriteLine("我是消费者,这里消费了一条信息是:" + Encoding.UTF8.GetString(msgBody)); + return true; + } + + [HttpGet] + public MessageModel> MyClaims() + { + return new MessageModel>() + { + success = true, + response = (_user.GetClaimsIdentity().ToList()).Select(d => + new ClaimDto + { + Type = d.Type, + Value = d.Value + } + ).ToList() + }; + } + + /// + /// 测试SqlSugar二级缓存 + /// 可设置过期时间 + /// 或通过接口方式更新该数据,也会离开清除缓存 + /// + /// + [HttpGet] + [AllowAnonymous] + public async Task TestSqlsugarWithCache() + { + return await _blogArticleServices.QueryById("1", true); + } + /// /// Get方法 /// @@ -81,24 +159,34 @@ public async Task> Get() /* * 测试 sql 查询 */ - var queryBySql = await _blogArticleServices.QuerySql("SELECT bsubmitter,btitle,bcontent,bCreateTime FROM BlogArticle WHERE bID>5"); + var queryBySql = + await _blogArticleServices.QuerySql( + "SELECT bsubmitter,btitle,bcontent,bCreateTime FROM BlogArticle WHERE bID>5"); + /* + * 测试按照指定列查询 + */ + var queryByColums = await _blogArticleServices + .Query(it => new BlogViewModels() { btitle = it.btitle }); + + /* + * 测试按照指定列查询带多条件和排序方法 + */ + Expression> registerInfoWhere = a => a.btitle == "xxx" && a.bRemark == "XXX"; + var queryByColumsByMultiTerms = await _blogArticleServices + .Query(it => new BlogArticle() { btitle = it.btitle }, registerInfoWhere, "bID Desc"); /* * 测试 sql 更新 - * + * * 【SQL参数】:@bID:5 * @bsubmitter:laozhang619 * @IsDeleted:False * 【SQL语句】:UPDATE `BlogArticle` SET * `bsubmitter`=@bsubmitter,`IsDeleted`=@IsDeleted WHERE `bID`=@bID */ - var updateSql = await _blogArticleServices.Update(new { bsubmitter = $"laozhang{DateTime.Now.Millisecond}", IsDeleted = false, bID = 5 }); - - - // 测试模拟异常,全局异常过滤器拦截 - var i = 0; - var d = 3 / i; + var updateSql = await _blogArticleServices.Update(new + { bsubmitter = $"laozhang{DateTime.Now.Millisecond}", IsDeleted = false, bID = 5 }); // 测试 AOP 缓存 @@ -111,19 +199,61 @@ public async Task> Get() // 测试多个异步执行时间 var roleModuleTask = _roleModulePermissionServices.Query(); - var listTask = _advertisementServices.Query(); - var ad = await roleModuleTask; - var list = await listTask; + var listTask = _advertisementServices.Query(); + var ad = await roleModuleTask; + var list = await listTask; // 测试service层返回异常 _advertisementServices.ReturnExp(); - Love love = null; - love.SayLoveU(); - return data; } + + + [HttpGet] + [AllowAnonymous] + public async Task>> Test_Aop_Cache() + { + // 测试 AOP 缓存 + var blogArticles = await _blogArticleServices.GetBlogs(); + + if (blogArticles.Any()) + { + return Success(blogArticles); + } + + return Failed>(); + } + + /// + /// 测试Redis消息队列 + /// + /// + /// + [HttpGet] + [AllowAnonymous] + public async Task RedisMq([FromServices] IRedisBasketRepository _redisBasketRepository) + { + var msg = $"这里是一条日志{DateTime.Now}"; + await _redisBasketRepository.ListLeftPushAsync(RedisMqKey.Loging, msg); + } + + /// + /// 测试RabbitMQ事件总线 + /// + /// + /// + /// + [HttpGet] + [AllowAnonymous] + public void EventBusTry([FromServices] IEventBus _eventBus, string blogId = "1") + { + var blogDeletedEvent = new BlogQueryIntegrationEvent(blogId); + + _eventBus.Publish(blogDeletedEvent); + } + /// /// Get(int id)方法 /// @@ -132,7 +262,6 @@ public async Task> Get() // GET api/values/5 [HttpGet("{id}")] [AllowAnonymous] - //[TypeFilter(typeof(DeleteSubscriptionCache),Arguments =new object[] { "1"})] [TypeFilter(typeof(UseServiceDIAttribute), Arguments = new object[] { "laozhang" })] public ActionResult Get(int id) { @@ -148,7 +277,7 @@ public ActionResult Get(int id) /// [HttpGet] [Route("/api/values/RequiredPara")] - public string RequiredP([Required]string id) + public string RequiredP([Required] string id) { return id; } @@ -166,8 +295,8 @@ public MessageModel> GetUserInfo(string ClaimType = "jti") var getUserInfoByToken = _user.GetUserInfoFromToken(ClaimType); return new MessageModel>() { - success = _user.IsAuthenticated(), - msg = _user.IsAuthenticated() ? _user.Name.ObjToString() : "未登录", + success = _user.IsAuthenticated(), + msg = _user.IsAuthenticated() ? _user.Name.ObjToString() : "未登录", response = _user.GetClaimValueByType(ClaimType) }; } @@ -202,7 +331,7 @@ public string Destination() /// 独立参数 [HttpPost] [AllowAnonymous] - public object Post([FromBody] BlogArticle blogArticle, int id) + public object Post([FromBody] BlogArticle blogArticle, int id) { return Ok(new { success = true, data = blogArticle, id = id }); } @@ -214,34 +343,12 @@ public object Post([FromBody] BlogArticle blogArticle, int id) /// /// [HttpPost] - [Route("TestPostPara")] [AllowAnonymous] public object TestPostPara(string name) { return Ok(new { success = true, name = name }); } - /// - /// 测试http请求 RestSharp Get - /// - /// - [HttpGet("RestsharpGet")] - [AllowAnonymous] - public TestRestSharpGetDto RestsharpGet() - { - return HttpHelper.GetApi("http://apk.neters.club/", "api/Blog/DetailNuxtNoPer", "id=1"); - } - /// - /// 测试http请求 RestSharp Post - /// - /// - [HttpGet("RestsharpPost")] - [AllowAnonymous] - public TestRestSharpPostDto RestsharpPost() - { - return HttpHelper.PostApi("http://apk.neters.club/api/Values/TestPostPara?name=老张", new { age = 18 }); - } - /// /// 测试多库连接 /// @@ -250,11 +357,13 @@ public TestRestSharpPostDto RestsharpPost() [AllowAnonymous] public async Task TestMutiDBAPI() { - // 从主库(Sqlite)中,操作blogs - var blogs = await _blogArticleServices.Query(d => d.bID == 1); + // 从主库中,操作blogs + var blogs = await _blogArticleServices.Query(d => d.bID == 1); + var addBlog = await _blogArticleServices.Add(new BlogArticle() { }); - // 从从库(Sqlserver)中,获取pwds - var pwds = await _passwordLibServices.Query(d => d.PLID > 0); + // 从从库中,操作pwds + var pwds = await _passwordLibServices.Query(d => d.PLID > 0); + var addPwd = await _passwordLibServices.Add(new PasswordLib() { }); return new { @@ -264,17 +373,16 @@ public async Task TestMutiDBAPI() } /// - /// 测试http请求 WebApiClient Get + /// 测试Fulent做参数校验 /// + /// /// - [HttpGet("WebApiClientGetAsync")] + [HttpPost] [AllowAnonymous] - public async Task WebApiClientGetAsync() + public async Task FluentVaTest([FromBody] UserRegisterVo param) { - int id = 1; - string isbn = "9787544270878"; - var doubanVideoDetail = await _doubanApi.VideoDetailAsync(isbn); - return await _blogApi.DetailNuxtNoPerAsync(id); + await Task.CompletedTask; + return "Okay"; } /// @@ -287,6 +395,7 @@ public async Task WebApiClientGetAsync() public void Put(int id, [FromBody] string value) { } + /// /// Delete方法 /// @@ -296,5 +405,117 @@ public void Put(int id, [FromBody] string value) public void Delete(int id) { } + + #region Apollo 配置 + + /// + /// 测试接入Apollo获取配置信息 + /// + [HttpGet("/apollo")] + [AllowAnonymous] + public async Task>> GetAllConfigByAppllo( + [FromServices] IConfiguration configuration) + { + return await Task.FromResult(configuration.AsEnumerable()); + } + + /// + /// 通过此处的key格式为 xx:xx:x + /// + [HttpGet("/apollo/{key}")] + [AllowAnonymous] + public async Task GetConfigByAppllo(string key) + { + return await Task.FromResult(AppSettings.app(key)); + } + + #endregion + + #region HttpPolly + + [HttpPost] + [AllowAnonymous] + public async Task HttpPollyPost() + { + var response = await _httpPollyHelper.PostAsync(HttpEnum.LocalHost, "/api/ElasticDemo/EsSearchTest", + "{\"from\": 0,\"size\": 10,\"word\": \"非那雄安\"}"); + + return response; + } + + [HttpGet] + [AllowAnonymous] + public async Task HttpPollyGet() + { + return await _httpPollyHelper.GetAsync(HttpEnum.LocalHost, + "/api/ElasticDemo/GetDetailInfo?esid=3130&esindex=chinacodex"); + } + + #endregion + + [HttpPost] + [AllowAnonymous] + public string TestEnum(EnumDemoDto dto) => dto.Type.ToString(); + + [HttpGet] + [AllowAnonymous] + public string TestOption() + { + return _seqOptions.ToJson(); + } + + /// + /// 获取雪花Id + /// + /// + [HttpGet] + [AllowAnonymous] + public long GetSnowflakeId() + { + return IdGeneratorUtility.NextId(); + } + + /// + /// 测试缓存 + /// + /// + [HttpGet] + [AllowAnonymous] + public async Task> TestCacheAsync() + { + await _cache.SetAsync("test", "test", new TimeSpan(0, 10, 0)); + + var result = await _cache.GetAsync("test"); + if (!"test".Equals(result)) + { + return Failed("缓存失败,值不一样"); + } + + var count = _cache.GetAllCacheKeys().Count; + if (count <= 0) + { + return Failed("缓存失败,数量不对"); + } + + return Success(""); + } + + /// + /// 雪花Id To DateTime + /// + /// + /// + [HttpGet] + [AllowAnonymous] + public DateTime SnowflakeIdToDateTime(long id) + { + return YitterSnowflakeHelper.GetDateTime(IdGeneratorUtility.GetOptions(), id); + } + } + + public class ClaimDto + { + public string Type { get; set; } + public string Value { get; set; } } -} +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/WeChatCompanyController.cs b/Blog.Core.Api/Controllers/WeChatCompanyController.cs new file mode 100644 index 00000000..dc12930b --- /dev/null +++ b/Blog.Core.Api/Controllers/WeChatCompanyController.cs @@ -0,0 +1,91 @@ +using Blog.Core.IServices; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Controllers +{ + /// + /// WeChatCompanyController + /// + [Route("api/[controller]/[action]")] + [ApiController] + [Authorize(Permissions.Name)] + public partial class WeChatCompanyController : Controller + { + readonly IWeChatCompanyServices _WeChatCompanyServices; + /// + /// 构造函数 + /// + /// + public WeChatCompanyController(IWeChatCompanyServices iWeChatCompanyServices) + { + _WeChatCompanyServices = iWeChatCompanyServices; + } + /// + /// 获取 + /// + /// 分页条件 + /// + [HttpGet] + public async Task>> Get([FromQuery] PaginationModel pagination) + { + var data = await _WeChatCompanyServices.QueryPage(pagination); + return new MessageModel> { success = true, response = data}; + } + /// + /// 获取(id) + /// + /// 主键ID + /// + [HttpGet("{id}")] + public async Task> Get(string id) + { + var data = await _WeChatCompanyServices.QueryById(id); + return new MessageModel { success = true, response = data }; + } + /// + /// 添加 + /// + /// + [HttpPost] + public async Task> Post([FromBody] WeChatCompany obj) + { + await _WeChatCompanyServices.Add(obj); + return new MessageModel { success = true}; + } + /// + /// 更新 + /// + /// + [HttpPut] + public async Task> Put([FromBody] WeChatCompany obj) + { + await _WeChatCompanyServices.Update(obj); + return new MessageModel { success = true}; + } + /// + /// 删除 + /// + /// + [HttpDelete] + public async Task> Delete(string id) + { + await _WeChatCompanyServices.DeleteById(id); + return new MessageModel { success = true}; + } + /// + /// 批量删除 + /// + /// + [HttpDelete] + public async Task> BatchDelete(string ids) + { + var i = ids.Split(","); + await _WeChatCompanyServices.DeleteByIds(i); + return new MessageModel { success = true }; + } + + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/WeChatConfigController.cs b/Blog.Core.Api/Controllers/WeChatConfigController.cs new file mode 100644 index 00000000..1f3b705d --- /dev/null +++ b/Blog.Core.Api/Controllers/WeChatConfigController.cs @@ -0,0 +1,91 @@ +using Blog.Core.IServices; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Controllers +{ + /// + /// WeChatConfigController + /// + [Route("api/[controller]/[action]")] + [ApiController] + [Authorize(Permissions.Name)] + public partial class WeChatConfigController : Controller + { + readonly IWeChatConfigServices _WeChatConfigServices; + /// + /// 构造函数 + /// + /// + public WeChatConfigController(IWeChatConfigServices iWeChatConfigServices) + { + _WeChatConfigServices = iWeChatConfigServices; + } + /// + /// 获取 + /// + /// 分页条件 + /// + [HttpGet] + public async Task>> Get([FromQuery] PaginationModel pagination) + { + var data = await _WeChatConfigServices.QueryPage(pagination); + return new MessageModel> { success = true, response = data}; + } + /// + /// 获取(id) + /// + /// 主键ID + /// + [HttpGet("{id}")] + public async Task> Get(string id) + { + var data = await _WeChatConfigServices.QueryById(id); + return new MessageModel { success = true, response = data }; + } + /// + /// 添加 + /// + /// + [HttpPost] + public async Task> Post([FromBody] WeChatConfig obj) + { + await _WeChatConfigServices.Add(obj); + return new MessageModel { success = true}; + } + /// + /// 更新 + /// + /// + [HttpPut] + public async Task> Put([FromBody] WeChatConfig obj) + { + await _WeChatConfigServices.Update(obj); + return new MessageModel { success = true}; + } + /// + /// 删除 + /// + /// + [HttpDelete] + public async Task> Delete(string id) + { + await _WeChatConfigServices.DeleteById(id); + return new MessageModel { success = true}; + } + /// + /// 批量删除 + /// + /// + [HttpDelete] + public async Task> BatchDelete(string ids) + { + var i = ids.Split(","); + await _WeChatConfigServices.DeleteByIds(i); + return new MessageModel { success = true }; + } + + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/WeChatController.cs b/Blog.Core.Api/Controllers/WeChatController.cs new file mode 100644 index 00000000..5c7e5c6f --- /dev/null +++ b/Blog.Core.Api/Controllers/WeChatController.cs @@ -0,0 +1,189 @@ +using Blog.Core.IServices; +using Blog.Core.Model; +using Blog.Core.Model.ViewModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Controllers +{ + /// + /// 微信公众号管理 + /// + [Route("api/[controller]/[action]")] + [ApiController] + [Authorize(Permissions.Name)] + public partial class WeChatController : Controller + { + readonly IWeChatConfigServices _weChatConfigServices; + readonly ILogger _logger; + /// + /// 构造函数 + /// + /// + /// + public WeChatController(IWeChatConfigServices weChatConfigServices, ILogger logger) + { + _weChatConfigServices = weChatConfigServices; + _logger = logger; + } + /// + /// 更新Token + /// + /// + /// + [HttpGet] + public async Task> GetToken(string id) + { + return await _weChatConfigServices.GetToken(id); + + } + /// + /// 刷新Token + /// + /// + /// + [HttpGet] + public async Task> RefreshToken(string id) + { + return await _weChatConfigServices.RefreshToken(id); + + } + /// + /// 获取模板 + /// + /// + /// + [HttpGet] + public async Task> GetTemplate(string id) + { + return await _weChatConfigServices.GetTemplate(id); + } + /// + /// 获取菜单 + /// + /// + /// + [HttpGet] + public async Task> GetMenu(string id) + { + return await _weChatConfigServices.GetMenu(id); + } + + /// + /// 更新菜单 + /// + /// + /// + [HttpPut] + public async Task> UpdateMenu(WeChatApiDto menu) + { + return await _weChatConfigServices.UpdateMenu(menu); + } + /// + /// 获取订阅用户(所有) + /// + /// + /// + [HttpGet] + public async Task> GetSubUsers(string id) + { + return await _weChatConfigServices.GetSubUsers(id); + } + /// + /// 入口 + /// + /// + /// + [AllowAnonymous] + [HttpPost] + [HttpGet] + public async Task Valid([FromQuery] WeChatValidDto validDto) + { + using (var reader = new StreamReader(Request.Body)) + { + var body = await reader.ReadToEndAsync(); + return await _weChatConfigServices.Valid(validDto, body); + } + } + /// + /// 获取订阅用户 + /// + /// + /// + /// + [HttpGet] + [AllowAnonymous] + public async Task> GetSubUser(string id,string openid) + { + return await _weChatConfigServices.GetSubUser(id,openid); + } + /// + /// 获取一个绑定员工公众号二维码 + /// + /// 消息 + /// + [HttpGet] + [AllowAnonymous] + public async Task> GetQRBind([FromQuery]WeChatUserInfo info) + { + return await _weChatConfigServices.GetQRBind(info); + } + /// + /// 推送卡片消息接口 + /// + /// 卡片消息对象 + /// + [HttpPost] + [AllowAnonymous] + public async Task> PushCardMsg(WeChatCardMsgDataDto msg) + { + string pushUserIP = $"{Request.HttpContext.Connection.RemoteIpAddress}:{Request.HttpContext.Connection.RemotePort}"; + return await _weChatConfigServices.PushCardMsg(msg, pushUserIP); + } + /// + /// 推送卡片消息接口 + /// + /// 卡片消息对象 + /// + [HttpGet] + [AllowAnonymous] + public async Task> PushCardMsgGet([FromQuery] WeChatCardMsgDataDto msg) + { + string pushUserIP = $"{Request.HttpContext.Connection.RemoteIpAddress}:{Request.HttpContext.Connection.RemotePort}"; + return await _weChatConfigServices.PushCardMsg(msg, pushUserIP); + } + /// + /// 推送文本消息 + /// + /// 消息对象 + /// + [HttpPost] + [AllowAnonymous] + public async Task> PushTxtMsg([FromBody] WeChatPushTestDto msg) + { + return await _weChatConfigServices.PushTxtMsg(msg); + } + /// + /// 通过绑定用户获取微信用户信息(一般用于初次绑定检测) + /// + /// 信息 + /// + [HttpGet] + [AllowAnonymous] + public async Task> GetBindUserInfo([FromQuery]WeChatUserInfo info) + { + return await _weChatConfigServices.GetBindUserInfo(info); + } + /// + /// 用户解绑 + /// + /// 消息 + /// + [HttpGet] + [AllowAnonymous] + public async Task> UnBind([FromQuery]WeChatUserInfo info) + { + return await _weChatConfigServices.UnBind(info); + } + } +} diff --git a/Blog.Core.Api/Controllers/WeChatPushLogController.cs b/Blog.Core.Api/Controllers/WeChatPushLogController.cs new file mode 100644 index 00000000..af168091 --- /dev/null +++ b/Blog.Core.Api/Controllers/WeChatPushLogController.cs @@ -0,0 +1,91 @@ +using Blog.Core.IServices; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Controllers +{ + /// + /// WeChatPushLogController + /// + [Route("api/[controller]/[action]")] + [ApiController] + [Authorize(Permissions.Name)] + public partial class WeChatPushLogController : Controller + { + readonly IWeChatPushLogServices _WeChatPushLogServices; + /// + /// 构造函数 + /// + /// + public WeChatPushLogController(IWeChatPushLogServices iWeChatPushLogServices) + { + _WeChatPushLogServices = iWeChatPushLogServices; + } + /// + /// 获取 + /// + /// 分页条件 + /// + [HttpGet] + public async Task>> Get([FromQuery] PaginationModel pagination) + { + var data = await _WeChatPushLogServices.QueryPage(pagination); + return new MessageModel> { success = true, response = data}; + } + /// + /// 获取(id) + /// + /// 主键ID + /// + [HttpGet("{id}")] + public async Task> Get(string id) + { + var data = await _WeChatPushLogServices.QueryById(id); + return new MessageModel { success = true, response = data }; + } + /// + /// 添加 + /// + /// + [HttpPost] + public async Task> Post([FromBody] WeChatPushLog obj) + { + await _WeChatPushLogServices.Add(obj); + return new MessageModel { success = true}; + } + /// + /// 更新 + /// + /// + [HttpPut] + public async Task> Put([FromBody] WeChatPushLog obj) + { + await _WeChatPushLogServices.Update(obj); + return new MessageModel { success = true}; + } + /// + /// 删除 + /// + /// + [HttpDelete] + public async Task> Delete(string id) + { + await _WeChatPushLogServices.DeleteById(id); + return new MessageModel { success = true}; + } + /// + /// 批量删除 + /// + /// + [HttpDelete] + public async Task> BatchDelete(string ids) + { + var i = ids.Split(","); + await _WeChatPushLogServices.DeleteByIds(i); + return new MessageModel { success = true }; + } + + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Controllers/WeChatSubController.cs b/Blog.Core.Api/Controllers/WeChatSubController.cs new file mode 100644 index 00000000..94f982d2 --- /dev/null +++ b/Blog.Core.Api/Controllers/WeChatSubController.cs @@ -0,0 +1,91 @@ +using Blog.Core.IServices; +using Blog.Core.Model; +using Blog.Core.Model.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Controllers +{ + /// + /// WeChatSubController + /// + [Route("api/[controller]/[action]")] + [ApiController] + [Authorize(Permissions.Name)] + public partial class WeChatSubController : Controller + { + readonly IWeChatSubServices _WeChatSubServices; + /// + /// 构造函数 + /// + /// + public WeChatSubController(IWeChatSubServices iWeChatSubServices) + { + _WeChatSubServices = iWeChatSubServices; + } + /// + /// 获取 + /// + /// 分页条件 + /// + [HttpGet] + public async Task>> Get([FromQuery] PaginationModel pagination) + { + var data = await _WeChatSubServices.QueryPage(pagination); + return new MessageModel> { success = true, response = data}; + } + /// + /// 获取(id) + /// + /// 主键ID + /// + [HttpGet("{id}")] + public async Task> Get(string id) + { + var data = await _WeChatSubServices.QueryById(id); + return new MessageModel { success = true, response = data }; + } + /// + /// 添加 + /// + /// + [HttpPost] + public async Task> Post([FromBody] WeChatSub obj) + { + await _WeChatSubServices.Add(obj); + return new MessageModel { success = true}; + } + /// + /// 更新 + /// + /// + [HttpPut] + public async Task> Put([FromBody] WeChatSub obj) + { + await _WeChatSubServices.Update(obj); + return new MessageModel { success = true}; + } + /// + /// 删除 + /// + /// + [HttpDelete] + public async Task> Delete(string id) + { + await _WeChatSubServices.DeleteById(id); + return new MessageModel { success = true}; + } + /// + /// 批量删除 + /// + /// + [HttpDelete] + public async Task> BatchDelete(string ids) + { + var i = ids.Split(","); + await _WeChatSubServices.DeleteByIds(i); + return new MessageModel { success = true }; + } + + } +} \ No newline at end of file diff --git a/Blog.Core.Api/Dockerfile b/Blog.Core.Api/Dockerfile index d217eab8..afb398c1 100644 --- a/Blog.Core.Api/Dockerfile +++ b/Blog.Core.Api/Dockerfile @@ -1,5 +1,41 @@ -FROM swr.cn-south-1.myhuaweicloud.com/mcr/aspnet:3.1-alpine +#这种模式是先dotnet build后,然后再把dll进行构建镜像。 +#如果你想把这两步合在一起,可以看.sln根目录下的那个dockerfile。 + +#FROM swr.cn-south-1.myhuaweicloud.com/mcr/aspnet:5.0-alpine +#FROM mcr.microsoft.com/dotnet/core/aspnet:5.0-buster-slim +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +RUN echo 'Asia/Shanghai' >/etc/timezone + +#RUN apk add --no-cache ca-certificates python3 bash openssh git openssl-dev uwsgi uwsgi-python3 +#RUN apk add --no-cache --virtual .build-deps python3-dev gcc musl-dev libffi-dev make \ + #&& pip3 install --no-cache-dir --trusted-host mirrors.aliyun.com -i http://mirrors.aliyun.com/pypi/simple/ \ + #pymysql==0.8.1 \ + #Flask==1.0.2 \ + #Flask-RESTful==0.3.6 \ + #Flask-Script==2.0.6 \ + #Flask-SQLAlchemy==2.3.2 \ + #Flask-WTF==0.14.2 \ + #SQLAlchemy==1.2.7 \ + #simplejson==5.06.0 \ + #six==1.11.0 \ + #celery==4.2.1 \ + #xlrd==1.1.0 \ + #xlwt==1.3.0 \ + #msgpack==0.5.0 \ + #&& apk del .build-deps +# +#RUN git clone https://github.com/Supervisor/supervisor.git \ + #&& cd supervisor \ + #&& python3 setup.py install \ + #&& cd .. \ + #&& rm -rf supervisor \ + #&& cd /etc/ \ + #&& echo_supervisord_conf > supervisord.conf \ + #&& echo '[include]' >> supervisord.conf \ + #&& echo 'files = /code/supervisor/*.ini' >> supervisord.conf \ + #&& supervisord -c /etc/supervisord.conf WORKDIR /app COPY . . -EXPOSE 8081 +EXPOSE 9291 ENTRYPOINT ["dotnet", "Blog.Core.Api.dll","-b","0.0.0.0"] \ No newline at end of file diff --git a/Blog.Core.Api/Filter/AutofacPropertityModuleReg.cs b/Blog.Core.Api/Filter/AutofacPropertityModuleReg.cs new file mode 100644 index 00000000..605c4f5a --- /dev/null +++ b/Blog.Core.Api/Filter/AutofacPropertityModuleReg.cs @@ -0,0 +1,19 @@ +using Autofac; +using Microsoft.AspNetCore.Mvc; + +namespace Blog.Core.Filter +{ + public class AutofacPropertityModuleReg : Autofac.Module + { + protected override void Load(ContainerBuilder builder) + { + // 记得要启动服务注册 + // builder.Services.Replace(ServiceDescriptor.Transient()); + var controllerBaseType = typeof(ControllerBase); + builder.RegisterAssemblyTypes(typeof(Program).Assembly) + .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType) + .PropertiesAutowired(); + + } + } +} diff --git a/Blog.Core.Api/Filter/GlobalExceptionFilter.cs b/Blog.Core.Api/Filter/GlobalExceptionFilter.cs index 694dcf41..e11d8dbd 100644 --- a/Blog.Core.Api/Filter/GlobalExceptionFilter.cs +++ b/Blog.Core.Api/Filter/GlobalExceptionFilter.cs @@ -1,14 +1,12 @@ -using Blog.Core.Common.LogHelper; +using Blog.Core.Common; +using Blog.Core.Common.Helper; +using Blog.Core.Common.LogHelper; using Blog.Core.Hubs; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; +using Blog.Core.Model; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.SignalR; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; using StackExchange.Profiling; -using System; namespace Blog.Core.Filter { @@ -21,37 +19,45 @@ public class GlobalExceptionsFilter : IExceptionFilter private readonly IHubContext _hubContext; private readonly ILogger _loggerHelper; - public GlobalExceptionsFilter(IWebHostEnvironment env, ILogger loggerHelper, IHubContext hubContext) + public GlobalExceptionsFilter(IWebHostEnvironment env, ILogger loggerHelper, + IHubContext hubContext) { - _env = env; + _env = env; _loggerHelper = loggerHelper; - _hubContext = hubContext; + _hubContext = hubContext; } public void OnException(ExceptionContext context) { - var json = new JsonErrorResponse(); + var json = new MessageModel(); - json.Message = context.Exception.Message;//错误信息 + json.msg = context.Exception.Message; //错误信息 + json.status = 500; //500异常 var errorAudit = "Unable to resolve service for"; - if (!string.IsNullOrEmpty(json.Message)&& json.Message.Contains(errorAudit)) + if (!string.IsNullOrEmpty(json.msg) && json.msg.Contains(errorAudit)) { - json.Message = json.Message.Replace(errorAudit, $"(若新添加服务,需要重新编译项目){errorAudit}"); + json.msg = json.msg.Replace(errorAudit, $"(若新添加服务,需要重新编译项目){errorAudit}"); } - if (_env.IsDevelopment()) + + if (_env.EnvironmentName.ObjToString().Equals("Development")) { - json.DevelopmentMessage = context.Exception.StackTrace;//堆栈信息 + json.msgDev = context.Exception.StackTrace; //堆栈信息 } - context.Result = new InternalServerErrorObjectResult(json); - MiniProfiler.Current.CustomTiming("Errors:", json.Message); + var res = new ContentResult(); + res.Content = JsonHelper.GetJSON>(json); + context.Result = res; - //采用log4net 进行错误日志记录 - _loggerHelper.LogError(json.Message + WriteLog(json.Message, context.Exception)); + MiniProfiler.Current.CustomTiming("Errors:", json.msg); - _hubContext.Clients.All.SendAsync("ReceiveUpdate", LogLock.GetLogData()).Wait(); + //进行错误日志记录 + _loggerHelper.LogError(json.msg + WriteLog(json.msg, context.Exception)); + if (AppSettings.app(new string[] { "Middleware", "SignalRSendLog", "Enabled" }).ObjToBool()) + { + _hubContext.Clients.All.SendAsync("ReceiveUpdate", json.msg).Wait(); + } } /// @@ -62,11 +68,14 @@ public void OnException(ExceptionContext context) /// public string WriteLog(string throwMsg, Exception ex) { - return string.Format("\r\n【自定义错误】:{0} \r\n【异常类型】:{1} \r\n【异常信息】:{2} \r\n【堆栈调用】:{3}", new object[] { throwMsg, - ex.GetType().Name, ex.Message, ex.StackTrace }); + return string.Format("\r\n【自定义错误】:{0} \r\n【异常类型】:{1} \r\n【异常信息】:{2} \r\n【堆栈调用】:{3}", new object[] + { + throwMsg, + ex.GetType().Name, ex.Message, ex.StackTrace + }); } - } + public class InternalServerErrorObjectResult : ObjectResult { public InternalServerErrorObjectResult(object value) : base(value) @@ -74,6 +83,7 @@ public InternalServerErrorObjectResult(object value) : base(value) StatusCode = StatusCodes.Status500InternalServerError; } } + //返回错误信息 public class JsonErrorResponse { @@ -81,10 +91,10 @@ public class JsonErrorResponse /// 生产环境的消息 /// public string Message { get; set; } + /// /// 开发环境的消息 /// public string DevelopmentMessage { get; set; } } - -} +} \ No newline at end of file diff --git a/Blog.Core.Api/Filter/UseServiceDIAttribute.cs b/Blog.Core.Api/Filter/UseServiceDIAttribute.cs index dc5f6780..2c487872 100644 --- a/Blog.Core.Api/Filter/UseServiceDIAttribute.cs +++ b/Blog.Core.Api/Filter/UseServiceDIAttribute.cs @@ -1,7 +1,5 @@ using Blog.Core.IServices; using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.Logging; -using System; namespace Blog.Core.Filter { @@ -12,7 +10,7 @@ public class UseServiceDIAttribute : ActionFilterAttribute private readonly IBlogArticleServices _blogArticleServices; private readonly string _name; - public UseServiceDIAttribute(ILogger logger, IBlogArticleServices blogArticleServices,string Name="") + public UseServiceDIAttribute(ILogger logger, IBlogArticleServices blogArticleServices, string Name = "") { _logger = logger; _blogArticleServices = blogArticleServices; @@ -22,21 +20,16 @@ public UseServiceDIAttribute(ILogger logger, IBlogArticle public override void OnActionExecuted(ActionExecutedContext context) { - //var dd =await _blogArticleServices.Query(); + var dd = _blogArticleServices.Query().Result; + _logger.LogInformation("测试自定义服务特性"); + Console.WriteLine(_name); base.OnActionExecuted(context); DeleteSubscriptionFiles(); } private void DeleteSubscriptionFiles() { - try - { - // ... - } - catch (Exception e) - { - _logger.LogError(e, "Error Delete Subscription Files"); - } + } } } diff --git a/Blog.Core.Api/Filter/UserRegisterVo.cs b/Blog.Core.Api/Filter/UserRegisterVo.cs new file mode 100644 index 00000000..163a39e3 --- /dev/null +++ b/Blog.Core.Api/Filter/UserRegisterVo.cs @@ -0,0 +1,67 @@ +using FluentValidation; +using System.Text.RegularExpressions; + +namespace Blog.Core.Filter +{ + public class UserRegisterVo + { + public string WxUid { get; set; } + + public string Telphone { get; set; } + + public string NickName { get; set; } + + public string SourceType { get; set; } + public IEnumerable Cars { get; set; } + + } + + public class CarInfo + { + public int CarCount { get; set; } + public int CarSize { get; set; } + } + + public class UserRegisterVoValidator : AbstractValidator + { + public UserRegisterVoValidator() + { + When(x => !string.IsNullOrEmpty(x.NickName) || !string.IsNullOrEmpty(x.Telphone), () => + { + RuleFor(x => x.NickName) + .Must(e => IsLegalName(e)).WithMessage("请填写合法的姓名,必须是汉字和字母"); + RuleFor(x => x.Telphone) + .Must(e => IsLegalPhone(e)).WithMessage("请填写正确的手机号码"); + RuleFor(x => x.Cars) + .NotNull().NotEmpty().WithMessage("车辆信息不正确"); + RuleForEach(x => x.Cars).SetValidator(new CarInfoValidator()); + }); + + } + + public static bool IsLegalName(string username) + { + //判断用户名是否合法 + const string pattern = "(^([A-Za-z]|[\u4E00-\u9FA5]){1,10}$)"; + return (!string.IsNullOrEmpty(username) && Regex.IsMatch(username, pattern)); + } + public static bool IsLegalPhone(string phone) + { + //判断手机号 + const string pattern = "(^1\\d{10}$)"; + return (!string.IsNullOrEmpty(phone) && Regex.IsMatch(phone, pattern)); + } + } + public class CarInfoValidator : AbstractValidator + { + public CarInfoValidator() + { + RuleFor(x => x.CarCount) + .GreaterThanOrEqualTo(0).WithMessage("车辆数量必须大于等于0") + .LessThanOrEqualTo(500).WithMessage($"存在车型数量已达上限"); + RuleFor(x => x.CarSize) + .IsInEnum().WithMessage("车型不正确"); + } + } + +} \ No newline at end of file diff --git a/Blog.Core.Api/Log4net.config b/Blog.Core.Api/Log4net.config deleted file mode 100644 index 7be4cf69..00000000 --- a/Blog.Core.Api/Log4net.config +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Blog.Core.Api/Program.cs b/Blog.Core.Api/Program.cs index 149b355d..bc2b51cc 100644 --- a/Blog.Core.Api/Program.cs +++ b/Blog.Core.Api/Program.cs @@ -1,40 +1,190 @@ -using Autofac.Extensions.DependencyInjection; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System.IO; +// 以下为asp.net 6.0的写法,如果用5.0,请看Program.five.cs文件, +// 或者参考github上的.net6.0分支相关代码 -namespace Blog.Core +using Autofac; +using Autofac.Extensions.DependencyInjection; +using Blog.Core; +using Blog.Core.Common; +using Blog.Core.Common.Core; +using Blog.Core.Common.Helper; +using Blog.Core.Extensions; +using Blog.Core.Extensions.Apollo; +using Blog.Core.Extensions.Middlewares; +using Blog.Core.Extensions.ServiceExtensions; +using Blog.Core.Filter; +using Blog.Core.Hubs; +using Blog.Core.Serilog.Utility; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.IdentityModel.Logging; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using Serilog; +using System.IdentityModel.Tokens.Jwt; +using System.Reflection; +using System.Text; + +var builder = WebApplication.CreateBuilder(args); + + +// 1、配置host与容器 +builder.Host + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) + .ConfigureContainer(builder => + { + builder.RegisterModule(new AutofacModuleRegister()); + builder.RegisterModule(); + }) + .ConfigureAppConfiguration((hostingContext, config) => + { + hostingContext.Configuration.ConfigureApplication(); + config.Sources.Clear(); + config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false); + config.AddConfigurationApollo("appsettings.apollo.json"); + }); +builder.ConfigureApplication(); + +// 2、配置服务 +builder.Services.AddSingleton(new AppSettings(builder.Configuration)); +builder.Services.AddAllOptionRegister(); + +builder.Services.AddUiFilesZipSetup(builder.Environment); + +Permissions.IsUseIds4 = AppSettings.app(new string[] { "Startup", "IdentityServer4", "Enabled" }).ObjToBool(); +Permissions.IsUseAuthing = AppSettings.app(new string[] { "Startup", "Authing", "Enabled" }).ObjToBool(); +RoutePrefix.Name = AppSettings.app(new string[] { "AppSettings", "SvcName" }).ObjToString(); + +JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + +builder.Services.AddCacheSetup(); +builder.Services.AddSqlsugarSetup(); +builder.Services.AddDbSetup(); +builder.Services.AddInitializationHostServiceSetup(); + +builder.Host.AddSerilogSetup(); + +builder.Services.AddAutoMapperSetup(); +builder.Services.AddCorsSetup(); +builder.Services.AddMiniProfilerSetup(); +builder.Services.AddSwaggerSetup(); +builder.Services.AddJobSetup(); + +builder.Services.AddHttpContextSetup(); +builder.Services.AddAppTableConfigSetup(builder.Environment); +builder.Services.AddHttpPollySetup(); +builder.Services.AddNacosSetup(builder.Configuration); +builder.Services.AddRedisInitMqSetup(); + +builder.Services.AddIpPolicyRateLimitSetup(builder.Configuration); +builder.Services.AddSignalR().AddNewtonsoftJsonProtocol(); + +builder.Services.AddAuthorizationSetup(); +if (Permissions.IsUseIds4 || Permissions.IsUseAuthing) +{ + if (Permissions.IsUseIds4) builder.Services.AddAuthentication_Ids4Setup(); + else if (Permissions.IsUseAuthing) builder.Services.AddAuthentication_AuthingSetup(); +} +else { - public class Program + builder.Services.AddAuthentication_JWTSetup(); +} + +builder.Services.AddScoped(); +builder.Services.Configure(x => x.AllowSynchronousIO = true) + .Configure(x => x.AllowSynchronousIO = true); + +builder.Services.AddSession(); +builder.Services.AddDataProtectionSetup(); +builder.Services.AddControllers(o => + { + o.Filters.Add(typeof(GlobalExceptionsFilter)); + //o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention()); + o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name))); + }) + .AddNewtonsoftJson(options => { - public static void Main(string[] args) - { - //初始化默认主机Builder - Host.CreateDefaultBuilder(args) - .UseServiceProviderFactory(new AutofacServiceProviderFactory()) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder - .UseStartup() - .UseUrls("http://*:8081") - .ConfigureLogging((hostingContext, builder) => - { - //过滤掉系统默认的一些日志 - builder.AddFilter("System", LogLevel.Error); - builder.AddFilter("Microsoft", LogLevel.Error); - builder.AddFilter("Blog.Core.AuthHelper.ApiResponseHandler", LogLevel.Error); - - //可配置文件 - var path = Path.Combine(Directory.GetCurrentDirectory(), "Log4net.config"); - builder.AddLog4Net(path); - }); - }) - // 生成承载 web 应用程序的 Microsoft.AspNetCore.Hosting.IWebHost。Build是WebHostBuilder最终的目的,将返回一个构造的WebHost,最终生成宿主。 - .Build() - // 运行 web 应用程序并阻止调用线程, 直到主机关闭。 - // ※※※※ 有异常,查看 Log 文件夹下的异常日志 ※※※※ - .Run(); - } - } + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + options.SerializerSettings.ContractResolver = new DefaultContractResolver(); + options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; + options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local; + options.SerializerSettings.Converters.Add(new StringEnumConverter()); + //将long类型转为string + options.SerializerSettings.Converters.Add(new NumberConverter(NumberConverterShip.Int64)); + }); + +builder.Services.AddRabbitMQSetup(); +builder.Services.AddKafkaSetup(builder.Configuration); +builder.Services.AddEventBusSetup(); + +builder.Services.AddEndpointsApiExplorer(); + +builder.Services.Replace(ServiceDescriptor.Transient()); +Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + +// 3、配置中间件 +var app = builder.Build(); +IdentityModelEventSource.ShowPII = true; + +app.ConfigureApplication(); +app.UseApplicationSetup(); +app.UseResponseBodyRead(); + +if (app.Environment.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); +} +else +{ + app.UseExceptionHandler("/Error"); + //app.UseHsts(); +} + +app.UseEncryptionRequest(); +app.UseEncryptionResponse(); + +app.UseExceptionHandlerMiddle(); +app.UseIpLimitMiddle(); +app.UseRequestResponseLogMiddle(); +app.UseRecordAccessLogsMiddle(); +app.UseSignalRSendMiddle(); +app.UseIpLogMiddle(); +app.UseAllServicesMiddle(builder.Services); + +app.UseSession(); +app.UseSwaggerAuthorized(); +app.UseSwaggerMiddle(() => Assembly.GetExecutingAssembly().GetManifestResourceStream("Blog.Core.Api.index.html")); + +app.UseCors(AppSettings.app(new string[] { "Startup", "Cors", "PolicyName" })); +DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions(); +defaultFilesOptions.DefaultFileNames.Clear(); +defaultFilesOptions.DefaultFileNames.Add("index.html"); +app.UseDefaultFiles(defaultFilesOptions); +app.UseStaticFiles(); +app.UseCookiePolicy(); +app.UseStatusCodePages(); +app.UseSerilogRequestLogging(options => +{ + options.MessageTemplate = SerilogRequestUtility.HttpMessageTemplate; + options.GetLevel = SerilogRequestUtility.GetRequestLevel; + options.EnrichDiagnosticContext = SerilogRequestUtility.EnrichFromRequest; +}); +app.UseRouting(); + +if (builder.Configuration.GetValue("AppSettings:UseLoadTest")) +{ + app.UseMiddleware(); } + +app.UseAuthentication(); +app.UseAuthorization(); +app.UseMiniProfilerMiddleware(); + +app.MapControllers(); +app.MapHub("/api2/chatHub"); + +// 4、运行 +app.Run(); \ No newline at end of file diff --git a/Blog.Core.Api/Program.five.cs b/Blog.Core.Api/Program.five.cs new file mode 100644 index 00000000..900c9495 --- /dev/null +++ b/Blog.Core.Api/Program.five.cs @@ -0,0 +1,75 @@ +//using Autofac.Extensions.DependencyInjection; +//using Blog.Core.Extensions.Apollo; +//using Microsoft.AspNetCore.Hosting; +//using Microsoft.Extensions.Configuration; +//using Microsoft.Extensions.Hosting; +//using Microsoft.Extensions.Logging; +//using System; +//using System.IO; + +// 这是asp.net5.0的写法,如果用5.0,请用本文件代码替换Program.cs代码 +//namespace Blog.Core +//{ +// public class Program +// { +// public static void Main(string[] args) +// { +// //初始化默认主机Builder +// Host.CreateDefaultBuilder(args) +// .UseServiceProviderFactory(new AutofacServiceProviderFactory()) +// .ConfigureWebHostDefaults(webBuilder => +// { +// webBuilder +// .UseStartup() +// .ConfigureAppConfiguration((hostingContext, config) => +// { +// config.Sources.Clear(); +// config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false) +// //.AddJsonFile($"appsettings{ GetAppSettingsConfigName() }json", optional: true, reloadOnChange: false) +// ; +// //接入Apollo配置中心 +// config.AddConfigurationApollo("appsettings.apollo.json"); +// }) +// .UseUrls("http://*:9291") +// .ConfigureLogging((hostingContext, builder) => +// { +// // 1.过滤掉系统默认的一些日志 +// builder.AddFilter("System", LogLevel.Error); +// builder.AddFilter("Microsoft", LogLevel.Error); + +// // 2.也可以在appsettings.json中配置,LogLevel节点 + +// // 3.统一设置 +// builder.SetMinimumLevel(LogLevel.Error); + +// // 默认log4net.confg +// builder.AddLog4Net(Path.Combine(Directory.GetCurrentDirectory(), "Log4net.config")); +// }) +// ; +// }) +// // 生成承载 web 应用程序的 Microsoft.AspNetCore.Hosting.IWebHost。Build是WebHostBuilder最终的目的,将返回一个构造的WebHost,最终生成宿主。 +// .Build() +// // 运行 web 应用程序并阻止调用线程, 直到主机关闭。 +// // ※※※※ 有异常,查看 Log 文件夹下的异常日志 ※※※※ +// .Run(); +// } + + +// /// +// /// 根据环境变量定向配置文件名称 +// /// +// /// +// private static string GetAppSettingsConfigName() +// { +// if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != null +// && Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != "") +// { +// return $".{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}."; +// } +// else +// { +// return "."; +// } +// } +// } +//} diff --git a/Blog.Core.Api/Properties/launchSettings.json b/Blog.Core.Api/Properties/launchSettings.json index 001e1040..e3113d39 100644 --- a/Blog.Core.Api/Properties/launchSettings.json +++ b/Blog.Core.Api/Properties/launchSettings.json @@ -14,8 +14,9 @@ "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" + //"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "SkyAPM.Agent.AspNetCore"// 如果要开始skywalking,请取消此行注释 }, - "applicationUrl": "http://localhost:8081" + "applicationUrl": "http://localhost:9291" }, "IIS Express": { "commandName": "IISExpress", diff --git a/Blog.Core.Api/Startup.cs b/Blog.Core.Api/Startup.cs deleted file mode 100644 index 59df4c2f..00000000 --- a/Blog.Core.Api/Startup.cs +++ /dev/null @@ -1,178 +0,0 @@ -using Autofac; -using Blog.Core.Common; -using Blog.Core.Common.LogHelper; -using Blog.Core.Extensions; -using Blog.Core.Filter; -using Blog.Core.Hubs; -using Blog.Core.IServices; -using Blog.Core.Middlewares; -using Blog.Core.Model.Seed; -using Blog.Core.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System.Reflection; - -namespace Blog.Core -{ - public class Startup - { - - private IServiceCollection _services; - - public Startup(IConfiguration configuration, IWebHostEnvironment env) - { - Configuration = configuration; - Env = env; - } - - public IConfiguration Configuration { get; } - public IWebHostEnvironment Env { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - // 以下code可能与文章中不一样,对代码做了封装,具体查看右侧 Extensions 文件夹. - services.AddSingleton(); - services.AddSingleton(new Appsettings(Configuration)); - services.AddSingleton(new LogLock(Env.ContentRootPath)); - - Permissions.IsUseIds4 = Appsettings.app(new string[] { "Startup", "IdentityServer4", "Enabled" }).ObjToBool(); - - services.AddMemoryCacheSetup(); - services.AddSqlsugarSetup(); - services.AddDbSetup(); - services.AddAutoMapperSetup(); - services.AddCorsSetup(); - services.AddMiniProfilerSetup(); - services.AddSwaggerSetup(); - services.AddJobSetup(); - services.AddHttpContextSetup(); - services.AddAppConfigSetup(); - services.AddHttpApi(); - if (Permissions.IsUseIds4) - { - services.AddAuthorization_Ids4Setup(); - } - else - { - services.AddAuthorizationSetup(); - } - services.AddIpPolicyRateLimitSetup(Configuration); - - services.AddSignalR().AddNewtonsoftJsonProtocol(); - - services.AddScoped(); - - services.Configure(x => x.AllowSynchronousIO = true) - .Configure(x => x.AllowSynchronousIO = true); - - services.AddControllers(o => - { - // 全局异常过滤 - o.Filters.Add(typeof(GlobalExceptionsFilter)); - // 全局路由权限公约 - //o.Conventions.Insert(0, new GlobalRouteAuthorizeConvention()); - // 全局路由前缀,统一修改路由 - o.Conventions.Insert(0, new GlobalRoutePrefixFilter(new RouteAttribute(RoutePrefix.Name))); - }) - //全局配置Json序列化处理 - .AddNewtonsoftJson(options => - { - //忽略循环引用 - options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; - //不使用驼峰样式的key - options.SerializerSettings.ContractResolver = new DefaultContractResolver(); - //设置时间格式 - //options.SerializerSettings.DateFormatString = "yyyy-MM-dd"; - }); - - _services = services; - } - - // 注意在Program.CreateHostBuilder,添加Autofac服务工厂 - public void ConfigureContainer(ContainerBuilder builder) - { - builder.RegisterModule(new AutofacModuleRegister()); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, MyContext myContext, ITasksQzServices tasksQzServices, ISchedulerCenter schedulerCenter, IHostApplicationLifetime lifetime) - { - // Ip限流,尽量放管道外层 - app.UseIpLimitMildd(); - // 记录请求与返回数据 - app.UseReuestResponseLog(); - // signalr - app.UseSignalRSendMildd(); - // 记录ip请求 - app.UseIPLogMildd(); - // 查看注入的所有服务 - app.UseAllServicesMildd(_services); - - if (env.IsDevelopment()) - { - // 在开发环境中,使用异常页面,这样可以暴露错误堆栈信息,所以不要放在生产环境。 - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - // 在非开发环境中,使用HTTP严格安全传输(or HSTS) 对于保护web安全是非常重要的。 - // 强制实施 HTTPS 在 ASP.NET Core,配合 app.UseHttpsRedirection - //app.UseHsts(); - } - - // 封装Swagger展示 - app.UseSwaggerMildd(() => GetType().GetTypeInfo().Assembly.GetManifestResourceStream("Blog.Core.Api.index.html")); - - // ↓↓↓↓↓↓ 注意下边这些中间件的顺序,很重要 ↓↓↓↓↓↓ - - // CORS跨域 - app.UseCors("LimitRequests"); - // 跳转https - //app.UseHttpsRedirection(); - // 使用静态文件 - app.UseStaticFiles(); - // 使用cookie - app.UseCookiePolicy(); - // 返回错误码 - app.UseStatusCodePages(); - // Routing - app.UseRouting(); - // 这种自定义授权中间件,可以尝试,但不推荐 - // app.UseJwtTokenAuth(); - // 先开启认证 - app.UseAuthentication(); - // 然后是授权中间件 - app.UseAuthorization(); - // 开启异常中间件,要放到最后 - //app.UseExceptionHandlerMidd(); - // 性能分析 - app.UseMiniProfiler(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - - endpoints.MapHub("/api2/chatHub"); - }); - - // 生成种子数据 - app.UseSeedDataMildd(myContext, Env.WebRootPath); - // 开启QuartzNetJob调度服务 - app.UseQuartzJobMildd(tasksQzServices, schedulerCenter); - //服务注册 - app.UseConsulMildd(Configuration, lifetime); - } - - } -} diff --git a/Blog.Core.Api/StopContainerImg.sh b/Blog.Core.Api/StopContainerImg.sh new file mode 100644 index 00000000..0bffe029 --- /dev/null +++ b/Blog.Core.Api/StopContainerImg.sh @@ -0,0 +1,8 @@ +#!/bin/bash +docker ps|grep ${1}|while read i;do i; +echo "容器已启动,详细信息:${i}"; +docker stop ${1}; +docker rm ${1}; +docker rmi ${2}; +echo "已关闭容器,${1}" ; +done; \ No newline at end of file diff --git a/Blog.Core.Api/appsettings.Development.json b/Blog.Core.Api/appsettings.Development.json index e203e940..9016c7ce 100644 --- a/Blog.Core.Api/appsettings.Development.json +++ b/Blog.Core.Api/appsettings.Development.json @@ -1,9 +1,11 @@ { - "Logging": { - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } + "nacos": { + "ServerAddresses": [ "http://localhost:8848" ], // nacos 连接地址 + "DefaultTimeOut": 15000, // 默认超时时间 + "Namespace": "public", // 命名空间 + "ListenInterval": 10000, // 监听的频率 + "ServiceName": "blog.Core.Api", // 服务名 + "Port": "9291", // 服务端口号 + "RegisterEnabled": true // 是否直接注册nacos } -} +} \ No newline at end of file diff --git a/Blog.Core.Api/appsettings.apollo.json b/Blog.Core.Api/appsettings.apollo.json new file mode 100644 index 00000000..826c75ca --- /dev/null +++ b/Blog.Core.Api/appsettings.apollo.json @@ -0,0 +1,18 @@ +{ + //apollo 配置 + "Apollo": { + "Enable": false, + "Config": { + "AppId": "blog.core", + "Env": "DEV", + "MetaServer": "http://localhost:8080/", + "ConfigServer": [ "http://localhost:8080/" ] + }, + "Namespaces": [ //Namespaces的数据格式Properties,Xml,Json,Yml,Yaml,Txt + { + "Name": "test", + "Format": "json" + } + ] + } +} \ No newline at end of file diff --git a/Blog.Core.Api/appsettings.json b/Blog.Core.Api/appsettings.json index 73306b1a..d62aae9e 100644 --- a/Blog.Core.Api/appsettings.json +++ b/Blog.Core.Api/appsettings.json @@ -1,54 +1,98 @@ { - "Logging": { - "IncludeScopes": false, - "Debug": { - "LogLevel": { - "Default": "Warning" + "urls": "http://*:9291", //web服务端口,如果用IIS部署,把这个去掉 + "Serilog": { + "MinimumLevel": { + "Default": "Information", //关闭日志1:修改Serilog的最低日志级别,比如Warning + "Override": { + "Microsoft": "Information", + "Microsoft.AspNetCore": "Warning", + "System": "Warning", + "System.Net.Http.HttpClient": "Warning", + "Hangfire": "Information", + "Magicodes": "Warning", + "DotNetCore.CAP": "Information", + "Savorboard.CAP": "Information", + "Quartz": "Information" } - }, - "Console": { - "LogLevel": { - "Default": "Warning", - "Microsoft.Hosting.Lifetime": "Debug" - } - }, - "Log4Net": { - "Name": "Blog.Core" } }, - //"urls": "http://localhost:8081",// IIS 部署,注释掉 "AllowedHosts": "*", + "Redis": { + "Enable": false, + "ConnectionString": "127.0.0.1:6379,allowAdmin=true", + "InstanceName": "" //前缀 + }, + "RabbitMQ": { + "Enabled": true, + "Connection": "101xxxx57", + "UserName": "xxxx", + "Password": "xxxxx", + "Port": "5672", + "RetryCount": 2 + }, + "Kafka": { + "Enabled": false, + "Servers": "localhost:9092", + "Topic": "blog", + "GroupId": "blog-consumer", + "NumPartitions": 3 //主题分区数量 + }, + "EventBus": { + "Enabled": false, + "SubscriptionClientName": "Blog.Core" + }, "AppSettings": { - "RedisCachingAOP": { - "Enabled": false, - "ConnectionString": "127.0.0.1:6319" - }, - "MemoryCachingAOP": { + "CachingAOP": { "Enabled": true }, + "LogToDb": true, "LogAOP": { - "Enabled": false + "Enabled": false, + "LogToFile": { + "Enabled": true + }, + "LogToDB": { + "Enabled": true + } }, "TranAOP": { + "Enabled": true + }, + "UserAuditAOP": { "Enabled": false }, "SqlAOP": { - "Enabled": false + "Enabled": true, //关闭日志2:修改Sql日志是否显示(也可以精准配置,是否生成到文件、数据库、控制台) + "LogToFile": { + "Enabled": true + }, + "LogToDB": { + "Enabled": true + }, + "LogToConsole": { + "Enabled": true + } }, "Date": "2018-08-28", "SeedDBEnabled": true, //只生成表结构 "SeedDBDataEnabled": true, //生成表,并初始化数据 - "Author": "Blog.Core" + "Author": "Blog.Core", + "SvcName": "", // /svc/blog + "UseLoadTest": false, + "CacheDbEnabled": false }, - // 请配置MainDB为你想要的主库的ConnId值,并设置对应的Enabled为true; - // *** 单库操作,把 MutiDBEnabled 设为false ***; - // *** 多库操作,把 MutiDBEnabled 设为true,其他的从库Enabled也为true **; - // 具体配置看视频:https://www.bilibili.com/video/BV1BJ411B7mn?p=6 - - "MainDB": "WMBLOG_SQLITE", //当前项目的主库,所对应的连接字符串的Enabled必须为true - "MutiDBEnabled": false, //是否开启多库模式 - "CQRSEnabled": false, //是否开启读写分离模式,必须是单库模式,且数据库类型一致,比如都是SqlServer + //优化DB配置、不会再区分单库多库 + //MainDb:标识当前项目的主库,所对应的连接字符串的Enabled必须为true + //Log:标识日志库,所对应的连接字符串的Enabled必须为true + //从库只需配置Slaves数组,要求数据库类型一致!,比如都是SqlServer + // + //新增,故障转移方案 + //如果主库挂了,会自动切换到备用连接(比如说主库+备用库) + //备用连接的ConnId配置为主库的ConnId+数字即可,比如主库的ConnId为Main,那么备用连接的ConnId为Mian1 + //主库、备用库无需数据库类型一致! + //备用库不会有程序维护,需要手动维护 + "MainDB": "Main", //当前项目的主库,所对应的连接字符串的Enabled必须为true "DBS": [ /* 对应下边的 DBType @@ -56,56 +100,104 @@ SqlServer = 1, Sqlite = 2, Oracle = 3, - PostgreSQL = 4 + PostgreSQL = 4, + Dm = 5,//达梦 + Kdbndp = 6,//人大金仓 */ { - "ConnId": "WMBLOG_SQLITE", + "ConnId": "Main", "DBType": 2, "Enabled": true, - "HitRate": 50, // 值越大,优先级越高 - "Connection": "WMBlog.db" //sqlite只写数据库名就行 + "Connection": "WMBlog.db", //sqlite只写数据库名就行 + "Slaves": [ + { + "HitRate": 0,// 值越大,优先级越高 0不使用 + "Connection": "WMBlog2.db" + } + ] + }, + { + "ConnId": "Main2", + "DBType": 2, + "Enabled": false, + "Connection": "WMBlog3.db", //sqlite只写数据库名就行 + "Slaves": [ + { + "HitRate": 0,// 值越大,优先级越高 0不使用 + "Connection": "WMBlog4.db" + } + ] + }, + { + "ConnId": "Log", //日志库连接固定名称,不要改,其他的可以改 + "DBType": 2, + "Enabled": true, + "HitRate": 50, + "Connection": "WMBlogLog.db" //sqlite只写数据库名就行 }, { "ConnId": "WMBLOG_MSSQL_1", "DBType": 1, - "Enabled": true, - "HitRate": 40, + "Enabled": false, "Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_1;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", "ProviderName": "System.Data.SqlClient" }, { "ConnId": "WMBLOG_MSSQL_2", "DBType": 1, - "Enabled": true, - "HitRate": 30, + "Enabled": false, "Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_2;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", "ProviderName": "System.Data.SqlClient" }, { "ConnId": "WMBLOG_MYSQL", "DBType": 0, - "Enabled": true, - "HitRate": 20, - "Connection": "Server=localhost; Port=3306;Stmt=; Database=wmblogdb; Uid=root; Pwd=456;" + "Enabled": false, + "Connection": "server=localhost;Database=blog;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;" + }, + { + "ConnId": "WMBLOG_MYSQL_2", + "DBType": 0, + "Enabled": false, + "Connection": "server=localhost;Database=blogcore001;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;" }, { "ConnId": "WMBLOG_ORACLE", "DBType": 3, "Enabled": false, - "HitRate": 10, - "Connection": "Provider=OraOLEDB.Oracle; Data Source=WMBlogDB; User Id=sss; Password=789;", - "OracleConnection_other1": "User ID=sss;Password=789;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.8.65)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME = orcl)))" + "Connection": "Data Source=127.0.0.1/ops;User ID=OPS;Password=123456;Persist Security Info=True;Connection Timeout=60;" + }, + { + "ConnId": "WMBLOG_DM", + "DBType": 5, + "Enabled": false, + "Connection": "Server=xxxxx:5236;User Id=xxxxx;PWD=xxxxx;SCHEMA=TESTDBA;" + }, + { + "ConnId": "WMBLOG_KDBNDP", + "DBType": 6, + "Enabled": false, + "Connection": "Server=127.0.0.1;Port=54321;UID=SYSTEM;PWD=system;database=SQLSUGAR4XTEST1;" } ], "Audience": { "Secret": "sdfsdfsrty45634kkhllghtdgdfss345t678fs", //不要太短,16位+ "SecretFile": "C:\\my-file\\blog.core.audience.secret.txt", //安全。内容就是Secret - "Issuer": "Blog.Core", - "Audience": "wr" + "Issuer": "Blog.Core", //这个值一定要在自己的项目里修改!! + "Audience": "wr" //这个值一定要在自己的项目里修改!! + }, + "Mongo": { + "ConnectionString": "mongodb://nosql.data", + "Database": "BlogCoreDb" }, "Startup": { + "Domain": "http://localhost:9291", "Cors": { - "IPs": "http://127.0.0.1:2364,http://localhost:2364,http://localhost:8080,http://localhost:8021,http://localhost:1818" + "PolicyName": "CorsIpAccess", //策略名称 + "EnableAllIPs": false, //当为true时,开放所有IP均可访问。 + // 支持多个域名端口,注意端口号后不要带/斜杆:比如localhost:8000/,是错的 + // 注意,http://127.0.0.1:1818 和 http://localhost:1818 是不一样的 + "IPs": "http://127.0.0.1:2364,http://localhost:2364,http://127.0.0.1:6688,http://localhost:6688" }, "AppConfigAlert": { "Enabled": true @@ -113,22 +205,59 @@ "ApiName": "Blog.Core", "IdentityServer4": { "Enabled": false, // 这里默认是false,表示使用jwt,如果设置为true,则表示系统使用Ids4模式 - "AuthorizationUrl": "https://ids.neters.club", // 认证中心域名 + "AuthorizationUrl": "http://localhost:5004", // 认证中心域名 "ApiName": "blog.core.api" // 资源服务器 + }, + "Authing": { + "Enabled": false, + "Issuer": "https://uldr24esx31h-demo.authing.cn/oidc", + "Audience": "63d51c4205c2849803be5178", + "JwksUri": "https://uldr24esx31h-demo.authing.cn/oidc/.well-known/jwks.json" + }, + "RedisMq": { + "Enabled": false //redis 消息队列 + }, + "MiniProfiler": { + "Enabled": true //性能分析开启 + }, + "Nacos": { + "Enabled": false //Nacos注册中心 } }, "Middleware": { "RequestResponseLog": { - "Enabled": false + "Enabled": true, + "LogToFile": { + "Enabled": true + }, + "LogToDB": { + "Enabled": true + } }, "IPLog": { - "Enabled": true + "Enabled": true, + "LogToFile": { + "Enabled": true + }, + "LogToDB": { + "Enabled": true + } }, - "RecordAllLogs": { - "Enabled": false + "RecordAccessLogs": { + "Enabled": true, + "LogToFile": { + "Enabled": true + }, + "LogToDB": { + "Enabled": true + }, + "IgnoreApis": "/api/permission/getnavigationbar,/api/monitor/getids4users,/api/monitor/getaccesslogs,/api/monitor/server,/api/monitor/getactiveusers,/api/monitor/server," }, "SignalR": { - "Enabled": false + "Enabled": true + }, + "SignalRSendLog": { + "Enabled": true }, "QuartzNetJob": { "Enabled": true @@ -138,6 +267,20 @@ }, "IpRateLimit": { "Enabled": true + }, + "EncryptionResponse": { + "Enabled": true, + "AllApis": false, + "LimitApis": [ + "/api/Login/GetJwtTokenSecret" + ] + }, + "EncryptionRequest": { + "Enabled": true, + "AllApis": false, + "LimitApis": [ + "/api/Login/GetJwtTokenSecret" + ] } }, "IpRateLimiting": { @@ -148,6 +291,11 @@ "IpWhitelist": [], //白名单 "EndpointWhitelist": [ "get:/api/xxx", "*:/api/yyy" ], "ClientWhitelist": [ "dev-client-1", "dev-client-2" ], + "QuotaExceededResponse": { + "Content": "{{\"status\":429,\"msg\":\"访问过于频繁,请稍后重试\",\"success\":false}}", + "ContentType": "application/json", + "StatusCode": 429 + }, "HttpStatusCode": 429, //返回状态码 "GeneralRules": [ //api规则,结尾一定要带* { @@ -176,8 +324,41 @@ "ConsulSetting": { "ServiceName": "BlogCoreService", "ServiceIP": "localhost", - "ServicePort": "8081", + "ServicePort": "9291", "ServiceHealthCheck": "/healthcheck", "ConsulAddress": "http://localhost:8500" + }, + "PayInfo": { //建行聚合支付信息 + "MERCHANTID": "", //商户号 + "POSID": "", //柜台号 + "BRANCHID": "", //分行号 + "pubKey": "", //公钥 + "USER_ID": "", //操作员号 + "PASSWORD": "", //密码 + "OutAddress": "http://127.0.0.1:12345" //外联地址 + }, + "nacos": { + "ServerAddresses": [ "http://localhost:8848" ], // nacos 连接地址 + "DefaultTimeOut": 15000, // 默认超时时间 + "Namespace": "public", // 命名空间 + "ListenInterval": 10000, // 监听的频率 + "ServiceName": "blog.Core.Api", // 服务名 + "Port": "9291", // 服务端口号 + "RegisterEnabled": true // 是否直接注册nacos + }, + "LogFiedOutPutConfigs": { + "tcpAddressHost": "", // 输出elk的tcp连接地址 + "tcpAddressPort": 0, // 输出elk的tcp端口号 + "ConfigsInfo": [ // 配置的输出elk节点内容 常用语动态标识 + { + "FiedName": "applicationName", + "FiedValue": "Blog.Core.Api" + } + ] + }, + "Seq": { + "Enabled": false, + "Address": "http://localhost:5341/", + "ApiKey": "" } -} +} \ No newline at end of file diff --git a/Blog.Core.Api/index.html b/Blog.Core.Api/index.html index 6a889485..99b4caa4 100644 --- a/Blog.Core.Api/index.html +++ b/Blog.Core.Api/index.html @@ -1,35 +1,38 @@ - - + - + + + + %(DocumentTitle) + - - + %(HeadContent) - + @@ -86,6 +110,11 @@
+ diff --git a/Blog.Core.Api/skyapm.json b/Blog.Core.Api/skyapm.json new file mode 100644 index 00000000..cdb0e606 --- /dev/null +++ b/Blog.Core.Api/skyapm.json @@ -0,0 +1,29 @@ +{ + "SkyWalking": { + "ServiceName": "blog-core-api", + "Namespace": "", + "HeaderVersions": [ + "sw8" + ], + "Sampling": { + "SamplePer3Secs": -1, + "Percentage": -1.0 + }, + "Logging": { + "Level": "Information", + "FilePath": "Logs/Skyapm/skyapm-{Date}.log" + }, + "Transport": { + "Interval": 3000, + "ProtocolVersion": "v8", + "QueueSize": 30000, + "BatchSize": 3000, + "gRPC": { + "Servers": "elasticsearch:11800", + "Timeout": 10000, + "ConnectTimeout": 10000, + "ReportTimeout": 600000 + } + } + } +} diff --git a/Blog.Core.Api/web.config b/Blog.Core.Api/web.config new file mode 100644 index 00000000..f9910150 --- /dev/null +++ b/Blog.Core.Api/web.config @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Department.xlsx b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Department.xlsx new file mode 100644 index 00000000..c0362d77 Binary files /dev/null and b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Department.xlsx differ diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Modules.xlsx b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Modules.xlsx new file mode 100644 index 00000000..e2de3e21 Binary files /dev/null and b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Modules.xlsx differ diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Permission.xlsx b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Permission.xlsx new file mode 100644 index 00000000..ec65657e Binary files /dev/null and b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Permission.xlsx differ diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Role.xlsx b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Role.xlsx new file mode 100644 index 00000000..89184c6c Binary files /dev/null and b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/Role.xlsx differ diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.excel/RoleModulePermission.xlsx b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/RoleModulePermission.xlsx new file mode 100644 index 00000000..99a771d2 Binary files /dev/null and b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/RoleModulePermission.xlsx differ diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.excel/SysUserInfo.xlsx b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/SysUserInfo.xlsx new file mode 100644 index 00000000..6a1e4ca6 Binary files /dev/null and b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/SysUserInfo.xlsx differ diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.excel/UserRole.xlsx b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/UserRole.xlsx new file mode 100644 index 00000000..4e7bb12d Binary files /dev/null and b/Blog.Core.Api/wwwroot/BlogCore.Data.excel/UserRole.xlsx differ diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.json/BlogArticle.tsv b/Blog.Core.Api/wwwroot/BlogCore.Data.json/BlogArticle.tsv index 7df11ca0..b6969787 100644 --- a/Blog.Core.Api/wwwroot/BlogCore.Data.json/BlogArticle.tsv +++ b/Blog.Core.Api/wwwroot/BlogCore.Data.json/BlogArticle.tsv @@ -2,651 +2,14 @@ { "bID": 1, "bsubmitter": "admin", - "btitle": "IIS new add website ,some wrong:The requested page cannot be accessed because the related configuration data for the page is invalid.", + "btitle": "测试数据:IIS new add website ,some wrong:The requested page cannot be accessed because the related configuration data for the page is invalid.", "bcategory": "技术博文", - "bcontent": "

Question:

The requested page cannot be accessed because the related configuration data for the page is invalid.

HTTP Error 500.19 - Internal Server Error The requested page cannot be accessed because the related configuration data for the page is invalid.

Detailed Error Information:

Module IIS Web Core

Notification Unknown

Handler Not yet determined

Error Code 0x80070003

Config Error Cannot read configuration file

Config File \\?\\D:\\Projects\\...\\web.config

Requested URL http:// localhost:8080/

Physical Path

Logon Method Not yet determined

Logon User Not yet determined

Request Tracing Directory C:\\Users\\...\\TraceLogFiles\\

Config Source:

Answer:

1,find the site's application pools

2,\"Advanced Settings\" ==> Indentity ==>  Custom account



", + "bcontent": "

问题:

The requested page cannot be accessed because the related configuration data for the page is invalid.

HTTP Error 500.19 - Internal Server Error The requested page cannot be accessed because the related configuration data for the page is invalid.

Detailed Error Information:

Module IIS Web Core

Notification Unknown

Handler Not yet determined

Error Code 0x80070003

Config Error Cannot read configuration file

Config File \\?\\D:\\Projects\\...\\web.config

Requested URL http:// localhost:8080/

Physical Path

Logon Method Not yet determined

Logon User Not yet determined

Request Tracing Directory C:\\Users\\...\\TraceLogFiles\\

Config Source:

Answer:

1,find the site's application pools

2,\"Advanced Settings\" ==> Indentity ==>  Custom account



", "btraffic": 127, "bcommentNum": 1, "bUpdateTime": "\/Date(1546272000000+0800)\/", "bCreateTime": "\/Date(1546272000000+0800)\/", "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 2, - "bsubmitter": "admin", - "btitle": "The 'targetFramework' attribute in the element of the Web.config file is used only to target version 4.0 and later of the .N", - "bcategory": "技术博文", - "bcontent": "

The 'targetFramework' attribute in the <compilation> element of the Web.config file is used only to target version 4.0 and later of the .NET Framework (for example, '<compilation targetFramework=\"4.0\">'). The 'targetFramework' attribute currently references a version that is later than the installed version of the .NET Framework. Specify a valid target version of the .NET Framework, or install the required version of the .NET Framework.

<system.web>    \r\n    <compilation debug=\"true\" targetFramework=\"4.5\" />\r\n    <httpRuntime targetFramework=\"4.5\" />\r\n</system.web>
<system.web>    \r\n    <compilation debug=\"true\" />\r\n    <httpRuntime targetFramework=\"4.0\" />\r\n</system.web>

compilation是编译设置,在部署环境无须设置 targetFramework,当然 debug 也可以设置成 false

httpRuntime是运行时,我们知道 .Net 4.0 和 .Net 4.5 的运行时版本都是 .Net 4.0,所以改成4.0就OK了


", - "btraffic": 67, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 3, - "bsubmitter": "admin", - "btitle": "Redis在windows下安装过程", - "bcategory": "技术博文", - "bcontent": "

去官网找了很久,发现原来在官网上可以下载的windows版本的,现在官网以及没有下载地址,只能在github上下载,官网只提供linux版本的下载

官网下载地址:http://redis.io/download

github下载地址:https://github.com/MSOpenTech/redis/tags

在运行中输入cmd,然后把目录指向解压的Redis目录。

redis-server redis.windows.conf,出现下图显示表示启动成功了。

1、由于上面虽然启动了redis,但是只要一关闭cmd窗口,redis就会消失。所以要把redis设置成windows下的服务。

也就是设置到这里,首先发现是没用这个Redis服务的。

2、设置服务命令

redis-server --service-install redis.windows-service.conf --loglevel verbose

输入命令之后没有报错,表示成功了,刷新服务,会看到多了一个redis服务。

3、常用的redis服务命令。

卸载服务:redis-server --service-uninstall

开启服务:redis-server --service-start

停止服务:redis-server --service-stop

4、启动服务


", - "btraffic": 23, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 4, - "bsubmitter": "admin", - "btitle": "The difference of between EF and ADO.NET", - "bcategory": "随笔日志", - "bcontent": "

ado.net EF作为微软的一个ORM框架,通过实体、关系型数据库表之间的映射,使开发人员可以通过操作表实体而间接的操作数据库,大大的提高了开发效率。

这样一来,.net平台下,我们与底层数据库的交互就有两种选择了(这句话说得不是很准确,微软.net 框架下还是有其他的ORM框架的,,如Nhibernate):ado.net EF、ado.net 。

你可能以为我上面的内容写错了,ado.net EF 、ado.net 两者怎么都带有一个ado.net呢?

OK,如果你有这样的疑问的话,那么我们就有必要来了解一下.net的一些基本知识了

(1).net: 最核心的基础平台(可以看做运行环境和巨多类库),仅次于操作系统
(2)asp.net: .net平台下进行网站开发的框架
(3)asp.net MVC:asp.net 框架下开发网页的一种框架
(4)ado.net: .net平台下访问数据库的框架,他提供了一些列的访问数据库的类库
(5)ado.net EF: ado.net框架下访问数据库的最新最强大的ORM
(6)ORM: 把数据库映射为实体类的技术
(7)NHibemate: .net平台内访问数据库的一种可选ORM,从Java转换而来

以上仅仅是个人见解,不代表官方说法。

上面只是对ado.net 和ado.net EF两者进行了简单了解,下面我们再对两者进行一个具体的比较学习

(1)ado.net 做为原装的直接跟数据库打交道,直接操作数据库,没有进行额外的封装。比如我们可以直接执行sql语句,直接调用存储过程。直接操作DataSet数据集等等数据。(2)EF 是ORM思想的付诸于实践,它对ado.net进行了封装,对数据表进行了映射处理,以对象的形式展现在开发人员面前。开发人员可以利用Linq语句的优势来执行增、改、查。但是最终的操作都是要转换成SQL语句来执行。比如:

  1. From a in Context.Student  
  2. Where a.id =1  
  3. Select a;  

 真正执行的时候会转换成 SQL \" Select * from Student Where id=1\"。

 EF让我们可以用面向对象的思想来编写程序,把注意力集中在系统中的业务环节。但是由于他要进行一次SQL语句的转换,所以相对于原始的ADO.NET来说,EF由于进行了封装,所以性能相对ADO.NET来说差一点点。不过EF也在不断的优化和改进中。 当然,EF也可以直接执行SQL语句和存储过程。有人会问,那为什么不直接执行SQL语句呢,回答是,直接执行的话要EF有什么用呢,EF就是在推行以面向对象编程的思想来处理业务。

OK,上面对两者进行了简单的比较,既然微软对ado.net 进行封装推出EF,那说明EF相对于原始的ado.net还是有优势的呢,那具体有哪些呢?

EF相对于ado.net 的优点
(1)开发效率高,开发人员完全可以根据面向对象的思维进行软件的开发
(2)可以使用三种设计模式中的ModelFirst来设计数据库,而且比较直观
(3)可以跨数据库,只需要在配置文件中修改连接字符串
(4)与vs结合的比较好

缺点:性能上赶不上原生的ado.net (因为他中间还有一个生成sql脚本的过程)

上面的缺点也暴露了一个问题:ado.net EF替代ado.net 。

那有没有折中一点的方案,两者都使用呢?

答案是肯定的,我们可以在EF中使用sql语句和存储过程。那具体如何使用?

不要急,下面我们就一起来学习。

在 EF第一个版本(.NET 3.5 SP1)中,我们只能通过将ObjectContext.Connection转换为EntityConnection,再把 EntityConnection.StoreConnection转换为SqlConnection。有了这个SqlConnection,我们再创建 SqlCommand便能顺利运行SQL命令了。(个人觉得其实很烦,呵呵)
例如:

  1. EntityConnection entityConnection = (EntityConnection)ctx.Connection;  
  2.  DbConnection storeConnection = entityConnection.StoreConnection;  
  3.  DbCommand cmd = storeConnection.CreateCommand();  
  4.  cmd.CommandType = System.Data.CommandType.StoredProcedure;  
  5. cmd.CommandText = \"[PRO_USER_DIGITALCARD_CHECK]\";  
  6. //。。。。。。。     


在EF4(.NET 4)中,我们有了全新的API:ObjectContext.ExecuteStoreCommand(...)和 ObjectContext.ExecuteStoreQuery<T>(...)。从函数名不难知道前者是为了执行某一并无返回集的SQL 命令,例如UPDATE,DELETE操作;后者是执行某一个查询,并可以将返回集转换为某一对象。


  1. using (FlowersPlatformEntities db = new FlowersPlatformEntities())  
  2.  {  
  3.      string selectSql = \"select * from Flower\";  
  4.      ObjectResult<Flower> result = db.ExecuteStoreQuery<Flower>(selectSql, null);  
  5.      foreach (var item in result)  
  6.      {  
  7.          //遍历查询结果  
  8.      }  
  9.      string insertSql = \"insert into dbo.Flower values('月季','月季很好看。。。。。。')\";  
  10.      int res = db.ExecuteStoreCommand(insertSql, null);  
  11.      if (res > 0)  
  12.      {  
  13.          //插入成功  
  14.      }  
  15.      else  
  16.      {  
  17.          //插入失败  
  18.      }  
  19.  }  

存储过程:

(1)新建存储过程


  1. create proc MianDemo  
  2. @id int  
  3. as   
  4. select *  
  5. from dbo.Indicator  
  6. where dbo.Indicator.Id=@id  

上面新建的存储过程没有什么实际意义,只是用来举例使用的。
(2)EF中执行存储过程


  1. SqlParameter[] param = new SqlParameter[] { new SqlParameter(\"@id\", 1) };  
  2. var temp = db.ExecuteStoreQuery<Indicator>(\"exec MianDemo @id\",param).ToList();  
  3. foreach (var item in temp)  
  4. {  
  5.     Response.Write(item.Id);  
  6. }  

存储过程的执行方法与查询的方法是同一个。

  1. </pre><pre code_snippet_id=\"1628892\" snippet_file_name=\"blog_20160330_4_5375036\" name=\"code\" class=\"csharp\">  

到了EF4.1,API的名字又有了些许改变。如果说DbContext将ObjectContext做了包装,那么DbContext.Database就是对应于数据库端信息的封装。执行SQL命令也自然从Database类型开始。对应于ExecuteStoreCommand和ExecuteStoreQuery<T>的是Database.ExecuteSqlCommand和Database.SqlQuery<T>。

只要修改上面的代码的方法名称,就可以实现代码重用,在此就不在罗列了。


", - "btraffic": 23, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 5, - "bsubmitter": "admin", - "btitle": "Windows Server 2008 R2提示密码即将过期怎么办", - "bcategory": "技术博文", - "bcontent": "

1,ctrl+alt+delete 去修改密码

2、打开“服务器管理器”,选择“配置”-“本地用户和组”-“用户,右击administrator,选择“属性”,在“常规”选项中勾上“密码永不过期”,点击“应用”和“确定”。

3、在开始菜单中选择“管理工具”-“本地安全策略”,选择“安全策略”-“账户策略”-“密码策略”,编辑“密码最短使用期限”和“密码最长使用期限”,天数设置为0,即永不过期,点击“确定”即可。


", - "btraffic": 29, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "1" - }, - { - "bID": 6, - "bsubmitter": "admin", - "btitle": "CodeFirst完美解决数据迁移-记录中-更新版", - "bcategory": "技术博文", - "bcontent": "


------------------2018-06-25 06:44-------------------------

迁移至指定版本(包括后退)

  迄今为止,我们总是升级至最新迁移,然而某些时候我们需要升级/降级至指定版本,例如我们想迁移数据库至运行 AddBlogUrl 迁移之后的状态,此时我们就可以使用 –TargetMigration 来降级到这个版本

  在 Package Manager Console 中运行命令 Update-Database –TargetMigration: AddBlogUrl 

 \"\"


------------------2018-06-25 06:36-------------------------

工程用的MVC + Entity Framework,根据CodeFirst的编程理念,先创建模型再自动生产数据库和数据表。

看起来这很方便,也给开发带来很多便利,开发时不用考虑数据建库建表。

所以首先建立框架,写好实体和DbContext

\"\"

问题来了

一、当我们的程序开发到中途时,发现还需要一个字段。好,按照常理,就在对应的实体加一个属性就是了,但当我们加入实体的时候,再次运行程序就报错了。

有个最笨但简单的方法,删除数据库,再次运行程序。OK,问题接着又来了。

二、当我们的程序试运行一段时间后,需要增加一个字段。怎么办呢?还是按照常理来,在对应的实体加一个属性,OK。接下来我们可能会想到

1、方案一:再次删掉数据库,重新运行程序。可是我们的数据都丢失了,可以发现表是重建了,数据都丢失了。不科学。

2、方案二:直接在数据库对应的表里面加上我们在实体里面命名的属性字段,并且选择对应的数据类型,好,想象中是可以的,而且运行没有报错,但实际会令我们失望。运行程序,程序仍然将我们的表重建,数据丢失。为什么我们手动把数据表字段与实体字段设置成一致了还会出错呢?这个我也没有深究。可能是EF框架另有玄机吧,望有高手指点。

3、方案三:首先备份现有表里面的数据,再删除数据库,运行我们的程序,新的表和字段都建好了,然后我们再想办法不论是写sql插入还是怎么办,反正很麻烦。而且如果遇到有自增主键关联的,你还没办法插对应主键的记录。所以仍不可行。

解决方法:

其实微软早就有很好很完美的解决办法了。通过网上搜集到的资料,简单说明其操作方法

涉及到变更表结构和字段的,都可以用数据迁移的方法。

具体操作如下:

1、首先修改我们的实体。编译通过。

2、打开“程序包管理器控制台”

3、打开之后如下图所示,选中我们的 Wchl.WMBlog.Model程序集

4、输入“Enable-Migrations -ContextTypeName  Wchl.WMBlog.Model.WMBlogDB”命令。别急,你得把Wchl.WMBlog.Model.WMBlogDB改成你的工程对应正确的类名,如下图

\"\"

5、命令执行之后,我们会发现我们的程序集里多了一些文件夹和文件。这个是自动生成的。

6、执行命令“add-migration Initial”,其中“Initial”可以自定成其他名字。

7、执行命令“update-database”,成功执行。

8、运行我们的程序,我们会惊奇地发现,我们的表结构已经修改了,而且我们的数据也都还在。


", - "btraffic": 48, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 7, - "bsubmitter": "admin", - "btitle": "Js,为什么if 表达式中有逗号表达式", - "bcategory": "技术博文", - "bcontent": "

比如:

var i = 4, j = 10;\r\n\r\nif((i > 5 ? true : false),i = 5,j > 8)\r\n{\r\n    alert(\"这里会被执行,并且i变成了5\") \r\n}

解答:

其实上面的代码可以这样写:


var i = 4, j = 10;\r\n(i > 5 ? ture : false);\r\ni=5;\r\nif(j > 8)\r\n{\r\n    alert(\"这里会被执行,并且i变成了5\") \r\n}

总结:

[?6/?27/?2018\r\n2:32 PM] 

js中逗号表达式的值为最右面的那个值

 if(1,1,1)等价于if(1)

 if(1,2,3,4,5)等价于if(5)

 if(false,true)等价于if(true) 

if(true,false)等价于if(false) 

与&&无任何关系

 

 


", - "btraffic": 16, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 8, - "bsubmitter": "admin", - "btitle": "厉害了,JS中 0.1+0.2 != 0.3!!!", - "bcategory": "技术博文", - "bcontent": "

console.log(0.1 + 0.2) // 结果是0.30000000000000004,而不是 0.3

这里0.1 + 0.2 != 0.3 这个就是我们要解决的问题了。

要弄清这个问题的原因,首先我们需要了解下在计算机中数字是如何存储和运算的。在计算机中,数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的。在JS中数字采用的IEEE 754的双精度标准进行存储,我们可以无需知道他的存储形式,只需要简单的理解成就是存储一个数值所使用的二进制位数比较多而已,这样得到的数会更加精确。

这里为了简单直观,我们使用定点数来说明问题。在定点数中,如果我们以8位二进制来存储数字。

对于整数来说,十进制的35会被存储为: 00100011 其代表 2^5 + 2^1 + 2^0。对于纯小数来说,十进制的0.375会被存储为: 0.011 其代表 1/2^2 + 1/2^3 = 1/4 + 1/8 = 0.375

而对于像0.1这样的数值用二进制表示你就会发现无法整除,最后算下来会是 0.000110011....由于存储空间有限,最后计算机会舍弃后面的数值,所以我们最后就只能得到一个近似值。在JS中采用的IEEE 754的双精度标准也是一样的道理,我们且不管这个标准下的存储方式跟定点数存储有何不同,单单在这一点上他们都是相同的,也就是存储空间有限,当出现这种无法整除的小数的时候就会取一个近似值,在js中如果这个近似值足够近似,那么js就会认为他就是那个值。(比较拗口,举个例子)

console.log(0.1000000000000001)  \r\n// 0.1000000000000001 (中间14个0,会打印出它本身)\r\n\r\nconsole.log(0.10000000000000001)  \r\n// 0.1 (中间15个0,js会认为这两个值足够接近,所以会显示0.1)\r\n

    所以我们现在应该可以理解,就是说由于0.1转换成二进制时是无限循环的,所以在计算机中0.1只能存储成一个近似值。另外说一句,除了那些能表示成 x/2^n 的数可以被精确表示以外,其余小数都是以近似值得方式存在的。    在0.1 + 0.2这个式子中,0.1和0.2都是近似表示的,在他们相加的时候,两个近似值进行了计算,导致最后得到的值是0.30000000000000004,此时对于JS来说,其不够近似于0.3,于是就出现了0.1 + 0.2 != 0.3这个现象。    当然,也并非所有的近似值相加都得不到正确的结果。有时两个近似值进行计算的时候,得到的值是在JS的近似范围内的,于是就可以得到正确答案。至于哪些值计算后能得到正确结果,哪些不能,我们也不需要去记。最好的方法就是我们想办法规避掉这类小数计算时的精度问题就好了。

 

那么最常用的方法就是将浮点数转化成整数计算。因为整数都是可以精确表示的。

方法也很简单,举个例子:

对于0.1 + 0.02 我们需要转化成 ( 10 + 2 ) / 1e2\r\n对于0.1 * 0.02 我们则转化成 1 * 2 / 1e3\r\n

 

按照这个思路,写个简单的方法就好了。

 


", - "btraffic": 23, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 9, - "bsubmitter": "admin", - "btitle": "如何将本地代码上传到Github", - "bcategory": "技术博文", - "bcontent": "

重大的GIT:

https://github.com/anjoy8/AZLinli.com.

https://github.com/anjoy8/AZLinli.ORM

https://github.com/anjoy8/AZLinli.Blog


1、下载Git,注册账号,等待略

2、Github创建项目
\"\"


3、Code所在根目录执行

git init 

git add . 

git commit -m \"first commit\" (first commit 本次提交的内容) 

git remote add origin https://github.com/1111/test1.git (地址换成你建的项目的地址,不知道的话看下边 项目地址是哪个的图) 

git push -u origin master (这一句执行的时候 可能需要输入你的 git 账号 和密码)

第三步:建立git仓库

git init\r\n

第四步:将项目的所有文件添加到仓库中

git add .\r\n

第五步:

git add README.md\r\n

第六步:提交到仓库

git commit -m \"注释语句\"\r\n

第七步:将本地的仓库关联到GitHub,后面的https改成刚刚自己的地址,上面的红框处

git remote add origin https://github.com/zlxzlxzlx/Test.git\r\n

第八步:上传github之前pull一下

git pull origin master\r\n

第九步:上传代码到GitHub远程仓库

git push -u origin master\r\n

中间可能会让你输入Username和Password,你只要输入github的账号和密码就行了。执行完后,如果没有异常,等待执行完就上传成功了。

更新代码

第一步:查看当前的git仓库状态,可以使用git status

git status\r\n

第二步:更新全部

git add *\r\n

第三步:接着输入git commit -m \"更新说明\"

git commit -m \"更新说明\"\r\n

第四步:先git pull,拉取当前分支最新代码

git pull\r\n

第五步:push到远程master分支上

git push origin master\r\n

不出意外,打开GitHub已经同步了



Git常见错误与操作:error: src refspec master does not match any解决办法

一、 出现错误 error:src refspec master does not match any

原因分析:

引起该错误的原因是目录中没有文件,空目录是不能提交上去的

解决办法:

  1. $ touch README
  2. $ git add README
  3. $ git commit –m’first commit’
  4. $ git push origin master


", - "btraffic": 45, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 10, - "bsubmitter": "admin", - "btitle": "纯Javascript 手写 全选/全不选 反选 单选 等", - "bcategory": "技术博文", - "bcontent": "
<style>\r\ntd {\r\n    border-right: 1px dashed;\r\n    border-bottom: 1px dashed;\r\n}\r\n</style>\r\n\r\n<div>\r\n\t<table>\r\n\t<thead>\r\n\t\t<td><input type=\"checkbox\" name=\"allCheck\" onclick=\"allCheck();\" />全选   <input type=\"checkbox\" name=\"allFanCheck\" onclick=\"allFanCheck();\" />反选</td><td>姓名</td><td>年龄</td>\r\n\t</thead>\r\n\t<tbody>\r\n\t\t<tr>\r\n\t\t\t<td><input name=\"itemCheck\" onclick=\"itemClick();\" type=\"checkbox\" /></td><td>张三</td><td>18</td>\r\n\t\t</tr>\r\n\t\t<tr>\r\n\t\t\t<td><input name=\"itemCheck\" onclick=\"itemClick();\"  type=\"checkbox\" /></td><td>李四</td><td>16</td>\r\n\t\t</tr>\r\n\t\t<tr>\r\n\t\t\t<td><input name=\"itemCheck\" onclick=\"itemClick();\"  type=\"checkbox\" /></td><td>王五</td><td>23</td>\r\n\t\t</tr>\r\n\t\t<tr>\r\n\t\t\t<td><input name=\"itemCheck\" onclick=\"itemClick();\"  type=\"checkbox\" /></td><td>小熊猫</td><td>24</td>\r\n\t\t</tr>\r\n\t</tbody>\r\n</table>\r\n\r\n</div>\r\n<script>\r\nvar allCheckbox=document.getElementsByName(\"allCheck\");\r\nvar allFanCheckbox=document.getElementsByName(\"allFanCheck\");\r\nvar itemCheckboxList=document.getElementsByName(\"itemCheck\");\r\n\r\nfunction allCheck(){\r\n\tfor(var i=0;i<itemCheckboxList.length;i++){\r\n\t\titemCheckboxList[i].checked=allCheckbox[0].checked;\r\n\t}\r\n}\r\nfunction itemClick(){\r\n\tallCheckbox[0].checked=true;\r\n\tfor(var i=0;i<itemCheckboxList.length;i++){\r\n\t\tallCheckbox[0].checked &=itemCheckboxList[i].checked;\r\n\t}\r\n}\r\n\r\nfunction allFanCheck(){\r\n\tallCheckbox[0].checked=true;\r\n\tfor(var i=0;i<itemCheckboxList.length;i++){\r\n\t\titemCheckboxList[i].checked=!itemCheckboxList[i].checked;\r\n\t\tallCheckbox[0].checked &=itemCheckboxList[i].checked;\r\n\t}\r\n}\r\n</script>


", - "btraffic": 17, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 11, - "bsubmitter": "admin", - "btitle": "C# 反射初探", - "bcategory": "技术博文", - "bcontent": "

1、什么是反射        Reflection,中文翻译为反射。        这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型(class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:        Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。2、命名空间与装配件的关系        很多人对这个概念可能还是很不清晰,对于合格的.Net程序员,有必要对这点进行澄清。        命名空间类似与Java的包,但又不完全等同,因为Java的包必须按照目录结构来放置,命名空间则不需要。        装配件是.Net应用程序执行的最小单位,编译出来的.dll、.exe都是装配件。        装配件和命名空间的关系不是一一对应,也不互相包含,一个装配件里面可以有多个命名空间,一个命名空间也可以在多个装配件中存在,这样说可能有点模糊,举个例子:装配件A:

namespace  N1\r\n{\r\n      public  class  AC1  {…}\r\n      public  class  AC2  {…}\r\n}\r\nnamespace  N2\r\n{\r\n      public  class  AC3  {…}\r\n      public  class  AC4{…}\r\n}

装配件B:

namespace  N1\r\n{\r\n      public  class  BC1  {…}\r\n      public  class  BC2  {…}\r\n}\r\nnamespace  N2\r\n{\r\n      public  class  BC3  {…}\r\n      public  class  BC4{…}\r\n}

复制代码

这两个装配件中都有N1和N2两个命名空间,而且各声明了两个类,这样是完全可以的,然后我们在一个应用程序中引用装配件A,那么在这个应用程序中,我们能看到N1下面的类为AC1和AC2,N2下面的类为AC3和AC4。        接着我们去掉对A的引用,加上对B的引用,那么我们在这个应用程序下能看到的N1下面的类变成了BC1和BC2,N2下面也一样。        如果我们同时引用这两个装配件,那么N1下面我们就能看到四个类:AC1、AC2、BC1和BC2。        到这里,我们可以清楚一个概念了,命名空间只是说明一个类型是那个族的,比如有人是汉族、有人是回族;而装配件表明一个类型住在哪里,比如有人住在北京、有人住在上海;那么北京有汉族人,也有回族人,上海有汉族人,也有回族人,这是不矛盾的。        上面我们说了,装配件是一个类型居住的地方,那么在一个程序中要使用一个类,就必须告诉编译器这个类住在哪儿,编译器才能找到它,也就是说必须引用该装配件。        那么如果在编写程序的时候,也许不确定这个类在哪里,仅仅只是知道它的名称,就不能使用了吗?答案是可以,这就是反射了,就是在程序运行的时候提供该类型的地址,而去找到它。有兴趣的话,接着往下看吧。

\"\"


\"\"



namespace ConsoleAppTest\r\n

{\r\n

    class Program\r\n

    {\r\n

        static void Main(string[] args)\r\n

        {\r\n

            MianJi mj = new MianJi(2.5, 3.5);\r\n

            mj.Display();\r\n

            Type t = typeof(MianJi);//遍历MianJi类的特性\r\n

            foreach (DeBugInfo info in t.GetCustomAttributes(true))\r\n

            {\r\n

                Console.WriteLine(\"Bugno: {0}\", info.BugNo);\r\n

                Console.WriteLine(\"Developer: {0}\", info.Developer);\r\n

                Console.WriteLine(\"LastReviewed: {0}\", info.LastReview);\r\n

                Console.WriteLine(\"Message: {0}\", info.Message);\r\n

            }\r\n

            //遍历属性的特性\r\n

            foreach (PropertyInfo prinfo in t.GetProperties())\r\n

            {\r\n

                foreach (DeBugInfo dbi in prinfo.GetCustomAttributes(true))\r\n

                {\r\n

                    Console.WriteLine(\"Bug no: {0}\", dbi.BugNo);\r\n

                    Console.WriteLine(\"Developer: {0}\", dbi.Developer);\r\n

                    Console.WriteLine(\"Last Reviewed: {0}\", dbi.LastReview);\r\n

                    Console.WriteLine(\"Remarks: {0}\", dbi.Message);\r\n

                }\r\n

            }\r\n

            //遍历方法的特性\r\n

            foreach (MethodInfo m in t.GetMethods())\r\n

            {\r\n

                try\r\n

                {\r\n

                    foreach (var dbi in m.GetCustomAttributes(true))\r\n

                    {\r\n

                        Console.WriteLine(dbi.ToString());\r\n

                        if (dbi is DeBugInfo)\r\n

                        {\r\n

                            DeBugInfo dbiNew = dbi as DeBugInfo;\r\n

                            Console.WriteLine(\"Bug no: {0}\", dbiNew.BugNo);\r\n

                            Console.WriteLine(\"Developer: {0}\", dbiNew.Developer);\r\n

                            Console.WriteLine(\"Last Reviewed: {0}\", dbiNew.LastReview);\r\n

                            Console.WriteLine(\"Remarks: {0}\", dbiNew.Message);\r\n

                        }\r\n

                        else {\r\n

                        }\r\n

                    }\r\n

                }\r\n

                catch (Exception e)\r\n

                {\r\n

                    Console.WriteLine(e.InnerException + e.Message);\r\n

                }\r\n

            }\r\n

            //遍历字段的特性\r\n

            foreach (FieldInfo fiinfo in t.GetFields())\r\n

            {\r\n

                foreach (DeBugInfo dbi in fiinfo.GetCustomAttributes(true))\r\n

                {\r\n

                    Console.WriteLine(\"Bug no: {0}\", dbi.BugNo);\r\n

                    Console.WriteLine(\"Developer: {0}\", dbi.Developer);\r\n

                    Console.WriteLine(\"Last Reviewed: {0}\", dbi.LastReview);\r\n

                    Console.WriteLine(\"Remarks: {0}\", dbi.Message);\r\n

                }\r\n

            }\r\n

            Console.ReadKey();\r\n

        }\r\n

    }\r\n

    public class DeBugInfo : System.Attribute\r\n

    {\r\n

        private int bugNo;\r\n

        private string developer;\r\n

        private string lastReview;\r\n

        public string message;\r\n

        public DeBugInfo(int _bugNo, string _developer, string _lastReview)\r\n

        {\r\n

            this.bugNo = _bugNo;\r\n

            this.developer = _developer;\r\n

            this.lastReview = _lastReview;\r\n

        }\r\n

        public int BugNo\r\n

        {\r\n

            get\r\n

            {\r\n

                return bugNo;\r\n

            }\r\n

        }\r\n

        public string Developer\r\n

        {\r\n

            get\r\n

            {\r\n

                return developer;\r\n

            }\r\n

        }\r\n

        public string LastReview\r\n

        {\r\n

            get\r\n

            {\r\n

                return lastReview;\r\n

            }\r\n

        }\r\n

        public string Message\r\n

        {\r\n

            get\r\n

            {\r\n

                return message;\r\n

            }\r\n

            set\r\n

            {\r\n

                message = value;\r\n

            }\r\n

        }\r\n

    }\r\n

    public class MianJi\r\n

    {\r\n

        protected double length;\r\n

        protected double width;\r\n

        private string _name;\r\n

        [DeBugInfo(1, \"Nuha Ali\", \"2018.7.17\", message = \"age\")]\r\n

        public int age = 18;\r\n

        public MianJi(double l, double w)\r\n

        {\r\n

            length = l;\r\n

            width = w;\r\n

        }\r\n

        [DeBugInfo(2, \"Zara Ali\", \"2018.7.17\", Message = \"This is Property\")]\r\n

        public string name\r\n

        {\r\n

            [DeBugInfo(21, \"Zara Ali\", \"2018.7.17\", Message = \"This is Property\")]\r\n

            get { return this._name; }\r\n

            [DeBugInfo(22, \"Zara Ali\", \"2018.7.17\", Message = \"This is Property\")]\r\n

            set { this._name = name; }\r\n

        }\r\n

        [DeBugInfo(3, \"Zara Ali\", \"2018.7.17\", Message = \"This is Property\")]\r\n

        public void SetName(string name)\r\n

        {\r\n

            this._name = name;\r\n

        }\r\n

        [DeBugInfo(4, \"Zara Ali\", \"2018.7.17\", Message = \"This is Property\")]\r\n

        public string GetName()\r\n

        {\r\n

            return this._name;\r\n

        }\r\n

        [DeBugInfo(5, \"Zara Ali\", \"2018.7.17\", Message = \"This is Area Method\")]\r\n

        public double Area()\r\n

        {\r\n

            return length * width;\r\n

        }\r\n

        [DeBugInfo(6, \"Nuha Ali\", \"2018.7.17\")]\r\n

        public void Display()\r\n

        {\r\n

            Console.WriteLine(\"Length: {0}\", length);\r\n

            Console.WriteLine(\"Width: {0}\", width);\r\n

            Console.WriteLine(\"Area: {0}\", Area());\r\n

        }\r\n

    }\r\n

}\r\n

\r\n


", - "btraffic": 27, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 12, - "bsubmitter": "admin", - "btitle": "23中设计模式", - "bcategory": "技术博文", - "bcontent": "

1、单例模式

\"\"


************************************************************************************************************************************

\"\"

**********************************************************************************************************************************************************************************

第三种

\"\"

**********************************************************************************************************************************************************************************

\"\"

*****************************************************************************************


2、简单工厂模式

\"\"

*************************************************************************************************************************************************************************************

\"\"


*************************************************************************************************************************************************************************************


\"\"


3、原型模式

浅克隆                  克隆的紧紧是地址                                                                        

\"\"

解决了单例模式的限制,

***********************************************************************************************************************************************************************************

\"\"

字符串和类一样,每次修改,都是new string()了



深克隆                        可以通过序列化,反序列化的方式,重新分配                                                        

\"\"


", - "btraffic": 22, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 13, - "bsubmitter": "admin", - "btitle": "委托学习 解耦 ++ 事件", - "bcategory": "技术博文", - "bcontent": "

1、委托

\"\"

***********************************

委托的调用,

method.Invoke(3,4);

method(5,6);

method.BeginInvoke(6,7,null,null);//异步调用


&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

\"\"

上边的是定义了一个委托,然后呢,接下来是实例化一个委托:

GreetingHandler handlerChinese = new GreetingHandler(GreetingClass.GreetChinest);

GreetingClass.Greeting(\"Hello world!\",handlerChinese);



2.事件

\"\"

多播委托,method.GetInvocationList();//找到委托里面的全部方法;

***************************************************************************************************************

猫叫 触发事件 

   public delegate void CatMiaoHandler();

        public CatMiaoHandler CatMiaoHandlerMethod;\r\n

        public event CatMiaoHandler  CatMiaoHandlerMethodEvent;//声明事件,事件的本质就是委托的一个实例,加了event关键字修饰;\r\n

        public void Miao()\r\n

        {\r\n

            Console.WriteLine(\"喵叫了一声\");\r\n

            //委托\r\n

            if (CatMiaoHandlerMethod != null)\r\n

            {\r\n

                CatMiaoHandlerMethod();\r\n

            }\r\n

            //事件\r\n

            if (CatMiaoHandlerMethodEvent != null)\r\n

            {\r\n

                CatMiaoHandlerMethodEvent();\r\n

            }\r\n

        }\r\n

        Cat cat = new Cat();\r\n

        cat.CatMiaoHandlerMethod =new CatMiaoHandler(Dog.Wang);\r\n

        cat.CatMiaoHandlerMethod +=Mouse.Run;\r\n

        cat.CatMiaoHandlerMethod +=People.Awake;\r\n

            \r\n

        //cat.CatMiaoHandlerMethodEvent =new CatMiaoHandler(Dog.Wang);//1.不能被初始化\r\n

        cat.CatMiaoHandlerMethodEvent +=Mouse.Run;\r\n

        cat.CatMiaoHandlerMethodEvent +=People.Awake;\r\n

        //cat.CatMiaoHandlerMethodEvent();//2.不能被外部调用\r\n


", - "btraffic": 23, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 14, - "bsubmitter": "admin", - "btitle": "Lambda 表达式,源于委托", - "bcategory": "技术博文", - "bcontent": "

\"\"

************************************************************************************************************

\"\"

lambda表达式 把delegate换成了=>  箭头的左边是参数列表,右边是方法体

\"\"


WithReturnWithPara func=(x,y) => { return x+y; };

WithReturnWithPara func=(x,y) =>  x+y ;//去掉了大括号,如果方法只有一行,带返回值则直接去掉return。

NoReturnNoPara action = () => { };

WithReturnNoPara action = () => \"Hello world!\";

\"\"

foreach(int i in intList.Where<int>(num=>num>55))\r\n{\r\n    console.writeLine(i);\r\n}


", - "btraffic": 19, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 15, - "bsubmitter": "admin", - "btitle": "异步学习 异步委托 ", - "bcategory": "技术博文", - "bcontent": "

异步委托

\"\"

同步方法会卡住界面,异步方法不卡界面,原因是异步启动了多个线程执行计算任务,主线程没有被占用

666666666666666666

\"\"

\"\"

\"\"


*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

\"\"

\"\"


", - "btraffic": 32, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 16, - "bsubmitter": "admin", - "btitle": "泛型初探 第一次", - "bcategory": "技术博文", - "bcontent": "

什么是泛型



       我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类型不同。有没有一种办法,在方法中传入通用的数据类型,这样不就可以合并代码了吗?泛型的出现就是专门解决这个问题的。读完本篇文章,你会对泛型有更深的了解。


为什么要使用泛型

为了了解这个问题,我们先看下面的代码,代码省略了一些内容,但功能是实现一个栈,这个栈只能处理int数据类型:


public class Stack


    {


        private int[] m_item;


        public int Pop(){...}


        public void Push(int item){...}


        public Stack(int i)


        {


            this.m_item = new int[i];


        }


}


上面代码运行的很好,但是,当我们需要一个栈来保存string类型时,该怎么办呢?很多人都会想到把上面的代码复制一份,把int改成string不就行了。当然,这样做本身是没有任何问题的,但一个优秀的程序是不会这样做的,因为他想到若以后再需要long、Node类型的栈该怎样做呢?还要再复制吗?优秀的程序员会想到用一个通用的数据类型object来实现这个栈:


public class Stack


    {


        private object[] m_item;


        public object Pop(){...}


        public void Push(object item){...}


        public Stack(int i)


        {


            this.m_item = new[i];


        }


      


    }


这个栈写的不错,他非常灵活,可以接收任何数据类型,可以说是一劳永逸。但全面地讲,也不是没有缺陷的,主要表现在:


当Stack处理值类型时,会出现装箱、折箱操作,这将在托管堆上分配和回收大量的变量,若数据量大,则性能损失非常严重。 

在处理引用类型时,虽然没有装箱和折箱操作,但将用到数据类型的强制转换操作,增加处理器的负担。 

在数据类型的强制转换上还有更严重的问题(假设stack是Stack的一个实例):

Node1 x = new Node1();


            stack.Push(x);


         Node2 y = (Node2)stack.Pop();


上面的代码在编译时是完全没问题的,但由于Push了一个Node1类型的数据,但在Pop时却要求转换为Node2类型,这将出现程序运行时的类型转换异常,但却逃离了编译器的检查。


 


针对object类型栈的问题,我们引入泛型,他可以优雅地解决这些问题。泛型用用一个通过的数据类型T来代替object,在类实例化时指定T的类型,运行时(Runtime)自动编译为本地代码,运行效率和代码质量都有很大提高,并且保证数据类型安全。


 


使用泛型

下面是用泛型来重写上面的栈,用一个通用的数据类型T来作为一个占位符,等待在实例化时用一个实际的类型来代替。让我们来看看泛型的威力:


public class Stack<T>


    {


        private T[] m_item;


        public T Pop(){...}


        public void Push(T item){...}


        public Stack(int i)


        {


            this.m_item = new T[i];


        }


}


类的写法不变,只是引入了通用数据类型T就可以适用于任何数据类型,并且类型安全的。这个类的调用方法:


//实例化只能保存int类型的类


Stack<int> a = new Stack<int>(100);


      a.Push(10);


      a.Push(\"8888\"); //这一行编译不通过,因为类a只接收int类型的数据


      int x = a.Pop();


 


//实例化只能保存string类型的类


Stack<string> b = new Stack<string>(100);


b.Push(10); //这一行编译不通过,因为类b只接收string类型的数据


      b.Push(\"8888\");


string y = b.Pop();


 


这个类和object实现的类有截然不同的区别:


1. 他是类型安全的。实例化了int类型的栈,就不能处理string类型的数据,其他数据类型也一样。


2. 无需装箱和折箱。这个类在实例化时,按照所传入的数据类型生成本地代码,本地代码数据类型已确定,所以无需装箱和折箱。


3. 无需类型转换。


 


泛型类实例化的理论

C#泛型类在编译时,先生成中间代码IL,通用类型T只是一个占位符。在实例化类时,根据用户指定的数据类型代替T并由即时编译器(JIT)生成本地代码,这个本地代码中已经使用了实际的数据类型,等同于用实际类型写的类,所以不同的封闭类的本地代码是不一样的。按照这个原理,我们可以这样认为:


泛型类的不同的封闭类是分别不同的数据类型。


例:Stack<int>和Stack<string>是两个完全没有任何关系的类,你可以把他看成类A和类B,这个解释对泛型类的静态成员的理解有很大帮助。


 


泛型类中数据类型的约束

程序员在编写泛型类时,总是会对通用数据类型T进行有意或无意地有假想,也就是说这个T一般来说是不能适应所有类型,但怎样限制调用者传入的数据类型呢?这就需要对传入的数据类型进行约束,约束的方式是指定T的祖先,即继承的接口或类。因为C#的单根继承性,所以约束可以有多个接口,但最多只能有一个类,并且类必须在接口之前。这时就用到了C#2.0的新增关键字:


public class Node<T, V> where T : Stack, IComparable


        where V: Stack


    {...}


以上的泛型类的约束表明,T必须是从Stack和IComparable继承,V必须是Stack或从Stack继承,否则将无法通过编译器的类型检查,编译失败。


通用类型T没有特指,但因为C#中所有的类都是从object继承来,所以他在类Node的编写中只能调用object类的方法,这给程序的编写造成了困难。比如你的类设计只需要支持两种数据类型int和string,并且在类中需要对T类型的变量比较大小,但这些却无法实现,因为object是没有比较大小的方法的。 了解决这个问题,只需对T进行IComparable约束,这时在类Node里就可以对T的实例执行CompareTo方法了。这个问题可以扩展到其他用户自定义的数据类型。


如果在类Node里需要对T重新进行实例化该怎么办呢?因为类Node中不知道类T到底有哪些构造函数。为了解决这个问题,需要用到new约束:


public class Node<T, V> where T : Stack, new()


        where V: IComparable


需要注意的是,new约束只能是无参数的,所以也要求相应的类Stack必须有一个无参构造函数,否则编译失败。


C#中数据类型有两大类:引用类型和值类型。引用类型如所有的类,值类型一般是语言的最基本类型,如int, long, struct等,在泛型的约束中,我们也可以大范围地限制类型T必须是引用类型或必须是值类型,分别对应的关键字是class和struct:


public class Node<T, V> where T : class


        where V: struct


 


泛型方法

泛型不仅能作用在类上,也可单独用在类的方法上,他可根据方法参数的类型自动适应各种参数,这样的方法叫泛型方法。看下面的类:


public class Stack2


    {


        public void Push<T>(Stack<T> s, params T[] p)


        {


            foreach (T t in p)


            {


                s.Push(t);


            }


        }


}


原来的类Stack一次只能Push一个数据,这个类Stack2扩展了Stack的功能(当然也可以直接写在Stack中),他可以一次把多个数据压入Stack中。其中Push是一个泛型方法,这个方法的调用示例如下:


Stack<int> x = new Stack<int>(100);


    Stack2 x2 = new Stack2();


    x2.Push(x, 1, 2, 3, 4, 6);


    string s = \"\";


    for (int i = 0; i < 5; i++)


    {


        s += x.Pop().ToString();


    } //至此,s的值为64321


   


 


泛型中的静态成员变量

在C#1.x中,我们知道类的静态成员变量在不同的类实例间是共享的,并且他是通过类名访问的。C#2.0中由于引进了泛型,导致静态成员变量的机制出现了一些变化:静态成员变量在相同封闭类间共享,不同的封闭类间不共享。


这也非常容易理解,因为不同的封闭类虽然有相同的类名称,但由于分别传入了不同的数据类型,他们是完全不同的类,比如:


Stack<int> a = new Stack<int>();


Stack<int> b = new Stack<int>();


Stack<long> c = new Stack<long>();


类实例a和b是同一类型,他们之间共享静态成员变量,但类实例c却是和a、b完全不同的类型,所以不能和a、b共享静态成员变量。


泛型中的静态构造函数

静态构造函数的规则:只能有一个,且不能有参数,他只能被.NET运行时自动调用,而不能人工调用。


泛型中的静态构造函数的原理和非泛型类是一样的,只需把泛型中的不同的封闭类理解为不同的类即可。以下两种情况可激发静态的构造函数:


1. 特定的封闭类第一次被实例化。


2. 特定封闭类中任一静态成员变量被调用。


 


泛型类中的方法重载

方法的重载在.Net Framework中被大量应用,他要求重载具有不同的签名。在泛型类中,由于通用类型T在类编写时并不确定,所以在重载时有些注意事项,这些事项我们通过以下的例子说明:


public class Node<T, V>


    {


        public T add(T a, V b) //第一个add


        {


            return a;


        }


        public T add(V a, T b) //第二个add


        {


            return b;


        }


        public int add(int a, int b) //第三个add


        {


            return a + b;


        }


}


上面的类很明显,如果T和V都传入int的话,三个add方法将具有同样的签名,但这个类仍然能通过编译,是否会引起调用混淆将在这个类实例化和调用add方法时判断。请看下面调用代码:


Node<int, int> node = new Node<int, int>();


    object x = node.add(2, 11);


这个Node的实例化引起了三个add具有同样的签名,但却能调用成功,因为他优先匹配了第三个add。但如果删除了第三个add,上面的调用代码则无法编译通过,提示方法产生的混淆,因为运行时无法在第一个add和第二个add之间选择。


Node<string, int> node = new Node<string, int>();


        object x = node.add(2, \"11\");


   这两行调用代码可正确编译,因为传入的string和int,使三个add具有不同的签名,当然能找到唯一匹配的add方法。


由以上示例可知,C#的泛型是在实例的方法被调用时检查重载是否产生混淆,而不是在泛型类本身编译时检查。同时还得出一个重要原则:


当一般方法与泛型方法具有相同的签名时,会覆盖泛型方法。


 


泛型类的方法重写

方法重写(override)的主要问题是方法签名的识别规则,在这一点上他与方法重载一样,请参考泛型类的方法重载。


 


泛型的使用范围

本文主要是在类中讲述泛型,实际上,泛型还可以用在类方法、接口、结构(struct)、委托等上面使用,使用方法大致相同,就不再讲述。


小结

C# 泛型是开发工具库中的一个无价之宝。它们可以提高性能、类型安全和质量,减少重复性的编程任务,简化总体编程模型,而这一切都是通过优雅的、可读性强的语法完成的。尽管 C# 泛型的根基是 C++ 模板,但 C# 通过提供编译时安全和支持将泛型提高到了一个新水平。C# 利用了两阶段编译、元数据以及诸如约束和一般方法之类的创新性的概念。毫无疑问,C# 的将来版本将继续发展泛型,以便添加新的功能,并且将泛型扩展到诸如数据访问或本地化之类的其他 .NET Framework 领域。


原文链接,原作者https://www.cnblogs.com/yueyue184/p/5032156.html

侵删

", - "btraffic": 21, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 17, - "bsubmitter": "admin", - "btitle": "expects the parameter '@GameDate', which was not supplied.\"\tstring 对于 我设了null,但是往数据库里写的时候提醒不能为null怎么办", - "bcategory": "技术博文", - "bcontent": "
    public static object GetSingle(string SQLString, params SqlParameter[] cmdParms)\r\n        {\r\n            using (SqlConnection connection = new SqlConnection(connectionString))\r\n            {\r\n                using (SqlCommand cmd = new SqlCommand())\r\n                {\r\n                    try\r\n                    {\r\n                        PrepareCommand(cmd, connection, null, SQLString, cmdParms);\r\n                        object obj = cmd.ExecuteScalar();\r\n                        cmd.Parameters.Clear();\r\n                        if ((Object.Equals(obj, null)) || (Object.Equals(obj, System.DBNull.Value)))\r\n                        {\r\n                            return null;\r\n                        }\r\n                        else\r\n                        {\r\n                            return obj;\r\n                        }\r\n                    }\r\n                    catch (System.Data.SqlClient.SqlException e)\r\n                    {\r\n                        throw e;\r\n                    }\r\n                }\r\n            }\r\n        }



private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans, string cmdText, SqlParameter[] cmdParms)\r\n        {\r\n            if (conn.State != ConnectionState.Open)\r\n                conn.Open();\r\n            cmd.Connection = conn;\r\n            cmd.CommandText = cmdText;\r\n            if (trans != null)\r\n                cmd.Transaction = trans;\r\n            cmd.CommandType = CommandType.Text;//cmdType;\r\n            if (cmdParms != null)\r\n            {\r\n\r\n\r\n                foreach (SqlParameter parameter in cmdParms)\r\n                {\r\n                    if ((parameter.Direction == ParameterDirection.InputOutput || parameter.Direction == ParameterDirection.Input) &&\r\n                        (parameter.Value == null))\r\n                    {\r\n                        parameter.Value = DBNull.Value;\r\n                    }\r\n                    cmd.Parameters.Add(parameter);\r\n                }\r\n            }\r\n        }


", - "btraffic": 14, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 18, - "bsubmitter": "admin", - "btitle": "强大的json转换,vs 一键快速json转实体类", - "bcategory": "技术博文", - "bcontent": "

强大的json转换,vs  一键快速json转实体类

\"\"


", - "btraffic": 17, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 19, - "bsubmitter": "admin", - "btitle": "如何扒取网站信息 贼溜", - "bcategory": "技术博文", - "bcontent": "
  static void Main(string[] args)\r\n        {\r\n            //从指定的地址加载html文档 Jumony.Core\r\n            IHtmlDocument source = new JumonyParser().LoadDocument(\"http://www.cnblogs.com/cate/csharp\");\r\n            var aLinks = source.Find(\".titlelnk\");//按照css选择器搜索符合要求的元素\r\n            Console.OutputEncoding = Encoding.GetEncoding(936);\r\n            foreach (var aLink in aLinks)\r\n            {\r\n                //<a>Hello</a> 获取hello \r\n                Console.WriteLine(aLink.InnerText());\r\n\r\n                //获取 a标签和它的父节点 <h3><a>Hello</a></h3>\r\n                Console.WriteLine(aLink.Parent());\r\n\r\n                //<a>Hello</a> 获取hello \r\n                Console.WriteLine(aLink.InnerHtml());\r\n\r\n                //获取指定属性名的值  value和AttributeValue都可以获取,但区别是value当 当前属性对象为null时不会抛出异常\r\n                Console.WriteLine(aLink.Attribute(\"href\").Value());\r\n                Console.WriteLine(aLink.Attribute(\"href\").AttributeValue);\r\n\r\n            }\r\n            Console.ReadKey();\r\n        }


", - "btraffic": 27, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 20, - "bsubmitter": "admin", - "btitle": "async和await 异步多线程记录", - "bcategory": "技术博文", - "bcontent": "

\"\"

\"\"


", - "btraffic": 28, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 21, - "bsubmitter": "admin", - "btitle": "c# 用@符号,字符串中有引号,怎么正则,贼溜!", - "bcategory": "技术博文", - "bcontent": "
            Regex regex = new Regex(@\"https://www\\.amazon\\.com/gp/video/detail/\\w+\");\r\n            Regex regex2= new Regex(\"href=\\\"(https://www\\\\.amazon\\\\.com/gp/video/detail/\\\\w+)/.*?\\\">.*?src=\\\"http\");\r\n\r\n            var str = \"href=\\\"(https://www\\\\.amazon\\\\.com/gp/video/detail/\\\\w+)/.*?\\\">.*?src=\\\"http\";\r\n            var str2 = @\"href=\"\"\" + @\"(https://www\\.amazon\\.com/gp/video/detail/\\w+)/.*?\"\"\" + \">.*?src=\\\"http\";\r\n            var str3 = @\"href=\"\"(https://www\\.amazon\\.com/gp/video/detail/\\w+)/.*?\"\">.*?src=\"\"http\";\r\n\r\n


没错,就是在字符串中把引号,变成两个引号


var str3 = @\"href=\"\"(https://www\\.amazon\\.com/gp/video/detail/\\w+)/.*?\"\">.*?src=\"\"http\";


", - "btraffic": 40, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 22, - "bsubmitter": "admin", - "btitle": "泛型list 去重 备份知识", - "bcategory": "技术博文", - "bcontent": "

【C#】list 去重(转载)
原作者:https://www.cnblogs.com/hao-1234-1234/p/8855218.html

 

Enumerable.Distinct 方法 是常用的LINQ扩展方法,属于System.Linq的Enumerable方法,可用于去除数组、集合中的重复元素,还可以自定义去重的规则。

有两个重载方法:

\"复制代码\"\"复制代码\"

        //\r\n        // 摘要: \r\n        //     通过使用默认的相等比较器对值进行比较返回序列中的非重复元素。\r\n        //\r\n        // 参数: \r\n        //   source:\r\n        //     要从中移除重复元素的序列。\r\n        //\r\n        // 类型参数: \r\n        //   TSource:\r\n        //     source 中的元素的类型。\r\n        //\r\n        // 返回结果: \r\n        //     一个 System.Collections.Generic.IEnumerable<T>,包含源序列中的非重复元素。\r\n        //\r\n        // 异常: \r\n        //   System.ArgumentNullException:\r\n        //     source 为 null。\r\n        public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source);\r\n        //\r\n        // 摘要: \r\n        //     通过使用指定的 System.Collections.Generic.IEqualityComparer<T> 对值进行比较返回序列中的非重复元素。\r\n        //\r\n        // 参数: \r\n        //   source:\r\n        //     要从中移除重复元素的序列。\r\n        //\r\n        //   comparer:\r\n        //     用于比较值的 System.Collections.Generic.IEqualityComparer<T>。\r\n        //\r\n        // 类型参数: \r\n        //   TSource:\r\n        //     source 中的元素的类型。\r\n        //\r\n        // 返回结果: \r\n        //     一个 System.Collections.Generic.IEnumerable<T>,包含源序列中的非重复元素。\r\n        //\r\n        // 异常: \r\n        //   System.ArgumentNullException:\r\n        //     source 为 null。\r\n        public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer);    

\"复制代码\"\"复制代码\"

第一个方法不带参数,第二个方法需要传一个System.Collections.Generic.IEqualityComparer<T>的实现对象

1.值类型元素集合去重

List<int> list = new List<int> { 1, 1, 2, 2, 3, 4, 5, 5 };\r\nlist.Distinct().ToList().ForEach(s => Console.WriteLine(s));

执行结果是:1 2 3 4 5

2.引用类型元素集合去重

首先自定义一个Student类

\"\"

使用不到参数的Distinct方法去重

\"复制代码\"\"复制代码\"

            List<Student> list = new List<Student>() { \r\n                new Student(\"James\",1,\"Basketball\"),\r\n                new Student(\"James\",1,\"Basketball\"),\r\n                new Student(\"Kobe\",2,\"Basketball\"),\r\n                new Student(\"Curry\",3,\"Football\"),\r\n                new Student(\"Curry\",3,\"Yoga\")\r\n            };\r\n            list.Distinct().ToList().ForEach(s => Console.WriteLine(s.ToString()));   

\"复制代码\"\"复制代码\"

执行结果:\"\"

可见,并没有去除重复的记录。

不带comparer参数的Distinct方法是使用的IEqualityComparer接口的默认比较器进行比较的,对于引用类型,默认比较器比较的是其引用地址,程序中集合里的每一个元素都是个新的实例,引用地址都是不同的,所以不会被作为重复记录删除掉。

因此,我们考虑使用第二个重载方法。

新建一个类,实现IEqualityComparer接口。注意GetHashCode方法的实现,只有HashCode相同才会去比较

\"复制代码\"\"复制代码\"

    public class Compare:IEqualityComparer<Student>\r\n    {\r\n        public bool Equals(Student x,Student y)\r\n        {\r\n            return x.Id == y.Id;//可以自定义去重规则,此处将Id相同的就作为重复记录,不管学生的爱好是什么\r\n        }\r\n        public int GetHashCode(Student obj)\r\n        {\r\n            return obj.Id.GetHashCode();\r\n        }\r\n    }

\"复制代码\"\"复制代码\"

然后调用

list.Distinct(new Compare()).ToList().ForEach(s => Console.WriteLine(s.ToString()));

执行结果:\"\"

我们按照Id去给这个集合去重成功!

3.如何编写一个具有扩展性的去重方法

\"\"\"复制代码\"

    public class Compare<T, C> : IEqualityComparer<T>\r\n    {\r\n        private Func<T, C> _getField;\r\n        public Compare(Func<T, C> getfield)\r\n        {\r\n            this._getField = getfield;\r\n        }\r\n        public bool Equals(T x, T y)\r\n        {\r\n            return EqualityComparer<C>.Default.Equals(_getField(x), _getField(y));\r\n        }\r\n        public int GetHashCode(T obj)\r\n        {\r\n            return EqualityComparer<C>.Default.GetHashCode(this._getField(obj));\r\n        }\r\n    }\r\n    public static class CommonHelper\r\n    {\r\n        /// <summary>\r\n        /// 自定义Distinct扩展方法\r\n        /// </summary>\r\n        /// <typeparam name=\"T\">要去重的对象类</typeparam>\r\n        /// <typeparam name=\"C\">自定义去重的字段类型</typeparam>\r\n        /// <param name=\"source\">要去重的对象</param>\r\n        /// <param name=\"getfield\">获取自定义去重字段的委托</param>\r\n        /// <returns></returns>\r\n        public static IEnumerable<T> MyDistinct<T, C>(this IEnumerable<T> source, Func<T, C> getfield)\r\n        {\r\n            return source.Distinct(new Compare<T, C>(getfield));\r\n        }\r\n    }

\"复制代码\"

调用:

list.MyDistinct(s=>s.Id).ToList().ForEach(s => Console.WriteLine(s.ToString()));

用到了泛型、委托、扩展方法等知识点。可以用于任何集合的各种去重场景


", - "btraffic": 19, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 23, - "bsubmitter": "admin", - "btitle": "关于.net 项目中的仓储模式 Respository + Service模式", - "bcategory": "技术博文", - "bcontent": "
在Asp.net MVC controller的底层,常常有提到repository和service layer, 好像都是逻辑相关的层,那么它们到底是什么区别呢?\r\n\r\n简单的说:\r\n\r\nrepository就是一个管理数据持久层的,它负责数据的CRUD(Create, Read, Update, Delete)\r\n\r\nservice layer是业务逻辑层,它常常需要访问repository层,但是它不关心数据是如何获取和存储的。

\"\"


我们来看下在LinqToSql中如何应用该模式。\r\n1. 我们将对实体的公共操作部分,提取为IRepository接口,比如常见的增加,删除等方法。如下代码:\r\n\r\ninterface IRepository<T> where T : class\r\n{\r\n    IEnumerable<T> FindAll(Func<T, bool> exp);\r\n    void Add(T entity);\r\n    void Delete(T entity);\r\n    void Save();\r\n}\r\n2.下面我们实现一个泛型的类来具体实现上面的接口的方法。\r\n\r\npublic class Repository<T> : IRepository<T> where T : class\r\n{\r\n    public DataContext context;\r\n    public Repository(DataContext context)\r\n    {\r\n        this.context = context;\r\n    }\r\n    public IEnumerable<T> FindAll(Func<T, bool> exp)\r\n    {\r\n        return context.GetTable<T>().Where(exp);\r\n    }\r\n    public void Add(T entity)\r\n    {\r\n        context.GetTable<T>().InsertOnSubmit(entity);\r\n    }\r\n    public void Delete(T entity)\r\n    {\r\n        context.GetTable<T>().DeleteOnSubmit(entity);\r\n    }\r\n    public void Save()\r\n    {\r\n        context.SubmitChanges();\r\n    }\r\n}\r\n3.上面我们实现是每个实体公共的操作,但是实际中每个实体都有符合自己业务的逻辑。我们单独定义另外一个接口,例如:\r\n\r\ninterface IBookRepository : IRepository<Book>\r\n{\r\n    IList<Book> GetAllByBookId(int id);\r\n}\r\n4.最后该实体的Repository类实现如下:\r\npublic class BookRepository : Repository<Book>, IBookRepository\r\n{\r\n    public BookRepository(DataContext dc)\r\n        : base(dc)\r\n    { }\r\n    public IList<Book> GetAllByBookId(int id)\r\n    {\r\n        var listbook = from c in context.GetTable<Book>()\r\n                       where c.BookId == id\r\n                       select c;\r\n        return listbook.ToList();\r\n    }\r\n} \r\n上面只是为大家提供了一个最基本使用框架。\r\n\r\n然后通过Servie层去调用,

然后通过Servie层去调用


", - "btraffic": 33, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 24, - "bsubmitter": "admin", - "btitle": "原生 js ajax 请求 写法 简单", - "bcategory": "技术博文", - "bcontent": "

var Ajax={\r\n

  get: function(url, fn) {\r\n

    // XMLHttpRequest对象用于在后台与服务器交换数据   \r\n

    var xhr = new XMLHttpRequest();            \r\n

    xhr.open('GET', url, true);\r\n

    xhr.onreadystatechange = function() {\r\n

      // readyState == 4说明请求已完成\r\n

      if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) { \r\n

        // 从服务器获得数据 \r\n

        fn.call(this, xhr.responseText);  \r\n

      }\r\n

    };\r\n

    xhr.send();\r\n

  },\r\n

  // datat应为'a=a1&b=b1'这种字符串格式,在jq里如果data为对象会自动将对象转成这种字符串格式\r\n

  post: function (url, data, fn) {\r\n

    var xhr = new XMLHttpRequest();\r\n

    xhr.open(\"POST\", url, true);\r\n

    // 添加http头,发送信息至服务器时内容编码类型\r\n

    xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");  \r\n

    xhr.onreadystatechange = function() {\r\n

      if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {\r\n

        fn.call(this, xhr.responseText);\r\n

      }\r\n

    };\r\n

    xhr.send(data);\r\n

  }\r\n

}


", - "btraffic": 29, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 25, - "bsubmitter": "admin", - "btitle": "MVC Rator语法,通配分页,简洁高效", - "bcategory": "技术博文", - "bcontent": "
\r\n@{\r\n    int pageindex = (int)ViewData[\"pageNumberIndex\"];\r\n    int pagecount = (int)ViewData[\"PageCount\"];\r\n    string otherPara = (string)ViewData[\"PageOtherPara\"];\r\n    int showPageCount = 9;\r\n    string pageParaName = \"page\";\r\n    string pagePrevName = \"?\";\r\n    string pageNextName = \"?\";\r\n}\r\n\r\n\r\n<style>\r\n    .disabl {\r\n        cursor: not-allowed;\r\n        color: #ccc;\r\n    }\r\n\r\n    ul.pagination {\r\n        display: inline-block;\r\n        padding: 0;\r\n        margin: 0;\r\n    }\r\n\r\n        ul.pagination li {\r\n            display: inline;\r\n        }\r\n\r\n            ul.pagination li a {\r\n                color: black;\r\n                float: left;\r\n                padding: 8px 16px;\r\n                text-decoration: none;\r\n                transition: background-color .3s;\r\n                border: 1px solid #ddd;\r\n            }\r\n\r\n                ul.pagination li a.active {\r\n                    background-color: #4CAF50;\r\n                    color: white;\r\n                    border: 1px solid #4CAF50;\r\n                }\r\n\r\n                ul.pagination li a:hover:not(.active) {\r\n                    background-color: #ddd;\r\n                }\r\n\r\n    div.center {\r\n        text-align: center;\r\n    }\r\n</style>\r\n\r\n<div class=\"center\" data-title=\"@pagecount\">\r\n    <ul class=\"pagination\">\r\n        @if ((pagecount) > 1)\r\n        {\r\n            <li><a href=\"@(pageindex>1 ? \"?\"+(pageParaName)+\"=\"+(pageindex-1):\"javascript:void(0);\")\" class=\"@(pageindex==1 ? \"disabl\":\"\")\" >@(pagePrevName)</a></li>\r\n\r\n\r\n            if ((pagecount) > showPageCount)\r\n            {\r\n                if ((pageindex) < showPageCount - 1)\r\n                {\r\n\r\n                    for (int i = 1; i < (pageindex); i++)\r\n                    {\r\n                        if (i > 0)\r\n                        {\r\n                            <li><a href=\"?@(pageParaName)=@(i)@(otherPara)\" style=\"\">@i</a></li>\r\n\r\n                        }\r\n\r\n                    }\r\n                    if ((pageindex) > 0)\r\n                    {\r\n                        <li><a href=\"?@(pageParaName)=@(pageindex)@(otherPara)\" class=\"active\">@(pageindex)</a></li>\r\n\r\n                    }\r\n                    for (int i = (pageindex) + 1; i <= showPageCount - 1; i++)\r\n                    {\r\n                        if (i > 1)\r\n                        {\r\n                            <li><a href=\"?@(pageParaName)=@(i)@(otherPara)\" style=\"\">@i</a></li>\r\n\r\n                        }\r\n                        if (i == 1)\r\n                        {\r\n                            <li><a href=\"?@(pageParaName)=@(i)@(otherPara)\" class=\"active\">@i</a></li>\r\n\r\n                        }\r\n                    }\r\n                    <li><a href=\"?@(pageParaName)=@(pagecount)@(otherPara)\" style=\"\">...@(pagecount)</a></li>\r\n\r\n\r\n                }\r\n                else if ((pageindex) > (pagecount) - (showPageCount - 2))\r\n                {\r\n                    <li><a href=\"?@(pageParaName)=1@(otherPara)\" style=\"\">1...</a></li>\r\n                    for (int i = (pagecount) - (showPageCount - 2); i <= (pagecount); i++)\r\n                    {\r\n                        if (i == (pageindex))\r\n                        {\r\n                            <li><a href=\"?@(pageParaName)=@(pageindex)@(otherPara)\" class=\"active\">@(pageindex)</a></li>\r\n                        }\r\n                        else\r\n                        {\r\n                            <li><a href=\"?@(pageParaName)=@(i)@(otherPara)\">@i</a></li>\r\n                        }\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    <li><a href=\"?@(pageParaName)=1@(otherPara)\" style=\"\">1...</a></li>\r\n                    for (int i = (pageindex) - (showPageCount / 2 - 1); i < (pageindex) + (showPageCount / 2); i++)\r\n                    {\r\n                        if (i == (pageindex))\r\n                        {\r\n                            <li><a href=\"?@(pageParaName)=@(pageindex)@(otherPara)\" class=\"active\">@(pageindex)</a></li>\r\n                        }\r\n                        else\r\n                        {\r\n                            <li><a href=\"?@(pageParaName)=@(i)@(otherPara)\">@i</a></li>\r\n                        }\r\n                    }\r\n                    <li><a href=\"?@(pageParaName)=@(pagecount)@(otherPara)\" style=\"\">...@(pagecount)</a></li>\r\n                }\r\n            }\r\n            else\r\n            {\r\n\r\n                for (int i = 1; i <= (pagecount); i++)\r\n                {\r\n                    if (i == (pageindex))\r\n                    {\r\n                        <li><a href=\"?@(pageParaName)=@(pageindex)@(otherPara)\" class=\"active\">@(pageindex)</a></li>\r\n                    }\r\n                    else\r\n                    {\r\n                        <li><a href=\"?@(pageParaName)=@(i)@(otherPara)\">@i</a></li>\r\n                    }\r\n                }\r\n            }\r\n\r\n            <li><a href=\"@(pageindex<pagecount ? \"?\"+(pageParaName)+\"=\"+(pageindex+1):\"javascript:void(0);\")\" class=\"@(pageindex==pagecount ? \"disabl\":\"\")\" >@(pageNextName)</a></li>\r\n\r\n        }\r\n        else\r\n        {\r\n            <li><a>1</a></li>\r\n        }\r\n\r\n    </ul>\r\n</div>


引用

    ViewData[\"pageNumberIndex\"] = ViewBag.pageindex;\r\n    ViewData[\"PageCount\"] = ViewBag.pagecount;\r\n    ViewData[\"PageOtherPara\"] = \"\";\r\n\r\n    @Html.Partial(\"_PPaging\", this.ViewData)\r\n


", - "btraffic": 80, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 26, - "bsubmitter": "admin", - "btitle": ".net core2.0 api + Swagger + Resposity Service + ", - "bcategory": "技术博文", - "bcontent": "

1 .Net Core API 2.0

\"\"

\"\"

\"\"


\r\n

\r\n

2 Swagger


\"\"


  // This method gets called by the runtime. Use this method to add services to the container.\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            services.AddMvc();\r\n\r\n            #region Swagger 放在前边\r\n            services.AddSwaggerGen(c =>\r\n            {\r\n                c.SwaggerDoc(\"v1\", new Info\r\n                {\r\n                    Version = \"v1.1.0\",\r\n                    Title = \"AZLinli.Blog.Core API\",\r\n                    Description = \"框架集合\",\r\n                    TermsOfService = \"None\",\r\n                    Contact = new Swashbuckle.AspNetCore.Swagger.Contact { Name = \"AZLinli.Blog.Core\", Email = \"AZLinli.Blog.Core\", Url = \"AZLinli.Blog.Core\" }\r\n                });\r\n                //添加读取注释服务\r\n                var basePath = PlatformServices.Default.Application.ApplicationBasePath;\r\n                var xmlPath = Path.Combine(basePath, \"AZLinli.Blog.Core.xml\");\r\n                c.IncludeXmlComments(xmlPath, true);\r\n\r\n            });\r\n            #endregion\r\n\r\n\r\n        }\r\n\r\n        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\r\n        public void Configure(IApplicationBuilder app, IHostingEnvironment env)\r\n        {\r\n            if (env.IsDevelopment())\r\n            {\r\n                app.UseDeveloperExceptionPage();\r\n            }\r\n\r\n            app.UseMvc();\r\n\r\n\r\n            #region Swagger\r\n            app.UseSwagger();\r\n            app.UseSwaggerUI(c =>\r\n            {\r\n                c.SwaggerEndpoint(\"/swagger/v1/swagger.json\", \"ApiHelp V1\");\r\n            });\r\n            #endregion\r\n        }

\"\"


****************************************************************************

Resposity Service


", - "btraffic": 80, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 27, - "bsubmitter": "admin", - "btitle": ".Net Core2.0 API + Vue2.0 系统博文总结", - "bcategory": "随笔日志", - "bcontent": "

1、【2018.08.17 16:18】 开通三大平台  

三大平台同步直播

简 书:https://www.jianshu.com/notebooks/28621653

博客园:https://www.cnblogs.com/laozhang-is-phi/

CSDN:https://blog.csdn.net/baidu_35726140


2、【2018.08.17 17:38】  开始书写代码,并提交到Github

https://github.com/anjoy8/Blog.Core

\"\"


3、【2018.08.18 09:00】 开始有用户阅读并突破10 


4、【2018.08.21 15:48】 简书平台获取第一个赞


5、【2018.08.21 16:02】 博客园第一次上首页,但15分钟后迅速被下架。[哭]

\"\"


6、【2018.08.22 10:00】 Github首次被Start

\"\"

7、【2018.08.22 05:03】 博客园终于提交首页,并保持4个小时,收获2个赞,阅读量目前突破500

\"\"


7、【2018.08.23 10:00】Github第一次被Fork

\"\"


8、【2018.08.23 16:10】博客第一次被反对 [怼]

\"\"


", - "btraffic": 35, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 28, - "bsubmitter": "admin", - "btitle": "Git 单纯的下载指定文件夹下文件,", - "bcategory": "技术博文", - "bcontent": "

一定是客户端,CMD会最后报错

打开 Git Bash (git 的命令行工具)

1.       用 cd 命令到 D:盘 根目录下 (或者在 D: 盘下 空白处右键 >>\r\nGit Bash Here) 

2.       如果本地还没有建版本库, 具体实现如下:  

·        \r\nmkdir Vcccccta  建立空文件夹  

·        \r\ncd Vidcccccta  进到目录下 

·        \r\ngit init <project> 

先建立一个空的版本库,用实际的目录名替代(<project>代表.git文件夹上级目录,如果已经进去到VideoIGData目录下<project>应当省略)

$ git init

·        \r\ngit remote add -f\r\norigin https://mstttttttttttttttttt/_git/ccccccccc/ 

·        \r\ngit config core.sparsecheckout true 

打开sparse checkout功能

·        \r\necho \"path1/\" >> .git/info/sparse-checkout 

添加2个目录到checkout的列表。路径是版本库下的相对路径,也可以用文本编辑器编辑这个文件。

$ echo \"/DA\"\r\n>> .git/info/sparse-checkout

·        \r\n$ git pull origin master 

 

 


", - "btraffic": 221, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "1" - }, - { - "bID": 29, - "bsubmitter": "admin", - "btitle": "从壹开始前后端分离【 Vue2.0 + .NET Core2.1】十五 ║ Vue前篇:JS面向对象", - "bcategory": "随笔日志", - "bcontent": "

缘起

书接上文《从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十四 ║ VUE 计划书 & 我的前后端开发简史》,昨天咱们说到了以我的经历说明的web开发经历的几个阶段,而且也说到了Vue系列需要讲到的知识点,今天就正式开始Code,当然今天的代码都特别简单,希望大家慢慢的学习,今天主要讲的是JS高级——关于面向对象的语法。

一、JS和C#一样,一切都是对象

0、关于JS函数方法的写法,目前有两种,不知道大家平时喜欢用哪种,请看:

    //这种是直接函数声明的方法\r\n    function GetGoods() {\r\n        var tmplTrips = new StringBuilder();\r\n        $('#DifCountry .cur').removeClass(\"cur\");\r\n\r\n        $.post(\"/Goods/GetGoods\", { brandid: 2, goodstype: \"2\" }, function (result) {\r\n            $('.random').html('');\r\n            if (result) {\r\n                if (result.length > 0) {\r\n                    $(result).each(function (i, item) {\r\n\r\n                        item.Goods_Logo = \"/Images/Logo/Goods/\" + item.Goods_Logo;\r\n                        if (i < 7) {\r\n                            tmplTrips.Append(' <dl data-goodsid=\"......... </dl>');\r\n                        }\r\n                        if (i == 6) {\r\n                            tmplTrips.Append('<dl class=\"more1\" onclick=\"window.location.href = \\'../.....</dl>');\r\n\r\n                        }\r\n\r\n\r\n\r\n\r\n                    });\r\n                    $('.random').html(tmplTrips.toString());\r\n                    $($('.random')).fadeIn().siblings('div').hide();\r\n                    bindGoodsDetailClick();\r\n\r\n                } else {\r\n                    $('.random').html('');\r\n                }\r\n            }\r\n        });\r\n    }\r\n\r\n//这一种是对象的写法\r\nObject.defineProperties(a, {\r\n  \"property\": {\r\n    set property(newValue) {\r\n      console.log(\"set property\");\r\n      return this._property = newValue;\r\n    },\r\n    get property() {\r\n      console.log(\"getgsd property\");\r\n      return this._property;\r\n    },\r\n    enumerable: true,\r\n    configurable: true\r\n  },\r\n  \"name\":{\r\n    value: \"maotr\",\r\n    writable: true,\r\n    enumerable: true,\r\n    configurable: true\r\n  }\r\n});\r\n

1、对象大家已经很熟悉了,包含 属性,方法,数据类型(字符串,数字,布尔,数组,对象),在C#中,随随便便就是写出几个对象,JS中也是如此。

2、这个时候,一定会有好多小伙伴问,既然是Vue,为什么要说JS呢,请看我写的简单的代码(这个是Vue中定义一个组件):

<script>\r\n  import myHeader from '../components/header.vue'\r\n  import myFooter from '../components/footer.vue'\r\n  export default {\r\n    components: {myHeader, myFooter},\r\n    data() {\r\n      return {\r\n        id: this.$route.params.id,\r\n        dat: {},\r\n        isShow: true\r\n      }\r\n    },\r\n    created() {\r\n      this.getData()\r\n    },\r\n\r\n    methods: {\r\n      getData() {\r\n        var that = this\r\n        this.$api.get('Blog/Get/' + this.id, null, r => {\r\n          r.data.bCreateTime = that.$utils.goodTime(r.data.bCreateTime)\r\n          this.dat = r.data\r\n          this.isShow = false\r\n        })\r\n      }\r\n    },\r\n    watch: {\r\n      '$route'(to, from) {\r\n        this.dat={}\r\n        this.isShow = true\r\n        this.id = to.params.id\r\n        this.getData()\r\n      }\r\n    }\r\n  }\r\n</script>

是不是和平时写的差不太多,但是又不太一样,如果你开发过微信小程序的话,可能学起来很简单,既然咱们要学,就好从头学,因为Vue基本的语法都是从ES5和ES6中过来的,大家如果真的想好好学,这一块是必须要掌握的。

二、定义对象的方式

1、通过new关键字

格式:new Object();

var obj=new Object();\r\n\r\nobj.Name='blog';\r\n\r\nobj.address='beijing';

2、嵌套字面量的方法,键值对的形式

格式:objectName = {property1:value1, property2:value2,…, propertyN:valueN} 。property是对象的属性 

       var obj = {\r\n            name: 'blog',\r\n            address: 'beijing',\r\n            say: function () {\r\n                alert(\"hello world\");\r\n            }\r\n        }

3、函数表达式,和函数声明很类似

注意!函数表达式必须先定义,再使用,有上下顺序之分;而函数声明没有。

//函数声明(定义和使用没有先后之分)\r\nfunction obj(){\r\n    alert('hi,我是函数声明');\r\n}\r\n\r\n//函数表达式(必须先定义声明,再使用)\r\nvar obj=function(){\r\n    alert('hi,我是函数表达式方法')\r\n}\r\n

4、构造函数声明

        function Blog() {\r\n            this.title = 'Vue学习',\r\n            this.font = '1100',\r\n            this.read = function () {\r\n                    alert('Hi ,Blog');\r\n                }\r\n        }\r\n        var blog1 = new Blog('JS学习', 100);\r\n        alert(blog1.title);\r\n        blog1.read();

总体来说,构造函数是目前使用最多的一种写法,但是要注意,构造函数和普通函数的区别:

//this的指向




", - "btraffic": 20, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 30, - "bsubmitter": "admin", - "btitle": "c# order by 字符型的数字时候,排序错误问题", - "bcategory": "技术博文", - "bcontent": "

比如:

List<digitalModel> digitalStrs = new List<digitalModel>() {\r\n     new digitalModel {\r\n        digitalStr=\"124844130139102\",//小\r\n    },\r\n    new digitalModel {\r\n        digitalStr=\"1000152864394053\",//大\r\n    },\r\n};\r\n

但是一般排序后会出错

   var sortStrs2 = digitalStrs.OrderByDescending(d => d.digitalStr).ToList();


所以应该增加条件

    class Program\r\n    {\r\n        static void Main(string[] args)\r\n        {\r\n            List<digitalModel> digitalStrs = new List<digitalModel>() {\r\n                 new digitalModel {\r\n                    digitalStr=\"124844130139102\",\r\n                },\r\n                new digitalModel {\r\n                    digitalStr=\"1000152864394053\",\r\n                },\r\n            };\r\n             \r\n            var sortStrs = digitalStrs.OrderByDescending(d => d.digitalStr, new SemiNumericComparer()).ToList();\r\n            var sortStrs2 = digitalStrs.OrderByDescending(d => d.digitalStr).ToList();\r\n\r\n\r\n\r\n            Console.ReadKey();\r\n        }\r\n\r\n\r\n        public class SemiNumericComparer : IComparer<string>\r\n        {\r\n            public int Compare(string s1, string s2)\r\n            {\r\n                if (IsNumeric(s1) && IsNumeric(s2))\r\n                {\r\n                    if (Convert.ToInt64(s1) > Convert.ToInt64(s2)) return 1;\r\n                    if (Convert.ToInt64(s1) < Convert.ToInt64(s2)) return -1;\r\n                    if (Convert.ToInt64(s1) == Convert.ToInt64(s2)) return 0;\r\n                }\r\n\r\n                if (IsNumeric(s1) && !IsNumeric(s2))\r\n                    return -1;\r\n\r\n                if (!IsNumeric(s1) && IsNumeric(s2))\r\n                    return 1;\r\n\r\n                return string.Compare(s1, s2, true);\r\n            }\r\n\r\n            public static bool IsNumeric(object value)\r\n            {\r\n                try\r\n                {\r\n                    long i = Convert.ToInt64(value.ToString());\r\n                    return true;\r\n                }\r\n                catch (FormatException)\r\n                {\r\n                    return false;\r\n                }\r\n            }\r\n        }\r\n\r\n\r\n\r\n\r\n\r\n\r\n        public class digitalModel\r\n        {\r\n            public string id { get; set; } = (new Guid()).ToString();\r\n            public string digitalStr { get; set; }\r\n\r\n        }\r\n    }\r\n



", - "btraffic": 73, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 31, - "bsubmitter": "admin", - "btitle": "netcore实现静态项目", - "bcategory": "技术博文", - "bcontent": "

修改 launchSettings.json ——》》 \"launchUrl\": \"swagger\",

  app.UseDefaultFiles();

   app.UseStaticFiles();

 

https://www.cnblogs.com/hantianwei/p/5641705.html


  app.UseDefaultFiles();

   app.UseStaticFiles();

 https://www.cnblogs.com/hantianwei/p/5641705.html

  app.UseDefaultFiles();

   app.UseStaticFiles();

 


https://www.cnblogs.com/hantianwei/p/5641705.html

  app.UseDefaultFiles();

   app.UseStaticFiles();


https://www.cnblogs.com/hantianwei/p/5641705.html

  app.UseDefaultFiles();

   app.UseStaticFiles();

 


https://www.cnblogs.com/hantianwei/p/5641705.html

  app.UseDefaultFiles();

   app.UseStaticFiles();

 

 


", - "btraffic": 291, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 32, - "bsubmitter": "admin", - "btitle": "EF 第三篇 生产环境下的数据迁移 ", - "bcategory": "技术博文", - "bcontent": "

步骤

1、创建实体

using System.ComponentModel.DataAnnotations.Schema;\r\n \r\nnamespace Migration\r\n{\r\n    public class User\r\n    {\r\n        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]\r\n        public Guid Id { get; set; }\r\n      //  public string Name { get; set; }\r\n        public string NickName { get; set; }\r\n       public int Sex { get; set; }\r\n    }\r\n}

 2、创建DbContext

using System.Data.Entity;\r\nnamespace Migration\r\n{\r\n    [DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]\r\n    public class DbBase : DbContext\r\n    {\r\n        public DbBase() : base(\"dbConnect\") {\r\n            \r\n        }\r\n        public DbSet<User> Users { get; set; }\r\n    }\r\n}

 3、打开程序包管理控制台,输入PM> enable-migrations,vs自动生成了Configuration类

\"\"

注意,生成的Configuration构造函数中AutomaticMigrationsEnabled值是false, 我们把它改成true,启用自动迁移。然后根据自已的需要设置数据库升级时是否允许数据丢失,建议还在开发阶段设AutomaticMigrationDataLossAllowed = true;直第一个生产环境发布了,将其改为AutomaticMigrationDataLossAllowed = false;以免造成客户重要数据丢失。这里的数据丢失指的是,例如:User表中,第一个版本有个Name字段,并且已经有数据录入了,然后第二个版本将Name字段删除了,此时若AutomaticMigrationDataLossAllowed = false则会出抛出异常,无法迁移。

3、修改DbContext


\r\n\r\nusing System.Data.Entity;\r\n \r\nnamespace Migration\r\n{\r\n \r\n    [DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]\r\n    public class DbBase : DbContext\r\n    {\r\n        public DbBase() : base(\"dbConnect\") {\r\n            //自动迁移\r\n            Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbBase, Migration.Migrations.Configuration>());\r\n        }\r\n        public DbSet<User> Users { get; set; }\r\n        \r\n        \r\n    }\r\n}


", - "btraffic": 94, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 33, - "bsubmitter": "admin", - "btitle": ".net 网站实现 HTTPS 访问,并自动跳转", - "bcategory": "技术博文", - "bcontent": "

准备

1.购买一台腾讯云CVM\r\n2.拥有一个已经在腾讯云备案成功的域名。

演示环境

系统:windows2008R2\r\n软件:IIS7.0,IIS的microsoft URL重写模块2.0

操作步骤:

1、给已备案的域名申请SSL证书并下载到服务器

这里我们使用IIS环境,所以选择IIS文件夹中的证书文件

2、打开IIS信息服务管理器部署SSL证书并绑定域名、开放并绑定端口

首先导入证书 (注意这个是在IIS里找,而不是在网站站点列表里找


接下来绑定https的443端口


6、然后打开IIS的主页找到服务器证书栏,双击打开即可。

\"有了SSL证书,如何在IIS环境下部署https?\"7、双击打开后,选择导入,导入我们刚刚解压得到的pfx文件,这个pfx文件就是你需要部署域名的那个文件。

\"有了SSL证书,如何在IIS环境下部署https?\"8、这个时候我们带https打开我们部署的网站,现在显示的还是红色的。

\"有了SSL证书,如何在IIS环境下部署https?\"9、现在我们去找到我们需要部署的网站,在服务器网站栏里,双击绑定。

\"有了SSL证书,如何在IIS环境下部署https?\"

10、然后我们点添加,添加,添加选择https,443端口。

\"有了SSL证书,如何在IIS环境下部署https?\"

\"有了SSL证书,如何在IIS环境下部署https?\"

11、这个时候我们通过浏览器打开https的网站。

\"有了SSL证书,如何在IIS环境下部署https?\"12、绿了有没有


3、安装URL重写工具

首先到URL重写工具下载页面,点击页面上的安装此扩展按钮。这样会跳到Web平台安装程序的下载页面,如果没有安装此工具,就在这里下载并安装;如果已经安装此工具,就直接打开,可以在IIS中,或者是直接在开始菜单中搜索此工具并打开。

\"\"



下载好了之后会发现我们的IIS界面多了个URL重写的组件,开始都没有的,没错,我是刚刚下的。

\"有了SSL证书,如何在IIS环境下部署https?\"


利用URL重写唯一就是能够实现全站http跳转https。

所以,在部署之前,请检查网站根目录是否有web.config文件,如有,请先备份这里的web.config文件,因为以下的配置可能会和web.config里面跳转冲突,个人建议是直接删除处理,毕竟旧的不去新的不来,哈哈哈(建议先备份)。


14、然后继续下一步,双击打开,添加规则。

\"有了SSL证书,如何在IIS环境下部署https?\"


15、填写规则名称:Redirect to https,使用正规表达式,模式填写 (.*),然后接下来选择添加条件。第一个填{HTTPS} 与模式匹配 ^OFF$ ,第二个填{HTTPS_HOST} 与模式不匹配 ^(localhost) 。

\"有了SSL证书,如何在IIS环境下部署https?\"


16、操作类型选择重定向,然后选择属性为https://{HTTP_HOST}/{R:1} 重定向类型选择303。

\"有了SSL证书,如何在IIS环境下部署https?\"


17、最后一步,检查下点保存即可。

\"有了SSL证书,如何在IIS环境下部署https?\"


18、现在我们可以去看看我们的网站,直接输入www.domain.com。

\"有了SSL证书,如何在IIS环境下部署https?\"


", - "btraffic": 198, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 34, - "bsubmitter": "admin", - "btitle": "asp.net 中的app_offline.htm的使用", - "bcategory": "技术博文", - "bcontent": "

前段时间,系统升级,由于系统更新发布时间较长,所以必须停掉站点进行更新。导致很多用户都来反馈系统无法访问,还认为站点被黑掉了。

所以经过那件事我们也在思考,如何做到不停机,进行热部署。单机环境下(双机或是分布式系统不用考虑这个问题),app_offline.htm是个不错的选择,

当asp.net看到应用程序中app_offline.htm文件时,它会关闭应用程序的app-domain,然后将请求发给app_offline的内容。

所以,在维护,升级的时候,就不必停止你的WEB应用程序,而是一个友好的方式提示给用户,本网站正在更新的提示,这样体验会更友好。

 

1. 创建一个app_offline.htm的HTM页面文件,


<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\"\r\ncontent=\"text/html; charset=gb2312\">\r\n<title>站点更新中</title>\r\n</head>\r\n<style>\r\ndiv {\r\nbackground-color:#ffffcc;\r\npadding-top:10px;\r\npadding-bottom:10px;\r\npadding-left:10px;\r\npadding-right:10px;\r\nborder-style:solid;\r\nborder-color:Black;\r\nborder-width:1px;\r\n}\r\n</style>\r\n<body>\r\n<div>\r\n<h1>站点更新中</h1>\r\n<p>站点更新中,请稍后访问。</p>\r\n</div>\r\n</body>\r\n</html>


 

2. 将app_offline.htm放在你的网站根目录下。这样,任何外部的请求的话,都会马上被转移到该页面了。

需要注意的是:

(1)app_offline.htm 不能小于 512 字节(可能不一定)。

(2)IIS 站点和进程池不需要停止。

(3)只有对.aspx文件的请求才自动转到app_offline.htm文件;如果请求的是.htm, .asp等文件,则不会转到app_offline.htm


", - "btraffic": 533, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 75, - "bsubmitter": "老张", - "btitle": "Session原理 知多少", - "bcategory": "技术博文", - "bcontent": "

一、session是怎么存储,提取的?


1、在服务器端有一个session池,用来存储每个用户提交session中的数据,Session对于每一个客户端(或者说浏览器实例)是“人手一份”,用户首次与Web服务器建立连接的时候,服务器会给用户分发一个SessionID作为标识。SessionID是一个由24个字符组成的随机字符串。用户每次提交页面,浏览器都会把这个SessionID包含在HTTP头中提交给Web服务器,这样Web服务器就能区分当前请求页面的是哪一个客户端,而这个SessionID是一cookie的方式保存的在客户端的内存中的,如果想要得到Session池中的数据,服务器就会根据客户端提交的唯一SessionID标识给出相应的数据返回。


2、输入正确的账号密码,点击登录,页面就会输出 “admin --- 点击登录”


二、Session池中每个客户端的数据是怎么存储的?


1、存储在Session池中的数据是全局型的数据,可以跨页面访问,每个SessionID中只存储唯一的数据,如:首先你这样设定:session[\"userName\"]=\"admin\",然后你在会话还没结束的session还没过期的情况下,你又设定:session[\"userName\"]=\"123\";这样这个SessionID没变,然而Session池中的数据则被覆盖。此时session[\"userName\"]的值就是“123”,而不是其它。

2、Session池中的数据不能跨进程访问。如:打开login.aspx页面写入session[“userName”]=\"admin\";然后login页面不关闭,即此会话不结束,在这是你再在另外一个浏览器中打开一个login.aspx页面则session[\"userName\"]=null

3、输入账号密码,点击登录页面输出  “admin --- 点击登录” ,如果紧接着点击获取session按钮,则页面只输出\"admin--- 点击获取session\",如果页面不关闭,打开另外一个浏览器,点击获取session按钮,则页面没法应。


三丶session的声明周期与销毁


1、session存储数据计时是滚动计时方式。具体是这样的,如果你打开写入session,从写入开始,此页面如果一直没有提交操作,则默认时间是20分钟,20分钟后session被服务器自动销毁,如过有提交操作,服务器会从提交后重新计时以此类推,直至设定时间内销毁。


2、可以设置session的销毁时间。上面代码有提到。


3丶session中保存的数据是在服务端的,而每个用户如进行登录操作,都要进行session数据写入,所以建议慎用session,就是少用。



", - "btraffic": 8, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 76, - "bsubmitter": "laozhang", - "btitle": "总结const、readonly、static三者的区别", - "bcategory": "技术博文", - "bcontent": "

const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享!

a、叫编译时常量的原因是它编译时会将其替换为所对应的值;

b、静态常量在速度上会稍稍快一些,但是灵活性却比动态常量差一些;

c、静态常量,隐式是静态的,即被static隐式修饰过,不能再用static重复修饰,

d、在声明时初始化;

e、静态常量只能被声明为简单的数据类型(内建的int和浮点型)、枚举或字符串。

f、应用场合例如:Math.PI的定义(要声明一些从不改变且处处唯一的常量,就应该使用静态常量)

 

readonly:动态常量,也称运行时常量(runtime constants),属于对象级,通过对象访问。

a、而动态常量的值是在运行时获得的;

b、动态常量在性能上稍差一点,但是灵活性好比前者好;

c、readonly可以被static修饰,这时的static readonly和const非常相似;

d、在声明是初始化,在构造函数里初始化;(static readonly常量,如果在构造函数内指定初始值,则必须是静态无参构造函数;)

e、动态常量可以是任意的数据类型。

f、应用场合例如:SqlHelper类的连接字符串定义

 

二者最大的差别在于:静态常量在编译时会将其换为对应的值,这就意味着对于不同的程序集来说,当你改变静态常量的时候需要将其重新编译,否则常量的值不会发生变化,可能引发潜在的问题,而动态常量就不会有这种情况,此时推荐使用static readonly,因为其是运行时赋值,当常量值被更改,运行时也随之更改。

 

static:本不应该把static与前两者放在一起区别对待的,但是static经常和它们搅在一起,所有这里特别把它拿来说个事。static的意义与const和readonly迥然不同,static是指所修饰的成员与类型有关,而与对象无关。

 静态字段和静态构造方法,通常适用于于一些不会经常变化而又频繁使用的数据,比如连接字符串,配置信息等,进行一次读取,以后就可以方便的使用了,同时也节约了托管资源,因为对于静态成员,一个静态字段只标识一个存储位置。

 非静态方法可以访问类中的任何成员,静态方法只能访问类中的静态成员。

 

总结:const是编译时常量,readonly是运行时常量;cosnt较高效,readonly较灵活。在应用上以static readonly代替const,以平衡const在灵活性上的不足,同时克服编译器优化cosnt性能,所带来的程序集引用不一致问题; 

本来想好好写一篇总结的,但是看了很多文章才发现水很深,有很多要注意的地方,不是这里三言两语就能说明白的。还要好好的积淀才能悟出它们的核心的区别的地方,把它们从本质上区分开来。

", - "btraffic": 31, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 77, - "bsubmitter": "ddd", - "btitle": "对于 Web 性能优化,您有哪些了解和经验吗?", - "bcategory": "技术博文", - "bcontent": "


1、前端优化


(1)减少 HTTP 请求的次数。我们知道每次发送http请求,建立连接和等待相应会花去相当一部分时间,所以在发送http请求的时候,尽量减少请求的次数,一次请求能取出的数据就不要分多次发送。

(2)启用浏览器缓存,当确定请求的数据不会发生变化时,能够直接读浏览器缓存的就不要向服务端发送请求。比如我们ajax里面有一个参数能够设置请求的时候是否启用缓存,这种情况下就需要我们在发送请求的时候做好相应的缓存处理。

(3)css文件放 在<head>里面,js文件尽量放在页面的底部。因为请求js文件是很花费时间,如果放在<head>里面,就会导致页面的 DOM树呈现需要等待js文件加载完成。这也就是为什么很多网站的源码里面看到引用的文件放在最后的原因。

(4)使用压缩的css和js文件。这个不用多说,网络流量小。

(5)如果条件允许,尽量使用CDN的方式引用文件,这样就能减少网络流量。比如我们常用的网站http://www.bootcdn.cn/。

(6)在写js和css的语法时,尽量避免重复的css,尽量减少js里面循环的次数,诸如此类。


2、后端优化:


(1)程序的优化:这是一个很大的话题,我这里就选几个常见的。比如减少代码的层级结构、避免循环嵌套、避免循环CURD数据库、优化算法等等。

(2)数据库的优化:(由于数据库优化不是本题重点,所以可选几个主要的来说)比如启用数据库缓存、常用的字段建索引、尽量避免大事务操作、避免select * 的写法、尽量不用in和not in 这种耗性能的用法等等。

(3)服务器优化:(这个可作为可选项)负载均衡、Web服务器和数据库分离、UI和Service分离等等。

", - "btraffic": 32, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 78, - "bsubmitter": "666", - "btitle": "666", - "bcategory": "技术博文", - "bcontent": "

666

", - "btraffic": 11, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "1" - }, - { - "bID": 79, - "bsubmitter": "xxx", - "btitle": "MVC路由理解?", - "bcategory": "技术博文", - "bcontent": "

1、首先我们要理解MVC中路由的作用:url Routing的作用是将浏览器的URL请求映射到特定的MVC控制器动作。


2、当我们访问http://localhost:8080/Home/Index 这个地址的时候,请求首先被UrlRoutingModule截获,截获请求后,从Routes中得到与当前请求URL相符合的RouteData对象, 将RouteData对象和当前URL封装成一个RequestContext对象,然后从Requestcontext封装的RouteData中得到 Controller名字,根据Controller的名字,通过反射创建控制器对象,这个时候控制器才真正被激活,最后去执行控制器里面对应的 action。

", - "btraffic": 42, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 80, - "bsubmitter": "laozhang", - "btitle": "谈谈你觉得做的不错系统,大概介绍下用到了哪些技术?", - "bcategory": "技术博文", - "bcontent": "

就拿我之前做过的一个项目为例来简单说明一下吧。项目分为客户端和服务端,客户端分 为BS客户端和CS客户端,BS客户端采用MVC 5.0的框架,CS客户端是Winform项目,服务端使用WebApi统一提供服务接口,考虑以后可能还要扩展手机端,所以服务接口的参数和返回值使用 通用的Json格式来传递数据。


1、服务端采用的面向接口编程,我们在软件架构的过程中,层和层之间通过接口依赖, 下层不是直接给上层提供实现,而是提供接口,具体的实现以依赖注入的方式在运行的时候动态注入进去。MEF就是实现依赖注入的一种组件。它的使用使得UI 层不直接依赖于BLL层,而是依赖于中间的一个IBLL层,在程序运行的时候,通过MEF动态将BLL里面的实现注入到UI层里面去,这样做的好处是减少 了层与层之间的耦合。服务端的异常里面、权限验证、日志记录等通用功能使用了AOP拦截的机制统一管理,项目中使用的是Postsharp这个组件,很好 地将通用需求功能从不相关的类当中分离出来,提高了代码的可维护性。


2、BS的客户端采用的jquery+bootstrap 的方式,所有页面采用流式布局,能更好适应各种不同的终端设备(PC、手机)。项目中使用了各种功能强大的bootstrap组件,能适应各种复杂的业务需求。

", - "btraffic": 203, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 84, - "bsubmitter": "IIS", - "btitle": "IIS的工作原理?", - "bcategory": "技术博文", - "bcontent": "

1、当客户端发送HTTP Request时,服务端的HTTP.sys(可以理解为IIS的一个监听组件) 拦截到这个请求;

2、HTTP.sys 联系 WAS 向配置存储中心请求配置信息。

3、然后将请求传入IIS的应用程序池。

4、检查请求的后缀,启动aspnet_isapi.dll这个dll,这个dll是.net framework里面的,也就是说到这一步,请求进入了.net framework的管辖范围。

5、这个时候如果是WebForm,开始执行复杂的页面生命周期(HttpRuntime→ProcessRequest→HttpContext→HttpHandler);如果是MVC,则启动mvc的路由机制,根据路由规则为URL来指定HttpHandler。

6、httpHandler处理请求后,请求结束,给出Response,客户端处理响应,整个过程结束。

", - "btraffic": 120, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 85, - "bsubmitter": "对对对", - "btitle": "代码:JS继承 + C# 单例模式", - "bcategory": "技术博文", - "bcontent": "

 单例模型


   public class Singleton\n    {\n\n        // 定义一个静态变量来保存类的实例\n        private static Singleton uniqueInstance;\n        // 定义一个标识确保线程同步\n        private static readonly object locker = new object();\n        // 定义私有构造函数,使外界不能创建该类实例\n        private Singleton()\n        {\n        }\n\n\n        /// <summary>\n        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点\n        /// </summary>\n        /// <returns></returns>\n        public static Singleton GetInstance()\n        {// 双重锁定只需要一句判断就可以了\n            if (uniqueInstance == null)\n            {\n                lock (locker)\n                {\n                    // 如果类的实例不存在则创建,否则直接返回\n                    if (uniqueInstance == null)\n                    {\n                        uniqueInstance = new Singleton();\n                    }\n                }\n            }\n            return uniqueInstance;\n        }\n    }\n\n




JS继承


     //1.定义Persiong函数\n      function Person(name, age) {\n          this.name = name;\n          this.age = age;\n      }\n\n      //2.通过原型链给Person添加一个方法\n      Person.prototype.getInfo = function () {\n          console.log(this.name + \" is \" + this.age + \" years old!\");\n      }\n      function Teacher(staffId) {\n          this.staffId = staffId;\n      }\n\n      //3.通过prototype生命 Teacher继承Person\n      Teacher.prototype = new Person();\n\n\n      //4.实例Teacher函数\n      var will = new Teacher(1000);\n      will.name= \"Will\";\n      will.age = 28;\n      //5.调用父类函数\n      will.getInfo();\n\n



", - "btraffic": 220, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 86, - "bsubmitter": "string", - "btitle": "string", - "bcategory": "string", - "bcontent": "string", - "btraffic": 20, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": "string", - "IsDeleted": "0" - }, - { - "bID": 87, - "bsubmitter": null, - "btitle": ";;;", - "bcategory": "技术博文", - "bcontent": "

;;;

", - "btraffic": 7, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "1" - }, - { - "bID": 88, - "bsubmitter": "string", - "btitle": "string", - "bcategory": "string", - "bcontent": "string", - "btraffic": 4, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": "string", - "IsDeleted": "1" - }, - { - "bID": 89, - "bsubmitter": "学习", - "btitle": ".Net Core 迁移之坑一 《WebAPI Get请求参数传入输入带有[]不识别问题》", - "bcategory": "技术博文", - "bcontent": "

在Framwork 体系下 WebAPI项目 会有很多默认特性,例如:Get查询竟然支持三种数组查询方式

1.https://localhost:44390/api/values?status=1&status=2

2.https://localhost:44390/api/values?status[]=1&status[]=2

3.https://localhost:44390/api/values?status[0]=1&status[1]=2

直到客户端同鞋找到我,才发现第二种在.net core webapi 默认竟然不支持

于是google了好久加上询问大牛,才找到一个解决方案,就是通过 Conventions 解决

\"复制代码\"

using Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.ApplicationModels;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing Microsoft.AspNetCore.Mvc.ModelBinding;\nusing Microsoft.Extensions.Primitives;\nusing System;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace WebApplication\n{\n    public class ArraryHandleQueryConvention : IParameterModelConvention\n    {\n        public void Apply(ParameterModel parameter)\n        {\n            if (parameter.ParameterType.IsArray || parameter.Attributes.OfType<FromQueryAttribute>().Any())\n                parameter.Action.Filters.Add(new ArrayQueryStringAttribute(parameter.ParameterName));\n        }\n    }\n    public class ArrayQueryStringValueProvider : QueryStringValueProvider\n    {\n        private readonly string _key;\n        private readonly IQueryCollection _values;\n\n        public ArrayQueryStringValueProvider(IQueryCollection values)\n            : this(null, values)\n        {\n        }\n\n        public ArrayQueryStringValueProvider(string key, IQueryCollection values)\n            : base(BindingSource.Query, values, CultureInfo.InvariantCulture)\n        {\n            _key = key;\n            _values = values;\n        }\n\n        public override ValueProviderResult GetValue(string key)\n        {\n            var result = base.GetValue(key + \"[]\");\n\n            if (_key != null && _key != key)\n            {\n                return result;\n            }\n            if (result != ValueProviderResult.None)\n            {\n                var splitValues = new StringValues(result.Values.ToArray());\n                return new ValueProviderResult(splitValues, result.Culture);\n            }\n            return result;\n        }\n    }\n\n    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = false)]\n    public class ArrayQueryStringAttribute : Attribute, IResourceFilter\n    {\n        private readonly ArrayQueryStringValueProviderFactory _factory;\n\n        public ArrayQueryStringAttribute(string key)\n        {\n            _factory = new ArrayQueryStringValueProviderFactory();\n        }\n\n        public void OnResourceExecuted(ResourceExecutedContext context)\n        {\n        }\n\n        public void OnResourceExecuting(ResourceExecutingContext context)\n        {\n            context.ValueProviderFactories.Insert(0, _factory);\n        }\n    }\n    public class ArrayQueryStringValueProviderFactory : IValueProviderFactory\n    {\n        private readonly string _key;\n\n        public ArrayQueryStringValueProviderFactory() \n        {\n        }\n\n        public ArrayQueryStringValueProviderFactory(string key)\n        {\n            _key = key;\n        }\n\n        public Task CreateValueProviderAsync(ValueProviderFactoryContext context)\n        {\n            context.ValueProviders.Insert(0, new ArrayQueryStringValueProvider(_key, context.ActionContext.HttpContext.Request.Query));\n            return Task.CompletedTask;\n        }\n    }\n}\n

\"复制代码\"

StartUp 里面添加就行了如图

说者无意听者有心,后来大牛找到我说其实还有第二种方式 就是 JQueryQueryStringValueProviderFactory

1行代码就解决了有木有

看下结果大功告成


", - "btraffic": 90, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 90, - "bsubmitter": "学习", - "btitle": "《WebAPI Get请求参数传入输入带有[]不识别问题》", - "bcategory": "技术博文", - "bcontent": "

在Framwork 体系下 WebAPI项目 会有很多默认特性,例如:Get查询竟然支持三种数组查询方式

1.https://localhost:44390/api/values?status=1&status=2

2.https://localhost:44390/api/values?status[]=1&status[]=2

3.https://localhost:44390/api/values?status[0]=1&status[1]=2


<img src=\"http://123.206.33.109:7090/images%5C0506120113image.png\" />


直到客户端同鞋找到我,才发现第二种在.net core webapi 默认竟然不支持

于是google了好久加上询问大牛,才找到一个解决方案,就是通过 Conventions 解决


using Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.ApplicationModels;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing Microsoft.AspNetCore.Mvc.ModelBinding;\nusing Microsoft.Extensions.Primitives;\nusing System;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace WebApplication\n{\n    public class ArraryHandleQueryConvention : IParameterModelConvention\n    {\n        public void Apply(ParameterModel parameter)\n        {\n            if (parameter.ParameterType.IsArray || parameter.Attributes.OfType<FromQueryAttribute>().Any())\n                parameter.Action.Filters.Add(new ArrayQueryStringAttribute(parameter.ParameterName));\n        }\n    }\n    public class ArrayQueryStringValueProvider : QueryStringValueProvider\n    {\n        private readonly string _key;\n        private readonly IQueryCollection _values;\n\n        public ArrayQueryStringValueProvider(IQueryCollection values)\n            : this(null, values)\n        {\n        }\n\n        public ArrayQueryStringValueProvider(string key, IQueryCollection values)\n            : base(BindingSource.Query, values, CultureInfo.InvariantCulture)\n        {\n            _key = key;\n            _values = values;\n        }\n\n        public override ValueProviderResult GetValue(string key)\n        {\n            var result = base.GetValue(key + \"[]\");\n\n            if (_key != null && _key != key)\n            {\n                return result;\n            }\n            if (result != ValueProviderResult.None)\n            {\n                var splitValues = new StringValues(result.Values.ToArray());\n                return new ValueProviderResult(splitValues, result.Culture);\n            }\n            return result;\n        }\n    }\n\n    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = false)]\n    public class ArrayQueryStringAttribute : Attribute, IResourceFilter\n    {\n        private readonly ArrayQueryStringValueProviderFactory _factory;\n\n        public ArrayQueryStringAttribute(string key)\n        {\n            _factory = new ArrayQueryStringValueProviderFactory();\n        }\n\n        public void OnResourceExecuted(ResourceExecutedContext context)\n        {\n        }\n\n        public void OnResourceExecuting(ResourceExecutingContext context)\n        {\n            context.ValueProviderFactories.Insert(0, _factory);\n        }\n    }\n    public class ArrayQueryStringValueProviderFactory : IValueProviderFactory\n    {\n        private readonly string _key;\n\n        public ArrayQueryStringValueProviderFactory() \n        {\n        }\n\n        public ArrayQueryStringValueProviderFactory(string key)\n        {\n            _key = key;\n        }\n\n        public Task CreateValueProviderAsync(ValueProviderFactoryContext context)\n        {\n            context.ValueProviders.Insert(0, new ArrayQueryStringValueProvider(_key, context.ActionContext.HttpContext.Request.Query));\n            return Task.CompletedTask;\n        }\n    }\n}\n


StartUp 里面添加就行了如图

说者无意听者有心,后来大牛找到我说其实还有第二种方式 就是 JQueryQueryStringValueProviderFactory



<img src=\"http://123.206.33.109:7090/images%5C0506120248image.png\" />


1行代码就解决了有木有

看下结果大功告成


", - "btraffic": 15, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "1" - }, - { - "bID": 91, - "bsubmitter": "学习", - "btitle": "《WebAPI Get请求参数传入输入带有[]不识别问题》", - "bcategory": "技术博文", - "bcontent": "

在Framwork 体系下 WebAPI项目 会有很多默认特性,例如:Get查询竟然支持三种数组查询方式

1.https://localhost:44390/api/values?status=1&status=2

2.https://localhost:44390/api/values?status[]=1&status[]=2

3.https://localhost:44390/api/values?status[0]=1&status[1]=2


<img src=\"http://123.206.33.109:7090/images%5C0506120113image.png\" />


直到客户端同鞋找到我,才发现第二种在.net core webapi 默认竟然不支持

于是google了好久加上询问大牛,才找到一个解决方案,就是通过 Conventions 解决


using Microsoft.AspNetCore.Http;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.AspNetCore.Mvc.ApplicationModels;\nusing Microsoft.AspNetCore.Mvc.Filters;\nusing Microsoft.AspNetCore.Mvc.ModelBinding;\nusing Microsoft.Extensions.Primitives;\nusing System;\nusing System.Globalization;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace WebApplication\n{\n    public class ArraryHandleQueryConvention : IParameterModelConvention\n    {\n        public void Apply(ParameterModel parameter)\n        {\n            if (parameter.ParameterType.IsArray || parameter.Attributes.OfType<FromQueryAttribute>().Any())\n                parameter.Action.Filters.Add(new ArrayQueryStringAttribute(parameter.ParameterName));\n        }\n    }\n    public class ArrayQueryStringValueProvider : QueryStringValueProvider\n    {\n        private readonly string _key;\n        private readonly IQueryCollection _values;\n\n        public ArrayQueryStringValueProvider(IQueryCollection values)\n            : this(null, values)\n        {\n        }\n\n        public ArrayQueryStringValueProvider(string key, IQueryCollection values)\n            : base(BindingSource.Query, values, CultureInfo.InvariantCulture)\n        {\n            _key = key;\n            _values = values;\n        }\n\n        public override ValueProviderResult GetValue(string key)\n        {\n            var result = base.GetValue(key + \"[]\");\n\n            if (_key != null && _key != key)\n            {\n                return result;\n            }\n            if (result != ValueProviderResult.None)\n            {\n                var splitValues = new StringValues(result.Values.ToArray());\n                return new ValueProviderResult(splitValues, result.Culture);\n            }\n            return result;\n        }\n    }\n\n    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = false)]\n    public class ArrayQueryStringAttribute : Attribute, IResourceFilter\n    {\n        private readonly ArrayQueryStringValueProviderFactory _factory;\n\n        public ArrayQueryStringAttribute(string key)\n        {\n            _factory = new ArrayQueryStringValueProviderFactory();\n        }\n\n        public void OnResourceExecuted(ResourceExecutedContext context)\n        {\n        }\n\n        public void OnResourceExecuting(ResourceExecutingContext context)\n        {\n            context.ValueProviderFactories.Insert(0, _factory);\n        }\n    }\n    public class ArrayQueryStringValueProviderFactory : IValueProviderFactory\n    {\n        private readonly string _key;\n\n        public ArrayQueryStringValueProviderFactory() \n        {\n        }\n\n        public ArrayQueryStringValueProviderFactory(string key)\n        {\n            _key = key;\n        }\n\n        public Task CreateValueProviderAsync(ValueProviderFactoryContext context)\n        {\n            context.ValueProviders.Insert(0, new ArrayQueryStringValueProvider(_key, context.ActionContext.HttpContext.Request.Query));\n            return Task.CompletedTask;\n        }\n    }\n}\n


StartUp 里面添加就行了如图

说者无意听者有心,后来大牛找到我说其实还有第二种方式 就是 JQueryQueryStringValueProviderFactory



<img src=\"http://123.206.33.109:7090/images%5C0506120248image.png\" />


1行代码就解决了有木有

看下结果大功告成


", - "btraffic": 115, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" - }, - { - "bID": 92, - "bsubmitter": null, - "btitle": null, - "bcategory": null, - "bcontent": null, - "btraffic": 0, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "1" - }, - { - "bID": 93, - "bsubmitter": "fffff", - "btitle": "Mvc model验证总结", - "bcategory": "技术博文", - "bcontent": "

Model 验证总结

https://www.cnblogs.com/starksoft/p/5616889.html




Model 验证总结 1

一.Model 验证标记 1

1、启用客户端验证: 1

2、在 Model 中加入验证标记 2

3 、 Model 类中可以添加的验证标记: 3

3.1、必填字段 3

3.2 、 字段长度 3

3.3 、 正则验证 3

3.4、范围 4

3.5、服务端参与的验证 4

3.6、比较 4

3.7、自定义错误消息 5

4、后台 Action 的写法 6

5 、 最后附上常用正则表达式(网上找的) 7

二、 Model 验证标记实例: 9

1 、  实例一: 9

2 、实例二: 10

附录: 13

一.Model 验证标记

1、启用客户端验证:

客户端验证主要是为了提高用户体验,在网页不回刷的情况下完成验证。

第一步是要在web.config里启用客户端验证,这在MVC3自带的模板项目中已经有了:

<addkey=\"ClientValidationEnabled\"value=\"true\"/>

<addkey=\"UnobtrusiveJavaScriptEnabled\"value=\"true\"/>

然后在被验证的View页面上要加入这样两个JavaScript,注意,他们是依赖于JQuery的:

<scriptsrc=\"@Url.Content(\"~/Scripts/jquery.validate.min.js\")\"type=\"text/javascript\"></script>

<scriptsrc=\"@Url.Content(\"~/Scripts/jquery.validate.unobtrusive.min.js\")\"type=\"text/javascript\"></script>

验证消息的显示有两种,一种是ValidationSummary,它可以显示一份验证消息的汇总,包括从后台Action里返回的消息。

@Html.ValidationSummary(true,\"Login was unsuccessful. Please correct the errors and try again.\")

另一种是Model中各属性对应HTML控件的验证消息:

@Html.ValidationMessageFor(m => m.UserName)

2、在 Model 中加入验证标记

MVC3项目模板自带的登录模型类如下:

\"复制代码\"

publicclassLogOnModel\n{\n\n    [Required]\n\n    [Display(Name =\"User name\")]\n\n    publicstringUserName {get;set; }\n\n    [Required]\n\n    [DataType(DataType.Password)]\n\n    [Display(Name =\"Password\")]\n\n    publicstringPassword {get;set; }\n\n    [Display(Name =\"Remember me?\")]\n\n    publicboolRememberMe {get;set; }\n\n}\n

\"复制代码\"


对比普通的C#类,我们发现每个属性上都多了被方括号“[]”包围的标记。其中,[Required]是验证标记的一种,而[Display]、[DataType]则是为了显示对应的HTML控件,这不在本文讨论范围之内。

除了Required,我们还可以在Model中添加其他有用的验证标记。下面是个较完整的列表:

3 、 Model 类中可以添加的验证标记:

3.1、必填字段

[Required]

public string FirstName { get; set; }

3.2 、 字段长度

至多n位:

[StringLength(160)]

public string FirstName { get; set; }

要求至少n位:

[StringLength(160, MinimumLength=3)]

public string FirstName { get; set; }

3.3 、 正则验证

[RegularExpression(@”[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}”)]

public string Email { get; set; }

3.4、范围

[Range(35,44)]

public int Age { get; set; }

小数的情况:

[Range(typeof(decimal), “0.00”, “49.99”)]

public decimal Price { get; set; }

3.5、服务端参与的验证

[Remote(“CheckUserName”, “Account”)]

public string UserName { get; set; }

然后在AccountController里指定一个CheckUserName方法:

publicJsonResult CheckUserName(stringusername)\n{\n    var result = Membership.FindUsersByName(username).Count == 0;\n    returnJson(result, JsonRequestBehavior.AllowGet);\n}\n

[RegularExpression(@”[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}”)]3.6、比较

public string Email { get; set; }

[Compare(“Email”)]

public string EmailConfirm { get; set; }

3.7、自定义错误消息

正则:

[RegularExpression(@”[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}”, ErrorMessage=”Email doesn’t look like a valid email address.”)]

public string Email { get; set; }

普通文本:

[Required(ErrorMessage=”Your last name is required”)]

[StringLength(160, ErrorMessage=”Your last name is too long”)]

public string LastName { get; set; }

占位符:

[Required(ErrorMessage=”Your {0} is required.”)]

[StringLength(160, ErrorMessage=”{0} is too long.”)]

public string LastName { get; set; }

4、后台 Action 的写法

Action里要做的有两件事:判断ModelState是否合法、添加错误消息。MVC3模板自带的登录Action如下:

\"复制代码\"

[HttpPost]\n\npublicActionResult LogOn(LogOnModel model,stringreturnUrl)\n{\n    if(ModelState.IsValid)\n    {\n        if(Membership.ValidateUser(model.UserName, model.Password))\n        {\n            FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);\n            if(Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith(\"/\")\n                && !returnUrl.StartsWith(\"//\") && !returnUrl.StartsWith(\"/\\\\\"))\n            {\n                returnRedirect(returnUrl);\n            }\n            else\n            {\n                returnRedirectToAction(\"Index\",\"Home\");\n            }\n        }\n        else\n        {\n            ModelState.AddModelError(\"\",\"The user name or password provided is incorrect.\");\n        }\n    }\n\n    // If we got this far, something failed, redisplay form\n    returnView(model);\n}\n

\"复制代码\"

 

if (ModelState.IsValid) 是重点,如果不出意外,即客户端浏览器没有关闭JavaScript,并且客户不是个黑客(黑客可能会通过一些工具模拟POST),那只要通过正常途径 POST到这个Action的Model都应该是IsValid的。当然,编程的一个重要原则是不能相信用户的输入,所以我们有必要再判断一次 ModelState.IsValid。[HttpPost]表示这个Action只能通过POST动作调用,这是为了配合View里的表单,因为FORM的ACTION是POST(当然也可以是GET),不过这不在本文的讨论范围内。

ModelState.AddModelError方法是给View返回一个错误消息,最终交给@Html.ValidationSummary显示。

5 、 最后附上常用正则表达式(网上找的)

数字:\"^[0-9]*$\"。

n位的数字:\"^\\d{n}$\"。

至少n位的数字:\"^\\d{n,}$\"。

m~n位的数字:。\"^\\d{m,n}$\"

零和非零开头的数字:\"^(0|[1-9][0-9]*)$\"。

有两位小数的正实数:\"^[0-9]+(.[0-9]{2})?$\"。

有1~3位小数的正实数:\"^[0-9]+(.[0-9]{1,3})?$\"。

非零的正整数:\"^\\+?[1-9][0-9]*$\"。

非零的负整数:\"^\\-[1-9][]0-9\"*$。

长度为3的字符:\"^.{3}$\"。

由26个英文字母组成的字符串:\"^[A-Za-z]+$\"。

由26个大写英文字母组成的字符串:\"^[A-Z]+$\"。

由26个小写英文字母组成的字符串:\"^[a-z]+$\"。

由数字和26个英文字母组成的字符串:\"^[A-Za-z0-9]+$\"。

由数字、26个英文字母或者下划线组成的字符串:\"^\\w+$\"。

验证用户密码:\"^[a-zA-Z]\\w{5,17}$\"正确格式为:以字母开头,长度在6~18之间,只能包含字符、数字和下划线。

验证是否含有^%&’,;=?$\\\"等字符:\"[^%&’,;=?$\\x22]+\"。

只能输入汉字:\"^[\\u4e00-\\u9fa5]{0,}$\"

验证Email地址:\"^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$\"。

验证InternetURL:\"^http://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?$\"。

验证电话号码:\"^(\\(\\d{3,4}-)|\\d{3.4}-)?\\d{7,8}$\"正确格式为:\"XXX-XXXXXXX\"、\"XXXX- XXXXXXXX\"、\"XXX-XXXXXXX\"、\"XXX-XXXXXXXX\"、\"XXXXXXX\"和\"XXXXXXXX\"。

验证身份证号(15位或18位数字):\"^\\d{15}|\\d{18}$\"。

验证一年的12个月:\"^(0?[1-9]|1[0-2])$\"正确格式为:\"01\"~\"09\"和\"1\"~\"12\"。

验证一个月的31天:\"^((0?[1-9])|((1|2)[0-9])|30|31)$\"正确格式为;\"01\"~\"09\"和\"1\"~\"31\"。

二、Model 验证标记实例:

1、实例一:

   

\"复制代码\"

public partial class UserDto     {\n\n        public long ID { get; set; }\n\n        [Display(Name=\"角色编号\")]        \n        public long RoleID { get; set; }\n\n        [Display(Name=\"角色\")]\n        public string RoleName { get; set; }\n\n        [StringLength(30)]\n        [Required(ErrorMessage=\"登录名不能为空\")]\n        [Display(Name = \"登录名\")]\n        [System.Web.Mvc.Remote(\"CheckUserName\", \"User\",\"Admin\", ErrorMessage = \"用户名已存在,请重新填写\")]\n        public string LoginID { get; set; }\n\n        [Display(Name = \"电话号码\")]\n        [RegularExpression(RegexHelper.Phone,ErrorMessage = \"电话格式有误,示例:023-12345678;(023)1234567-1234\")]       \n        public string Mobile { get; set; }\n\n        [RegularExpression(RegexHelper.Email, ErrorMessage = \"请输入正确的Email格式:abc@123.com\")]\n        [Display(Name = \"邮箱\")]\n        [StringLength(30)]\n        public string Email { get; set; }\n\n        [Display(Name = \"密码\")]\n        [Required(ErrorMessage=\"请输入密码\")]  \n        [DataType(DataType.Password)]\n        [StringLength(16,MinimumLength=6)]\n        public string Password { get; set; }\n\n        [DataType(DataType.Password)]\n        [Display(Name = \"确认密码\")]\n        [System.ComponentModel.DataAnnotations.Compare(\"Password\")]\n        public string PasaswordConfirm { get; set; }\n\n        [StringLength(80)]     \n        public string PasswordHash { get; set; }\n\n        [StringLength(10)]\n        [Display(Name = \"密码盐\")]\n        public string PasswordSalt { get; set; }\n\n        [StringLength(80)]\n        [Display(Name = \"用户名\")]\n        public string UserName { get; set; }\n\n        [StringLength(2)]\n        [Display(Name = \"性别\")]\n        public string Gender { get; set; }\n\n        [Display(Name = \"出生日期\")]\n        [DataType(DataType.Date)]\n        public DateTime? Birthday { get; set; }\n\n        [Display(Name = \"操作\")]\n        public string Operation { get; set; }\n\n    }\n\n}\n

\"复制代码\"

2 、实例二:

\"复制代码\"

namespace MvcApplication4.Models\n\n{\n\n    public class UserInfo\n\n    {        //ID编号\n\n        [ScaffoldColumn(false)]\n        [Required(AllowEmptyStrings = false, ErrorMessage = \"用户ID不能为空\")]\n        [Display(Name = \"记录编号\", Order = 20000)]\n        public int ID { get; set; }\n\n        [Display(Order = 15000)]\n        [Required(AllowEmptyStrings = false, ErrorMessage = \"用户名不能为空\")]\n        [StringLength(20, MinimumLength = 6, ErrorMessage = \"用户名不能大于{2} 且要小于{1}\")]\n        [Remote(\"User\", \"Validate\", HttpMethod = \"post\", ErrorMessage = \"用户名已经存在\")]\n        public string UserName { get; set; }        \n\n        [Display(Name=\"password\")]\n        [DataType(DataType.Password)]\n        [Required(AllowEmptyStrings = false, ErrorMessage = \"密码不能为空\")]\n        [StringLength(60, MinimumLength = 20, ErrorMessage = \"密码必须在{2} 和{1}之间\")]\n        public string UserPassword { get; set; }\n\n        [Required(AllowEmptyStrings = false, ErrorMessage = \"邮箱必填\")]\n        [RegularExpression(@\"[A-Za-z0-9._%+-]+@[A-Za-z0-9]+\\.[A-Za-z]{2,4}\", ErrorMessage = \"{0}的格式不正确\")]\n        public string Email { get; set; }\n\n        [Compare(\"Email\", ErrorMessage = \"邮箱要相同\")]\n        public string TEmail { get; set; }  //compare 大小写要相同 否则不会触发 验证\n\n        [Display(Name = \"身份证号码\")]\n        [RegularExpression(@\"\\d{17}[\\d|x]|\\d{15}\", ErrorMessage = \"身份证号码格式错误\")]\n        public string IdentityNo { get; set; }\n\n        [Required(AllowEmptyStrings = false, ErrorMessage = \"年龄必填\")]\n        [Range(10, 100, ErrorMessage = \"年龄不能大于{2} 不能小于{1}\")]\n        public int Age { get; set; }\n\n        [ReadOnly(true)]\n        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = \"{0:c}\")]\n        [Required(ErrorMessage = \"金额不能为空\")]\n        [Range(typeof(decimal), \"20.0\", \"30.0\", ErrorMessage = \"金额在{1}和{2}之间\")]\n        public decimal Money { get; set; }\n\n    }\n\n}\n

\"复制代码\"

", - "btraffic": 298, - "bcommentNum": 0, - "bUpdateTime": "\/Date(1546272000000+0800)\/", - "bCreateTime": "\/Date(1546272000000+0800)\/", - "bRemark": null, - "IsDeleted": "0" + "IsDeleted": 0 } ] diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.json/Department.tsv b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Department.tsv new file mode 100644 index 00000000..dfb887b1 --- /dev/null +++ b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Department.tsv @@ -0,0 +1 @@ +[{"CodeRelationship":"0,","Name":"BCVP开发社区","Leader":"老张的哲学","OrderSort":0,"Status":true,"IsDeleted":false,"CreateBy":"老张的哲学","CreateTime":"2022-04-01 15:47:25","ModifyTime":"2022-04-01 15:47:25","hasChildren":true,"Pid":0,"Id":1},{"CodeRelationship":"0,","Name":"DDD思想社区组织","Leader":"DDD","OrderSort":0,"Status":true,"IsDeleted":false,"CreateBy":"老张的哲学","CreateTime":"2022-04-01 15:48:08","ModifyTime":"2022-04-01 15:48:08","hasChildren":true,"Pid":0,"Id":2},{"CodeRelationship":"0,1,","Name":"BCVP-北京分部","Leader":"北京","OrderSort":0,"Status":true,"IsDeleted":false,"CreateBy":"老张的哲学","CreateTime":"2022-04-01 15:48:41","ModifyTime":"2022-04-01 15:48:41","hasChildren":true,"Pid":1,"Id":3},{"CodeRelationship":"0,1,","Name":"BCVP-上海分部","Leader":"上海","OrderSort":0,"Status":true,"IsDeleted":false,"CreateBy":"老张的哲学","CreateTime":"2022-04-01 15:49:27","ModifyTime":"2022-04-01 15:49:27","hasChildren":true,"Pid":1,"Id":4},{"CodeRelationship":"0,1,","Name":"BCVP-广州分部","Leader":"广州","OrderSort":0,"Status":true,"IsDeleted":false,"CreateBy":"老张的哲学","CreateTime":"2022-04-01 15:50:23","ModifyTime":"2022-04-01 15:50:44","hasChildren":true,"Pid":1,"Id":5},{"CodeRelationship":"0,1,3,","Name":"前端小组(1群)","Leader":"--","OrderSort":0,"Status":true,"IsDeleted":false,"CreateBy":"老张的哲学","CreateTime":"2022-04-01 15:51:43","ModifyTime":"2022-04-01 15:51:43","hasChildren":true,"Pid":3,"Id":6},{"CodeRelationship":"0,1,4,","Name":"后端小组(2群)","Leader":"--","OrderSort":0,"Status":true,"IsDeleted":false,"CreateBy":"老张的哲学","CreateTime":"2022-04-01 15:58:13","ModifyTime":"2022-04-01 15:58:13","hasChildren":true,"Pid":4,"Id":7},{"CodeRelationship":"0,","Name":"VUE学习联盟","Leader":"vue","OrderSort":0,"Status":true,"IsDeleted":false,"CreateBy":"老张的哲学","CreateTime":"2022-04-01 16:14:21","ModifyTime":"2022-04-01 16:14:21","hasChildren":true,"Pid":0,"Id":8},{"CodeRelationship":"0,8,","Name":"ES指导(1组)","Leader":"es","OrderSort":0,"Status":true,"IsDeleted":false,"CreateBy":"老张的哲学","CreateTime":"2022-04-01 16:14:47","ModifyTime":"2022-04-01 16:15:00","hasChildren":true,"Pid":8,"Id":9}] \ No newline at end of file diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.json/Modules.tsv b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Modules.tsv index 446327d7..76c55a22 100644 --- a/Blog.Core.Api/wwwroot/BlogCore.Data.json/Modules.tsv +++ b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Modules.tsv @@ -1,6 +1,6 @@ [ { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "values接口", "LinkUrl": "\/api\/values", @@ -11,8 +11,8 @@ "Code": null, "OrderSort": 1, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -22,7 +22,7 @@ "Id": 1 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "claims的接口", "LinkUrl": "\/api\/claims", @@ -33,8 +33,8 @@ "Code": null, "OrderSort": 1, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -44,7 +44,7 @@ "Id": 2 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "UserRole接口", "LinkUrl": "\/api\/UserRole", @@ -55,8 +55,8 @@ "Code": null, "OrderSort": 1, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -66,7 +66,7 @@ "Id": 3 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": null, "LinkUrl": "\/api\/v2\/Apb\/apbs", @@ -77,8 +77,8 @@ "Code": null, "OrderSort": 1, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -88,7 +88,7 @@ "Id": 4 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "修改 tibug 文章", "LinkUrl": "\/api\/TopicDetail\/update", @@ -99,8 +99,8 @@ "Code": null, "OrderSort": 1, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -110,7 +110,7 @@ "Id": 5 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "删除tibug文章", "LinkUrl": "\/api\/TopicDetail\/delete", @@ -121,8 +121,8 @@ "Code": null, "OrderSort": 1, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -132,7 +132,7 @@ "Id": 6 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取用户", "LinkUrl": "\/api\/user\/get", @@ -143,8 +143,8 @@ "Code": null, "OrderSort": 1, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -154,7 +154,7 @@ "Id": 7 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取用户详情", "LinkUrl": "\/api\/user\/get\/\\d+", @@ -165,8 +165,8 @@ "Code": null, "OrderSort": 1, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -176,7 +176,7 @@ "Id": 8 }, { - "IsDeleted": "1", + "IsDeleted": 1, "ParentId": null, "Name": "角色接口", "LinkUrl": "\/api\/role", @@ -187,8 +187,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -198,7 +198,7 @@ "Id": 9 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "添加用户", "LinkUrl": "\/api\/user\/post", @@ -209,8 +209,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -220,7 +220,7 @@ "Id": 10 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "删除用户", "LinkUrl": "\/api\/user\/delete", @@ -231,8 +231,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -242,7 +242,7 @@ "Id": 11 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "修改用户", "LinkUrl": "\/api\/user\/put", @@ -253,8 +253,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -264,7 +264,7 @@ "Id": 12 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取api接口", "LinkUrl": "\/api\/module\/get", @@ -275,8 +275,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -286,7 +286,7 @@ "Id": 13 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "删除api接口", "LinkUrl": "\/api\/module\/delete", @@ -297,8 +297,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -308,7 +308,7 @@ "Id": 14 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "修改api接口", "LinkUrl": "\/api\/module\/put", @@ -319,8 +319,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -330,7 +330,7 @@ "Id": 15 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "添加api接口", "LinkUrl": "\/api\/module\/post", @@ -341,8 +341,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -352,7 +352,7 @@ "Id": 16 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取菜单", "LinkUrl": "\/api\/permission\/get", @@ -363,8 +363,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -374,7 +374,7 @@ "Id": 17 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "删除菜单", "LinkUrl": "\/api\/permission\/delete", @@ -385,8 +385,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -396,7 +396,7 @@ "Id": 18 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "修改菜单", "LinkUrl": "\/api\/permission\/put", @@ -407,8 +407,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -418,7 +418,7 @@ "Id": 19 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "添加菜单", "LinkUrl": "\/api\/permission\/post", @@ -429,8 +429,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -440,7 +440,7 @@ "Id": 20 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取菜单树", "LinkUrl": "\/api\/permission\/getpermissiontree", @@ -451,8 +451,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -462,7 +462,7 @@ "Id": 21 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取角色", "LinkUrl": "\/api\/role\/get", @@ -473,8 +473,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -484,7 +484,7 @@ "Id": 22 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "删除角色", "LinkUrl": "\/api\/role\/delete", @@ -495,8 +495,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -506,7 +506,7 @@ "Id": 23 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "修改角色", "LinkUrl": "\/api\/role\/put", @@ -517,8 +517,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -528,7 +528,7 @@ "Id": 24 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "添加角色", "LinkUrl": "\/api\/role\/post", @@ -539,8 +539,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -550,7 +550,7 @@ "Id": 25 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取bug", "LinkUrl": "\/api\/TopicDetail\/Get", @@ -561,8 +561,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -572,7 +572,7 @@ "Id": 26 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取博客", "LinkUrl": "\/api\/Blog", @@ -583,8 +583,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -594,7 +594,7 @@ "Id": 27 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "保存分配", "LinkUrl": "\/api\/permission\/Assign", @@ -605,8 +605,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -616,7 +616,7 @@ "Id": 28 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "Get导航条", "LinkUrl": "\/api\/permission\/GetNavigationBar", @@ -627,8 +627,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -638,7 +638,7 @@ "Id": 29 }, { - "IsDeleted": "1", + "IsDeleted": 1, "ParentId": null, "Name": "test", "LinkUrl": "\/api\/Blog\/delete1", @@ -649,8 +649,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -660,7 +660,7 @@ "Id": 30 }, { - "IsDeleted": "1", + "IsDeleted": 1, "ParentId": null, "Name": "test", "LinkUrl": "\/api\/Blog\/delete2", @@ -671,8 +671,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -682,7 +682,7 @@ "Id": 31 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "删除博客", "LinkUrl": "\/api\/Blog\/delete", @@ -693,8 +693,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -704,7 +704,7 @@ "Id": 32 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取全部日志", "LinkUrl": "\/api\/Monitor\/get", @@ -715,8 +715,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -726,7 +726,7 @@ "Id": 33 }, { - "IsDeleted": "1", + "IsDeleted": 1, "ParentId": null, "Name": "Agent -测试- 快速添加接口权限", "LinkUrl": "\/api\/Agent\/get", @@ -737,8 +737,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -748,7 +748,7 @@ "Id": 34 }, { - "IsDeleted": "1", + "IsDeleted": 1, "ParentId": null, "Name": "test", "LinkUrl": "\/api\/test\/get", @@ -759,8 +759,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -770,7 +770,7 @@ "Id": 35 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "Department - 测试新建api - 部门管控", "LinkUrl": "\/api\/Department\/get", @@ -781,8 +781,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -792,7 +792,7 @@ "Id": 36 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "获取任务调取分页", "LinkUrl": "\/api\/TasksQz\/get", @@ -803,8 +803,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -814,7 +814,7 @@ "Id": 37 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "添加任务", "LinkUrl": "\/api\/TasksQz\/Post", @@ -825,8 +825,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -836,7 +836,7 @@ "Id": 38 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "编辑任务", "LinkUrl": "\/api\/TasksQz\/put", @@ -847,8 +847,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -858,7 +858,7 @@ "Id": 39 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "开启任务", "LinkUrl": "\/api\/TasksQz\/StartJob", @@ -869,8 +869,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -880,7 +880,7 @@ "Id": 40 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "停止任务", "LinkUrl": "\/api\/TasksQz\/StopJob", @@ -891,8 +891,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -902,7 +902,7 @@ "Id": 41 }, { - "IsDeleted": "0", + "IsDeleted": 0, "ParentId": null, "Name": "重启任务", "LinkUrl": "\/api\/TasksQz\/ReCovery", @@ -913,8 +913,8 @@ "Code": null, "OrderSort": 0, "Description": null, - "IsMenu": "0", - "Enabled": "1", + "IsMenu": 0, + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -922,5 +922,662 @@ "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", "Id": 42 + }, + { + "IsDeleted": 0, + "ParentId": null, + "Name": "删除任务", + "LinkUrl": "\/api\/TasksQz\/Delete", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 12, + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "Id": 43 + }, + { + "IsDeleted": 0, + "ParentId": null, + "Name": "暂停任务", + "LinkUrl": "\/api\/TasksQz\/PauseJob", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 12, + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "Id": 44 + }, + { + "IsDeleted": 0, + "ParentId": null, + "Name": "恢复任务", + "LinkUrl": "\/api\/TasksQz\/ResumeJob", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 12, + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "Id": 45 + }, + { + "IsDeleted": 0, + "ParentId": null, + "Name": "获取任务类名", + "LinkUrl": "\/api\/TasksQz\/GetTaskNameSpace", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 12, + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "Id": 46 + }, + + { + "Id": "47", + "IsDeleted": 0, + "Name": "微信获取", + "LinkUrl": "\/api\/WeChatConfig\/get", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-22 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "48", + "IsDeleted": 0, + "Name": "微信客户批量删除", + "LinkUrl": "\/api\/WeChatCompany\/BatchDelete", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "49", + "IsDeleted": 0, + "Name": "微信客户删除", + "LinkUrl": "\/api\/WeChatCompany\/delete", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "50", + "IsDeleted": 0, + "Name": "微信客户获取", + "LinkUrl": "\/api\/WeChatCompany\/get", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "51", + "IsDeleted": 0, + "Name": "微信客户添加", + "LinkUrl": "\/api\/WeChatCompany\/post", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "52", + "IsDeleted": 0, + "Name": "微信客户更新", + "LinkUrl": "\/api\/WeChatCompany\/put", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "53", + "IsDeleted": 0, + "Name": "微信公众号批量删除", + "LinkUrl": "\/api\/WeChatConfig\/BatchDelete", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-25 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "54", + "IsDeleted": 0, + "Name": "微信公众号获取", + "LinkUrl": "\/api\/WeChatConfig\/get", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-22 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "55", + "IsDeleted": 0, + "Name": "获取公众号菜单设置", + "LinkUrl": "\/api\/WeChat\/GetMenu", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "ParentId": 0 + }, + { + "Id": "56", + "IsDeleted": 0, + "Name": "获取订阅用户", + "LinkUrl": "\/api\/WeChat\/GetSubUsers", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-23 16:20:30", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "ParentId": 0 + }, + { + "Id": "57", + "IsDeleted": 0, + "Name": "获取消息模板列表", + "LinkUrl": "\/api\/WeChat\/GetTemplate", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-08 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "ParentId": 0 + }, + { + "Id": "58", + "IsDeleted": 0, + "Name": "微信公众号更新", + "LinkUrl": "\/api\/WeChatConfig\/post", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-24 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "59", + "IsDeleted": 0, + "Name": "微信公众号添加", + "LinkUrl": "\/api\/WeChatConfig\/put", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-24 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "Id": "60", + "IsDeleted": 0, + "Name": "刷新Token", + "LinkUrl": "\/api\/WeChat\/RefreshToken", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-30 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "ParentId": 0 + }, + { + "Id": "61", + "IsDeleted": 0, + "Name": "更新微信菜单设置", + "LinkUrl": "\/api\/WeChat\/UpdateMenu", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "ParentId": 0 + }, + { + "Id": "62", + "IsDeleted": 0, + "Name": "获取推送记录", + "LinkUrl": "\/api\/WeChatPushLog\/get", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-08 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "ParentId": 0 + }, + { + "Id": "63", + "IsDeleted": 0, + "Name": "获取绑定用户", + "LinkUrl": "\/api\/WeChatSub\/get", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-23 16:20:47", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-23 00:00:00", + "ParentId": 0 + }, + { + "Id": "64", + "IsDeleted": 0, + "Name": "微信公众号删除", + "LinkUrl": "\/api\/WeChatConfig\/delete", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-24 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "ParentId": 0 + }, + { + "IsDeleted": false, + "Name": "获取部门数据", + "LinkUrl": "/api/department/get", + "OrderSort": 0, + "IsMenu": false, + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "ParentId": 0, + "Id": 65 + }, + { + "IsDeleted": false, + "Name": "获取部门数据树表格", + "LinkUrl": "/api/permission/GetTreeTable", + "OrderSort": 0, + "IsMenu": false, + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "ParentId": 0, + "Id": 66 + }, + { + "IsDeleted": false, + "Name": "删除部门", + "LinkUrl": "/api/department/delete", + "OrderSort": 0, + "IsMenu": false, + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "ParentId": 0, + "Id": 67 + }, + { + "IsDeleted": false, + "Name": "更新部门", + "LinkUrl": "/api/department/put", + "OrderSort": 0, + "IsMenu": false, + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "ParentId": 0, + "Id": 68 + }, + { + "IsDeleted": false, + "Name": "添加部门", + "LinkUrl": "/api/department/post", + "OrderSort": 0, + "IsMenu": false, + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "ParentId": 0, + "Id": 69 + }, + { + "IsDeleted": false, + "Name": "获取部门树", + "LinkUrl": "/api/department/getDepartmentTree", + "OrderSort": 0, + "IsMenu": false, + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "ParentId": 0, + "Id": 70 + }, + { + "IsDeleted": 0, + "ParentId": null, + "Name": "Get导航条Pro", + "LinkUrl": "\/api\/permission\/GetNavigationBarPro", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 23, + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "Id": 71 + }, + { + "IsDeleted": 0, + "ParentId": null, + "Name": "菜单同步", + "LinkUrl": "\/api\/permission\/migratepermission", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 23, + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "Id": 72 + }, + { + "IsDeleted": 0, + "ParentId": null, + "Name": "任务日志查询", + "LinkUrl": "\/api\/TasksQz\/GetTaskLogs", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 23, + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "Id": 73 + }, + { + "IsDeleted": 0, + "ParentId": null, + "Name": "任务概况", + "LinkUrl": "\/api\/TasksQz\/GetTaskOverview", + "Area": null, + "Controller": null, + "Action": null, + "Icon": null, + "Code": null, + "OrderSort": 0, + "Description": null, + "IsMenu": 0, + "Enabled": 1, + "CreateId": 23, + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "Id": 74 } ] diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.json/Permission.tsv b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Permission.tsv index d3f1ef10..66b4313e 100644 --- a/Blog.Core.Api/wwwroot/BlogCore.Data.json/Permission.tsv +++ b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Permission.tsv @@ -1,255 +1,261 @@ [ { "Code": "\/", - "Name": "QQ欢迎页", - "IsButton": "0", + "Name": "首页", + "IsButton": 0, "Pid": 0, "Mid": 0, - "OrderSort": 0, - "Icon": "fa-qq", + "OrderSort": -90, + "Icon": "fa-home", + "IconNew": "HomeFilled", "Description": "33", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 1, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "用户角色管理", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": "fa-users", + "IconNew": "UserFilled", "Description": "11", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 2, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/User\/Roles", "Name": "角色管理", - "IsButton": "0", + "IsButton": 0, "Pid": 2, "Mid": 22, "OrderSort": 0, "Icon": null, + "IconNew": "Menu", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 3, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/User\/Users", "Name": "用户管理", - "IsButton": "0", + "IsButton": 0, "Pid": 2, "Mid": 7, "OrderSort": 0, "Icon": null, + "IconNew": "Menu", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 4, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "菜单权限管理", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": "fa-sitemap", + "IconNew": "Lock", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 5, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Permission\/Module", "Name": "接口管理", - "IsButton": "0", + "IsButton": 0, "Pid": 5, "Mid": 13, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 6, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Permission\/Permission", "Name": "菜单管理", - "IsButton": "0", + "IsButton": 0, "Pid": 5, "Mid": 17, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 7, - "IsHide": "0" + "IsHide": 0 }, { - "Code": "\/Thanks", - "Name": "致谢页", - "IsButton": "0", - "Pid": 0, + "Code": "\/System\/BasicSetting", + "Name": "个人设置", + "IsButton": 0, + "Pid": 68, "Mid": 0, "OrderSort": 5, "Icon": "fa-star ", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 8, - "IsHide": "0" + "IsHide": 0 }, { "Code": "无", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 4, "Mid": 7, "OrderSort": 0, "Icon": null, "Description": "这个用户页的查询按钮", - "Enabled": "1", - "Func": "getUsers", + "Enabled": 1, + "Func": "handleQuery", "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 9, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "报表管理", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": "fa-line-chart", + "IconNew": "Histogram", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 10, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Form\/Charts", "Name": "图表", - "IsButton": "0", + "IsButton": 0, "Pid": 10, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 11, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Form\/Form", "Name": "表单", - "IsButton": "0", + "IsButton": 0, "Pid": 10, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 12, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "新增", - "IsButton": "1", + "IsButton": 1, "Pid": 4, "Mid": 10, "OrderSort": 0, "Icon": null, "Description": "新增用户", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -257,20 +263,20 @@ "Func": "handleAdd", "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 13, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "编辑", - "IsButton": "1", + "IsButton": 1, "Pid": 4, "Mid": 12, "OrderSort": 0, "Icon": null, "Description": "编辑用户", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -278,20 +284,20 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 14, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "删除", - "IsButton": "1", + "IsButton": 1, "Pid": 4, "Mid": 11, "OrderSort": 0, "Icon": null, "Description": "删除用户", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -299,41 +305,41 @@ "Func": "handleDel", "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 15, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 3, "Mid": 22, "OrderSort": 0, "Icon": null, "Description": "查询 角色", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "Func": "getRoles", - "IsDeleted": "0", + "Func": "handleQuery", + "IsDeleted": 0, "Id": 16, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "新增", - "IsButton": "1", + "IsButton": 1, "Pid": 3, "Mid": 25, "OrderSort": 0, "Icon": null, "Description": "新增 角色", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -341,20 +347,20 @@ "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", "Func": "handleAdd", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 17, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "编辑", - "IsButton": "1", + "IsButton": 1, "Pid": 3, "Mid": 24, "OrderSort": 0, "Icon": null, "Description": "编辑角色", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -362,20 +368,20 @@ "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", "Func": "handleEdit", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 18, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "删除", - "IsButton": "1", + "IsButton": 1, "Pid": 3, "Mid": 23, "OrderSort": 0, "Icon": null, "Description": "删除角色", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -383,41 +389,41 @@ "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", "Func": "handleDel", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 19, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 6, "Mid": 13, "OrderSort": 0, "Icon": null, "Description": "查询 接口", - "Func": "getModules", - "Enabled": "1", + "Func": "handleQuery", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 20, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "新增", - "IsButton": "1", + "IsButton": 1, "Pid": 6, "Mid": 16, "OrderSort": 0, "Icon": null, "Description": "新增 接口", - "Enabled": "1", + "Enabled": 1, "Func": "handleAdd", "CreateId": 18, "CreateBy": "提bug账号", @@ -425,20 +431,20 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 21, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "编辑", - "IsButton": "1", + "IsButton": 1, "Pid": 6, "Mid": 15, "OrderSort": 0, "Icon": null, "Description": "编辑 接口", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "Func": "handleEdit", @@ -446,20 +452,20 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 22, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "删除", - "IsButton": "1", + "IsButton": 1, "Pid": 6, "Mid": 14, "OrderSort": 0, "Icon": null, "Description": "删除接口", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "Func": "handleDel", "CreateBy": "提bug账号", @@ -467,41 +473,41 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 23, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 7, "Mid": 17, "OrderSort": 0, "Icon": null, "Description": "查询 菜单", - "Func": "getPermissions", - "Enabled": "1", + "Func": "handleQuery", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 24, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "新增", - "IsButton": "1", + "IsButton": 1, "Pid": 7, "Mid": 20, "OrderSort": 0, "Icon": null, "Description": "新增菜单", - "Enabled": "1", + "Enabled": 1, "Func": "handleAdd", "CreateId": 18, "CreateBy": "提bug账号", @@ -509,20 +515,20 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 25, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "编辑", - "IsButton": "1", + "IsButton": 1, "Pid": 7, "Mid": 19, "OrderSort": 0, "Icon": null, "Description": "编辑菜单", - "Enabled": "1", + "Enabled": 1, "Func": "handleEdit", "CreateId": 18, "CreateBy": "提bug账号", @@ -530,20 +536,20 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 26, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "删除", - "IsButton": "1", + "IsButton": 1, "Pid": 7, "Mid": 18, "OrderSort": 0, "Icon": null, "Description": "删除 菜单", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "Func": "handleDel", "CreateBy": "提bug账号", @@ -551,60 +557,61 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 27, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Tibug\/Bugs", "Name": "TiBug", - "IsButton": "0", + "IsButton": 0, "Pid": 42, "Mid": 26, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 28, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "博客管理", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": "fa-file-word-o", + "IconNew": "List", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 29, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "编辑", - "IsButton": "1", + "IsButton": 1, "Pid": 28, "Mid": 5, "OrderSort": 0, "Icon": null, "Description": "编辑 tibug ", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -612,20 +619,20 @@ "ModifyBy": null, "Func": "handleEdit", "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 30, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "删除", - "IsButton": "1", + "IsButton": 1, "Pid": 28, "Mid": 6, "OrderSort": 0, "Icon": null, "Description": "删除 tibug", - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -633,661 +640,665 @@ "Func": "handleDel", "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 31, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 28, "Mid": 26, "OrderSort": 0, "Icon": null, "Description": "查询 tibug", - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, - "Func": "getBugs", + "Func": "handleQuery", "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 32, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "菜单树", - "IsButton": "1", + "IsButton": 1, "Pid": 7, "Mid": 21, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 33, - "IsHide": "1" + "IsHide": 1 }, { "Code": "\/Permission\/Assign", "Name": "权限分配", - "IsButton": "0", + "IsButton": 0, "Pid": 5, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 34, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "保存权限", - "IsButton": "1", + "IsButton": 1, "Pid": 34, "Mid": 28, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 35, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "左侧导航", - "IsButton": "1", + "IsButton": 1, "Pid": 7, "Mid": 29, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 36, - "IsHide": "1" + "IsHide": 1 }, { "Code": "-", "Name": "测试页面管理", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": "fa-flask", + "IconNew": "WarningFilled", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 37, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/TestShow\/TestOne", "Name": "测试页面1", - "IsButton": "0", + "IsButton": 0, "Pid": 37, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 38, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/TestShow\/TestTwo", "Name": "测试页面2", - "IsButton": "0", + "IsButton": 0, "Pid": 37, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 39, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/I18n\/index", "Name": "国际化", - "IsButton": "0", + "IsButton": 0, "Pid": 41, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 40, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "多语言管理", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": "fa-language", + "IconNew": "HelpFilled", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 41, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "问题管理", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": "fa-bug", + "IconNew": "Flag", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 42, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Blog\/Blogs", "Name": "博客", - "IsButton": "0", + "IsButton": 0, "Pid": 29, "Mid": 27, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 43, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "多级路由", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": "fa-sort-amount-asc", + "IconNew": "ChromeFilled", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 44, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "Menu-1", - "IsButton": "0", + "IsButton": 0, "Pid": 44, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 45, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Recursion\/Menu_1\/Menu_1_2", "Name": "Menu-1-2", - "IsButton": "0", + "IsButton": 0, "Pid": 45, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 46, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "Menu-1-1", - "IsButton": "0", + "IsButton": 0, "Pid": 45, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 47, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Recursion\/Menu_1\/Menu_1_1\/Menu_1_1_1", "Name": "Menu-1-1-1", - "IsButton": "0", + "IsButton": 0, "Pid": 47, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 48, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Recursion\/Menu_1\/Menu_1_1\/Menu_1_1_2", "Name": "Menu-1-1-2", - "IsButton": "0", + "IsButton": 0, "Pid": 47, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 49, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 50, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 51, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 52, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 53, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 54, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 55, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 56, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 57, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 58, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 59, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 60, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 61, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 62, - "IsHide": "0" + "IsHide": 0 }, { "Code": "s", "Name": "s", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "0", + "Enabled": 0, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 63, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "删除", - "IsButton": "1", + "IsButton": 1, "Pid": 43, "Mid": 32, "OrderSort": 0, "Icon": null, "Description": "删除博客按钮", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "Func": "handleDel", @@ -1295,201 +1306,203 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 64, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "日志管理", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 0, "Icon": "fa-diamond", + "IconNew": "Stamp", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 65, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Logs\/Index", "Name": "全部日志", - "IsButton": "0", + "IsButton": 0, "Pid": 65, "Mid": 33, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 66, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Blog\/Detail\/:id", "Name": "博客详情", - "IsButton": "0", + "IsButton": 0, "Pid": 29, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 67, - "IsHide": "1" + "IsHide": 1 }, { "Code": "-", "Name": "系统管理", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 1, "Icon": "el-icon-s-operation", + "IconNew": "Tools", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 68, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/System\/My", "Name": "个人中心", - "IsButton": "0", + "IsButton": 0, "Pid": 68, "Mid": 0, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 69, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 69, "Mid": 34, "OrderSort": 0, "Icon": null, "Description": "Agent 代理的查询接口", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 70, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 69, "Mid": 35, "OrderSort": 0, "Icon": null, "Description": "查询 部门 Department get", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "1", + "IsDeleted": 1, "Id": 71, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 69, "Mid": 36, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 72, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 43, "Mid": 27, "OrderSort": 0, "Icon": null, "Description": "查询博客按钮", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", - "Func": "getBlogs", + "Func": "handleQuery", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 73, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "编辑", - "IsButton": "1", + "IsButton": 1, "Pid": 43, "Mid": 27, "OrderSort": 0, "Icon": null, "Description": "编辑博客按钮", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "Func": "handleEdit", @@ -1497,81 +1510,82 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 74, - "IsHide": "0" + "IsHide": 0 }, { "Code": "-", "Name": "任务调度", - "IsButton": "0", + "IsButton": 0, "Pid": 0, "Mid": 0, "OrderSort": 1, "Icon": "fa-history", + "IconNew": "Ticket", "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 75, - "IsHide": "0" + "IsHide": 0 }, { "Code": "\/Task\/QuartzJob", "Name": "任务列表", - "IsButton": "0", + "IsButton": 0, "Pid": 75, "Mid": 37, "OrderSort": 0, "Icon": null, "Description": null, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 76, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "查询", - "IsButton": "1", + "IsButton": 1, "Pid": 76, "Mid": 37, "OrderSort": 0, "Icon": null, "Description": "查询任务按钮", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", - "Func": "getTasks", + "Func": "handleQuery", "CreateTime": "\/Date(1546272000000+0800)\/", "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 77, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "添加", - "IsButton": "1", + "IsButton": 1, "Pid": 76, "Mid": 38, "OrderSort": 0, "Icon": null, "Description": "添加任务按钮", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "Func": "handleAdd", @@ -1579,20 +1593,20 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 78, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "编辑", - "IsButton": "1", + "IsButton": 1, "Pid": 76, "Mid": 39, "OrderSort": 0, "Icon": null, "Description": "编辑任务按钮", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "Func": "handleEdit", @@ -1600,20 +1614,20 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 79, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "开启", - "IsButton": "1", + "IsButton": 1, "Pid": 76, "Mid": 40, "OrderSort": 0, "Icon": null, "Description": "开启任务按钮", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "Func": "handleStartJob", @@ -1621,20 +1635,20 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 80, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", - "Name": "暂停", - "IsButton": "1", + "Name": "停止", + "IsButton": 1, "Pid": 76, "Mid": 41, "OrderSort": 0, "Icon": null, - "Description": "暂停任务按钮", - "Enabled": "1", + "Description": "停止任务按钮", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "Func": "handleStopJob", @@ -1642,20 +1656,20 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 81, - "IsHide": "0" + "IsHide": 0 }, { "Code": " ", "Name": "重启", - "IsButton": "1", + "IsButton": 1, "Pid": 76, "Mid": 42, "OrderSort": 0, "Icon": null, "Description": "重启任务按钮", - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "Func": "handleReCoveryJob", @@ -1663,8 +1677,958 @@ "ModifyId": null, "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", - "IsDeleted": "0", + "IsDeleted": 0, "Id": 82, - "IsHide": "0" + "IsHide": 0 + }, + { + "Code": " ", + "Name": "删除", + "IsButton": 1, + "Pid": 76, + "Mid": 43, + "OrderSort": 0, + "Icon": null, + "Description": "删除任务按钮", + "Enabled": 1, + "CreateId": 12, + "CreateBy": "后台总管理员", + "Func": "handleDel", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "IsDeleted": 0, + "Id": 83, + "IsHide": 0 + }, + { + "Code": " ", + "Name": "暂停", + "IsButton": 1, + "Pid": 76, + "Mid": 44, + "OrderSort": 0, + "Icon": null, + "Description": "暂停任务按钮", + "Enabled": 1, + "CreateId": 12, + "CreateBy": "后台总管理员", + "Func": "handlePauseJob", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "IsDeleted": 0, + "Id": 84, + "IsHide": 0 + }, + { + "Code": " ", + "Name": "恢复", + "IsButton": 1, + "Pid": 76, + "Mid": 45, + "OrderSort": 0, + "Icon": null, + "Description": "恢复任务按钮", + "Enabled": 1, + "CreateId": 12, + "CreateBy": "后台总管理员", + "Func": "handleResumeJob", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "IsDeleted": 0, + "Id": 85, + "IsHide": 0 + }, + { + "Code": " ", + "Name": "获取任务名称", + "IsButton": 1, + "Pid": 76, + "Mid": 46, + "OrderSort": 0, + "Icon": null, + "Description": "获取任务名称按钮", + "Enabled": 1, + "CreateId": 12, + "CreateBy": "后台总管理员", + "Func": "", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "IsDeleted": 0, + "Id": 86, + "IsHide": 1 + }, + { + "Id": 87, + "Code": "-", + "Name": "微信公众号管理", + "IsButton": 0, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 3, + "IconNew": "WalletFilled", + "Icon": "fa-weixin", + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-21 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-13 00:00:00", + "IsDeleted": 0, + "Pid": 0, + "Mid": 0 + }, + { + "Id": 88, + "Code": "\/WeChat\/Manager", + "Name": "微信列表", + "IsButton": 0, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 1, + "Icon": "fa-list", + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-21 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-30 00:00:00", + "IsDeleted": 0, + "Pid": 87, + "Mid": 0 + }, + { + "Id": 89, + "Code": "\/WeChat\/Company", + "Name": "微信客户", + "IsButton": 0, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": "2", + "Icon": "fa-address-book", + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-26 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-30 00:00:00", + "IsDeleted": 0, + "Pid": 87, + "Mid": 0 + }, + { + "Id": 90, + "Code": "\/WeChat\/Menu", + "Name": "微信菜单", + "IsButton": 0, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 3, + "Icon": "fa-sliders", + "Description": "微信菜单设置", + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-30 00:00:00", + "IsDeleted": 0, + "Pid": 87, + "Mid": 0 + }, + { + "Id": 91, + "Code": "\/WeChat\/Template", + "Name": "模板消息", + "IsButton": 0, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 4, + "Icon": "fa-comments-o", + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-08 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-30 00:00:00", + "IsDeleted": 0, + "Pid": 87, + "Mid": 0 + }, + { + "Id": 92, + "Code": "\/WeChat\/PushLog", + "Name": "推送记录", + "IsButton": 0, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 8, + "Icon": "fa-history", + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-08 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-30 00:00:00", + "IsDeleted": 0, + "Pid": 87, + "Mid": 0 + }, + { + "Id": 93, + "Code": "\/WeChat\/SubUser", + "Name": "订阅用户", + "IsButton": 0, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 6, + "Icon": "fa fa-user", + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-23 14:09:08", + "ModifyId": 8, + "ModifyBy": "test", + "ModifyTime": "2021-09-30 00:00:00", + "IsDeleted": 0, + "Pid": 87, + "Mid": 0 + }, + { + "Id": 94, + "Code": "\/WeChat\/BindUser", + "Name": "绑定用户", + "IsButton": 0, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 7, + "Icon": "fa fa-user-circle-o", + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-23 16:12:52", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-30 00:00:00", + "IsDeleted": 0, + "Pid": 87, + "Mid": 0 + }, + { + "Id": 95, + "Code": "\/WeChat\/SendMessage", + "Name": "文本消息", + "IsButton": 0, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 5, + "Icon": "fa fa-paper-plane", + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-24 09:05:50", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-30 00:00:00", + "IsDeleted": 0, + "Pid": 87, + "Mid": 0 + }, + { + "Id": 96, + "Code": " ", + "Name": "查询", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": "getWeChatAccount", + "OrderSort": "0", + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-22 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-17 00:00:00", + "IsDeleted": 0, + "Pid": 88, + "Mid": 54 + }, + { + "Id": 98, + "Code": " ", + "Name": "删除", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": "handleDel", + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-22 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-17 00:00:00", + "IsDeleted": 0, + "Pid": 88, + "Mid": 64 + }, + { + "Id": 99, + "Code": " ", + "Name": "新增", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": "handleAdd", + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-24 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-17 00:00:00", + "IsDeleted": 0, + "Pid": 88, + "Mid": 59 + }, + { + "Id": 100, + "Code": " ", + "Name": "编辑", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": "handleEdit", + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-24 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-17 00:00:00", + "IsDeleted": 0, + "Pid": 88, + "Mid": 58 + }, + { + "Id": 101, + "Code": " ", + "Name": "批量删除", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": "batchRemove", + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-25 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-17 00:00:00", + "IsDeleted": 0, + "Pid": 88, + "Mid": 53 + }, + { + "Id": 102, + "Code": " ", + "Name": "刷新Token", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": "handleRefreshWeChatToken", + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-03-30 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-17 00:00:00", + "IsDeleted": 0, + "Pid": 88, + "Mid": 60 + }, + { + "Id": 103, + "Code": " ", + "Name": "查询", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": null, + "Func": "getWeChatCompany", + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "IsDeleted": 0, + "Pid": 89, + "Mid": 50 + }, + { + "Id": 104, + "Code": " ", + "Name": "删除", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": null, + "Func": "handleDel", + "OrderSort": "0", + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "IsDeleted": 0, + "Pid": 89, + "Mid": 49 + }, + { + "Id": 105, + "Code": " ", + "Name": "批量删除", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": null, + "Func": "batchRemove", + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "IsDeleted": 0, + "Pid": 89, + "Mid": 48 + }, + { + "Id": 106, + "Code": " ", + "Name": "添加", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": null, + "Func": "handleAdd", + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "IsDeleted": 0, + "Pid": 89, + "Mid": 51 + }, + { + "Id": 107, + "Code": " ", + "Name": "编辑", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": null, + "Func": "handleEdit", + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-06 00:00:00", + "IsDeleted": 0, + "Pid": 89, + "Mid": 52 + }, + { + "Id": 108, + "Code": " ", + "Name": "获取菜单", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "IsDeleted": 0, + "Pid": 90, + "Mid": 55 + }, + { + "Id": 109, + "Code": " ", + "Name": "更新菜单", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-06 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "IsDeleted": 0, + "Pid": 90, + "Mid": 61 + }, + { + "Id": 110, + "Code": " ", + "Name": "获取消息模板", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-08 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "IsDeleted": 0, + "Pid": 91, + "Mid": 57 + }, + { + "Id": 111, + "Code": " ", + "Name": "获取推送记录", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-08 00:00:00", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "IsDeleted": 0, + "Pid": 92, + "Mid": 62 + }, + { + "Id": 112, + "Code": " ", + "Name": "获取订阅用户", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": null, + "Func": null, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-23 16:21:53", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2020-04-23 00:00:00", + "IsDeleted": 0, + "Pid": 93, + "Mid": 56 + }, + { + "Id": 113, + "Code": " ", + "Name": "获取绑定用户", + "IsButton": 1, + "IsHide": 0, + "IskeepAlive": 0, + "Func": null, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 8, + "CreateBy": "test", + "CreateTime": "2020-04-23 16:22:11", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "2021-09-29 00:00:00", + "IsDeleted": 0, + "Pid": 94, + "Mid": 63 + }, + //{ + // "Id": 114, + // "Code": " ", + // "Name": "推送文字消息", + // "IsButton": 1, + // "IsHide": 0, + // "IskeepAlive": 0, + // "Func": null, + // "OrderSort": 0, + // "Icon": null, + // "Description": null, + // "Enabled": 1, + // "CreateId": 8, + // "CreateBy": "test", + // "CreateTime": "2020-04-23 16:22:11", + // "ModifyId": null, + // "ModifyBy": null, + // "ModifyTime": "2021-09-29 00:00:00", + // "IsDeleted": 0, + // "Pid": 95, + // "Mid": 0 + //}, + { + "Code": "-", + "Name": "部门权限管理", + "IsButton": false, + "IsHide": false, + "IskeepAlive": false, + "OrderSort": -10, + "Icon": "fa-address-book", + "IconNew": "Briefcase", + "Description": "", + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "IsDeleted": false, + "PnameArr": [ + + ], + "PCodeArr": [ + + ], + "hasChildren": true, + "Pid": 0, + "Mid": 0, + "Id": 114 + }, + { + "Code": "/Department/Department", + "Name": "部门管理", + "IsButton": false, + "IsHide": false, + "IskeepAlive": false, + "OrderSort": 0, + "Icon": "", + "IconNew": "Collection", + "Description": "", + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "IsDeleted": false, + "PnameArr": [ + + ], + "PCodeArr": [ + + ], + "hasChildren": true, + "Pid": 114, + "Mid": 66, + "Id": 115 + }, + { + "Code": " ", + "Name": "查询", + "IsButton": true, + "IsHide": false, + "IskeepAlive": false, + "Func": "handleQuery", + "OrderSort": 0, + "Icon": "", + "Description": "", + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "IsDeleted": false, + "PnameArr": [ + + ], + "PCodeArr": [ + + ], + "hasChildren": true, + "Pid": 115, + "Mid": 66, + "Id": 116 + }, + { + "Code": " ", + "Name": "新增", + "IsButton": true, + "IsHide": false, + "IskeepAlive": false, + "Func": "handleAdd", + "OrderSort": 0, + "Icon": "", + "Description": "", + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "IsDeleted": false, + "PnameArr": [ + + ], + "PCodeArr": [ + + ], + "hasChildren": true, + "Pid": 115, + "Mid": 69, + "Id": 117 + }, + { + "Code": " ", + "Name": "编辑", + "IsButton": true, + "IsHide": false, + "IskeepAlive": false, + "Func": "handleEdit", + "OrderSort": 0, + "Icon": "", + "Description": "", + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "IsDeleted": false, + "PnameArr": [ + + ], + "PCodeArr": [ + + ], + "hasChildren": true, + "Pid": 115, + "Mid": 68, + "Id": 118 + }, + { + "Code": " ", + "Name": "删除", + "IsButton": true, + "IsHide": false, + "IskeepAlive": false, + "Func": "handleDel", + "OrderSort": 0, + "Icon": "", + "Description": "", + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "IsDeleted": false, + "PnameArr": [ + + ], + "PCodeArr": [ + + ], + "hasChildren": true, + "Pid": 115, + "Mid": 67, + "Id": 119 + }, + { + "Code": " ", + "Name": "部门树", + "IsButton": true, + "IsHide": true, + "IskeepAlive": false, + "OrderSort": 0, + "Icon": "", + "Description": "", + "Enabled": true, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 00:00:00", + "ModifyTime": "2022-03-23 00:00:00", + "IsDeleted": false, + "PnameArr": [ + + ], + "PCodeArr": [ + + ], + "hasChildren": true, + "Pid": 115, + "Mid": 70, + "Id": 120 + }, + { + "Code": " ", + "Name": "左侧导航Pro", + "IsButton": 1, + "Pid": 7, + "Mid": 71, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 23, + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "IsDeleted": 0, + "Id": 121, + "IsHide": 1 + }, + { + "Code": " ", + "Name": "菜单同步", + "IsButton": 1, + "Pid": 7, + "Mid": 72, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 23, + "Func": "handleSync", + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "IsDeleted": 0, + "Id": 122, + "IsHide": 0 + }, + { + "Code": " ", + "Name": "日志查询", + "IsButton": 1, + "Pid": 76, + "Mid": 73, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 23, + "Func": "handleLog", + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "IsDeleted": 0, + "Id": 123, + "IsHide": 0 + }, + { + "Code": " ", + "Name": "任务概况", + "IsButton": 1, + "Pid": 76, + "Mid": 74, + "OrderSort": 0, + "Icon": null, + "Description": null, + "Enabled": 1, + "CreateId": 23, + "Func": "handleOverview", + "CreateBy": "后台总管理员", + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "IsDeleted": 0, + "Id": 124, + "IsHide": 0 } ] diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.json/Role.tsv b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Role.tsv index 510cbb12..d29deacc 100644 --- a/Blog.Core.Api/wwwroot/BlogCore.Data.json/Role.tsv +++ b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Role.tsv @@ -1,10 +1,10 @@ [ { - "IsDeleted": "0", + "IsDeleted": 0, "Name": "Admin", "Description": "普通管理", "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -14,11 +14,11 @@ "Id": 1 }, { - "IsDeleted": "0", + "IsDeleted": 0, "Name": "System", "Description": "系统管理", "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -28,11 +28,11 @@ "Id": 2 }, { - "IsDeleted": "0", + "IsDeleted": 0, "Name": "Tibug", "Description": "tibug系统管理", "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -42,11 +42,11 @@ "Id": 3 }, { - "IsDeleted": "0", + "IsDeleted": 0, "Name": "SuperAdmin", "Description": "超级管理", "OrderSort": 0, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "blogadmin", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -56,11 +56,11 @@ "Id": 4 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "AdminTest", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": 18, "CreateBy": "提bug账号", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -70,11 +70,11 @@ "Id": 5 }, { - "IsDeleted": "0", + "IsDeleted": 0, "Name": "AdminTest", "Description": "测试管理", "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -84,11 +84,11 @@ "Id": 6 }, { - "IsDeleted": "0", + "IsDeleted": 0, "Name": "AdminTest2", "Description": "测试管理2", "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": 23, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -98,11 +98,11 @@ "Id": 7 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -112,11 +112,11 @@ "Id": 8 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -126,11 +126,11 @@ "Id": 9 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -140,11 +140,11 @@ "Id": 10 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -154,11 +154,11 @@ "Id": 11 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -168,11 +168,11 @@ "Id": 12 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -182,11 +182,11 @@ "Id": 13 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -196,11 +196,11 @@ "Id": 14 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -210,11 +210,11 @@ "Id": 15 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -224,11 +224,11 @@ "Id": 16 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -238,11 +238,11 @@ "Id": 17 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -252,11 +252,11 @@ "Id": 18 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -266,11 +266,11 @@ "Id": 19 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -280,11 +280,11 @@ "Id": 20 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -294,11 +294,11 @@ "Id": 21 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -308,11 +308,11 @@ "Id": 22 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -322,11 +322,11 @@ "Id": 23 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -340,7 +340,7 @@ "Name": "sss", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -354,7 +354,7 @@ "Name": "213", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -368,7 +368,7 @@ "Name": "抬头填", "Description": null, "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": null, "CreateBy": null, "CreateTime": "\/Date(1546272000000+0800)\/", @@ -378,11 +378,11 @@ "Id": 27 }, { - "IsDeleted": "0", + "IsDeleted": 0, "Name": "hello1", "Description": "测试 常用 get post put 请求", "OrderSort": 1, - "Enabled": "1", + "Enabled": 1, "CreateId": 12, "CreateBy": "后台总管理员", "CreateTime": "\/Date(1546272000000+0800)\/", @@ -392,11 +392,11 @@ "Id": 28 }, { - "IsDeleted": "1", + "IsDeleted": 1, "Name": "55", "Description": "555", "OrderSort": 1, - "Enabled": "0", + "Enabled": 0, "CreateId": 39, "CreateBy": "Kawhi", "CreateTime": "\/Date(1546272000000+0800)\/", diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.json/RoleModulePermission.tsv b/Blog.Core.Api/wwwroot/BlogCore.Data.json/RoleModulePermission.tsv index bb624d09..5626b81f 100644 --- a/Blog.Core.Api/wwwroot/BlogCore.Data.json/RoleModulePermission.tsv +++ b/Blog.Core.Api/wwwroot/BlogCore.Data.json/RoleModulePermission.tsv @@ -1,6 +1,6 @@ [ { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 1, "ModuleId": 1, "PermissionId": null, @@ -13,7 +13,7 @@ "Id": 1 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 1, "ModuleId": 2, "PermissionId": null, @@ -26,7 +26,7 @@ "Id": 2 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 1, "ModuleId": 3, "PermissionId": null, @@ -39,7 +39,7 @@ "Id": 3 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 1, "ModuleId": 4, "PermissionId": null, @@ -52,7 +52,7 @@ "Id": 4 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 2, "ModuleId": 4, "PermissionId": null, @@ -65,7 +65,7 @@ "Id": 5 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 3, "ModuleId": 5, "PermissionId": 30, @@ -78,7 +78,7 @@ "Id": 6 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 3, "ModuleId": 6, "PermissionId": 31, @@ -91,7 +91,7 @@ "Id": 7 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 3, "ModuleId": 7, "PermissionId": 9, @@ -104,7 +104,7 @@ "Id": 8 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 3, "ModuleId": 26, "PermissionId": 28, @@ -117,7 +117,7 @@ "Id": 9 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 7, "PermissionId": 3, @@ -130,7 +130,7 @@ "Id": 10 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 7, "PermissionId": 9, @@ -143,7 +143,7 @@ "Id": 11 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 10, "PermissionId": 13, @@ -156,7 +156,7 @@ "Id": 12 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 12, "PermissionId": 14, @@ -169,7 +169,7 @@ "Id": 13 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 11, "PermissionId": 15, @@ -182,7 +182,7 @@ "Id": 14 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 2, @@ -195,7 +195,7 @@ "Id": 15 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 22, "PermissionId": 4, @@ -208,7 +208,7 @@ "Id": 16 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 22, "PermissionId": 16, @@ -221,7 +221,7 @@ "Id": 17 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 25, "PermissionId": 17, @@ -234,7 +234,7 @@ "Id": 18 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 24, "PermissionId": 18, @@ -247,7 +247,7 @@ "Id": 19 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 23, "PermissionId": 19, @@ -260,7 +260,7 @@ "Id": 20 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 1, @@ -273,7 +273,7 @@ "Id": 21 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 5, @@ -286,7 +286,7 @@ "Id": 22 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 13, "PermissionId": 6, @@ -299,7 +299,7 @@ "Id": 23 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 13, "PermissionId": 20, @@ -312,7 +312,7 @@ "Id": 24 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 16, "PermissionId": 21, @@ -325,7 +325,7 @@ "Id": 25 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 15, "PermissionId": 22, @@ -338,7 +338,7 @@ "Id": 26 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 14, "PermissionId": 23, @@ -351,7 +351,7 @@ "Id": 27 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 17, "PermissionId": 7, @@ -364,7 +364,7 @@ "Id": 28 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 17, "PermissionId": 24, @@ -377,7 +377,7 @@ "Id": 29 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 20, "PermissionId": 25, @@ -390,7 +390,7 @@ "Id": 30 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 19, "PermissionId": 26, @@ -403,7 +403,7 @@ "Id": 31 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 18, "PermissionId": 27, @@ -416,7 +416,7 @@ "Id": 32 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 8, @@ -429,7 +429,7 @@ "Id": 33 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 10, @@ -442,7 +442,7 @@ "Id": 34 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 11, @@ -455,7 +455,7 @@ "Id": 35 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 12, @@ -468,7 +468,7 @@ "Id": 36 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 26, "PermissionId": 28, @@ -481,7 +481,7 @@ "Id": 37 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 5, "PermissionId": 30, @@ -494,7 +494,7 @@ "Id": 38 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 6, "PermissionId": 31, @@ -507,7 +507,7 @@ "Id": 39 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 27, "PermissionId": 29, @@ -520,7 +520,7 @@ "Id": 40 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 26, "PermissionId": 32, @@ -533,7 +533,7 @@ "Id": 41 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 1, @@ -546,7 +546,7 @@ "Id": 42 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 8, @@ -559,7 +559,7 @@ "Id": 43 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 10, @@ -572,7 +572,7 @@ "Id": 44 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 11, @@ -585,7 +585,7 @@ "Id": 45 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 12, @@ -598,7 +598,7 @@ "Id": 46 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 27, "PermissionId": 29, @@ -611,7 +611,7 @@ "Id": 47 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 2, @@ -624,7 +624,7 @@ "Id": 48 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 7, "PermissionId": 3, @@ -637,7 +637,7 @@ "Id": 49 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 22, "PermissionId": 4, @@ -650,7 +650,7 @@ "Id": 50 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 5, @@ -663,7 +663,7 @@ "Id": 51 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 13, "PermissionId": 6, @@ -676,7 +676,7 @@ "Id": 52 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 17, "PermissionId": 7, @@ -689,7 +689,7 @@ "Id": 53 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 26, "PermissionId": 28, @@ -702,7 +702,7 @@ "Id": 54 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 28, "PermissionId": 34, @@ -715,7 +715,7 @@ "Id": 55 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 21, "PermissionId": 33, @@ -728,7 +728,7 @@ "Id": 56 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 7, "PermissionId": 9, @@ -741,7 +741,7 @@ "Id": 57 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 22, "PermissionId": 16, @@ -754,7 +754,7 @@ "Id": 58 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 13, "PermissionId": 20, @@ -767,7 +767,7 @@ "Id": 59 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 17, "PermissionId": 24, @@ -780,7 +780,7 @@ "Id": 60 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 26, "PermissionId": 32, @@ -793,7 +793,7 @@ "Id": 61 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 28, "PermissionId": 35, @@ -806,7 +806,7 @@ "Id": 62 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 21, "PermissionId": 33, @@ -819,7 +819,7 @@ "Id": 63 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 29, "PermissionId": 36, @@ -832,7 +832,7 @@ "Id": 64 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 34, @@ -845,7 +845,7 @@ "Id": 65 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 7, "ModuleId": 0, "PermissionId": 1, @@ -858,7 +858,7 @@ "Id": 66 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 7, "ModuleId": 0, "PermissionId": 2, @@ -871,7 +871,7 @@ "Id": 67 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 7, "ModuleId": 7, "PermissionId": 4, @@ -884,7 +884,7 @@ "Id": 68 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 7, "ModuleId": 0, "PermissionId": 10, @@ -897,7 +897,7 @@ "Id": 69 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 7, "ModuleId": 0, "PermissionId": 12, @@ -910,7 +910,7 @@ "Id": 70 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 7, "ModuleId": 0, "PermissionId": 8, @@ -923,7 +923,7 @@ "Id": 71 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 7, "ModuleId": 22, "PermissionId": 16, @@ -936,7 +936,7 @@ "Id": 72 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 37, @@ -949,7 +949,7 @@ "Id": 73 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 38, @@ -962,7 +962,7 @@ "Id": 74 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 39, @@ -975,7 +975,7 @@ "Id": 75 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 40, @@ -988,7 +988,7 @@ "Id": 76 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 40, @@ -1001,7 +1001,7 @@ "Id": 77 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 37, @@ -1014,7 +1014,7 @@ "Id": 78 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 38, @@ -1027,7 +1027,7 @@ "Id": 79 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 39, @@ -1040,7 +1040,7 @@ "Id": 80 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 41, @@ -1053,7 +1053,7 @@ "Id": 81 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 41, @@ -1066,7 +1066,7 @@ "Id": 82 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 42, @@ -1079,7 +1079,7 @@ "Id": 83 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 42, @@ -1092,7 +1092,7 @@ "Id": 84 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 3, "ModuleId": 0, "PermissionId": 42, @@ -1105,7 +1105,7 @@ "Id": 85 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 43, @@ -1118,7 +1118,7 @@ "Id": 86 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 43, @@ -1131,7 +1131,7 @@ "Id": 87 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 44, @@ -1144,7 +1144,7 @@ "Id": 88 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 45, @@ -1157,7 +1157,7 @@ "Id": 89 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 46, @@ -1170,7 +1170,7 @@ "Id": 90 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 47, @@ -1183,7 +1183,7 @@ "Id": 91 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 48, @@ -1196,7 +1196,7 @@ "Id": 92 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 32, "PermissionId": 64, @@ -1209,7 +1209,7 @@ "Id": 128 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 65, @@ -1222,7 +1222,7 @@ "Id": 129 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 33, "PermissionId": 66, @@ -1235,7 +1235,7 @@ "Id": 130 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 65, @@ -1248,7 +1248,7 @@ "Id": 131 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 33, "PermissionId": 66, @@ -1261,7 +1261,7 @@ "Id": 132 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 67, @@ -1274,7 +1274,7 @@ "Id": 133 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 67, @@ -1287,7 +1287,7 @@ "Id": 134 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 68, @@ -1300,7 +1300,7 @@ "Id": 135 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 0, "PermissionId": 69, @@ -1313,7 +1313,7 @@ "Id": 136 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 68, @@ -1326,7 +1326,7 @@ "Id": 137 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 0, "PermissionId": 69, @@ -1339,7 +1339,7 @@ "Id": 138 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 29, "PermissionId": 36, @@ -1352,7 +1352,7 @@ "Id": 139 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 7, "ModuleId": 29, "PermissionId": 36, @@ -1365,7 +1365,7 @@ "Id": 140 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 7, "ModuleId": 27, "PermissionId": 33, @@ -1378,7 +1378,7 @@ "Id": 141 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 36, "PermissionId": 72, @@ -1391,7 +1391,7 @@ "Id": 144 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 0, "PermissionId": 1, @@ -1404,7 +1404,7 @@ "Id": 145 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 0, "PermissionId": 2, @@ -1417,7 +1417,7 @@ "Id": 146 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 22, "PermissionId": 3, @@ -1430,7 +1430,7 @@ "Id": 147 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 7, "PermissionId": 4, @@ -1443,7 +1443,7 @@ "Id": 148 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 22, "PermissionId": 16, @@ -1456,7 +1456,7 @@ "Id": 149 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 7, "PermissionId": 9, @@ -1469,7 +1469,7 @@ "Id": 150 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 25, "PermissionId": 17, @@ -1482,7 +1482,7 @@ "Id": 151 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 10, "PermissionId": 13, @@ -1495,7 +1495,7 @@ "Id": 152 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 21, "PermissionId": 33, @@ -1508,7 +1508,7 @@ "Id": 153 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 28, "ModuleId": 29, "PermissionId": 36, @@ -1521,7 +1521,7 @@ "Id": 154 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 32, "PermissionId": 73, @@ -1534,7 +1534,7 @@ "Id": 155 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 6, "ModuleId": 32, "PermissionId": 73, @@ -1547,7 +1547,7 @@ "Id": 156 }, { - "IsDeleted": "0", + "IsDeleted": 0, "RoleId": 4, "ModuleId": 27, "PermissionId": 74, @@ -1558,5 +1558,1541 @@ "ModifyBy": null, "ModifyTime": "\/Date(1546272000000+0800)\/", "Id": 157 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyTime": "2022-03-23 19:21:58", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 114, + "Id": 121 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyTime": "2022-03-23 19:21:58", + "RoleId": 4, + "ModuleId": 66, + "PermissionId": 115, + "Id": 122 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyTime": "2022-03-23 19:21:58", + "RoleId": 4, + "ModuleId": 66, + "PermissionId": 116, + "Id": 123 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyTime": "2022-03-23 19:21:58", + "RoleId": 4, + "ModuleId": 69, + "PermissionId": 117, + "Id": 124 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyTime": "2022-03-23 19:21:58", + "RoleId": 4, + "ModuleId": 68, + "PermissionId": 118, + "Id": 125 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyTime": "2022-03-23 19:21:58", + "RoleId": 4, + "ModuleId": 67, + "PermissionId": 119, + "Id": 126 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyTime": "2022-03-23 19:21:58", + "RoleId": 4, + "ModuleId": 70, + "PermissionId": 120, + "Id": 127 + }, + { + "IsDeleted": 0, + "RoleId": 4, + "ModuleId": 71, + "PermissionId": 121, + "CreateId": null, + "CreateBy": null, + "CreateTime": "\/Date(1546272000000+0800)\/", + "ModifyId": null, + "ModifyBy": null, + "ModifyTime": "\/Date(1546272000000+0800)\/", + "Id": 228 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-04-11 16:08:48", + "ModifyTime": "2022-04-11 00:00:00", + "RoleId": 6, + "ModuleId": 0, + "PermissionId": 114, + "Id": 229 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-04-11 16:08:48", + "ModifyTime": "2022-04-11 00:00:00", + "RoleId": 6, + "ModuleId": 66, + "PermissionId": 115, + "Id": 230 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-04-11 16:08:49", + "ModifyTime": "2022-04-11 00:00:00", + "RoleId": 6, + "ModuleId": 70, + "PermissionId": 120, + "Id": 231 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-04-11 16:08:49", + "ModifyTime": "2022-04-11 00:00:00", + "RoleId": 6, + "ModuleId": 66, + "PermissionId": 116, + "Id": 232 + }, + { + "IsDeleted": false, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-04-11 16:08:49", + "ModifyTime": "2022-04-11 00:00:00", + "RoleId": 4, + "ModuleId": 72, + "PermissionId": 122, + "Id": 233 + }, + { + "Id": 1658115520798527489, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 1 + }, + { + "Id": 1658115520798527490, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 114 + }, + { + "Id": 1658115520798527491, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 66, + "PermissionId": 115 + }, + { + "Id": 1658115520798527492, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 2 + }, + { + "Id": 1658115520798527493, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 22, + "PermissionId": 3 + }, + { + "Id": 1658115520798527494, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 7, + "PermissionId": 4 + }, + { + "Id": 1658115520798527495, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 5 + }, + { + "Id": 1658115520798527496, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 13, + "PermissionId": 6 + }, + { + "Id": 1658115520798527497, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 17, + "PermissionId": 7 + }, + { + "Id": 1658115520798527498, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 34 + }, + { + "Id": 1658115520798527499, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 10 + }, + { + "Id": 1658115520798527500, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 11 + }, + { + "Id": 1658115520798527501, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 12 + }, + { + "Id": 1658115520798527502, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 29 + }, + { + "Id": 1658115520798527503, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 27, + "PermissionId": 43 + }, + { + "Id": 1658115520798527504, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 67 + }, + { + "Id": 1658115520798527505, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 37 + }, + { + "Id": 1658115520798527506, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 38 + }, + { + "Id": 1658115520798527507, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 39 + }, + { + "Id": 1658115520798527508, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 41 + }, + { + "Id": 1658115520798527509, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 40 + }, + { + "Id": 1658115520798527510, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 42 + }, + { + "Id": 1658115520798527511, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 26, + "PermissionId": 28 + }, + { + "Id": 1658115520798527512, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 44 + }, + { + "Id": 1658115520798527513, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 45 + }, + { + "Id": 1658115520798527514, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 46 + }, + { + "Id": 1658115520798527515, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 47 + }, + { + "Id": 1658115520798527516, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 48 + }, + { + "Id": 1658115520798527517, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 49 + }, + { + "Id": 1658115520798527518, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 65 + }, + { + "Id": 1658115520798527519, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 33, + "PermissionId": 66 + }, + { + "Id": 1658115520798527520, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 68 + }, + { + "Id": 1658115520798527521, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 69 + }, + { + "Id": 1658115520798527522, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 8 + }, + { + "Id": 1658115520798527523, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 75 + }, + { + "Id": 1658115520798527524, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 37, + "PermissionId": 76 + }, + { + "Id": 1658115520798527525, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 87 + }, + { + "Id": 1658115520798527526, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 88 + }, + { + "Id": 1658115520798527527, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 89 + }, + { + "Id": 1658115520798527528, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 90 + }, + { + "Id": 1658115520798527529, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 91 + }, + { + "Id": 1658115520798527530, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 95 + }, + { + "Id": 1658115520798527531, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 93 + }, + { + "Id": 1658115520798527532, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 94 + }, + { + "Id": 1658115520798527533, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 0, + "PermissionId": 92 + }, + { + "Id": 1658115520798527534, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 7, + "PermissionId": 9 + }, + { + "Id": 1658115520798527535, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 10, + "PermissionId": 13 + }, + { + "Id": 1658115520798527536, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 12, + "PermissionId": 14 + }, + { + "Id": 1658115520798527537, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 11, + "PermissionId": 15 + }, + { + "Id": 1658115520798527538, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 22, + "PermissionId": 16 + }, + { + "Id": 1658115520798527539, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 25, + "PermissionId": 17 + }, + { + "Id": 1658115520798527540, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 24, + "PermissionId": 18 + }, + { + "Id": 1658115520798527541, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 23, + "PermissionId": 19 + }, + { + "Id": 1658115520798527542, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 13, + "PermissionId": 20 + }, + { + "Id": 1658115520798527543, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 16, + "PermissionId": 21 + }, + { + "Id": 1658115520798527544, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 15, + "PermissionId": 22 + }, + { + "Id": 1658115520798527545, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 14, + "PermissionId": 23 + }, + { + "Id": 1658115520798527546, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 17, + "PermissionId": 24 + }, + { + "Id": 1658115520798527547, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 20, + "PermissionId": 25 + }, + { + "Id": 1658115520798527548, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 19, + "PermissionId": 26 + }, + { + "Id": 1658115520798527549, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 18, + "PermissionId": 27 + }, + { + "Id": 1658115520798527550, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 5, + "PermissionId": 30 + }, + { + "Id": 1658115520798527551, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 6, + "PermissionId": 31 + }, + { + "Id": 1658115520798527552, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 26, + "PermissionId": 32 + }, + { + "Id": 1658115520798527553, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 21, + "PermissionId": 33 + }, + { + "Id": 1658115520798527554, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 28, + "PermissionId": 35 + }, + { + "Id": 1658115520798527555, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 29, + "PermissionId": 36 + }, + { + "Id": 1658115520798527556, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 66, + "PermissionId": 116 + }, + { + "Id": 1658115520798527557, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 69, + "PermissionId": 117 + }, + { + "Id": 1658115520798527558, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 68, + "PermissionId": 118 + }, + { + "Id": 1658115520798527559, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 67, + "PermissionId": 119 + }, + { + "Id": 1658115520798527560, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-03-23 19:21:58", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 70, + "PermissionId": 120 + }, + { + "Id": 1658115520798527561, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 32, + "PermissionId": 64 + }, + { + "Id": 1658115520798527562, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 36, + "PermissionId": 72 + }, + { + "Id": 1658115520798527563, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 27, + "PermissionId": 73 + }, + { + "Id": 1658115520798527564, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 27, + "PermissionId": 74 + }, + { + "Id": 1658115520798527565, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2019-01-01 00:00:00", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 71, + "PermissionId": 121 + }, + { + "Id": 1658115520798527566, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2022-04-11 16:08:49", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 72, + "PermissionId": 122 + }, + { + "Id": 1658115520798527567, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 37, + "PermissionId": 77 + }, + { + "Id": 1658115520798527568, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 38, + "PermissionId": 78 + }, + { + "Id": 1658115520798527569, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 39, + "PermissionId": 79 + }, + { + "Id": 1658115520798527570, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 40, + "PermissionId": 80 + }, + { + "Id": 1658115520798527571, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 41, + "PermissionId": 81 + }, + { + "Id": 1658115520798527572, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 42, + "PermissionId": 82 + }, + { + "Id": 1658115520798527573, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 43, + "PermissionId": 83 + }, + { + "Id": 1658115520798527574, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 44, + "PermissionId": 84 + }, + { + "Id": 1658115520798527575, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 45, + "PermissionId": 85 + }, + { + "Id": 1658115520798527576, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 46, + "PermissionId": 86 + }, + { + "Id": 1658115520798527577, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 73, + "PermissionId": 123 + }, + { + "Id": 1658115520798527578, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 74, + "PermissionId": 124 + }, + { + "Id": 1658115520798527579, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 55, + "PermissionId": 108 + }, + { + "Id": 1658115520798527580, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 61, + "PermissionId": 109 + }, + { + "Id": 1658115520798527581, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 50, + "PermissionId": 103 + }, + { + "Id": 1658115520798527582, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 49, + "PermissionId": 104 + }, + { + "Id": 1658115520798527583, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 48, + "PermissionId": 105 + }, + { + "Id": 1658115520798527584, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 51, + "PermissionId": 106 + }, + { + "Id": 1658115520798527585, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 52, + "PermissionId": 107 + }, + { + "Id": 1658115520798527586, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 54, + "PermissionId": 96 + }, + { + "Id": 1658115520798527587, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 64, + "PermissionId": 98 + }, + { + "Id": 1658115520798527588, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 59, + "PermissionId": 99 + }, + { + "Id": 1658115520798527589, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 58, + "PermissionId": 100 + }, + { + "Id": 1658115520798527590, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 53, + "PermissionId": 101 + }, + { + "Id": 1658115520798527591, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 60, + "PermissionId": 102 + }, + { + "Id": 1658115520798527592, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 57, + "PermissionId": 110 + }, + { + "Id": 1658115520798527593, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 56, + "PermissionId": 112 + }, + { + "Id": 1658115520798527594, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 62, + "PermissionId": 111 + }, + { + "Id": 1658115520798527595, + "IsDeleted": 0, + "CreateId": 12, + "CreateBy": "blogadmin", + "CreateTime": "2023-05-15 14:20:12", + "ModifyId": 12, + "ModifyBy": "blogadmin", + "ModifyTime": "2023-05-15 14:20:12", + "RoleId": 4, + "ModuleId": 63, + "PermissionId": 113 } ] diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.json/TasksQz.tsv b/Blog.Core.Api/wwwroot/BlogCore.Data.json/TasksQz.tsv index cc043fe8..5aaef106 100644 --- a/Blog.Core.Api/wwwroot/BlogCore.Data.json/TasksQz.tsv +++ b/Blog.Core.Api/wwwroot/BlogCore.Data.json/TasksQz.tsv @@ -2,17 +2,18 @@ { "Name": "博客管理", "JobGroup": "博客测试组", - "TriggerType": 1, + "TriggerType": 1, "Cron": "0 */1 * * * ?", "AssemblyName": "Blog.Core.Tasks", "ClassName": "Job_Blogs_Quartz", "Remark": "", "RunTimes": 0, "BeginTime": "\/Date(1546272000000+0800)\/", - "EndTime": "\/Date(1640966400000+0800)\/", + "EndTime": "\/Date(8888888800000+0800)\/", "IntervalSecond": 0, + "CycleRunTimes": 0, "IsStart": true, - "JobParams": "1", + "JobParams": 1, "IsDeleted": false, "CreateTime": "\/Date(1546272000000+0800)\/", "Id": 1 diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.json/Topic.tsv b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Topic.tsv index 56272e84..8da69479 100644 --- a/Blog.Core.Api/wwwroot/BlogCore.Data.json/Topic.tsv +++ b/Blog.Core.Api/wwwroot/BlogCore.Data.json/Topic.tsv @@ -5,180 +5,12 @@ "tDetail": "这是一个荡气回肠的故事", "tAuthor": "Laozhang", "tSectendDetail": null, - "tIsDelete": "0", + "tIsDelete": 0, "tRead": 0, "tCommend": 0, "tGood": 0, "tCreatetime": "\/Date(1546272000000+0800)\/", "tUpdatetime": "\/Date(1546272000000+0800)\/", "Id": 1 - }, - { - "tLogo": "\/Upload\/20180626\/0f2ba547089f49cea1e5813890de2f68.jpg", - "tName": "《红楼梦概要》", - "tDetail": "开谈不读红楼梦,读尽诗书也枉然", - "tAuthor": "老张", - "tSectendDetail": null, - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 2 - }, - { - "tLogo": "\/Upload\/20180709\/4f6ae5435c6648afac5777adcb6d5ab6.png", - "tName": "《运营工作知多少》", - "tDetail": "简单了解相关知识", - "tAuthor": "老张", - "tSectendDetail": null, - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 3 - }, - { - "tLogo": null, - "tName": "学英语要经常看这里哦", - "tDetail": "英语网站、视频、资源汇总", - "tAuthor": "laoli", - "tSectendDetail": null, - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 4 - }, - { - "tLogo": "\/Upload\/20180713\/ad78ea105cd84182b475a10f5d373a4b.png", - "tName": "《面试准备题》", - "tDetail": "为了不知道啥时候的面试", - "tAuthor": "老张", - "tSectendDetail": null, - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 5 - }, - { - "tLogo": "\/Upload\/20180717\/41ebf597c0fc439c8bcac373f4130fa1.png", - "tName": "百无聊赖是书生——书读百篇", - "tDetail": "书读百篇", - "tAuthor": "老张", - "tSectendDetail": null, - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 6 - }, - { - "tLogo": "\/Upload\/20180802\/74e05e0894f646a6ae334fa725f735b6.jpg", - "tName": "偶尔看演出", - "tDetail": "音乐会、戏剧、舞蹈...", - "tAuthor": "laoli", - "tSectendDetail": null, - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 7 - }, - { - "tLogo": null, - "tName": ".NetCore", - "tDetail": null, - "tAuthor": "老张", - "tSectendDetail": "tbug", - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 8 - }, - { - "tLogo": null, - "tName": "VUE", - "tDetail": null, - "tAuthor": "老张", - "tSectendDetail": "tbug", - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 9 - }, - { - "tLogo": null, - "tName": "DDD", - "tDetail": null, - "tAuthor": "老张", - "tSectendDetail": "tbug", - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 10 - }, - { - "tLogo": null, - "tName": "SqlSugar", - "tDetail": null, - "tAuthor": "老张", - "tSectendDetail": "tbug", - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 11 - }, - { - "tLogo": null, - "tName": "Nuxt", - "tDetail": null, - "tAuthor": "老张", - "tSectendDetail": "tbug", - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 12 - }, - { - "tLogo": null, - "tName": "关于我", - "tDetail": null, - "tAuthor": "老张", - "tSectendDetail": "tbug", - "tIsDelete": "0", - "tRead": 0, - "tCommend": 0, - "tGood": 0, - "tCreatetime": "\/Date(1546272000000+0800)\/", - "tUpdatetime": "\/Date(1546272000000+0800)\/", - "Id": 13 } ] diff --git a/Blog.Core.Api/wwwroot/BlogCore.Data.json/TopicDetail.tsv b/Blog.Core.Api/wwwroot/BlogCore.Data.json/TopicDetail.tsv index 1af2c588..ff5f8d68 100644 --- a/Blog.Core.Api/wwwroot/BlogCore.Data.json/TopicDetail.tsv +++ b/Blog.Core.Api/wwwroot/BlogCore.Data.json/TopicDetail.tsv @@ -3,10 +3,10 @@ "TopicId": 1, "tdLogo": null, "tdName": "第一章 罗马的诞生 第一节 传说的年代", - "tdContent": "

第一节 传说的年代<\/p>

每个民族都有自己的神话传说。大概希望知道本民族的来源是个很自然的愿望吧。但这是一个难题,因为这几乎不可能用科学的方法来解释清楚。不过所有的民族都没有这样的奢求。他们只要有一个具有一定的条理性,而又能振奋其民族精神的浪漫故事就行,别抬杠,象柏杨那样将中国的三皇五帝都来个科学分析,来评论他们的执政之优劣是大可不必的。<\/p>

对於罗马人,他们有一个和特洛伊城的陷落相关的传说。<\/p>

位於小亚细亚西岸的繁荣的城市特洛伊,在遭受了阿加美农统帅的希腊联军的十年围攻之後,仍未陷落。希腊联军於是留下一个巨大的木马後假装撤兵。特洛伊人以为那是希腊联军留给自己的礼物,就将它拉入城内。<\/p>

当庆祝胜利的狂欢结束,特洛伊人满怀对明日的和平生活的希望熟睡後,藏在木马内的希腊士兵一个又一个地爬了出来。就在这天夜里,特洛伊城便在火光和叫喊中陷落了。全城遭到大屠杀 ,幸免於死的人全都沦为奴隶。混乱之中只有特洛伊国王的驸马阿伊尼阿斯带着老父,儿子等数人在女神维娜斯的帮助下成功地逃了出来。这驸马爷乃是女神维娜斯与凡人男子之间的儿子,女神维娜斯不忍心看着自己的儿子被希腊士兵屠杀 。<\/p>

这阿驸马一行人分乘几条船,离开了火光冲天的特洛伊城。在女神维娜斯的指引下,浪迹地中海,最後在意大利西岸登陆。当地的国王看上了阿伊尼阿斯并把自己的女儿嫁给了他。他又是驸马了,与他的新妻过起了幸福的生活。难民们也安定了下来。<\/p>

阿伊尼阿斯死後,跟随他逃难来的儿子继承了王位。新王在位三十年後,离开了这块地方,到台伯河(Tiber)下游建了一个新城亚尔巴龙迦城。这便是罗马城的前身了。<\/p>

罗马人自古相信罗马城是公元前731年4月21日由罗莫路和勒莫(Romulus and Remus)建设的。而这两个孪生兄弟是从特洛伊逃出的阿伊尼阿斯的子孙。後来,罗马人接触了希腊文化後才知道特洛伊的陷落是在公元前十三世纪,老早的事了。罗马人好象并没有对这段空白有任何烦恼,随手编出一串传说,把那空白给填补了。反正传说这事荒唐一点的更受欢迎。经过了一堆搞不清谁是谁的王的统治,出现了一个什麽王的公主。<\/p>

公主的叔父在篡夺了王位後,为了防止公主结婚生子威胁自己的王位,便任命未婚的公主为巫女。这是主管祭神的职位,象修女一样不得结婚。<\/p>

不巧一日这美丽的公主在祭事的空余,来到小河边午睡。也是合当有事,被过往的战神玛尔斯(Mars)一见钟情。这玛尔斯本是靠挑起战争混饭吃的,但也常勾引 良家妇女。这天战神也没错过机会,立刻由天而降,与公主一试云雨。据说战神的技术特神,公主还没来得及醒便完事升天去了。後来公主生了一双胞胎,起名罗莫路和勒莫。<\/p>

叔父闻知此事大怒,将公主投入大牢,又把那双胞胎放在篮子里抛入台伯河,指望那篮子漂入大海将那双胞胎淹死。类似的故事在旧约圣经里也有,那是关於摩西的事,好象这类传说在当地十分流行。<\/p>

再说那兄弟俩的篮子被河口附近茂密的灌木丛钩住而停了下来,俩人哭声引来的一只过路的母狼。意大利的狼都带点慈悲心,不但没吃了俩人当点心,还用自己的奶去喂他们,这才救了俩小命。<\/p>

不过,总是由狼养活也没法交 待,於是又一日一放羊的在这地盘上溜哒,发现了兄弟俩,将他们抱了回去扶养成人 。据说现在这一带仍有许多放羊的。<\/p>

兄弟俩长大後成了这一带放羊人的头,在与别的放羊人的圈子的打斗中不断地扩展自己的势力范围。圈子大了,情报也就多了,终于有一天,罗莫路和勒莫知道了自己身事。<\/p>

兄弟俩就带着手下的放羊人呼啸着去打破了亚尔巴龙迦城,杀了那国王,将王位又交 还给了自己祖父。他们的母亲似乎已经死在了大牢里。但兄弟俩也没在亚尔巴龙迦城多住,他们认为亚尔巴龙迦城位於山地,虽然易守难攻,却不利发展。加上兄弟俩是在台伯河的下游长大的,所以便回到原地,建了个新城。除了手下的放羊人又加上了附近的放羊人和农民。<\/p>

消灭了共同的敌人後,兄弟俩的关系开始恶化。有人说是为了新城的命名,有人说是为了新城的城址,也有人说是为了争夺王位。兄弟俩於是分割统治,各占一小山包。但纷争又开始了,勒莫跳过了罗莫路为表示势力范围而挖的沟。对於这种侵犯他人权力的行为,罗莫路大义灭亲地在自己兄弟的後脑上重重地来了一锄头,勒莫便被灭了。<\/p>

<\/p>

於是这城便以罗莫路的名字命名为罗马,这就是公元前731年4月21日的事了,到现在这天仍是意大利的节日,罗马人会欢天喜地的庆祝罗莫路杀了自己的…不,是庆祝罗马建城。王位当然也得由罗莫路来坐,一切问题都没了。这时四年一度的奥林匹克运动会在希腊已经开了六回,罗马也从传说的时代走出,近入了历史时代。<\/p>


<\/p>", + "tdContent": "

第一节 传说的年代<\/p>

每个民族都有自己的神话传说。大概希望知道本民族的来源是个很自然的愿望吧。但这是一个难题,因为这几乎不可能用科学的方法来解释清楚。", "tdDetail": "标题", "tdSectendDetail": null, - "tdIsDelete": "0", + "tdIsDelete": 0, "tdRead": 8, "tdCommend": 0, "tdGood": 0, @@ -15,1161 +15,5 @@ "tdTop": 0, "tdAuthor": null, "Id": 1 - }, - { - "TopicId": 2, - "tdLogo": "\/Upload\/20180627\/7548de20944c45d48a055111b5a6c1b9.jpg", - "tdName": "金陵十二钗主人公判词,命运之说 ", - "tdContent": "

\"\"
<\/b><\/p>

1\/2. 正册之首 · 钗黛<\/b><\/h3>

《判词》<\/b><\/p>\r\n

画:两株枯木,木上悬着一围玉带;又有一堆雪,雪下一股金簪。<\/i><\/p>\r\n

判词:可叹停机德,堪怜咏絮才!玉带林中挂,金簪雪里埋。<\/i><\/p>\r\n

解析:<\/p>\r\n

     林黛玉与薛宝钗,一个是寄人篱下的孤女,一个是皇家大商人的千金;一个天真率直,一个城府极深;一个孤立无援,一个有多方支持;一个作判逆者知己,一个为卫道而说教。脂砚斋曾有过“钗黛合一”说,确切的解说如何,可以研究;但无疑不是否定林薛二人的差别或对立。作者将她俩在一首诗中并提,除了因为她们在小说中的地位相当外,至少还可以通过贾宝玉对她们的不同的态度的比较,以显示钗黛的命运遭遇虽则不同,其结果却都是一场悲剧。<\/p><\/blockquote>

《结局》<\/b><\/p>

\"\"
<\/b><\/p>

林黛玉,<\/b>前世为三生石边的一株绛珠草,受神瑛侍者的甘露之惠,愿跟其下凡还尽眼泪。今世为巡盐御史林如海与贾府千金贾林敏的独生女,少时其母因病辞世,外祖母怜其孤独,接来荣国府抚养。<\/span>她生性孤傲,多愁善感,才思敏捷。和神瑛侍者的转世贾宝玉真心相爱,有共同的价值观、爱情观,但这一段爱情因悲剧性的家族命运而遭到扼杀。<\/span><\/p>

\"\"
<\/span><\/p>

薛宝钗,<\/b>小说《红楼梦》中人物,与林黛玉同为金陵十二钗之冠,薛姨妈之女,贾宝玉的姨表姐,被誉为“群芳之冠”。<\/p>

她挂有一把錾有“不离不弃,芳龄永继”的金锁,与贾宝玉随身所载之玉上所刻之“莫失莫忘,仙寿恒昌”恰好是一对,寓意金玉良缘。<\/p>

后来贾宝玉与薛宝钗成婚,婚后不久,宝玉对黛玉念念不忘,最终出家。薛宝钗独守空闺,孤独地死去。<\/strong><\/p>


<\/p>\r\n

3. 正册之三<\/b> · 贾<\/b>元春<\/b><\/p>

《判词》<\/b><\/p>\r\n

画: 一张弓,弓上挂着香橼。<\/i><\/p>\r\n

判词:二十年来辨是非,榴花开处照宫闱;三春争及初春景,虎兔相逢大梦归。<\/i><\/p>

【恨无常】喜荣华正好,恨无常又到.眼睁睁,把万事抛.荡悠悠,把芳魂消耗.望家乡,路远山高.故向爹娘梦里相寻告:儿命已入黄泉,天伦啊,须要退步抽身早!<\/pre>\r\n

解析:<\/p>\r\n

     贾府在四大家族中居于首位,是因为它财富最多,权势最大,而这又因为它有确保这种显贵地位的大靠山---贾元春。世代勋臣的贾府,因为她而又成了皇亲国戚。所以,小说的前半部就围绕着元春“才选凤藻宫”、“加封贤德妃”和“省亲”等情节,竭力铺写贾府“烈火烹油,鲜花着锦之盛”。但是,“豪华虽足羡,离别却难堪。博得虚名在,谁人识苦甘?”试看元春回家省亲在私室与亲人相聚的一幕,在“荣华”的背后,便可见骨肉生离的惨状。元春说一句,哭一句,把皇宫大内说成是“终无意趣”的“不得见人的去处”,完全象从一个幽闭囚禁她的地方出来一样。曹雪芹有力的笔触,揭出了封建阶级所钦羡的荣华,对贾元春这样的贵族女子来说,也还是深渊,她不得不为些付出丧失自由的代价。<\/p><\/blockquote>\r\n

     但是,这一切还不是后来情节发展的铺垫。省亲之后,元春回宫似乎是生离,其实已是死别;她丧失的不只是自由,还有她的生命。因而,写元春显贵所带来的贾府盛况,也是为了预示后来她的死是庇护着贾府大树的摧倒,为贾府事败、抄没后的凄惨景况作了反衬。脂批点出元妃之死也与贾家之败、黛玉之死一样,“乃通部书之大过节、大关键”。不过,在现存的后四十回续书中,这种成为“大过节,大关键”的转折作用,并没有加以表现。相反的,续书倒通过元春之死称功颂德一番,说什么因为“圣眷隆重身体发福”才“多痰”致疾,仿佛她的死也足以显示皇恩浩荡似的。<\/p><\/blockquote>\r\n

    《红楼梦》人物中,短命的都有令人信服的原因,唯独元春青春早卒的原因不明不白。这本身就足以引人深思。作者究竟怎样写的,从“虎兔相逢”四个字是无法推断的。《恨无常》中有些话也很蹊跷,如说元春“荡悠悠,芳魂消耗”,“望家乡,路远山高”。倘元春后来死于宫中,对筑于“帝城西”的贾府并不算远,“路远山高”、“相寻告”云云,都是很难解通的。这现在也只能成为悬案。不过,有一点,曲子中写得比较明确,即写元春以托梦的形式向爹娘哭诉说“儿命已入黄泉,天伦呵,须要退步抽身早!”这岂不是明明白白地要亲人以她自己的含恨而死作为前车之鉴,赶快从官场脱身,避开即将临头的灾祸吗?由此可知,元春之死,不仅标志着四大家族所代表的那一派在政治上的失势,敲响了贾家败亡的丧钟,而且她自己也完全是封建统治阶级宫闱内部互相倾轧的牺牲品。这样,声称“毫不干涉时世”的曹雪芹,就大胆地揭开了政治帏幕的一角,让人们从一个封建家庭的盛衰遭遇,看到了它背后封建统治集团内部各派势力之间不择手段地争权夺利的肮脏勾当。贾探春所说的“恨不得你吃了我,我吃你”的话深长含义,也不妨从这方面去理解。<\/p><\/blockquote>

《结局》<\/b><\/p>

即贾妃,贾元春是贾政的长女,生于正月初一故名为元春,因“贤孝才德”选入宫中,起初掌管王后的礼职,充任女史。不久封为凤藻宫尚书,加封贤德妃。后来,蒙天子降谕特准鸾舆入其私第。元春后因为政治斗争被陷害,死于皇宫之内,她的死也是荣国府从盛转衰的一个转折点。<\/strong><\/p>


<\/p>\r\n

4. 正册之四<\/b> · 贾<\/b>迎春<\/b><\/p>

《判词》<\/b><\/p>\r\n

画:一恶狼,追扑一美女----欲啖之意。<\/i><\/p>\r\n

判词:子系中山狼,得志便猖狂。金闺花柳质,一载赴黄梁。<\/i><\/p>

【喜冤家】]中山狼,无情兽,全不念当日根由.一味的骄奢淫荡贪欢遘.觑着那,侯门艳质同蒲柳;作践的,公府千金似下流.叹芳魂艳魄,一载荡悠悠. <\/pre>\r\n

解析:<\/p>\r\n

     贾府的二小姐迎春和同为庶出却精明能干的探春相反,老实无能,懦弱怕事,所以有“二木头”的浑名。她不但做诗猜谜不如姊妹们,在处世为人上,也只知道让,任人欺侮,对周围发生的矛盾纠纷,采取一概不闻不问的态度。她的攒珠累丝金凤首饰被人拿去赌钱,她不追究;别人设法要替她追回,她说“宁可没有了,又何必生事”;事情闹起来了,她不管,却拿一本《太上感应篇》自己去看。抄检大观园,司棋被逐。迎春虽然感到“数年之情难舍”,掉了眼泪,但司棋求她去说情,她却“连一句话也没有”。如此怯懦之人,最后终不免悲惨的结局,这在当时的社会环境里,实在是有其必然性的。<\/p><\/blockquote>\r\n

     看起来,迎春象是被“中山狼,无情兽”吃掉的,其实,吞噬她的是整个封建宗法制度。她从小死了娘,她父亲贾赦和邢夫人对她毫不怜惜,贾赦欠了孙家五千两银子,将她嫁给孙家,实际上等于拿她抵债。当初,虽有人劝阻这门亲事,但“大老爷执意不听”,谁也没有办法,因为儿女的婚事决定于父母。后来,迎春回贾府哭诉她在孙家所受到的虐待,尽管大家十分伤感,也无可奈何,因为嫁出去的女儿已属夫家的人了,所以只好忍心把她再送回狼窝里去。<\/p><\/blockquote>\r\n

     在大观园女儿国中,迎春是成为封建包办婚姻的牺牲品的一个典型代表。作者通过她的不幸结局,揭露和控诉了这种婚姻制度的罪恶,这是谁也无法否认的客观事实。可是,有些人偏偏要把这个反对封建婚姻制度的功劳记在程伟元、高鄂续书的帐上,认为续书也有比曹雪原著价值更高的地方,即所谓“有更深一层的反封建意义---暴露封建社会婚姻不自由”,因而“在读者中发生更巨大的反封建的作用”。甚至还认为,“婚姻不自由。在《红楼梦》中,它牵动全书的线索”。这无非是说,续书把宝黛悲剧烈军属成因婚姻不自由而产生的悲剧是提高了原著的思想性。我们的看法恰恰相反。所谓“更深一层的反封建意义”,如上所述,原著本来就有的。《红楼梦》虽暴露封建婚姻罪恶,但决不是一部以反对婚姻不自由为主题或主线的书。把这一点作为“牵动全线索”,自然就改变了这部书政治性很强的小说的广泛揭露封建社会种种黑暗的主题,改变了小说表现四大家族在封建统治阶级内部政治斗争中趋向没落的主线,把基本矛盾局限在一个家庭的小范围之内,把读者的视线引到男女恋爱婚姻问题上去,真的就是儿女之情了。这实在是续书作者对原著精神的歪曲。<\/p><\/blockquote>

《结局》<\/b><\/p>

贾赦与妾所生,排行为贾府二小姐。她老实无能,懦弱怕事,有“二木头”的诨名。<\/p>

她不但作诗猜谜不如姐妹们,在处世为人上,也只知退让,任人欺侮。她的攒珠垒丝金凤首饰被下人拿去赌钱,她不追究,别人设法要替她追回,她却说∶“宁可没有了,又何必生气。”她父亲贾赦欠了孙家五千两银子还不出,就把她嫁给孙家,实际上是拿她抵债。<\/span>出嫁后不久,她就被孙绍祖虐待而死。<\/strong><\/p>


<\/p>\r\n

5. 正册之五<\/b> · 贾<\/b>探春<\/b><\/p>

《判词》<\/b><\/p>\r\n

画:两人放风筝,一片大海,一只大船,船中有一女子,掩面泣涕之状。<\/i><\/p>\r\n

判词:才自精明志自高,生于末世运偏消。清明涕送江边望,千里东风一梦遥。<\/i><\/p>

【分骨肉】一帆风雨路三千,把骨肉家园齐来抛闪.恐哭损残年,告爹娘,休把儿悬念.自古穷通皆有定,离合岂无缘?从今分两地,各自保平安.奴去也,莫牵连. <\/pre>\r\n

解析:<\/p>\r\n

     贾府的三小姐探春,浑名“玫瑰花”,她在思想上性格上与同是庶出的姊妹“二木头”迎春形成了鲜明的对照。她精明能干,有心机,能决断,连凤姐和王夫人都畏她几分,让她几分。在她的意识中,区分主仆尊卑的封建等级观念特别深固。她之所以对生母赵姨娘如此轻蔑厌恶,冷酷无情,重要的原因,是一个处于婢妾地位的人,竟敢逾越这个界线,冒犯她作为主子的尊严。抄检大观园,在探春看来,“引出这等丑态”比什么都严重。她“命丫头秉烛开门而待”,只许别人搜自己的箱柜,不许动一下她丫头的东西,并且说到做到,绝对无回旋的余地。这也是为了在婢仆前竭力维护作主子的威信与尊严。“心内没有成算的”王善保家的,不懂这一点,动手动脚,所以当场挨了一巴掌。探春对贾府面临大厦将倾的危局颇有感触,她想用“兴利除弊”的微小改革来挽回这个封建大家庭的颓势。但这只能是心劳日拙,无济于事。<\/p><\/blockquote>\r\n

     对于探春这样的人,作者是有阶级偏爱和阶级同情的。但是,作者没有违反历史和人物的客观真实性,仍然十分深刻地描绘了这个形象,如实地写出了她“生于末世运偏消”的必然结局。原稿中写探春后来远嫁的情节,与续书所写不同。“三春去后诸芳尽”。迎春出嫁,八十回前已写到;元春之死、探春之嫁,从她们的曲文和有关脂批看,也都在贾府事败之前,可能八十回后很快就会写到。这样,八十回后必然是一波未平,一波又起,情节发展相当紧张急遽,决不会像续作者写“四美钓游鱼”那样松散、无聊。<\/p><\/blockquote>

《结局》<\/b><\/p>

贾政与赵姨娘所生,贾府三小姐。她精明能干,有“玫瑰花”之诨名。<\/p>

探春对贾府面临的大厦将倾的危局颇有感触,她想用“兴利除弊”的改革来挽救,改革成功,但无济大事。最后<\/span>贾探春远嫁他乡<\/strong>,最终印证着“三春去后诸芳尽,各自须寻各自门”的悲惨结局。<\/span><\/p>\r\n


<\/p>

6. 正册之六<\/b> · 贾<\/b>惜春<\/u><\/b><\/p>\r\n

画:一所古庙,里面有一美人,在内看经独坐。<\/i><\/p>\r\n

判词:勘破三春景不长,缁衣顿改昔年妆。可怜绣户侯门女,独卧青灯古佛旁。<\/span><\/i><\/p>

【虚花悟】将那三春看破,桃红柳绿待如何?把这韶华打灭,觅那清淡天和.说什么,天上夭桃盛,云中杏蕊多;到头来,谁把秋捱过?则看那,白杨村里人呜咽,青枫树下鬼吟哦.更兼着,连天衰草遮坟墓.这的是,昨贫今富人劳碌,春荣秋谢花折磨.似这般,生关死劫谁能躲?闻说道,西方宝树唤婆娑,上结着长生果. <\/pre>\r\n

解析:<\/p>\r\n

     贾惜春“勘破三春”,披缁为尼,这并不表明她在大观园的姊妹中,见识最高,最能悟彻人生的真谛。恰恰相反,作者在小说中,非常深刻地对惜春作了解剖,让我们看到她所以选择这条生活道路的主客观原因。客观上,她在贾氏四姊妹中年龄最小,当她逐渐懂事的时候,周围所接触到的多是贾府已衰败的景象。四大家族的没落命运,三个姐姐的不幸结局,使她为自己的未来担忧,现实的一切既对她失去了吸引力,她便产生了弃世的念头。主观上,则是由环境塑造成的她那种毫不关心他人的孤僻冷漠性格,这是典型的利己主义世界观的表现。人家说她是“心冷嘴冷”的人,她自己的处世哲学是“我只能保住自己就够了”。抄检大观园时,她咬定牙,撵走毫无过错的丫环入画,而对别人的流泪哀伤无动于衷,就是她麻木不仁的典型性格的表现。所以,当贾府一败涂地的时候,入庵为尼便是她逃避统治阶级内部倾轧,保全自己的必然道路。对于皈依宗教的人物的精神面貌,作如此现实的描绘,而绝不在她们头上添加神秘的灵光圈,这实际上已成了对宗教的批判,因为,曹雪芹用他的艺术手腕“摘去了装饰在锁链上的那些虚幻的花朵”。同样,曹雪芹也没有按照佛家理论,把惜春的皈依佛门,看作是登上了普济众生的慈航仙舟,从此能获得光明和解脱,而是按照现实与生活的逻辑来描写她的归宿的。“可怜绣户侯门女,独卧青灯古佛旁!”在原稿中,她所过的“缁衣乞食”的生活,境况也要比续书所写的悲惨得多。<\/p><\/blockquote>

《结局》<\/b><\/p>

贾珍的妹妹,自小喜爱画画,因父亲贾敬一味好道炼丹,别的事一概不管,而母亲又早逝,她一直在荣国府贾母身边长大。四大家族的没落命运,三个本家姐姐的不幸结局,使她产生了弃世的念头,<\/span>后入栊翠庵为尼<\/strong>。<\/span><\/p>


<\/span><\/p>\r\n

7. 正册之七<\/b> · 王熙凤<\/b><\/p>

《判词》<\/b><\/p>\r\n

画:一片冰山,山上有一只雌凤。<\/i><\/p>\r\n

判词:凡鸟偏从末世来,都知爱慕此生才。一从二令三人木,哭向金陵事更哀。<\/i><\/p>

【聪明累】机关算尽太聪明,反算了卿卿性命.生前心已碎,死后性空灵.家富人宁,终有个家亡人散各奔腾.枉费了,意悬悬半世心;好一似,荡悠悠三更梦.忽喇喇似大厦倾,昏惨惨似灯将尽.呀!一场欢喜忽悲辛.叹人世,终难定! <\/pre>\r\n

解析:<\/p>\r\n

     王熙凤的贾府的实际当权派。她主持荣,协理宁国府,而且交通官府,为所欲为。这是个政治性很强的人物,不是普通的贵族家庭的管家婆。她显著特点,就是“弄权”,一手抓权,一手抓钱,十足表现出剥削阶级的权欲和贪欲。王熙凤不仅是一个人,而是代表了一个阶级。“忽喇喇似大厦倾,昏惨惨似灯将尽”,不光是王熙凤的个人命运,也是垂死的封建阶级和他们所代表的反动社会制度彻底崩溃的形象写照。<\/p><\/blockquote>\r\n

    《聪明累》中“机关算尽太聪明,反算了卿卿性命!”这两句道出了正在走向没落的一切反动阶级的共同规律。王熙凤是四大家族中首屈一指的“末世之才”,在短暂的几年掌权中,她极尽权术机变、残忍阴毒之能事,制造了许多罪恶,直接死在她手里的就有好几条人命。这一切只不过为她自己的最后垮台准备条件。按照曹雪芹的原意,这个贾门女霸的结局是很糟的。从脂批中可以知道原稿后半部有以下情节:<\/p><\/blockquote>\r\n

      一、获罪离家,与宝玉同淹留于狱神庙。原因不外乎她敛财害命等罪行的被揭露。如对“弄权铁槛寺”,逼迫一对未婚夫妻自尽,自己坐享三千两银子一节,脂批就指出:“如何消缴,造业者不知,自有知者。”“后文不必细写其事,则知其平生之作为,回首时无怪首其惨痛之态”。离家在外期间,刘姥姥还与她在“狱神庙相逢”。此外,在狱神庙见到凤姐的,还有小红、茜雪等人。<\/p><\/blockquote>\r\n

     二、在大观园执帚扫雪。这当是获罪外出,经一番周折,重返贾府以后的事。脂批说过,怡红院的穿堂门前,将来“便是凤姐扫雪拾玉之处”<\/p><\/blockquote>\r\n

     三、被丈夫休弃,“哭向金陵”娘家。从第二十一顺脂批看,她发现丈夫私藏的多姑娘头发是一个导火线。丈夫借此闹翻,将其休弃。那时,凤姐“身微运蹇”,只能忍辱,这与“俏平儿软语救贾琏”时的“阿凤英气”有天壤之别。所以后半部那一回的回目叫《王熙凤知命强英雄》。<\/p><\/blockquote>\r\n

     四、回首惨痛,短命而死。尤氏对凤姐说:“明儿带了棺材里使去。”脂批:“此言不假,伏下后文短命。”<\/p><\/blockquote>\r\n

     总之,凤姐的惨痛结局是自食恶果,并不是什么人世祸福难定。<\/p><\/blockquote>

《结局》<\/b><\/p>

贾琏之妻,金陵四大家王家的小姐、贾家的媳妇,王夫人的内侄女。她精明强干,深得贾母和王夫人的信任,成为贾府的实际大管家,支撑着贾府上上下下所有人的吃穿住行,老死病辞。为人处事也十分圆滑周到,图财害命的事也是干过的。<\/span>她病死在监狱里,被狱卒用一领破席卷了出去,正应了那句“机关算尽太聪明,反算了卿卿性命”。<\/strong><\/p>\r\n


<\/u><\/b><\/p>

8. 正册之八<\/b> · 史<\/b>湘云<\/b><\/p>

《判词》<\/b><\/p>\r\n

画:几缕飞云,一湾逝水。<\/i><\/p>\r\n

判词:富贵又何为?襁褓之间父母违;展眼吊斜晖,湘江水逝楚云飞。<\/i><\/p>

【乐中悲】襁褓中,父母叹双亡。纵居那绮罗丛,谁知娇养?幸生来,英豪阔大宽宏量,从未将儿女私情略萦心上。好一似,霁月光风耀玉堂,厮配得才貌仙郎,博得个地久天长,准折得幼儿时坎坷形状。终久是云散高唐,水涸湘江。这是尘寰中消长数应当,何必枉悲伤!<\/pre>\r\n

解析:<\/p>\r\n

    《红楼梦》以“写儿女之笔墨”的面目出现,这有作者顾忌当时政治环境因素在。因而,书中所塑造的众多的代表不同性格、类型的女子,从她们的形象取材于现实生活这一点来看,经剪裁、提炼,被综合在小说的原型人物的个性、细节等等,恐不一定只限于女性。在大观园女儿国中,须眉气象出以脂粉精神最明显的,要数史湘云了。她从小父母双亡,由叔父抚养,她的婶母待她并不好。因此,她的身世和林黛玉有点相似。但她心直口快,开朗豪爽,爱淘气,又不大瞻前顾后,甚至敢于喝醉酒后在园子里的青石板凳上睡大觉。她和宝玉也算是好友,在一起,有时亲热,有时也会恼火,但毕竟襟怀坦荡,“从未将儿女私情萦心上”。不过,另一方面,她也没有林黛玉那种叛逆精神,且在一定程度上受到薛宝钗的影响。在史湘云身上,除她特有的个性外,我们还可以看到在封建时代被赞扬的某些文人的豪放不羁的特点。<\/p><\/blockquote>\r\n

     史湘云的不幸遭遇主要在八十回以后。根据这个《乐中悲》和脂砚斋评注中提供的零星材料,史湘云后来和一个颇有侠气的贵族公子卫若兰结婚,婚后生活还比较美满。但好景不长,不久夫妻离散,她因而寂寞憔悴。至于传说有的续写本中宝钗早卒,宝玉沦为击柝的役卒,史湘云沦为乞丐,最后与宝玉结为夫妻,看来这并不合乎曹雪芹原来的写作计划,乃附会第三十一回“因麒麟伏白首双星”的回目而产生。其实“白首双星”就是指卫若兰、史湘云两到老都过着分离的生活;因为史湘云的金麒麟与薛宝钗的金锁相仿,同作为婚姻的凭证,正如脂批所说:“后数十回若兰射圃所佩之麒麟,正此麒麟也。提纲伏于此回目中,所谓草蛇灰线在千里之外。”那么,“提纲”是怎么“伏”法的呢?这一回写宝玉失落这金麒麟恰巧被湘云拾到,而湘云的丫环正与小姐谈论着“雄雌”“阴阳”之理。这初看起来,倒确是很象“伏”湘云与宝玉有“缘”,况且,与“金玉姻缘”之说也合。黛玉也曾为此而起过疑,对宝玉说了些带讽刺的话。其实,宝玉只是无竟中充当了中间人的角色。就象袭人与蒋玉菡之“缘”是通过他的传带,交换了彼此的汗巾子差不多。这一点,脂班次说得非常清楚:“金玉姻缘已定,又写一个金麒麟,是间色法也。保颦儿为其所感,故颦儿谓‘情情’。”绘画为使主色鲜明,另用一色衬托叫“间色法”。湘云的婚姻是宝钗婚姻的陪衬:一个因金锁结缘,一个因金麒麟结缘;一个当宝二奶奶仿佛幸运,但丈夫出家,自己守寡;一个“厮配得才貌仙郎”,谁料“云散高唐,水涸湘江”,最后也是空房独守。“双星”,就是牵牛、织女星的别称。故七夕又称双星节。总之“白首双星”是说史湘云和卫若兰结成夫妻后,由于某种尚不知道的原因,很快就离异了,成了牛郎织女。这正好作宝钗“金玉良缘”的衬托。《好了歌注》:“说甚么脂正浓、粉正香,如何两鬓又成霜?”脂批就并提宝钗、湘云,说是指她们两人。可见,因回目而附会湘云将来要嫁给宝玉的人们,也与黛玉当时因宝玉收了金麒麟而“为其所感”一样,同是出于误会。<\/p><\/blockquote>

《结局》<\/b><\/p>

金陵四大家中史家的千金小姐,是贾母的侄孙女。<\/p>

她心直口快,开朗豪爽,爱淘气,甚至敢于喝醉酒后在园子里的大青石上睡大觉;身着男装,大说大笑;风流倜傥,不拘小节;诗思敏锐,才情超逸;说话“咬舌”,把“二哥哥”叫作“爱哥哥”。她是一个富有浪漫色彩、令人喜爱、富有“真、善、美”的豪放女性。<\/span><\/p>

高鹗续本中史湘云和卫若兰成婚,但卫早死,史湘云孤独终老。<\/p>\r\n


<\/p>

9. 正册之九<\/b> · <\/b>秦可卿<\/b><\/p>

《判词》<\/b><\/p>\r\n

画:高楼大厦,有一美人悬梁自缢。<\/i><\/p>\r\n

判词:情天情海幻情身,情既相逢必主淫;漫言不肖皆荣出,造衅开端实在宁。<\/i><\/p>

【好事终】画梁春尽落香尘.擅风情,秉月貌,便是败家的根本.箕裘颓堕皆从敬,家事消亡首罪宁.宿孽总因情.<\/pre>\r\n

解析:<\/p>\r\n

     秦可卿本是被弃于养生堂的孤儿。她从抱养她的“寒儒薄宦”之家进入贾府以后,就堕入了罪恶的渊薮。她走上绝路是贾府主子们糜烂生活的恶果,其中首恶便是贾珍这些人形兽类。《好事终》有一点是颇令人思索的:那就是秦可卿在小说中死得较早,接着还有元春省亲、庆元宵等盛事,为什么要说她是“败家的根本”呢?难道作者真的认为后来贾府之败是象这首曲子所归结的“宿孽总因情”吗?四大家族的衰亡是社会的、政治的客观规律所决定的,封建统治阶级的生活腐朽、道德败坏也是其阶级本性所决定的。纵然曹雪芹远远不可能有这样的认识,又何至于把后来发生的重大变故的责任,全推在一个受贾府这个罪恶封建家庭的毒氛污染而丧生的女子身上,把一切原因都说成是因为“情”呢?原来,这和十二支曲的《引子》中所说的“都只为风月情浓”一样,只是作者有意识在小说一切人物、事件上盖上的瞒人的印记。作者在很大程度上为了给人以“大皆谈情”的假象,才虚构了太虚幻境、警幻仙子的。但是,这种“荒唐言”若不与现实沟通,就起不了掩护有政治性的真事的作用。因而,作者又在现实中选择了秦可卿这个因风月之事败露而死亡的人,作为这种“情”的象征,让她在宝玉梦中“幻”为“情身”,还让那个也叫“可卿”的仙姬与钗、黛的形象混成一体,最后与宝玉一齐堕入“迷津”,暗示这是后来情节发展的影子,以自圆其“宿孽因情”之说。当然,作者思想是充满着矛盾的。以假象示人是不得已的。所以他在太虚幻境入口处写下了一副对联,预先就一再警告读者要辨清“真假有无”。<\/p><\/blockquote>\r\n

     我们已经知道,贾府后来发生变故的直接导火线在荣国府,获罪而淹留在狱神庙的宝玉、凤姐都是荣国府的人。宝玉的罪状,不外乎“不肖种种大承笞挞”时所传的那种口舌。宝玉固然有沾花惹草的贵族公子习气,但决不至于象贾珍父子那样无耻,使这一点成为累及整个贾府的罪状,当然是因为在政治斗争中敌对势力要心量抓住把柄来整治对方。现在偏要说这是风月之情造的孽,关且把它归结到它的发端---秦氏的诱惑。但即使就这个起因来说,也不能不指出,这一切宁国府本来就更不象话。比如,若按封建礼法颓堕家教论罪,贾敬纵容子孙恣意妄为,就要比贾政想用严训教子就范而无能为力更严重,更应定为“首罪”。王熙凤的弄权、剑财、害命,也起于她协理宁国罕。贾珍向王夫人流泪求情请凤姐料理丧事,纵容她“爱怎样就怎样,要什么只管……取去”,使她忘乎所以。铁槛寺害命受贿后,“凤姐胆识愈壮,以后有了这样的事,便恣意的作为起来”。而办这样奢靡的丧事,又因为贾珍与死者有特殊关系。凤姐计赚尤二姐、大闹宁国府,事情也起于贾珍、贾蓉。而贾蓉又与凤姐有着不可告人的关系,他还是与凤姐最亲的秦氏的丈夫哩!然而,尽管如此,“风情”“月貌”以至秦可卿本人,都不过是作者用来揭示贾府中种种关系的一种凭借,贾府衰亡的前因后果,自有具体的情节会作出说明的,这就象作者在具体描写冯渊、张金哥之死的情节时毫不含糊一样。秦可卿“判词”和曲子中的词句的含义,要比我们草草读去所得的表面印象来得深奥,就连曲名“好事终”,我们体会起来,其所指恐怕也不限于秦氏一人,而可以是整个贾府的败亡。<\/p><\/blockquote>

《结局》<\/b><\/p>

秦可卿为太虚境中警幻仙子的妹妹,是宁国府贾蓉的妻子。她长得袅娜纤巧,性格风流,行事又温柔和平,深得贾母等人的欢心。<\/span><\/p>

可惜因爬灰、养小叔子两件丑事曝光,致其年轻早夭。<\/p>\r\n


<\/p>

10. 正册之十<\/b> · <\/b>李纨<\/b><\/p>

《判词》<\/b><\/p>\r\n

画:一盆茂兰,旁有一位凤冠霞帔的美人。<\/i><\/p>\r\n

判词:桃李春风结子完,到头谁似一盆兰?如冰水好空相妒,枉与他人作笑谈。<\/i><\/p>

【晚韶华】镜里恩情,更那堪梦里功名!那美韶华去之何迅!再休提绣帐鸳衾.只这带珠冠,披凤袄,也抵不了无常性命.虽说是,人生莫受老来贫,也须要阴骘积儿孙.气昂昂头戴簪缨;光灿灿胸悬金印;威赫赫爵禄高登;昏惨惨黄泉路近.问古来将相可还存?也只是虚名儿与后人钦敬 <\/pre>\r\n

解析:<\/p>\r\n

     在小说中许多重要事件上,李纨都在场,可是她永远只充当“敲边鼓”的角色,没有给读者留下什么特殊的印象。这也许正是符合她身分地位和思想性格的---荣国府的大嫂子,一个恪守封建礼法、与世无争的寡妇,从来安分顺时,不肯卷入矛盾斗争的旋涡。作者在第四回的开头,就对她作了一番介绍,那段文字除了未提结局外,已可作为她的一篇小传。她是一个封建社会中被称为贤女节妇的典型,“三从四德”的妇道的化身。清代的卫道者们鼓吹程朱理学,宣扬妇女贞烈气节特别起劲,妇女所受的封建主义“四大绳索”压迫的痛苦也更为深重。象李纨这样的人,在统治者看来,是完全有资格受表旌,立牌坊,编入“列女传”的。虽则“无常性命”没有使她有更多享晚福的机会,但她毕竟在寿终前得到了“凤冠霞帔”的富贵荣耀,这正可以用来作为天道无私,终身能茹苦含辛、贞节自守者必有善报的明证。然而,曹雪芹偏将她入了“薄命司”册子,说这一切只不过是“枉与他人作笑谈”罢了,这实是对儒家传统观念的大胆挑战,是从封建王国的黑暗中透射出来的民主主义思想的光辉。<\/p><\/blockquote>

《结局》<\/b><\/p>

出身金陵名宦,贾珠之妻,生有儿子贾兰。<\/p>

她从小就受父亲“女子无才便是德”的教育,以认得几个字,记得前朝几个贤女便了,每日以纺织女红为要。李纨是个恪守封建礼法的贤女节妇的典型,是标准的节妇,妇德妇功的化身。<\/span><\/p>

后来在儿子得了功名富贵之后,李纨突然死去,\"枉与他人作笑谈\"。<\/p>\r\n


<\/p>

11. 正册之十一<\/b> · <\/b>妙玉<\/b><\/p>

《判词》<\/b><\/p>\r\n

画:一块美玉,落在泥垢之中。<\/i><\/p>\r\n

判词:欲洁何曾洁,云空未必空。可怜金玉质,终陷淖泥中。<\/i><\/p>

【世难容】]:气质美如兰,才华馥比仙.天生成孤僻人皆罕.你道是啖肉食腥膻,视绮罗俗厌;却不知太高人愈妒,过洁世同嫌.可叹这,青灯古佛人将老;辜负了,红粉朱楼春色阑.到头来,依旧是风尘肮脏违心愿.好一似,无暇白玉遭泥陷;又何须,王孙公子叹无缘. <\/pre>\r\n

解析:<\/p>\r\n

     来自苏州的带发修行的尼姑妙玉,原来也是富家小姐一。她住在大观园中的栊翠庵,依附权门,受贾府的供养,却又自称“槛外人”。这正如鲁迅所揭露的:“要做这样的人,恰如用自己的手拔头发,要离开地球一样。”实际上她并没有置身于贾府的各种现实关系之外。她的“高”和“洁”都带有矫情的味道。她标榜清高,连黛玉也被她称为“大俗人”,却独喜欢和宝玉往来,连宝玉生日也不忘记,特地派人送来祝寿的贴子。她珍藏的晋代豪门富室王恺的茶杯,对她也是个讽刺。她有特殊的洁癖。刘姥姥喝过一口茶的成窑杯她因嫌脏要砸碎,但又特意把“自己日常吃茶”的绿玉斗招待宝玉。所谓洁与不洁,都深深打上了阶级和感情的烙印。她最后流落风尘,好象是对她过高过洁的一种难堪的惩罚。象妙玉这样依附于没落阶级的人,怎么能超然自拔而不随同这个阶级一起没落呢!<\/p><\/blockquote>\r\n

     有人说《红楼梦》是演绎“色空”观念的书,这无论就作品的社会意义或作者的创作思想来看,都是过于夸大的。曹雪芹的意识中是有某种程度的“色空”观念,那就是他对现实的深刻的悲观主义。但《红楼梦》决不是这种那种观念的演绎,更没有堕入宣扬宗教意识的迷津。曹雪芹对妙玉这个人物的描写,很能说明问题。作者既没有认为入空门就能成为一尘不染的高人,也没有因此而特意为她安排更好的命运。<\/p><\/blockquote>\r\n

     原稿中妙玉的结局与续书所写是不同的。续书写妙玉的遭劫是因为强人觉得她“长的实在好看”,又听说她为宝玉“害起相思病来了”,故动了邪念。这与妙玉的“太高”、“过洁”的“偏僻”个性又有什么相干呢?这倒是续书作者一贯意识的表现:在续作者看来,黛玉的病也是相思病,故有“心病终须心药治”,“这心病也是断断有不得的”一类话头。问题当然并不仅仅在于怎样的结局更好些,而在于通过人物的遭遇说明什么。续书想要说明的是妙玉情欲未断,心地不净,因而内虚外乘,先有邪魔缠扰,后遭贼人劫持。这是她自己作孽而受到的报应。结论是出家人应该灭绝人欲,“一念不生,万缘俱寂”。这也就是程朱理学所鼓吹的“以理禁欲,去欲存理”。而原稿的处理,显然是把妙玉的命运与贾府的命运紧紧地联系在一起的。这样,妙玉悲剧所具有的客观意义,就要比曲子中用“太高”、“过洁”等纯属个人品质的原因去说明它,更为深刻。<\/p><\/blockquote>

《结局》<\/b><\/p>

妙玉是一个带发修行尼姑,原本是仕宦人家的小姐,极端美丽、博学、聪颖,但也极端孤傲、清高、不合群,不为世俗所容,投奔贾府,居于大观园中拢翠庵。贾母去世后,贾府的富贵也走入了尽头,随后妙<\/span>玉被坏人掳走<\/strong>。后来又有传闻说,妙玉在海边被坏人杀死,又有人说妙玉被卖入了烟花之地。<\/span><\/p>\r\n


<\/p>

12. 正册之十二 · 巧姐<\/b><\/p>

《判词》<\/b><\/p>\r\n

画:一座荒村野店,有一美人在那里纺绩。<\/i><\/p>\r\n

判词:势败休云贵,家亡莫论亲。偶因济刘氏,巧得遇恩人。<\/i><\/p>

<\/p>

【留余庆】留余庆,留余庆,忽遇恩人;幸娘亲,幸娘亲,积得阴功.劝人生,寄困扶穷.休似俺那爱银钱忘骨肉的狠舅奸兄!正是乘除加减,上有苍穹. <\/pre>\r\n

解析:<\/p>\r\n

     贾府丑事败露后,王熙凤获罪,自身难保,女儿贾巧姐为狠舅奸兄欺骗出卖,流落在烟花巷。贾琏夫妻、父女,“家亡人散各奔腾”。后来,巧姐幸遇恩人刘姥姥救助,使她死里逃生。这些是佚稿中的情节。那么这样描写巧姐的命运,在小说之中,究竟有什么特殊的意义没有泥?我们认为它很有可能表现出作者曹雪芹在经历过长期的贫困生活后,思想上所出现的某些接近人民的新因素。<\/p><\/blockquote>\r\n

     作者描写刘姥姥形象的真正用意,并不象小说所声称的那样是因为贾府大小事多,理不出头绪来,所以借她为引线;也不是为了让她进荣国府闹出许多笑话来,供太太小姐们取乐,借以使文字生色。作者安排这个人物是胸有成竹的。脂批指出,小说在介绍刘姥姥一家时说“略有些瓜葛”,是数十回后之正脉也。这就是说,刘姥姥一家在后半部中因巧为板儿媳妇,真的成了贾家的亲戚,而且是正派亲戚。“势败休云贵,家亡莫论亲。”在“树倒猢狲散”的情况下,贾府主子们之间的勾心斗角已发展为骨肉相残。到那时,肯伸手相援的都是一些曾被人瞧不起的小人物,如贾芸、小红、茜雪等,而曾作贾府上下嘲弄对象的刘姥姥,不但是贾府兴衰的见证者,反过来,她也成了真正能出大力救助贾府的人。要把被卖作妓女的巧人火坑里救出来,就不外乎出钱和向人求情,这对刘姥姥来说,是不容易的。接着,招烟花女子为媳妇,则更要承受封建道德观念的巨大压力。在脂批看来,“老妪有忍耻之心,故后有招大姐之事”。其实,这正是在考验关头表现一个农村劳动妇女的思想品质,大大高出于表面上维护着虚伪的封建道德的上层统治阶级的地方。<\/p><\/blockquote>\r\n

      贾巧姐终于从一个出身公侯之门的千金,变成了一个在“荒村野店”里“纺绩”的劳动妇女了,就象秦氏出殡途中,宝玉所见的那个二丫头那样。与前半部十二钗所过的那种吟风弄月的寄生生活相反,巧姐走上了一条全新的自食其力的生活道路。于是刘姥姥为巧姐取名时所说的话得到了证验。曹雪芹思想的深度是一般封建时代的小说家所难以企及的。脂批的思想,就有很大的距离。续书者就更不用说了,在他看来,女子失节,不如一死;既沦为烟花女,便无“余庆”可谈;招巧姐而使她成为靠“两亩薄田度日”的卑贱的家妇,刘氏也算不得“恩人”。所以续书让巧幸免于难,并且最后非让她嫁到“家资巨万”的大地主家不可,还让“刘姥姥见了王夫人等,便说起来将来怎么升官,怎么起家,怎么子孙昌盛”。这与曹雪芹的原意,真有天壤之别。<\/p><\/blockquote>\r\n

当然,曹雪芹笔下的刘姥姥,身上也戴着封建阶级精神奴役的沉重枷锁;说王熙凤能“留余庆”,“积得阴功”,也完全是一种阶级偏见;《留余庆》宣扬“乘除加减,上有苍穹”的冥冥报应的迷信思想,更明显的属封建糟粕。这些无疑都应批判剔除。但是,我们也应该看到使作者产生“劝人生,济困扶穷”思想的实际生活基础,把它与封建剥削阶级惯于进行的虚伪、廉价的慈善说教区别开来。<\/p>\r\n

《结局》<\/b><\/p>

巧姐是王熙凤与贾琏之女,列入金陵十二钗。巧姐由于年纪细小,性格尚未形成,所以在书中处于陪衬地位。<\/p>

巧姐娇贵多病,生在七月初七,所以刘姥姥给她取名为“巧姐”。在贾府败落后被狠舅奸兄卖到了烟花巷。<\/span>但最终被知恩图报的刘姥姥赎出,与刘姥姥的孙子板儿结婚,在农村有了很好的结果,成了一位纺绩妇人。<\/strong><\/p><\/div>

 郑重声明<\/u><\/b>:
<\/p>

本文重点引用 <\/p>

  1. 瑞文网 之文章 红楼梦判词解析十二金钗判词及解析<\/a> 网址 http:\/\/www.ruiwen.com\/news\/68916.htm
    <\/li><\/ol>

    本文旨在为红迷爱好者读,侵权请连续以下邮箱,或评论,进行删除。<\/p>

    laozhang@azlinli.com<\/p>


    <\/p>", - "tdDetail": "简要说明 金陵十二钗主人公判词,命运之说 ", - "tdSectendDetail": null, - "tdIsDelete": "0", - "tdRead": 47, - "tdCommend": 0, - "tdGood": 0, - "tdCreatetime": "\/Date(1546272000000+0800)\/", - "tdUpdatetime": "\/Date(1546272000000+0800)\/", - "tdTop": 1, - "tdAuthor": null, - "Id": 2 - }, - { - "TopicId": 2, - "tdLogo": null, - "tdName": "红楼梦 主要人物关系构架 更新中", - "tdContent": "

    \r\n \r\n