4

篇(18)-Asp.Net Core入门实战-文章管理之文章内容管理(下拉框二级结构递归) - 荣景智...

 1 year ago
source link: https://www.cnblogs.com/mushaobai/p/16911139.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

篇(18)-Asp.Net Core入门实战-文章管理之文章内容管理(下拉框二级结构递归)

篇(18)-Asp.Net Core入门实战-文章管理之文章内容管理(下拉框二级结构递归实现)

文章管理是CMS系统的核心表之一,存储文章内容,特点就是字段端,属性多,比如是否标识为热点、推荐等属性,是否发布,类别,SEO关键字等。我们本章讲解文章内容的增删改查。

(1).文章Sql表结构设计

39139-20221121150147334-1486688426.jpg
CREATE TABLE [dbo].[Article](
[Id] [int] IDENTITY(1,1) NOT NULL,
[CategoryId] [int] NOT NULL,
[Title] [varchar](128) NOT NULL,
[ImageUrl] [varchar](128) NULL,
[Content] [text] NULL,
[ViewCount] [int] NOT NULL,
[Sort] [int] NOT NULL,
[Author] [varchar](64) NULL,
[Source] [varchar](128) NULL,
[SeoTitle] [varchar](128) NULL,
[SeoKeyword] [varchar](256) NULL,
[SeoDescription] [varchar](512) NULL,
[AddManagerId] [int] NOT NULL,
[AddTime] [datetime] NOT NULL,
[ModifyManagerId] [int] NULL,
[ModifyTime] [datetime] NULL,
[IsTop] [bit] NOT NULL,
[IsSlide] [bit] NOT NULL,
[IsRed] [bit] NOT NULL,
[IsPublish] [bit] NOT NULL,
[IsDeleted] [bit] NOT NULL,
CONSTRAINT [PK_ARTICLE] PRIMARY KEY NONCLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Article] ADD DEFAULT (getdate()) FOR [AddTime]
GO
ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsTop]
GO
ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsSlide]
GO
ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsRed]
GO
ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsPublish]
GO
ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsDeleted]
GO
ALTER TABLE [dbo].[Article] WITH CHECK ADD CONSTRAINT [FK_ARTICLE_RELATIONS_ARTICLEC] FOREIGN KEY([CategoryId])
REFERENCES [dbo].[ArticleCategory] ([Id])
GO
ALTER TABLE [dbo].[Article] CHECK CONSTRAINT [FK_ARTICLE_RELATIONS_ARTICLEC]
GO

那么对应的Article Model代码如下:

public class Article
{
/// <summary>
/// 主键
/// </summary>
[Key]
public Int32 Id { get; set; }
/// <summary>
/// 分类ID
/// </summary>
[Required]
public Int32 CategoryId { get; set; }
/// <summary>
/// 文章标题
/// </summary>
[Required]
public String Title { get; set; }
/// <summary>
/// 图片地址
/// </summary>
public String ImageUrl { get; set; }
/// <summary>
/// 文章内容
/// </summary>
public String Content { get; set; }
/// <summary>
/// 浏览次数
/// </summary>
[Required]
public Int32 ViewCount { get; set; }
/// <summary>
/// 排序
/// </summary>
[Required]
public Int32 Sort { get; set; }
/// <summary>
/// 作者
/// </summary>
public String Author { get; set; }
/// <summary>
/// 来源
/// </summary>
public String Source { get; set; }
/// <summary>
/// SEO标题
/// </summary>
public String SeoTitle { get; set; }
/// <summary>
/// SEO关键字
/// </summary>
public String SeoKeyword { get; set; }
/// <summary>
/// SEO描述
/// </summary>
public String SeoDescription { get; set; }
/// <summary>
/// 添加人ID
/// </summary>
[Required]
public Int32 AddManagerId { get; set; }
/// <summary>
/// 添加时间
/// </summary>
[Required]
public DateTime AddTime { get; set; }
/// <summary>
/// 修改人ID
/// </summary>
public Int32? ModifyManagerId { get; set; }
/// <summary>
/// 修改时间
/// </summary>
public DateTime? ModifyTime { get; set; }
/// <summary>
/// 是否置顶
/// </summary>
public Boolean IsTop { get; set; }
/// <summary>
/// 是否轮播显示
/// </summary>
public Boolean IsSlide { get; set; }
/// <summary>
/// 是否热门
/// </summary>
public Boolean IsRed { get; set; }
/// <summary>
/// 是否发布
/// </summary>
public Boolean IsPublish { get; set; }
/// <summary>
/// 是否删除
/// </summary>
[Required]
public Boolean IsDeleted { get; set; }
}

