表2.1搜索博客列表接口描述表_基于 abp vNext 和 .NET Core 开发博客项目 博客接口实战篇(二)...

系列文章

  1. 使用 abp cli 搭建项目
  2. 给项目瘦身,让它跑起来
  3. 完善与美化,Swagger登场
  4. 数据访问和代码优先
  5. 自定义仓储之增删改查
  6. 统一规范API,包装返回模型
  7. 再说Swagger,分组、描述、小绿锁
  8. 接入GitHub,用JWT保护你的API
  9. 异常处理和日志记录
  10. 使用Redis缓存数据
  11. 集成Hangfire实现定时任务处理
  12. 用AutoMapper搞定对象映射
  13. 定时任务最佳实战(一)
  14. 定时任务最佳实战(二)
  15. 定时任务最佳实战(三)
  16. 博客接口实战篇(一)


上篇文章完成了两个接口:文章列表页、文章详情页,本篇继续。

分类列表

007c81f7b71089c71285e677689c6605.png

分析:这里多了一个统计文章数量的字段,可以直接新建一个模型QueryCategoryDto.cs继承CategoryDto

//QueryCategoryDto.csnamespace Meowv.Blog.Application.Contracts.Blog{    public class QueryCategoryDto : CategoryDto    {        ///         /// 总数        ///         public int Count { get; set; }    }}

添加查询分类列表接口和缓存接口。

//IBlogService.Category.csusing 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();    }}
//IBlogCacheService.Category.csusing 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);    }}

分别实现这两个接口。

//BlogCacheService.Category.csusing 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);        }    }}
//BlogService.Category.csusing 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。

/// /// 查询分类列表/// /// [HttpGet][Route("categories")]public async Task>> QueryCategoriesAsync(){    return await _blogService.QueryCategoriesAsync();}

f28007af50956bf2eff2f16bde0c7377.png

标签列表

c0c479c8704fe83534279bff84dc92a6.png

分析:和分类列表差不多,新建模型QueryTagDto.cs继承TagDto

//QueryTagDto.csnamespace Meowv.Blog.Application.Contracts.Blog{    public class QueryTagDto : TagDto    {        ///         /// 总数        ///         public int Count { get; set; }    }}

添加查询标签列表接口和缓存接口。

//IBlogCacheService.Tag.csusing 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);    }}
//IBlogService.Tag.csusing 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();    }}

分别实现这两个接口。

//BlogCacheService.Tag.csusing 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);        }    }}
//BlogService.Tag.csusing 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。

/// /// 查询标签列表/// /// [HttpGet][Route("tags")]public async Task>> QueryTagsAsync(){    return await _blogService.QueryTagsAsync();}

3541f774fdca22b519fcc9055e2a9622.png

分类名称&文章列表

b19c654b22aae3befae50ed1b607e816.png

分析:此页面下包含两个接口,查询分类的名称和当前分类下的文章列表,和文章列表不同的是,它不带分页。分类包含两个字段,分类名称和展示名称,我们要把真正的名称查询出来展示在页面上。

分类名称

不需要给他添加返回模型,直接返回一个string类型即可,同时给一个查询参数name,添加获取分类名称接口和缓存接口。

//IBlogService.Category.cs/// /// 获取分类名称/// /// /// Taskstring>> GetCategoryAsync(
//IBlogCacheService.Category.cs/// /// 获取分类名称/// /// /// /// Taskstring>> GetCategoryAsync(

实现这两个接口。

//BlogCacheService.Category.cs...    public partial class BlogCacheService    {        private const string KEY_GetCategory = "Blog:Category:GetCategory-{0}";        ///         /// 获取分类名称        ///         ///         ///         ///         public async Taskstring>> GetCategoryAsync(        {            return await Cache.GetOrAddAsync(KEY_GetCategory.FormatWith(name), factory, CacheStrategy.ONE_DAY);        }    }...
//BlogService.Category.cs/// /// 获取分类名称/// /// /// public async Taskstring>> GetCategoryAsync({    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。

