.netcore项目ZrAdminNetCore学习

1,827 阅读3分钟

ZrAdminNetCore这个项目是参考若依框架改造的,前者是.netcore项目,后者是Java项目。只要学会一个,其他一个很容易看懂的。当然你必须有这两种语言的基础,否则还是有点困难。若依框架这个项目目前很有名气,很多公司的项目都是参考它,并基于它改造变成公司的项目。

公司如果想快速出成果,又不想自己从头开始,选择它是个不错的。今天我来总结.netcore版本的项目。

我们下载下来项目,用vs打开,然后运行出现这样的结果。表示运行成功了!

image.png

netcore2.2以后都会生成exe文件 项目解构

image.png

一基础类设施层

1.1 基础类

这里有日志特性类,状态类,异常类,一些帮助类

image.png

1.2 代码生成器

这里是根据数据表格,生成业务模块的处理逻辑代码

image.png

1.3 通用类

这里有两个缓存类,阿里云存储类,邮箱处理类,工具类。

image.png

二 业务链接层

image.png

2.1 model 层

这个很好理解,就是实体层

2.2 ZR.Repository 层

这个是仓储层

2.3 ZR.Service 层

这个服务层

三 ui 层

这里有各个模块的控制器也是调用服务层

image.png

四 定时任务

image.png

五 SignalR 用法

 public class MessageHub : Hub
    {
        //创建用户集合,用于存储所有链接的用户数据
        private static readonly List<OnlineUsers> clientUsers = new();
        private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        private ISysNoticeService SysNoticeService;

        public MessageHub(ISysNoticeService noticeService)
        {
            SysNoticeService = noticeService;
        }

        private ApiResult SendNotice()
        {
            var result = SysNoticeService.GetSysNotices();

            return new ApiResult(200, "success", result);
        }

        #region 客户端连接

        /// <summary>
        /// 客户端连接的时候调用
        /// </summary>
        /// <returns></returns>
        public override Task OnConnectedAsync()
        {
            var name = Context.User.Identity.Name;

            var user = clientUsers.Any(u => u.ConnnectionId == Context.ConnectionId);
            //判断用户是否存在,否则添加集合
            if (!user && Context.User.Identity.IsAuthenticated)
            {
                clientUsers.Add(new OnlineUsers(Context.ConnectionId, name));
                Console.WriteLine($"{DateTime.Now}{name},{Context.ConnectionId}连接服务端success,当前已连接{clientUsers.Count}个");
                //Clients.All.SendAsync("welcome", $"欢迎您:{name},当前时间:{DateTime.Now}");
                Clients.All.SendAsync(HubsConstant.MoreNotice, SendNotice());
            }
            
            Clients.All.SendAsync(HubsConstant.OnlineNum, clientUsers.Count);
            return base.OnConnectedAsync();
        }

        /// <summary>
        /// 连接终止时调用。
        /// </summary>
        /// <returns></returns>
        public override Task OnDisconnectedAsync(Exception exception)
        {
            var user = clientUsers.Where(p => p.ConnnectionId == Context.ConnectionId).FirstOrDefault();
            //判断用户是否存在,否则添加集合
            if (user != null)
            {
                Console.WriteLine($"用户{user?.Name}离开了,当前已连接{clientUsers.Count}个");
                clientUsers.Remove(user);
                Clients.All.SendAsync(HubsConstant.OnlineNum, clientUsers.Count);
            }
            return base.OnDisconnectedAsync(exception);
        }

        #endregion
    }

vue 页面调用方法

 initSignalR() {
                var _this = this;
                _this.signalR = new signalR.HubConnectionBuilder()
                    .withUrl("http://localhost:8888/msgHub")
                    .configureLogging(signalR.LogLevel.Information)
                    .build();
                try {
                    _this.signalR.start();
                } catch (err) {
                    console.log(err);
                }
 
                //监听连接成功
                _this.signalR.on("OnConnectedAsync", (message) => {
                    HeyUI.$Message(message)
                });
 
                // _this.signalR.on("ReceiveMessage", (user, message) => {
                //     HeyUI.$Notice({
                //         type: "info",
                //         title: user + " 回复 ",
                //         content: message
                //     });
                // });
            },

运行结果

image.png 参考链接 :blog.csdn.net/weichaoya/a…

六 功能说明

