MVC5 网站开发之七 用户功能 2 用户添加和浏览

一、数据存储层

1、查找分页列表

在写用户列表时遇到了问题,考虑到用户可能会较多的情况需要分页,在数据存储层写的方法是public IQueryable<T> FindPageList<TKey>(int pageSize, int pageIndex, out int totalNumber, Expression<Func<T, bool>> where, Expression<Func<T, TKey>> order, bool asc)。

主要问题就在红色的order这儿,这个参数不好传递,比如:如果是已ID来排序哪TKey类型是int,如果以注册时间来排序哪TKey类型就是datetime。如果我在业务逻辑层写一个函数可以支持选择排序类型,那么我没有办法声明一个变量既可以存储TKey为int的值,又可以存储datetime的值,那么排序就要写成下面这个样子,感觉不舒服。

//排序
            switch(order)
            {
                case 0://ID升序
                    _users.Items = Repository.FindPageList((int)pageSize, (int)pageIndex, out _users.TotalNumber, _where, u => u.UserID, true).ToList();
                    break;
                case 1://ID降序
                    _users.Items = Repository.FindPageList((int)pageSize, (int)pageIndex, out _users.TotalNumber, _where, u => u.UserID, false).ToList();
                    break;
                case 2://注册时间降序
                    _users.Items = Repository.FindPageList((int)pageSize, (int)pageIndex, out _users.TotalNumber, _where, u => u.RegTime, true).ToList();
                    break;
                case 3://注册时间升序
                    _users.Items = Repository.FindPageList((int)pageSize, (int)pageIndex, out _users.TotalNumber, _where, u => u.RegTime, false).ToList();
                    break;
                case 4://最后登录时间升序
                    _users.Items = Repository.FindPageList((int)pageSize, (int)pageIndex, out _users.TotalNumber, _where, u => u.LastLoginTime, true).ToList();
                    break;
                case 5://最后登录时间降序
                    _users.Items = Repository.FindPageList((int)pageSize, (int)pageIndex, out _users.TotalNumber, _where, u => u.LastLoginTime, false).ToList();
                    break;
                default://ID降序
                    _users.Items = Repository.FindPageList((int)pageSize, (int)pageIndex, out _users.TotalNumber, _where, u => u.UserID, false).ToList();
                    break;
            }

后来将TKey设为dynamic类型,不论Expression<Func<T, dynamic>> order = u => u.UserID  或者u => u.RegTime都可以编译通过,但是一运行就会出错。

前几天没写博客一直在考虑这个问题,后来还是换成用字符串的方式来动态排序。 步骤如下:

Ninesky.DataLibrary[右键]->添加->类,输入类名OrderParam

namespace Ninesky.DataLibrary
{
    /// <summary>
    /// 排序参数
    /// </summary>
    public class OrderParam
    {
        /// <summary>
        /// 属性名
        /// </summary>
        public string PropertyName { get; set; }

        /// <summary>
        /// 排序方式
        /// </summary>
        public OrderMethod Method { get; set; }
    }

    /// <summary>
    /// 排序方式
    /// </summary>
    public enum OrderMethod
    {
        /// <summary>
        /// 正序
        /// </summary>
        ASC,
        /// <summary>
        /// 倒序
        /// </summary>
        DESC
    }
}

打开Ninesky.DataLibrary/Repository.cs,将方法public IQueryable<T> FindPageList<TKey>(int pageSize, int pageIndex, out int totalNumber, Expression<Func<T, bool>> where, Expression<Func<T, TKey>> order, bool asc)的代码修改为

/// <summary>
        /// 查找分页列表
        /// </summary>
        /// <param name="pageSize">每页记录数。必须大于1</param>
        /// <param name="pageIndex">页码。首页从1开始,页码必须大于1</param>
        /// <param name="totalNumber">总记录数</param>
        /// <param name="where">查询表达式</param>
        /// <param name="orderParams">排序【null-不设置】</param>
        public IQueryable<T> FindPageList(int pageSize, int pageIndex, out int totalNumber, Expression<Func<T, bool>> where, OrderParam[] orderParams)
        {
            if (pageIndex < 1) pageIndex = 1;
            if (pageSize < 1) pageSize = 10;
            IQueryable<T> _list = DbContext.Set<T>().Where(where);
            var _orderParames = Expression.Parameter(typeof(T), "o");
            if (orderParams != null && orderParams.Length > 0)
            {
                for (int i = 0; i < orderParams.Length; i++)
                {
                    //根据属性名获取属性
                    var _property = typeof(T).GetProperty(orderParams[i].PropertyName);
                    //创建一个访问属性的表达式
                    var _propertyAccess = Expression.MakeMemberAccess(_orderParames, _property);
                    var _orderByExp = Expression.Lambda(_propertyAccess, _orderParames);
                    string _orderName = orderParams[i].Method == OrderMethod.ASC ? "OrderBy" : "OrderByDescending";
                    MethodCallExpression resultExp = Expression.Call(typeof(Queryable), _orderName, new Type[] { typeof(T), _property.PropertyType }, _list.Expression, Expression.Quote(_orderByExp));
                    _list = _list.Provider.CreateQuery<T>(resultExp);
                }
            }
            totalNumber = _list.Count();
            return _list.Skip((pageIndex - 1) * pageIndex).Take(pageSize);
        }

