基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二)

基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二)

转载于:https://github.com/Meowv/Blog

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

分类列表

图片

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

//QueryCategoryDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
public class QueryCategoryDto : CategoryDto
{
///
/// 总数
///
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
{
///
/// 查询分类列表
///
///
Task<ServiceResult<IEnumerable>> 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
{
///
/// 查询分类列表
///
///
///
Task<ServiceResult<IEnumerable>> QueryCategoriesAsync(Func<Task<ServiceResult<IEnumerable>>> 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
{
///
/// 查询分类列表
///
///
public async Task<ServiceResult<IEnumerable>> QueryCategoriesAsync()
{
return await _blogCacheService.QueryCategoriesAsync(async () =>
{
var result = new ServiceResult<IEnumerable>();

            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<ServiceResult<IEnumerable>> QueryCategoriesAsync()
{
return await _blogService.QueryCategoriesAsync();
}

图片

标签列表

图片

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

//QueryTagDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
public class QueryTagDto : TagDto
{
///
/// 总数
///
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
{
///
/// 查询标签列表
///
///
///
Task<ServiceResult<IEnumerable>> QueryTagsAsync(Func<Task<ServiceResult<IEnumerable>>> 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
{
///
/// 查询标签列表
///
///
Task<ServiceResult<IEnumerable>> 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
{
///
/// 查询标签列表
///
///
public async Task<ServiceResult<IEnumerable>> QueryTagsAsync()
{
return await _blogCacheService.QueryTagsAsync(async () =>
{
var result = new ServiceResult<IEnumerable>();

            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<ServiceResult<IEnumerable>> QueryTagsAsync()
{
return await _blogService.QueryTagsAsync();
}

图片

分类名称&文章列表

图片

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

分类名称

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

//IBlogService.Category.cs
///
/// 获取分类名称
///
///
///
Task<ServiceResult> GetCategoryAsync(string name);

//IBlogCacheService.Category.cs
///
/// 获取分类名称
///
///
///
///
Task<ServiceResult> GetCategoryAsync(string name, Func<Task<ServiceResult>> 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
///
/// 获取分类名称
///
///
///
public async Task<ServiceResult> 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。

///
/// 获取分类名称
///
///
///
[HttpGet]
[Route(“category”)]
public async Task<ServiceResult> GetCategoryAsync(([Required] string name)
{
return await _blogService.GetCategoryAsync(name);
}
[Required]Attribute 指定参数name必填。

图片

图片

文章列表

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

//IBlogService.Post.cs
///
/// 通过分类名称查询文章列表
///
///
///
Task<ServiceResult<IEnumerable>> QueryPostsByCategoryAsync(string name);

//IBlogCacheService.Post.cs
///
/// 通过分类名称查询文章列表
///
///
///
///
Task<ServiceResult<IEnumerable>> QueryPostsByCategoryAsync(string name, Func<Task<ServiceResult<IEnumerable>>> 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
///
/// 通过分类名称查询文章列表
///
///
///
public async Task<ServiceResult<IEnumerable>> QueryPostsByCategoryAsync(string name)
{
return await _blogCacheService.QueryPostsByCategoryAsync(name, async () =>
{
var result = new ServiceResult<IEnumerable>();

    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<ServiceResult<IEnumerable>> QueryPostsByCategoryAsync([Required] string name)
{
return await _blogService.QueryPostsByCategoryAsync(name);
}

图片

标签名称&文章列表

图片

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

标签名称

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

//IBlogService.Tag.cs
///
/// 获取标签名称
///
///
///
Task<ServiceResult> GetTagAsync(string name);
//IBlogCacheService.Tag.cs
///
/// 获取标签名称
///
///
///
///
Task<ServiceResult> GetTagAsync(string name, Func<Task<ServiceResult>> 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
///
/// 获取标签名称
///
///
///
public async Task<ServiceResult> 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。

///
/// 获取标签名称
///
///
///
[HttpGet]
[Route(“tag”)]
public async Task<ServiceResult> GetTagAsync(string name)
{
return await _blogService.GetTagAsync(name);
}
[Required]Attribute 指定参数name必填。

图片

图片

文章列表

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

//IBlogService.Post.cs
///
/// 通过标签名称查询文章列表
///
///
///
Task<ServiceResult<IEnumerable>> QueryPostsByTagAsync(string name);
//IBlogCacheService.Post.cs
///
/// 通过标签名称查询文章列表
///
///
///
///
Task<ServiceResult<IEnumerable>> QueryPostsByTagAsync(string name, Func<Task<ServiceResult<IEnumerable>>> 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
///
/// 通过标签名称查询文章列表
///
///
///
public async Task<ServiceResult<IEnumerable>> QueryPostsByTagAsync(string name)
{
return await _blogCacheService.QueryPostsByTagAsync(name, async () =>
{
var result = new ServiceResult<IEnumerable>();

    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<ServiceResult<IEnumerable>> QueryPostsByTagAsync(string name)
{
return await _blogService.QueryPostsByTagAsync(name);
}

图片

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值