6.1 权限过滤器

 /// <summary>
    /// API授权判断
    /// </summary>
    public class ActionPermissionFilter : ActionFilterAttribute//, IAsyncActionFilter
    {
        private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 权限字符串,例如 system:user:view
        /// </summary>
        public string Permission { get; set; }
        private bool HasPermi { get; set; }
        private bool HasRole { get; set; }

        public ActionPermissionFilter() { }

        public ActionPermissionFilter(string permission)
        {
            Permission = permission;
            HasPermi = !string.IsNullOrEmpty(Permission);
        }

        /// <summary>
        /// 执行Action前校验是否有权限访问
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            //上下文获取用户信息
            LoginUser info = Framework.JwtUtil.GetLoginUser(context.HttpContext);

            if (info != null && info?.UserId > 0)
            {
                List<string> perms = info.Permissions;
                List<string> rolePerms = info.RoleIds;
                if (perms.Exists(f => f.Equals(GlobalConstant.AdminPerm)))
                {
                    HasPermi = true;
                }
                else if (rolePerms.Exists(f => f.Equals(GlobalConstant.AdminRole)))
                {
                    HasPermi = true;
                }
                else if (!string.IsNullOrEmpty(Permission))//控制器方法上的权限
                {
                    HasPermi = perms.Exists(f => f.ToLower() == Permission.ToLower());//用户拥有的和操作方法上的权限判断
                }

                bool isDemoMode = AppSettings.GetAppConfig("DemoMode", false);
                var url = context.HttpContext.Request.Path;//请求路径
                //演示公开环境屏蔽权限
                string[] denyPerms = new string[] { "update", "add", "remove", "add", "edit", "delete", "import", "run", "start", "stop", "clear", "send", "export", "upload", "common" };
                if (isDemoMode && denyPerms.Any(f => Permission.ToLower().Contains(f)))
                {
                    context.Result = new JsonResult(new { code = ResultCode.FORBIDDEN, msg = "演示模式 , 不允许操作" });
                }
                if (!HasPermi && !Permission.Equals("common"))
                {
                    logger.Info($"用户{info.UserName}没有权限访问{url},当前权限[{Permission}]");
                    JsonResult result = new(new ApiResult()
                    {
                        Code = (int)ResultCode.FORBIDDEN,
                        Msg = $"你当前没有权限[{Permission}]访问,请联系管理员",
                        Data = url
                    })
                    {
                        ContentType = "application/json",
                    };
                    context.Result = result;
                }
            }

            return base.OnActionExecutionAsync(context, next);
        }
    }

6.2 控制器方法操作监视过滤器

  public class GlobalActionMonitor : ActionFilterAttribute
    {
        static readonly Logger logger = LogManager.GetCurrentClassLogger();
        private ISysOperLogService OperLogService;
        public GlobalActionMonitor(ISysOperLogService operLogService)
        {
            OperLogService = operLogService;
        }

        /// <summary>
        /// Action请求前
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            ApiResult response = new();
            response.Code = (int)ResultCode.PARAM_ERROR;

            var values = context.ModelState.Values;
            foreach (var item in values)
            {
                foreach (var err in item.Errors)
                {
                    if (err.ErrorMessage.Contains("JSON"))
                    {
                        return next();
                    }
                    if (!string.IsNullOrEmpty(response.Msg))
                    {
                        response.Msg += " | ";
                    }

                    response.Msg += err.ErrorMessage;
                }
            }
            if (!string.IsNullOrEmpty(response.Msg))
            {
                logger.Info($"请求参数错误,{response.Msg}");
                context.Result = new JsonResult(response);
            }
            return base.OnActionExecutionAsync(context, next);
        }

        /// <summary>
        /// OnActionExecuted是在Action中的代码执行之后运行的方法。
        /// </summary>
        /// <param name="context"></param>
        public override void OnResultExecuted(ResultExecutedContext context)
        {
            if (context.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) return;

            //获得注解信息
            LogAttribute logAttribute = GetLogAttribute(controllerActionDescriptor);
            if (logAttribute == null) return;

            try
            {
                string method = context.HttpContext.Request.Method.ToUpper();
                // 获取当前的用户
                string userName = context.HttpContext.GetName();
                string jsonResult = string.Empty;
                if (context.Result is ContentResult result && result.ContentType == "application/json")
                {
                    jsonResult = result.Content.Replace("\r\n", "").Trim();
                }
                if (context.Result is JsonResult result2)
                {
                    jsonResult = result2.Value?.ToString();
                }
                //获取当前执行方法的类名
                //string className =  System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name;
                //获取当前成员的名称
                //string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
                string controller = context.RouteData.Values["Controller"].ToString();
                string action = context.RouteData.Values["Action"].ToString();

                string ip = HttpContextExtension.GetClientUserIp(context.HttpContext);
                var ip_info = IpTool.Search(ip);

                SysOperLog sysOperLog = new()
                {
                    status = 0,
                    operName = userName,
                    operIp = ip,
                    operUrl = HttpContextExtension.GetRequestUrl(context.HttpContext),
                    requestMethod = method,
                    jsonResult = jsonResult,
                    operLocation = ip_info.Province + " " + ip_info.City,
                    method = controller + "." + action + "()",
                    //Elapsed = _stopwatch.ElapsedMilliseconds,
                    operTime = DateTime.Now
                };
                HttpContextExtension.GetRequestValue(context.HttpContext, sysOperLog);

                if (logAttribute != null)
                {
                    sysOperLog.title = logAttribute?.Title;
                    sysOperLog.businessType = (int)logAttribute?.BusinessType;
                    sysOperLog.operParam = logAttribute.IsSaveRequestData ? sysOperLog.operParam : "";
                    sysOperLog.jsonResult = logAttribute.IsSaveResponseData ? sysOperLog.jsonResult : "";
                }

                LogEventInfo ei = new(LogLevel.Info, "GlobalActionMonitor", "");
                
                ei.Properties["jsonResult"] = !HttpMethods.IsGet(method) ? jsonResult : "";
                ei.Properties["requestParam"] = sysOperLog.operParam;
                ei.Properties["user"] = userName;
                logger.Log(ei);

                OperLogService.InsertOperlog(sysOperLog);
            }
            catch (Exception ex)
            {
                logger.Error(ex, $"记录操作日志出错了#{ex.Message}");
            }
        }

        //获取控制器方法上LogAttribute 特性内容
        private LogAttribute GetLogAttribute(ControllerActionDescriptor controllerActionDescriptor)
        {
            var attribute = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
                .FirstOrDefault(a => a.GetType().Equals(typeof(LogAttribute)));

            return (LogAttribute)attribute;
        }
    }