方法中排序参数(OrderParam[]) 使用数组,是考虑到多级排序的情况。对FindPageList重载代码进行修改,修改完的代码如下:

//查找实体分页列表
        #region FindPageList

        /// <summary>
        /// 查找分页列表
        /// </summary>
        /// <param name="pageSize">每页记录数。必须大于1</param>
        /// <param name="pageIndex">页码。首页从1开始,页码必须大于1</param>
        /// <param name="totalNumber">总记录数</param>
        /// <returns></returns>
        public IQueryable<T> FindPageList(int pageSize, int pageIndex, out int totalNumber)
        {
            OrderParam _orderParam = null;
            return FindPageList(pageSize, pageIndex, out totalNumber, _orderParam);
        }

        /// <summary>
        /// 查找分页列表
        /// </summary>
        /// <param name="pageSize">每页记录数。必须大于1</param>
        /// <param name="pageIndex">页码。首页从1开始,页码必须大于1</param>
        /// <param name="totalNumber">总记录数</param>
        /// <param name="order">排序键</param>
        /// <param name="asc">是否正序</param>
        /// <returns></returns>
        public IQueryable<T> FindPageList(int pageSize, int pageIndex, out int totalNumber, OrderParam orderParam)
        {
            return FindPageList(pageSize, pageIndex, out totalNumber, (T)=> true, orderParam);
        }

        /// <summary>
        /// 查找分页列表
        /// </summary>
        /// <param name="pageSize">每页记录数。必须大于1</param>
        /// <param name="pageIndex">页码。首页从1开始,页码必须大于1</param>
        /// <param name="totalNumber">总记录数</param>
        /// <param name="where">查询表达式</param>
        public IQueryable<T> FindPageList(int pageSize, int pageIndex, out int totalNumber, Expression<Func<T, bool>> where)
        {
            OrderParam _param = null;
            return FindPageList(pageSize, pageIndex, out totalNumber, where, _param);
        }

        /// <summary>
        /// 查找分页列表
        /// </summary>
        /// <param name="pageSize">每页记录数。</param>
        /// <param name="pageIndex">页码。首页从1开始</param>
        /// <param name="totalNumber">总记录数</param>
        /// <param name="where">查询表达式</param>
        /// <param name="orderParam">排序【null-不设置】</param>
        /// <returns></returns>
        public IQueryable<T> FindPageList(int pageSize, int pageIndex, out int totalNumber, Expression<Func<T, bool>> where, OrderParam orderParam)
        {
            OrderParam[] _orderParams = null;
            if (orderParam != null) _orderParams = new OrderParam[] { orderParam };
            return FindPageList(pageSize, pageIndex, out totalNumber, where, _orderParams);
        }

        /// <summary>
        /// 查找分页列表
        /// </summary>
        /// <param name="pageSize">每页记录数。</param>
        /// <param name="pageIndex">页码。首页从1开始</param>
        /// <param name="totalNumber">总记录数</param>
        /// <param name="where">查询表达式</param>
        /// <param name="orderParams">排序【null-不设置】</param>
        public IQueryable<T> FindPageList(int pageSize, int pageIndex, out int totalNumber, Expression<Func<T, bool>> where, OrderParam[] orderParams)
        {
            if (pageIndex < 1) pageIndex = 1;
            if (pageSize < 1) pageSize = 10;
            IQueryable<T> _list = DbContext.Set<T>().Where(where);
            var _orderParames = Expression.Parameter(typeof(T), "o");
            if (orderParams != null && orderParams.Length > 0)
            {
                for (int i = 0; i < orderParams.Length; i++)
                {
                    //根据属性名获取属性
                    var _property = typeof(T).GetProperty(orderParams[i].PropertyName);
                    //创建一个访问属性的表达式
                    var _propertyAccess = Expression.MakeMemberAccess(_orderParames, _property);
                    var _orderByExp = Expression.Lambda(_propertyAccess, _orderParames);
                    string _orderName = orderParams[i].Method == OrderMethod.ASC ? "OrderBy" : "OrderByDescending";
                    MethodCallExpression resultExp = Expression.Call(typeof(Queryable), _orderName, new Type[] { typeof(T), _property.PropertyType }, _list.Expression, Expression.Quote(_orderByExp));
                    _list = _list.Provider.CreateQuery<T>(resultExp);
                }
            }
            totalNumber = _list.Count();
            return _list.Skip((pageIndex - 1) * pageIndex).Take(pageSize);
        }

        #endregion

2、查找列表

基于分页列表同样的原因,对FindList方法也进行修改。

//查找实体列表
        #region FindList
        /// <summary>
        /// 查找实体列表
        /// </summary>
        /// <returns></returns>
        public IQueryable<T> FindList()
        {
            return DbContext.Set<T>();
        }

        /// <summary>
        /// 查找实体列表
        /// </summary>
        /// <param name="where">查询Lambda表达式</param>
        /// <returns></returns>
        public IQueryable<T> FindList(Expression<Func<T, bool>> where)
        {
            return DbContext.Set<T>().Where(where);
        }

        /// <summary>
        /// 查找实体列表
        /// </summary>
        /// <param name="where">查询Lambda表达式</param>
        /// <param name="number">获取的记录数量</param>
        /// <returns></returns>
        public IQueryable<T> FindList(Expression<Func<T, bool>> where, int number)
        {
            return DbContext.Set<T>().Where(where).Take(number);
        }

        /// <summary>
        /// 查找实体列表
        /// </summary>
        /// <param name="where">查询Lambda表达式</param>
        /// <param name="orderParam">排序参数</param>
        /// <returns></returns>
        public IQueryable<T> FindList(Expression<Func<T, bool>> where, OrderParam orderParam)
        {
            return FindList(where, orderParam, 0);
        }

        /// <summary>
        /// 查找实体列表
        /// </summary>
        /// <param name="where">查询Lambda表达式</param>
        /// <param name="orderParam">排序参数</param>
        /// <param name="number">获取的记录数量【0-不启用】</param>
        public IQueryable<T> FindList(Expression<Func<T, bool>> where, OrderParam orderParam, int number)
        {
            OrderParam[] _orderParams = null;
            if (orderParam != null) _orderParams = new OrderParam[] { orderParam };
            return FindList(where, _orderParams, number);
        }

        /// <summary>
        /// 查找实体列表
        /// </summary>
        /// <param name="where">查询Lambda表达式</param>
        /// <param name="orderParams">排序参数</param>
        /// <param name="number">获取的记录数量【0-不启用】</param>
        /// <returns></returns>
        public IQueryable<T> FindList(Expression<Func<T, bool>> where, OrderParam[] orderParams, int number)
        {
            var _list = DbContext.Set<T>().Where(where);
            var _orderParames = Expression.Parameter(typeof(T), "o");
            if (orderParams != null && orderParams.Length > 0)
            {
                for (int i = 0; i < orderParams.Length; i++)
                {
                    //根据属性名获取属性
                    var _property = typeof(T).GetProperty(orderParams[i].PropertyName);
                    //创建一个访问属性的表达式
                    var _propertyAccess = Expression.MakeMemberAccess(_orderParames, _property);
                    var _orderByExp = Expression.Lambda(_propertyAccess, _orderParames);
                    string _orderName = orderParams[i].Method == OrderMethod.ASC ? "OrderBy" : "OrderByDescending";
                    MethodCallExpression resultExp = Expression.Call(typeof(Queryable), _orderName, new Type[] { typeof(T), _property.PropertyType }, _list.Expression, Expression.Quote(_orderByExp));
                    _list = _list.Provider.CreateQuery<T>(resultExp);
                }
            }
            if (number > 0) _list = _list.Take(number);
            return _list;
        }
        #endregion

二、业务逻辑层

1、用户模型

Ninesky.Core【右键】->添加->类,输入类名User

引用System.ComponentModel.DataAnnotations命名空间

using System;
using System.ComponentModel.DataAnnotations;

namespace Ninesky.Core
{
    /// <summary>
    /// 用户模型
    /// </summary>
    public class User
    {
        [Key]
        public int UserID { get; set; }

        /// <summary>
        /// 角色ID
        /// </summary>
        [Required(ErrorMessage = "必须输入{0}")]
        [Display(Name = "角色ID")]
        public int RoleID { get; set; }

        /// <summary>
        /// 用户名
        /// </summary>
        [StringLength(50, MinimumLength = 4, ErrorMessage = "{0}长度为{2}-{1}个字符")]
        [Display(Name = "用户名")]
        public string Username { get; set; }

        /// <summary>
        /// 名称【可做昵称、真实姓名等】
        /// </summary>
        [StringLength(20, ErrorMessage = "{0}必须少于{1}个字符")]
        [Display(Name = "名称")]
        public string Name { get; set; }

        /// <summary>
        /// 性别【0-女,1-男,2-保密】
        /// </summary>
        [Required(ErrorMessage = "必须输入{0}")]
        [Range(0,2,ErrorMessage ="{0}范围{1}-{2}")]
        [Display(Name = "性别")]
        public int Sex { get; set; }

        /// <summary>
        /// 密码
        /// </summary>
        [DataType(DataType.Password)]
        [StringLength(256, ErrorMessage = "{0}长度少于{1}个字符")]
        [Display(Name = "密码")]
        public string Password { get; set; }

        /// <summary>
        /// Email
        /// </summary>
        [DataType(DataType.EmailAddress)]
        [StringLength(50, MinimumLength = 4, ErrorMessage = "{0}长度为{2}-{1}个字符")]
        [Display(Name = "Email")]
        public string Email { get; set; }

