系列文章
- 基于 abp vNext 和 .NET Core 開發博客專案 - 使用 abp cli 搭建專案
- 基于 abp vNext 和 .NET Core 開發博客專案 - 給專案瘦身,讓它跑起來
- 基于 abp vNext 和 .NET Core 開發博客專案 - 完善與美化,Swagger登場
- 基于 abp vNext 和 .NET Core 開發博客專案 - 資料訪問和代碼優先
- 基于 abp vNext 和 .NET Core 開發博客專案 - 自定義倉儲之增刪改查
- 基于 abp vNext 和 .NET Core 開發博客專案 - 統一規范API,包裝回傳模型
- 基于 abp vNext 和 .NET Core 開發博客專案 - 再說Swagger,分組、描述、小綠鎖
- 基于 abp vNext 和 .NET Core 開發博客專案 - 接入GitHub,用JWT保護你的API
- 基于 abp vNext 和 .NET Core 開發博客專案 - 例外處理和日志記錄
- 基于 abp vNext 和 .NET Core 開發博客專案 - 使用Redis快取資料
- 基于 abp vNext 和 .NET Core 開發博客專案 - 集成Hangfire實作定時任務處理
- 基于 abp vNext 和 .NET Core 開發博客專案 - 用AutoMapper搞定物件映射
- 基于 abp vNext 和 .NET Core 開發博客專案 - 定時任務最佳實戰(一)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 定時任務最佳實戰(二)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 定時任務最佳實戰(三)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 博客介面實戰篇(一)
上篇文章完成了兩個介面:文章串列頁、文章詳情頁,本篇繼續,
分類串列

分析:這里多了一個統計文章數量的欄位,可以直接新建一個模型QueryCategoryDto.cs繼承CategoryDto,
//QueryCategoryDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
public class QueryCategoryDto : CategoryDto
{
/// <summary>
/// 總數
/// </summary>
public int Count { get; set; }
}
}
添加查詢分類串列介面和快取介面,
//IBlogService.Category.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Meowv.Blog.Application.Blog
{
public partial interface IBlogService
{
/// <summary>
/// 查詢分類串列
/// </summary>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync();
}
}
//IBlogCacheService.Category.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Meowv.Blog.Application.Caching.Blog
{
public partial interface IBlogCacheService
{
/// <summary>
/// 查詢分類串列
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync(Func<Task<ServiceResult<IEnumerable<QueryCategoryDto>>>> factory);
}
}
分別實作這兩個介面,
//BlogCacheService.Category.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using static Meowv.Blog.Domain.Shared.MeowvBlogConsts;
namespace Meowv.Blog.Application.Caching.Blog.Impl
{
public partial class BlogCacheService
{
private const string KEY_QueryCategories = "Blog:Category:QueryCategories";
/// <summary>
/// 查詢分類串列
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync(Func<Task<ServiceResult<IEnumerable<QueryCategoryDto>>>> factory)
{
return await Cache.GetOrAddAsync(KEY_QueryCategories, factory, CacheStrategy.ONE_DAY);
}
}
}
//BlogService.Category.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Meowv.Blog.Application.Blog.Impl
{
public partial class BlogService
{
/// <summary>
/// 查詢分類串列
/// </summary>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync()
{
return await _blogCacheService.QueryCategoriesAsync(async () =>
{
var result = new ServiceResult<IEnumerable<QueryCategoryDto>>();
var list = from category in await _categoryRepository.GetListAsync()
join posts in await _postRepository.GetListAsync()
on category.Id equals posts.CategoryId
group category by new
{
category.CategoryName,
category.DisplayName
} into g
select new QueryCategoryDto
{
CategoryName = g.Key.CategoryName,
DisplayName = g.Key.DisplayName,
Count = g.Count()
};
result.IsSuccess(list);
return result;
});
}
}
}
快取就不說了,查詢分類串列,聯合查詢文章和分類兩張表,關聯欄位為CategoryId,然后分組,計算出對應的數量,在BlogController中添加API,
/// <summary>
/// 查詢分類串列
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("categories")]
public async Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync()
{
return await _blogService.QueryCategoriesAsync();
}

