基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(二)
阿新 • • 發佈:2020-06-03
## 系列文章
1. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用 abp cli 搭建專案](https://www.cnblogs.com/meowv/p/12896177.html)**
2. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 給專案瘦身,讓它跑起來](https://www.cnblogs.com/meowv/p/12896898.html)**
3. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 完善與美化,Swagger登場](https://www.cnblogs.com/meowv/p/12909558.html)**
4. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 資料訪問和程式碼優先](https://www.cnblogs.com/meowv/p/12913676.html)**
5. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 自定義倉儲之增刪改查](https://www.cnblogs.com/meowv/p/12916613.html)**
6. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 統一規範API,包裝返回模型](https://www.cnblogs.com/meowv/p/12924409.html)**
7. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 再說Swagger,分組、描述、小綠鎖](https://www.cnblogs.com/meowv/p/12924859.html)**
8. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 接入GitHub,用JWT保護你的API](https://www.cnblogs.com/meowv/p/12935693.html)**
9. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 異常處理和日誌記錄](https://www.cnblogs.com/meowv/p/12943699.html)**
10. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 使用Redis快取資料](https://www.cnblogs.com/meowv/p/12956696.html)**
11. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 整合Hangfire實現定時任務處理](https://www.cnblogs.com/meowv/p/12961014.html)**
12. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 用AutoMapper搞定物件對映](https://www.cnblogs.com/meowv/p/12966092.html)**
13. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 定時任務最佳實戰(一)](https://www.cnblogs.com/meowv/p/12971041.html)**
14. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 定時任務最佳實戰(二)](https://www.cnblogs.com/meowv/p/12974439.html)**
15. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 定時任務最佳實戰(三)](https://www.cnblogs.com/meowv/p/12980301.html)**
16. **[基於 abp vNext 和 .NET Core 開發部落格專案 - 部落格介面實戰篇(一)](https://www.cnblogs.com/meowv/p/12987623.html)**
---
[上篇文章](https://www.cnblogs.com/meowv/p/12987623.html)完成了兩個介面:文章列表頁、文章詳情頁,本篇繼續。
## 分類列表
![1](https://img2020.cnblogs.com/blog/891843/202005/891843-20200530205934508-1023085331.png)
分析:這裡多了一個統計文章數量的欄位,可以直接新建一個模型`QueryCategoryDto.cs`繼承`CategoryDto`。
```CSharp
//QueryCategoryDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
public class QueryCategoryDto : CategoryDto
{
///
/// 總數
///
public int Count { get; set; }
}
}
```
新增查詢分類列表介面和快取介面。
```CSharp
//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
{
///
/// 查詢分類列表
///
///
Task>> QueryCategoriesAsync();
}
}
```
```CSharp
//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
{
///
/// 查詢分類列表
///
///
///
Task>> QueryCategoriesAsync(Func>>> factory);
}
}
```
分別實現這兩個介面。
```CSharp
//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";
///
/// 查詢分類列表
///
///
///
public async Task>> QueryCategoriesAsync(Func>>> factory)
{
return await Cache.GetOrAddAsync(KEY_QueryCategories, factory, CacheStrategy.ONE_DAY);
}
}
}
```
```CSharp
//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
{
///
/// 查詢分類列表
///
///
public async Task>> QueryCategoriesAsync()
{
return await _blogCacheService.QueryCategoriesAsync(async () =>
{
var result = new ServiceResult>();
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。
```CSharp
///
/// 查詢分類列表
///
///
[HttpGet]
[Route("categories")]
public async Task>> QueryCategoriesAsync()
{
return await _blogService.QueryCategoriesAsync();
}
```
![2](https://img2020.cnblogs.com/blog/891843/202005/891843-20200530221606938-125033028.png)
## 標籤列表
![3](https://img2020.cnblogs.com/blog/891843/202005/891843-20200530210035938-936314470.png)
分析:和分類列表差不多,新建模型`QueryTagDto.cs`繼承`TagDto`。
```CSharp
//QueryTagDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
public class QueryTagDto : TagDto
{
///
/// 總數
///
public int Count { get; set; }
}
}
```
新增查詢標籤列表介面和快取介面。
```CSharp
//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
{
///
/// 查詢標籤列表
///
///
///
Task>> QueryTagsAsync(Func>>> factory);
}
}
```
```CSharp
//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
{
///
/// 查詢標籤列表
///
///
Task>> QueryTagsAsync();
}
}
```
分別實現這兩個介面。
```CSharp
//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";
///
/// 查詢標籤列表
///
///
///
public async Task>> QueryTagsAsync(Func>>> factory)
{
return await Cache.GetOrAddAsync(KEY_QueryTags, factory, CacheStrategy.ONE_DAY);
}
}
}
```
```CSharp
//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
{
///
/// 查詢標籤列表
///
///
public async Task>> QueryTagsAsync()
{
return await _blogCacheService.QueryTagsAsync(async () =>
{
var result = new ServiceResult>();
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。
```CSharp
///
/// 查詢標籤列表
///
///
[HttpGet]
[Route("tags")]
public async Task>> QueryTagsAsync()
{
return await _blogService.QueryTagsAsync();
}
```
![4](https://img2020.cnblogs.com/blog/891843/202005/891843-20200531203709733-747030904.png)
## 分類名稱&文章列表
![5](https://img2020.cnblogs.com/blog/891843/202005/891843-20200531204711870-406154660.png)
分析:此頁面下包含兩個介面,查詢分類的名稱和當前分類下的文章列表,和文章列表不同的是,它不帶分頁。分類包含兩個欄位,分類名稱和展示名稱,我們要把真正的名稱查詢出來展示在頁面上。
### 分類名稱
不需要給他新增返回模型,直接返回一個string型別即可,同時給一個查詢引數name,新增獲取分類名稱介面和快取介面。
```CSharp
//IBlogService.Category.cs
///
/// 獲取分類名稱
///
///
///
Task> GetCategoryAsync(string name);
```
```CSharp
//IBlogCacheService.Category.cs
///
/// 獲取分類名稱
///
///
///
///
Task> GetCategoryAsync(string name, Func>> factory);
```
實現這兩個介面。
```CSharp
//BlogCacheService.Category.cs
...
public partial class BlogCacheService
{
private const string KEY_GetCategory = "Blog:Category:GetCategory-{0}";
///
/// 獲取分類名稱
///
///
///
///
public async Task> GetCategoryAsync(string name, Func>> factory)
{
return await Cache.GetOrAddAsync(KEY_GetCategory.FormatWith(name), factory, CacheStrategy.ONE_DAY);
}
}
...
```
```CSharp
//BlogService.Category.cs
///
/// 獲取分類名稱
///
///
///
public async Task> GetCategoryAsync(string name)
{
return await _blogCacheService.GetCategoryAsync(name, async () =>
{
var result = new ServiceResult();
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。
```CSharp
///
/// 獲取分類名稱
///
///
///
[HttpGet]
[Route("category")]
public async Task> GetCategoryAsync(([Required] string name)
{
return await _blogService.GetCategoryAsync(name);
}
```
`[Required]`Attribute 指定引數name必填。
![6](https://img2020.cnblogs.com/blog/891843/202005/891843-20200531211747782-1793939137.png)
![7](https://img2020.cnblogs.com/blog/891843/202005/891843-20200531211754464-1880035472.png)
### 文章列表
通過分類名稱查詢文章列表和分頁查詢文章列表返回模型是一樣的,只是不用分頁,所以直接返回一個列表就可以了,新增通過分類名稱查詢文章列表和快取的介面。
```CSharp
//IBlogService.Post.cs
///
/// 通過分類名稱查詢文章列表
///
///
///
Task>> QueryPostsByCategoryAsync(string name);
```
```CSharp
//IBlogCacheService.Post.cs
///
/// 通過分類名稱查詢文章列表
///
///
///
///
Task>> QueryPostsByCategoryAsync(string name, Func>>> factory);
```
分別實現這兩個介面。
```CSharp
//BlogCacheService.Post.cs
...
public partial class BlogCacheService
{
private const string KEY_QueryPostsByCategory = "Blog:Post:QueryPostsByCategory-{0}";
///
/// 通過分類名稱查詢文章列表
///
///
///
///
public async Task>> QueryPostsByCategoryAsync(string name, Func>>> factory)
{
return await Cache.GetOrAddAsync(KEY_QueryPostsByCategory.FormatWith(name), factory, CacheStrategy.ONE_DAY);
}
}
...
```
```CSharp
//BlogService.Post.cs
///
/// 通過分類名稱查詢文章列表
///
///
///
public async Task>> QueryPostsByCategoryAsync(string name)
{
return await _blogCacheService.QueryPostsByCategoryAsync(name, async () =>
{
var result = new ServiceResult>();
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。
```CSharp
///
/// 通過分類名稱查詢文章列表
///
///
///
[HttpGet]
[Route("posts/category")]
public async Task>> QueryPostsByCategoryAsync([Required] string name)
{
return await _blogService.QueryPostsByCategoryAsync(name);
}
```
![8](https://img2020.cnblogs.com/blog/891843/202005/891843-20200531220321132-1666394468.png)
## 標籤名稱&文章列表
![9](https://img2020.cnblogs.com/blog/891843/202005/891843-20200531204717274-1679439636.png)
分析:此頁面和分類頁一樣,包含兩個介面,查詢標籤的名稱和當前標籤下的文章列表。
### 標籤名稱
新增獲取標籤名稱介面和快取介面,`GetTagAsync()`。
```CSharp
//IBlogService.Tag.cs
///
/// 獲取標籤名稱
///
///
///
Task> GetTagAsync(string name);
```
```CSharp
//IBlogCacheService.Tag.cs
///
/// 獲取標籤名稱
///
///
///
///
Task> GetTagAsync(string name, Func>> factory);
```
實現這兩個介面。
```CSharp
//BlogCacheService.Tag.cs
...
public partial class BlogCacheService
{
private const string KEY_GetTag = "Blog:Tag:GetTag-{0}";
///
/// 獲取標籤名稱
///
///
///
///
public async Task> GetTagAsync(string name, Func>> factory)
{
return await Cache.GetOrAddAsync(KEY_GetTag.FormatWith(name), factory, CacheStrategy.ONE_DAY);
}
}
...
```
```CSharp
//BlogService.Tag.cs
///
/// 獲取標籤名稱
///
///
///
public async Task> GetTagAsync(string name)
{
return await _blogCacheService.GetTagAsync(name, async () =>
{
var result = new ServiceResult();
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。
```CSharp
///
/// 獲取標籤名稱
///
///
///
[HttpGet]
[Route("tag")]
public async Task> GetTagAsync(string name)
{
return await _blogService.GetTagAsync(name);
}
```
`[Required]`Attribute 指定引數name必填。
![10](https://img2020.cnblogs.com/blog/891843/202006/891843-20200601160443559-1169185098.png)
![11](https://img2020.cnblogs.com/blog/891843/202006/891843-20200601160449415-1542518908.png)
### 文章列表
和上面一模一樣的,新增通過標籤名稱查詢文章列表介面和快取介面。
```CSharp
//IBlogService.Post.cs
///
/// 通過標籤名稱查詢文章列表
///
///
///
Task>> QueryPostsByTagAsync(string name);
```
```CSharp
//IBlogCacheService.Post.cs
///
/// 通過標籤名稱查詢文章列表
///
///
///
///
Task>> QueryPostsByTagAsync(string name, Func>>> factory);
```
分別實現這兩個介面。
```CSharp
//BlogCacheService.Post.cs
...
public partial class BlogCacheService
{
private const string KEY_QueryPostsByTag = "Blog:Post:QueryPostsByTag-{0}";
///
/// 通過標籤名稱查詢文章列表
///
///
///
///
public async Task>> QueryPostsByTagAsync(string name, Func>>> factory)
{
return await Cache.GetOrAddAsync(KEY_QueryPostsByTag.FormatWith(name), factory, CacheStrategy.ONE_DAY);
}
}
...
```
```CSharp
//BlogService.Post.cs
///
/// 通過標籤名稱查詢文章列表
///
///
///
public async Task>> QueryPostsByTagAsync(string name)
{
return await _blogCacheService.QueryPostsByTagAsync(name, async () =>
{
var result = new ServiceResult>();
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。
```CSharp
///
/// 通過標籤名稱查詢文章列表
///
///
///
[HttpGet]
[Route("posts/tag")]
public async Task>> QueryPostsByTagAsync(string name)
{
return await _blogService.QueryPostsByTagAsync(name);
}
```
![12](https://img2020.cnblogs.com/blog/891843/202006/891843-20200601163237731-1951619840.png)
至此,基本上完成了部落格前端所需的所有查詢介面,就還剩下友鏈的查詢,大家可以自己完成,後面如果需要什麼新的介面再回頭來寫就好了。
開源地址:https://github.com/Meowv/Blog/tree/blog_tutorial
---
**搭配下方課程學習更佳 ↓ ↓ ↓**
[http://gk.link/a/10iQ7](http://gk.link/a/10iQ7)
![7](https://img2020.cnblogs.com/blog/891843/202006/891843-20200603101718800-1586400