上篇文章完成了兩個接口:文章列表頁、文章詳情頁,本篇繼續。html
分析:這裏多了一個統計文章數量的字段,能夠直接新建一個模型QueryCategoryDto.cs
繼承CategoryDto
。前端
//QueryCategoryDto.cs namespace Meowv.Blog.Application.Contracts.Blog { public class QueryCategoryDto : CategoryDto { /// <summary> /// 總數 /// </summary> public int Count { get; set; } } }
添加查詢分類列表接口和緩存接口。git
//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); } }
分別實現這兩個接口。github
//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
。app
//QueryTagDto.cs namespace Meowv.Blog.Application.Contracts.Blog { public class QueryTagDto : TagDto { /// <summary> /// 總數 /// </summary> public int Count { get; set; } } }
添加查詢標籤列表接口和緩存接口。async
//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(); } }
分別實現這兩個接口。post
//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(); }
分析:此頁面下包含兩個接口,查詢分類的名稱和當前分類下的文章列表,和文章列表不一樣的是,它不帶分頁。分類包含兩個字段,分類名稱和展現名稱,咱們要把真正的名稱查詢出來展現在頁面上。ui
不須要給他添加返回模型,直接返回一個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
搭配下方課程學習更佳 ↓ ↓ ↓