基于.NetCore开发博客项目 StarBlog - (13) 加入友情链接功能
系列文章
- 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客?
- 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目
- 基于.NetCore开发博客项目 StarBlog - (3) 模型设计
- 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入
- 基于.NetCore开发博客项目 StarBlog - (5) 开始搭建Web项目
- 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表
- 基于.NetCore开发博客项目 StarBlog - (7) 页面开发之文章详情页面
- 基于.NetCore开发博客项目 StarBlog - (8) 分类层级结构展示
- 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入
- 基于.NetCore开发博客项目 StarBlog - (10) 图片瀑布流
- 基于.NetCore开发博客项目 StarBlog - (11) 实现访问统计
- 基于.NetCore开发博客项目 StarBlog - (12) Razor页面动态编译
- 基于.NetCore开发博客项目 StarBlog - (13) 加入友情链接功能
- ...
前言
很快啊,pia的一下,博客上线已经一周时间了(网址:http://blog.deali.cn)
阅读量不高,不过对于没有做过SEO的网站来说已经不错了~
这段时间虽然忙不过一直在写代码给博客添砖加瓦(Github上的Commit每天不断的)
这不,友情链接功能来了~
本文来一步步介绍这个功能的实现。
同时所有项目代码已经上传GitHub,欢迎各位大佬Star/Fork!
- 博客后端+前台项目地址:https://github.com/Deali-Axy/StarBlog
- 管理后台前端项目地址:https://github.com/Deali-Axy/StarBlog-Admin
先看效果

分析
先分析一下功能
友情链接,既可以自己手动添加,也可以由访问网站的人申请
其他站长可以申请互换友链,提交申请之后在博客后台可以看到,确认之后就会显示到网站中啦~
这就是初步的功能设计
当然我还想到了一些扩展的功能,比如根据链接的点击量来调整链接的显示顺序(百度:听起来怎么那么熟悉)
建模
根据需求,需要俩模型
一个是要显示的友情链接,一个是友情链接申请记录
那开始吧
在StarBlog.Data/Models中创建数据模型
/// <summary>
/// 友情链接
/// </summary>
public class Link {
[Column(IsIdentity = true, IsPrimary = true)]
public int Id { get; set; }
/// <summary>
/// 网站名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 介绍
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 网址
/// </summary>
public string Url { get; set; }
/// <summary>
/// 是否显示
/// </summary>
public bool Visible { get; set; }
}
还有这个
/// <summary>
/// 友情链接申请记录
/// </summary>
public class LinkExchange {
[Column(IsIdentity = true, IsPrimary = true)]
public int Id { get; set; }
/// <summary>
/// 网站名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 介绍
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 网址
/// </summary>
public string Url { get; set; }
/// <summary>
/// 站长
/// </summary>
public string WebMaster { get; set; }
/// <summary>
/// 联系邮箱
/// </summary>
public string Email { get; set; }
/// <summary>
/// 是否已验证
/// <para>友情链接需要验证后才显示在网站上</para>
/// </summary>
public bool Verified { get; set; } = false;
/// <summary>
/// 申请时间
/// </summary>
public DateTime ApplyTime { get; set; } = DateTime.Now;
}
Service
有了模型,接下来完善一下逻辑
在StarBlog.Web/Services中写逻辑
首先是友情链接的,增删改查除外,还加一个设置可见性的快捷方式
public class LinkService {
private IBaseRepository<Link> _repo;
public LinkService(IBaseRepository<Link> repo) {
_repo = repo;
}
/// <summary>
/// 获取全部友情链接
/// </summary>
/// <param name="onlyVisible">只获取显示的链接</param>
/// <returns></returns>
public List<Link> GetAll(bool onlyVisible = true) {
return onlyVisible
? _repo.Where(a => a.Visible).ToList()
: _repo.Select.ToList();
}
public Link? GetById(int id) {
return _repo.Where(a => a.Id == id).First();
}
public Link? GetByName(string name) {
return _repo.Where(a => a.Name == name).First();
}
public Link AddOrUpdate(Link item) {
return _repo.InsertOrUpdate(item);
}
public Link? SetVisibility(int id, bool visible) {
var item = GetById(id);
if (item == null) return null;
item.Visible = visible;
_repo.Update(item);
return GetById(id);
}
public int DeleteById(int id) {
return _repo.Delete(a => a.Id == id);
}
}
这个没啥特别的
继续
管理友情链接申请记录的逻辑,同样也是有增删改查,这部分代码跟上面的一样,省略了
这里只贴设置是否验证的代码
public class LinkExchangeService {
private readonly IBaseRepository<LinkExchange> _repo;
private readonly LinkService _linkService;
public LinkExchangeService(IBaseRepository<LinkExchange> repo, LinkService linkService) {
_repo = repo;
_linkService = linkService;
}
// 设置是否验证
public LinkExchange? SetVerifyStatus(int id, bool status) {
var item = GetById(id);
if (item == null) return null;
item.Verified = status;
_repo.Update(item);
var link = _linkService.GetByName(item.Name);
if (status) {
if (link == null) {
_linkService.AddOrUpdate(new Link {
Name = item.Name,
Description = item.Description,
Url = item.Url,
Visible = true
});
}
else {
_linkService.SetVisibility(link.Id, true);
}
}
else {
if (link != null) _linkService.DeleteById(link.Id);
}
return GetById(id);
}
}
在设置是否验证的方法中,实现了:
- 设置一个申请为已验证,自动将该申请的链接添加到友情链接中
- 设置一个申请为未验证,则自动将对应的友情链接删除(如果存在的话)
其他地方就跟上面的友情链接一样了。
写完之后别忘了注册服务
builder.Services.AddScoped<LinkExchangeService>();
builder.Services.AddScoped<LinkService>();
添加数据
虽然管理这些链接的接口我也写了,但目前本系列文章还处在介绍前台的部分,我打算把接口实现放到后面的RESTFul接口开发部分讲~
所以先直接在数据库中添加吧~

页面展示
数据模型和逻辑都实现了,接下来就是找一个合适的地方显示
参考了几个同类的博客之后,我决定把友链放在主页底部
编辑StarBlog.Web/ViewModels/HomeViewModel.cs,添加一个新属性
public class HomeViewModel {
/// <summary>
/// 友情链接
/// </summary>
public List<Link> Links { get; set; } = new();
}
用Bootstrap5的responsive variation来做响应式的友情链接展示
<div class="d-grid gap-2 d-md-block">
<button class="btn btn-primary" type="button">Button</button>
<button class="btn btn-primary" type="button">Button</button>
</div>
官网上的例子效果是这样的

勉强还行,不过都是一样的颜色太单调了,我要七彩的!
封装Razor组件
于是封装了一个名为ColorfulButton的Razor组件
先定义ViewModel,用来配置这个组件
在StarBlog.Web/ViewModels中新增ColorfulButtonViewModel.cs文件,代码如下
public static class LinkTarget {
public const string Blank = "_blank";
public const string Parent = "_parent";
public const string Self = "_self";
public const string Top = "_top";
}
public class ColorfulButtonViewModel {
public string Name { get; set; }
public string Url { get; set; } = "#";
public string Target { get; set; } = "_self";
}
然后在StarBlog.Web/Views/Shared/Widgets中新增ColorfulButton.cshtml
把Bootstrap支持的几种按钮颜色放进去,然后每次随机显示一个颜色~
@model ColorfulButtonViewModel
@{
var rnd = Random.Shared;
var colorList = new[] {
"btn-outline-primary",
"btn-outline-secondary",
"btn-outline-success",
"btn-outline-danger",
"btn-outline-warning",
"btn-outline-info",
"btn-outline-dark",
};
var btnColor = colorList[rnd.Next(0, colorList.Length)];
}
<a href="@Model.Url" role="button" class="btn btn-sm @btnColor mb-1" target="@Model.Target">
@Model.Name
</a>
添加到页面中
组件完成了,最后在主页中实现友情链接的展示
编辑StarBlog.Web/Views/Home/Index.cshtml文件
在最底下(推荐博客板块下方)新增代码
<div class="container px-4 py-3">
<h2 class="pb-2 border-bottom">Link Exchange</h2>
@if (Model.Links.Count > 0) {
<div class="d-grid gap-2 d-md-block">
@foreach (var link in Model.Links) {
@await Html.PartialAsync("Widgets/ColorfulButton",
new ColorfulButtonViewModel { Name = link.Name, Url = link.Url })
}
</div>
}
else {
@await Html.PartialAsync("Widgets/PlaceholderCard", "友情链接")
}
</div>
最终效果就是一开始展示的那样,每次访问都会有不同的颜色,老炫酷了~
搞定
完成了,很简单的一个功能,可以给单调的博客小小增色一下~
同时也欢迎各位站长大佬来交换友链~!
基于.NetCore开发博客项目 StarBlog - (13) 加入友情链接功能的更多相关文章
- 基于.NetCore开发博客项目 StarBlog - (14) 实现主题切换功能
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (15) 生成随机尺寸图片
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (16) 一些新功能 (监控/统计/配置/初始化)
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (17) 自动下载文章里的外部图片
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (18) 实现本地Typora文章打包上传
前言 九月太忙,只更新了三篇文章,本来这个功能是从九月初就开始做的,结果一直拖到现在国庆假期才有时间完善并且写文章~ 之前我更新了几篇关于 Python 的文章,有朋友留言问是不是不更新 .Net 了 ...
- 基于.NetCore开发博客项目 StarBlog - (19) Markdown渲染方案探索
前言 笔者认为,一个博客网站,最核心的是阅读体验. 在开发StarBlog的过程中,最耗时的恰恰也是文章的展示部分功能. 最开始还没研究出来如何很好的使用后端渲染,所以只能先用Editor.md组件做 ...
- 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 ... 基于. ...
- 基于.NetCore开发博客项目 StarBlog - (3) 模型设计
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- 基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
随机推荐
- toFixed()与银行家舍入
toFixed()与银行家舍入 一直在用toFixed()方法做浮点数的舍入取值,如果只是客户端展示数据是没有多大问题的,但是如果涉及到和后端互交,数据的精度可能会导致接口对接失败,当然了,涉及安全性 ...
- Java语言学习day08--7月7日
###13遍历数组 * A:遍历数组 * 在操作数组时,经常需要依次访问数组中的每个元素,这种操作称作数组的遍历 * B:练习 public class ArrayDemo04 { publ ...
- XGBoost文本分类,多分类、二分类、10-Fold(K-Fold)
做机器学习的时候经常用到XGB,简单记录一下 K折交叉验证也是模型常用的优化方法.一起记录... K折交叉验证:类似三个臭皮匠,顶个诸葛亮.我的理解是,就是用民主投票的方式,选取票数最高的那个当结果. ...
- 记一次 PHP 省市县三级联动 数据库取值
/** * Notes:省市县三级联动 * Created by depressiom * Date: 2022年4月14日 */ public function getCityData(){ //获 ...
- vue package.json 详解
示例: { "name": "scrm", "version": "0.1.0", "private" ...
- Python 什么是flask框架?快速入门
一:Python flask框架 前言 1.Python 面向对象的高级编程语言,以其语法简单.免费开源.免编译扩展性高,同时也可以嵌入到C/C++程序和丰富的第三方库,Python运用到大数据分析. ...
- scrapy架构与目录介绍、scrapy解析数据、配置相关、全站爬取cnblogs数据、存储数据、爬虫中间件、加代理、加header、集成selenium
今日内容概要 scrapy架构和目录介绍 scrapy解析数据 setting中相关配置 全站爬取cnblgos文章 存储数据 爬虫中间件和下载中间件 加代理,加header,集成selenium 内 ...
- Spring 源码(13)Spring Bean 的创建过程(4)
Spring Bean的创建过程非常的复杂,上一篇重点介绍了Spring在创建Bean的过程中,使用InstantiationBeanPostProcessor进行提前创建Bean,我们可以通过CGL ...
- 基础路径规划算法(Dijikstra、A*、D*)总结
引言 在一张固定地图上选择一条路径,当存在多条可选的路径之时,需要选择代价最小的那条路径.我们称这类问题为最短路径的选择问题.解决这个问题最经典的算法为Dijikstra算法,其通过贪心选择的步骤从源 ...
- 命令行参数 getopt模块
getopt中的函数: getopt.getopt(sys.argv[1:], shortopts, longopts=[]) args指的是当前脚本接收的参数,它是一个列表,可以通过sys.argv ...