6.3 授权校验过滤器

 /// <summary>
    /// 授权校验访问
    /// 如果跳过授权登录在Action 或controller加上 AllowAnonymousAttribute
    /// </summary>
    public class VerifyAttribute : Attribute, IAuthorizationFilter
    {
        static readonly Logger logger = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 只判断token是否正确,不判断权限
        /// 如果需要判断权限的在Action上加上ApiActionPermission属性标识权限类别,ActionPermissionFilter作权限处理
        /// </summary>
        /// <param name="context"></param>
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var noNeedCheck = false;
            if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
            {
                noNeedCheck = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
                  .Any(a => a.GetType().Equals(typeof(AllowAnonymousAttribute)));
            }

            if (noNeedCheck) return;

            string ip = HttpContextExtension.GetClientUserIp(context.HttpContext);
            string url = context.HttpContext.Request.Path;
            var isAuthed = context.HttpContext.User.Identity.IsAuthenticated;

            //使用jwt token校验2020-11-21
            LoginUser info = JwtUtil.GetLoginUser(context.HttpContext);

            if (info == null || !isAuthed)
            {
                string msg = $"请求访问[{url}]失败,无法访问系统资源";
                logger.Info($"{msg}");

                context.Result = new JsonResult(new ApiResult((int)ResultCode.DENY, msg));
            }
        }
    }

6.4 给实体添加默认值扩展类

 public static class EntityExtension
    {
        public static TSource ToCreate<TSource>(this TSource source, HttpContext context = null)
        {
            var types = source.GetType();

            if (types.GetProperty("CreateTime") != null)
            {
                types.GetProperty("CreateTime").SetValue(source, DateTime.Now, null);
            }
            if (types.GetProperty("AddTime") != null)
            {
                types.GetProperty("AddTime").SetValue(source, DateTime.Now, null);
            }
            if (types.GetProperty("UpdateTime") != null)
            {
                types.GetProperty("UpdateTime").SetValue(source, DateTime.Now, null);
            }
            if (types.GetProperty("Create_by") != null && context != null)
            {
                types.GetProperty("Create_by").SetValue(source, context.GetName(), null);
            }
            if (types.GetProperty("UserId") != null && context != null)
            {
                types.GetProperty("UserId").SetValue(source, context.GetUId(), null);
            }
            return source;
        }

        public static TSource ToUpdate<TSource>(this TSource source, HttpContext context = null)
        {
            var types = source.GetType();

            if (types.GetProperty("UpdateTime") != null)
            {
                types.GetProperty("UpdateTime").SetValue(source, DateTime.Now, null);
            }
            if (types.GetProperty("Update_time") != null)
            {
                types.GetProperty("Update_time").SetValue(source, DateTime.Now, null);
            }

            if (types.GetProperty("UpdateBy") != null)
            {
                types.GetProperty("UpdateBy").SetValue(source,context.GetName(), null);
            }
            if (types.GetProperty("Update_by") != null)
            {
                types.GetProperty("Update_by").SetValue(source, context.GetName(), null);
            }

            return source;
        }

    }