(2).视图Create代码

(2.1)视图代码

考虑到要同时上传图片,注意form表单的额 enctype类型;

@{ ViewData["Title"] = "新建文章"; }
@model Article
<form action="/Article/Create" method="post" enctype="multipart/form-data">
@Html.AntiForgeryToken()
<div>
<label asp-for="Title">标题</label>
<div>
<input type="text" asp-for="Title" name="Title" placeholder="请输入标题">
</div>
</div>
<div>
<label asp-for="CategoryId">文章类型</label>
<div>
@Html.DropDownList("ddl_CategoryId", ViewBag.database as IEnumerable<SelectListItem>)
</div>
</div>
<div>
<label>设置</label>
<div>
@*@Html.CheckBox("IsTop") 置顶
@Html.CheckBox("IsRed") 热点
@Html.CheckBox("IsSlide") 幻灯*@
<input type="checkbox" name="IsTop" asp-for="IsTop" />置顶
<input type="checkbox" name="IsRed" asp-for="IsRed"/>热点
<input type="checkbox" name="IsSlide" asp-for="IsSlide" />幻灯
</div>
</div>
<div>
<label asp-for="ImageUrl">文章首页图</label>
<div>
<input type="file" asp-for="ImageUrl" name="ImageUrl"/>
</div>
</div>
<div>
<label asp-for="Content">内容</label>
<div>
<textarea placeholder="内容" asp-for="Content" name="Content" cols="30" rows="10"></textarea>
</div>
</div>
<div>
<label asp-for="Sort">排序</label>
<div>
<input type="text" placeholder="排序" asp-for="Sort" name="Sort" />
</div>
</div>
<div>
<label asp-for="ViewCount">点击量</label>
<div>
<input type="text" placeholder="点击量" asp-for="ViewCount" name="ViewCount" />
</div>
</div>
<div>
<label asp-for="IsPublish">是否发布</label>
<div>
<select asp-for="IsPublish" name="IsPublish" class="IsPublish">
<option value="False">否</option>
<option value="True" selected>是</option>
</select>
</div>
</div>
<div>
<label asp-for="Author">作者</label>
<div>
<input type="text" asp-for="Author" name="Author" placeholder="作者名">
</div>
</div>
<div>
<label asp-for="Source">来源</label>
<div>
<input type="text" asp-for="Source" name="Source" placeholder="文章来源">
</div>
</div>
<div>
<label asp-for="SeoTitle">SEO标题</label>
<div>
<input type="text" asp-for="SeoTitle" name="SeoTitle" placeholder="SEO标题">
</div>
</div>
<div>
<label asp-for="SeoKeyword">SEO关键词</label>
<div>
<input type="text" asp-for="SeoKeyword" name="SeoKeyword" placeholder="SEO关键词">
</div>
</div>
<div>
<label asp-for="SeoDescription">SEO摘要描述</label>
<div>
<input type="text" asp-for="SeoDescription" name="SeoDescription" placeholder="SEO摘要描述">
</div>
</div>
<div>
<div>
<button type="submit">确定</button>
<button type="reset">重置</button>
</div>
</div>
</form>

(2.2)视图中的下拉框的实现方式(递归和循环嵌套)

39139-20221121150147334-1206323220.jpg

我想在添加文章时,实现一个具有二级层次结构的下拉框,如上图所示。所以,在对下拉框进行数据绑定时,就要费点功夫,上个章节讲文章类别管理时,的表结构就一个,分类都存在一张表中,所以要进行递归的获取子菜单或者通过循环嵌套来实现。

递归的主要核心函数为:

