本文介绍了24.博客系统项目开发之友链模块功能实现求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。
对技术面试,学习经验等有一些体会,在此分享。
Spring Boot 博客系统项目开发之友链模块功能实现
本项目的开源仓库地址为:https://github.com/ZHENFENG13/My-Blog
除 My-Blog 项目外,我也在维护另外一个开源项目,仓库地址为:https://github.com/newbee-ltd/newbee-mall
感兴趣的朋友可以去关注一下。
文章总览
本节实验将会对博客的友情链接管理模块进行介绍和功能开发及完善。
知识点
- 友情链接模块介绍
- 友情链接模块表结构设计及接口实现
- 友情链接模块页面设计及编码
- 友情链接功能测试
环境
- JDK 1.8 或者更高版本
- Spring Boot 2.1.0-RELEASE
- Maven 3+
友情链接模块简介
友情链接是具有一定资源互补优势的网站之间的简单合作形式,即分别在自己的网站上放置对方网站的 LOGO 图片或文字的网站名称,并设置对方网站的超链接使得用户可以从合作网站中发现自己的网站,达到互相推广的目的,因此常作为一种网站推广基本手段。友情链接是指互相在自己的网站上放对方网站的链接。必须要能在网页代码中找到网址和网站名称,而且浏览网页的时候能显示网站名称,这样才叫友情链接。
以下为部分博客网站的友情链接模块:
通常来说,友情链接交换的意义主要体现在如下几方面:
- 提升网站流量
- 完善用户体验
- 增加网站外链
- 提高关键字排名
- 提高网站权重
- 提高知名度
自建的技术博客网站毕竟是私人网站,流量和关注度肯定不会特别高,通过友情链接的设置可以增加一些流量,这也是大部分技术博客中不可缺少的一个元素,基本上每个博主都会设置友情链接。
表结构设计及 Mapper 文件自动生成
表结构设计
在进行接口设计和具体的功能实现前,首先将表结构确定下来,根据前文中几张友情链接模块的图片我们可以发现,该模块也只是用作展示使用,其中有三个字段是非常重要的,依次为:
- 友情链接的名称
- 友情链接的跳转链接
- 友情链接的简单描述
基于此友情链接表的 SQL 设计如下,直接执行如下 SQL 语句即可:
USE `my_blog_db`; DROP TABLE IF EXISTS `tb_link`; CREATE TABLE `tb_link` ( `link_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '友链表主键id', `link_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '友链类别 0-友链 1-推荐 2-个人网站', `link_name` varchar(50) NOT NULL COMMENT '网站名称', `link_url` varchar(100) NOT NULL COMMENT '网站链接', `link_description` varchar(100) NOT NULL COMMENT '网站描述', `link_rank` int(11) NOT NULL DEFAULT '0' COMMENT '用于列表排序', `is_deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否删除 0-未删除 1-已删除', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间', PRIMARY KEY (`link_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
友情链接表的字段以及每个字段对应的含义都在上面的 SQL 中有介绍,大家可以对照 SQL 进行理解,在三个基础字段的基础上又添加了友链类别 link_type 字段,因为有些链接是个人网站,为了更好的区分友链就加了此字段,把表结构导入到数据库中即可,接下来我们进行编码工作。
MyBatis-Generator 插件自动生成 Mapper 文件
首先,我们使用 MyBatis-Generator 插件将该表对应的 Mapper 文件及对应的实体类和 Dao 层接口生成出来,这部分代码就不贴在文章中了,大家可以通过下载源码来查看。
需要注意的是,在代码生成后需要在 dao 层下的 BlogLinkMapper 接口类上添加 @Mapper 注解以将其注册到 IOC 容器中以供后续调用(如果已经在主类上添加 @MapperScan 注解这一步可以省略)。其次,在 tb_link 表中,我们设计了一个 is_deleted 字段,用于逻辑删除的标志位,由于 is_deleted 的字段设计,我们对表中数据的删除都是软删除,而不是真正意义的删除,只是做了一个删除标志位,如果此字段为 1 则表示已经被删除不再使用,因为是个人博客,这么做的目的主要也是为了防止误删,因此我们需要修改 Mapper 文件中的 查询语句和删除语句,将 is_deleted 条件带上,修改后的语句如下:(注:完整代码位于 resources/mapper/BlogLinkMapper.xml)
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from tb_link where link_id = #{linkId,jdbcType=INTEGER} AND is_deleted = 0 </select> <update id="deleteByPrimaryKey" parameterType="java.lang.Integer"> UPDATE tb_link SET is_deleted = 1 where link_id = #{linkId,jdbcType=INTEGER} AND is_deleted = 0 </update>
通过以上代码我们可以看出,在删除操作时我们并不是执行 delete 语句,而是将需要删除的这条记录的 is_deleted 字段修改为 1,这样就表示该行记录已经被执行了删除操作,那么其他的 select 查询语句就需要在查询条件中添加 is_deleted = 0
将“被删除”的记录给过滤出去,这个知识点希望大家能够理解,在后续的其他功能模块中我们也会使用软删除的设计。
友情链接管理页面制作
导航栏
首先在左侧导航栏中新增友情链接管理页的导航按钮,在 sidebar.html 文件中新增如下代码:(注:完整代码位于 resources/templates/admin/sidebar.html)
<li class="nav-item"> <a th:href="@{/admin/links}" th:class="${path}=='links'?'nav-link active':'nav-link'" > <i class="fa fa-heart nav-icon" aria-hidden="true"></i> <p> 友情链接 </p> </a> </li>
点击后的跳转路径为 /admin/links,之后我们新建 Controller 来处理该路径并跳转到对应的页面。
Controller 处理跳转
首先在 controller/admin 包下新建 LinkController.java,之后新增如下代码:
package com.site.blog.my.core.controller.admin; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; @Controller @RequestMapping("/admin") public class LinkController { @GetMapping("/links") public String linkPage(HttpServletRequest request) { request.setAttribute("path", "links"); return "admin/link"; } }
该方法用于处理 /admin/links 请求,并设置 path 字段,之后跳转到 admin 目录下的 link.html 中。
link.html 页面制作
接下来就是博客编辑页面的模板文件制作了,在 resources/templates/admin 目录下新建 link.html,并引入对应的 js 文件和 css 样式文件,代码如下:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <header th:replace="admin/header::header-fragment"></header> <body class="hold-transition sidebar-mini"> <div class="wrapper"> <!-- 引入页面头header-fragment --> <div th:replace="admin/header::header-nav"></div> <!-- 引入工具栏sidebar-fragment --> <div th:replace="admin/sidebar::sidebar-fragment(${path})"></div> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <div class="content-header"> <div class="container-fluid"> </div><!-- /.container-fluid --> </div> <!-- Main content --> <div class="content"> <div class="container-fluid"> <div class="card card-primary card-outline"> <div class="card-header"> <h3 class="card-title">友情链接管理</h3> </div> <!-- /.card-body --> </div> </div> </div> <div th:replace="admin/footer::footer-fragment"></div> </div> <!-- jQuery --> <script th:src="@{/admin/plugins/jquery/jquery.min.js}"></script> <!-- jQuery UI 1.11.4 --> <script th:src="@{/admin/plugins/jQueryUI/jquery-ui.min.js}"></script> <!-- Bootstrap 4 --> <script th:src="@{/admin/plugins/bootstrap/js/bootstrap.bundle.min.js}"></script> <!-- AdminLTE App --> <script th:src="@{/admin/dist/js/adminlte.min.js}"></script> </body> </html>
至此,跳转逻辑处理完毕,演示效果如下:
友情链接模块接口设计及实现
接口介绍
友链模块在后台管理系统中有 5 个接口,分别是:
- 友链列表分页接口
- 添加友链接口
- 根据 id 获取单条友链记录接口
- 修改友链接口
- 删除友链接口
接下来讲解每个接口具体的实现代码,首先在 controller/admin 包下新建 LinkController.java,并在 service 包下新建业务层代码 LinkService.java 及实现类,之后参照接口分别进行功能实现。
友情链接列表分页接口
列表接口负责接收前端传来的分页参数,如 page 、limit 等参数,之后将数据总数和对应页面的数据列表查询出来并封装为分页数据返回给前端。
- 控制层代码(注:完整代码位于 com.site.blog.my.core.controller.admin.LinkController.java):
接口的映射地址为 /links/list,请求方法为 GET,代码如下:
/** * 友链列表 */ @GetMapping("/links/list") @ResponseBody public Result list(@RequestParam Map<String, Object> params) { if (StringUtils.isEmpty(params.get("page")) || StringUtils.isEmpty(params.get("limit"))) { return ResultGenerator.genFailResult("参数异常!"); } PageQueryUtil pageUtil = new PageQueryUtil(params); return ResultGenerator.genSuccessResult(linkService.getBlogLinkPage(pageUtil)); }
- 业务层代码(注:完整代码位于 com.site.blog.my.core.service.impl.LinkServiceImpl.java):
public PageResult getBlogLinkPage(PageQueryUtil pageUtil) { List<BlogLink> links = blogLinkMapper.findLinkList(pageUtil); int total = blogLinkMapper.getTotalLinks(pageUtil); PageResult pageResult = new PageResult(links, total, pageUtil.getLimit(), pageUtil.getPage()); return pageResult; }
- BlogLinkMapper.xml (注:完整代码位于 resources/mapper/BlogLinkMapper.xml):
<select id="findLinkList" parameterType="Map" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from tb_link where is_deleted=0 order by link_id desc <if test="start!=null and limit!=null"> limit #{start},#{limit} </if> </select> <select id="getTotalLinks" parameterType="Map" resultType="int"> select count(*) from tb_link where is_deleted=0 </select>
SQL 语句在 BlogLinkMapper.xml 文件中,一般的分页也就是使用 limit
关键字实现,获取响应条数的记录和总数之后再进行数据封装,这个接口就是根据前端传的分页参数进行查询并返回分页数据以供前端页面进行数据渲染。
添加友链接口
添加接口负责接收前端的 POST 请求并处理其中的参数,接收的参数依次为:
-
linkType 字段(友链类型)
-
linkName 字段(友链名称)
-
linkUrl 字段(友链的跳转链接)
-
linkRank 字段(排序值)
-
linkDescription 字段(友链简介)
- 控制层代码(注:完整代码位于 com.site.blog.my.core.controller.admin.LinkController.java):
接口的映射地址为 /links/save,请求方法为 POST,代码如下:
/** * 友链添加 */ @RequestMapping(value = "/links/save", method = RequestMethod.POST) @ResponseBody public Result save(@RequestParam("linkType") Integer linkType, @RequestParam("linkName") String linkName, @RequestParam("linkUrl") String linkUrl, @RequestParam("linkRank") Integer linkRank, @RequestParam("linkDescription") String linkDescription) { if (linkType == null || linkType < 0 || linkRank == null || linkRank < 0 || StringUtils.isEmpty(linkName) || StringUtils.isEmpty(linkName) || StringUtils.isEmpty(linkUrl) || StringUtils.isEmpty(linkDescription)) { return ResultGenerator.genFailResult("参数异常!"); } BlogLink link = new BlogLink(); link.setLinkType(linkType.byteValue()); link.setLinkRank(linkRank); link.setLinkName(linkName); link.setLinkUrl(linkUrl); link.setLinkDescription(linkDescription); return ResultGenerator.genSuccessResult(linkService.saveLink(link)); }
- 业务层代码(注:完整代码位于 com.site.blog.my.core.service.impl.LinkServiceImpl.java):
public Boolean saveLink(BlogLink link) { return blogLinkMapper.insertSelective(link) > 0; }
SQL 语句在 BlogLinkMapper.xml 文件中,是自动生成的 SQL,这里就不贴了。添加接口中,首先会对参数进行校验,之后交给业务层代码进行操作。
删除友情链接接口
删除接口负责接收前端的友情链接删除请求,处理前端传输过来的数据后,将这些记录从数据库中删除,这里的“删除”功能并不是真正意义上的删除,而是逻辑删除,我们将接受的参数设置为一个数组,可以同时删除多条记录,只需要在前端将用户选择的记录 id 封装好再传参到后端即可。
- 控制层代码(注:完整代码位于 com.site.blog.my.core.controller.admin.LinkController.java):
接口的映射地址为 /links/delete,请求方法为 POST,代码如下:
/** * 友链删除 */ @RequestMapping(value = "/links/delete", method = RequestMethod.POST) @ResponseBody public Result delete(@RequestBody Integer[] ids) { if (ids.length < 1) { return ResultGenerator.genFailResult("参数异常!"); } if (linkService.deleteBatch(ids)) { return ResultGenerator.genSuccessResult(); } else { return ResultGenerator.genFailResult("删除失败"); } }
- 业务层代码(注:完整代码位于 com.site.blog.my.core.service.impl.LinkServiceImpl.java):
public Boolean deleteBatch(Integer[] ids) { return blogLinkMapper.deleteBatch(ids) > 0; }
- BlogLinkMapper.xml (注:完整代码位于 resources/mapper/BlogLinkMapper.xml):
<update id="deleteBatch"> update tb_link set is_deleted=1 where link_id in <foreach item="id" collection="array" open="(" separator="," close=")"> #{id} </foreach> </update>
接口的请求路径为 /links/delete,并使用 @RequestBody 将前端传过来的参数封装为 id 数组,参数验证通过后则调用 deleteBatch() 批量删除方法进行数据库操作,否则将向前端返回错误信息。
其它
还有根据 id 获取详情的接口,路径为 links/info/{id},请求方法为 GET;修改接口,路径为 links/update,请求方法为 POST。在接口设计和实现完成后,需要对接口进行测试,如果出现问题立刻修复,以上这些代码我都已经编写完成并将代码以压缩包的形式提供,大家在学习时可以直接使用我给的代码进行练习。
前端页面实现
功能按钮
友情链接管理模块我们也设计了常用的几个功能:友链信息增加、友链信息编辑、友链信息删除,因此在页面中添加对应的功能按钮以及触发事件,代码如下:(注:完整代码位于 resources/templates/admin/link.html)
<div class="grid-btn"> <button class="btn btn-info" onclick="linkAdd()"> <i class="fa fa-plus"></i> 新增 </button> <button class="btn btn-info" onclick="linkEdit()"> <i class="fa fa-pencil-square-o"></i> 修改 </button> <button class="btn btn-danger" onclick="deleteLink()"> <i class="fa fa-trash-o"></i> 删除 </button> </div>
分别是添加按钮对应的触发事件是 linkAdd()
方法,修改按钮对应的触发事件是 linkEdit()
方法,删除按钮对应的触发事件是 deleteLink()
方法,这些方法我们将在后续的代码实现中给出。
分页信息展示区域
Spring Boot 博客系统项目开发之友链模块功能实现
本项目的开源仓库地址为:https://github.com/ZHENFENG13/My-Blog
除 My-Blog 项目外,我也在维护另外一个开源项目,仓库地址为:https://github.com/newbee-ltd/newbee-mall
感兴趣的朋友可以去关注一下。
文章总览
本节实验将会对博客的友情链接管理模块进行介绍和功能开发及完善。
知识点
- 友情链接模块介绍
- 友情链接模块表结构设计及接口实现
- 友情链接模块页面设计及编码
- 友情链接功能测试
环境
- JDK 1.8 或者更高版本
- Spring Boot 2.1.0-RELEASE
- Maven 3+
友情链接模块简介
友情链接是具有一定资源互补优势的网站之间的简单合作形式,即分别在自己的网站上放置对方网站的 LOGO 图片或文字的网站名称,并设置对方网站的超链接使得用户可以从合作网站中发现自己的网站,达到互相推广的目的,因此常作为一种网站推广基本手段。友情链接是指互相在自己的网站上放对方网站的链接。必须要能在网页代码中找到网址和网站名称,而且浏览网页的时候能显示网站名称,这样才叫友情链接。
以下为部分博客网站的友情链接模块:
通常来说,友情链接交换的意义主要体现在如下几方面:
- 提升网站流量
- 完善用户体验
- 增加网站外链
- 提高关键字排名
- 提高网站权重
- 提高知名度
自建的技术博客网站毕竟是私人网站,流量和关注度肯定不会特别高,通过友情链接的设置可以增加一些流量,这也是大部分技术博客中不可缺少的一个元素,基本上每个博主都会设置友情链接。
表结构设计及 Mapper 文件自动生成
表结构设计
在进行接口设计和具体的功能实现前,首先将表结构确定下来,根据前文中几张友情链接模块的图片我们可以发现,该模块也只是用作展示使用,其中有三个字段是非常重要的,依次为:
- 友情链接的名称
- 友情链接的跳转链接
- 友情链接的简单描述
基于此友情链接表的 SQL 设计如下,直接执行如下 SQL 语句即可:
USE `my_blog_db`; DROP TABLE IF EXISTS `tb_link`; CREATE TABLE `tb_link` ( `link_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '友链表主键id', `link_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '友链类别 0-友链 1-推荐 2-个人网站', `link_name` varchar(50) NOT NULL COMMENT '网站名称', `link_url` varchar(100) NOT NULL COMMENT '网站链接', `link_description` varchar(100) NOT NULL COMMENT '网站描述', `link_rank` int(11) NOT NULL DEFAULT '0' COMMENT '用于列表排序', `is_deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否删除 0-未删除 1-已删除', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间', PRIMARY KEY (`link_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
友情链接表的字段以及每个字段对应的含义都在上面的 SQL 中有介绍,大家可以对照 SQL 进行理解,在三个基础字段的基础上又添加了友链类别 link_type 字段,因为有些链接是个人网站,为了更好的区分友链就加了此字段,把表结构导入到数据库中即可,接下来我们进行编码工作。
MyBatis-Generator 插件自动生成 Mapper 文件
首先,我们使用 MyBatis-Generator 插件将该表对应的 Mapper 文件及对应的实体类和 Dao 层接口生成出来,这部分代码就不贴在文章中了,大家可以通过下载源码来查看。
需要注意的是,在代码生成后需要在 dao 层下的 BlogLinkMapper 接口类上添加 @Mapper 注解以将其注册到 IOC 容器中以供后续调用(如果已经在主类上添加 @MapperScan 注解这一步可以省略)。其次,在 tb_link 表中,我们设计了一个 is_deleted 字段,用于逻辑删除的标志位,由于 is_deleted 的字段设计,我们对表中数据的删除都是软删除,而不是真正意义的删除,只是做了一个删除标志位,如果此字段为 1 则表示已经被删除不再使用,因为是个人博客,这么做的目的主要也是为了防止误删,因此我们需要修改 Mapper 文件中的 查询语句和删除语句,将 is_deleted 条件带上,修改后的语句如下:(注:完整代码位于 resources/mapper/BlogLinkMapper.xml)
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from tb_link where link_id = #{linkId,jdbcType=INTEGER} AND is_deleted = 0 </select> <update id="deleteByPrimaryKey" parameterType="java.lang.Integer"> UPDATE tb_link SET is_deleted = 1 where link_id = #{linkId,jdbcType=INTEGER} AND is_deleted = 0 </update>
通过以上代码我们可以看出,在删除操作时我们并不是执行 delete 语句,而是将需要删除的这条记录的 is_deleted 字段修改为 1,这样就表示该行记录已经被执行了删除操作,那么其他的 select 查询语句就需要在查询条件中添加 is_deleted = 0
将“被删除”的记录给过滤出去,这个知识点希望大家能够理解,在后续的其他功能模块中我们也会使用软删除的设计。
友情链接管理页面制作
导航栏
首先在左侧导航栏中新增友情链接管理页的导航按钮,在 sidebar.html 文件中新增如下代码:(注:完整代码位于 resources/templates/admin/sidebar.html)
<li class="nav-item"> <a th:href="@{/admin/links}" th:class="${path}=='links'?'nav-link active':'nav-link'" > <i class="fa fa-heart nav-icon" aria-hidden="true"></i> <p> 友情链接 </p> </a> </li>
点击后的跳转路径为 /admin/links,之后我们新建 Controller 来处理该路径并跳转到对应的页面。
Controller 处理跳转
首先在 controller/admin 包下新建 LinkController.java,之后新增如下代码:
package com.site.blog.my.core.controller.admin; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; @Controller @RequestMapping("/admin") public class LinkController { @GetMapping("/links") public String linkPage(HttpServletRequest request) { request.setAttribute("path", "links"); return "admin/link"; } }
该方法用于处理 /admin/links 请求,并设置 path 字段,之后跳转到 admin 目录下的 link.html 中。
link.html 页面制作
接下来就是博客编辑页面的模板文件制作了,在 resources/templates/admin 目录下新建 link.html,并引入对应的 js 文件和 css 样式文件,代码如下:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <header th:replace="admin/header::header-fragment"></header> <body class="hold-transition sidebar-mini"> <div class="wrapper"> <!-- 引入页面头header-fragment --> <div th:replace="admin/header::header-nav"></div> <!-- 引入工具栏sidebar-fragment --> <div th:replace="admin/sidebar::sidebar-fragment(${path})"></div> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <div class="content-header"> <div class="container-fluid"> </div><!-- /.container-fluid --> </div> <!-- Main content --> <div class="content"> <div class="container-fluid"> <div class="card card-primary card-outline"> <div class="card-header"> <h3 class="card-title">友情链接管理</h3> </div> <!-- /.card-body --> </div> </div> </div> <div th:replace="admin/footer::footer-fragment"></div> </div> <!-- jQuery --> <script th:src="@{/admin/plugins/jquery/jquery.min.js}"></script> <!-- jQuery UI 1.11.4 --> <script th:src="@{/admin/plugins/jQueryUI/jquery-ui.min.js}"></script> <!-- Bootstrap 4 --> <script th:src="@{/admin/plugins/bootstrap/js/bootstrap.bundle.min.js}"></script> <!-- AdminLTE App --> <script th:src="@{/admin/dist/js/adminlte.min.js}"></script> </body> </html>
至此,跳转逻辑处理完毕,演示效果如下:
友情链接模块接口设计及实现
接口介绍
友链模块在后台管理系统中有 5 个接口,分别是:
- 友链列表分页接口
- 添加友链接口
- 根据 id 获取单条友链记录接口
- 修改友链接口
- 删除友链接口
接下来讲解每个接口具体的实现代码,首先在 controller/admin 包下新建 LinkController.java,并在 service 包下新建业务层代码 LinkService.java 及实现类,之后参照接口分别进行功能实现。
友情链接列表分页接口
列表接口负责接收前端传来的分页参数,如 page 、limit 等参数,之后将数据总数和对应页面的数据列表查询出来并封装为分页数据返回给前端。
- 控制层代码(注:完整代码位于 com.site.blog.my.core.controller.admin.LinkController.java):
接口的映射地址为 /links/list,请求方法为 GET,代码如下:
/** * 友链列表 */ @GetMapping("/links/list") @ResponseBody public Result list(@RequestParam Map<String, Object> params) { if (StringUtils.isEmpty(params.get("page")) || StringUtils.isEmpty(params.get("limit"))) { return ResultGenerator.genFailResult("参数异常!"); } PageQueryUtil pageUtil = new PageQueryUtil(params); return ResultGenerator.genSuccessResult(linkService.getBlogLinkPage(pageUtil)); }
- 业务层代码(注:完整代码位于 com.site.blog.my.core.service.impl.LinkServiceImpl.java):
public PageResult getBlogLinkPage(PageQueryUtil pageUtil) { List<BlogLink> links = blogLinkMapper.findLinkList(pageUtil); int total = blogLinkMapper.getTotalLinks(pageUtil); PageResult pageResult = new PageResult(links, total, pageUtil.getLimit(), pageUtil.getPage()); return pageResult; }
- BlogLinkMapper.xml (注:完整代码位于 resources/mapper/BlogLinkMapper.xml):
<select id="findLinkList" parameterType="Map" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from tb_link where is_deleted=0 order by link_id desc <if test="start!=null and limit!=null"> limit #{start},#{limit} </if> </select> <select id="getTotalLinks" parameterType="Map" resultType="int"> select count(*) from tb_link where is_deleted=0 </select>
SQL 语句在 BlogLinkMapper.xml 文件中,一般的分页也就是使用 limit
关键字实现,获取响应条数的记录和总数之后再进行数据封装,这个接口就是根据前端传的分页参数进行查询并返回分页数据以供前端页面进行数据渲染。
添加友链接口
添加接口负责接收前端的 POST 请求并处理其中的参数,接收的参数依次为:
-
linkType 字段(友链类型)
-
linkName 字段(友链名称)
-
linkUrl 字段(友链的跳转链接)
-
linkRank 字段(排序值)
-
linkDescription 字段(友链简介)
- 控制层代码(注:完整代码位于 com.site.blog.my.core.controller.admin.LinkController.java):
接口的映射地址为 /links/save,请求方法为 POST,代码如下:
/** * 友链添加 */ @RequestMapping(value = "/links/save", method = RequestMethod.POST) @ResponseBody public Result save(@RequestParam("linkType") Integer linkType, @RequestParam("linkName") String linkName, @RequestParam("linkUrl") String linkUrl, @RequestParam("linkRank") Integer linkRank, @RequestParam("linkDescription") String linkDescription) { if (linkType == null || linkType < 0 || linkRank == null || linkRank < 0 || StringUtils.isEmpty(linkName) || StringUtils.isEmpty(linkName) || StringUtils.isEmpty(linkUrl) || StringUtils.isEmpty(linkDescription)) { return ResultGenerator.genFailResult("参数异常!"); } BlogLink link = new BlogLink(); link.setLinkType(linkType.byteValue()); link.setLinkRank(linkRank); link.setLinkName(linkName); link.setLinkUrl(linkUrl); link.setLinkDescription(linkDescription); return ResultGenerator.genSuccessResult(linkService.saveLink(link)); }
- 业务层代码(注:完整代码位于 com.site.blog.my.core.service.impl.LinkServiceImpl.java):
public Boolean saveLink(BlogLink link) { return blogLinkMapper.insertSelective(link) > 0; }
SQL 语句在 BlogLinkMapper.xml 文件中,是自动生成的 SQL,这里就不贴了。添加接口中,首先会对参数进行校验,之后交给业务层代码进行操作。
删除友情链接接口
删除接口负责接收前端的友情链接删除请求,处理前端传输过来的数据后,将这些记录从数据库中删除,这里的“删除”功能并不是真正意义上的删除,而是逻辑删除,我们将接受的参数设置为一个数组,可以同时删除多条记录,只需要在前端将用户选择的记录 id 封装好再传参到后端即可。
- 控制层代码(注:完整代码位于 com.site.blog.my.core.controller.admin.LinkController.java):
接口的映射地址为 /links/delete,请求方法为 POST,代码如下:
/** * 友链删除 */ @RequestMapping(value = "/links/delete", method = RequestMethod.POST) @ResponseBody public Result delete(@RequestBody Integer[] ids) { if (ids.length < 1) { return ResultGenerator.genFailResult("参数异常!"); } if (linkService.deleteBatch(ids)) { return ResultGenerator.genSuccessResult(); } else { return ResultGenerator.genFailResult("删除失败"); } }
- 业务层代码(注:完整代码位于 com.site.blog.my.core.service.impl.LinkServiceImpl.java):
public Boolean deleteBatch(Integer[] ids) { return blogLinkMapper.deleteBatch(ids) > 0; }
- BlogLinkMapper.xml (注:完整代码位于 resources/mapper/BlogLinkMapper.xml):
<update id="deleteBatch"> update tb_link set is_deleted=1 where link_id in <foreach item="id" collection="array" open="(" separator="," close=")"> #{id} </foreach> </update>
接口的请求路径为 /links/delete,并使用 @RequestBody 将前端传过来的参数封装为 id 数组,参数验证通过后则调用 deleteBatch() 批量删除方法进行数据库操作,否则将向前端返回错误信息。
其它
还有根据 id 获取详情的接口,路径为 links/info/{id},请求方法为 GET;修改接口,路径为 links/update,请求方法为 POST。在接口设计和实现完成后,需要对接口进行测试,如果出现问题立刻修复,以上这些代码我都已经编写完成并将代码以压缩包的形式提供,大家在学习时可以直接使用我给的代码进行练习。
前端页面实现
功能按钮
友情链接管理模块我们也设计了常用的几个功能:友链信息增加、友链信息编辑、友链信息删除,因此在页面中添加对应的功能按钮以及触发事件,代码如下:(注:完整代码位于 resources/templates/admin/link.html)
<div class="grid-btn"> <button class="btn btn-info" onclick="linkAdd()"> <i class="fa fa-plus"></i> 新增 </button> <button class="btn btn-info" onclick="linkEdit()"> <i class="fa fa-pencil-square-o"></i> 修改 </button> <button class="btn btn-danger" onclick="deleteLink()"> <i class="fa fa-trash-o"></i> 删除 </button> </div>
分别是添加按钮对应的触发事件是 linkAdd()
方法,修改按钮对应的触发事件是 linkEdit()
方法,删除按钮对应的触发事件是 deleteLink()
方法,这些方法我们将在后续的代码实现中给出。
分页信息展示区域
Spring Boot 博客系统项目开发之友链模块功能实现
本项目的开源仓库地址为:https://github.com/ZHENFENG13/My-Blog
除 My-Blog 项目外,我也在维护另外一个开源项目,仓库地址为:https://github.com/newbee-ltd/newbee-mall
感兴趣的朋友可以去关注一下。
文章总览
本节实验将会对博客的友情链接管理模块进行介绍和功能开发及完善。
知识点
- 友情链接模块介绍
- 友情链接模块表结构设计及接口实现
- 友情链接模块页面设计及编码
- 友情链接功能测试
环境
- JDK 1.8 或者更高版本
- Spring Boot 2.1.0-RELEASE
- Maven 3+
友情链接模块简介
友情链接是具有一定资源互补优势的网站之间的简单合作形式,即分别在自己的网站上放置对方网站的 LOGO 图片或文字的网站名称,并设置对方网站的超链接使得用户可以从合作网站中发现自己的网站,达到互相推广的目的,因此常作为一种网站推广基本手段。友情链接是指互相在自己的网站上放对方网站的链接。必须要能在网页代码中找到网址和网站名称,而且浏览网页的时候能显示网站名称,这样才叫友情链接。
以下为部分博客网站的友情链接模块:
通常来说,友情链接交换的意义主要体现在如下几方面:
- 提升网站流量
- 完善用户体验
- 增加网站外链
- 提高关键字排名
- 提高网站权重
- 提高知名度
自建的技术博客网站毕竟是私人网站,流量和关注度肯定不会特别高,通过友情链接的设置可以增加一些流量,这也是大部分技术博客中不可缺少的一个元素,基本上每个博主都会设置友情链接。
表结构设计及 Mapper 文件自动生成
表结构设计
在进行接口设计和具体的功能实现前,首先将表结构确定下来,根据前文中几张友情链接模块的图片我们可以发现,该模块也只是用作展示使用,其中有三个字段是非常重要的,依次为:
- 友情链接的名称
- 友情链接的跳转链接
- 友情链接的简单描述
基于此友情链接表的 SQL 设计如下,直接执行如下 SQL 语句即可:
USE `my_blog_db`; DROP TABLE IF EXISTS `tb_link`; CREATE TABLE `tb_link` ( `link_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '友链表主键id', `link_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '友链类别 0-友链 1-推荐 2-个人网站', `link_name` varchar(50) NOT NULL COMMENT '网站名称', `link_url` varchar(100) NOT NULL COMMENT '网站链接', `link_description` varchar(100) NOT NULL COMMENT '网站描述', `link_rank` int(11) NOT NULL DEFAULT '0' COMMENT '用于列表排序', `is_deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否删除 0-未删除 1-已删除', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间', PRIMARY KEY (`link_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
友情链接表的字段以及每个字段对应的含义都在上面的 SQL 中有介绍,大家可以对照 SQL 进行理解,在三个基础字段的基础上又添加了友链类别 link_type 字段,因为有些链接是个人网站,为了更好的区分友链就加了此字段,把表结构导入到数据库中即可,接下来我们进行编码工作。
MyBatis-Generator 插件自动生成 Mapper 文件
首先,我们使用 MyBatis-Generator 插件将该表对应的 Mapper 文件及对应的实体类和 Dao 层接口生成出来,这部分代码就不贴在文章中了,大家可以通过下载源码来查看。
需要注意的是,在代码生成后需要在 dao 层下的 BlogLinkMapper 接口类上添加 @Mapper 注解以将其注册到 IOC 容器中以供后续调用(如果已经在主类上添加 @MapperScan 注解这一步可以省略)。其次,在 tb_link 表中,我们设计了一个 is_deleted 字段,用于逻辑删除的标志位,由于 is_deleted 的字段设计,我们对表中数据的删除都是软删除,而不是真正意义的删除,只是做了一个删除标志位,如果此字段为 1 则表示已经被删除不再使用,因为是个人博客,这么做的目的主要也是为了防止误删,因此我们需要修改 Mapper 文件中的 查询语句和删除语句,将 is_deleted 条件带上,修改后的语句如下:(注:完整代码位于 resources/mapper/BlogLinkMapper.xml)
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from tb_link where link_id = #{linkId,jdbcType=INTEGER} AND is_deleted = 0 </select> <update id="deleteByPrimaryKey" parameterType="java.lang.Integer"> UPDATE tb_link SET is_deleted = 1 where link_id = #{linkId,jdbcType=INTEGER} AND is_deleted = 0 </update>
通过以上代码我们可以看出,在删除操作时我们并不是执行 delete 语句,而是将需要删除的这条记录的 is_deleted 字段修改为 1,这样就表示该行记录已经被执行了删除操作,那么其他的 select 查询语句就需要在查询条件中添加 is_deleted = 0
将“被删除”的记录给过滤出去,这个知识点希望大家能够理解,在后续的其他功能模块中我们也会使用软删除的设计。
友情链接管理页面制作
导航栏
首先在左侧导航栏中新增友情链接管理页的导航按钮,在 sidebar.html 文件中新增如下代码:(注:完整代码位于 resources/templates/admin/sidebar.html)
<li class="nav-item"> <a th:href="@{/admin/links}" th:class="${path}=='links'?'nav-link active':'nav-link'" > <i class="fa fa-heart nav-icon" aria-hidden="true"></i> <p> 友情链接 </p> </a> </li>
点击后的跳转路径为 /admin/links,之后我们新建 Controller 来处理该路径并跳转到对应的页面。
Controller 处理跳转
首先在 controller/admin 包下新建 LinkController.java,之后新增如下代码:
package com.site.blog.my.core.controller.admin; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; @Controller @RequestMapping("/admin") public class LinkController { @GetMapping("/links") public String linkPage(HttpServletRequest request) { request.setAttribute("path", "links"); return "admin/link"; } }
该方法用于处理 /admin/links 请求,并设置 path 字段,之后跳转到 admin 目录下的 link.html 中。
link.html 页面制作
接下来就是博客编辑页面的模板文件制作了,在 resources/templates/admin 目录下新建 link.html,并引入对应的 js 文件和 css 样式文件,代码如下:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <header th:replace="admin/header::header-fragment"></header> <body class="hold-transition sidebar-mini"> <div class="wrapper"> <!-- 引入页面头header-fragment --> <div th:replace="admin/header::header-nav"></div> <!-- 引入工具栏sidebar-fragment --> <div th:replace="admin/sidebar::sidebar-fragment(${path})"></div> <!-- Content Wrapper. Contains page content --> <div class="content-wrapper"> <!-- Content Header (Page header) --> <div class="content-header"> <div class="container-fluid"> </div><!-- /.container-fluid --> </div> <!-- Main content --> <div class="content"> <div class="container-fluid"> <div class="card card-primary card-outline"> <div class="card-header"> <h3 class="card-title">友情链接管理</h3> </div> <!-- /.card-body --> </div> </div> </div> <div th:replace="admin/footer::footer-fragment"></div> </div> <!-- jQuery --> <script th:src="@{/admin/plugins/jquery/jquery.min.js}"></script> <!-- jQuery UI 1.11.4 --> <script th:src="@{/admin/plugins/jQueryUI/jquery-ui.min.js}"></script> <!-- Bootstrap 4 --> <script th:src="@{/admin/plugins/bootstrap/js/bootstrap.bundle.min.js}"></script> <!-- AdminLTE App --> <script th:src="@{/admin/dist/js/adminlte.min.js}"></script> </body> </html>
至此,跳转逻辑处理完毕,演示效果如下:
友情链接模块接口设计及实现
接口介绍
友链模块在后台管理系统中有 5 个接口,分别是:
- 友链列表分页接口
- 添加友链接口
- 根据 id 获取单条友链记录接口
- 修改友链接口
- 删除友链接口
接下来讲解每个接口具体的实现代码,首先在 controller/admin 包下新建 LinkController.java,并在 service 包下新建业务层代码 LinkService.java 及实现类,之后参照接口分别进行功能实现。
友情链接列表分页接口
列表接口负责接收前端传来的分页参数,如 page 、limit 等参数,之后将数据总数和对应页面的数据列表查询出来并封装为分页数据返回给前端。
- 控制层代码(注:完整代码位于 com.site.blog.my.core.controller.admin.LinkController.java):
接口的映射地址为 /links/list,请求方法为 GET,代码如下:
/** * 友链列表 */ @GetMapping("/links/list") @ResponseBody public Result list(@RequestParam Map<String, Object> params) { if (StringUtils.isEmpty(params.get("page")) || StringUtils.isEmpty(params.get("limit"))) { return ResultGenerator.genFailResult("参数异常!"); } PageQueryUtil pageUtil = new PageQueryUtil(params); return ResultGenerator.genSuccessResult(linkService.getBlogLinkPage(pageUtil)); }
- 业务层代码(注:完整代码位于 com.site.blog.my.core.service.impl.LinkServiceImpl.java):
public PageResult getBlogLinkPage(PageQueryUtil pageUtil) { List<BlogLink> links = blogLinkMapper.findLinkList(pageUtil); int total = blogLinkMapper.getTotalLinks(pageUtil); PageResult pageResult = new PageResult(links, total, pageUtil.getLimit(), pageUtil.getPage()); return pageResult; }
- BlogLinkMapper.xml (注:完整代码位于 resources/mapper/BlogLinkMapper.xml):
<select id="findLinkList" parameterType="Map" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from tb_link where is_deleted=0 order by link_id desc <if test="start!=null and limit!=null"> limit #{start},#{limit} </if> </select> <select id="getTotalLinks" parameterType="Map" resultType="int"> select count(*) from tb_link where is_deleted=0 </select>
SQL 语句在 BlogLinkMapper.xml 文件中,一般的分页也就是使用 limit
关键字实现,获取响应条数的记录和总数之后再进行数据封装,这个接口就是根据前端传的分页参数进行查询并返回分页数据以供前端页面进行数据渲染。
添加友链接口
添加接口负责接收前端的 POST 请求并处理其中的参数,接收的参数依次为:
-
linkType 字段(友链类型)
-
linkName 字段(友链名称)
-
linkUrl 字段(友链的跳转链接)
-
linkRank 字段(排序值)
-
linkDescription 字段(友链简介)
- 控制层代码(注:完整代码位于 com.site.blog.my.core.controller.admin.LinkController.java):
接口的映射地址为 /links/save,请求方法为 POST,代码如下:
/** * 友链添加 */ @RequestMapping(value = "/links/save", method = RequestMethod.POST) @ResponseBody public Result save(@RequestParam("linkType") Integer linkType, @RequestParam("linkName") String linkName, @RequestParam("linkUrl") String linkUrl, @RequestParam("linkRank") Integer linkRank, @RequestParam("linkDescription") String linkDescription) { if (linkType == null || linkType < 0 || linkRank == null || linkRank < 0 || StringUtils.isEmpty(linkName) || StringUtils.isEmpty(linkName) || StringUtils.isEmpty(linkUrl) || StringUtils.isEmpty(linkDescription)) { return ResultGenerator.genFailResult("参数异常!"); } BlogLink link = new BlogLink(); link.setLinkType(linkType.byteValue()); link.setLinkRank(linkRank); link.setLinkName(linkName); link.setLinkUrl(linkUrl); link.setLinkDescription(linkDescription); return ResultGenerator.genSuccessResult(linkService.saveLink(link)); }
- 业务层代码(注:完整代码位于 com.site.blog.my.core.service.impl.LinkServiceImpl.java):
public Boolean saveLink(BlogLink link) { return blogLinkMapper.insertSelective(link) > 0; }
SQL 语句在 BlogLinkMapper.xml 文件中,是自动生成的 SQL,这里就不贴了。添加接口中,首先会对参数进行校验,之后交给业务层代码进行操作。
删除友情链接接口
删除接口负责接收前端的友情链接删除请求,处理前端传输过来的数据后,将这些记录从数据库中删除,这里的“删除”功能并不是真正意义上的删除,而是逻辑删除,我们将接受的参数设置为一个数组,可以同时删除多条记录,只需要在前端将用户选择的记录 id 封装好再传参到后端即可。
- 控制层代码(注:完整代码位于 com.site.blog.my.core.controller.admin.LinkController.java):
接口的映射地址为 /links/delete,请求方法为 POST,代码如下:
/** * 友链删除 */ @RequestMapping(value = "/links/delete", method = RequestMethod.POST) @ResponseBody public Result delete(@RequestBody Integer[] ids) { if (ids.length < 1) { return ResultGenerator.genFailResult("参数异常!"); } if (linkService.deleteBatch(ids)) { return ResultGenerator.genSuccessResult(); } else { return ResultGenerator.genFailResult("删除失败"); } }
- 业务层代码(注:完整代码位于 com.site.blog.my.core.service.impl.LinkServiceImpl.java):
public Boolean deleteBatch(Integer[] ids) { return blogLinkMapper.deleteBatch(ids) > 0; }
- BlogLinkMapper.xml (注:完整代码位于 resources/mapper/BlogLinkMapper.xml):
<update id="deleteBatch"> update tb_link set is_deleted=1 where link_id in <foreach item="id" collection="array" open="(" separator="," close=")"> #{id} </foreach> </update>
接口的请求路径为 /links/delete,并使用 @RequestBody 将前端传过来的参数封装为 id 数组,参数验证通过后则调用 deleteBatch() 批量删除方法进行数据库操作,否则将向前端返回错误信息。
其它
还有根据 id 获取详情的接口,路径为 links/info/{id},请求方法为 GET;修改接口,路径为 links/update,请求方法为 POST。在接口设计和实现完成后,需要对接口进行测试,如果出现问题立刻修复,以上这些代码我都已经编写完成并将代码以压缩包的形式提供,大家在学习时可以直接使用我给的代码进行练习。
前端页面实现
功能按钮
友情链接管理模块我们也设计了常用的几个功能:友链信息增加、友链信息编辑、友链信息删除,因此在页面中添加对应的功能按钮以及触发事件,代码如下:(注:完整代码位于 resources/templates/admin/link.html)
<div class="grid-btn"> <button class="btn btn-info" onclick="linkAdd()"> <i class="fa fa-plus"></i> 新增 </button> <button class="btn btn-info" onclick="linkEdit()"> <i class="fa fa-pencil-square-o"></i> 修改 </button> <button class="btn btn-danger" onclick="deleteLink()"> <i class="fa fa-trash-o"></i> 删除 </button> </div>
分别是添加按钮对应的触发事件是 linkAdd()
方法,修改按钮对应的触发事件是 linkEdit()
方法,删除按钮对应的触发事件是 deleteLink()
方法,这些方法我们将在后续的代码实现中给出。
分页信息展示区域
部分转自互联网,侵权删除联系
最新评论