        /// <summary>
        /// 最后登录时间
        /// </summary>
        [DataType(DataType.DateTime)]
        [Display(Name = "最后登录时间")]
        public Nullable<DateTime> LastLoginTime { get; set; }

        /// <summary>
        /// 最后登录IP
        /// </summary>
        [Display(Name = "最后登录IP")]
        public string LastLoginIP { get; set; }

        /// <summary>
        /// 注册时间
        /// </summary>
        [Required(ErrorMessage = "必须输入{0}")]
        [Display(Name = "注册时间")]
        public DateTime RegTime { get; set; }

        /// <summary>
        /// 角色
        /// </summary>
        public virtual Role Role { get; set; }

    }
}

用户名、密码和Email未设置成必填是考虑到,以后可以扩展QQ账号、微博账号等Owin方式登录等功能,用Owin登录的账号不会有这几个参数。对于用户添加和注册,可以写一个视图模型进行验证。

2、添加表映射

打开Ninesky.Core/NineskyContext.cs,添加Users表映射(红框部分)

3、更新数据表

在【工具栏】->【工具】->NuGet包管理器->程序包管理器控制台,运行命令Update-Database

4、用户管理类

Ninesky.Core【右键】->添加->类,输入类名UserManager,类继承自BaseManager<User>

引用命名空间:using Ninesky.Core.Types; using Ninesky.DataLibrary;

因一般网站用户的数量肯能要较多,在显示用户列表的时候要分页显示,在数据存储层(Ninesky.DataLibrary)的Repository类中 public IQueryable<T> FindPageList<TKey>(int pageSize, int pageIndex, out int totalNumber, Expression<Func<T, bool>> where, Expression<Func<T, TKey>> order, bool asc)等分页方法,方法参数where为Lambda表达式树,在UserManager类的方法中我希望动态构造表达式树,这里需要借助一个小工具LINQKit。

Ninesky.Core->引用【右键】->管理NuGet程序包。

在NuGet包管理器中搜索linqkit,安装LinqKit最新版本。

在UserController中引用命名空间using LinqKit;

4.1 分页列表

添加FindPageList方法,代码如下:

/// <summary>
        /// 分页列表
        /// </summary>
        /// <param name="pagingUser">分页数据</param>
        /// <param name="roleID">角色ID</param>
        /// <param name="username">用户名</param>
        /// <param name="name">名称</param>
        /// <param name="sex">性别</param>
        /// <param name="email">Email</param>
        /// <param name="order">排序【null(默认)-ID降序,0-ID升序,1-ID降序,2-注册时间降序,3-注册时间升序,4-最后登录时间升序,5-最后登录时间降序】</param>
        /// <returns></returns>
        public Paging<User> FindPageList(Paging<User> pagingUser, int? roleID, string username, string name, int? sex, string email, int? order)
        {
            //查询表达式
            var _where = PredicateBuilder.True<User>();
            if (roleID != null && roleID > 0) _where = _where.And(u => u.RoleID == roleID);
            if (!string.IsNullOrEmpty(username)) _where = _where.And(u => u.Username.Contains(username));
            if (!string.IsNullOrEmpty(name)) _where = _where.And(u => u.Name.Contains(name));
            if (sex != null && sex >= 0 && sex <= 2) _where = _where.And(u => u.Sex == sex);
            if (!string.IsNullOrEmpty(email)) _where = _where.And(u => u.Email.Contains(email));
            //排序
            OrderParam _orderParam;
            switch(order)
            {
                case 0://ID升序
                    _orderParam = new OrderParam() { PropertyName = "UserID", Method = OrderMethod.ASC };
                    break;
                case 1://ID降序
                    _orderParam = new OrderParam() { PropertyName = "UserID", Method = OrderMethod.DESC };
                    break;
                case 2://注册时间降序
                    _orderParam = new OrderParam() { PropertyName = "RegTime", Method = OrderMethod.ASC };
                    break;
                case 3://注册时间升序
                    _orderParam = new OrderParam() { PropertyName = "RegTime", Method = OrderMethod.DESC };
                    break;
                case 4://最后登录时间升序
                    _orderParam = new OrderParam() { PropertyName = "LastLoginTime", Method = OrderMethod.ASC };
                    break;
                case 5://最后登录时间降序
                    _orderParam = new OrderParam() { PropertyName = "LastLoginTime", Method = OrderMethod.DESC };
                    break;
                default://ID降序
                    _orderParam = new OrderParam() { PropertyName = "UserID", Method = OrderMethod.DESC };
                    break;
            }
            pagingUser.Items = Repository.FindPageList(pagingUser.PageSize,pagingUser.PageIndex, out pagingUser.TotalNumber, _where.Expand(),_orderParam).ToList();
            return pagingUser;
        }

4.2 判断用户名是否存在

添加HasUsername方法,代码如下

/// <summary>
        /// 用户名是否存在
        /// </summary>
        /// <param name="accounts">用户名[不区分大小写]</param>
        /// <returns></returns>
        public bool HasUsername(string username)
        {
            return base.Repository.IsContains(u => u.Username.ToUpper() == username.ToUpper());
        }

