1、AdminLTE
一个基于 bootstrap 的轻量级后台模板
2、AdminLTE 文档
在线中文Demo:http://adminlte.la998.com/
在线中文文档:http://adminlte.la998.com/documentation/index.html
Github:https://github.com/almasaeed2010/AdminLTE/releases
3、AdminLTE 布局
AdminLTE依赖于两个主要框架:JQ和Bootstrap,其他插件可以按需增加。
从文档可以知道,使用AdminLTE主要有四个部分:
-
包装.wrapper。包裹整个网站的div。
-
主标题.main-header。包含徽标和导航栏。
-
边栏.sidebar-wrapper。包含用户面板和侧边栏菜单。
-
内容.content-wrapper。包含页眉和内容。
在文档中,可以找到下载地址,本文示例是使用最新的版本V2.4.5。
4、Asp.Net Core Razor
新建项目Asp.net Core Web应用程序,默认就是Razor Pages,然后添加相应的模块,
如图:本文使用的SDK版本为:dotNet Core 2.1。
5、First
在Asp.Net Core项目中,引用AdminLTE,在wwwroot仅添加如图三个文件夹即可:
-
bower_components 基本组件。
-
dist adminlte的主要文件。
-
plugins 其他插件。
6、Second
在_Layout.cshtml文件中添加引入相关文件:
<!-- Tell the browser to be responsive to screen width --> <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport"> <!-- Bootstrap 3.3.7 --> <link rel="stylesheet" href="~/adminlte/bower_components/bootstrap/dist/css/bootstrap.min.css"> <!-- Font Awesome --> <link rel="stylesheet" href="~/adminlte/bower_components/font-awesome/css/font-awesome.min.css"> <!-- Ionicons --> <link href="~/adminlte/bower_components/Ionicons/css/ionicons.min.css" rel="stylesheet" /> <!-- Theme style --> <link rel="stylesheet" href="~/adminlte/dist/css/AdminLTE.min.css"> <!-- AdminLTE Skins. Choose a skin from the css/skins folder instead of downloading all of them to reduce the load. --> <link rel="stylesheet" href="~/adminlte/dist/css/skins/_all-skins.min.css"> <!-- Pace style --> <link href="~/adminlte/plugins/pace/pace.min.css" rel="stylesheet" /> <link href="~/css/common.css" rel="stylesheet" /> <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <!-- Google Font --> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
在body中,添加js:
<!-- jQuery 3 --> <script src="~/adminlte/bower_components/jquery/dist/jquery.min.js"></script> <!-- jQuery UI 1.11.4 --> <script src="~/adminlte/bower_components/jquery-ui/jquery-ui.min.js"></script> <!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip --> <script> $.widget.bridge('uibutton', $.ui.button); </script> <!-- Bootstrap 3.3.7 --> <script src="~/adminlte/bower_components/bootstrap/dist/js/bootstrap.min.js"></script> <!-- Slimscroll --> <script src="~/adminlte/bower_components/jquery-slimscroll/jquery.slimscroll.min.js"></script> <!-- FastClick --> <script src="~/adminlte/bower_components/fastclick/lib/fastclick.js"></script> <!-- AdminLTE App --> <script src="~/adminlte/dist/js/adminlte.min.js"></script> <!-- Skin --> <script type="text/javascript" src="~/adminlte/dist/js/sidebarskins.js" charset="gbk"></script>
sidebarskins.js是个人汉化的侧边栏皮肤,框架包里不存在
7、Third
开始使用AdminLTE
最后就可以运行项目来预览一下效果了:
移动端的效果:
需要注意的是,点击这个小图标可以实现左侧边栏收缩展开的功能,当只有侧边栏可以正常收缩展开但Logo无动于衷的时候,
你可能是少了【sidebar-mini】样式和【logo-mini】logo小图的引用
8、添加一个登陆
登录界面写得比较简约,在Pages文件夹中,添加一个Razor界面
@page @model AdminLTE.Net.Web.Pages.LoginModel @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>登录 - AdminLTE.Net.Web</title> <meta name="developer" content="EminemJK"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css" rel="stylesheet" /> <link href="~/adminlte/dist/css/AdminLTE.min.css" rel="stylesheet" /> <link href="~/css/login.css" rel="stylesheet" /> </head> <body> <div> <div class="row"> <div class="loginHeader"> <img class="logo-img" src="~/images/banana_logo.ico" /> <h1 class="logo-name">Banana</h1> <div class="clearfix"></div> </div> </div> <div class="row login-bg"> <div class="loginInBox"> @if (!string.IsNullOrEmpty(Model.Message)) { <p class="login-box-msg" style="color:red">@Model.Message</p> } else { <p class="login-box-msg">Sign in to start your session</p> } <form method="post"> <div class="form-group has-feedback"> <input type="text" class="form-control" asp-for="Login.UserName"> <span class="glyphicon glyphicon-user form-control-feedback"></span> </div> <div class="form-group has-feedback"> <input type="password" class="form-control" asp-for="Login.Password"> <span class="glyphicon glyphicon-lock form-control-feedback"></span> </div> <button type="submit" class="btn btn-primary btn-block btn-flat login-btn">Sign In</button> </form> </div> </div> </div> <footer class="footer"> <strong>Copyright © 2018 <a href="http://www.cnblogs.com/EminemJK/">EminemJK</a>.</strong> All rights reserved. </footer> </body> </html>
在Startup中引入Authentication身份验证:
services.AddAuthentication(CookieService.AuthenticationScheme) .AddCookie(CookieService.AuthenticationScheme, o => { o.LoginPath = new PathString("/Login"); });
Configure方法内调用
app.UseAuthentication();
在Login.cshtml.cs中增加一个OnPostAsync的方法:
[HttpPost] public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { Message = ModelState.Root.Errors[0].ErrorMessage; } else { var user = userService.Login(Login.UserName, Login.Password); if (user != null) { VUserModel model = new VUserModel() { Id = user.Id, UserName = user.UserName, Time = DateTime.Now }; var identity = new ClaimsIdentity(CookieService.AuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Sid, CookieService.GetDesEncrypt(model))); await HttpContext.SignInAsync(CookieService.AuthenticationScheme, new ClaimsPrincipal(identity), new AuthenticationProperties() { //记住我 IsPersistent = true, //过期时间 ExpiresUtc = DateTimeOffset.Now.Add(TimeSpan.FromMinutes(30)) }); return RedirectToPage("./Index"); } Message = "登录失败,用户名密码不正确。"; } return Page(); }
userService和CookieService都是在业务层定义的,gayhub会在文章末尾。
在.Net Core Razor中,xx.cshtml.cs中默认触发的是Get和Post方法,
-
OnGet
-
OnPost
-
OnGetAsync
-
OnPostAsync
如果是需要自定义的,举个栗子,定义为:OnPostLoginAsync,然后在Form表单提交的【按钮】增加asp-page-handler="Login",
详细的推荐大家阅读这篇文章:ASP.NET Core - Razor页面之Handlers处理方法。
接着,然后再Index和需要身份验证的地方都加上Authorize特性即可:
namespace AdminLTE.Net.Web.Pages { [Authorize(AuthenticationSchemes = CookieService.AuthenticationScheme)] public class IndexModel : BasePageModel { public void OnGet() { } } }
9、踩坑
一、Ajax Post请求, 400 Bad Request
function uploadfile() { var file = $("#input-userimg")[0].files[0]; var data = new FormData(); data.append('file', file); $.ajax({ url: "/Account/UserList?handler=Upload", type: 'POST', data: data, contentType: false, processData: false, success: function (returndata) { $("#user-img").attr('src', returndata.path); }, error: function (a, b, c) { alert('上传失败') } }); };
折腾许久,原因是Razor被设计为可以自动防止跨站请求伪造(CSRF / XSRF)攻击。你不必编写任何其他代码。Razor页面中自动包含防伪令牌生成和验证。
这里请求失败,是因为POST没有提交AntiForgeryToken。
解决方法:
1.增加"XSRF-TOKEN"标识到框架中
//增加了"XSRF-TOKEN"标识,值为表单自动生成的防伪标记 services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
2.页面*.cshtml头部加上
@Html.AntiForgeryToken()
3.ajax引入
function uploadfile() { var file = $("#input-userimg")[0].files[0]; var data = new FormData(); data.append('file', file); $.ajax({ url: "/Account/UserList?handler=Upload", type: 'POST', data: data, contentType: false, processData: false, beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); }, success: function (returndata) { $("#user-img").attr('src', returndata.path); }, error: function (a, b, c) { alert('上传失败') } }); };
然后既可以正常访问Handler
二、DataTables参数实例加说明
var table = $('#userListTable').DataTable({ "processing": true, "serverSide": true, "ajax": function (data, callback, settings) { //data的参数请参考: https://segmentfault.com/a/1190000004478726 var param = {}; param.draw = data.draw; param.pageNum = (data.start / data.length) + 1; param.pageSize = data.length; param.sex = $('#select-sex option:selected').val(); param.phone = $('#input-phone').val(); param.name = $('#input-name').val(); $.ajax({ type: "GET", data: param, url: "/Account/UserList?handler=UserPage", dataType: "json", success: function (data) { //成功后回调自动渲染 callback(data); } }); }, 'columns': [ { 'data': 'id' }, { 'data': 'name' }, { 'data': 'userName' }, { 'data': 'sexString' }, { 'data': 'phone' }, { 'data': 'createTime' }, { 'data': 'enableString', 'render': function (data, type, row) { if (row.enable == 1) return '<span style="color:#19be6b" >' + row.enableString + '</span>'; else return '<span style="color:#ed3f14" >' + row.enableString + '</span>'; } }, { 'data': null, 'render': function (data, type, row) { return '<a id="btn-edit" class="btn btn-success btn-xs" title="编辑" onClick=btn_edit(' + row.id + ')><i class="fa fa-edit"></i>编辑</a> ' + '<a id="btn-edit" class="btn btn-danger btn-xs" title="删除" onClick=btn_edit(' + row.id + ')><i class="fa fa-trash " title="删除" style="cursor:pointer"></i>删除</a>'; } }, ], //datatable设置参数 http://www.datatables.club/reference/option/ 'paging': true, //启用分页 'lengthChange': true, //设置每页数量 'searching': false, 'ordering': false, 'info': true, 'autoWidth': false, //设置中文 'language': { "sProcessing": "玩命加载中...", "sLengthMenu": "每页显示显示 _MENU_", "sZeroRecords": "没有匹配结果", "sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项", "sInfoEmpty": "显示第 0 至 0 项结果,共 0 项", "sInfoFiltered": "(由 _MAX_ 项结果过滤)", "sInfoPostFix": "", "sSearch": "搜索:", "sUrl": "", "sEmptyTable": "表中数据为空", "sLoadingRecords": "玩命加载中...", "sInfoThousands": ",", "oPaginate": { "sFirst": "首页", "sPrevious": "上页", "sNext": "下页", "sLast": "末页" }, "oAria": { "sSortAscending": ": 以升序排列此列", "sSortDescending": ": 以降序排列此列" } } });
10、Banana
Demo中会使用到这两个个人封装的组件:
Banana.Uow是基于Dapper封装的工作单元和仓储;
Banana.Utility是常用的工具类,有Redis,加解密,拼音等等;