/// <summary>
/// 递归函数,实现获取子菜单
/// </summary>
/// <param name="lists">递归前的列表</param>
/// <param name="newlists">递归后的新列表</param>
/// <param name="parentId">父Id</param>
/// <returns></returns>
public static List<CategorySelectItemListView> GetChildCategory(List<CategorySelectItemListView> lists, List<CategorySelectItemListView> newlists, int parentId)
{
newlists = new List<CategorySelectItemListView>();
List<CategorySelectItemListView> tempList = lists.Where(c => c.ParentId == parentId).ToList();
for (int i = 0; i < tempList.Count; i++)
{
CategorySelectItemListView category = new CategorySelectItemListView();
category.Id = tempList[i].Id;
category.ParentId = tempList[i].ParentId;
category.Title = tempList[i].Title;
category.Children = GetChildCategory(lists, newlists, category.Id);
newlists.Add(category);
}
return newlists;
}


/// <summary>
/// 循环嵌套,实现获取子菜单
/// </summary>
/// <param name="lists">循环遍历前的列表</param>
/// <returns></returns>
public static List<CategorySelectItemListView> GetChildCategory(List<CategorySelectItemListView> lists)
{
List<CategorySelectItemListView> categorylist = new List<CategorySelectItemListView>();
for (int i = 0; i < lists.Count; i++)
{
if (0 == lists[i].ParentId)
categorylist.Add(lists[i]);
for (int j = 0; j < lists.Count; j++)
{
if (lists[j].ParentId == lists[i].Id)
lists[i].Children.Add(lists[j]);
}
}
return categorylist;
}

然后在Create和Edit的Action中去绑定对应的下拉菜单即可。

注意:List<CategorySelectItemListView> 集合的CategorySelectItemListView,这个是新建的ViewModel对象,用来专门绑定下拉菜单使用,其代码如下:

public class CategorySelectItemListView
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentId { get; set; }
public List<CategorySelectItemListView> Children { get; set; }
public CategorySelectItemListView()
{
Children = new List<CategorySelectItemListView>();
}

public CategorySelectItemListView(int id,string title,int parentid)
{
this.Id = id;
this.Title = title;
this.ParentId = parentid;
Children = new List<CategorySelectItemListView>();
}

public CategorySelectItemListView(int id, string title, CategorySelectItemListView parent)
{
this.Id = id;
this.Title = title;
this.ParentId = parent.Id;
Children = new List<CategorySelectItemListView>();
}

(3).视图Edit代码,注解部分的代码可以参考,我尝试用过,也可以达到目的,演练代码最好是用多种方式实现,查看其区别,这样掌握的牢固一些

@{ ViewData["Title"] = "编辑文章"; }
@model Article
@section Scripts{
<script type="text/javascript" src="~/js/jquery-3.6.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$.ajax({
type: "GET",
url: "/ArticleCategory/GetCategory",
data: "{}",
success: function (data) {
console.log(data);
var s = '<option value="0">请选择</option>';
for (var i = 0; i < data.length; i++) {
s += '<option value="' + data[i].Title + '"+>' + data[i].Id + '</option>';
}
$("#ArticleCategory").html(s);
}
});
});
</script>
}