4.3判断Email是否存在

添加HasEmail方法,代码如下

/// <summary>
        /// Email是否存在
        /// </summary>
        /// <param name="email">Email[不区分大小写]</param>
        /// <returns></returns>
        public bool HasEmail(string email)
        {
            return base.Repository.IsContains(u => u.Email.ToUpper() == email.ToUpper());
        }

4.4 添加用户

因添加用户时,账号和Email不能重复所以添加前先判断一下用户名和密码是否存在。这里用户名为空时不进行判断是因为考虑有可能以后使用可能用QQ等其他方式登录。

/// <summary>
        /// 添加【返回值Response.Code:0-失败,1-成功,2-账号已存在,3-Email已存在】
        /// </summary>
        /// <param name="user">用户</param>
        /// <returns></returns>
        public override Response Add(User user)
        {
            Response _resp = new Response();
            //账号是否存在
            if (!string.IsNullOrEmpty(user.Username) && HasUsername(user.Username))
            {
                _resp.Code = 2;
                _resp.Message = "用户名已存在";
            }
            //Email是否存在
            if (!string.IsNullOrEmpty(user.Email) && HasUsername(user.Email))
            {
                _resp.Code = 3;
                _resp.Message = "Email已存在";
            }
            if(_resp.Code == 0) _resp = base.Add(user);
            return _resp;
        }

三、展示层

Ninesky.Web/Areas/Control/Controllers【右键】->添加->控制器。选择 MVC5 控制器 – 空, 输入控制器名称UserController。

在控制器中引入命名空间Ninesky.Core;(1)

为控制器添加身份验证[AdminAuthorize](2)

添加变量private RoleManager roleManager = new RoleManager();(3)

1、用户浏览

1.1、分页列表方法

在UserController中添加方法PageListJson,返回Json格式的分页数据。

 

/// <summary>
        /// 分页列表【json】
        /// </summary>
        /// <param name="roleID">角色ID</param>
        /// <param name="username">用户名</param>
        /// <param name="name">名称</param>
        /// <param name="sex">性别</param>
        /// <param name="email">Email</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页记录数</param>
        /// <param name="order">排序</param>
        /// <returns>Json</returns>
        public ActionResult PageListJson(int? roleID, string username,string name,int? sex,string email,int? pageNumber, int? pageSize,int? order)
        {
            Paging<User> _pagingUser = new Paging<Core.User>();
            if (pageNumber != null && pageNumber > 0) _pagingUser.PageIndex = (int)pageNumber;
            if (pageSize != null && pageSize > 0) _pagingUser.PageSize = (int)pageSize;
            var _paging = userManager.FindPageList(_pagingUser, roleID, username, name, sex, email, null);
            return Json(new { total = _paging.TotalNumber, rows = _paging.Items });
        }

1.2、默认页视图

在UserController中添加Index方法

/// <summary>
        /// 默认页
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            return View();
        }

在Index 方法上点右键 –>添加->视图

@{
    ViewBag.Title = "用户管理";
}

@section SideNav{@Html.Partial("SideNavPartialView")}

<ol class="breadcrumb">
    <li><span class="glyphicon glyphicon-home"></span>  @Html.ActionLink("首页", "Index", "Home")</li>
    <li class="active">@Html.ActionLink("用户管理", "Index", "User")</li>
</ol>

<table id="usergrid"></table>
@section style{
    @Styles.Render("~/Content/bootstrapplugincss")
}