標簽串列

分析:和分類串列差不多,新建模型QueryTagDto.cs繼承TagDto,
//QueryTagDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
public class QueryTagDto : TagDto
{
/// <summary>
/// 總數
/// </summary>
public int Count { get; set; }
}
}
添加查詢標簽串列介面和快取介面,
//IBlogCacheService.Tag.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Meowv.Blog.Application.Caching.Blog
{
public partial interface IBlogCacheService
{
/// <summary>
/// 查詢標簽串列
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync(Func<Task<ServiceResult<IEnumerable<QueryTagDto>>>> factory);
}
}
//IBlogService.Tag.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Meowv.Blog.Application.Blog
{
public partial interface IBlogService
{
/// <summary>
/// 查詢標簽串列
/// </summary>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync();
}
}
分別實作這兩個介面,
//BlogCacheService.Tag.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using static Meowv.Blog.Domain.Shared.MeowvBlogConsts;
namespace Meowv.Blog.Application.Caching.Blog.Impl
{
public partial class BlogCacheService
{
private const string KEY_QueryTags = "Blog:Tag:QueryTags";
/// <summary>
/// 查詢標簽串列
/// </summary>
/// <param name="factory"></param>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync(Func<Task<ServiceResult<IEnumerable<QueryTagDto>>>> factory)
{
return await Cache.GetOrAddAsync(KEY_QueryTags, factory, CacheStrategy.ONE_DAY);
}
}
}
//BlogService.Tag.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Meowv.Blog.Application.Blog.Impl
{
public partial class BlogService
{
/// <summary>
/// 查詢標簽串列
/// </summary>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync()
{
return await _blogCacheService.QueryTagsAsync(async () =>
{
var result = new ServiceResult<IEnumerable<QueryTagDto>>();
var list = from tags in await _tagRepository.GetListAsync()
join post_tags in await _postTagRepository.GetListAsync()
on tags.Id equals post_tags.TagId
group tags by new
{
tags.TagName,
tags.DisplayName
} into g
select new QueryTagDto
{
TagName = g.Key.TagName,
DisplayName = g.Key.DisplayName,
Count = g.Count()
};
result.IsSuccess(list);
return result;
});
}
}
}
查詢標簽串列需要聯合查詢tags和post_tags,根據TagId進行關聯,然后分組從而獲取標簽下文章的總數,在BlogController中添加API,
/// <summary>
/// 查詢標簽串列
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("tags")]
public async Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync()
{
return await _blogService.QueryTagsAsync();
}

分類名稱&文章串列