<form action="/Article/Edit" method="post" enctype="multipart/form-data">
@Html.AntiForgeryToken()
<div>
<label asp-for="Title">标题</label>
<div>
<input type="text" asp-for="Title" name="Title" placeholder="请输入标题">
<input type="hidden" asp-for="Id" />
</div>
</div>
<div>
<label asp-for="CategoryId">文章类型</label>
<div>
@Html.DropDownList("ddl_CategoryId", ViewBag.database as IEnumerable<SelectListItem>)
</div>
</div>
<div>
<label>设置</label>
<div>
@*@Html.CheckBox("IsTop", Model.IsTop,new { value = Model.IsTop}) 置顶
@Html.CheckBox("IsRed", Model.IsRed, new { value = Model.IsRed }) 热点
@Html.CheckBox("IsSlide", Model.IsSlide, new { value = Model.IsSlide }) 幻灯*@
<input asp-for="IsTop" />置顶
<input asp-for="IsRed" />热点
<input asp-for="IsSlide" />幻灯
@*<input type="checkbox" name="IsTop" @(Html.Raw(@Model.IsTop ? "checked=\"checked\"" : "")) asp-for="IsTop" />置顶
<input type="checkbox" name="IsRed" @(Html.Raw(@Model.IsRed ? "checked=\"checked\"" : "")) asp-for="IsRed" />热点
<input type="checkbox" name="IsSlide" @(Html.Raw(@Model.IsSlide ? "checked=\"checked\"" : "")) asp-for="IsSlide" />幻灯*@
@*<input type="checkbox" name="IsTop" asp-for="IsTop" />置顶
<input type="checkbox" name="IsRed" asp-for="IsRed"/>热点
<input type="checkbox" name="IsSlide" asp-for="IsSlide"/>幻灯*@
</div>
</div>
<div>
<label asp-for="ImageUrl">文章首页图</label>
<div>
<input type="file" asp-for="ImageUrl" name="ImageUrl" />
<label asp-for="ImageUrl">@Model.ImageUrl</label>
</div>
</div>
<div>
<label asp-for="Content">内容</label>
<div>
<textarea placeholder="内容" asp-for="Content" name="Content" cols="30" rows="10"></textarea>
</div>
</div>
<div>
<label asp-for="Sort">排序</label>
<div>
<input type="text" placeholder="排序" asp-for="Sort" name="Sort" />
</div>
</div>
<div>
<label asp-for="ViewCount">点击量</label>
<div>
<input type="text" placeholder="点击量" asp-for="ViewCount" name="ViewCount" />
</div>
</div>
<div>
<label asp-for="IsPublish">是否发布</label>
<div>
<select asp-for="IsPublish" name="IsPublish" class="IsPublish">
<option value="False">否</option>
<option value="True" selected>是</option>
</select>
</div>
</div>
<div>
<label asp-for="Author">作者</label>
<div>
<input type="text" asp-for="Author" name="Author" placeholder="作者名">
</div>
</div>
<div>
<label asp-for="Source">来源</label>
<div>
<input type="text" asp-for="Source" name="Source" placeholder="文章来源">
</div>
</div>
<div>
<label asp-for="SeoTitle">SEO标题</label>
<div>
<input type="text" asp-for="SeoTitle" name="SeoTitle" placeholder="SEO标题">
</div>
</div>
<div>
<label asp-for="SeoKeyword">SEO关键词</label>
<div>
<input type="text" asp-for="SeoKeyword" name="SeoKeyword" placeholder="SEO关键词">
</div>
</div>
<div>
<label asp-for="SeoDescription">SEO摘要描述</label>
<div>
<input type="text" asp-for="SeoDescription" name="SeoDescription" placeholder="SEO摘要描述">
</div>
</div>
<div>
<div>
<button type="submit">确定</button>
<button type="reset">重置</button>
</div>
</div>
</form>

(4).视图Index列表的代码

针对列表的显示,又专门编写了ArticeView的这个ViewModel。