@section scripts{
    @Scripts.Render("~/bundles/jqueryval")
    @Scripts.Render("~/bundles/bootstrapplugin")
    <script type="text/javascript">
        $(document).ready(function () {
            //表格
            var $table = $(‘#usergrid‘);
            $table.bootstrapTable({
                showRefresh: true,
                showColumns: true,
                pagination: true,
                sidePagination: "server",
                pageList:"[5, 10, 20, 50, 100]",
                method: "post",
                url: "@Url.Action("PageListJson")",
                columns: [
                    { title: "ID", field: "UserID" },
                    { title: "角色", field: "RoleID" },
                    { title: "用户名", field: "Username" },
                    { title: "名称", field: "Name", formatter: function (value, row, index) { return "<a href=‘@Url.Action("Modify", "User")/" + row.UserID + "‘>" + value + "</a>" } },
                    { title: "性别", field: "Sex" },
                    { title: "Email", field: "Email", visible:false },
                    { title: "最后登录时间", field: "LastLoginTime" },
                    { title: "最后登录IP", field: "LastLoginIP", visible:false },
                    { title: "注册时间", field: "RegTime",visible:false },
                    { title: "操作", field: "UserID", formatter: function (value) { return "<a class=‘btn btn-sm btn-danger‘ data-operation=‘deleteuser‘ data-value=‘" + value + "‘>删除</a>" } }
                ],
                onLoadSuccess: function () {
                    //删除按钮
                    //删除按钮结束
                }
            });
            //表格结束
        });
    </script>
}

1.3侧导航局部视图

Ninesky.Web/Areas/Control/Views/User【右键】->添加->视图,输入视图名称

<div class="panel panel-default">
    <div class="panel-heading">
        <div class="panel-title"><span class="glyphicon glyphicon-user"></span> 用户管理</div>
    </div>
    <div class="panel-body">
        <div class="list-group">
            <div class="list-group-item"><span class="glyphicon glyphicon-plus"></span>  @Html.ActionLink("添加用户", "Add", "User")</div>
            <div class="list-group-item"><span class="glyphicon glyphicon-list"></span>  @Html.ActionLink("用户管理", "Index", "User")</div>
        </div>
    </div>
</div>

2、添加用户

2.1 添加用户视图模型

Ninesky.Web/Areas/Control/Models【右键】->添加->“AddUserViewModel”

using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace Ninesky.Web.Areas.Control.Models
{
    /// <summary>
    ///  添加用户视图模型类
    /// </summary>
    public class AddUserViewModel
    {
        /// <summary>
        /// 角色ID
        /// </summary>
        [Required(ErrorMessage = "必须选择{0}")]
        [Display(Name = "角色ID")]
        public int RoleID { get; set; }

        /// <summary>
        /// 用户名
        /// </summary>
        [Remote("CanUsername","User",HttpMethod = "Post", ErrorMessage ="用户名已存在")]
        [StringLength(50, MinimumLength = 4, ErrorMessage = "{0}长度为{2}-{1}个字符")]
        [Required(ErrorMessage = "必须输入{0}")]
        [Display(Name = "用户名")]
        public string Username { get; set; }

        /// <summary>
        /// 姓名【可做昵称、真实姓名等】
        /// </summary>
        [StringLength(20, ErrorMessage = "{0}必须少于{1}个字符")]
        [Display(Name = "姓名")]
        public string Name { get; set; }

        /// <summary>
        /// 性别【0-女,1-男,2-保密】
        /// </summary>
        [Required(ErrorMessage = "必须选择{0}")]
        [Range(0, 2, ErrorMessage = "{0}范围{1}-{2}")]
        [Display(Name = "性别")]
        public int Sex { get; set; }

        /// <summary>
        /// 密码
        /// </summary>
        [Required(ErrorMessage = "必须输入{0}")]
        [DataType(DataType.Password)]
        [StringLength(256, ErrorMessage = "{0}长度少于{1}个字符")]
        [Display(Name = "密码")]
        public string Password { get; set; }

        /// <summary>
        /// 确认密码
        /// </summary>
        [System.ComponentModel.DataAnnotations.Compare("Password",ErrorMessage ="两次输入的密码不一致")]
        [DataType(DataType.Password)]
        [Display(Name = "确认密码")]
        public string ConfirmPassword { get; set; }

        /// <summary>
        /// Email
        /// </summary>
        [Required(ErrorMessage = "必须输入{0}")]
        [DataType(DataType.EmailAddress)]
        [Remote("CanEmail", "User",HttpMethod = "Post", ErrorMessage = "Email已存在")]
        [StringLength(50, MinimumLength = 4, ErrorMessage = "{0}长度为{2}-{1}个字符")]
        [Display(Name = "Email")]
        public string Email { get; set; }
    }
}

模型中使用到了远程验证(Remote)、属性比较(Compare)等验证方式。

2.2用户名和Email远程验证方法

在UserController中添加CanUsername和CanEmail方法

/// <summary>
        /// 用户名是否可用
        /// </summary>
        /// <param name="UserName">用户名</param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult CanUsername(string UserName)
        {
            return Json(!userManager.HasUsername(UserName));
        }

        /// <summary>
        /// Email是否存可用
        /// </summary>
        /// <param name="Email">Email</param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult CanEmail(string Email)
        {
            return Json(!userManager.HasEmail(Email));
        }

2.3 添加用户页面

在UserController中添加Add方法

/// <summary>
        /// 添加用户
        /// </summary>
        /// <returns></returns>
        public ActionResult Add()
        {
            //角色列表
            var _roles = new RoleManager().FindList();
            List<SelectListItem> _listItems = new List<SelectListItem>(_roles.Count());
            foreach(var _role in _roles)
            {
                _listItems.Add(new SelectListItem() { Text = _role.Name, Value = _role.RoleID.ToString() });
            }
            ViewBag.Roles = _listItems;
            //角色列表结束
            return View();
        }

方法中向视图传递角色列表ViewBag.Roles

右键添加视图

代码如下:

@model Ninesky.Web.Areas.Control.Models.AddUserViewModel

@{
    ViewBag.Title = "添加用户";
}

@section SideNav{@Html.Partial("SideNavPartialView")}

<ol class="breadcrumb">
    <li><span class="glyphicon glyphicon-home"></span>  @Html.ActionLink("首页", "Index", "Home")</li>
    <li> @Html.ActionLink("用户管理", "Index", "User")</li>
    <li class="active">@Html.ActionLink("添加用户", "Add", "User")</li>
</ol>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.RoleID, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.RoleID, (IEnumerable<SelectListItem>)ViewBag.Roles, new { @class = "form-control" });
                @Html.ValidationMessageFor(model => model.RoleID, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Username, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Username, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Username, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Sex, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.RadioButtonFor(model => model.Sex, 1) 男
                @Html.RadioButtonFor(model => model.Sex, 0) 女
                @Html.RadioButtonFor(model => model.Sex, 2) 保密

                @Html.ValidationMessageFor(model => model.Sex, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.ConfirmPassword, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ConfirmPassword, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ConfirmPassword, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="添加" class="btn btn-default" />
            </div>
        </div>
    </div>
}
@Scripts.Render("~/bundles/jqueryval")
 

2.4添加处理方法

UserController中添加Add(AddUserViewModel userViewModel)方法

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Add(AddUserViewModel userViewModel)
        {
            if (userManager.HasUsername(userViewModel.Username)) ModelState.AddModelError("Username","用户名已存在");
            if (userManager.HasEmail(userViewModel.Email)) ModelState.AddModelError("Email", "Email已存在");
            if (ModelState.IsValid)
            {
                Core.User _user = new Core.User();
                _user.RoleID = userViewModel.RoleID;
                _user.Username = userViewModel.Username;
                _user.Name = userViewModel.Name;
                _user.Sex = userViewModel.Sex;
                _user.Password = Core.General.Security.SHA256(userViewModel.Password);
                _user.Email = userViewModel.Email;
                _user.RegTime = System.DateTime.Now;
                var _response = userManager.Add(_user);
                if (_response.Code == 1) return View("Prompt",new Prompt() { Title="添加用户成功",
                 Message="您已成功添加了用户【"+ _response.Data.Username+ "("+ _response.Data.Name + ")】",
                 Buttons= new List<string> {"<a href=\"" + Url.Action("Index", "User") + "\" class=\"btn btn-default\">用户管理</a>",
                 "<a href=\"" + Url.Action("Details", "User",new { id= _response.Data.UserID }) + "\" class=\"btn btn-default\">查看用户</a>",
                 "<a href=\"" + Url.Action("Add", "User") + "\" class=\"btn btn-default\">继续添加</a>"} });
                else ModelState.AddModelError("", _response.Message);
            }
            //角色列表
            var _roles = new RoleManager().FindList();
            List<SelectListItem> _listItems = new List<SelectListItem>(_roles.Count());
            foreach (var _role in _roles)
            {
                _listItems.Add(new SelectListItem() { Text = _role.Name, Value = _role.RoleID.ToString() });
            }
            ViewBag.Roles = _listItems;
            //角色列表结束

            return View(userViewModel);
        }

 

2.5添加成功提示

UserController中[右键]添加视图-Prompt

@model Ninesky.Web.Models.Prompt

@{
    ViewBag.Title = "提示";
}

@section SideNav{@Html.Partial("SideNavPartialView")}

<ol class="breadcrumb">
    <li><span class="glyphicon glyphicon-home"></span>  @Html.ActionLink("首页", "Index", "Home")</li>
    <li class="active"> @Html.ActionLink("用户管理", "Index", "User")</li>
</ol>
@Html.Partial("PromptPartialView", Model)

2.6 添加提示消息局部视图

Ninesky.Web/Areas/Control/Views/Shared【右键】->添加->视图。视图名为PromptPartialView。

代码如下:

@model Ninesky.Web.Models.Prompt

<div class="panel panel-default">
    <div class="panel-heading"><div class="panel-title">@Model.Title</div></div>
    <div class="panel-body">
        <p>@Html.Raw(Model.Message)</p>
        @if (Model.Buttons != null && Model.Buttons.Count > 0)
        {
            <p>
                @foreach (var item in Model.Buttons)
                {
                    @Html.Raw(item + "&nbsp;&nbsp;")

                }
            </p>
        }
    </div>
</div>

 

运行效果

===============================================================

前几天就忙完了,中间休息了一下,顺便调整一下状态。

由于代码20多天前些了一部分,到现在有些忘记当时的想法了,今天又写了一些感觉衔接不好,有点乱。

时间: 2024-11-16 13:29:40

MVC5 网站开发之七 用户功能 2 用户添加和浏览的相关文章

MVC5 网站开发之七 用户功能 1、角色的后台管理

角色是网站中都有的一个功能,用来区分用户的类型.划分用户的权限,这次实现角色列表浏览.角色添加.角色修改和角色删除. 目录 奔跑吧,代码小哥! MVC5网站开发之一 总体概述 MVC5 网站开发之二 创建项目 MVC5 网站开发之三 数据存储层功能实现 MVC5 网站开发之四 业务逻辑层的架构和基本功能 MVC5 网站开发之五 展示层架构 MVC5 网站开发之六 管理员 1.登录.验证和注销 MVC5 网站开发之六 管理员 2.添加.删除.重置密码.修改密码.列表浏览 MVC5 网站开发之七 用

MVC5 网站开发之七 用户功能 2 .1用户资料的修改和删除

这次主要实现管理后台界面用户资料的修改和删除,修改用户资料和角色是经常用到的功能,但删除用户的情况比较少,为了功能的完整性还是坐上了.主要用到两个action “Modify”和“Delete”. 目录 MVC5网站开发之一 总体概述 MVC5 网站开发之二 创建项目 MVC5 网站开发之三 数据存储层功能实现 MVC5 网站开发之四 业务逻辑层的架构和基本功能 MVC5 网站开发之五 展示层架构 MVC5 网站开发之六 管理员 1.登录.验证和注销 MVC5 网站开发之六 管理员 2.添加.删

MVC5 网站开发之八 栏目功能 添加、修改和删除

本次实现栏目的浏览.添加.修改和删除. 栏目一共有三种类型. 常规栏目-可以添加子栏目,也可以添加内容模型.当不选择内容模型时,不能添加内容. 单页栏目-栏目只有一个页面,可以设置视图. 链接栏目-栏目为一个链接,点击后转到相应链接. 在视图中原本栏目的树形显示插件使用Bootstrap TreeView 1.2.0(MVC5 网站开发之六 管理员 2.添加.删除.重置密码.修改密码.列表浏览),后来使用中发现zTree使用起来更习惯,所以更换成zTree了. 目录 MVC5网站开发之一 总体概

MVC5 网站开发之六 管理员功能之添加、删除、重置密码、修改密码、列表浏览

  一.安装插件. 展示层前端框架以Bootstrap为主,因为Bootstrap的js功能较弱,这里添加一些插件作补充.其实很多js插件可以通过NuGet安装,只是NuGet安装时添加的内容较多,不如自己复制来的干净,所以这里所有的插件都是下载然后复制到项目中. 1.Bootstrap 3 Datepicker 4.17.37 网址:https://eonasdan.github.io/bootstrap-datetimepicker/ 下载并解压压缩包->将bootstrap-datetim

MVC5 网站开发之六 管理员功能之登录、验证和注销

上次业务逻辑和展示层的架构都写了,可以开始进行具体功能的实现,这次先实现管理员的登录.验证和注销功能.   一.业务逻辑层 1.实现256散列加密方法. Ninesky.Core[右键]-> 添加->文件夹,输入文件夹名General. General文件夹[右键]->添加->类,输入类名Security. 引用System.Security.Cryptography命名空间(1),并实现SHA256静态加密方法. 2.Administrator模型类 Ninesky.Core[右

MVC5 网站开发之九 网站设置

网站配置一般用来保存网站的一些设置,写在配置文件中比写在数据库中要合适一下,因为配置文件本身带有缓存,随网站启动读入缓存中,速度更快,而保存在数据库中要单独为一条记录创建一个表,结构不够清晰,而且读写也没有配置文件容易实现.这次要做的是网站的基本信息,数据保存在SiteConfig.config. 目录 MVC5网站开发之一 总体概述 MVC5 网站开发之二 创建项目 MVC5 网站开发之三 数据存储层功能实现 MVC5 网站开发之四 业务逻辑层的架构和基本功能 MVC5 网站开发之五 展示层架

ASP.NET MVC5 网站开发实践(二) Member区域 - 添加文章

转自:http://www.cnblogs.com/mzwhj/p/3592895.html 上次把架构做好了,这次做添加文章.添加文章涉及附件的上传管理及富文本编辑器的使用,早添加文章时一并实现. 要点: 富文本编辑器采用KindEditor.功能很强大,国人开发,LGPL开源,自己人的好东西没有理由不支持. 附件的上传同样基于KindEditor实现,可以上传图片,flash,影音,文件等. 目录 ASP.NET MVC5 网站开发实践 - 概述 ASP.NET MVC5 网站开发实践(一)

MVC5 网站开发实践 2.2、管理员身份验证

上次完成了管理员的登录,这次要解决对管理员登录后的验证,采用AuthorizeAttribute属性的方式.之前还要解决几个问题,然后才重写验证类,最后稍微改一下界面. 目录 MVC5 网站开发实践  概述 MVC5 网站开发实践  1.建立项目 MVC5 网站开发实践  2.后台管理 MVC5 网站开发实践  2.1.管理员登陆 一.解决问题Home控制器错误提示 @泰德  在评论中说浏览器中打开存在以下错误.这是因为项目中存在多个Home控制器,但系统不清楚你要访问的是哪个控制器的内容,因此

MVC5 网站开发实践 2.1、管理员登陆

目录 MVC5 网站开发实践  概述 MVC5 网站开发实践  1.建立项目 MVC5 网站开发实践  2.后台管理   1. 创建SHA256加密方法. 在Data项目中添加文件夹[Security],在文件夹中添加类 [Encryption],在类中写一个SHA256加密方法. using System; using System.Security.Cryptography; using System.Text; namespace Ninesky.Data.Security { /// <