分析:此頁面下包含兩個介面,查詢分類的名稱和當前分類下的文章串列,和文章串列不同的是,它不帶分頁,分類包含兩個欄位,分類名稱和展示名稱,我們要把真正的名稱查詢出來展示在頁面上,
分類名稱
不需要給他添加回傳模型,直接回傳一個string型別即可,同時給一個查詢引數name,添加獲取分類名稱介面和快取介面,
//IBlogService.Category.cs
/// <summary>
/// 獲取分類名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Task<ServiceResult<string>> GetCategoryAsync(string name);
//IBlogCacheService.Category.cs
/// <summary>
/// 獲取分類名稱
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<string>> GetCategoryAsync(string name, Func<Task<ServiceResult<string>>> factory);
實作這兩個介面,
//BlogCacheService.Category.cs
...
public partial class BlogCacheService
{
private const string KEY_GetCategory = "Blog:Category:GetCategory-{0}";
/// <summary>
/// 獲取分類名稱
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
public async Task<ServiceResult<string>> GetCategoryAsync(string name, Func<Task<ServiceResult<string>>> factory)
{
return await Cache.GetOrAddAsync(KEY_GetCategory.FormatWith(name), factory, CacheStrategy.ONE_DAY);
}
}
...
//BlogService.Category.cs
/// <summary>
/// 獲取分類名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public async Task<ServiceResult<string>> GetCategoryAsync(string name)
{
return await _blogCacheService.GetCategoryAsync(name, async () =>
{
var result = new ServiceResult<string>();
var category = await _categoryRepository.FindAsync(x => x.DisplayName.Equals(name));
if (null == category)
{
result.IsFailed(ResponseText.WHAT_NOT_EXIST.FormatWith("分類", name));
return result;
}
result.IsSuccess(category.CategoryName);
return result;
});
}
FormatWith()是擴展方法,ResponseText.WHAT_NOT_EXIST是之前說過的常量,直接查詢是否存在當前name的分類,如果不存在給出錯誤提示,存在的話,則只回傳分類名稱,在BlogController中添加API,
/// <summary>
/// 獲取分類名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
[Route("category")]
public async Task<ServiceResult<string>> GetCategoryAsync(([Required] string name)
{
return await _blogService.GetCategoryAsync(name);
}
[Required]Attribute 指定引數name必填,


文章串列
通過分類名稱查詢文章串列和分頁查詢文章串列回傳模型是一樣的,只是不用分頁,所以直接回傳一個串列就可以了,添加通過分類名稱查詢文章串列和快取的介面,
//IBlogService.Post.cs
/// <summary>
/// 通過分類名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync(string name);
//IBlogCacheService.Post.cs
/// <summary>
/// 通過分類名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync(string name, Func<Task<ServiceResult<IEnumerable<QueryPostDto>>>> factory);
分別實作這兩個介面,
//BlogCacheService.Post.cs
...
public partial class BlogCacheService
{
private const string KEY_QueryPostsByCategory = "Blog:Post:QueryPostsByCategory-{0}";
/// <summary>
/// 通過分類名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync(string name, Func<Task<ServiceResult<IEnumerable<QueryPostDto>>>> factory)
{
return await Cache.GetOrAddAsync(KEY_QueryPostsByCategory.FormatWith(name), factory, CacheStrategy.ONE_DAY);
}
}
...
//BlogService.Post.cs
/// <summary>
/// 通過分類名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync(string name)
{
return await _blogCacheService.QueryPostsByCategoryAsync(name, async () =>
{
var result = new ServiceResult<IEnumerable<QueryPostDto>>();
var list = (from posts in await _postRepository.GetListAsync()
join categories in await _categoryRepository.GetListAsync()
on posts.CategoryId equals categories.Id
where categories.DisplayName.Equals(name)
orderby posts.CreationTime descending
select new PostBriefDto
{
Title = posts.Title,
Url = posts.Url,
Year = posts.CreationTime.Year,
CreationTime = posts.CreationTime.TryToDateTime()
})
.GroupBy(x => x.Year)
.Select(x => new QueryPostDto
{
Year = x.Key,
Posts = x.ToList()
});
result.IsSuccess(list);
return result;
});
}
這個邏輯和分頁查詢文章串列是差不多的,聯合查詢文章表和分類表,關聯欄位為CategoryId,指定查詢條件categories.DisplayName==name,以CreationTime倒序排序,年份分組,篩選出所需欄位回傳,在BlogController中添加API,
/// <summary>
/// 通過分類名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
[Route("posts/category")]
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync([Required] string name)
{
return await _blogService.QueryPostsByCategoryAsync(name);
}

標簽名稱&文章串列

分析:此頁面和分類頁一樣,包含兩個介面,查詢標簽的名稱和當前標簽下的文章串列,
標簽名稱
添加獲取標簽名稱介面和快取介面,GetTagAsync(),
//IBlogService.Tag.cs
/// <summary>
/// 獲取標簽名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Task<ServiceResult<string>> GetTagAsync(string name);
//IBlogCacheService.Tag.cs
/// <summary>
/// 獲取標簽名稱
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<string>> GetTagAsync(string name, Func<Task<ServiceResult<string>>> factory);
實作這兩個介面,
//BlogCacheService.Tag.cs
...
public partial class BlogCacheService
{
private const string KEY_GetTag = "Blog:Tag:GetTag-{0}";
/// <summary>
/// 獲取標簽名稱
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
public async Task<ServiceResult<string>> GetTagAsync(string name, Func<Task<ServiceResult<string>>> factory)
{
return await Cache.GetOrAddAsync(KEY_GetTag.FormatWith(name), factory, CacheStrategy.ONE_DAY);
}
}
...
//BlogService.Tag.cs
/// <summary>
/// 獲取標簽名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public async Task<ServiceResult<string>> GetTagAsync(string name)
{
return await _blogCacheService.GetTagAsync(name, async () =>
{
var result = new ServiceResult<string>();
var tag = await _tagRepository.FindAsync(x => x.DisplayName.Equals(name));
if (null == tag)
{
result.IsFailed(ResponseText.WHAT_NOT_EXIST.FormatWith("標簽", name));
return result;
}
result.IsSuccess(tag.TagName);
return result;
});
}
FormatWith()是擴展方法,ResponseText.WHAT_NOT_EXIST是之前說過的常量,直接查詢是否存在當前name的分類,如果不存在給出錯誤提示,存在的話,則只回傳分類名稱,在BlogController中添加API,
/// <summary>
/// 獲取標簽名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
[Route("tag")]
public async Task<ServiceResult<string>> GetTagAsync(string name)
{
return await _blogService.GetTagAsync(name);
}
[Required]Attribute 指定引數name必填,


文章串列
和上面一模一樣的,添加通過標簽名稱查詢文章串列介面和快取介面,
//IBlogService.Post.cs
/// <summary>
/// 通過標簽名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name);
//IBlogCacheService.Post.cs
/// <summary>
/// 通過標簽名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name, Func<Task<ServiceResult<IEnumerable<QueryPostDto>>>> factory);
分別實作這兩個介面,
//BlogCacheService.Post.cs
...
public partial class BlogCacheService
{
private const string KEY_QueryPostsByTag = "Blog:Post:QueryPostsByTag-{0}";
/// <summary>
/// 通過標簽名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name, Func<Task<ServiceResult<IEnumerable<QueryPostDto>>>> factory)
{
return await Cache.GetOrAddAsync(KEY_QueryPostsByTag.FormatWith(name), factory, CacheStrategy.ONE_DAY);
}
}
...
//BlogService.Post.cs
/// <summary>
/// 通過標簽名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name)
{
return await _blogCacheService.QueryPostsByTagAsync(name, async () =>
{
var result = new ServiceResult<IEnumerable<QueryPostDto>>();
var list = (from post_tags in await _postTagRepository.GetListAsync()
join tags in await _tagRepository.GetListAsync()
on post_tags.TagId equals tags.Id
join posts in await _postRepository.GetListAsync()
on post_tags.PostId equals posts.Id
where tags.DisplayName.Equals(name)
orderby posts.CreationTime descending
select new PostBriefDto
{
Title = posts.Title,
Url = posts.Url,
Year = posts.CreationTime.Year,
CreationTime = posts.CreationTime.TryToDateTime()
})
.GroupBy(x => x.Year)
.Select(x => new QueryPostDto
{
Year = x.Key,
Posts = x.ToList()
});
result.IsSuccess(list);
return result;
});
}
這個查詢有點特殊,聯合查詢了3張表,先查post_tags和tags,關聯欄位TagId,再根據PostId查詢posts,指定查詢條件tags.DisplayName==name,以CreationTime倒序排序,年份分組,篩選出所需欄位回傳,在BlogController中添加API,
/// <summary>
/// 通過標簽名稱查詢文章串列
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
[Route("posts/tag")]
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name)
{
return await _blogService.QueryPostsByTagAsync(name);
}

至此,基本上完成了博客前端所需的所有查詢介面,就還剩下友鏈的查詢,大家可以自己完成,后面如果需要什么新的介面再回頭來寫就好了,
開源地址:https://github.com/Meowv/Blog/tree/blog_tutorial
搭配下方課程學習更佳 ↓ ↓ ↓
http://gk.link/a/10iQ7

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/20559.html
標籤:.NET Core
下一篇:SOCKET連接超時問題
