ZrAdminNetCore这个项目是参考若依框架改造的,前者是.netcore项目,后者是Java项目。只要学会一个,其他一个很容易看懂的。当然你必须有这两种语言的基础,否则还是有点困难。若依框架这个项目目前很有名气,很多公司的项目都是参考它,并基于它改造变成公司的项目。
公司如果想快速出成果,又不想自己从头开始,选择它是个不错的。今天我来总结.netcore版本的项目。
我们下载下来项目,用vs打开,然后运行出现这样的结果。表示运行成功了!
netcore2.2以后都会生成exe文件 项目解构
一基础类设施层
1.1 基础类
这里有日志特性类,状态类,异常类,一些帮助类
1.2 代码生成器
这里是根据数据表格,生成业务模块的处理逻辑代码
1.3 通用类
这里有两个缓存类,阿里云存储类,邮箱处理类,工具类。
二 业务链接层
2.1 model 层
这个很好理解,就是实体层
2.2 ZR.Repository 层
这个是仓储层
2.3 ZR.Service 层
这个服务层
三 ui 层
这里有各个模块的控制器也是调用服务层
四 定时任务
五 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
// });
// });
},
运行结果
参考链接 :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;
}
}