/// /// 获取分类名称/// /// /// [HttpGet][Route("category")]public async Taskstring>> GetCategoryAsync(([Required] {    return await _blogService.GetCategoryAsync(name);}

[Required]Attribute 指定参数name必填。

90ef4235970b2879c092f25831243084.png

d5644b0a0af19b9ec5509ee6a47ab6ed.png

文章列表

通过分类名称查询文章列表和分页查询文章列表返回模型是一样的,只是不用分页,所以直接返回一个列表就可以了,添加通过分类名称查询文章列表和缓存的接口。

//IBlogService.Post.cs/// /// 通过分类名称查询文章列表/// /// /// Task>> QueryPostsByCategoryAsync(string name);
//IBlogCacheService.Post.cs/// /// 通过分类名称查询文章列表/// /// /// /// Task>> QueryPostsByCategoryAsync(string name, Func>>> factory);

分别实现这两个接口。

//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);        }    }...
//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。

/// /// 通过分类名称查询文章列表/// /// /// [HttpGet][Route("posts/category")]public async Task>> QueryPostsByCategoryAsync([Required] string name){    return await _blogService.QueryPostsByCategoryAsync(name);}

c7d0928879a079fd0e4c25c89907830f.png

标签名称&文章列表

8c13d55f5e4b9f2baff537457f330732.png

分析:此页面和分类页一样,包含两个接口,查询标签的名称和当前标签下的文章列表。

标签名称

添加获取标签名称接口和缓存接口,GetTagAsync()

//IBlogService.Tag.cs/// /// 获取标签名称/// /// /// Taskstring>> GetTagAsync(
//IBlogCacheService.Tag.cs/// /// 获取标签名称/// /// /// /// Taskstring>> GetTagAsync(

实现这两个接口。

//BlogCacheService.Tag.cs...    public partial class BlogCacheService    {        private const string KEY_GetTag = "Blog:Tag:GetTag-{0}";        ///         /// 获取标签名称        ///         ///         ///         ///         public async Taskstring>> GetTagAsync(        {            return await Cache.GetOrAddAsync(KEY_GetTag.FormatWith(name), factory, CacheStrategy.ONE_DAY);        }    }...
//BlogService.Tag.cs/// /// 获取标签名称/// /// /// public async Taskstring>> GetTagAsync({    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。

/// /// 获取标签名称/// /// /// [HttpGet][Route("tag")]public async Taskstring>> GetTagAsync({    return await _blogService.GetTagAsync(name);}

[Required]Attribute 指定参数name必填。

b9dc9e35b10c7a28325089e38be39921.png

e7dd8824166a7a315a4592a6656f90bc.png

文章列表

和上面一模一样的,添加通过标签名称查询文章列表接口和缓存接口。

//IBlogService.Post.cs/// /// 通过标签名称查询文章列表/// /// /// Task>> QueryPostsByTagAsync(string name);
//IBlogCacheService.Post.cs/// /// 通过标签名称查询文章列表/// /// /// /// Task>> QueryPostsByTagAsync(string name, Func>>> factory);

分别实现这两个接口。

//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);        }    }...
//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。

/// /// 通过标签名称查询文章列表/// /// /// [HttpGet][Route("posts/tag")]public async Task>> QueryPostsByTagAsync(string name){    return await _blogService.QueryPostsByTagAsync(name);}

2a27dfb1c931d28a251403571a377c1e.png

至此,基本上完成了博客前端所需的所有查询接口,就还剩下友链的查询,大家可以自己完成,后面如果需要什么新的接口再回头来写就好了。

开源地址:https://github.com/Meowv/Blog/tree/blog_tutorial


搭配下方课程学习更佳 ↓ ↓ ↓

44fa044457d60ad09263674d47efef1a.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值