Layui+MVC+EF (项目从新创建开始)

最近学习Layui ,就准备通过Layui来实现之前练习的项目,

先创建一个新的Web 空项目,选MVC

新建项目

创建各种类库,模块之间添加引用,并安装必要Nuget包(EF包)

     模块名称            模块之间引用                    安装Nuget包


BizLogic-------业务逻辑      (BizModel.DLL, DataEntity.DLL, Util.DLL)                      entityframework


BizModel------实体类      


DataEntity-----DB映射模块             (Util.DLL)                     entityframework 


Util---------------公共类库


Web--------------界面UI     (BizLogic.DLL, BizModel.DLL, DataEntity.DLL, Util.DLL)       entityframework

 创建并生成EF

  

 中小项目 可以直接关闭懒加载

 连接DB配置,移动到UI层

 下面编写公共方法

DataResult.cs ------------通用数据结果类

PagedResult.cs----------分页通过数据结果

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CarterHotel.Util
{
    /// <summary>
    /// 通用数据结果类
    /// </summary>
    /// <typeparam name="TModel"></typeparam>
    public class DataResult<TModel>
    {
        /// <summary>
        /// 操作是否成功
        /// </summary>
        public bool IsSuccess { get; set; }
        /// <summary>
        /// 错误提示信息
        /// </summary>
        public string ErrorMessage { get; set; }
        /// <summary>
        /// 数据结果
        /// </summary>
        public TModel Data { get; set; }

        public DataResult()
        {
            IsSuccess = true;
        }

        public DataResult(string errorMessage)
        {
            IsSuccess = false;
            ErrorMessage = errorMessage;
        }

        public DataResult(TModel data)
        {
            IsSuccess = true;
            Data = data;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CarterHotel.Util
{
    /// <summary>
    /// 分页通过数据结果
    /// </summary>
    public class PagedResult<TModel>:DataResult<TModel>//继承DataResult
    {
        /// <summary>
        /// 当前页索引
        /// </summary>
        public int PageIndex { get; set; }
        
        /// <summary>
        /// 每页记录条数
        /// </summary>
        public int PageSize { get; set; }

        /// <summary>
        /// 数据记录条数
        /// </summary>
        public int TotalCount { get; set; }

        /// <summary>
        /// 当前页数据
        /// </summary>
        public List<TModel> CurrentPageData { get; set; }

        public PagedResult(int pageIndex, int pageSize, int totalCount, List<TModel> currentPageData)
        {
            IsSuccess = true;
            PageIndex = pageIndex;
            TotalCount = totalCount;
            CurrentPageData = currentPageData;
        }

        public PagedResult(int totalCount, List<TModel> currentPageData)
        {
            IsSuccess = true;
            TotalCount = totalCount;
            CurrentPageData = currentPageData;
        }
    }
}

创建EncryptionMD5.cs 单向MD5加密

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace CarterHotel.Util
{
    /// <summary>
    /// MD5
    /// 单向加密
    /// </summary>
    public class EncryptionMD5
    {
        /// <summary>
        /// 获得一个字符串的加密密文
        /// 此密文为单向加密,即不可逆(解密)密文
        /// </summary>
        /// <param name="plainText">待加密明文</param>
        /// <returns>已加密密文</returns>
        public static string EncryptString(string plainText)
        {
            return EncryptStringMD5(plainText);
        }

        /// <summary>
        /// 获得一个字符串的加密密文
        /// 此密文为单向加密,即不可逆(解密)密文
        /// </summary>
        /// <param name="plainText">待加密明文</param>
        /// <returns>已加密密文</returns>
        public static string EncryptStringMD5(string plainText)
        {
            MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
            byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(plainText));
            StringBuilder encryptText = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                encryptText.Append(data[i].ToString("x2"));
            }
            return encryptText.ToString();

        }

        /// <summary>
        /// 判断明文与密文是否相符
        /// </summary>
        /// <param name="plainText">待检查的明文</param>
        /// <param name="encryptText">待检查的密文</param>
        /// <returns>bool</returns>
        public static bool EqualEncryptString(string plainText, string encryptText)
        {
            return EqualEncryptStringMD5(plainText, encryptText);
        }

        /// <summary>
        /// 判断明文与密文是否相符
        /// </summary>
        /// <param name="plainText">待检查的明文</param>
        /// <param name="encryptText">待检查的密文</param>
        /// <returns>bool</returns>
        public static bool EqualEncryptStringMD5(string plainText, string encryptText)
        {
            bool result = false;
            if (string.IsNullOrEmpty(plainText) || string.IsNullOrEmpty(encryptText))
                return result;
            result = EncryptStringMD5(plainText).Equals(encryptText);
            return result;
        }
    }
}

 接下来对公共错误页面的编写

 在UI层新建StaticContent文件夹 并将下载好的Layui 样式 js 文件放到文件夹下,并添加对应的视图,异常处理过滤器

 下面 错误页面html代码

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>错误提示</title>
    <link href="~/StaticContent/layui/css/layui.css" rel="stylesheet" />
    <style>
        .layadmin-tips {
            margin-top: 30px;
            text-align: center
        }

            .layadmin-tips .layui-icon[face] {
                display: inline-block;
                font-size: 300px;
                color: #393D49;
            }

            .layadmin-tips .layui-text {
                width: 500px;
                margin: 30px auto;
                padding-top: 20px;
                border-top: 5px solid #009688;
                font-size: 22px
            }
    </style>
</head>
<body>
    <div class="layui-fluid">
        <div class="layadmin-tips">
            <i class="layui-icon layui-icon-face-surprised" face></i>
            <div class="layui-text">好像出错了</div>
        </div>
    </div>
</body>
</html>

增加异常处理过滤器 App_Start 新创建Filter-->HandleExceptionFileterAttribute类 并实现IExceptionFilter 接口; 

2,在App_Start 下创建FilterConfig 过滤器配置类,并注册过滤器

 代码如下

using CarterHotel.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace CarterHotel.Web.App_Start.Filters
{
    /// <summary>
    /// 异常处理过滤器
    /// </summary>
    public class HandleExceptionFileterAttribute : IExceptionFilter
    {
        public void OnException(ExceptionContext filterContext)
        {
            //判断当前的请求是否为ajax
            bool isAjaxRequest = filterContext.HttpContext.Request.IsAjaxRequest();
            if (isAjaxRequest)
            {
                filterContext.Result = new JsonResult()
                {
                    Data = new DataResult<string>(errorMessage: "系统发生错误")
                };
            }
            else
            {
                filterContext.Result = new RedirectResult(url: "/Error");
            }

            //异常发生后,进行处理以后,需要告诉应用程序,这个异常处理意见处理过了
            filterContext.ExceptionHandled = true;
        }
    }
}

注册过滤器

using CarterHotel.Web.App_Start.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace CarterHotel.Web.App_Start
{
    /// <summary>
    /// 过滤器配置类
    /// </summary>
    public static class FilterConfig
    {
        /// <summary>
        /// 过滤器注册
        /// </summary>
        /// <param name="filters"></param>
        public static void RegisterFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleExceptionFileterAttribute());
        }
    }
}

 控制器里增加Home控制器

 此时此刻公共错误页面已经完成,我们可以测试,公共错误页面是否有问题;