39139-20221121150147472-823072694.jpg
public class ArticleView
{
public int Id { get; set; }
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public string Title { get; set; }
public int ViewCount { get; set; }
public int Sort { get; set; }
public string Author { get; set; }
public string Source { get; set; }
public int AddManagerId { get; set; }
public DateTime AddTime { get; set; }
}
@using Humanizer;
@using RjWebCms.Db;
@using RjWebCms.Models.Articles;
@model PaginatedList<ArticleView>
@{
ViewData["Title"] = "文章列表";
}
@section Scripts{
<script src="~/js/jquery-2.1.0.min.js"></script>
<script type="text/javascript">
function DelAll() {
var ids = document.getElementsByName("#chk_ids");
var arrIds = "";
var n = 0;
for (var i = 0; i < ids.length; i++)
{
if (ids[i].checked == true) {
arrIds += ids[i].value + ",";
n++;
}
}
if (n == 0) {
alert("请选择要删除的信息");
return;
}
arrIds = arrids.substr(0, arrIds.length - 1);
//
if (confirm("确定要全部删除选择信息吗")) {
$.ajax({
type: "post",
url: "/Article/DeleteAll",
data: { ids: arrIds },
success: function (data, state) {
alert('删除成功!');
window.location.href = "";
},

error: function (data, state) {
alert('删除失败');
}
});
}
}
</script>
}
<div class="panel panel-default todo-panel">
<div class="panel-heading">@ViewData["Title"]</div>
@Html.AntiForgeryToken()
<form asp-action="Index" method="get">
<table>
<tr><td><a asp-controller="Article" asp-action="Create">添加</a></td></tr>
<tr>
<td>查询关键词:<input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" /></td>
<td><input type="submit" value="查询" /></td>
<td><a asp-action="Index">Back</a></td>
<td><a asp-action="DeleteAll">批量删除</a></td>
</tr>
</table>
</form>
<table class="table table-hover">
<thead>
<tr>
<td>✔</td>
<td><a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">标题</a></td>
<td>类别</td>
<td><a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">添加时间</a></td>
<td>作者</td>
<td>操作</td>
</tr>
@foreach (var item in Model)
{
<tr>
<td><input type="checkbox" class="done-checkbox" name="chk_ids" value="@item.Id"></td>
<td>@item.Title</td>
<td>@item.CategoryName</td>
<td>@item.AddTime</td>
<td>@item.Author</td>
<td>
<a asp-action="Details" asp-route-id="@item.Id">Details</a>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a>
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</thead>
</table>
@{
var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
var nextDisabled = !Model.HasNextPage ? "disabled" : ""; ;
}

<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-pageNumber="@(Model.PageIndex - 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @prevDisabled">
上一页
</a>
<a asp-action="Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-pageNumber="@(Model.PageIndex + 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
class="btn btn-default @nextDisabled">
下一页
</a>
<div class="panel-footer add-item-form">
<!--TODO: Add item form -->
</div>
</div>

(5).Controller部分的全部代码,注意看代码注释

public class ArticleController : Controller
    {
        private readonly IHostEnvironment _hostEnvironment;
        private readonly IArticleService _articleService;
        private readonly IArticleCategoryService _articleCategoryService;
        private readonly AppDbContext _appDbContext;
        public ArticleController(IArticleService articleService, IArticleCategoryService articleCategoryService,AppDbContext appDbContext,IHostEnvironment hostEnvironment)
        {
            _hostEnvironment = hostEnvironment;
            _appDbContext = appDbContext;
            _articleService = articleService;
            _articleCategoryService = articleCategoryService;
        }

        public async Task<IActionResult> Index(string sortOrder, string currentFilter, string searchString, int? pageNumber)
        {
            ViewData["CurrentSort"] = sortOrder;
            ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
            ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";

            if (searchString != null)
            {
                pageNumber = 1;
            }
            else
            {
                searchString = currentFilter;
            }
            ViewData["CurrentFilter"] = searchString;
            var article = from s in _appDbContext.Article
                          join p in _appDbContext.ArticleCategory on s.CategoryId equals p.Id
                          select new ArticleView { 
                            Id = s.Id,
                            CategoryId = s.CategoryId,
                            CategoryName = p.Title,
                            Title = s.Title,
                            Sort = s.Sort,
                            AddManagerId = s.AddManagerId,
                            AddTime = s.AddTime,
                            Author = s.Author,
                            Source = s.Source,
                            ViewCount = s.ViewCount,
                          };
            if (!string.IsNullOrEmpty(searchString))
            {
                article = article.Where(s => s.Title.Contains(searchString));
            }
            switch (sortOrder)
            {
                case "name_desc":
                    article = article.OrderByDescending(s => s.Title) ;
                    break;
                case "Date":
                    article = article.OrderBy(s => s.AddTime);
                    break;
                case "date_desc":
                    article = article.OrderByDescending(s => s.AddTime);
                    break;
                default:
                    article = article.OrderBy(s => s.Title);
                    break;
            }
            int pageSize = 4;
            return View(await PaginatedList<ArticleView>.CreateAsync(article.AsNoTracking(), pageNumber ?? 1, pageSize));
        }


        [HttpGet]
        public async Task<IActionResult> CreateAsync()
        {
            #region 绑定类别下拉框
            var categories = await _articleCategoryService.GetArticleCategory();//列出文章类别字典
            var categoryItems = new List<SelectListItem>()
            {
                new SelectListItem(){ Value="0",Text="全部",Selected=true}
            };
            //全部列出并转成DropDownList对象
            List<CategorySelectItemListView> list = new List<CategorySelectItemListView>();
            foreach (var category in categories)
            {
                list.Add(new CategorySelectItemListView { 
                    Id=category.Id,
                    Title = category.Title,
                    ParentId = category.ParentId
                });
            }

            #region 循环嵌套调用
            //List<CategorySelectItemListView> list1 = GetChildCategory(list);
            //foreach (var li in list1)
            //{
            //    categoryItems.Add(new SelectListItem { Value = li.Id.ToString(), Text = li.Title });
            //    if (li.Children.Count > 0)
            //    { 
            //        foreach(var t in li.Children)
            //            categoryItems.Add(new SelectListItem { Value = t.Id.ToString(),Text= "|-" + t.Title });
            //    }
            //}
            #endregion

            #region  递归调用
            List<CategorySelectItemListView> list1 = GetChildCategory(list, new List<CategorySelectItemListView>(), 0);
            foreach (var li in list1)
            {
                categoryItems.Add(new SelectListItem { Value = li.Id.ToString(), Text = li.Title });
                if (li.Children.Count > 0)
                {
                    foreach (var t in li.Children)
                        categoryItems.Add(new SelectListItem { Value = t.Id.ToString(), Text = "  |-" + t.Title });
                }
            }
            #endregion

            ViewBag.database = categoryItems;
            #endregion
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> CreateAsync(Article article,[FromForm]IFormCollection fromData)
        {
            //去掉对字段IsSystem的验证,IsSystem在数据库是bool类型,而前端是0和1,ModelState的验证总是报false,所以去掉对其验证
            //ModelState.Remove("IsSystem");//在View端已经解决了了bool类型,那么此行代码可以不用
            #region 下拉菜单
            string strCategoryId = Request.Form["ddl_CategoryId"];
            if (!string.IsNullOrEmpty(strCategoryId))
                article.CategoryId = int.Parse(strCategoryId);
            else
                article.CategoryId = 0;
            #endregion

            #region 复选框
            article.IsTop = fromData["IsTop"] != "false";//使用FormCollection时,可以这样
            article.IsRed = fromData["IsRed"] != "false";
            article.IsSlide = fromData["IsSlide"] != "false";
            //也可以这样取值,但要注意View内的写法
            //if (!string.IsNullOrEmpty(fromData["IsTop"]))
            //    article.IsTop = true;
            //else
            //    article.IsTop = false;
            #endregion

            #region 上传文件
            IFormFileCollection files = fromData.Files;
           foreach(var formFile in files)
            {
                //var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
                string webContentPath = _hostEnvironment.ContentRootPath;
                var fileExt = formFile.FileName.Substring(formFile.FileName.LastIndexOf('.'));//文件扩展名
                var fileNew = DateTime.Now.ToString("yyyyMMddHHmmss") + fileExt; //给文件重新命名
                
                //string upLoadPath = webContentPath + $@"\{fileName}";
                string upLoadPath = webContentPath + $@"\UpFiles";
                var fileUrl = upLoadPath + $@"\{fileNew}";

                if (formFile.Length > 0)
                {
                    using (var stream = new FileStream(fileUrl,FileMode.Create))
                    {
                        await formFile.CopyToAsync(stream);
                    }
                }
                article.ImageUrl = "../UpFiles/" + fileNew;


            }       
            #endregion 

            if (ModelState.IsValid)
            {
                var successful = await _articleService.AddArticleAysnc(article);
                if (successful)
                    return RedirectToAction("Index");
                else
                    return BadRequest("失败");
            }
            return View(article);
        }


        [HttpGet]
        public async Task<IActionResult> Edit(int id)
        {

            if (string.IsNullOrEmpty(id.ToString()))
                return NotFound();

            var article = await _articleService.FindArticleAsync(id);
            if (article == null)
                return NotFound();

            #region 绑定角色下拉框
            var categories = await _articleCategoryService.GetArticleCategory();//列出文章类别字典
            var categoryItems = new List<SelectListItem>()
            {
                new SelectListItem(){ Value="0",Text="全部",Selected=true}
            };
            //全部列出并转成DropDownList对象
            List<CategorySelectItemListView> list = new List<CategorySelectItemListView>();
            foreach (var category in categories)
            {
                list.Add(new CategorySelectItemListView
                {
                    Id = category.Id,
                    Title = category.Title,
                    ParentId = category.ParentId
                });
            }
            #region  递归调用
            List<CategorySelectItemListView> list1 = GetChildCategory(list, new List<CategorySelectItemListView>(), 0);
            foreach (var li in list1)
            {
                categoryItems.Add(new SelectListItem { Value = li.Id.ToString(), Text = li.Title });
                if (li.Children.Count > 0)
                {
                    foreach (var t in li.Children)
                        categoryItems.Add(new SelectListItem { Value = t.Id.ToString(), Text = "  |-" + t.Title });
                }
            }
            #endregion

            #region 遍历并选中
            foreach (SelectListItem item in categoryItems)
            {
                if (item.Value == article.CategoryId.ToString())
                    item.Selected = true;
            }
            #endregion 
            ViewBag.database = categoryItems;
            #endregion

            return View(article);
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [FromForm]Article article)
        {
            if (id != article.Id)
            {
                return NotFound();
            }
            #region 下拉菜单
            string strCategoryId = Request.Form["ddl_CategoryId"];
            if (!string.IsNullOrEmpty(strCategoryId))
                article.CategoryId = int.Parse(strCategoryId);
            else
                article.CategoryId = 0;
            #endregion
            #region 复选框
            if (Request.Form["IsTop"].Contains("true"))
                article.IsTop = true;
            else
                article.IsTop = false;
            if (Request.Form["IsRed"].Contains("true"))
                article.IsRed = true;
            else
                article.IsRed = false;
            if (Request.Form["IsSlide"].Contains("true"))
                article.IsSlide = true;
            else
                article.IsSlide = false;
            #endregion 
            //ModelState.Remove("IsTop");
            //ModelState.Remove("IsRed");
            //ModelState.Remove("IsSlide");
            if (ModelState.IsValid)
            {
                try
                {
                    var result = await _articleService.UpdateArticleAsync(id, article);
                    //跳转
                    if (result)
                        return RedirectToAction("Index");
                    else
                        return BadRequest("编辑失败");
                }
                catch (Exception ex)
                {
                    return BadRequest("编辑失败");
                }
            }
            else
            {
                return BadRequest("数据输入有误!");
            }
        }

        /// <summary>
        /// 递归函数,实现获取子菜单
        /// </summary>
        /// <param name="lists">递归前的列表</param>
        /// <param name="newlists">递归后的新列表</param>
        /// <param name="parentId">父Id</param>
        /// <returns></returns>
        public static List<CategorySelectItemListView> GetChildCategory(List<CategorySelectItemListView> lists, List<CategorySelectItemListView> newlists, int parentId)
        {
            newlists = new List<CategorySelectItemListView>();
            List<CategorySelectItemListView> tempList = lists.Where(c => c.ParentId == parentId).ToList();
            for (int i = 0; i < tempList.Count; i++)
            {
                CategorySelectItemListView category = new CategorySelectItemListView();
                category.Id = tempList[i].Id;
                category.ParentId = tempList[i].ParentId;
                category.Title = tempList[i].Title;
                category.Children = GetChildCategory(lists, newlists, category.Id);
                newlists.Add(category);
            }
            return newlists;
        }

        /// <summary>
        /// 循环嵌套,实现获取子菜单
        /// </summary>
        /// <param name="lists">循环遍历前的列表</param>
        /// <returns></returns>
        public static List<CategorySelectItemListView> GetChildCategory(List<CategorySelectItemListView> lists)
        {
            List<CategorySelectItemListView> categorylist = new List<CategorySelectItemListView>();
            for (int i = 0; i < lists.Count; i++)
            {
                if (0 == lists[i].ParentId)
                    categorylist.Add(lists[i]);

                for (int j = 0; j < lists.Count; j++)
                {
                    if (lists[j].ParentId == lists[i].Id)
                        lists[i].Children.Add(lists[j]);
                }
            }
            return categorylist;
        }


    }

(6).Service应用层代码

39139-20221121150147333-734536496.jpg
    public class ArticleService : IArticleService
    {
        private readonly AppDbContext _appDbContext;
        public ArticleService(AppDbContext appDbContext)
        {
            _appDbContext = appDbContext;
        }
        /// <summary>
        /// 添加文章
        /// </summary>
        /// <param name="article"></param>
        /// <returns></returns>
        public async Task<bool> AddArticleAysnc(Article article)
        {
            article.IsDeleted = false;
            article.AddManagerId = 1;//用户id
            article.AddTime = DateTime.Now;
            article.IsPublish = true;
            await _appDbContext.Article.AddAsync(article);
            var result = await _appDbContext.SaveChangesAsync();
            return result == 1;
        }

        /// <summary>
        /// 删除文章
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<bool> DeleteArticleAsync(int Id)
        {
            var article = await _appDbContext.Article.FirstOrDefaultAsync(x => x.Id == Id);
            if (article != null)
            {
                _appDbContext.Article.Remove(article);
            }
            var result = await _appDbContext.SaveChangesAsync();
            return result == 1; //注意(result==1 如果等式成立,则返回true,说明删除成功)
        }

        /// <summary>
        /// 按Id查询文章
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<Article> FindArticleAsync(int Id)
        {
            var item = await _appDbContext.Article.Where(x => x.Id == Id).FirstOrDefaultAsync();
            return item;
        }

        /// <summary>
        /// 按标题查询文章
        /// </summary>
        /// <param name="title"></param>
        /// <returns></returns>
        public async Task<Article[]> GetArtcleByTitle(string title)
        {
            var items = await _appDbContext.Article.Where(x => x.Title.Contains(title)).ToArrayAsync();
            return items;
        }

        /// <summary>
        /// 查询文章
        /// </summary>
        /// <returns></returns>
        public async Task<Article[]> GetArticles()
        {
            var items = await _appDbContext.Article.Where(x => x.IsDeleted==false).ToArrayAsync();
            return items;
        }

        /// <summary>
        /// 更新文章
        /// </summary>
        /// <param name="id"></param>
        /// <param name="article"></param>
        /// <returns></returns>
        public async Task<bool> UpdateArticleAsync(int id, Article article)
        {
            var oldArticle = await  FindArticleAsync(id); //找出旧对象

            //将新值赋到旧对象上
            oldArticle.Title = article.Title;
            oldArticle.CategoryId = article.CategoryId;
            oldArticle.SeoDescription = article.SeoDescription;
            oldArticle.SeoTitle = article.SeoTitle;
            oldArticle.SeoKeyword = article.SeoKeyword;
            oldArticle.Content = article.Content;
            oldArticle.Sort = article.Sort;
            oldArticle.Source = article.Source;
            oldArticle.IsSlide = article.IsSlide;
            oldArticle.IsPublish = article.IsPublish;
            oldArticle.IsRed = article.IsRed;
            oldArticle.IsTop = article.IsTop;
            oldArticle.ViewCount = article.ViewCount;
            oldArticle.Author = article.Author;
            oldArticle.ImageUrl = article.ImageUrl;

            oldArticle.ModifyManagerId = 11;//
            oldArticle.ModifyTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

            //对旧对象执行更新
            _appDbContext.Entry(oldArticle).State = EntityState.Modified;
            var result = await _appDbContext.SaveChangesAsync();
            return result == 1;
        }
    }

再谈CheckBox的使用

1.在View视图页增加的代码格式如果为:

<input type="checkbox" name="IsTop" asp-for="IsTop" />置顶

或者是这样:

<input asp-for="IsTop" />置顶

那么在生成的html代码中,都会自动成id,name,type=“checkbox” value的属性。

2.在Controller中进行取值时的代码为:

if (Request.Form["IsTop"].Contains("true"))

article.IsTop = true;

article.IsTop = false;

跟踪时发现,View中Checkbox选中是,会产生true和false两个值,如图跟踪变量发现:

39139-20221121150147311-81247631.jpg

如此,取值时,就用了Contains功能,因为View中CheckBox没选中,这只有一个false值;

3.在View视图页增加代码的格式如果为:

<input type="checkbox" name="IsTop" @(Html.Raw(@Model.IsTop ? "checked=\"checked\"" : "")) asp-for="IsTop" />置顶

4.在Controller中进行取值时的代码为:

if (!string.IsNullOrEmpty(Request.Form["IsTop"]))

article.IsTop = true;

article.IsTop = false;

跟踪时发现,View中的CheckBox选中是,取到的值为“on”,如图跟踪发现:

39139-20221121150147474-1893295358.jpg

所以,才用了IsNullOrEmpty这个函数,依据判空来确定是否选中。

但是这样写有个问题,在ModelState.IsValid()的模型验证中,一直无法通过,IsTop一直为false,为此,我干脆就把其去除掉验证:

ModelState.Remove("IsTop");//去除name=IsTop的checkbox的模型验证

5.使用Checkbox,还是要看给在数据表中为其定义的字段类型,Model中的指定类型和验证属性,如果你赋予了Value值,那么就在Controller中取值,Asp.Net Core中Checkbox默认是True和False的值,网上关于@Html.CheckBox()形式也行,你可以尝试跟踪变量值来判断如何处理,其宗旨就是根据具体条件来处理。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK