.NET 个人博客-给文章添加上标签
个人博客-给文章添加上标签优化计划
[*] 置顶3个且可滚动或切换
[*] 推荐改为4个,然后新增历史文章,将推荐的加载更多放入历史文章,按文章发布时间降序排列。
[*] 标签功能,可以为文章贴上标签
[*] 推荐点赞功能
本篇文章实现文章标签功能
思路
首先需要新增一个标签类Tag,然后Post文章类和Tag标签类的关系是多对多的关系。也就是一个文章可以有多个标签,一个标签也可以被多个文章使用。
为了实现这个多对多关系,光有Tag表和Post表还不够,还需要一个中间表去维护标签和文章之间的关联关系,就定为PostTag表吧。
代码实现
准备工作
为Post类新增导航属性
public List<Tag> Tags { get; set; }新增Tag类
public class Tag
{
/// <summary>
/// 标签ID
/// </summary>
//主键
public int Id { get; set; }
/// <summary>
/// 标签名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 导航属性 - 文章列表
/// </summary>
public List<Post>? Posts { get; set; }
}新增PostTag类
public class PostTag
{
/// <summary>
/// 标签ID
/// </summary>
public int TagId { get; set; }
/// <summary>
/// 导航属性 - 文章
/// </summary>
public Post Post { get; set; }
/// <summary>
/// 导航属性 - 标签
/// </summary>
public Tag Tag { get; set; }
}在DbContext数据库上下文中添加新增类
public DbSet<Tag> Tags { get; set; }
public DbSet<PostTag> PostTags { get; set; }然后是上下文的protected override void OnModelCreating(ModelBuilder modelBuilder)方法中添加
modelBuilder.Entity<Post>()
.HasMany(e => e.Tags)
.WithMany(e => e.Posts)
.UsingEntity<PostTag>();类创建完成后,需要在数据库中新增Tags表和PostTags表,使用Code First模式或者手动创建都行。
控制器
修改之前打包上传文章的控制器,新增List tags
public async Task<ApiResponse<Post>> Upload( String Categoryname,String Parent, List<string> tags,IFormFile file, ICategoryService categoryService )服务
在之前的打包上传服务新增标签处理
public async Task<Post> Upload(int CategoryId, List<string> tags,IFormFile file){
....之前的代码
foreach (var tagName in tags)
{
var tag = await _myDbContext.Tags.FirstOrDefaultAsync(t => t.Name == tagName);
if (tag == null)
{
tag = new Tag { Name = tagName };
_myDbContext.Tags.Add(tag);
}
var postTag = new PostTag
{
Post = post,
Tag = tag
};
_myDbContext.PostTags.Add(postTag);
}
await _myDbContext.SaveChangesAsync();
return post;
}接口测试
可以看到tags是一个数组类型的参数
数据库也是添加成功了
Razor页面
上述只是简单的在上传文章的时候设置了一下标签,接下来设计一下页面显示
分页查询服务
首先是分页查询服务,可以看到是返回的一个元组,然后PaginationMetadata是分页数据,之前在做推荐博客加载的时候提过一下,之前是没有用到的,然后现在是用到了,所以需要计算一下分页的信息。顺便提一下这个类是大佬的一个Nuget包,然后是提供了ApiResponsePaged类去把元组和数据类结合在一起,在博客的评论中就用到了ApiResponsePaged类来返回数据给前端。但考虑的标签页的设计,就没用这个类,而是直接使用元组,我发现元组用着也不错。
public async Task<(List<PostTag>, PaginationMetadata)> GetAllTagPostAsync(QueryParameters param)
{
var postTags = await _myDbContext.PostTags
.Where(p => p.TagId == param.TagId)
.Include(p => p.Post)
.ThenInclude(p => p.Categories)
.Include(p => p.Post)
.ThenInclude(p => p.Comments)
.Include(p => p.Post)
.ThenInclude(p => p.Tags)
.Skip((param.Page - 1) * param.PageSize)
.Take(param.PageSize)
.ToListAsync();
var totalCount = await _myDbContext.PostTags.CountAsync(p => p.TagId == param.TagId);
var pageCount = (int)Math.Ceiling((double)totalCount / param.PageSize);
var pagination = new PaginationMetadata()
{
PageNumber = param.Page,
PageSize = param.PageSize,
TotalItemCount = totalCount,
PageCount = pageCount,
HasPreviousPage = param.Page > 1,
HasNextPage = param.Page < pageCount,
IsFirstPage = param.Page == 1,
IsLastPage = param.Page == pageCount,
FirstItemOnPage = (param.Page - 1) * param.PageSize + 1,
LastItemOnPage = Math.Min(param.Page * param.PageSize, totalCount)
};
return (postTags, pagination);
}控制器
public async Task<IActionResult> Index(int tagId = 1, int page = 1, int pageSize = 8)
{
var TagList = await _tagService.GetAllTagAsync();
if (TagList.Count == 0)
return View(new TagIndex()
{
TagList = await _tagService.GetAllTagAsync(),
TagId = 0,
TagAllPosts = await _tagService.GetAllTagPostAsync(
new QueryParameters
{
Page = page,
PageSize = pageSize,
TagId = tagId,
})
});
var currentTag = tagId == 1 ? TagList :await _tagService.GetById(tagId);
if (currentTag == null)
{
_messages.Error($"标签 {currentTag} 不存在!");
return RedirectToAction(nameof(Index));
}
TagIndex tagIndex = new TagIndex()
{
TagList = await _tagService.GetAllTagAsync(),
TagId = currentTag.Id,
TagAllPosts = await _tagService.GetAllTagPostAsync(
new QueryParameters
{
Page = page,
PageSize = pageSize,
TagId = currentTag.Id,
})
};
return View(tagIndex);
}分页组件
@model (Personalblog.Model.ViewModels.Categories.PaginationMetadata,int) <ul > <li disabled" : "")"> « Previous @for (int i = 1; i
页:
[1]