JS文件

StaticContent-->scripts-->unobtrusive.js(内容如下)

layui.define(["jquery"], function (exports) {
    var jQuery = layui.jquery;

    (function ($) {
        var data_click = "unobtrusiveAjaxClick",
            data_target = "unobtrusiveAjaxClickTarget",
            data_validation = "unobtrusiveValidation";

        function getFunction(code, argNames) {
            var fn = window, parts = (code || "").split(".");
            while (fn && parts.length) {
                fn = fn[parts.shift()];
            }
            if (typeof (fn) === "function") {
                return fn;
            }
            argNames.push(code);
            return Function.constructor.apply(null, argNames);
        }

        function isMethodProxySafe(method) {
            return method === "GET" || method === "POST";
        }

        function asyncOnBeforeSend(xhr, method) {
            if (!isMethodProxySafe(method)) {
                xhr.setRequestHeader("X-HTTP-Method-Override", method);
            }
        }

        function asyncOnSuccess(element, data, contentType) {
            var mode;

            if (contentType.indexOf("application/x-javascript") !== -1) {  // jQuery already executes JavaScript for us
                return;
            }

            mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase();
            $(element.getAttribute("data-ajax-update")).each(function (i, update) {
                var top;

                switch (mode) {
                    case "BEFORE":
                        top = update.firstChild;
                        $("<div />").html(data).contents().each(function () {
                            update.insertBefore(this, top);
                        });
                        break;
                    case "AFTER":
                        $("<div />").html(data).contents().each(function () {
                            update.appendChild(this);
                        });
                        break;
                    case "REPLACE-WITH":
                        $(update).replaceWith(data);
                        break;
                    default:
                        $(update).html(data);
                        break;
                }
            });
        }

        function asyncRequest(element, options) {
            var confirm, loading, method, duration;

            confirm = element.getAttribute("data-ajax-confirm");
            if (confirm && !window.confirm(confirm)) {
                return;
            }

            loading = $(element.getAttribute("data-ajax-loading"));
            duration = parseInt(element.getAttribute("data-ajax-loading-duration"), 10) || 0;

            $.extend(options, {
                type: element.getAttribute("data-ajax-method") || undefined,
                url: element.getAttribute("data-ajax-url") || undefined,
                cache: !!element.getAttribute("data-ajax-cache"),
                beforeSend: function (xhr) {
                    var result;
                    asyncOnBeforeSend(xhr, method);
                    result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(element, arguments);
                    if (result !== false) {
                        loading.show(duration);
                    }
                    return result;
                },
                complete: function () {
                    loading.hide(duration);
                    getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(element, arguments);
                },
                success: function (data, status, xhr) {
                    asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html");
                    getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(element, arguments);
                },
                error: function () {
                    getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"]).apply(element, arguments);
                }
            });

            options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });

            method = options.type.toUpperCase();
            if (!isMethodProxySafe(method)) {
                options.type = "POST";
                options.data.push({ name: "X-HTTP-Method-Override", value: method });
            }

            $.ajax(options);
        }

        function validate(form) {
            var validationInfo = $(form).data(data_validation);
            return !validationInfo || !validationInfo.validate || validationInfo.validate();
        }

        $(document).on("click", "a[data-ajax=true]", function (evt) {
            evt.preventDefault();
            asyncRequest(this, {
                url: this.href,
                type: "GET",
                data: []
            });
        });

        $(document).on("click", "form[data-ajax=true] input[type=image]", function (evt) {
            var name = evt.target.name,
                target = $(evt.target),
                form = $(target.parents("form")[0]),
                offset = target.offset();

            form.data(data_click, [
                { name: name + ".x", value: Math.round(evt.pageX - offset.left) },
                { name: name + ".y", value: Math.round(evt.pageY - offset.top) }
            ]);

            setTimeout(function () {
                form.removeData(data_click);
            }, 0);
        });

        $(document).on("click", "form[data-ajax=true] :submit", function (evt) {
            var name = evt.currentTarget.name,
                target = $(evt.target),
                form = $(target.parents("form")[0]);

            form.data(data_click, name ? [{ name: name, value: evt.currentTarget.value }] : []);
            form.data(data_target, target);

            setTimeout(function () {
                form.removeData(data_click);
                form.removeData(data_target);
            }, 0);
        });

        $(document).on("submit", "form[data-ajax=true]", function (evt) {
            var clickInfo = $(this).data(data_click) || [],
                clickTarget = $(this).data(data_target),
                isCancel = clickTarget && clickTarget.hasClass("cancel");
            evt.preventDefault();
            if (!isCancel && !validate(this)) {
                return;
            }
            asyncRequest(this, {
                url: this.action,
                type: this.method || "GET",
                data: clickInfo.concat($(this).serializeArray())
            });
        });
    }(jQuery));
    exports('unobtrusive',null)
});

StaticContentimageuser.png 图片如下

二, 实现基于layui前台页面后台管理的搭建

1, 添加区域

2, 在Shared-->_Layout.cshtml  (新增)

3, Views-->_ViewStart.cshtml   (新增)

  _Layout.cshtml(下面增加的js需要在这里注册)

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>后台管理</title>
    <link href="~/StaticContent/layui/css/layui.css" rel="stylesheet" />
    @RenderSection("styles",false)
</head>
<body>
    @RenderBody()
    <script src="~/StaticContent/layui/layui.js"></script>
    <script type="text/javascript">

//js模块自定义,需要注意下

layui.config({
base: '/StaticContent/scripts/'
}).extend({
request: 'request',
unobtrusive: 'unobtrusive'
})

  

    </script>
    @RenderSection("scripts",false);
</body>
</html>

_ViewStart.cshtml

@{ 

    Layout = "~/Areas/Manage/Views/Shared/_Layout.cshtml";
}

在增加的区域里控制器增加Main控制器,并添加对应的视图及控制器

 视图代码

<body class="layui-layout-body">
    <div class="layui-layout-admin">
        <!--头部内容-->
        <div class="layui-header">
            <div class="layui-logo">后台管理</div>
            <ul class="layui-nav layui-layout-right">
                <li class="layui-nav-item">
                    <a href="#">
                        <img src="~/StaticContent/image/user.png" class="layui-nav-img" /> @View.UserName
                    </a>
                    <dl class="layui-nav-child">
                        <dd><a href="#">修改密码</a></dd>
                        <dd><a href="@Url.Action("LoginOut","Account")">退出登入</a></dd>
                    </dl>
                </li>
            </ul>
        </div>
        <!--侧边导航-->
        <div class="layui-side layui-bg-black">
            <div class="layui-side-scroll">
                <ul class="layui-nav layui-nav-tree">
                    <li class="layui-nav-item">
                        <a href="javascript:;">
                            <i class="layui-icon layui-icon-home">主页</i>
                        </a>
                    </li>
                </ul>
            </div>
        </div>
        <!--主内容区-->
        <div class="layui-body" style="overflow:hidden">
            <iframe src="https://www.baidu.com/" frameborder="0" style="height:100%;100%"></iframe>
        </div>
        <!--底部区域-->
        <div class="layui-footer">
            ©1999-2020 个人开发
        </div>
    </div>
</body>
@section Scripts
{
    <script type="text/javascript">
        layui.use('element')
    </script>
}

Main控制器代码如下,随便在web.config 增加 form授权认证

using System.Web.Mvc;

namespace CreateTest.Web.Areas.Manage.Controllers
{
    public class MainController : Controller
    {
        // GET: Manage/Main
        [Authorize]
        public ActionResult Index()
        {
            ViewBag.UserName = HttpContext.User.Identity.Name;
            return View();
        }

        public ActionResult Main()
        {
            return View();
        }
    }
}
View Code

运行测试,整个页面已经搭建了7788,运行页面如下

 主页面是用的度娘做的测试,下面我们创建Main页面

 Main页面增加,测试OK的

 到这里我们已经整个框架已经搭建的差不多了,下面将实现具体功能的实现,

一, 实现登入功能

1, 完成登入业务逻辑

2, 完成 Account控制器登入(退出)功能

3, 实现前台登入页面

using CarterHotel.DataEntity;
using CarterHotel.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CarterHotel.BizLogic.AdminManage
{
    public class AccountService
    {
        /// <summary>
        /// 管理员登入
        /// </summary>
        /// <param name="saveEntity">账号密码</param>
        /// <returns></returns>
        public DataResult<SysAdmins> AdminLogin(SysAdmins saveEntity)
        {
            using (HotelDBConnection db = new HotelDBConnection())
            {
                SysAdmins getEntity = db.SysAdmins.FirstOrDefault(a => a.LoginId == saveEntity.LoginId);
                if (getEntity == null)
                {
                    return new DataResult<SysAdmins>("用户不存在");
                }
                else
                {
                    if (!EncryptionMD5.EqualEncryptStringMD5(saveEntity.LoginPwd,getEntity.LoginPwd))
                    {
                        return new DataResult<SysAdmins>("密码不正确");
                    }
                    else
                    {
                        return new DataResult<SysAdmins>(getEntity);
                    }
                }
            }
        }
    }
}
View Code

 AccountController 控制器代码

using CreateTest.BizLogic.AdminManage;
using CreateTest.DataEntity;
using CreateTest.Util.Result;
using System.Web.Mvc;
using System.Web.Security;

namespace CreateTest.Web.Areas.Manage.Controllers
{
    public class AccountController : Controller
    {
        private AccountService _accountService = new AccountService();

        // GET: Manage/Account
        /// <summary>
        /// 登入视图跳转
        /// </summary>
        /// <returns></returns>
        public ActionResult Login()
        {
            return View();
        }
        /// <summary>
        /// 用户登入
        /// </summary>
        /// <param name="sysAdmin"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Login(SysAdmin sysAdmin)
        {
           DataResult<SysAdmin> resultAdmin= _accountService.AdminLogin(sysAdmin);
            if (resultAdmin.IsSuccess)
            {
                FormsAuthentication.SetAuthCookie(resultAdmin.Data.LoginName,true);
            }
            return Json(resultAdmin);
        }

        /// <summary>
        /// 退出登入
        /// </summary>
        /// <returns></returns>
        public ActionResult LoginOut()
        {
            FormsAuthentication.SignOut();
            return RedirectToAction("Login");
        }
    }
}
View Code

Login.cshtml

@model CreateTest.DataEntity.SysAdmin
<div class="layadmin-user-login layadmin-user-display-show" id="LAY-user-login">
    <div class="layadmin-user-login-main">
        <div class="layadmin-user-login-box layadmin-user-login-header">
            <h2>管理系统</h2>
            <p>后台管理系统</p>
        </div>
        @using (Ajax.BeginForm("Login", "Account", FormMethod.Post, new AjaxOptions()
        {
            OnBegin = "OnAjaxBegin",
            OnFailure = "OnAjaxFailure",
            OnSuccess = "OnAjaxSuccess",
            OnComplete = "OnLoginComplete",
        }))
        {
            <div class="layadmin-user-login-box layadmin-user-login-body layui-form">
                <div class="layui-form-item">
                    <label class="layadmin-user-login-icon layui-icon layui-icon-username" for="LoginId"></label>
                    @Html.TextBoxFor(a => a.LoginId, new Dictionary<string, object>()
                    {
                        { "class","layui-input"},
                        { "autocomplete","off"},
                        { "lay-verify","required"},
                        { "placeholder","请输入账号"}
                    })
                </div>
                <div class="layui-form-item">
                    <label class="layadmin-user-login-icon layui-icon layui-icon-password" for="LoginPwd"></label>
                    @Html.PasswordFor(a => a.LoginPwd, new Dictionary<string, object>()
                    {
                        { "class","layui-input"},
                        { "autocomplete","off"},
                        { "lay-verify","required"},
                        { "placeholder","请输入密码"}
                    })
                </div>
                <div class="layui-form-item">
                    <button class="layui-btn layui-btn-fluid" lay-submit>
                        登入
                    </button>
                </div>
            </div>
        }
    </div>
</div>

@section Styles
{
    <link href="~/StaticContent/css/login.css" rel="stylesheet" />
}

@section Scripts
{
    <script type="text/javascript">
        layui.use(['form', 'unobtrusive', 'request'], function () {
            var request = layui.request;
            window.OnLoginComplete = function (response) {
                debugger
                var res = response.responseJSON;
                request.handleResult(res, function () {
                    debugger
                    window.location.href = "/Manage/Main";
                })
            }
        })
    </script>
}
View Code

创建js文件,

layui.define('layer', function (exports) {
    var layer = self === parent ? layui.layer : top.layui.layer;//判断是否为顶层页面
    var layerIndex;//定义加载层索引,因为加载层不会自动关闭

    //请求开始,开启弹窗
    window.OnAjaxBegin = function () {
        layerIndex = layer.load();
    }

    //请求失败时,提示错误信息
    window.OnAjaxFailure = function () {
        layer.close(layerIndex);
        layer.alert('请求错误', {
            title: '信息提示',
            icon: 2
        });
    }

    //请求完成时,关闭弹窗
    window.OnAjaxSuccess = function () {
        layer.close(layerIndex);
    }

    var instance = {
        //处理返回结果
        handleResult: function (res, success) {
            if (!res.IsSuccess) {
                layer.alert(res.ErrorMessage, {
                    title: '信息提示',
                    icon: 2
                });
            } else {
                success && success(res.Data);
            }
        }
    }

    exports('request', instance)
})
View Code

 写到这里应该已经差不多了, 测试发现登入页面只会返回json数据,登入不成功的模态框无法出现,

要将自定义的JS模块引入到_Layout.cshtml页面中

 再次测试,

 已经可以成功登入主页面

本人也 不是太会排版, 附上下载地址:http://1.15.96.17:8011/TestWeb.zip

原文地址:https://www.cnblogs.com/victor-huang/p/13439698.html