From 18b25015c76c0c8b3f0acc3359bb51adac75ce42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cduan138=E2=80=9D?= Date: Sat, 22 Oct 2022 21:51:29 +0800 Subject: [PATCH 1/2] =?UTF-8?q?sql=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/sg_article.sql | 49 ++++++++++++++ sql/sg_article_tag.sql | 36 ++++++++++ sql/sg_category.sql | 44 ++++++++++++ sql/sg_comment.sql | 46 +++++++++++++ sql/sg_link.sql | 45 +++++++++++++ sql/sg_menu.sql | 103 +++++++++++++++++++++++++++++ sql/sg_tag.sql | 42 ++++++++++++ sql/sys_user.sql | 49 ++++++++++++++ "sql/\350\257\264\346\230\216.txt" | 1 + 9 files changed, 415 insertions(+) create mode 100644 sql/sg_article.sql create mode 100644 sql/sg_article_tag.sql create mode 100644 sql/sg_category.sql create mode 100644 sql/sg_comment.sql create mode 100644 sql/sg_link.sql create mode 100644 sql/sg_menu.sql create mode 100644 sql/sg_tag.sql create mode 100644 sql/sys_user.sql create mode 100644 "sql/\350\257\264\346\230\216.txt" diff --git a/sql/sg_article.sql b/sql/sg_article.sql new file mode 100644 index 0000000..40a8c4b --- /dev/null +++ b/sql/sg_article.sql @@ -0,0 +1,49 @@ +/* +SQLyog v10.2 +MySQL - 5.5.40 : Database - sg_blog +********************************************************************* +*/ + +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/`sg_blog` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; + +USE `sg_blog`; + +/*Table structure for table `sg_article` */ + +DROP TABLE IF EXISTS `sg_article`; + +CREATE TABLE `sg_article` ( + `id` bigint(200) NOT NULL AUTO_INCREMENT, + `title` varchar(256) DEFAULT NULL COMMENT '标题', + `content` longtext COMMENT '文章内容', + `summary` varchar(1024) DEFAULT NULL COMMENT '文章摘要', + `category_id` bigint(20) DEFAULT NULL COMMENT '所属分类id', + `thumbnail` varchar(256) DEFAULT NULL COMMENT '缩略图', + `is_top` char(1) DEFAULT '0' COMMENT '是否置顶(0否,1是)', + `status` char(1) DEFAULT '1' COMMENT '状态(0已发布,1草稿)', + `view_count` bigint(200) DEFAULT '0' COMMENT '访问量', + `is_comment` char(1) DEFAULT '1' COMMENT '是否允许评论 1是,0否', + `create_by` bigint(20) DEFAULT NULL, + `create_time` datetime DEFAULT NULL, + `update_by` bigint(20) DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + `del_flag` int(1) DEFAULT '0' COMMENT '删除标志(0代表未删除,1代表已删除)', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COMMENT='文章表'; + +/*Data for the table `sg_article` */ + +insert into `sg_article`(`id`,`title`,`content`,`summary`,`category_id`,`thumbnail`,`is_top`,`status`,`view_count`,`is_comment`,`create_by`,`create_time`,`update_by`,`update_time`,`del_flag`) values (1,'SpringSecurity从入门到精通','## 课程介绍\n![image20211219121555979.png](https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/31/e7131718e9e64faeaf3fe16404186eb4.png)\n\n## 0. 简介1\n\n​ **Spring Security** 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架**Shiro**,它提供了更丰富的功能,社区资源也比Shiro丰富。\n\n​ 一般来说中大型的项目都是使用**SpringSecurity** 来做安全框架。小项目有Shiro的比较多,因为相比与SpringSecurity,Shiro的上手更加的简单。\n\n​ 一般Web应用的需要进行**认证**和**授权**。\n\n​ **认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户**\n\n​ **授权:经过认证后判断当前用户是否有权限进行某个操作**\n\n​ 而认证和授权也是SpringSecurity作为安全框架的核心功能。\n\n\n\n## 1. 快速入门\n\n### 1.1 准备工作\n\n​ 我们先要搭建一个简单的SpringBoot工程\n\n① 设置父工程 添加依赖\n\n~~~~\n \n org.springframework.boot\n spring-boot-starter-parent\n 2.5.0\n \n \n \n org.springframework.boot\n spring-boot-starter-web\n \n \n org.projectlombok\n lombok\n true\n \n \n~~~~\n\n② 创建启动类\n\n~~~~\n@SpringBootApplication\npublic class SecurityApplication {\n\n public static void main(String[] args) {\n SpringApplication.run(SecurityApplication.class,args);\n }\n}\n\n~~~~\n\n③ 创建Controller\n\n~~~~java\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class HelloController {\n\n @RequestMapping(\"/hello\")\n public String hello(){\n return \"hello\";\n }\n}\n\n~~~~\n\n\n\n### 1.2 引入SpringSecurity\n\n​ 在SpringBoot项目中使用SpringSecurity我们只需要引入依赖即可实现入门案例。\n\n~~~~xml\n \n org.springframework.boot\n spring-boot-starter-security\n \n~~~~\n\n​ 引入依赖后我们在尝试去访问之前的接口就会自动跳转到一个SpringSecurity的默认登陆页面,默认用户名是user,密码会输出在控制台。\n\n​ 必须登陆之后才能对接口进行访问。\n\n\n\n## 2. 认证\n\n### 2.1 登陆校验流程\n![image20211215094003288.png](https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/31/414a87eeed344828b5b00ffa80178958.png)','SpringSecurity框架教程-Spring Security+JWT实现项目级前端分离认证授权',1,'https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/31/948597e164614902ab1662ba8452e106.png','1','0',105,'0',NULL,'2022-01-23 23:20:11',NULL,NULL,0),(2,'weq','adadaeqe','adad',2,'https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/15/fd2e9460c58a4af3bbeae5d9ed581688.png','1','0',22,'0',NULL,'2022-01-21 14:58:30',NULL,NULL,1),(3,'dad','asdasda','sadad',1,'https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/15/737a0ed0b8ea430d8700a12e76aa1cd1.png','1','0',33,'0',NULL,'2022-01-18 14:58:34',NULL,NULL,1),(5,'sdad','![Snipaste_20220115_165812.png](https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/15/1d9d283f5d874b468078b183e4b98b71.png)\r\n\r\n## sda \r\n\r\n222\r\n### sdasd newnewnew',NULL,2,'','1','0',44,'0',NULL,'2022-01-17 14:58:37',NULL,NULL,0); + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/sql/sg_article_tag.sql b/sql/sg_article_tag.sql new file mode 100644 index 0000000..b9a05ce --- /dev/null +++ b/sql/sg_article_tag.sql @@ -0,0 +1,36 @@ +/* +SQLyog v10.2 +MySQL - 5.5.40 : Database - sg_blog +********************************************************************* +*/ + +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/`sg_blog` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; + +USE `sg_blog`; + +/*Table structure for table `sg_article_tag` */ + +DROP TABLE IF EXISTS `sg_article_tag`; + +CREATE TABLE `sg_article_tag` ( + `article_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '文章id', + `tag_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '标签id', + PRIMARY KEY (`article_id`,`tag_id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='文章标签关联表'; + +/*Data for the table `sg_article_tag` */ + +insert into `sg_article_tag`(`article_id`,`tag_id`) values (1,4),(2,1),(2,4),(3,4),(3,5); + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/sql/sg_category.sql b/sql/sg_category.sql new file mode 100644 index 0000000..bc759a3 --- /dev/null +++ b/sql/sg_category.sql @@ -0,0 +1,44 @@ +/* +SQLyog v10.2 +MySQL - 5.5.40 : Database - sg_blog +********************************************************************* +*/ + +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/`sg_blog` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; + +USE `sg_blog`; + +/*Table structure for table `sg_category` */ + +DROP TABLE IF EXISTS `sg_category`; + +CREATE TABLE `sg_category` ( + `id` bigint(200) NOT NULL AUTO_INCREMENT, + `name` varchar(128) DEFAULT NULL COMMENT '分类名', + `pid` bigint(200) DEFAULT '-1' COMMENT '父分类id,如果没有父分类为-1', + `description` varchar(512) DEFAULT NULL COMMENT '描述', + `status` char(1) DEFAULT '0' COMMENT '状态0:正常,1禁用', + `create_by` bigint(200) DEFAULT NULL, + `create_time` datetime DEFAULT NULL, + `update_by` bigint(200) DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + `del_flag` int(11) DEFAULT '0' COMMENT '删除标志(0代表未删除,1代表已删除)', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COMMENT='分类表'; + +/*Data for the table `sg_category` */ + +insert into `sg_category`(`id`,`name`,`pid`,`description`,`status`,`create_by`,`create_time`,`update_by`,`update_time`,`del_flag`) values (1,'java',-1,'wsd','0',NULL,NULL,NULL,NULL,0),(2,'PHP',-1,'wsd','0',NULL,NULL,NULL,NULL,0); + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/sql/sg_comment.sql b/sql/sg_comment.sql new file mode 100644 index 0000000..77cbddb --- /dev/null +++ b/sql/sg_comment.sql @@ -0,0 +1,46 @@ +/* +SQLyog v10.2 +MySQL - 5.5.40 : Database - sg_blog +********************************************************************* +*/ + +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/`sg_blog` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; + +USE `sg_blog`; + +/*Table structure for table `sg_comment` */ + +DROP TABLE IF EXISTS `sg_comment`; + +CREATE TABLE `sg_comment` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `type` char(1) DEFAULT '0' COMMENT '评论类型(0代表文章评论,1代表友链评论)', + `article_id` bigint(20) DEFAULT NULL COMMENT '文章id', + `root_id` bigint(20) DEFAULT '-1' COMMENT '根评论id', + `content` varchar(512) DEFAULT NULL COMMENT '评论内容', + `to_comment_user_id` bigint(20) DEFAULT '-1' COMMENT '所回复的目标评论的userid', + `to_comment_id` bigint(20) DEFAULT '-1' COMMENT '回复目标评论id', + `create_by` bigint(20) DEFAULT NULL, + `create_time` datetime DEFAULT NULL, + `update_by` bigint(20) DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + `del_flag` int(1) DEFAULT '0' COMMENT '删除标志(0代表未删除,1代表已删除)', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8mb4 COMMENT='评论表'; + +/*Data for the table `sg_comment` */ + +insert into `sg_comment`(`id`,`type`,`article_id`,`root_id`,`content`,`to_comment_user_id`,`to_comment_id`,`create_by`,`create_time`,`update_by`,`update_time`,`del_flag`) values (1,'0',1,-1,'asS',-1,-1,1,'2022-01-29 07:59:22',1,'2022-01-29 07:59:22',0),(2,'0',1,-1,'[哈哈]SDAS',-1,-1,1,'2022-01-29 08:01:24',1,'2022-01-29 08:01:24',0),(3,'0',1,-1,'是大多数',-1,-1,1,'2022-01-29 16:07:24',1,'2022-01-29 16:07:24',0),(4,'0',1,-1,'撒大声地',-1,-1,1,'2022-01-29 16:12:09',1,'2022-01-29 16:12:09',0),(5,'0',1,-1,'你再说什么',-1,-1,1,'2022-01-29 18:19:56',1,'2022-01-29 18:19:56',0),(6,'0',1,-1,'hffd',-1,-1,1,'2022-01-29 22:13:52',1,'2022-01-29 22:13:52',0),(9,'0',1,2,'你说什么',1,2,1,'2022-01-29 22:18:40',1,'2022-01-29 22:18:40',0),(10,'0',1,2,'哈哈哈哈[哈哈]',1,9,1,'2022-01-29 22:29:15',1,'2022-01-29 22:29:15',0),(11,'0',1,2,'we全文',1,10,3,'2022-01-29 22:29:55',1,'2022-01-29 22:29:55',0),(12,'0',1,-1,'王企鹅',-1,-1,1,'2022-01-29 22:30:20',1,'2022-01-29 22:30:20',0),(13,'0',1,-1,'什么阿是',-1,-1,1,'2022-01-29 22:30:56',1,'2022-01-29 22:30:56',0),(14,'0',1,-1,'新平顶山',-1,-1,1,'2022-01-29 22:32:51',1,'2022-01-29 22:32:51',0),(15,'0',1,-1,'2222',-1,-1,1,'2022-01-29 22:34:38',1,'2022-01-29 22:34:38',0),(16,'0',1,2,'3333',1,11,1,'2022-01-29 22:34:47',1,'2022-01-29 22:34:47',0),(17,'0',1,2,'回复weqedadsd',3,11,1,'2022-01-29 22:38:00',1,'2022-01-29 22:38:00',0),(18,'0',1,-1,'sdasd',-1,-1,1,'2022-01-29 23:18:19',1,'2022-01-29 23:18:19',0),(19,'0',1,-1,'111',-1,-1,1,'2022-01-29 23:22:23',1,'2022-01-29 23:22:23',0),(20,'0',1,1,'你说啥?',1,1,1,'2022-01-30 10:06:21',1,'2022-01-30 10:06:21',0),(21,'0',1,-1,'友链添加个呗',-1,-1,1,'2022-01-30 10:06:50',1,'2022-01-30 10:06:50',0),(22,'1',1,-1,'友链评论2',-1,-1,1,'2022-01-30 10:08:28',1,'2022-01-30 10:08:28',0),(23,'1',1,22,'回复友链评论3',1,22,1,'2022-01-30 10:08:50',1,'2022-01-30 10:08:50',0),(24,'1',1,-1,'友链评论4444',-1,-1,1,'2022-01-30 10:09:03',1,'2022-01-30 10:09:03',0),(25,'1',1,22,'收到的',1,22,1,'2022-01-30 10:13:28',1,'2022-01-30 10:13:28',0),(26,'0',1,-1,'sda',-1,-1,1,'2022-01-30 10:39:05',1,'2022-01-30 10:39:05',0),(27,'0',1,1,'说你咋地',1,20,14787164048662,'2022-01-30 17:19:30',14787164048662,'2022-01-30 17:19:30',0),(28,'0',1,1,'sdad',1,1,14787164048662,'2022-01-31 11:11:20',14787164048662,'2022-01-31 11:11:20',0),(29,'0',1,-1,'你说是的ad',-1,-1,14787164048662,'2022-01-31 14:10:11',14787164048662,'2022-01-31 14:10:11',0),(30,'0',1,1,'撒大声地',1,1,14787164048662,'2022-01-31 20:19:18',14787164048662,'2022-01-31 20:19:18',0); + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/sql/sg_link.sql b/sql/sg_link.sql new file mode 100644 index 0000000..7c3e57f --- /dev/null +++ b/sql/sg_link.sql @@ -0,0 +1,45 @@ +/* +SQLyog v10.2 +MySQL - 5.5.40 : Database - sg_blog +********************************************************************* +*/ + +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/`sg_blog` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; + +USE `sg_blog`; + +/*Table structure for table `sg_link` */ + +DROP TABLE IF EXISTS `sg_link`; + +CREATE TABLE `sg_link` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(256) DEFAULT NULL, + `logo` varchar(256) DEFAULT NULL, + `description` varchar(512) DEFAULT NULL, + `address` varchar(128) DEFAULT NULL COMMENT '网站地址', + `status` char(1) DEFAULT '2' COMMENT '审核状态 (0代表审核通过,1代表审核未通过,2代表未审核)', + `create_by` bigint(20) DEFAULT NULL, + `create_time` datetime DEFAULT NULL, + `update_by` bigint(20) DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + `del_flag` int(1) DEFAULT '0' COMMENT '删除标志(0代表未删除,1代表已删除)', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='友链'; + +/*Data for the table `sg_link` */ + +insert into `sg_link`(`id`,`name`,`logo`,`description`,`address`,`status`,`create_by`,`create_time`,`update_by`,`update_time`,`del_flag`) values (1,'sda','https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fn1.itc.cn%2Fimg8%2Fwb%2Frecom%2F2016%2F05%2F10%2F146286696706220328.PNG&refer=http%3A%2F%2Fn1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646205529&t=f942665181eb9b0685db7a6f59d59975','sda','https://www.baidu.com','1',NULL,'2022-01-13 08:25:47',NULL,'2022-01-13 08:36:14',0),(2,'sda','https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fn1.itc.cn%2Fimg8%2Fwb%2Frecom%2F2016%2F05%2F10%2F146286696706220328.PNG&refer=http%3A%2F%2Fn1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646205529&t=f942665181eb9b0685db7a6f59d59975','dada','https://www.qq.com','1',NULL,'2022-01-13 09:06:10',NULL,'2022-01-13 09:07:09',0),(3,'sa','https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fn1.itc.cn%2Fimg8%2Fwb%2Frecom%2F2016%2F05%2F10%2F146286696706220328.PNG&refer=http%3A%2F%2Fn1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646205529&t=f942665181eb9b0685db7a6f59d59975','da','https://www.taobao.com','1',NULL,'2022-01-13 09:23:01',NULL,'2022-01-13 09:23:01',0); + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/sql/sg_menu.sql b/sql/sg_menu.sql new file mode 100644 index 0000000..b851254 --- /dev/null +++ b/sql/sg_menu.sql @@ -0,0 +1,103 @@ +/* +SQLyog v10.2 +MySQL - 5.5.40 : Database - sg_blog +********************************************************************* +*/ + +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/`sg_blog` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; + +USE `sg_blog`; + +/*Table structure for table `sys_menu` */ + +DROP TABLE IF EXISTS `sys_menu`; + +CREATE TABLE `sys_menu` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '菜单ID', + `menu_name` varchar(50) NOT NULL COMMENT '菜单名称', + `parent_id` bigint(20) DEFAULT '0' COMMENT '父菜单ID', + `order_num` int(4) DEFAULT '0' COMMENT '显示顺序', + `path` varchar(200) DEFAULT '' COMMENT '路由地址', + `component` varchar(255) DEFAULT NULL COMMENT '组件路径', + `is_frame` int(1) DEFAULT '1' COMMENT '是否为外链(0是 1否)', + `menu_type` char(1) DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮)', + `visible` char(1) DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)', + `status` char(1) DEFAULT '0' COMMENT '菜单状态(0正常 1停用)', + `perms` varchar(100) DEFAULT NULL COMMENT '权限标识', + `icon` varchar(100) DEFAULT '#' COMMENT '菜单图标', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT '' COMMENT '备注', + `del_flag` char(1) DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2034 DEFAULT CHARSET=utf8 COMMENT='菜单权限表'; + +/*Data for the table `sys_menu` */ + +insert into `sys_menu`(`id`,`menu_name`,`parent_id`,`order_num`,`path`,`component`,`is_frame`,`menu_type`,`visible`,`status`,`perms`,`icon`,`create_by`,`create_time`,`update_by`,`update_time`,`remark`,`del_flag`) values (1,'系统管理',0,1,'system',NULL,1,'M','0','0','','system',0,'2021-11-12 10:46:19',0,NULL,'系统管理目录','0'),(100,'用户管理',1,1,'user','system/user/index',1,'C','0','0','system:user:list','user',0,'2021-11-12 10:46:19',1,'2022-07-31 15:47:58','用户管理菜单','0'),(101,'角色管理',1,2,'role','system/role/index',1,'C','0','0','system:role:list','peoples',0,'2021-11-12 10:46:19',0,NULL,'角色管理菜单','0'),(102,'菜单管理',1,3,'menu','system/menu/index',1,'C','0','0','system:menu:list','tree-table',0,'2021-11-12 10:46:19',0,NULL,'菜单管理菜单','0'),(1001,'用户查询',100,1,'','',1,'F','0','0','system:user:query','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1002,'用户新增',100,2,'','',1,'F','0','0','system:user:add','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1003,'用户修改',100,3,'','',1,'F','0','0','system:user:edit','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1004,'用户删除',100,4,'','',1,'F','0','0','system:user:remove','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1005,'用户导出',100,5,'','',1,'F','0','0','system:user:export','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1006,'用户导入',100,6,'','',1,'F','0','0','system:user:import','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1007,'重置密码',100,7,'','',1,'F','0','0','system:user:resetPwd','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1008,'角色查询',101,1,'','',1,'F','0','0','system:role:query','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1009,'角色新增',101,2,'','',1,'F','0','0','system:role:add','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1010,'角色修改',101,3,'','',1,'F','0','0','system:role:edit','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1011,'角色删除',101,4,'','',1,'F','0','0','system:role:remove','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1012,'角色导出',101,5,'','',1,'F','0','0','system:role:export','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1013,'菜单查询',102,1,'','',1,'F','0','0','system:menu:query','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1014,'菜单新增',102,2,'','',1,'F','0','0','system:menu:add','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1015,'菜单修改',102,3,'','',1,'F','0','0','system:menu:edit','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(1016,'菜单删除',102,4,'','',1,'F','0','0','system:menu:remove','#',0,'2021-11-12 10:46:19',0,NULL,'','0'),(2017,'内容管理',0,4,'content',NULL,1,'M','0','0',NULL,'table',NULL,'2022-01-08 02:44:38',1,'2022-07-31 12:34:23','','0'),(2018,'分类管理',2017,1,'category','content/category/index',1,'C','0','0','content:category:list','example',NULL,'2022-01-08 02:51:45',NULL,'2022-01-08 02:51:45','','0'),(2019,'文章管理',2017,0,'article','content/article/index',1,'C','0','0','content:article:list','build',NULL,'2022-01-08 02:53:10',NULL,'2022-01-08 02:53:10','','0'),(2021,'标签管理',2017,6,'tag','content/tag/index',1,'C','0','0','content:tag:index','button',NULL,'2022-01-08 02:55:37',NULL,'2022-01-08 02:55:50','','0'),(2022,'友链管理',2017,4,'link','content/link/index',1,'C','0','0','content:link:list','404',NULL,'2022-01-08 02:56:50',NULL,'2022-01-08 02:56:50','','0'),(2023,'写博文',0,0,'write','content/article/write/index',1,'C','0','0','content:article:writer','build',NULL,'2022-01-08 03:39:58',1,'2022-07-31 22:07:05','','0'),(2024,'友链新增',2022,0,'',NULL,1,'F','0','0','content:link:add','#',NULL,'2022-01-16 07:59:17',NULL,'2022-01-16 07:59:17','','0'),(2025,'友链修改',2022,1,'',NULL,1,'F','0','0','content:link:edit','#',NULL,'2022-01-16 07:59:44',NULL,'2022-01-16 07:59:44','','0'),(2026,'友链删除',2022,1,'',NULL,1,'F','0','0','content:link:remove','#',NULL,'2022-01-16 08:00:05',NULL,'2022-01-16 08:00:05','','0'),(2027,'友链查询',2022,2,'',NULL,1,'F','0','0','content:link:query','#',NULL,'2022-01-16 08:04:09',NULL,'2022-01-16 08:04:09','','0'),(2028,'导出分类',2018,1,'',NULL,1,'F','0','0','content:category:export','#',NULL,'2022-01-21 07:06:59',NULL,'2022-01-21 07:06:59','','0'); + +/*Table structure for table `sys_role` */ + +DROP TABLE IF EXISTS `sys_role`; + +CREATE TABLE `sys_role` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID', + `role_name` varchar(30) NOT NULL COMMENT '角色名称', + `role_key` varchar(100) NOT NULL COMMENT '角色权限字符串', + `role_sort` int(4) NOT NULL COMMENT '显示顺序', + `status` char(1) NOT NULL COMMENT '角色状态(0正常 1停用)', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COMMENT='角色信息表'; + +/*Data for the table `sys_role` */ + +insert into `sys_role`(`id`,`role_name`,`role_key`,`role_sort`,`status`,`del_flag`,`create_by`,`create_time`,`update_by`,`update_time`,`remark`) values (1,'超级管理员','admin',1,'0','0',0,'2021-11-12 10:46:19',0,NULL,'超级管理员'),(2,'普通角色','common',2,'0','0',0,'2021-11-12 10:46:19',0,'2022-01-01 22:32:58','普通角色'),(11,'嘎嘎嘎','aggag',5,'0','0',NULL,'2022-01-06 14:07:40',NULL,'2022-01-07 03:48:48','嘎嘎嘎'),(12,'友链审核员','link',1,'0','0',NULL,'2022-01-16 06:49:30',NULL,'2022-01-16 08:05:09',NULL); + +/*Table structure for table `sys_role_menu` */ + +DROP TABLE IF EXISTS `sys_role_menu`; + +CREATE TABLE `sys_role_menu` ( + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + `menu_id` bigint(20) NOT NULL COMMENT '菜单ID', + PRIMARY KEY (`role_id`,`menu_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色和菜单关联表'; + +/*Data for the table `sys_role_menu` */ + +insert into `sys_role_menu`(`role_id`,`menu_id`) values (0,0),(2,1),(2,102),(2,1013),(2,1014),(2,1015),(2,1016),(2,2000),(3,2),(3,3),(3,4),(3,100),(3,101),(3,103),(3,104),(3,105),(3,106),(3,107),(3,108),(3,109),(3,110),(3,111),(3,112),(3,113),(3,114),(3,115),(3,116),(3,500),(3,501),(3,1001),(3,1002),(3,1003),(3,1004),(3,1005),(3,1006),(3,1007),(3,1008),(3,1009),(3,1010),(3,1011),(3,1012),(3,1017),(3,1018),(3,1019),(3,1020),(3,1021),(3,1022),(3,1023),(3,1024),(3,1025),(3,1026),(3,1027),(3,1028),(3,1029),(3,1030),(3,1031),(3,1032),(3,1033),(3,1034),(3,1035),(3,1036),(3,1037),(3,1038),(3,1039),(3,1040),(3,1041),(3,1042),(3,1043),(3,1044),(3,1045),(3,1046),(3,1047),(3,1048),(3,1049),(3,1050),(3,1051),(3,1052),(3,1053),(3,1054),(3,1055),(3,1056),(3,1057),(3,1058),(3,1059),(3,1060),(3,2000),(11,1),(11,100),(11,101),(11,102),(11,103),(11,104),(11,105),(11,106),(11,107),(11,108),(11,500),(11,501),(11,1001),(11,1002),(11,1003),(11,1004),(11,1005),(11,1006),(11,1007),(11,1008),(11,1009),(11,1010),(11,1011),(11,1012),(11,1013),(11,1014),(11,1015),(11,1016),(11,1017),(11,1018),(11,1019),(11,1020),(11,1021),(11,1022),(11,1023),(11,1024),(11,1025),(11,1026),(11,1027),(11,1028),(11,1029),(11,1030),(11,1031),(11,1032),(11,1033),(11,1034),(11,1035),(11,1036),(11,1037),(11,1038),(11,1039),(11,1040),(11,1041),(11,1042),(11,1043),(11,1044),(11,1045),(11,2000),(11,2003),(11,2004),(11,2005),(11,2006),(11,2007),(11,2008),(11,2009),(11,2010),(11,2011),(11,2012),(11,2013),(11,2014),(12,2017),(12,2022),(12,2024),(12,2025),(12,2026),(12,2027); + +/*Table structure for table `sys_user_role` */ + +DROP TABLE IF EXISTS `sys_user_role`; + +CREATE TABLE `sys_user_role` ( + `user_id` bigint(20) NOT NULL COMMENT '用户ID', + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + PRIMARY KEY (`user_id`,`role_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户和角色关联表'; + +/*Data for the table `sys_user_role` */ + +insert into `sys_user_role`(`user_id`,`role_id`) values (1,1),(2,2),(5,2),(6,12); + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/sql/sg_tag.sql b/sql/sg_tag.sql new file mode 100644 index 0000000..f6f984e --- /dev/null +++ b/sql/sg_tag.sql @@ -0,0 +1,42 @@ +/* +SQLyog v10.2 +MySQL - 5.5.40 : Database - sg_blog +********************************************************************* +*/ + +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/`sg_blog` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; + +USE `sg_blog`; + +/*Table structure for table `sg_tag` */ + +DROP TABLE IF EXISTS `sg_tag`; + +CREATE TABLE `sg_tag` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `name` varchar(128) DEFAULT NULL COMMENT '标签名', + `create_by` bigint(20) DEFAULT NULL, + `create_time` datetime DEFAULT NULL, + `update_by` bigint(20) DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + `del_flag` int(1) DEFAULT '0' COMMENT '删除标志(0代表未删除,1代表已删除)', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='标签'; + +/*Data for the table `sg_tag` */ + +insert into `sg_tag`(`id`,`name`,`create_by`,`create_time`,`update_by`,`update_time`,`del_flag`,`remark`) values (1,'Mybatis',NULL,NULL,NULL,'2022-01-11 09:20:50',0,'weqwe'),(2,'asdas',NULL,'2022-01-11 09:20:55',NULL,'2022-01-11 09:20:55',1,'weqw'),(3,'weqw',NULL,'2022-01-11 09:21:07',NULL,'2022-01-11 09:21:07',1,'qweqwe'),(4,'Java',NULL,'2022-01-13 15:22:43',NULL,'2022-01-13 15:22:43',0,'sdad'),(5,'WAD',NULL,'2022-01-13 15:22:47',NULL,'2022-01-13 15:22:47',0,'ASDAD'); + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/sql/sys_user.sql b/sql/sys_user.sql new file mode 100644 index 0000000..ecf5bff --- /dev/null +++ b/sql/sys_user.sql @@ -0,0 +1,49 @@ +/* +SQLyog v10.2 +MySQL - 5.5.40 : Database - sg_blog +********************************************************************* +*/ + +/*!40101 SET NAMES utf8 */; + +/*!40101 SET SQL_MODE=''*/; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +CREATE DATABASE /*!32312 IF NOT EXISTS*/`sg_blog` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; + +USE `sg_blog`; + +/*Table structure for table `sys_user` */ + +DROP TABLE IF EXISTS `sys_user`; + +CREATE TABLE `sys_user` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_name` varchar(64) NOT NULL DEFAULT 'NULL' COMMENT '用户名', + `nick_name` varchar(64) NOT NULL DEFAULT 'NULL' COMMENT '昵称', + `password` varchar(64) NOT NULL DEFAULT 'NULL' COMMENT '密码', + `type` char(1) DEFAULT '0' COMMENT '用户类型:0代表普通用户,1代表管理员', + `status` char(1) DEFAULT '0' COMMENT '账号状态(0正常 1停用)', + `email` varchar(64) DEFAULT NULL COMMENT '邮箱', + `phonenumber` varchar(32) DEFAULT NULL COMMENT '手机号', + `sex` char(1) DEFAULT NULL COMMENT '用户性别(0男,1女,2未知)', + `avatar` varchar(128) DEFAULT NULL COMMENT '头像', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建人的用户id', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` int(11) DEFAULT '0' COMMENT '删除标志(0代表未删除,1代表已删除)', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + +/*Data for the table `sys_user` */ + +insert into `sys_user`(`id`,`user_name`,`nick_name`,`password`,`type`,`status`,`email`,`phonenumber`,`sex`,`avatar`,`create_by`,`create_time`,`update_by`,`update_time`,`del_flag`) values (1,'sg','sg333','$2a$10$Jnq31rRkNV3RNzXe0REsEOSKaYK8UgVZZqlNlNXqn.JeVcj2NdeZy','1','0','23412332@qq.com','18888888888','1','https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2F3bf9c263bc0f2ac5c3a7feb9e218d07475573ec8.gi',NULL,'2022-01-05 09:01:56',1,'2022-01-30 15:37:03',0),(3,'sg3','weqe','$2a$10$ydv3rLkteFnRx9xelQ7elOiVhFvXOooA98xCqk/omh7G94R.K/E3O','1','0',NULL,NULL,'0',NULL,NULL,'2022-01-05 13:28:43',NULL,'2022-01-05 13:28:43',0),(4,'sg2','dsadd','$2a$10$kY4T3SN7i4muBccZppd2OOkhxMN6yt8tND1sF89hXOaFylhY2T3he','1','0','23412332@qq.com','19098790742','0',NULL,NULL,NULL,NULL,NULL,0),(5,'sg2233','tteqe','','1','0',NULL,'18246845873','1',NULL,NULL,'2022-01-06 03:51:13',NULL,'2022-01-06 07:00:50',0),(6,'sangeng','sangeng','$2a$10$Jnq31rRkNV3RNzXe0REsEOSKaYK8UgVZZqlNlNXqn.JeVcj2NdeZy','1','0','2312321','17777777777','0',NULL,NULL,'2022-01-16 06:54:26',NULL,'2022-01-16 07:06:34',0),(14787164048662,'weixin','weixin','$2a$10$y3k3fnMZsBNihsVLXWfI8uMNueVXBI08k.LzWYaKsW8CW7xXy18wC','0','0','weixin@qq.com',NULL,NULL,NULL,-1,'2022-01-30 17:18:44',-1,'2022-01-30 17:18:44',0); + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git "a/sql/\350\257\264\346\230\216.txt" "b/sql/\350\257\264\346\230\216.txt" new file mode 100644 index 0000000..4adc2f5 --- /dev/null +++ "b/sql/\350\257\264\346\230\216.txt" @@ -0,0 +1 @@ +sg_menu.sql里面包含好几张表 \ No newline at end of file -- Gitee From 2afb51f514fb67a3692af480ebb8818ec50f6112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Cduan138=E2=80=9D?= Date: Sat, 22 Oct 2022 21:58:14 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FastJsonRedisSerializer.java" | 64 + .../JwtUtil.java" | 113 + .../RedisCache.java" | 238 + .../RedisConfig.java" | 32 + .../WebUtils.java" | 44 + ...mage-20220202111056036-16437714601701.png" | Bin 0 -> 10205 bytes .../img/image-20220202111056036.png" | Bin 0 -> 10205 bytes ...mage-20220202121318183-16437751995162.png" | Bin 0 -> 4811 bytes .../img/image-20220202121318183.png" | Bin 0 -> 4811 bytes ...mage-20220202152402296-16437866440853.png" | Bin 0 -> 4096 bytes .../img/image-20220202152402296.png" | Bin 0 -> 4096 bytes .../img/image-20220202152440565.png" | Bin 0 -> 24537 bytes .../img/image-20220208214106296.png" | Bin 0 -> 100238 bytes .../img/image-20220227224443813.png" | Bin 0 -> 94689 bytes .../img/image-20220227224537701.png" | Bin 0 -> 154777 bytes .../img/image-20220228230512598.png" | Bin 0 -> 20025 bytes .../img/image-20220228230933808.png" | Bin 0 -> 33625 bytes .../img/image-20220313133714102.png" | Bin 0 -> 26988 bytes .../img/image-20220717120448125.png" | Bin 0 -> 4888 bytes ...32\345\256\242\347\263\273\347\273\237.md" | 8459 +++++++++++++++++ ...32\345\256\242\347\263\273\347\273\237.md" | 8459 +++++++++++++++++ 21 files changed, 17409 insertions(+) create mode 100644 "doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/FastJsonRedisSerializer.java" create mode 100644 "doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/JwtUtil.java" create mode 100644 "doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/RedisCache.java" create mode 100644 "doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/RedisConfig.java" create mode 100644 "doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/WebUtils.java" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220202111056036-16437714601701.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220202111056036.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220202121318183-16437751995162.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220202121318183.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220202152402296-16437866440853.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220202152402296.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220202152440565.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220208214106296.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220227224443813.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220227224537701.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220228230512598.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220228230933808.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220313133714102.png" create mode 100644 "doc/\347\254\224\350\256\260/img/image-20220717120448125.png" create mode 100644 "doc/\347\254\224\350\256\260/\351\241\271\347\233\256\345\256\236\346\210\230-\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\215\232\345\256\242\347\263\273\347\273\237.md" create mode 100644 "doc/\351\241\271\347\233\256\345\256\236\346\210\230-\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\215\232\345\256\242\347\263\273\347\273\237.md" diff --git "a/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/FastJsonRedisSerializer.java" "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/FastJsonRedisSerializer.java" new file mode 100644 index 0000000..ec5a2a7 --- /dev/null +++ "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/FastJsonRedisSerializer.java" @@ -0,0 +1,64 @@ +package com.sangeng.config; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.SerializationException; +import com.alibaba.fastjson.parser.ParserConfig; +import org.springframework.util.Assert; +import java.nio.charset.Charset; + +/** + * Redis使用FastJson序列化 + * + * @author sg + */ +public class FastJsonRedisSerializer implements RedisSerializer +{ + + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private Class clazz; + + static + { + ParserConfig.getGlobalInstance().setAutoTypeSupport(true); + } + + public FastJsonRedisSerializer(Class clazz) + { + super(); + this.clazz = clazz; + } + + @Override + public byte[] serialize(T t) throws SerializationException + { + if (t == null) + { + return new byte[0]; + } + return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); + } + + @Override + public T deserialize(byte[] bytes) throws SerializationException + { + if (bytes == null || bytes.length <= 0) + { + return null; + } + String str = new String(bytes, DEFAULT_CHARSET); + + return JSON.parseObject(str, clazz); + } + + + protected JavaType getJavaType(Class clazz) + { + return TypeFactory.defaultInstance().constructType(clazz); + } +} \ No newline at end of file diff --git "a/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/JwtUtil.java" "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/JwtUtil.java" new file mode 100644 index 0000000..fd40de3 --- /dev/null +++ "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/JwtUtil.java" @@ -0,0 +1,113 @@ +package com.sangeng.utils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.util.Base64; +import java.util.Date; +import java.util.UUID; + +/** + * JWT工具类 + */ +public class JwtUtil { + + //有效期为 + public static final Long JWT_TTL = 24*60 * 60 *1000L;// 60 * 60 *1000 一个小时 + //设置秘钥明文 + public static final String JWT_KEY = "sangeng"; + + public static String getUUID(){ + String token = UUID.randomUUID().toString().replaceAll("-", ""); + return token; + } + + /** + * 生成jtw + * @param subject token中要存放的数据(json格式) + * @return + */ + public static String createJWT(String subject) { + JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间 + return builder.compact(); + } + + /** + * 生成jtw + * @param subject token中要存放的数据(json格式) + * @param ttlMillis token超时时间 + * @return + */ + public static String createJWT(String subject, Long ttlMillis) { + JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间 + return builder.compact(); + } + + private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) { + SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; + SecretKey secretKey = generalKey(); + long nowMillis = System.currentTimeMillis(); + Date now = new Date(nowMillis); + if(ttlMillis==null){ + ttlMillis=JwtUtil.JWT_TTL; + } + long expMillis = nowMillis + ttlMillis; + Date expDate = new Date(expMillis); + return Jwts.builder() + .setId(uuid) //唯一的ID + .setSubject(subject) // 主题 可以是JSON数据 + .setIssuer("sg") // 签发者 + .setIssuedAt(now) // 签发时间 + .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥 + .setExpiration(expDate); + } + + /** + * 创建token + * @param id + * @param subject + * @param ttlMillis + * @return + */ + public static String createJWT(String id, String subject, Long ttlMillis) { + JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间 + return builder.compact(); + } + + public static void main(String[] args) throws Exception { + String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjYWM2ZDVhZi1mNjVlLTQ0MDAtYjcxMi0zYWEwOGIyOTIwYjQiLCJzdWIiOiJzZyIsImlzcyI6InNnIiwiaWF0IjoxNjM4MTA2NzEyLCJleHAiOjE2MzgxMTAzMTJ9.JVsSbkP94wuczb4QryQbAke3ysBDIL5ou8fWsbt_ebg"; + Claims claims = parseJWT(token); + System.out.println(claims); + } + + /** + * 生成加密后的秘钥 secretKey + * @return + */ + public static SecretKey generalKey() { + byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY); + SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); + return key; + } + + /** + * 解析 + * + * @param jwt + * @return + * @throws Exception + */ + public static Claims parseJWT(String jwt) throws Exception { + SecretKey secretKey = generalKey(); + return Jwts.parser() + .setSigningKey(secretKey) + .parseClaimsJws(jwt) + .getBody(); + } + + +} \ No newline at end of file diff --git "a/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/RedisCache.java" "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/RedisCache.java" new file mode 100644 index 0000000..f8ac900 --- /dev/null +++ "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/RedisCache.java" @@ -0,0 +1,238 @@ +package com.sangeng.utils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.BoundSetOperations; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +@SuppressWarnings(value = { "unchecked", "rawtypes" }) +@Component +public class RedisCache +{ + @Autowired + public RedisTemplate redisTemplate; + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public void setCacheObject(final String key, final T value) + { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 + * @param timeUnit 时间颗粒度 + */ + public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) + { + redisTemplate.opsForValue().set(key, value, timeout, timeUnit); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout) + { + return expire(key, timeout, TimeUnit.SECONDS); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @param unit 时间单位 + * @return true=设置成功;false=设置失败 + */ + public boolean expire(final String key, final long timeout, final TimeUnit unit) + { + return redisTemplate.expire(key, timeout, unit); + } + + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * @return 缓存键值对应的数据 + */ + public T getCacheObject(final String key) + { + ValueOperations operation = redisTemplate.opsForValue(); + return operation.get(key); + } + + /** + * 删除单个对象 + * + * @param key + */ + public boolean deleteObject(final String key) + { + return redisTemplate.delete(key); + } + + /** + * 删除集合对象 + * + * @param collection 多个对象 + * @return + */ + public long deleteObject(final Collection collection) + { + return redisTemplate.delete(collection); + } + + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * @return 缓存的对象 + */ + public long setCacheList(final String key, final List dataList) + { + Long count = redisTemplate.opsForList().rightPushAll(key, dataList); + return count == null ? 0 : count; + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public List getCacheList(final String key) + { + return redisTemplate.opsForList().range(key, 0, -1); + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public BoundSetOperations setCacheSet(final String key, final Set dataSet) + { + BoundSetOperations setOperation = redisTemplate.boundSetOps(key); + Iterator it = dataSet.iterator(); + while (it.hasNext()) + { + setOperation.add(it.next()); + } + return setOperation; + } + + /** + * 获得缓存的set + * + * @param key + * @return + */ + public Set getCacheSet(final String key) + { + return redisTemplate.opsForSet().members(key); + } + + /** + * 缓存Map + * + * @param key + * @param dataMap + */ + public void setCacheMap(final String key, final Map dataMap) + { + if (dataMap != null) { + redisTemplate.opsForHash().putAll(key, dataMap); + } + } + + /** + * 获得缓存的Map + * + * @param key + * @return + */ + public Map getCacheMap(final String key) + { + return redisTemplate.opsForHash().entries(key); + } + + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public void setCacheMapValue(final String key, final String hKey, final T value) + { + redisTemplate.opsForHash().put(key, hKey, value); + } + + /** + * 获取Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public T getCacheMapValue(final String key, final String hKey) + { + HashOperations opsForHash = redisTemplate.opsForHash(); + return opsForHash.get(key, hKey); + } + + /** + * 删除Hash中的数据 + * + * @param key + * @param hkey + */ + public void delCacheMapValue(final String key, final String hkey) + { + HashOperations hashOperations = redisTemplate.opsForHash(); + hashOperations.delete(key, hkey); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public List getMultiCacheMapValue(final String key, final Collection hKeys) + { + return redisTemplate.opsForHash().multiGet(key, hKeys); + } + + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * @return 对象列表 + */ + public Collection keys(final String pattern) + { + return redisTemplate.keys(pattern); + } +} \ No newline at end of file diff --git "a/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/RedisConfig.java" "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/RedisConfig.java" new file mode 100644 index 0000000..ab2e1ad --- /dev/null +++ "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/RedisConfig.java" @@ -0,0 +1,32 @@ +package com.sangeng.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +public class RedisConfig { + + @Bean + @SuppressWarnings(value = { "unchecked", "rawtypes" }) + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) + { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(connectionFactory); + + FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class); + + // 使用StringRedisSerializer来序列化和反序列化redis的key值 + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(serializer); + + // Hash的key也采用StringRedisSerializer的序列化方式 + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(serializer); + + template.afterPropertiesSet(); + return template; + } +} \ No newline at end of file diff --git "a/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/WebUtils.java" "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/WebUtils.java" new file mode 100644 index 0000000..7ea8be2 --- /dev/null +++ "b/doc/\347\231\273\345\275\225\345\212\237\350\203\275\346\211\200\351\234\200\350\265\204\346\272\220/WebUtils.java" @@ -0,0 +1,44 @@ +package com.sangeng.utils; + +import org.springframework.web.context.request.RequestContextHolder; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +public class WebUtils +{ + /** + * 将字符串渲染到客户端 + * + * @param response 渲染对象 + * @param string 待渲染的字符串 + * @return null + */ + public static void renderString(HttpServletResponse response, String string) { + try + { + response.setStatus(200); + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + response.getWriter().print(string); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + + public static void setDownLoadHeader(String filename, ServletContext context, HttpServletResponse response) throws UnsupportedEncodingException { + String mimeType = context.getMimeType(filename);//获取文件的mime类型 + response.setHeader("content-type",mimeType); + String fname= URLEncoder.encode(filename,"UTF-8"); + response.setHeader("Content-disposition","attachment; filename="+fname); + +// response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); +// response.setCharacterEncoding("utf-8"); + } +} \ No newline at end of file diff --git "a/doc/\347\254\224\350\256\260/img/image-20220202111056036-16437714601701.png" "b/doc/\347\254\224\350\256\260/img/image-20220202111056036-16437714601701.png" new file mode 100644 index 0000000000000000000000000000000000000000..08a58869b2d898d030121ccf14e3f4679ee8444a GIT binary patch literal 10205 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 XeM1Nbf?6P600000NkvXXu0mjf!SEwO literal 0 HcmV?d00001 diff --git "a/doc/\347\254\224\350\256\260/img/image-20220202111056036.png" "b/doc/\347\254\224\350\256\260/img/image-20220202111056036.png" new file mode 100644 index 0000000000000000000000000000000000000000..08a58869b2d898d030121ccf14e3f4679ee8444a GIT binary patch literal 10205 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 XeM1Nbf?6P600000NkvXXu0mjf!SEwO literal 0 HcmV?d00001 diff --git "a/doc/\347\254\224\350\256\260/img/image-20220202121318183-16437751995162.png" "b/doc/\347\254\224\350\256\260/img/image-20220202121318183-16437751995162.png" new file mode 100644 index 0000000000000000000000000000000000000000..47827a0d0ab6fbf760f3692a262c42fe9eb68d53 GIT binary patch literal 4811 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 literal 0 HcmV?d00001 diff --git "a/doc/\347\254\224\350\256\260/img/image-20220202121318183.png" "b/doc/\347\254\224\350\256\260/img/image-20220202121318183.png" new file mode 100644 index 0000000000000000000000000000000000000000..47827a0d0ab6fbf760f3692a262c42fe9eb68d53 GIT binary patch literal 4811 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 literal 0 HcmV?d00001 diff --git "a/doc/\347\254\224\350\256\260/img/image-20220202152402296-16437866440853.png" "b/doc/\347\254\224\350\256\260/img/image-20220202152402296-16437866440853.png" new file mode 100644 index 0000000000000000000000000000000000000000..1f9bf4666a8e97cb671477117ea88432f65827ec GIT binary patch literal 4096 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�Z{#<(L*M^S~+h?j54(XLQ8bNl+hHebsx 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
GICI8-S4gJcCg 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 literal 0 HcmV?d00001 diff --git "a/doc/\347\254\224\350\256\260/img/image-20220228230512598.png" "b/doc/\347\254\224\350\256\260/img/image-20220228230512598.png" new file mode 100644 index 0000000000000000000000000000000000000000..be279c535dc065cc8a6f1b688e9d8758ac062611 GIT binary patch literal 20025 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 literal 0 HcmV?d00001 diff --git "a/doc/\347\254\224\350\256\260/img/image-20220717120448125.png" "b/doc/\347\254\224\350\256\260/img/image-20220717120448125.png" new file mode 100644 index 0000000000000000000000000000000000000000..a0a29058eaeaa84456f9da6736ac823722657958 GIT binary patch literal 4888 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 YPoe9E>^6n|D_$hJnugDj>fo6F0S0(*hyVZp literal 0 HcmV?d00001 diff --git "a/doc/\347\254\224\350\256\260/\351\241\271\347\233\256\345\256\236\346\210\230-\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\215\232\345\256\242\347\263\273\347\273\237.md" "b/doc/\347\254\224\350\256\260/\351\241\271\347\233\256\345\256\236\346\210\230-\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\215\232\345\256\242\347\263\273\347\273\237.md" new file mode 100644 index 0000000..43d6433 --- /dev/null +++ "b/doc/\347\254\224\350\256\260/\351\241\271\347\233\256\345\256\236\346\210\230-\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\215\232\345\256\242\347\263\273\347\273\237.md" @@ -0,0 +1,8459 @@ +# 项目实战-前后端分离博客系统 + +## 1.课程介绍 + +* 纯后端讲解 +* 完整的前台后台代码编写 +* 主流技术栈(SpringBoot,MybatisPlus,SpringSecurity,EasyExcel,Swagger2,Redis,Echarts,Vue,ElementUI....) +* 完善细致的需求分析 +* 由易到难循序渐进 + + + +## 2.创建工程 + +​ 我们有前台和后台两套系统。两套系统的前端工程都已经提供好了。所以我们只需要写两套系统的后端。 + +​ 但是大家思考下,实际上两套后端系统的很多内容是可能重复的。这里如果我们只是单纯的创建两个后端工程。那么就会有大量的重复代码,并且需要修改的时候也需要修改两次。这就是代码复用性不高。 + +​ 所以我们需要创建多模块项目,两套系统可能都会用到的代码可以写到一个公共模块中,让前台系统和后台系统分别取依赖公共模块。 + + + +① 创建父模块 + +~~~~xml + + + 4.0.0 + + com.sangeng + SGBlog + pom + 1.0-SNAPSHOT + + sangeng-framework + sangeng-admin + sangeng-blog + + + + UTF-8 + 1.8 + + + + + + + + org.springframework.boot + spring-boot-dependencies + 2.5.0 + pom + import + + + + com.alibaba + fastjson + 1.2.33 + + + + io.jsonwebtoken + jjwt + 0.9.0 + + + + com.baomidou + mybatis-plus-boot-starter + 3.4.3 + + + + + com.aliyun.oss + aliyun-sdk-oss + 3.10.2 + + + + + com.alibaba + easyexcel + 3.0.5 + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + + + +~~~~ + + + +②创建公共子模块 sangeng-framework + +~~~~xml + + + + SGBlog + com.sangeng + 1.0-SNAPSHOT + + 4.0.0 + + sangeng-framework + + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + com.alibaba + fastjson + + + + io.jsonwebtoken + jjwt + + + + com.baomidou + mybatis-plus-boot-starter + + + + mysql + mysql-connector-java + + + + + com.aliyun.oss + aliyun-sdk-oss + + + + + org.springframework.boot + spring-boot-starter-aop + + + + com.alibaba + easyexcel + + + io.springfox + springfox-swagger2 + + + io.springfox + springfox-swagger-ui + + + + + +~~~~ + + + +③创建博客后台模块sangeng-admin + +~~~~xml + + + + SGBlog + com.sangeng + 1.0-SNAPSHOT + + 4.0.0 + + sangeng-admin + + + + com.sangeng + sangeng-framework + 1.0-SNAPSHOT + + + + +~~~~ + +④创建博客前台模块sangeng-blog + +~~~~xml + + + + SGBlog + com.sangeng + 1.0-SNAPSHOT + + 4.0.0 + + sangeng-blog + + + + com.sangeng + sangeng-framework + 1.0-SNAPSHOT + + + + + +~~~~ + + + +## 3.博客前台 + +### 3.0 准备工作 + +#### 3.1 SpringBoot和MybatisPuls整合配置测试 + +①创建启动类 + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@SpringBootApplication +@MapperScan("com.sangeng.mapper") +public class SanGengBlogApplication { + + public static void main(String[] args) { + SpringApplication.run(SanGengBlogApplication.class,args); + } +} +~~~~ + +②创建application.yml配置文件 + +~~~~yml +server: + port: 7777 +spring: + datasource: + url: jdbc:mysql://localhost:3306/sg_blog?characterEncoding=utf-8&serverTimezone=Asia/Shanghai + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + servlet: + multipart: + max-file-size: 2MB + max-request-size: 5MB +mybatis-plus: + configuration: + # 日志 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + global-config: + db-config: + logic-delete-field: delFlag + logic-delete-value: 1 + logic-not-delete-value: 0 + id-type: auto + +~~~~ + +③ SQL语句 + +​ SQL脚本:SGBlog\资源\SQL\sg_article.sql + +④ 创建实体类,Mapper,Service + +​ 注意思考这些文件应该写在哪个模块下? + +~~~~java +@SuppressWarnings("serial") +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("sg_article") +public class Article { + @TableId + private Long id; + //标题 + private String title; + //文章内容 + private String content; + //文章类型:1 文章 2草稿 + private String type; + //文章摘要 + private String summary; + //所属分类id + private Long categoryId; + //缩略图 + private String thumbnail; + //是否置顶(0否,1是) + private String isTop; + //状态(0已发布,1草稿) + private String status; + //评论数 + private Integer commentCount; + //访问量 + private Long viewCount; + //是否允许评论 1是,0否 + private String isComment; + + private Long createBy; + + private Date createTime; + + private Long updateBy; + + private Date updateTime; + //删除标志(0代表未删除,1代表已删除) + private Integer delFlag; + +} + + +~~~~ + +~~~~java +public interface ArticleMapper extends BaseMapper
{ + + +} + +~~~~ + +~~~~java +public interface ArticleService extends IService
{ +} + +~~~~ + +~~~~java +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + +} +~~~~ + + + +⑤ 创建Controller测试接口 + +​ 注意思考这些文件应该写在哪个模块下? + +~~~~java +@RestController +@RequestMapping("/article") +public class ArticleController { + + @Autowired + private ArticleService articleService; + + @GetMapping("/list") + public List
test(){ + return articleService.list(); + } +} + +~~~~ + +​ 我们可以暂时先注释掉sangeng-framework中的SpringSecurity依赖方便测试 + + + +### 3.1 热门文章列表 + +#### 3.1.0 文章表分析 + +​ 通过需求去分析需要有哪些字段。 + +#### 3.1.1 需求 + +​ 需要查询浏览量最高的前10篇文章的信息。要求展示文章标题和浏览量。把能让用户自己点击跳转到具体的文章详情进行浏览。 + +​ 注意:不能把草稿展示出来,不能把删除了的文章查询出来。要按照浏览量进行降序排序。 + +#### 3.1.2 接口设计 + +​ 见接口文档 + +#### 3.1.3 基础版本代码实现 + +①准备工作 + +统一响应类和响应枚举 + +~~~~java +package com.sangeng.domain; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.sangeng.enums.AppHttpCodeEnum; + +import java.io.Serializable; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ResponseResult implements Serializable { + private Integer code; + private String msg; + private T data; + + public ResponseResult() { + this.code = AppHttpCodeEnum.SUCCESS.getCode(); + this.msg = AppHttpCodeEnum.SUCCESS.getMsg(); + } + + public ResponseResult(Integer code, T data) { + this.code = code; + this.data = data; + } + + public ResponseResult(Integer code, String msg, T data) { + this.code = code; + this.msg = msg; + this.data = data; + } + + public ResponseResult(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + public static ResponseResult errorResult(int code, String msg) { + ResponseResult result = new ResponseResult(); + return result.error(code, msg); + } + public static ResponseResult okResult() { + ResponseResult result = new ResponseResult(); + return result; + } + public static ResponseResult okResult(int code, String msg) { + ResponseResult result = new ResponseResult(); + return result.ok(code, null, msg); + } + + public static ResponseResult okResult(Object data) { + ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getMsg()); + if(data!=null) { + result.setData(data); + } + return result; + } + + public static ResponseResult errorResult(AppHttpCodeEnum enums){ + return setAppHttpCodeEnum(enums,enums.getMsg()); + } + + public static ResponseResult errorResult(AppHttpCodeEnum enums, String msg){ + return setAppHttpCodeEnum(enums,msg); + } + + public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums){ + return okResult(enums.getCode(),enums.getMsg()); + } + + private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String msg){ + return okResult(enums.getCode(),msg); + } + + public ResponseResult error(Integer code, String msg) { + this.code = code; + this.msg = msg; + return this; + } + + public ResponseResult ok(Integer code, T data) { + this.code = code; + this.data = data; + return this; + } + + public ResponseResult ok(Integer code, T data, String msg) { + this.code = code; + this.data = data; + this.msg = msg; + return this; + } + + public ResponseResult ok(T data) { + this.data = data; + return this; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + + +} +~~~~ + +~~~~java +package com.sangeng.enums; + +public enum AppHttpCodeEnum { + // 成功 + SUCCESS(200,"操作成功"), + // 登录 + NEED_LOGIN(401,"需要登录后操作"), + NO_OPERATOR_AUTH(403,"无权限操作"), + SYSTEM_ERROR(500,"出现错误"), + USERNAME_EXIST(501,"用户名已存在"), + PHONENUMBER_EXIST(502,"手机号已存在"), EMAIL_EXIST(503, "邮箱已存在"), + REQUIRE_USERNAME(504, "必需填写用户名"), + LOGIN_ERROR(505,"用户名或密码错误"); + int code; + String msg; + + AppHttpCodeEnum(int code, String errorMessage){ + this.code = code; + this.msg = errorMessage; + } + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } +} + +~~~~ + + + +② 代码实现 + +~~~~java +@RestController +@RequestMapping("/article") +public class ArticleController { + + @Autowired + private ArticleService articleService; + + @GetMapping("/hotArticleList") + public ResponseResult hotArticleList(){ + + ResponseResult result = articleService.hotArticleList(); + return result; + } +} + +~~~~ + +~~~~java +public interface ArticleService extends IService
{ + ResponseResult hotArticleList(); +} + +~~~~ + +~~~~java +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + + @Override + public ResponseResult hotArticleList() { + //查询热门文章 封装成ResponseResult返回 + LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); + //必须是正式文章 + queryWrapper.eq(Article::getStatus,0); + //按照浏览量进行排序 + queryWrapper.orderByDesc(Article::getViewCount); + //最多只查询10条 + Page
page = new Page(1,10); + page(page,queryWrapper); + + List
articles = page.getRecords(); + return ResponseResult.okResult(articles); + } +} + +~~~~ + + + + + +③ 解决跨域问题 + +~~~~java +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + // 设置允许跨域的路径 + registry.addMapping("/**") + // 设置允许跨域请求的域名 + .allowedOriginPatterns("*") + // 是否允许cookie + .allowCredentials(true) + // 设置允许的请求方式 + .allowedMethods("GET", "POST", "DELETE", "PUT") + // 设置允许的header属性 + .allowedHeaders("*") + // 跨域允许时间 + .maxAge(3600); + } + +} +~~~~ + + + + + +#### 3.1.4 使用VO优化 + +​ 目前我们的响应格式其实是不符合接口文档的标准的,多返回了很多字段。这是因为我们查询出来的结果是Article来封装的,Article中字段比较多。 + +​ 我们在项目中一般最后还要把VO来接受查询出来的结果。一个接口对应一个VO,这样即使接口响应字段要修改也只要改VO即可。 + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HotArticleVo { + private Long id; + //标题 + private String title; + + //访问量 + private Long viewCount; +} + +~~~~ + +~~~~java +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + + @Override + public ResponseResult hotArticleList() { + //查询热门文章 封装成ResponseResult返回 + LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); + //必须是正式文章 + queryWrapper.eq(Article::getStatus,0); + //按照浏览量进行排序 + queryWrapper.orderByDesc(Article::getViewCount); + //最多只查询10条 + Page
page = new Page(1,10); + page(page,queryWrapper); + + List
articles = page.getRecords(); + //bean拷贝 + List articleVos = new ArrayList<>(); + for (Article article : articles) { + HotArticleVo vo = new HotArticleVo(); + BeanUtils.copyProperties(article,vo); + articleVos.add(vo); + } + + return ResponseResult.okResult(articleVos); + } +} +~~~~ + +#### 3.1.5 字面值处理 + +​ 实际项目中都不允许直接在代码中使用字面值。都需要定义成常量来使用。这种方式有利于提高代码的可维护性。 + +~~~~java +public class SystemConstants +{ + /** + * 文章是草稿 + */ + public static final int ARTICLE_STATUS_DRAFT = 1; + /** + * 文章是正常分布状态 + */ + public static final int ARTICLE_STATUS_NORMAL = 0; + +} +~~~~ + +~~~~java +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + + @Override + public ResponseResult hotArticleList() { + //查询热门文章 封装成ResponseResult返回 + LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); + //必须是正式文章 + queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL); + //按照浏览量进行排序 + queryWrapper.orderByDesc(Article::getViewCount); + //最多只查询10条 + Page
page = new Page(1,10); + page(page,queryWrapper); + + List
articles = page.getRecords(); + //bean拷贝 + List articleVos = new ArrayList<>(); + for (Article article : articles) { + HotArticleVo vo = new HotArticleVo(); + BeanUtils.copyProperties(article,vo); + articleVos.add(vo); + } + + return ResponseResult.okResult(articleVos); + } +} +~~~~ + + + + + +### 3.2 Bean拷贝工具类封装 + +~~~~java +public class BeanCopyUtils { + + private BeanCopyUtils() { + } + + public static V copyBean(Object source,Class clazz) { + //创建目标对象 + V result = null; + try { + result = clazz.newInstance(); + //实现属性copy + BeanUtils.copyProperties(source, result); + } catch (Exception e) { + e.printStackTrace(); + } + //返回结果 + return result; + } + public static List copyBeanList(List list,Class clazz){ + return list.stream() + .map(o -> copyBean(o, clazz)) + .collect(Collectors.toList()); + } +} + +~~~~ + + + + + +### 3.2 查询分类列表 + +#### 3.2.0 分类表分析 + +​ 通过需求去分析需要有哪些字段。 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sg_category.sql + +#### 3.2.1 需求 + +![image-20220202111056036](img/image-20220202111056036-16437714601701.png) + +​ 页面上需要展示分类列表,用户可以点击具体的分类查看该分类下的文章列表。 + +​ 注意: ①要求只展示有发布正式文章的分类 ②必须是正常状态的分类 + + + +#### 3.2.2 接口设计 + +​ 见接口文档 + +#### 3.2.3 EasyCode代码模板 + +~~~~java +##导入宏定义 +$!{define.vm} + +##保存文件(宏定义) +#save("/entity", ".java") + +##包路径(宏定义) +#setPackageSuffix("entity") + +##自动导入包(全局变量) +$!{autoImport.vm} + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +##表注释(宏定义) +#tableComment("表实体类") +@SuppressWarnings("serial") +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("$!{tableInfo.obj.name}") +public class $!{tableInfo.name} { +#foreach($column in $tableInfo.pkColumn) + #if(${column.comment})//${column.comment}#end +@TableId + private $!{tool.getClsNameByFullName($column.type)} $!{column.name}; +#end + +#foreach($column in $tableInfo.otherColumn) + #if(${column.comment})//${column.comment}#end + + private $!{tool.getClsNameByFullName($column.type)} $!{column.name}; +#end + + + +} + +~~~~ + +~~~~java +##导入宏定义 +$!{define.vm} + +##设置表后缀(宏定义) +#setTableSuffix("Mapper") + +##保存文件(宏定义) +#save("/mapper", "Mapper.java") + +##包路径(宏定义) +#setPackageSuffix("mapper") + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + + +##表注释(宏定义) +#tableComment("表数据库访问层") +public interface $!{tableName} extends BaseMapper<$!tableInfo.name> { + +} + +~~~~ + +~~~~java +##导入宏定义 +$!{define.vm} + +##设置表后缀(宏定义) +#setTableSuffix("Service") + +##保存文件(宏定义) +#save("/service", "Service.java") + +##包路径(宏定义) +#setPackageSuffix("service") + +import com.baomidou.mybatisplus.extension.service.IService; + + +##表注释(宏定义) +#tableComment("表服务接口") +public interface $!{tableName} extends IService<$!tableInfo.name> { + +} + +~~~~ + + + +~~~~java +##导入宏定义 +$!{define.vm} + +##设置表后缀(宏定义) +#setTableSuffix("ServiceImpl") + +##保存文件(宏定义) +#save("/service/impl", "ServiceImpl.java") + +##包路径(宏定义) +#setPackageSuffix("service.impl") + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +##表注释(宏定义) +#tableComment("表服务实现类") +@Service("$!tool.firstLowerCase($tableInfo.name)Service") +public class $!{tableName} extends ServiceImpl<$!{tableInfo.name}Mapper, $!{tableInfo.name}> implements $!{tableInfo.name}Service { + +} + +~~~~ + + + +#### 3.2.4 代码实现 + +~~~~java +@RestController +@RequestMapping("/category") +public class CategoryController { + + @Autowired + private CategoryService categoryService; + + @GetMapping("/getCategoryList") + public ResponseResult getCategoryList(){ + return categoryService.getCategoryList(); + } +} + + +~~~~ + +~~~~java +public interface CategoryService extends IService { + + + ResponseResult getCategoryList(); + +} +~~~~ + +~~~~java +@Service("categoryService") +public class CategoryServiceImpl extends ServiceImpl implements CategoryService { + + @Autowired + private ArticleService articleService; + + @Override + public ResponseResult getCategoryList() { + //查询文章表 状态为已发布的文章 + LambdaQueryWrapper
articleWrapper = new LambdaQueryWrapper<>(); + articleWrapper.eq(Article::getStatus,SystemConstants.ARTICLE_STATUS_NORMAL); + List
articleList = articleService.list(articleWrapper); + //获取文章的分类id,并且去重 + Set categoryIds = articleList.stream() + .map(article -> article.getCategoryId()) + .collect(Collectors.toSet()); + + //查询分类表 + List categories = listByIds(categoryIds); + categories = categories.stream(). + filter(category -> SystemConstants.STATUS_NORMAL.equals(category.getStatus())) + .collect(Collectors.toList()); + //封装vo + List categoryVos = BeanCopyUtils.copyBeanList(categories, CategoryVo.class); + + return ResponseResult.okResult(categoryVos); + } +} + +~~~~ + + + +### 3.3 分页查询文章列表 + +#### 3.3.1 需求 + +​ 在首页和分类页面都需要查询文章列表。 + +​ 首页:查询所有的文章 + +​ 分类页面:查询对应分类下的文章 + +​ 要求:①只能查询正式发布的文章 ②置顶的文章要显示在最前面 + +#### 3.3.2 接口设计 + +​ 见文档 + +#### 3.3.3 代码实现 + +MP支持分页配置 + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@Configuration +public class MbatisPlusConfig { + + /** + * 3.4.0之后版本 + * @return + */ + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor(){ + MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); + mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + return mybatisPlusInterceptor; + } +} +~~~~ + +在ArticleController中 + +~~~~java + @GetMapping("/articleList") + public ResponseResult articleList(Integer pageNum,Integer pageSize,Long categoryId){ + return articleService.articleList(pageNum,pageSize,categoryId); + } +~~~~ + +在ArticleService中 + +~~~~java +ResponseResult articleList(Integer pageNum, Integer pageSize, Long categoryId); +~~~~ + +在ArticleServiceImpl中 + +~~~~java + +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + + @Autowired + private CategoryService categoryService; + + @Override + public ResponseResult hotArticleList() { + //查询热门文章 封装成ResponseResult返回 + LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); + //必须是正式文章 + queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL); + //按照浏览量进行排序 + queryWrapper.orderByDesc(Article::getViewCount); + //最多只查询10条 + Page
page = new Page(1,10); + page(page,queryWrapper); + + List
articles = page.getRecords(); + //bean拷贝 +// List articleVos = new ArrayList<>(); +// for (Article article : articles) { +// HotArticleVo vo = new HotArticleVo(); +// BeanUtils.copyProperties(article,vo); +// articleVos.add(vo); +// } + List vs = BeanCopyUtils.copyBeanList(articles, HotArticleVo.class); + return ResponseResult.okResult(vs); + } + + @Override + public ResponseResult articleList(Integer pageNum, Integer pageSize, Long categoryId) { + //查询条件 + LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); + // 如果 有categoryId 就要 查询时要和传入的相同 + lambdaQueryWrapper.eq(Objects.nonNull(categoryId)&&categoryId>0 ,Article::getCategoryId,categoryId); + // 状态是正式发布的 + lambdaQueryWrapper.eq(Article::getStatus,SystemConstants.ARTICLE_STATUS_NORMAL); + // 对isTop进行降序 + lambdaQueryWrapper.orderByDesc(Article::getIsTop); + + //分页查询 + Page
page = new Page<>(pageNum,pageSize); + page(page,lambdaQueryWrapper); + + List
articles = page.getRecords(); + //查询categoryName + articles.stream() + .map(article -> article.setCategoryName(categoryService.getById(article.getCategoryId()).getName())) + .collect(Collectors.toList()); + //articleId去查询articleName进行设置 +// for (Article article : articles) { +// Category category = categoryService.getById(article.getCategoryId()); +// article.setCategoryName(category.getName()); +// } + + //封装查询结果 + List articleListVos = BeanCopyUtils.copyBeanList(page.getRecords(), ArticleListVo.class); + + PageVo pageVo = new PageVo(articleListVos,page.getTotal()); + return ResponseResult.okResult(pageVo); + } +} +~~~~ + + + +PageVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PageVo { + private List rows; + private Long total; +} + +~~~~ + +ArticleListVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ArticleListVo { + + private Long id; + //标题 + private String title; + //文章摘要 + private String summary; + //所属分类名 + private String categoryName; + //缩略图 + private String thumbnail; + + + //访问量 + private Long viewCount; + + private Date createTime; + + +} +~~~~ + +在Article中增加一个字段 + +~~~~java + @TableField(exist = false) + private String categoryName; +~~~~ + + + +#### 3.3.4 FastJson配置 + +~~~~java + @Bean//使用@Bean注入fastJsonHttpMessageConvert + public HttpMessageConverter fastJsonHttpMessageConverters() { + //1.需要定义一个Convert转换消息的对象 + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); + fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); + + SerializeConfig.globalInstance.put(Long.class, ToStringSerializer.instance); + + fastJsonConfig.setSerializeConfig(SerializeConfig.globalInstance); + fastConverter.setFastJsonConfig(fastJsonConfig); + HttpMessageConverter converter = fastConverter; + return converter; + } + + @Override + public void configureMessageConverters(List> converters) { + converters.add(fastJsonHttpMessageConverters()); + } +~~~~ + + + +### 3.4 文章详情接口 + +#### 3.4.1 需求 + +​ 要求在文章列表点击阅读全文时能够跳转到文章详情页面,可以让用户阅读文章正文。 + +​ 要求:①要在文章详情中展示其分类名 + +#### 3.4.2 接口设计 + +| 请求方式 | 请求路径 | +| -------- | ------------- | +| Get | /article/{id} | + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "categoryId": "1", + "categoryName": "java", + "content": "内容", + "createTime": "2022-01-23 23:20:11", + "id": "1", + "isComment": "0", + "title": "SpringSecurity从入门到精通", + "viewCount": "114" + }, + "msg": "操作成功" +} +~~~~ + +#### 3.4.3 代码实现 + +ArticleController中新增 + +~~~~java + @GetMapping("/{id}") + public ResponseResult getArticleDetail(@PathVariable("id") Long id){ + return articleService.getArticleDetail(id); + } +~~~~ + + + +Service + +~~~~java +ResponseResult getArticleDetail(Long id); +~~~~ + + + +ServiceImpl + +~~~~java + @Override + public ResponseResult getArticleDetail(Long id) { + //根据id查询文章 + Article article = getById(id); + //转换成VO + ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class); + //根据分类id查询分类名 + Long categoryId = articleDetailVo.getCategoryId(); + Category category = categoryService.getById(categoryId); + if(category!=null){ + articleDetailVo.setCategoryName(category.getName()); + } + //封装响应返回 + return ResponseResult.okResult(articleDetailVo); + } +~~~~ + + + + + +### 3.5 友联查询 + +#### 3.5.0 友链表分析 + +​ 通过需求去分析需要有哪些字段。 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sg_link.sql + +#### 3.5.1 需求 + +​ 在友链页面要查询出所有的审核通过的友链。 + +#### 3.5.2 接口设计 + +| 请求方式 | 请求路径 | +| -------- | ---------------- | +| Get | /link/getAllLink | + +响应格式: + +~~~~json +{ + "code": 200, + "data": [ + { + "address": "https://www.baidu.com", + "description": "sda", + "id": "1", + "logo": "图片url1", + "name": "sda" + }, + { + "address": "https://www.qq.com", + "description": "dada", + "id": "2", + "logo": "图片url2", + "name": "sda" + } + ], + "msg": "操作成功" +} +~~~~ + + + +#### 3.5.3 代码实现 + +Controller + +~~~~java +@RestController +@RequestMapping("/link") +public class LinkController { + + @Autowired + private LinkService linkService; + + @GetMapping("/getAllLink") + public ResponseResult getAllLink(){ + return linkService.getAllLink(); + } +} + +~~~~ + + + +Service + +~~~~java +public interface LinkService extends IService { + + ResponseResult getAllLink(); +} + + +~~~~ + + + +ServiceImpl + +~~~~java +@Service("linkService") +public class LinkServiceImpl extends ServiceImpl implements LinkService { + + @Override + public ResponseResult getAllLink() { + //查询所有审核通过的 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Link::getStatus, SystemConstants.LINK_STATUS_NORMAL); + List links = list(queryWrapper); + //转换成vo + List linkVos = BeanCopyUtils.copyBeanList(links, LinkVo.class); + //封装返回 + return ResponseResult.okResult(linkVos); + } +} + +~~~~ + + + +SystemConstants + +~~~~java + /** + * 友链状态为审核通过 + */ + public static final String LINK_STATUS_NORMAL = "0"; +~~~~ + + + + + +### 3.6 登录功能实现 + +​ 使用我们前台和后台的认证授权统一都使用SpringSecurity安全框架来实现。 + +#### 3.6.0 需求 + +​ 需要实现登录功能 + +​ 有些功能必须登录后才能使用,未登录状态是不能使用的。 + +#### 3.6.1 接口设计 + +| 请求方式 | 请求路径 | +| -------- | -------- | +| POST | /login | + +请求体: + +~~~~json +{ + "userName":"sg", + "password":"1234" +} +~~~~ + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0ODBmOThmYmJkNmI0NjM0OWUyZjY2NTM0NGNjZWY2NSIsInN1YiI6IjEiLCJpc3MiOiJzZyIsImlhdCI6MTY0Mzg3NDMxNiwiZXhwIjoxNjQzOTYwNzE2fQ.ldLBUvNIxQCGemkCoMgT_0YsjsWndTg5tqfJb77pabk", + "userInfo": { + "avatar": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2F3bf9c263bc0f2ac5c3a7feb9e218d07475573ec8.gi", + "email": "23412332@qq.com", + "id": 1, + "nickName": "sg333", + "sex": "1" + } + }, + "msg": "操作成功" +} +~~~~ + +#### 3.6.2 表分析 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sys_user.sql + +​ 顺便生成下User和UserMapper后面会用到 + +#### 3.6.3 思路分析 + +登录 + +​ ①自定义登录接口 + +​ 调用ProviderManager的方法进行认证 如果认证通过生成jwt + +​ 把用户信息存入redis中 + +​ ②自定义UserDetailsService + +​ 在这个实现类中去查询数据库 + +​ 注意配置passwordEncoder为BCryptPasswordEncoder + +校验: + +​ ①定义Jwt认证过滤器 + +​ 获取token + +​ 解析token获取其中的userid + +​ 从redis中获取用户信息 + +​ 存入SecurityContextHolder + +#### 3.6.4 准备工作 + +①添加依赖 + +注意放开Security依赖的注释 + +~~~~xml + + + org.springframework.boot + spring-boot-starter-data-redis + + + + com.alibaba + fastjson + 1.2.33 + + + + io.jsonwebtoken + jjwt + 0.9.0 + +~~~~ + +②工具类和相关配置类 + +​ 见 :SGBlog\资源\登录功能所需资源 + +#### 3.6.5 登录接口代码实现 + +##### BlogLoginController + +~~~~java +@RestController +public class BlogLoginController { + @Autowired + private BlogLoginService blogLoginService; + + @PostMapping("/login") + public ResponseResult login(@RequestBody User user){ + return blogLoginService.login(user); + } +} + +~~~~ + + + +##### BlogLoginService + +~~~~java +public interface BlogLoginService { + ResponseResult login(User user); +} + +~~~~ + + + +##### SecurityConfig + +~~~~java +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + + http.logout().disable(); + //允许跨域 + http.cors(); + } + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } +} +~~~~ + + + +##### BlogLoginServiceImpl + +~~~~java + +@Service +public class BlogLoginServiceImpl implements BlogLoginService { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private RedisCache redisCache; + + @Override + public ResponseResult login(User user) { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword()); + Authentication authenticate = authenticationManager.authenticate(authenticationToken); + //判断是否认证通过 + if(Objects.isNull(authenticate)){ + throw new RuntimeException("用户名或密码错误"); + } + //获取userid 生成token + LoginUser loginUser = (LoginUser) authenticate.getPrincipal(); + String userId = loginUser.getUser().getId().toString(); + String jwt = JwtUtil.createJWT(userId); + //把用户信息存入redis + redisCache.setCacheObject("bloglogin:"+userId,loginUser); + + //把token和userinfo封装 返回 + //把User转换成UserInfoVo + UserInfoVo userInfoVo = BeanCopyUtils.copyBean(loginUser.getUser(), UserInfoVo.class); + BlogUserLoginVo vo = new BlogUserLoginVo(jwt,userInfoVo); + return ResponseResult.okResult(vo); + } +} +~~~~ + + + +##### UserDetailServiceImpl + +~~~~java +@Service +public class UserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private UserMapper userMapper; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + //根据用户名查询用户信息 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(User::getUserName,username); + User user = userMapper.selectOne(queryWrapper); + //判断是否查到用户 如果没查到抛出异常 + if(Objects.isNull(user)){ + throw new RuntimeException("用户不存在"); + } + //返回用户信息 + // TODO 查询权限信息封装 + return new LoginUser(user); + } +} +~~~~ + + + + + +##### LoginUser + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LoginUser implements UserDetails { + + private User user; + + + @Override + public Collection getAuthorities() { + return null; + } + + @Override + public String getPassword() { + return user.getPassword(); + } + + @Override + public String getUsername() { + return user.getUserName(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} + +~~~~ + + + + + +##### BlogUserLoginVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BlogUserLoginVo { + + private String token; + private UserInfoVo userInfo; +} +~~~~ + + + +##### UserInfoVo + +~~~~java +@Data +@Accessors(chain = true) +public class UserInfoVo { + /** + * 主键 + */ + private Long id; + + /** + * 昵称 + */ + private String nickName; + + /** + * 头像 + */ + private String avatar; + + private String sex; + + private String email; + + +} + +~~~~ + + + + + +#### 3.6.6 登录校验过滤器代码实现 + +##### 思路 + +​ ①定义Jwt认证过滤器 + +​ 获取token + +​ 解析token获取其中的userid + +​ 从redis中获取用户信息 + +​ 存入SecurityContextHolder + +##### JwtAuthenticationTokenFilter + +~~~~java +@Component +public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { + + @Autowired + private RedisCache redisCache; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + //获取请求头中的token + String token = request.getHeader("token"); + if(!StringUtils.hasText(token)){ + //说明该接口不需要登录 直接放行 + filterChain.doFilter(request, response); + return; + } + //解析获取userid + Claims claims = null; + try { + claims = JwtUtil.parseJWT(token); + } catch (Exception e) { + e.printStackTrace(); + //token超时 token非法 + //响应告诉前端需要重新登录 + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + WebUtils.renderString(response, JSON.toJSONString(result)); + return; + } + String userId = claims.getSubject(); + //从redis中获取用户信息 + LoginUser loginUser = redisCache.getCacheObject("bloglogin:" + userId); + //如果获取不到 + if(Objects.isNull(loginUser)){ + //说明登录过期 提示重新登录 + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + WebUtils.renderString(response, JSON.toJSONString(result)); + return; + } + //存入SecurityContextHolder + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,null); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + + filterChain.doFilter(request, response); + } + + +} +~~~~ + +##### SecurityConfig + +~~~~java +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Autowired + private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + //jwt过滤器测试用,如果测试没有问题吧这里删除了 + .antMatchers("/link/getAllLink").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } +} + +~~~~ + + + +### 3.7 认证授权失败处理 + +​ 目前我们的项目在认证出错或者权限不足的时候响应回来的Json是Security的异常处理结果。但是这个响应的格式肯定是不符合我们项目的接口规范的。所以需要自定义异常处理。 + + + +​ AuthenticationEntryPoint 认证失败处理器 + +​ AccessDeniedHandler 授权失败处理器 + + + +~~~~java +@Component +public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { + authException.printStackTrace(); + //InsufficientAuthenticationException + //BadCredentialsException + ResponseResult result = null; + if(authException instanceof BadCredentialsException){ + result = ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_ERROR.getCode(),authException.getMessage()); + }else if(authException instanceof InsufficientAuthenticationException){ + result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + }else{ + result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),"认证或授权失败"); + } + //响应给前端 + WebUtils.renderString(response, JSON.toJSONString(result)); + } +} + +~~~~ + + + +~~~~java +@Component +public class AccessDeniedHandlerImpl implements AccessDeniedHandler { + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { + accessDeniedException.printStackTrace(); + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH); + //响应给前端 + WebUtils.renderString(response, JSON.toJSONString(result)); + } +} + +~~~~ + + + +配置Security异常处理器 + +~~~~java +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Autowired + private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; + @Autowired + AuthenticationEntryPoint authenticationEntryPoint; + @Autowired + AccessDeniedHandler accessDeniedHandler; + + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + //jwt过滤器测试用,如果测试没有问题吧这里删除了 + .antMatchers("/link/getAllLink").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } +} + +~~~~ + +### 3.8 统一异常处理 + +​ 实际我们在开发过程中可能需要做很多的判断校验,如果出现了非法情况我们是期望响应对应的提示的。但是如果我们每次都自己手动去处理就会非常麻烦。我们可以选择直接抛出异常的方式,然后对异常进行统一处理。把异常中的信息封装成ResponseResult响应给前端。 + +​ + +SystemException + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +public class SystemException extends RuntimeException{ + + private int code; + + private String msg; + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } + + public SystemException(AppHttpCodeEnum httpCodeEnum) { + super(httpCodeEnum.getMsg()); + this.code = httpCodeEnum.getCode(); + this.msg = httpCodeEnum.getMsg(); + } + +} + +~~~~ + +GlobalExceptionHandler + +~~~~java +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(SystemException.class) + public ResponseResult systemExceptionHandler(SystemException e){ + //打印异常信息 + log.error("出现了异常! {}",e); + //从异常对象中获取提示信息封装返回 + return ResponseResult.errorResult(e.getCode(),e.getMsg()); + } + + + @ExceptionHandler(Exception.class) + public ResponseResult exceptionHandler(Exception e){ + //打印异常信息 + log.error("出现了异常! {}",e); + //从异常对象中获取提示信息封装返回 + return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),e.getMessage()); + } +} + +~~~~ + + + +### 3.9 退出登录接口 + +#### 3.9.1 接口设计 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | --------------- | +| POST | /logout | 需要token请求头 | + +响应格式: + +~~~~json +{ + "code": 200, + "msg": "操作成功" +} +~~~~ + + + +#### 3.9.2 代码实现 + +要实现的操作: + +​ 删除redis中的用户信息 + +BlogLoginController + +~~~~java + @PostMapping("/logout") + public ResponseResult logout(){ + return blogLoginService.logout(); + } +~~~~ + +BlogLoginService + +~~~~java +ResponseResult logout(); +~~~~ + +BlogLoginServiceImpl + +~~~~java + @Override + public ResponseResult logout() { + //获取token 解析获取userid + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + //获取userid + Long userId = loginUser.getUser().getId(); + //删除redis中的用户信息 + redisCache.deleteObject("bloglogin:"+userId); + return ResponseResult.okResult(); + } +~~~~ + +SecurityConfig + +要关闭默认的退出登录功能。并且要配置我们的退出登录接口需要认证才能访问 + +~~~~java + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + //注销接口需要认证才能访问 + .antMatchers("/logout").authenticated() + //jwt过滤器测试用,如果测试没有问题吧这里删除了 + .antMatchers("/link/getAllLink").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + //关闭默认的注销功能 + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } +~~~~ + + + +### 3.10 查询评论列表接口 + +#### 3.10.1 需求 + +​ 文章详情页面要展示这篇文章下的评论列表。 + +​ 效果如下: + +![image-20220208214106296](img/image-20220208214106296.png) + + + + + +#### 3.10.2 评论表分析 + +​ 通过需求去分析需要有哪些字段。 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sg_comment.sql + +​ **顺便生成下对应的代码** + +#### 3.10.3 接口设计 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------------------- | ----------------- | +| GET | /comment/commentList | 不需要token请求头 | + +Query格式请求参数: + +articleId:文章id + +pageNum: 页码 + +pageSize: 每页条数 + + + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "rows": [ + { + "articleId": "1", + "children": [ + { + "articleId": "1", + "content": "你说啥?", + "createBy": "1", + "createTime": "2022-01-30 10:06:21", + "id": "20", + "rootId": "1", + "toCommentId": "1", + "toCommentUserId": "1", + "toCommentUserName": "sg333", + "username": "sg333" + } + ], + "content": "asS", + "createBy": "1", + "createTime": "2022-01-29 07:59:22", + "id": "1", + "rootId": "-1", + "toCommentId": "-1", + "toCommentUserId": "-1", + "username": "sg333" + } + ], + "total": "15" + }, + "msg": "操作成功" +} +~~~~ + + + +#### 3.10.4 代码实现 + +##### 3.10.4.1 不考虑子评论 + +CommentController + +~~~~java +@RestController +@RequestMapping("/comment") +public class CommentController { + + @Autowired + private CommentService commentService; + + @GetMapping("/commentList") + public ResponseResult commentList(Long articleId,Integer pageNum,Integer pageSize){ + return commentService.commentList(articleId,pageNum,pageSize); + } +} + +~~~~ + + + +CommentService + +~~~~java +public interface CommentService extends IService { + + ResponseResult commentList(Long articleId, Integer pageNum, Integer pageSize); +} + +~~~~ + + + +CommentServiceImpl + +~~~~java +@Service("commentService") +public class CommentServiceImpl extends ServiceImpl implements CommentService { + + @Autowired + private UserService userService; + + @Override + public ResponseResult commentList(Long articleId, Integer pageNum, Integer pageSize) { + //查询对应文章的根评论 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //对articleId进行判断 + queryWrapper.eq(Comment::getArticleId,articleId); + //根评论 rootId为-1 + queryWrapper.eq(Comment::getRootId,-1); + + //分页查询 + Page page = new Page(pageNum,pageSize); + page(page,queryWrapper); + + List commentVoList = toCommentVoList(page.getRecords()); + + return ResponseResult.okResult(new PageVo(commentVoList,page.getTotal())); + } + + private List toCommentVoList(List list){ + List commentVos = BeanCopyUtils.copyBeanList(list, CommentVo.class); + //遍历vo集合 + for (CommentVo commentVo : commentVos) { + //通过creatyBy查询用户的昵称并赋值 + String nickName = userService.getById(commentVo.getCreateBy()).getNickName(); + commentVo.setUsername(nickName); + //通过toCommentUserId查询用户的昵称并赋值 + //如果toCommentUserId不为-1才进行查询 + if(commentVo.getToCommentUserId()!=-1){ + String toCommentUserName = userService.getById(commentVo.getToCommentUserId()).getNickName(); + commentVo.setToCommentUserName(toCommentUserName); + } + } + return commentVos; + } +} + + +~~~~ + + + +CommentVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CommentVo { + private Long id; + //文章id + private Long articleId; + //根评论id + private Long rootId; + //评论内容 + private String content; + //所回复的目标评论的userid + private Long toCommentUserId; + private String toCommentUserName; + //回复目标评论id + private Long toCommentId; + + private Long createBy; + + private Date createTime; + + private String username; +} + +~~~~ + + + +##### 3.10.4.2 查询子评论 + +CommentVo在之前的基础上增加了 private List children; + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CommentVo { + private Long id; + //文章id + private Long articleId; + //根评论id + private Long rootId; + //评论内容 + private String content; + //所回复的目标评论的userid + private Long toCommentUserId; + private String toCommentUserName; + //回复目标评论id + private Long toCommentId; + + private Long createBy; + + private Date createTime; + + private String username; + + private List children; +} + +~~~~ + + + +CommentServiceImpl + +~~~~java +@Service("commentService") +public class CommentServiceImpl extends ServiceImpl implements CommentService { + + @Autowired + private UserService userService; + + @Override + public ResponseResult commentList(Long articleId, Integer pageNum, Integer pageSize) { + //查询对应文章的根评论 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //对articleId进行判断 + queryWrapper.eq(Comment::getArticleId,articleId); + //根评论 rootId为-1 + queryWrapper.eq(Comment::getRootId,-1); + + //分页查询 + Page page = new Page(pageNum,pageSize); + page(page,queryWrapper); + + List commentVoList = toCommentVoList(page.getRecords()); + + //查询所有根评论对应的子评论集合,并且赋值给对应的属性 + for (CommentVo commentVo : commentVoList) { + //查询对应的子评论 + List children = getChildren(commentVo.getId()); + //赋值 + commentVo.setChildren(children); + } + + return ResponseResult.okResult(new PageVo(commentVoList,page.getTotal())); + } + + /** + * 根据根评论的id查询所对应的子评论的集合 + * @param id 根评论的id + * @return + */ + private List getChildren(Long id) { + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Comment::getRootId,id); + queryWrapper.orderByAsc(Comment::getCreateTime); + List comments = list(queryWrapper); + + List commentVos = toCommentVoList(comments); + return commentVos; + } + + private List toCommentVoList(List list){ + List commentVos = BeanCopyUtils.copyBeanList(list, CommentVo.class); + //遍历vo集合 + for (CommentVo commentVo : commentVos) { + //通过creatyBy查询用户的昵称并赋值 + String nickName = userService.getById(commentVo.getCreateBy()).getNickName(); + commentVo.setUsername(nickName); + //通过toCommentUserId查询用户的昵称并赋值 + //如果toCommentUserId不为-1才进行查询 + if(commentVo.getToCommentUserId()!=-1){ + String toCommentUserName = userService.getById(commentVo.getToCommentUserId()).getNickName(); + commentVo.setToCommentUserName(toCommentUserName); + } + } + return commentVos; + } +} +~~~~ + + + + + +### 3.11 发表评论接口 + +#### 3.11.1 需求 + +​ 用户登录后可以对文章发表评论,也可以对评论进行回复。 + +​ 用户登录后也可以在友链页面进行评论。 + +#### 3.11.2 接口设计 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | ----------- | +| POST | /comment | 需要token头 | + +##### 请求体: + +回复了文章: + +~~~~json +{"articleId":1,"type":0,"rootId":-1,"toCommentId":-1,"toCommentUserId":-1,"content":"评论了文章"} +~~~~ +回复了某条评论: +~~~~json +{"articleId":1,"type":0,"rootId":"3","toCommentId":"3","toCommentUserId":"1","content":"回复了某条评论"} +~~~~ + + + +如果是友链评论,type应该为1 + + + +##### 响应格式: + +~~~~java +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +#### 3.11.3 代码实现 + +CommentController + +~~~~java + @PostMapping + public ResponseResult addComment(@RequestBody Comment comment){ + return commentService.addComment(comment); + } +~~~~ + +CommentService + +~~~~java +ResponseResult addComment(Comment comment); +~~~~ + +CommentServiceImpl + +~~~~java + @Override + public ResponseResult addComment(Comment comment) { + //评论内容不能为空 + if(!StringUtils.hasText(comment.getContent())){ + throw new SystemException(AppHttpCodeEnum.CONTENT_NOT_NULL); + } + save(comment); + return ResponseResult.okResult(); + } +~~~~ + + + +SecurityUtils + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +public class SecurityUtils +{ + + /** + * 获取用户 + **/ + public static LoginUser getLoginUser() + { + return (LoginUser) getAuthentication().getPrincipal(); + } + + /** + * 获取Authentication + */ + public static Authentication getAuthentication() { + return SecurityContextHolder.getContext().getAuthentication(); + } + + public static Boolean isAdmin(){ + Long id = getLoginUser().getUser().getId(); + return id != null && 1L == id; + } + + public static Long getUserId() { + return getLoginUser().getUser().getId(); + } +} +~~~~ + +配置MP字段自动填充 + +~~~~java +@Component +public class MyMetaObjectHandler implements MetaObjectHandler { + @Override + public void insertFill(MetaObject metaObject) { + Long userId = null; + try { + userId = SecurityUtils.getUserId(); + } catch (Exception e) { + e.printStackTrace(); + userId = -1L;//表示是自己创建 + } + this.setFieldValByName("createTime", new Date(), metaObject); + this.setFieldValByName("createBy",userId , metaObject); + this.setFieldValByName("updateTime", new Date(), metaObject); + this.setFieldValByName("updateBy", userId, metaObject); + } + + @Override + public void updateFill(MetaObject metaObject) { + this.setFieldValByName("updateTime", new Date(), metaObject); + this.setFieldValByName(" ", SecurityUtils.getUserId(), metaObject); + } +} +~~~~ + +用注解标识哪些字段在什么情况下需要自动填充 + +~~~~java + /** + * 创建人的用户id + */ + @TableField(fill = FieldFill.INSERT) + private Long createBy; + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + /** + * 更新人 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; +~~~~ + + + + + +### 3.12 友联评论列表 + +#### 3.12.1 需求 + +​ 友链页面也需要查询对应的评论列表。 + + + +#### 3.12.2 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------------------ | ----------------- | +| GET | /comment/linkCommentList | 不需要token请求头 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "rows": [ + { + "articleId": "1", + "children": [ + { + "articleId": "1", + "content": "回复友链评论3", + "createBy": "1", + "createTime": "2022-01-30 10:08:50", + "id": "23", + "rootId": "22", + "toCommentId": "22", + "toCommentUserId": "1", + "toCommentUserName": "sg333", + "username": "sg333" + } + ], + "content": "友链评论2", + "createBy": "1", + "createTime": "2022-01-30 10:08:28", + "id": "22", + "rootId": "-1", + "toCommentId": "-1", + "toCommentUserId": "-1", + "username": "sg333" + } + ], + "total": "1" + }, + "msg": "操作成功" +} +~~~~ + + + + + +#### 3.12.3 代码实现 + +CommentController 修改了之前的文章评论列表接口,并且增加了新的友联评论接口 + +~~~~java + @GetMapping("/commentList") + public ResponseResult commentList(Long articleId,Integer pageNum,Integer pageSize){ + return commentService.commentList(SystemConstants.ARTICLE_COMMENT,articleId,pageNum,pageSize); + } + @GetMapping("/linkCommentList") + public ResponseResult linkCommentList(Integer pageNum,Integer pageSize){ + return commentService.commentList(SystemConstants.LINK_COMMENT,null,pageNum,pageSize); + } +~~~~ + + + +SystemConstants增加了两个常量 + +~~~~java + /** + * 评论类型为:文章评论 + */ + public static final String ARTICLE_COMMENT = "0"; + /** + * 评论类型为:友联评论 + */ + public static final String LINK_COMMENT = "1"; +~~~~ + + + + + +CommentService修改了commentList方法,增加了一个参数commentType + +~~~~java +ResponseResult commentList(String commentType, Long articleId, Integer pageNum, Integer pageSize); +~~~~ + + + +CommentServiceImpl修改commentList方法的代码,必须commentType为0的时候才增加articleId的判断,并且增加了一个评论类型的添加。 + +~~~~java + @Override + public ResponseResult commentList(String commentType, Long articleId, Integer pageNum, Integer pageSize) { + //查询对应文章的根评论 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //对articleId进行判断 + queryWrapper.eq(SystemConstants.ARTICLE_COMMENT.equals(commentType),Comment::getArticleId,articleId); + //根评论 rootId为-1 + queryWrapper.eq(Comment::getRootId,-1); + + //评论类型 + queryWrapper.eq(Comment::getType,commentType); + + //分页查询 + Page page = new Page(pageNum,pageSize); + page(page,queryWrapper); + + List commentVoList = toCommentVoList(page.getRecords()); + + //查询所有根评论对应的子评论集合,并且赋值给对应的属性 + for (CommentVo commentVo : commentVoList) { + //查询对应的子评论 + List children = getChildren(commentVo.getId()); + //赋值 + commentVo.setChildren(children); + } + + return ResponseResult.okResult(new PageVo(commentVoList,page.getTotal())); + } +~~~~ + + + + + +### 3.13 个人信息查询接口 + +#### 3.13.1 需求 + +​ 进入个人中心的时候需要能够查看当前用户信息 + +#### 3.13.2 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------------- | --------------- | +| GET | /user/userInfo | 需要token请求头 | + +不需要参数 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "avatar":"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2F3bf9c263bc0f2ac5c3a7feb9e218d07475573ec8.gi", + "email":"23412332@qq.com", + "id":"1", + "nickName":"sg333", + "sex":"1" + }, + "msg":"操作成功" +} +~~~~ + + + +#### 3.13.3 代码实现 + + + +UserController + +~~~~java +@RestController +@RequestMapping("/user") +public class UserController { + + @Autowired + private UserService userService; + + @GetMapping("/userInfo") + public ResponseResult userInfo(){ + return userService.userInfo(); + } +} + +~~~~ + + + +UserService增加方法定义 + +~~~~java +public interface UserService extends IService { + + ResponseResult userInfo(); + +} + +~~~~ + + + +UserServiceImpl实现userInfo方法 + +~~~~java + @Override + public ResponseResult userInfo() { + //获取当前用户id + Long userId = SecurityUtils.getUserId(); + //根据用户id查询用户信息 + User user = getById(userId); + //封装成UserInfoVo + UserInfoVo vo = BeanCopyUtils.copyBean(user,UserInfoVo.class); + return ResponseResult.okResult(vo); + } +~~~~ + + + +SecurityConfig配置该接口必须认证后才能访问 + +~~~~java + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + //注销接口需要认证才能访问 + .antMatchers("/logout").authenticated() + //个人信息接口必须登录后才能访问 + .antMatchers("/user/userInfo").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + //关闭默认的注销功能 + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } +~~~~ + + + +### 3.14 头像上传接口 + +#### 3.14.1 需求 + +​ 在个人中心点击编辑的时候可以上传头像图片。上传完头像后,可以用于更新个人信息接口。 + + + +#### 3.14.2 OSS + +##### 3.14.2.1 为什么要使用OSS + +​ 因为如果把图片视频等文件上传到自己的应用的Web服务器,在读取图片的时候会占用比较多的资源。影响应用服务器的性能。 + +​ 所以我们一般使用OSS(Object Storage Service对象存储服务)存储图片或视频。 + + + +##### 3.14.2.2 七牛云基本使用测试 + +![image-20220227224537701](img/image-20220227224537701.png) + +![image-20220227224443813](img/image-20220227224443813.png) + + + +秘钥 + +![image-20220228230512598](img/image-20220228230512598.png) + +![image-20220228230933808](img/image-20220228230933808.png) + + + +##### 3.14.2.3 七牛云测试代码编写 + +①添加依赖 + +~~~~xml + + com.qiniu + qiniu-java-sdk + [7.7.0, 7.7.99] + +~~~~ + + + +②复制修改案例代码 + +application.yml + +~~~~yml +oss: + accessKey: xxxx + secretKey: xxxx + bucket: sg-blog +~~~~ + +OSSTest.java + +~~~~java +@SpringBootTest +@ConfigurationProperties(prefix = "oss") +public class OSSTest { + + private String accessKey; + private String secretKey; + private String bucket; + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public void setBucket(String bucket) { + this.bucket = bucket; + } + + @Test + public void testOss(){ + //构造一个带指定 Region 对象的配置类 + Configuration cfg = new Configuration(Region.autoRegion()); + //...其他参数参考类注释 + + UploadManager uploadManager = new UploadManager(cfg); + //...生成上传凭证,然后准备上传 +// String accessKey = "your access key"; +// String secretKey = "your secret key"; +// String bucket = "sg-blog"; + + //默认不指定key的情况下,以文件内容的hash值作为文件名 + String key = "2022/sg.png"; + + try { +// byte[] uploadBytes = "hello qiniu cloud".getBytes("utf-8"); +// ByteArrayInputStream byteInputStream=new ByteArrayInputStream(uploadBytes); + + + InputStream inputStream = new FileInputStream("C:\\Users\\root\\Desktop\\Snipaste_2022-02-28_22-48-37.png"); + Auth auth = Auth.create(accessKey, secretKey); + String upToken = auth.uploadToken(bucket); + + try { + Response response = uploadManager.put(inputStream,key,upToken,null, null); + //解析上传成功的结果 + DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); + System.out.println(putRet.key); + System.out.println(putRet.hash); + } catch (QiniuException ex) { + Response r = ex.response; + System.err.println(r.toString()); + try { + System.err.println(r.bodyString()); + } catch (QiniuException ex2) { + //ignore + } + } + } catch (Exception ex) { + //ignore + } + + } +} +~~~~ + + + +#### 3.14.2 接口设计 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | --------- | +| POST | /upload | 需要token | + +参数: + +​ img,值为要上传的文件 + +请求头: + +​ Content-Type :multipart/form-data; + + + +响应格式: + +~~~~json +{ + "code": 200, + "data": "文件访问链接", + "msg": "操作成功" +} +~~~~ + +#### 3.14.3 代码实现 + +~~~~java +@RestController +public class UploadController { + @Autowired + private UploadService uploadService; + + @PostMapping("/upload") + public ResponseResult uploadImg(MultipartFile img){ + return uploadService.uploadImg(img); + } +} + +~~~~ + +~~~~java +public interface UploadService { + ResponseResult uploadImg(MultipartFile img); +} + +~~~~ + + + +~~~~java +@Service +@Data +@ConfigurationProperties(prefix = "oss") +public class OssUploadService implements UploadService { + @Override + public ResponseResult uploadImg(MultipartFile img) { + //判断文件类型 + //获取原始文件名 + String originalFilename = img.getOriginalFilename(); + //对原始文件名进行判断 + if(!originalFilename.endsWith(".png")){ + throw new SystemException(AppHttpCodeEnum.FILE_TYPE_ERROR); + } + + //如果判断通过上传文件到OSS + String filePath = PathUtils.generateFilePath(originalFilename); + String url = uploadOss(img,filePath);// 2099/2/3/wqeqeqe.png + return ResponseResult.okResult(url); + } + + private String accessKey; + private String secretKey; + private String bucket; + + + private String uploadOss(MultipartFile imgFile, String filePath){ + //构造一个带指定 Region 对象的配置类 + Configuration cfg = new Configuration(Region.autoRegion()); + //...其他参数参考类注释 + UploadManager uploadManager = new UploadManager(cfg); + //默认不指定key的情况下,以文件内容的hash值作为文件名 + String key = filePath; + try { + InputStream inputStream = imgFile.getInputStream(); + Auth auth = Auth.create(accessKey, secretKey); + String upToken = auth.uploadToken(bucket); + try { + Response response = uploadManager.put(inputStream,key,upToken,null, null); + //解析上传成功的结果 + DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); + System.out.println(putRet.key); + System.out.println(putRet.hash); + return "http://r7yxkqloa.bkt.clouddn.com/"+key; + } catch (QiniuException ex) { + Response r = ex.response; + System.err.println(r.toString()); + try { + System.err.println(r.bodyString()); + } catch (QiniuException ex2) { + //ignore + } + } + } catch (Exception ex) { + //ignore + } + return "www"; + } +} + +~~~~ + + + +PathUtils + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +public class PathUtils { + + public static String generateFilePath(String fileName){ + //根据日期生成路径 2022/1/15/ + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/"); + String datePath = sdf.format(new Date()); + //uuid作为文件名 + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + //后缀和文件后缀一致 + int index = fileName.lastIndexOf("."); + // test.jpg -> .jpg + String fileType = fileName.substring(index); + return new StringBuilder().append(datePath).append(uuid).append(fileType).toString(); + } +} + +~~~~ + + + +### 3.15 更新个人信息接口 + +#### 3.15.1 需求 + +​ 在编辑完个人资料后点击保存会对个人资料进行更新。 + +#### 3.15.2 接口设计 + +​ + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------------- | --------------- | +| PUT | /user/userInfo | 需要token请求头 | + +参数 + +请求体中json格式数据: + +~~~~json +{ + "avatar":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/31/948597e164614902ab1662ba8452e106.png", + "email":"23412332@qq.com", + "id":"1", + "nickName":"sg333", + "sex":"1" +} +~~~~ + + + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 3.15.3 代码实现 + +UserController + +~~~~java + @PutMapping("/userInfo") + public ResponseResult updateUserInfo(@RequestBody User user){ + return userService.updateUserInfo(user); + } +~~~~ + +UserService + +~~~~java +ResponseResult updateUserInfo(User user); +~~~~ + + + +UserServiceImpl + +~~~~java + @Override + public ResponseResult updateUserInfo(User user) { + updateById(user); + return ResponseResult.okResult(); + } +~~~~ + +### 3.16 用户注册 + +#### 3.16.1 需求 + +​ 要求用户能够在注册界面完成用户的注册。要求用户名,昵称,邮箱不能和数据库中原有的数据重复。如果某项重复了注册失败并且要有对应的提示。并且要求用户名,密码,昵称,邮箱都不能为空。 + +​ 注意:密码必须密文存储到数据库中。 + +#### 3.16.2 接口设计 + +​ + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------------- | ----------------- | +| POST | /user/register | 不需要token请求头 | + +参数 + +请求体中json格式数据: + +~~~~json +{ + "email": "string", + "nickName": "string", + "password": "string", + "userName": "string" +} +~~~~ + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +#### 3.16.3 代码实现 + +UserController + +~~~~java + @PostMapping("/register") + public ResponseResult register(@RequestBody User user){ + return userService.register(user); + } +~~~~ + +UserService + +~~~~java +ResponseResult register(User user); +~~~~ + +UserServiceImpl + +~~~~java + @Autowired + private PasswordEncoder passwordEncoder; + @Override + public ResponseResult register(User user) { + //对数据进行非空判断 + if(!StringUtils.hasText(user.getUserName())){ + throw new SystemException(AppHttpCodeEnum.USERNAME_NOT_NULL); + } + if(!StringUtils.hasText(user.getPassword())){ + throw new SystemException(AppHttpCodeEnum.PASSWORD_NOT_NULL); + } + if(!StringUtils.hasText(user.getEmail())){ + throw new SystemException(AppHttpCodeEnum.EMAIL_NOT_NULL); + } + if(!StringUtils.hasText(user.getNickName())){ + throw new SystemException(AppHttpCodeEnum.NICKNAME_NOT_NULL); + } + //对数据进行是否存在的判断 + if(userNameExist(user.getUserName())){ + throw new SystemException(AppHttpCodeEnum.USERNAME_EXIST); + } + if(nickNameExist(user.getNickName())){ + throw new SystemException(AppHttpCodeEnum.NICKNAME_EXIST); + } + //... + //对密码进行加密 + String encodePassword = passwordEncoder.encode(user.getPassword()); + user.setPassword(encodePassword); + //存入数据库 + save(user); + return ResponseResult.okResult(); + } + +~~~~ + +~~~~java +public enum AppHttpCodeEnum { + // 成功 + SUCCESS(200,"操作成功"), + // 登录 + NEED_LOGIN(401,"需要登录后操作"), + NO_OPERATOR_AUTH(403,"无权限操作"), + SYSTEM_ERROR(500,"出现错误"), + USERNAME_EXIST(501,"用户名已存在"), + PHONENUMBER_EXIST(502,"手机号已存在"), EMAIL_EXIST(503, "邮箱已存在"), + REQUIRE_USERNAME(504, "必需填写用户名"), + CONTENT_NOT_NULL(506, "评论内容不能为空"), + FILE_TYPE_ERROR(507, "文件类型错误,请上传png文件"), + USERNAME_NOT_NULL(508, "用户名不能为空"), + NICKNAME_NOT_NULL(509, "昵称不能为空"), + PASSWORD_NOT_NULL(510, "密码不能为空"), + EMAIL_NOT_NULL(511, "邮箱不能为空"), + NICKNAME_EXIST(512, "昵称已存在"), + LOGIN_ERROR(505,"用户名或密码错误"); + int code; + String msg; + + AppHttpCodeEnum(int code, String errorMessage){ + this.code = code; + this.msg = errorMessage; + } + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } +} + +~~~~ + + + + + + + +### 3.17 AOP实现日志记录 + +#### 3.17.1 需求 + +​ 需要通过日志记录接口调用信息。便于后期调试排查。并且可能有很多接口都需要进行日志的记录。 + +​ 接口被调用时日志打印格式如下: + +![image-20220313133714102](img/image-20220313133714102.png) + + + +#### 3.17.2 思路分析 + +​ 相当于是对原有的功能进行增强。并且是批量的增强,这个时候就非常适合用AOP来进行实现。 + +​ + +#### 3.17.3 代码实现 + +日志打印格式 + +~~~~java + log.info("=======Start======="); + // 打印请求 URL + log.info("URL : {}",); + // 打印描述信息 + log.info("BusinessName : {}", ); + // 打印 Http method + log.info("HTTP Method : {}", ); + // 打印调用 controller 的全路径以及执行方法 + log.info("Class Method : {}.{}", ); + // 打印请求的 IP + log.info("IP : {}",); + // 打印请求入参 + log.info("Request Args : {}",); + // 打印出参 + log.info("Response : {}", ); + // 结束后换行 + log.info("=======End=======" + System.lineSeparator()); +~~~~ + + + + + + + +### 3.18 更新浏览次数 + +#### 3.18.1 需求 + +​ 在用户浏览博文时要实现对应博客浏览量的增加。 + +#### 3.18.2 思路分析 + +​ 我们只需要在每次用户浏览博客时更新对应的浏览数即可。 + +​ 但是如果直接操作博客表的浏览量的话,在并发量大的情况下会出现什么问题呢? + +​ 如何去优化呢? + +​ + +①在应用启动时把博客的浏览量存储到redis中 + +②更新浏览量时去更新redis中的数据 + +③每隔10分钟把Redis中的浏览量更新到数据库中 + +④读取文章浏览量时从redis读取 + + + +#### 3.18.3 铺垫知识 + +##### 3.18.3.1 CommandLineRunner实现项目启动时预处理 + +​ 如果希望在SpringBoot应用启动时进行一些初始化操作可以选择使用CommandLineRunner来进行处理。 + +​ 我们只需要实现CommandLineRunner接口,并且把对应的bean注入容器。把相关初始化的代码重新到需要重新的方法中。 + +​ 这样就会在应用启动的时候执行对应的代码。 + +~~~~java +@Component +public class TestRunner implements CommandLineRunner { + @Override + public void run(String... args) throws Exception { + System.out.println("程序初始化"); + } +} + +~~~~ + + + +##### 3.18.3.2 定时任务 + +​ 定时任务的实现方式有很多,比如XXL-Job等。但是其实核心功能和概念都是类似的,很多情况下只是调用的API不同而已。 + +​ 这里就先用SpringBoot为我们提供的定时任务的API来实现一个简单的定时任务,让大家先对定时任务里面的一些核心概念有个大致的了解。 + +实现步骤 + +① 使用@EnableScheduling注解开启定时任务功能 + +​ 我们可以在配置类上加上@EnableScheduling + +~~~~java +@SpringBootApplication +@MapperScan("com.sangeng.mapper") +@EnableScheduling +public class SanGengBlogApplication { + public static void main(String[] args) { + SpringApplication.run(SanGengBlogApplication.class,args); + } +} +~~~~ + +② 确定定时任务执行代码,并配置任务执行时间 + +​ 使用@Scheduled注解标识需要定时执行的代码。注解的cron属性相当于是任务的执行时间。目前可以使用 0/5 * * * * ? 进行测试,代表从0秒开始,每隔5秒执行一次。 + +​ 注意:对应的bean要注入容器,否则不会生效。 + +~~~~java +@Component +public class TestJob { + + @Scheduled(cron = "0/5 * * * * ?") + public void testJob(){ + //要执行的代码 + System.out.println("定时任务执行了"); + } +} + +~~~~ + + + +###### 3.18.3.2.1 cron 表达式语法 + +​ cron表达式是用来设置定时任务执行时间的表达式。 + +​ 很多情况下我们可以用 : [在线Cron表达式生成器](https://www.bejson.com/othertools/cron/) 来帮助我们理解cron表达式和书写cron表达式。 + +​ 但是我们还是有需要学习对应的Cron语法的,这样可以更有利于我们书写Cron表达式。 + + + +如上我们用到的 0/5 * * * * ? *,cron表达式由七部分组成,中间由空格分隔,这七部分从左往右依次是: + +秒(0~59),分钟(0~59),小时(0~23),日期(1-月最后一天),月份(1-12),星期几(1-7,1表示星期日),年份(一般该项不设置,直接忽略掉,即可为空值) + + + +通用特殊字符:, - * / (可以在任意部分使用) + +> * + +星号表示任意值,例如: + +``` +* * * * * ? +``` + +表示 “ 每年每月每天每时每分每秒 ” 。 + + + +> , + +可以用来定义列表,例如 : + +``` +1,2,3 * * * * ? +``` + +表示 “ 每年每月每天每时每分的每个第1秒,第2秒,第3秒 ” 。 + + + +> - + +定义范围,例如: + +``` +1-3 * * * * ? +``` + +表示 “ 每年每月每天每时每分的第1秒至第3秒 ”。 + + + +> / + +每隔多少,例如 + +``` +5/10 * * * * ? +``` + +表示 “ 每年每月每天每时每分,从第5秒开始,每10秒一次 ” 。即 “ / ” 的左侧是开始值,右侧是间隔。如果是从 “ 0 ” 开始的话,也可以简写成 “ /10 ” + + + + + + + + + +日期部分还可允许特殊字符: ? L W + +星期部分还可允许的特殊字符: ? L # + + + +> ? + +只可用在日期和星期部分。表示没有具体的值,使用?要注意冲突。日期和星期两个部分如果其中一个部分设置了值,则另一个必须设置为 “ ? ”。 + +例如: + +~~~~ +0\* * * 2 * ? + 和 +0\* * * ? * 2 +~~~~ + +同时使用?和同时不使用?都是不对的 + +例如下面写法就是错的 + +~~~~ +* * * 2 * 2 + 和 +* * * ? * ? + +~~~~ + + + + + +> W + +只能用在日期中,表示当月中最接近某天的工作日 + +``` +0 0 0 31W * ? +``` + +表示最接近31号的工作日,如果31号是星期六,则表示30号,即星期五,如果31号是星期天,则表示29号,即星期五。如果31号是星期三,则表示31号本身,即星期三。 + + + + + + + + + +> L + +表示最后(Last),只能用在日期和星期中 + + + +在日期中表示每月最后一天,在一月份中表示31号,在六月份中表示30号 + +也可以表示每月倒是第N天。例如: L-2表示每个月的倒数第2天 + + + + 0 0 0 LW * ? + LW可以连起来用,表示每月最后一个工作日,即每月最后一个星期五 + + + +在星期中表示7即星期六 + + +~~~~ +0 0 0 ? * L +表示每个星期六 +0 0 0 ? * 6L +若前面有其他值的话,则表示最后一个星期几,即每月的最后一个星期五 +~~~~ + + + + + + +> # + +只能用在星期中,表示第几个星期几 + +~~~~ +0 0 0 ? * 6#3 +表示每个月的第三个星期五。 +~~~~ + + + + + + + +#### 3.18.4 接口设计 + +​ + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------------------------- | ----------------- | +| PUT | /article/updateViewCount/{id} | 不需要token请求头 | + +参数 + +​ 请求路径中携带文章id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 3.18.5 代码实现 + +##### ①在应用启动时把博客的浏览量存储到redis中 + +​ 实现CommandLineRunner接口,在应用启动时初始化缓存。 + +~~~~java +@Component +public class ViewCountRunner implements CommandLineRunner { + + @Autowired + private ArticleMapper articleMapper; + + @Autowired + private RedisCache redisCache; + + @Override + public void run(String... args) throws Exception { + //查询博客信息 id viewCount + List
articles = articleMapper.selectList(null); + Map viewCountMap = articles.stream() + .collect(Collectors.toMap(article -> article.getId().toString(), article -> { + return article.getViewCount().intValue();// + })); + //存储到redis中 + redisCache.setCacheMap("article:viewCount",viewCountMap); + } +} + +~~~~ + + + +##### ②更新浏览量时去更新redsi中的数据 + +RedisCache增加方法 + +~~~~java + public void incrementCacheMapValue(String key,String hKey,long v){ + redisTemplate.boundHashOps(key).increment(hKey, v); + } +~~~~ + +ArticleController中增加方法更新阅读数 + +~~~~java + @PutMapping("/updateViewCount/{id}") + public ResponseResult updateViewCount(@PathVariable("id") Long id){ + return articleService.updateViewCount(id); + } +~~~~ + +ArticleService中增加方法 + +~~~~java +ResponseResult updateViewCount(Long id); +~~~~ + +ArticleServiceImpl中实现方法 + +~~~~java + @Override + public ResponseResult updateViewCount(Long id) { + //更新redis中对应 id的浏览量 + redisCache.incrementCacheMapValue("article:viewCount",id.toString(),1); + return ResponseResult.okResult(); + } +~~~~ + + + + + + + +##### ③定时任务每隔10分钟把Redis中的浏览量更新到数据库中 + +Article中增加构造方法 + +~~~~java + public Article(Long id, long viewCount) { + this.id = id; + this.viewCount = viewCount; + } +~~~~ + + + + + +~~~~java +@Component +public class UpdateViewCountJob { + + @Autowired + private RedisCache redisCache; + + @Autowired + private ArticleService articleService; + + @Scheduled(cron = "0/5 * * * * ?") + public void updateViewCount(){ + //获取redis中的浏览量 + Map viewCountMap = redisCache.getCacheMap("article:viewCount"); + + List
articles = viewCountMap.entrySet() + .stream() + .map(entry -> new Article(Long.valueOf(entry.getKey()), entry.getValue().longValue())) + .collect(Collectors.toList()); + //更新到数据库中 + articleService.updateBatchById(articles); + + } +} + +~~~~ + + + +##### ④读取文章浏览量时从redis读取 + +~~~~java + @Override + public ResponseResult getArticleDetail(Long id) { + //根据id查询文章 + Article article = getById(id); + //从redis中获取viewCount + Integer viewCount = redisCache.getCacheMapValue("article:viewCount", id.toString()); + article.setViewCount(viewCount.longValue()); + //转换成VO + ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class); + //根据分类id查询分类名 + Long categoryId = articleDetailVo.getCategoryId(); + Category category = categoryService.getById(categoryId); + if(category!=null){ + articleDetailVo.setCategoryName(category.getName()); + } + //封装响应返回 + return ResponseResult.okResult(articleDetailVo); + } + +~~~~ + + + + + +## 4. Swagger2 + +### 4.1 简介 + +​ Swagger 是一套基于 OpenAPI 规范构建的开源工具,可以帮助我们设计、构建、记录以及使用 Rest API。 + +### 4.2 为什么使用Swagger + +​ 当下很多公司都采取前后端分离的开发模式,前端和后端的工作由不同的工程师完成。在这种开发模式下,维持一份及时更新且完整的 Rest API 文档将会极大的提高我们的工作效率。传统意义上的文档都是后端开发人员手动编写的,相信大家也都知道这种方式很难保证文档的及时性,这种文档久而久之也就会失去其参考意义,反而还会加大我们的沟通成本。而 Swagger 给我们提供了一个全新的维护 API 文档的方式,下面我们就来了解一下它的优点: + +1.代码变,文档变。只需要少量的注解,Swagger 就可以根据代码自动生成 API 文档,很好的保证了文档的时效性。 +2.跨语言性,支持 40 多种语言。 +3.Swagger UI 呈现出来的是一份可交互式的 API 文档,我们可以直接在文档页面尝试 API 的调用,省去了准备复杂的调用参数的过程。 + + + +### 4.3 快速入门 + +#### 4.3.1 引入依赖 + +~~~~xml + + io.springfox + springfox-swagger2 + + + io.springfox + springfox-swagger-ui + + +~~~~ + + + +#### 4.3.2 启用Swagger2 + +​ 在启动类上或者配置类加 @EnableSwagger2 注解 + +~~~~java +@SpringBootApplication +@MapperScan("com.sangeng.mapper") +@EnableScheduling +@EnableSwagger2 +public class SanGengBlogApplication { + public static void main(String[] args) { + SpringApplication.run(SanGengBlogApplication.class,args); + } +} +~~~~ + + + +#### 4.3.3 测试 + +​ 访问:http://localhost:7777/swagger-ui.html 注意其中localhost和7777要调整成实际项目的域名和端口号。 + + + +### 4.4 具体配置 + + + +#### 4.4.1 Controller配置 + +##### 4.4.1 @Api 注解 + +属性介绍: + +tags 设置标签 + +description 设置描述信息 + +~~~~java +@RestController +@RequestMapping("/comment") +@Api(tags = "评论",description = "评论相关接口") +public class CommentController { +} +~~~~ + + + + + +#### 4.4.2 接口配置 + +##### 4.4.2.1 接口描述配置@ApiOperation + +~~~~java + @GetMapping("/linkCommentList") + @ApiOperation(value = "友链评论列表",notes = "获取一页友链评论") + public ResponseResult linkCommentList(Integer pageNum,Integer pageSize){ + return commentService.commentList(SystemConstants.LINK_COMMENT,null,pageNum,pageSize); + } +~~~~ + + + +##### 4.4.2.2 接口参数描述 + + @ApiImplicitParam 用于描述接口的参数,但是一个接口可能有多个参数,所以一般与 @ApiImplicitParams 组合使用。 + +~~~~java + @GetMapping("/linkCommentList") + @ApiOperation(value = "友链评论列表",notes = "获取一页友链评论") + @ApiImplicitParams({ + @ApiImplicitParam(name = "pageNum",value = "页号"), + @ApiImplicitParam(name = "pageSize",value = "每页大小") + } + ) + public ResponseResult linkCommentList(Integer pageNum,Integer pageSize){ + return commentService.commentList(SystemConstants.LINK_COMMENT,null,pageNum,pageSize); + } +~~~~ + + + +#### 4.4.3 实体类配置 + +##### 4.4.3.1 实体的描述配置@ApiModel + +@ApiModel用于描述实体类。 + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel(description = "添加评论dto") +public class AddCommentDto{ + //.. +} +~~~~ + + + +##### 4.4.3.2 实体的属性的描述配置@ApiModelProperty + +@ApiModelProperty用于描述实体的属性 + +~~~~java + @ApiModelProperty(notes = "评论类型(0代表文章评论,1代表友链评论)") + private String type; +~~~~ + + + + + + + +#### 4.4.4 文档信息配置 + +~~~~java +@Configuration +public class SwaggerConfig { + @Bean + public Docket customDocket() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.sangeng.controller")) + .build(); + } + + private ApiInfo apiInfo() { + Contact contact = new Contact("团队名", "http://www.my.com", "my@my.com"); + return new ApiInfoBuilder() + .title("文档标题") + .description("文档描述") + .contact(contact) // 联系方式 + .version("1.1.0") // 版本 + .build(); + } +} +~~~~ + + + +## 5. 博客后台 + +### 5.0 准备工作 + +前端工程启动 + +npm install + +npm run dev + + + +①创建启动类 + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@SpringBootApplication +@MapperScan("com.sangeng.mapper") +public class BlogAdminApplication { + public static void main(String[] args) { + SpringApplication.run(BlogAdminApplication.class, args); + } +} + +~~~~ + +②创建application.yml配置文件 + +~~~~yml +server: + port: 8989 +spring: + datasource: + url: jdbc:mysql://localhost:3306/sg_blog?characterEncoding=utf-8&serverTimezone=UTC + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + servlet: + multipart: + max-file-size: 2MB + max-request-size: 5MB + +mybatis-plus: + configuration: + # 日志 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + global-config: + db-config: + logic-delete-field: delFlag + logic-delete-value: 1 + logic-not-delete-value: 0 + id-type: auto + + +~~~~ + +③ SQL语句 + +​ SQL脚本:SGBlog\资源\SQL\sg_tag.sql + +④ 创建实体类,Mapper,Service + +​ 注意思考这些文件应该写在哪个模块下? + + + +Tag + +~~~~java + +@SuppressWarnings("serial") +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("sg_tag") +public class Tag { + @TableId + private Long id; + + + private Long createBy; + + private Date createTime; + + private Long updateBy; + + private Date updateTime; + //删除标志(0代表未删除,1代表已删除) + private Integer delFlag; + //备注 + private String remark; + //标签名 + private String name; + + + +} + +~~~~ + + +TagMapper +~~~~java +/** + * 标签(Tag)表数据库访问层 + * + * @author makejava + * @since 2022-07-19 22:33:35 + */ +public interface TagMapper extends BaseMapper { + +} + + + +~~~~ + + +TagService +~~~~java +/** + * 标签(Tag)表服务接口 + * + * @author makejava + * @since 2022-07-19 22:33:38 + */ +public interface TagService extends IService { + +} + +~~~~ + + +TagServiceImpl +~~~~java +/** + * 标签(Tag)表服务实现类 + * + * @author makejava + * @since 2022-07-19 22:33:38 + */ +@Service("tagService") +public class TagServiceImpl extends ServiceImpl implements TagService { + +} + + +~~~~ + + + +⑤ 创建Controller测试接口 + +​ 注意思考这些文件应该写在哪个模块下? + +TagController /content/tag +~~~~java +@RestController +@RequestMapping("/content/tag") +public class TagController { + @Autowired + private TagService tagService; + + @GetMapping("/list") + public ResponseResult list(){ + return ResponseResult.okResult(tagService.list()); + } +} + + +~~~~ + + + +⑥添加security相关类 + +~~~~java +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Autowired + private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; + @Autowired + AuthenticationEntryPoint authenticationEntryPoint; + @Autowired + AccessDeniedHandler accessDeniedHandler; + + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 +// .antMatchers("/login").anonymous() +// //注销接口需要认证才能访问 +// .antMatchers("/logout").authenticated() +// .antMatchers("/user/userInfo").authenticated() +// .antMatchers("/upload").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + //关闭默认的注销功能 + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } +} + +~~~~ + + + +~~~~java +@Component +public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { + + @Autowired + private RedisCache redisCache; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + //获取请求头中的token + String token = request.getHeader("token"); + if(!StringUtils.hasText(token)){ + //说明该接口不需要登录 直接放行 + filterChain.doFilter(request, response); + return; + } + //解析获取userid + Claims claims = null; + try { + claims = JwtUtil.parseJWT(token); + } catch (Exception e) { + e.printStackTrace(); + //token超时 token非法 + //响应告诉前端需要重新登录 + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + WebUtils.renderString(response, JSON.toJSONString(result)); + return; + } + String userId = claims.getSubject(); + //从redis中获取用户信息 + LoginUser loginUser = redisCache.getCacheObject("login:" + userId); + //如果获取不到 + if(Objects.isNull(loginUser)){ + //说明登录过期 提示重新登录 + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + WebUtils.renderString(response, JSON.toJSONString(result)); + return; + } + //存入SecurityContextHolder + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,null); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + + filterChain.doFilter(request, response); + } + + +} + +~~~~ + + + +### 5.1 后台登录 + +​ 后台的认证授权也使用SpringSecurity安全框架来实现。 + +#### 5.1.0 需求 + +​ 需要实现登录功能 + +​ 后台所有功能都必须登录才能使用。 + +#### 5.1.1 接口设计 + +| 请求方式 | 请求路径 | +| -------- | ----------- | +| POST | /user/login | + +请求体: + +~~~~json +{ + "userName":"sg", + "password":"1234" +} +~~~~ + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0ODBmOThmYmJkNmI0NjM0OWUyZjY2NTM0NGNjZWY2NSIsInN1YiI6IjEiLCJpc3MiOiJzZyIsImlhdCI6MTY0Mzg3NDMxNiwiZXhwIjoxNjQzOTYwNzE2fQ.ldLBUvNIxQCGemkCoMgT_0YsjsWndTg5tqfJb77pabk" + }, + "msg": "操作成功" +} +~~~~ + +#### 5.1.2 思路分析 + +登录 + +​ ①自定义登录接口 + +​ 调用ProviderManager的方法进行认证 如果认证通过生成jwt + +​ 把用户信息存入redis中 + +​ ②自定义UserDetailsService + +​ 在这个实现类中去查询数据库 + +​ 注意配置passwordEncoder为BCryptPasswordEncoder + +校验: + +​ ①定义Jwt认证过滤器 + +​ 获取token + +​ 解析token获取其中的userid + +​ 从redis中获取用户信息 + +​ 存入SecurityContextHolder + +#### 5.1.3 准备工作 + +①添加依赖 + +前面已经添加过相关依赖,不需要做什么处理 + +~~~~xml + + + org.springframework.boot + spring-boot-starter-data-redis + + + + com.alibaba + fastjson + 1.2.33 + + + + io.jsonwebtoken + jjwt + 0.9.0 + +~~~~ + + + + + +#### 5.1.4 登录接口代码实现 + +##### LoginController + +复制一份BlogLoginController ,命名为LoginController,其中注入 LoginService + +请求地址修改为/user/login即可 + + + +~~~~java +@RestController +public class LoginController { + @Autowired + private LoginService loginService; + + @PostMapping("/user/login") + public ResponseResult login(@RequestBody User user){ + if(!StringUtils.hasText(user.getUserName())){ + //提示 必须要传用户名 + throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME); + } + return loginService.login(user); + } + +} +~~~~ + + + +##### LoginService + +复制一份BlogLoginService命名为LoginService即可 + +~~~~java +public interface LoginService { + ResponseResult login(User user); + +} + +~~~~ + + + +##### SecurityConfig + +之前已经复制过了 + + + + + +##### SystemLoginServiceImpl + +复制一份,LoginServiceImpl,命名为SystemLoginServiceImpl 实现 LoginService + +login方法中存redis的key的前缀修改为login + +返回的数据中只要返回token + + + +~~~~java +@Service +public class SystemLoginServiceImpl implements LoginService { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private RedisCache redisCache; + + @Override + public ResponseResult login(User user) { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword()); + Authentication authenticate = authenticationManager.authenticate(authenticationToken); + //判断是否认证通过 + if(Objects.isNull(authenticate)){ + throw new RuntimeException("用户名或密码错误"); + } + //获取userid 生成token + LoginUser loginUser = (LoginUser) authenticate.getPrincipal(); + String userId = loginUser.getUser().getId().toString(); + String jwt = JwtUtil.createJWT(userId); + //把用户信息存入redis + redisCache.setCacheObject("login:"+userId,loginUser); + + //把token封装 返回 + Map map = new HashMap<>(); + map.put("token",jwt); + return ResponseResult.okResult(map); + } +} +~~~~ + + + +##### UserDetailServiceImpl + +复用原来的即可 + +##### LoginUser + +复用原来的即可 + + + + + +### 5.2 后台权限控制及动态路由 + +#### 需求 + +​ 后台系统需要能实现不同的用户权限可以看到不同的功能。 + +​ 用户只能使用他的权限所允许使用的功能。 + + + +#### 功能设计 + +​ 之前在我的SpringSecurity的课程中就介绍过RBAC权限模型。没有学习过的可以去看下 [RBAC权限模型](https://www.bilibili.com/video/BV1mm4y1X7Hc?p=28) 。这里我们就是在RBAC权限模型的基础上去实现这个功能。 + +​ + +#### 表分析 + +​ 通过需求去分析需要有哪些字段。 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sg_menu.sql + + + +#### 接口设计 + +##### getInfo接口 + +是 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | --------------- | +| GET | /getInfo | 需要token请求头 | + +请求参数: + +无 + +响应格式: + +如果用户id为1代表管理员,roles 中只需要有admin,permissions中需要有所有菜单类型为C或者F的,状态为正常的,未被删除的权限 + +~~~~json +{ + "code":200, + "data":{ + "permissions":[ + "system:user:list", + "system:role:list", + "system:menu:list", + "system:user:query", + "system:user:add" + //此次省略1000字 + ], + "roles":[ + "admin" + ], + "user":{ + "avatar":"http://r7yxkqloa.bkt.clouddn.com/2022/03/05/75fd15587811443a9a9a771f24da458d.png", + "email":"23412332@qq.com", + "id":1, + "nickName":"sg3334", + "sex":"1" + } + }, + "msg":"操作成功" +} +~~~~ + + + +##### getRouters接口 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------- | --------------- | +| GET | /getRouters | 需要token请求头 | + +请求参数: + +无 + +响应格式: + +​ 前端为了实现动态路由的效果,需要后端有接口能返回用户所能访问的菜单数据。 + +​ 注意:**返回的菜单数据需要体现父子菜单的层级关系** + +​ 如果用户id为1代表管理员,menus中需要有所有菜单类型为C或者M的,状态为正常的,未被删除的权限 + +​ 数据格式如下: + +~~~~json +{ + "code":200, + "data":{ + "menus":[ + { + "children":[], + "component":"content/article/write/index", + "createTime":"2022-01-08 11:39:58", + "icon":"build", + "id":2023, + "menuName":"写博文", + "menuType":"C", + "orderNum":"0", + "parentId":0, + "path":"write", + "perms":"content:article:writer", + "status":"0", + "visible":"0" + }, + { + "children":[ + { + "children":[], + "component":"system/user/index", + "createTime":"2021-11-12 18:46:19", + "icon":"user", + "id":100, + "menuName":"用户管理", + "menuType":"C", + "orderNum":"1", + "parentId":1, + "path":"user", + "perms":"system:user:list", + "status":"0", + "visible":"0" + }, + { + "children":[], + "component":"system/role/index", + "createTime":"2021-11-12 18:46:19", + "icon":"peoples", + "id":101, + "menuName":"角色管理", + "menuType":"C", + "orderNum":"2", + "parentId":1, + "path":"role", + "perms":"system:role:list", + "status":"0", + "visible":"0" + }, + { + "children":[], + "component":"system/menu/index", + "createTime":"2021-11-12 18:46:19", + "icon":"tree-table", + "id":102, + "menuName":"菜单管理", + "menuType":"C", + "orderNum":"3", + "parentId":1, + "path":"menu", + "perms":"system:menu:list", + "status":"0", + "visible":"0" + } + ], + "createTime":"2021-11-12 18:46:19", + "icon":"system", + "id":1, + "menuName":"系统管理", + "menuType":"M", + "orderNum":"1", + "parentId":0, + "path":"system", + "perms":"", + "status":"0", + "visible":"0" + } + ] + }, + "msg":"操作成功" +} +~~~~ + + + +#### 代码实现 + +##### 准备工作 + +​ 生成menu和role表对于的类 + +##### getInfo接口 + + + +```java +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +public class AdminUserInfoVo { + + private List permissions; + + private List roles; + + private UserInfoVo user; +} +``` + + + +~~~~java +@RestController +public class LoginController { + @Autowired + private LoginService loginService; + + @Autowired + private MenuService menuService; + + @Autowired + private RoleService roleService; + + @PostMapping("/user/login") + public ResponseResult login(@RequestBody User user){ + if(!StringUtils.hasText(user.getUserName())){ + //提示 必须要传用户名 + throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME); + } + return loginService.login(user); + } + + @GetMapping("getInfo") + public ResponseResult getInfo(){ + //获取当前登录的用户 + LoginUser loginUser = SecurityUtils.getLoginUser(); + //根据用户id查询权限信息 + List perms = menuService.selectPermsByUserId(loginUser.getUser().getId()); + //根据用户id查询角色信息 + List roleKeyList = roleService.selectRoleKeyByUserId(loginUser.getUser().getId()); + + //获取用户信息 + User user = loginUser.getUser(); + UserInfoVo userInfoVo = BeanCopyUtils.copyBean(user, UserInfoVo.class); + //封装数据返回 + + AdminUserInfoVo adminUserInfoVo = new AdminUserInfoVo(perms,roleKeyList,userInfoVo); + return ResponseResult.okResult(adminUserInfoVo); + } + +} +~~~~ + + + + + +RoleServiceImpl selectRoleKeyByUserId方法 + +~~~~java +@Service("menuService") +public class MenuServiceImpl extends ServiceImpl implements MenuService { + + @Override + public List selectPermsByUserId(Long id) { + //如果是管理员,返回所有的权限 + if(id == 1L){ + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(Menu::getMenuType,SystemConstants.MENU,SystemConstants.BUTTON); + wrapper.eq(Menu::getStatus,SystemConstants.STATUS_NORMAL); + List menus = list(wrapper); + List perms = menus.stream() + .map(Menu::getPerms) + .collect(Collectors.toList()); + return perms; + } + //否则返回所具有的权限 + return getBaseMapper().selectPermsByUserId(id); + } +} +~~~~ + +MenuMapper + +~~~~java +/** + * 菜单权限表(Menu)表数据库访问层 + * + * @author makejava + * @since 2022-08-09 22:32:07 + */ +public interface MenuMapper extends BaseMapper { + + List selectPermsByUserId(Long userId); +} + +~~~~ + +~~~~xml + + + + + + +~~~~ + + + + + +MenuServiceImpl selectPermsByUserId方法 + +~~~~java +@Service("roleService") +public class RoleServiceImpl extends ServiceImpl implements RoleService { + + @Override + public List selectRoleKeyByUserId(Long id) { + //判断是否是管理员 如果是返回集合中只需要有admin + if(id == 1L){ + List roleKeys = new ArrayList<>(); + roleKeys.add("admin"); + return roleKeys; + } + //否则查询用户所具有的角色信息 + return getBaseMapper().selectRoleKeyByUserId(id); + } +} +~~~~ + +~~~~java +public interface RoleMapper extends BaseMapper { + + List selectRoleKeyByUserId(Long userId); +} + +~~~~ + +~~~~xml + + + + + +~~~~ + + + + + +##### getRouters接口 + +RoutersVo + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RoutersVo { + + private List menus; +} + +~~~~ + + + +LoginController + +~~~~java + @GetMapping("getRouters") + public ResponseResult getRouters(){ + Long userId = SecurityUtils.getUserId(); + //查询menu 结果是tree的形式 + List menus = menuService.selectRouterMenuTreeByUserId(userId); + //封装数据返回 + return ResponseResult.okResult(new RoutersVo(menus)); + } + +~~~~ + +MenuService + +~~~~java +public interface MenuService extends IService { + + List selectPermsByUserId(Long id); + + List selectRouterMenuTreeByUserId(Long userId); +} + +~~~~ + +MenuServiceImpl + +~~~~java +@Override + public List selectRouterMenuTreeByUserId(Long userId) { + MenuMapper menuMapper = getBaseMapper(); + List menus = null; + //判断是否是管理员 + if(SecurityUtils.isAdmin()){ + //如果是 获取所有符合要求的Menu + menus = menuMapper.selectAllRouterMenu(); + }else{ + //否则 获取当前用户所具有的Menu + menus = menuMapper.selectRouterMenuTreeByUserId(userId); + } + + //构建tree + //先找出第一层的菜单 然后去找他们的子菜单设置到children属性中 + List menuTree = builderMenuTree(menus,0L); + return menuTree; + } + + private List builderMenuTree(List menus, Long parentId) { + List menuTree = menus.stream() + .filter(menu -> menu.getParentId().equals(parentId)) + .map(menu -> menu.setChildren(getChildren(menu, menus))) + .collect(Collectors.toList()); + return menuTree; + } + + /** + * 获取存入参数的 子Menu集合 + * @param menu + * @param menus + * @return + */ + private List getChildren(Menu menu, List menus) { + List childrenList = menus.stream() + .filter(m -> m.getParentId().equals(menu.getId())) + .map(m->m.setChildren(getChildren(m,menus))) + .collect(Collectors.toList()); + return childrenList; + } +~~~~ + +MenuMapper.java + +~~~~java + List selectAllRouterMenu(); + + List selectRouterMenuTreeByUserId(Long userId); +~~~~ + + + +MenuMapper.xml + +~~~~xml + + +~~~~ + + + +查询的列: + +SELECT DISTINCT m.id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status, IFNULL(m.perms,'') AS perms, m.is_frame, m.menu_type, m.icon, m.order_num, m.create_time + +注意需要按照parent_id和order_num排序 + + + + + +### 5.3 退出登录接口 + +#### 5.3.1 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------ | --------------- | +| POST | /user/logout | 需要token请求头 | + +响应格式: + +~~~~json +{ + "code": 200, + "msg": "操作成功" +} +~~~~ + + + +#### 5.3.2 代码实现 + +要实现的操作: + +​ 删除redis中的用户信息 + +LoginController + +~~~~java + @PostMapping("/user/logout") + public ResponseResult logout(){ + return loginServcie.logout(); + } +~~~~ + +LoginService + +~~~~java +ResponseResult logout(); +~~~~ + +SystemLoginServiceImpl + +~~~~java + @Override + public ResponseResult logout() { + //获取当前登录的用户id + Long userId = SecurityUtils.getUserId(); + //删除redis中对应的值 + redisCache.deleteObject("login:"+userId); + return ResponseResult.okResult(); + } +~~~~ + +SecurityConfig + +要关闭默认的退出登录功能。并且要配置我们的退出登录接口需要认证才能访问 + +~~~~java + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/user/login").anonymous() +// //注销接口需要认证才能访问 +// .antMatchers("/logout").authenticated() +// .antMatchers("/user/userInfo").authenticated() +// .antMatchers("/upload").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().authenticated(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + //关闭默认的注销功能 + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } +~~~~ + + + + + + + + + + + +### 5.4 查询标签列表 + +#### 5.4.0 需求 + +​ 为了方便后期对文章进行管理,需要提供标签的功能,一个文章可以有多个标签。 + +​ 在后台需要分页查询标签功能,要求能根据标签名进行分页查询。 **后期可能会增加备注查询等需求**。 + +​ 注意:不能把删除了的标签查询出来。 + +#### 5.4.1 标签表分析 + +​ 通过需求去分析需要有哪些字段。 + +#### 5.4.2 接口设计 + + + +| 请求方式 | 请求路径 | +| -------- | ---------------- | +| Get | content/tag/list | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +name:标签名 + +remark:备注 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "id":4, + "name":"Java", + "remark":"sdad" + } + ], + "total":1 + }, + "msg":"操作成功" +} +~~~~ + + + +#### 5.4.3 代码实现 + +Controller + +~~~~java +@RestController +@RequestMapping("/content/tag") +public class TagController { + @Autowired + private TagService tagService; + + @GetMapping("/list") + public ResponseResult list(Integer pageNum, Integer pageSize, TagListDto tagListDto){ + return tagService.pageTagList(pageNum,pageSize,tagListDto); + } +} + + +~~~~ + + + +Service + +```java +public interface TagService extends IService { + + ResponseResult pageTagList(Integer pageNum, Integer pageSize, TagListDto tagListDto); +} + +``` + +~~~~java +@Service("tagService") +public class TagServiceImpl extends ServiceImpl implements TagService { + + @Override + public ResponseResult pageTagList(Integer pageNum, Integer pageSize, TagListDto tagListDto) { + //分页查询 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(StringUtils.hasText(tagListDto.getName()),Tag::getName,tagListDto.getName()); + queryWrapper.eq(StringUtils.hasText(tagListDto.getRemark()),Tag::getRemark,tagListDto.getRemark()); + + Page page = new Page<>(); + page.setCurrent(pageNum); + page.setSize(pageSize); + page(page, queryWrapper); + //封装数据返回 + PageVo pageVo = new PageVo(page.getRecords(),page.getTotal()); + return ResponseResult.okResult(pageVo); + } +} +~~~~ + + + +### 5.5 新增标签 + +#### 5.5.0 需求 + +​ 点击标签管理的新增按钮可以实现新增标签的功能。 + +#### 5.5.1 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------ | --------------- | +| POST | /content/tag | 需要token请求头 | + +请求体格式: + +~~~~json +{"name":"c#","remark":"c++++"} +~~~~ + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 5.5.2 测试 + +测试时注意,添加到数据库中的记录有没有 创建时间,更新时间,创建人,更新人字段。 + + + + + +### 5.6 删除标签 + +#### 5.6.1 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------------- | --------------- | +| DELETE | /content/tag/{id} | 需要token请求头 | + +请求参数在path中 + +例如:content/tag/6 代表删除id为6的标签数据 + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 5.6.2 测试 + +注意测试删除后在列表中是否查看不到该条数据 + +数据库中该条数据还是存在的,只是修改了逻辑删除字段的值 + + + + + +### 5.7 修改标签 + +#### 5.7.1 接口设计 + +##### 5.7.1.1 获取标签信息 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------------- | --------------- | +| GET | /content/tag/{id} | 需要token请求头 | + +请求参数在path中 + +例如:content/tag/6 代表获取id为6的标签数据 + + + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "id":4, + "name":"Java", + "remark":"sdad" + }, + "msg":"操作成功" +} +~~~~ + + + +##### 5.7.1.2 修改标签接口 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------ | --------------- | +| PUT | /content/tag | 需要token请求头 | + +请求体格式: + +~~~~json +{"id":7,"name":"c#","remark":"c++++"} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.8 写博文 + +#### 5.8.1 需求 + +​ 需要提供写博文的功能,写博文时需要关联分类和标签。 + +​ 可以上传缩略图,也可以在正文中添加图片。 + +​ 文章可以直接发布,也可以保存到草稿箱。 + + + +#### 5.8.2 表分析 + +​ 标签和文章需要关联所以需要一张关联表。 + +​ SQL脚本:SGBlog\资源\SQL\sg_article_tag.sql + + + +#### 5.8.2 接口设计 + +​ 思考下需要哪些接口才能实现这个功能? + + + +##### 5.8.2.1 查询所有分类接口 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | --------------------------------- | --------------- | +| GET | /content/category/listAllCategory | 需要token请求头 | + +请求参数: + +​ 无 + + + + + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "description":"wsd", + "id":1, + "name":"java" + }, + { + "description":"wsd", + "id":2, + "name":"PHP" + } + ], + "msg":"操作成功" +} +~~~~ + + + +##### 5.8.2.2 查询所有标签接口 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------------------- | --------------- | +| GET | /content/tag/listAllTag | 需要token请求头 | + +请求参数: + +​ 无 + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "id":1, + "name":"Mybatis" + }, + { + "id":4, + "name":"Java" + } + ], + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.8.2.3 上传图片 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | --------------- | +| POST | /upload | 需要token请求头 | + +参数: + +​ img,值为要上传的文件 + +请求头: + +​ Content-Type :multipart/form-data; + + + +响应格式: + +~~~~json +{ + "code": 200, + "data": "文件访问链接", + "msg": "操作成功" +} +~~~~ + + + +##### 5.8.2.4 新增博文 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ---------------- | --------------- | +| POST | /content/article | 需要token请求头 | + +请求体格式: + +~~~~json +{ + "title":"测试新增博文", + "thumbnail":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/21/4ceebc07e7484beba732f12b0d2c43a9.png", + "isTop":"0", + "isComment":"0", + "content":"# 一级标题\n## 二级标题\n![Snipaste_20220228_224837.png](https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/21/c3af554d4a0f4935b4073533a4c26ee8.png)\n正文", + "tags":[ + 1, + 4 + ], + "categoryId":1, + "summary":"哈哈", + "status":"1" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 5.8.3 代码实现 + + + +##### 5.8.3.1 查询所有分类接口 + +CategoryController + + + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@RestController +@RequestMapping("/content/category") +public class CategoryController { + @Autowired + private CategoryService categoryService; + + @GetMapping("/listAllCategory") + public ResponseResult listAllCategory(){ + List list = categoryService.listAllCategory(); + return ResponseResult.okResult(list); + } + + +} + +~~~~ + + + +CategoryVo修改,增加description属性 + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CategoryVo { + + private Long id; + private String name; + //描述 + private String description; +} +~~~~ + +CategoryService增加listAllCategory方法 + +~~~~java +public interface CategoryService extends IService { + + + ResponseResult getCategoryList(); + + List listAllCategory(); +} + +~~~~ + +SystemConstants中增加常量 + +~~~~java + /** 正常状态 */ + public static final String NORMAL = "0"; +~~~~ + + + + + +CategoryServiceImpl增加方法 + +~~~~java + @Override + public List listAllCategory() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Category::getStatus, SystemConstants.NORMAL); + List list = list(wrapper); + List categoryVos = BeanCopyUtils.copyBeanList(list, CategoryVo.class); + return categoryVos; + } +~~~~ + + + + + +##### 5.8.3.2 查询所有标签接口 + +TagVo + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TagVo { + private Long id; + + //标签名 + private String name; + + + +} + +~~~~ + + + +TagController + +~~~~java + @GetMapping("/listAllTag") + public ResponseResult listAllTag(){ + List list = tagService.listAllTag(); + return ResponseResult.okResult(list); + } +~~~~ + + + +TagService 增加listAllTag方法 + +~~~~java +List listAllTag(); + +~~~~ + +TagServiceImpl + +~~~~java + @Override + public List listAllTag() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.select(Tag::getId,Tag::getName); + List list = list(wrapper); + List tagVos = BeanCopyUtils.copyBeanList(list, TagVo.class); + return tagVos; + } +~~~~ + + + + + +##### 5.8.3.3 上传图片接口 + +在sangeng-admin中增加UploadController + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@RestController +public class UploadController { + + @Autowired + private UploadService uploadService; + + @PostMapping("/upload") + public ResponseResult uploadImg(@RequestParam("img") MultipartFile multipartFile) { + try { + return uploadService.uploadImg(multipartFile); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException("文件上传上传失败"); + } + } +} +~~~~ + + + + + + + +##### 5.8.3.4 新增博文接口 + + + +ArticleController + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@RestController +@RequestMapping("/content/article") +public class ArticleController { + + @Autowired + private ArticleService articleService; + + @PostMapping + public ResponseResult add(@RequestBody AddArticleDto article){ + return articleService.add(article); + } + + +} + +~~~~ + + + +AddArticleDto + +注意增加tags属性用于接收文章关联标签的id + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AddArticleDto { + + private Long id; + //标题 + private String title; + //文章内容 + private String content; + //文章摘要 + private String summary; + //所属分类id + private Long categoryId; + + //缩略图 + private String thumbnail; + //是否置顶(0否,1是) + private String isTop; + //状态(0已发布,1草稿) + private String status; + //访问量 + private Long viewCount; + //是否允许评论 1是,0否 + private String isComment; + private List tags; + +} + +~~~~ + + + + + + + +Article 修改这样创建时间创建人修改时间修改人可以自动填充 + +~~~~java + @TableField(fill = FieldFill.INSERT) + private Long createBy; + @TableField(fill = FieldFill.INSERT) + private Date createTime; + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; +~~~~ + + + + + +ArticleService增加方法 + +~~~~java +ResponseResult add(AddArticleDto article); +~~~~ + + + +创建ArticleTag表相关的实体类,mapper,service,serviceimpl等 + +```java +@TableName(value="sg_article_tag") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ArticleTag implements Serializable { + private static final long serialVersionUID = 625337492348897098L; + + /** + * 文章id + */ + private Long articleId; + /** + * 标签id + */ + private Long tagId; + + + +} +``` + + + + + +ArticleServiceImpl增加如下代码 + +~~~~java + @Autowired + private ArticleTagService articleTagService; + + @Override + @Transactional + public ResponseResult add(AddArticleDto articleDto) { + //添加 博客 + Article article = BeanCopyUtils.copyBean(articleDto, Article.class); + save(article); + + + List articleTags = articleDto.getTags().stream() + .map(tagId -> new ArticleTag(article.getId(), tagId)) + .collect(Collectors.toList()); + + //添加 博客和标签的关联 + articleTagService.saveBatch(articleTags); + return ResponseResult.okResult(); + } +~~~~ + + + + + + + +### 5.9 导出所有分类到Excel + +#### 5.9.1 需求 + + + +​ 在分类管理中点击导出按钮可以把所有的分类导出到Excel文件中。 + +​ + +#### 5.9.2 技术方案 + +​ 使用EasyExcel实现Excel的导出操作。 + +​ https://github.com/alibaba/easyexcel + +​ https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write#%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81-1 + +#### 5.9.3 接口设计 + +​ + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------------------ | --------------- | +| GET | /content/category/export | 需要token请求头 | + +请求参数: + +​ 无 + + + + + +响应格式: + +成功的话可以直接导出一个Excel文件 + + + +失败的话响应格式如下: + +~~~~json +{ + "code":500, + "msg":"出现错误" +} +~~~~ + + + +#### 5.9.4 代码实现 + +工具类方法修改 + +WebUtils + +~~~~java + public static void setDownLoadHeader(String filename, HttpServletResponse response) throws UnsupportedEncodingException { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fname= URLEncoder.encode(filename,"UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition","attachment; filename="+fname); + } +~~~~ + + + +CategoryController + +~~~~java + @GetMapping("/export") + public void export(HttpServletResponse response){ + try { + //设置下载文件的请求头 + WebUtils.setDownLoadHeader("分类.xlsx",response); + //获取需要导出的数据 + List categoryVos = categoryService.list(); + + List excelCategoryVos = BeanCopyUtils.copyBeanList(categoryVos, ExcelCategoryVo.class); + //把数据写入到Excel中 + EasyExcel.write(response.getOutputStream(), ExcelCategoryVo.class).autoCloseStream(Boolean.FALSE).sheet("分类导出") + .doWrite(excelCategoryVos); + + } catch (Exception e) { + //如果出现异常也要响应json + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR); + WebUtils.renderString(response, JSON.toJSONString(result)); + } + } +~~~~ + + + + + +ExcelCategoryVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ExcelCategoryVo { + @ExcelProperty("分类名") + private String name; + //描述 + @ExcelProperty("描述") + private String description; + + //状态0:正常,1禁用 + @ExcelProperty("状态0:正常,1禁用") + private String status; +} + +~~~~ + + + +### 5.10 权限控制 + +#### 5.10.1 需求 + +​ 需要对导出分类的接口做权限控制。 + +sg eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJkZGJkNjM5MWJiZTA0NmMzOTc4NDg1ZTcxNWQ3YjQ0MSIsInN1YiI6IjEiLCJpc3MiOiJzZyIsImlhdCI6MTY2MjI0NDE4NywiZXhwIjoxNjYyMzMwNTg3fQ.z4JGwFN3lWyVbOCbhikCe-O4D6SvCQFEE5eQY3jDJkw + +sangeng + +eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0Y2I1ZjhmMTc0Mjk0NzM0YjI4Y2M1NTQzYjQ2Yjc1YyIsInN1YiI6IjYiLCJpc3MiOiJzZyIsImlhdCI6MTY2MjI0NDQzMywiZXhwIjoxNjYyMzMwODMzfQ.yEkbyGYXBp5ndnyq-3acdgpvqx2mnI8B9fK9f3Y6Jco + +#### 5.10.2 代码实现 + + + +SecurityConfig + +~~~~java +@EnableGlobalMethodSecurity(prePostEnabled = true) +~~~~ + + + + + +UserDetailsServiceImpl + +~~~~java +@Service +public class UserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private UserMapper userMapper; + + @Autowired + private MenuMapper menuMapper; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + //根据用户名查询用户信息 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(User::getUserName,username); + User user = userMapper.selectOne(queryWrapper); + //判断是否查到用户 如果没查到抛出异常 + if(Objects.isNull(user)){ + throw new RuntimeException("用户不存在"); + } + //返回用户信息 + if(user.getType().equals(SystemConstants.ADMAIN)){ + List list = menuMapper.selectPermsByUserId(user.getId()); + return new LoginUser(user,list); + } + return new LoginUser(user,null); + } +} + +~~~~ + + + +LoginUser + +增加属性 + +~~~~java +private List permissions; +~~~~ + + + + + +PermissionService + +hasPermisson + +~~~~java + +@Service("ps") +public class PermissionService { + + /** + * 判断当前用户是否具有permission + * @param permission 要判断的权限 + * @return + */ + public boolean hasPermission(String permission){ + //如果是超级管理员 直接返回true + if(SecurityUtils.isAdmin()){ + return true; + } + //否则 获取当前登录用户所具有的权限列表 如何判断是否存在permission + List permissions = SecurityUtils.getLoginUser().getPermissions(); + return permissions.contains(permission); + } +} +~~~~ + + + +CategoryController + +~~~~java + + @PreAuthorize("@ps.hasPermission('content:category:export')") + @GetMapping("/export") + public void export(HttpServletResponse response){ + try { + //设置下载文件的请求头 + WebUtils.setDownLoadHeader("分类.xlsx",response); + //获取需要导出的数据 + List categoryVos = categoryService.list(); + + List excelCategoryVos = BeanCopyUtils.copyBeanList(categoryVos, ExcelCategoryVo.class); + //把数据写入到Excel中 + EasyExcel.write(response.getOutputStream(), ExcelCategoryVo.class).autoCloseStream(Boolean.FALSE).sheet("分类导出") + .doWrite(excelCategoryVos); + + } catch (Exception e) { + //如果出现异常也要响应json + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR); + WebUtils.renderString(response, JSON.toJSONString(result)); + } + } +~~~~ + + + + + +### 5.11 文章列表 + +#### 5.10.1 需求 + +​ 为了对文章进行管理,需要提供文章列表, + +​ 在后台需要分页查询文章功能,要求能根据标题和摘要**模糊查询**。 + +​ 注意:不能把删除了的文章查询出来 + + + +#### 5.10.2 接口设计 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------------- | --------------- | +| Get | /content/article/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +title:文章标题 + +summary:文章摘要 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "categoryId":"1", + "content":"嘻嘻嘻嘻嘻嘻", + "createTime":"2022-01-24 07:20:11", + "id":"1", + "isComment":"0", + "isTop":"1", + "status":"0", + "summary":"SpringSecurity框架教程-Spring Security+JWT实现项目级前端分离认证授权", + "thumbnail":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/31/948597e164614902ab1662ba8452e106.png", + "title":"SpringSecurity从入门到精通", + "viewCount":"161" + } + ], + "total":"1" + }, + "msg":"操作成功" +} +~~~~ + + + +​ + +### 5.12 修改文章 + +#### 5.12.1 需求 + +​ 点击文章列表中的修改按钮可以跳转到写博文页面。回显示该文章的具体信息。 + +​ 用户可以在该页面修改文章信息。点击更新按钮后修改文章。 + + + + + +#### 5.12.2 分析 + +​ 这个功能的实现首先需要能够根据文章id查询文章的详细信息这样才能实现文章的回显。 + +​ 如何需要提供更新文章的接口。 + + + +#### 5.12.3 接口设计 + +##### 5.12.3.1 查询文章详情接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | -------------------- | --------------- | +| Get | content/article/{id} | 是 | + +Path格式请求参数: + +id: 文章id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "categoryId":"1", + "content":"xxxxxxx", + "createBy":"1", + "createTime":"2022-08-28 15:15:46", + "delFlag":0, + "id":"10", + "isComment":"0", + "isTop":"1", + "status":"0", + "summary":"啊实打实", + "tags":[ + "1", + "4", + "5" + ], + "thumbnail":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/28/7659aac2b74247fe8ebd9e054b916dbf.png", + "title":"委屈饿驱蚊器", + "updateBy":"1", + "updateTime":"2022-08-28 15:15:46", + "viewCount":"0" + }, + "msg":"操作成功" +} +~~~~ + + + +##### 5.12.3.2 更新文章接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------- | --------------- | +| PUT | content/article | 是 | + +请求体参数格式: + +~~~~json +{ + "categoryId":"1", + "content":"![Snipaste_20220228_224837.png](https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/28/f3938a0368c540ee909ba7f7079a829a.png)\n\n# 十大\n## 时代的", + "createBy":"1", + "createTime":"2022-08-28 15:15:46", + "delFlag":0, + "id":"10", + "isComment":"0", + "isTop":"1", + "status":"0", + "summary":"啊实打实2", + "tags":[ + "1", + "4", + "5" + ], + "thumbnail":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/28/7659aac2b74247fe8ebd9e054b916dbf.png", + "title":"委屈饿驱蚊器", + "updateBy":"1", + "updateTime":"2022-08-28 15:15:46", + "viewCount":"0" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.13 删除文章 + +#### 5.13.1 需求 + +​ 点击文章后面的删除按钮可以删除该文章 + +​ 注意:是逻辑删除不是物理删除 + +#### 5.13.2 接口设计 + +​ + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | -------------------- | --------------- | +| DELETE | content/article/{id} | 是 | + +Path请求参数: + +id:要删除的文章id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + + + +### 5.14 菜单列表 + +#### 5.14.1 需求 + +​ 需要展示菜单列表,不需要分页。 + +​ 可以针对菜单名进行模糊查询 + +​ 也可以针对菜单的状态进行查询。 + +​ 菜单要按照父菜单id和orderNum进行排序 + +#### 5.14.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| GET | system/menu/list | 是 | + +Query请求参数: + +status : 状态 + +menuName: 菜单名 + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "component":"content/article/write/index", + "icon":"build", + "id":"2023", + "isFrame":1, + "menuName":"写博文", + "menuType":"C", + "orderNum":0, + "parentId":"0", + "path":"write", + "perms":"content:article:writer", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"system", + "id":"1", + "isFrame":1, + "menuName":"系统管理", + "menuType":"M", + "orderNum":1, + "parentId":"0", + "path":"system", + "perms":"", + "remark":"系统管理目录", + "status":"0", + "visible":"0" + }, + { + "icon":"table", + "id":"2017", + "isFrame":1, + "menuName":"内容管理", + "menuType":"M", + "orderNum":4, + "parentId":"0", + "path":"content", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"system/user/index", + "icon":"user", + "id":"100", + "isFrame":1, + "menuName":"用户管理", + "menuType":"C", + "orderNum":1, + "parentId":"1", + "path":"user", + "perms":"system:user:list", + "remark":"用户管理菜单", + "status":"0", + "visible":"0" + }, + { + "component":"system/role/index", + "icon":"peoples", + "id":"101", + "isFrame":1, + "menuName":"角色管理", + "menuType":"C", + "orderNum":2, + "parentId":"1", + "path":"role", + "perms":"system:role:list", + "remark":"角色管理菜单", + "status":"0", + "visible":"0" + }, + { + "component":"system/menu/index", + "icon":"tree-table", + "id":"102", + "isFrame":1, + "menuName":"菜单管理", + "menuType":"C", + "orderNum":3, + "parentId":"1", + "path":"menu", + "perms":"system:menu:list", + "remark":"菜单管理菜单", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1001", + "isFrame":1, + "menuName":"用户查询", + "menuType":"F", + "orderNum":1, + "parentId":"100", + "path":"", + "perms":"system:user:query", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1002", + "isFrame":1, + "menuName":"用户新增", + "menuType":"F", + "orderNum":2, + "parentId":"100", + "path":"", + "perms":"system:user:add", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1003", + "isFrame":1, + "menuName":"用户修改", + "menuType":"F", + "orderNum":3, + "parentId":"100", + "path":"", + "perms":"system:user:edit", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1004", + "isFrame":1, + "menuName":"用户删除", + "menuType":"F", + "orderNum":4, + "parentId":"100", + "path":"", + "perms":"system:user:remove", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1005", + "isFrame":1, + "menuName":"用户导出", + "menuType":"F", + "orderNum":5, + "parentId":"100", + "path":"", + "perms":"system:user:export", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1006", + "isFrame":1, + "menuName":"用户导入", + "menuType":"F", + "orderNum":6, + "parentId":"100", + "path":"", + "perms":"system:user:import", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1007", + "isFrame":1, + "menuName":"重置密码", + "menuType":"F", + "orderNum":7, + "parentId":"100", + "path":"", + "perms":"system:user:resetPwd", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1008", + "isFrame":1, + "menuName":"角色查询", + "menuType":"F", + "orderNum":1, + "parentId":"101", + "path":"", + "perms":"system:role:query", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1009", + "isFrame":1, + "menuName":"角色新增", + "menuType":"F", + "orderNum":2, + "parentId":"101", + "path":"", + "perms":"system:role:add", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1010", + "isFrame":1, + "menuName":"角色修改", + "menuType":"F", + "orderNum":3, + "parentId":"101", + "path":"", + "perms":"system:role:edit", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1011", + "isFrame":1, + "menuName":"角色删除", + "menuType":"F", + "orderNum":4, + "parentId":"101", + "path":"", + "perms":"system:role:remove", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1012", + "isFrame":1, + "menuName":"角色导出", + "menuType":"F", + "orderNum":5, + "parentId":"101", + "path":"", + "perms":"system:role:export", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1013", + "isFrame":1, + "menuName":"菜单查询", + "menuType":"F", + "orderNum":1, + "parentId":"102", + "path":"", + "perms":"system:menu:query", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1014", + "isFrame":1, + "menuName":"菜单新增", + "menuType":"F", + "orderNum":2, + "parentId":"102", + "path":"", + "perms":"system:menu:add", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1015", + "isFrame":1, + "menuName":"菜单修改", + "menuType":"F", + "orderNum":3, + "parentId":"102", + "path":"", + "perms":"system:menu:edit", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1016", + "isFrame":1, + "menuName":"菜单删除", + "menuType":"F", + "orderNum":4, + "parentId":"102", + "path":"", + "perms":"system:menu:remove", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"content/article/index", + "icon":"build", + "id":"2019", + "isFrame":1, + "menuName":"文章管理", + "menuType":"C", + "orderNum":0, + "parentId":"2017", + "path":"article", + "perms":"content:article:list", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"content/category/index", + "icon":"example", + "id":"2018", + "isFrame":1, + "menuName":"分类管理", + "menuType":"C", + "orderNum":1, + "parentId":"2017", + "path":"category", + "perms":"content:category:list", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"content/link/index", + "icon":"404", + "id":"2022", + "isFrame":1, + "menuName":"友链管理", + "menuType":"C", + "orderNum":4, + "parentId":"2017", + "path":"link", + "perms":"content:link:list", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"content/tag/index", + "icon":"button", + "id":"2021", + "isFrame":1, + "menuName":"标签管理", + "menuType":"C", + "orderNum":6, + "parentId":"2017", + "path":"tag", + "perms":"content:tag:index", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2028", + "isFrame":1, + "menuName":"导出分类", + "menuType":"F", + "orderNum":1, + "parentId":"2018", + "path":"", + "perms":"content:category:export", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2024", + "isFrame":1, + "menuName":"友链新增", + "menuType":"F", + "orderNum":0, + "parentId":"2022", + "path":"", + "perms":"content:link:add", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2025", + "isFrame":1, + "menuName":"友链修改", + "menuType":"F", + "orderNum":1, + "parentId":"2022", + "path":"", + "perms":"content:link:edit", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2026", + "isFrame":1, + "menuName":"友链删除", + "menuType":"F", + "orderNum":1, + "parentId":"2022", + "path":"", + "perms":"content:link:remove", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2027", + "isFrame":1, + "menuName":"友链查询", + "menuType":"F", + "orderNum":2, + "parentId":"2022", + "path":"", + "perms":"content:link:query", + "remark":"", + "status":"0", + "visible":"0" + } + ], + "msg":"操作成功" +} +~~~~ + + + + + +### 5.15 新增菜单 + +#### 5.15.1 需求 + +​ 可以新增菜单 + +#### 5.15.2 接口设计 + +​ + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------- | --------------- | +| POST | content/article | 是 | + +请求体参数: + +​ Menu类对应的json格式 + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +### 5.16 修改菜单 + +#### 5.16.1 需求 + +​ 能够修改菜单,但是修改的时候不能把父菜单设置为当前菜单,如果设置了需要给出相应的提示。并且修改失败。 + +#### 5.16.2 接口设计 + +##### 5.16.2.1 根据id查询菜单数据 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| Get | system/menu/{id} | 是 | + +Path格式请求参数: + +id: 菜单id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "icon":"table", + "id":"2017", + "menuName":"内容管理", + "menuType":"M", + "orderNum":"4", + "parentId":"0", + "path":"content", + "remark":"", + "status":"0", + "visible":"0" + }, + "msg":"操作成功" +} +~~~~ + + + +##### 5.16.2.2 更新菜单 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------- | --------------- | +| PUT | system/menu | 是 | + +请求体参数: + +​ Menu类对应的json格式 + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + +如果把父菜单设置为当前菜单: + +~~~~java +{ + "code":500, + "msg":"修改菜单'写博文'失败,上级菜单不能选择自己" +} +~~~~ + + + +### 5.17 删除菜单 + +#### 5.17.1 需求 + +​ 能够删除菜单,但是如果要删除的菜单有子菜单则提示:存在子菜单不允许删除 并且删除失败。 + +#### 5.17.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------------ | --------------- | +| DELETE | content/article/{menuId} | 是 | + +Path参数: + +menuId:要删除菜单的id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + +如果要删除的菜单有子菜单则 + +~~~~java +{ + "code":500, + "msg":"存在子菜单不允许删除" +} +~~~~ + + + + + +### 5.18 角色列表 + +#### 5.18.1 需求 + +​ 需要有角色列表分页查询的功能。 + +​ 要求能够针对角色名称进行模糊查询。 + +​ 要求能够针对状态进行查询。 + +​ 要求按照role_sort进行升序排列。 + +#### 5.18.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| GET | system/role/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +roleName:角色名称 + +status:状态 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "id":"12", + "roleKey":"link", + "roleName":"友链审核员", + "roleSort":"1", + "status":"0" + } + ], + "total":"1" + }, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.19 改变角色状态 + +#### 5.19.1 需求 + +​ 要求能够修改角色的停启用状态 + +#### 5.19.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------------ | --------------- | +| PUT | system/role/changeStatus | 是 | + +请求体: + +~~~~json +{"roleId":"11","status":"1"} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.20 新增角色!! + +#### 5.20.1 需求 + +​ 需要提供新增角色的功能。新增角色时能够直接设置角色所关联的菜单权限。 + +#### 5.20.2 接口设计 + +##### 5.20.2.1 获取菜单树接口 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------------- | --------------- | +| GET | /system/menu/treeselect | 是 | + +无需请求参数 + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "children":[], + "id":"2023", + "label":"写博文", + "parentId":"0" + }, + { + "children":[ + { + "children":[ + { + "children":[], + "id":"1001", + "label":"用户查询", + "parentId":"100" + }, + { + "children":[], + "id":"1002", + "label":"用户新增", + "parentId":"100" + }, + { + "children":[], + "id":"1003", + "label":"用户修改", + "parentId":"100" + }, + { + "children":[], + "id":"1004", + "label":"用户删除", + "parentId":"100" + }, + { + "children":[], + "id":"1005", + "label":"用户导出", + "parentId":"100" + }, + { + "children":[], + "id":"1006", + "label":"用户导入", + "parentId":"100" + }, + { + "children":[], + "id":"1007", + "label":"重置密码", + "parentId":"100" + } + ], + "id":"100", + "label":"用户管理", + "parentId":"1" + }, + { + "children":[ + { + "children":[], + "id":"1008", + "label":"角色查询", + "parentId":"101" + }, + { + "children":[], + "id":"1009", + "label":"角色新增", + "parentId":"101" + }, + { + "children":[], + "id":"1010", + "label":"角色修改", + "parentId":"101" + }, + { + "children":[], + "id":"1011", + "label":"角色删除", + "parentId":"101" + }, + { + "children":[], + "id":"1012", + "label":"角色导出", + "parentId":"101" + } + ], + "id":"101", + "label":"角色管理", + "parentId":"1" + }, + { + "children":[ + { + "children":[], + "id":"1013", + "label":"菜单查询", + "parentId":"102" + }, + { + "children":[], + "id":"1014", + "label":"菜单新增", + "parentId":"102" + }, + { + "children":[], + "id":"1015", + "label":"菜单修改", + "parentId":"102" + }, + { + "children":[], + "id":"1016", + "label":"菜单删除", + "parentId":"102" + } + ], + "id":"102", + "label":"菜单管理", + "parentId":"1" + } + ], + "id":"1", + "label":"系统管理", + "parentId":"0" + }, + { + "children":[ + { + "children":[], + "id":"2019", + "label":"文章管理", + "parentId":"2017" + }, + { + "children":[ + { + "children":[], + "id":"2028", + "label":"导出分类", + "parentId":"2018" + } + ], + "id":"2018", + "label":"分类管理", + "parentId":"2017" + }, + { + "children":[ + { + "children":[], + "id":"2024", + "label":"友链新增", + "parentId":"2022" + }, + { + "children":[], + "id":"2025", + "label":"友链修改", + "parentId":"2022" + }, + { + "children":[], + "id":"2026", + "label":"友链删除", + "parentId":"2022" + }, + { + "children":[], + "id":"2027", + "label":"友链查询", + "parentId":"2022" + } + ], + "id":"2022", + "label":"友链管理", + "parentId":"2017" + }, + { + "children":[], + "id":"2021", + "label":"标签管理", + "parentId":"2017" + } + ], + "id":"2017", + "label":"内容管理", + "parentId":"0" + } + ], + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.20.2.2 新增角色接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------- | --------------- | +| POST | system/role | 是 | + +请求体: + +~~~~json +{ + "roleName":"测试新增角色", + "roleKey":"wds", + "roleSort":0, + "status":"0", + "menuIds":[ + "1", + "100" + ], + "remark":"我是角色备注" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + + + +### 5.21 修改角色 + +#### 5.21.1 需求 + +​ 需要提供修改角色的功能。修改角色时可以修改角色所关联的菜单权限 + +#### 5.21.2 接口设计 + +##### 5.21.2.1 角色信息回显接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| Get | system/role/{id} | 是 | + +Path格式请求参数: + +id: 角色id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "id":"11", + "remark":"嘎嘎嘎", + "roleKey":"aggag", + "roleName":"嘎嘎嘎", + "roleSort":"5", + "status":"0" + }, + "msg":"操作成功" +} +~~~~ + +##### 5.21.2.2 加载对应角色菜单列表树接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------------------------ | --------------- | +| Get | /system/menu/roleMenuTreeselect/{id} | 是 | + +Path格式请求参数: + +id: 角色id + +响应格式: + +字段介绍 + +​ menus:菜单树。 + +​ checkedKeys:角色所关联的菜单权限id列表。 + +~~~~json +{ + "code":200, + "data":{ + "menus":[ + { + "children":[], + "id":"2023", + "label":"写博文", + "parentId":"0" + }, + { + "children":[ + { + "children":[ + { + "children":[], + "id":"1001", + "label":"用户查询", + "parentId":"100" + }, + { + "children":[], + "id":"1002", + "label":"用户新增", + "parentId":"100" + }, + { + "children":[], + "id":"1003", + "label":"用户修改", + "parentId":"100" + }, + { + "children":[], + "id":"1004", + "label":"用户删除", + "parentId":"100" + }, + { + "children":[], + "id":"1005", + "label":"用户导出", + "parentId":"100" + }, + { + "children":[], + "id":"1006", + "label":"用户导入", + "parentId":"100" + }, + { + "children":[], + "id":"1007", + "label":"重置密码", + "parentId":"100" + } + ], + "id":"100", + "label":"用户管理", + "parentId":"1" + }, + { + "children":[ + { + "children":[], + "id":"1008", + "label":"角色查询", + "parentId":"101" + }, + { + "children":[], + "id":"1009", + "label":"角色新增", + "parentId":"101" + }, + { + "children":[], + "id":"1010", + "label":"角色修改", + "parentId":"101" + }, + { + "children":[], + "id":"1011", + "label":"角色删除", + "parentId":"101" + }, + { + "children":[], + "id":"1012", + "label":"角色导出", + "parentId":"101" + } + ], + "id":"101", + "label":"角色管理", + "parentId":"1" + }, + { + "children":[ + { + "children":[], + "id":"1013", + "label":"菜单查询", + "parentId":"102" + }, + { + "children":[], + "id":"1014", + "label":"菜单新增", + "parentId":"102" + }, + { + "children":[], + "id":"1015", + "label":"菜单修改", + "parentId":"102" + }, + { + "children":[], + "id":"1016", + "label":"菜单删除", + "parentId":"102" + } + ], + "id":"102", + "label":"菜单管理", + "parentId":"1" + } + ], + "id":"1", + "label":"系统管理", + "parentId":"0" + }, + { + "children":[ + { + "children":[], + "id":"2019", + "label":"文章管理", + "parentId":"2017" + }, + { + "children":[ + { + "children":[], + "id":"2028", + "label":"导出分类", + "parentId":"2018" + } + ], + "id":"2018", + "label":"分类管理", + "parentId":"2017" + }, + { + "children":[ + { + "children":[], + "id":"2024", + "label":"友链新增", + "parentId":"2022" + }, + { + "children":[], + "id":"2025", + "label":"友链修改", + "parentId":"2022" + }, + { + "children":[], + "id":"2026", + "label":"友链删除", + "parentId":"2022" + }, + { + "children":[], + "id":"2027", + "label":"友链查询", + "parentId":"2022" + } + ], + "id":"2022", + "label":"友链管理", + "parentId":"2017" + }, + { + "children":[], + "id":"2021", + "label":"标签管理", + "parentId":"2017" + } + ], + "id":"2017", + "label":"内容管理", + "parentId":"0" + } + ], + "checkedKeys":[ + "1001" + ] + }, + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.21.2.3 更新角色信息接口 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------- | --------------- | +| PUT | system/role | 是 | + +请求体: + +~~~~json +{ + "id":"13", + "remark":"我是角色备注", + "roleKey":"wds", + "roleName":"测试新增角色", + "roleSort":0, + "status":"0", + "menuIds":[ + "1", + "100", + "1001" + ] +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + + + + + +### 5.22 删除角色 + +#### 5.22.1 需求 + +​ 删除固定的某个角色(逻辑删除) + +#### 5.22.2 接口设计 + +​ + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| DELETE | system/role/{id} | 是 | + +Path请求参数: + +id:要删除的角色id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.23 用户列表 + +#### 5.23.1 需求 + +​ 需要用户分页列表接口。 + +​ 可以根据用户名模糊搜索。 + +​ 可以进行手机号的搜索。 + +​ 可以进行状态的查询。 + +#### 5.23.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| GET | system/user/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +userName:用户名 + +phonenumber:手机号 + +status:状态 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "avatar":"http://r7yxkqloa.bkt.clouddn.com/2022/03/05/75fd15587811443a9a9a771f24da458d.png", + "createTime":"2022-01-05 17:01:56", + "email":"23412332@qq.com", + "id":"1", + "nickName":"sg3334", + "phonenumber":"18888888888", + "sex":"1", + "status":"0", + "updateBy":"1", + "updateTime":"2022-03-13 21:36:22", + "userName":"sg" + } + ], + "total":"1" + }, + "msg":"操作成功" +} +~~~~ + + + +### 5.24 新增用户!!! + + + +#### 5.24.1 需求 + +​ 需要新增用户功能。新增用户时可以直接关联角色。 + +​ 注意:新增用户时注意密码加密存储。 + +​ 用户名不能为空,否则提示:必需填写用户名 + +​ 用户名必须之前未存在,否则提示:用户名已存在 + +​ 手机号必须之前未存在,否则提示:手机号已存在 + +​ 邮箱必须之前未存在,否则提示:邮箱已存在 + +#### 5.24.2 接口设计 + +##### 5.24.2.1 查询角色列表接口 + +注意:查询的是所有状态正常的角色 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------------ | --------------- | +| GET | /system/role/listAllRole | 是 | + + + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "createBy":"0", + "createTime":"2021-11-12 18:46:19", + "delFlag":"0", + "id":"1", + "remark":"超级管理员", + "roleKey":"admin", + "roleName":"超级管理员", + "roleSort":"1", + "status":"0", + "updateBy":"0" + }, + { + "createBy":"0", + "createTime":"2021-11-12 18:46:19", + "delFlag":"0", + "id":"2", + "remark":"普通角色", + "roleKey":"common", + "roleName":"普通角色", + "roleSort":"2", + "status":"0", + "updateBy":"0", + "updateTime":"2022-01-02 06:32:58" + }, + { + "createTime":"2022-01-06 22:07:40", + "delFlag":"0", + "id":"11", + "remark":"嘎嘎嘎", + "roleKey":"aggag", + "roleName":"嘎嘎嘎", + "roleSort":"5", + "status":"0", + "updateBy":"1", + "updateTime":"2022-09-12 10:00:25" + }, + { + "createTime":"2022-01-16 14:49:30", + "delFlag":"0", + "id":"12", + "roleKey":"link", + "roleName":"友链审核员", + "roleSort":"1", + "status":"0", + "updateTime":"2022-01-16 16:05:09" + } + ], + "msg":"操作成功" +} +~~~~ + + + + + + + +##### 5.24.2.2 新增用户 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------- | --------------- | +| POST | system/user | 是 | + +请求体: + +~~~~json +{ + "userName":"wqeree", + "nickName":"测试新增用户", + "password":"1234343", + "phonenumber":"18889778907", + "email":"233@sq.com", + "sex":"0", + "status":"0", + "roleIds":[ + "2" + ] +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.25 删除用户 + +#### 5.25.1 需求 + +删除固定的某个用户(逻辑删除) + +#### 5.25.2 接口设计 + +不能删除当前操作的用户 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| DELETE | /system/user/{id} | 是 | + +Path请求参数: + +id:要删除的用户id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.26 修改用户 + +#### 5.26.1 需求 + +需要提供修改用户的功能。修改用户时可以修改用户所关联的角色。 + +#### 5.26.2 接口设计 + +##### 5.26.2.1 根据id查询用户信息回显接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| Get | /system/user/{id} | 是 | + +Path格式请求参数: + +id: 用户id + +响应格式: + +roleIds:用户所关联的角色id列表 + +roles:所有角色的列表 + +user:用户信息 + +~~~~json +{ + "code":200, + "data":{ + "roleIds":[ + "11" + ], + "roles":[ + { + "createBy":"0", + "createTime":"2021-11-12 18:46:19", + "delFlag":"0", + "id":"1", + "remark":"超级管理员", + "roleKey":"admin", + "roleName":"超级管理员", + "roleSort":"1", + "status":"0", + "updateBy":"0" + }, + { + "createBy":"0", + "createTime":"2021-11-12 18:46:19", + "delFlag":"0", + "id":"2", + "remark":"普通角色", + "roleKey":"common", + "roleName":"普通角色", + "roleSort":"2", + "status":"0", + "updateBy":"0", + "updateTime":"2022-01-02 06:32:58" + }, + { + "createTime":"2022-01-06 22:07:40", + "delFlag":"0", + "id":"11", + "remark":"嘎嘎嘎", + "roleKey":"aggag", + "roleName":"嘎嘎嘎", + "roleSort":"5", + "status":"0", + "updateBy":"1", + "updateTime":"2022-09-11 20:34:49" + }, + { + "createTime":"2022-01-16 14:49:30", + "delFlag":"0", + "id":"12", + "roleKey":"link", + "roleName":"友链审核员", + "roleSort":"1", + "status":"0", + "updateTime":"2022-01-16 16:05:09" + } + ], + "user":{ + "email":"weq@2132.com", + "id":"14787164048663", + "nickName":"sg777", + "sex":"0", + "status":"0", + "userName":"sg777" + } + }, + "msg":"操作成功" +} +~~~~ + + + +##### 5.26.2.2 更新用户信息接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------ | --------------- | +| PUT | /system/user | 是 | + +请求体: + +~~~~json +{ + "email":"weq@2132.com", + "id":"14787164048663", + "nickName":"sg777", + "sex":"1", + "status":"0", + "userName":"sg777", + "roleIds":[ + "11" + ] +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +### 5.27 分页查询分类列表 + +#### 5.27.1 需求 + +​ 需要分页查询分类列表。 + +​ 能根据分类名称进行模糊查询。 + +​ 能根据状态进行查询。 + +#### 5.27.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------------- | --------------- | +| GET | content/category/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +name:分类名 + +status: 状态 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "description":"wsd", + "id":"1", + "name":"java", + "status":"0" + }, + { + "description":"wsd", + "id":"2", + "name":"PHP", + "status":"0" + } + ], + "total":"2" + }, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.28 新增分类 + +#### 5.28.1 需求 + +​ 需要新增分类功能 + +#### 5.28.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| POST | /content/category | 是 | + +请求体: + +~~~~json +{ + "name":"威威", + "description":"是的", + "status":"0" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.29 修改分类 + +#### 5.29.1 需求 + +​ 需要提供修改分类的功能 + +#### 5.29.2 接口设计 + +##### 5.29.2.1 根据id查询分类 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------------- | --------------- | +| Get | content/category/{id} | 是 | + +Path格式请求参数: + +id: 分类id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "description":"qwew", + "id":"4", + "name":"ww", + "status":"0" + }, + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.29.2.2 更新分类 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| PUT | /content/category | 是 | + +请求体: + +~~~~json +{ + "description":"是的", + "id":"3", + "name":"威威2", + "status":"0" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.30 删除分类 + +#### 5.30.1 需求 + +​ 删除某个分类(逻辑删除) + +#### 5.30.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------------- | --------------- | +| DELETE | /content/category/{id} | 是 | + +Path请求参数: + +id:要删除的分类id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.31 分页查询友链列表 + +#### 5.31.1 需求 + +​ 需要分页查询友链列表。 + +​ 能根据友链名称进行模糊查询。 + +​ 能根据状态进行查询。 + +#### 5.31.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------ | --------------- | +| GET | /content/link/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +name:友链名 + +status:状态 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "address":"https://www.baidu.com", + "description":"sda", + "id":"1", "logo":"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fn1.itc.cn%2Fimg8%2Fwb%2Frecom%2F2016%2F05%2F10%2F146286696706220328.PNG&refer=http%3A%2F%2Fn1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646205529&t=f942665181eb9b0685db7a6f59d59975", + "name":"sda", + "status":"0" + } + ], + "total":"1" + }, + "msg":"操作成功" +} +~~~~ + + + +### 5.32 新增友链 + +#### 5.32.1 需求 + +​ 需要新增友链功能 + +#### 5.32.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------- | --------------- | +| POST | /content/link | 是 | + +请求体: + +~~~~json +{ + "name":"sda", + "description":"weqw", + "address":"wewe", + "logo":"weqe", + "status":"2" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +### 5.33 修改友链 + +#### 5.33.1 需求 + +​ 需要提供修改友链的功能 + +#### 5.33.2 接口设计 + +##### 5.33.2.1 根据id查询友联 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| Get | content/link/{id} | 是 | + +Path格式请求参数: + +id: 友链id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "address":"wewe", + "description":"weqw", + "id":"4", + "logo":"weqe", + "name":"sda", + "status":"2" + }, + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.33.2.2 修改友链 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------- | --------------- | +| PUT | /content/link | 是 | + +请求体: + +~~~~json +{ + "address":"https://www.qq.com", + "description":"dada2", + "id":"2", + "logo":"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fn1.itc.cn%2Fimg8%2Fwb%2Frecom%2F2016%2F05%2F10%2F146286696706220328.PNG&refer=http%3A%2F%2Fn1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646205529&t=f942665181eb9b0685db7a6f59d59975", + "name":"sda", + "status":"0" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +### 5.34 删除友链 + +#### 5.34.1 需求 + +​ 删除某个友链(逻辑删除) + +#### 5.34.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------ | --------------- | +| DELETE | /content/link/{id} | 是 | + +Path请求参数: + +id:要删除的友链id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + diff --git "a/doc/\351\241\271\347\233\256\345\256\236\346\210\230-\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\215\232\345\256\242\347\263\273\347\273\237.md" "b/doc/\351\241\271\347\233\256\345\256\236\346\210\230-\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\215\232\345\256\242\347\263\273\347\273\237.md" new file mode 100644 index 0000000..942374d --- /dev/null +++ "b/doc/\351\241\271\347\233\256\345\256\236\346\210\230-\345\211\215\345\220\216\347\253\257\345\210\206\347\246\273\345\215\232\345\256\242\347\263\273\347\273\237.md" @@ -0,0 +1,8459 @@ +# 项目实战-前后端分离博客系统 + +## 1.课程介绍 + +* 纯后端讲解 +* 完整的前台后台代码编写 +* 主流技术栈(SpringBoot,MybatisPlus,SpringSecurity,EasyExcel,Swagger2,Redis,Echarts,Vue,ElementUI....) +* 完善细致的需求分析 +* 由易到难循序渐进 + + + +## 2.创建工程 + +​ 我们有前台和后台两套系统。两套系统的前端工程都已经提供好了。所以我们只需要写两套系统的后端。 + +​ 但是大家思考下,实际上两套后端系统的很多内容是可能重复的。这里如果我们只是单纯的创建两个后端工程。那么就会有大量的重复代码,并且需要修改的时候也需要修改两次。这就是代码复用性不高。 + +​ 所以我们需要创建多模块项目,两套系统可能都会用到的代码可以写到一个公共模块中,让前台系统和后台系统分别取依赖公共模块。 + + + +① 创建父模块 + +~~~~xml + + + 4.0.0 + + com.sangeng + SGBlog + pom + 1.0-SNAPSHOT + + sangeng-framework + sangeng-admin + sangeng-blog + + + + UTF-8 + 1.8 + + + + + + + + org.springframework.boot + spring-boot-dependencies + 2.5.0 + pom + import + + + + com.alibaba + fastjson + 1.2.33 + + + + io.jsonwebtoken + jjwt + 0.9.0 + + + + com.baomidou + mybatis-plus-boot-starter + 3.4.3 + + + + + com.aliyun.oss + aliyun-sdk-oss + 3.10.2 + + + + + com.alibaba + easyexcel + 3.0.5 + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + + + +~~~~ + + + +②创建公共子模块 sangeng-framework + +~~~~xml + + + + SGBlog + com.sangeng + 1.0-SNAPSHOT + + 4.0.0 + + sangeng-framework + + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + com.alibaba + fastjson + + + + io.jsonwebtoken + jjwt + + + + com.baomidou + mybatis-plus-boot-starter + + + + mysql + mysql-connector-java + + + + + com.aliyun.oss + aliyun-sdk-oss + + + + + org.springframework.boot + spring-boot-starter-aop + + + + com.alibaba + easyexcel + + + io.springfox + springfox-swagger2 + + + io.springfox + springfox-swagger-ui + + + + + +~~~~ + + + +③创建博客后台模块sangeng-admin + +~~~~xml + + + + SGBlog + com.sangeng + 1.0-SNAPSHOT + + 4.0.0 + + sangeng-admin + + + + com.sangeng + sangeng-framework + 1.0-SNAPSHOT + + + + +~~~~ + +④创建博客前台模块sangeng-blog + +~~~~xml + + + + SGBlog + com.sangeng + 1.0-SNAPSHOT + + 4.0.0 + + sangeng-blog + + + + com.sangeng + sangeng-framework + 1.0-SNAPSHOT + + + + + +~~~~ + + + +## 3.博客前台 + +### 3.0 准备工作 + +#### 3.1 SpringBoot和MybatisPuls整合配置测试 + +①创建启动类 + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@SpringBootApplication +@MapperScan("com.sangeng.mapper") +public class SanGengBlogApplication { + + public static void main(String[] args) { + SpringApplication.run(SanGengBlogApplication.class,args); + } +} +~~~~ + +②创建application.yml配置文件 + +~~~~yml +server: + port: 7777 +spring: + datasource: + url: jdbc:mysql://localhost:3306/sg_blog?characterEncoding=utf-8&serverTimezone=Asia/Shanghai + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + servlet: + multipart: + max-file-size: 2MB + max-request-size: 5MB +mybatis-plus: + configuration: + # 日志 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + global-config: + db-config: + logic-delete-field: delFlag + logic-delete-value: 1 + logic-not-delete-value: 0 + id-type: auto + +~~~~ + +③ SQL语句 + +​ SQL脚本:SGBlog\资源\SQL\sg_article.sql + +④ 创建实体类,Mapper,Service + +​ 注意思考这些文件应该写在哪个模块下? + +~~~~java +@SuppressWarnings("serial") +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("sg_article") +public class Article { + @TableId + private Long id; + //标题 + private String title; + //文章内容 + private String content; + //文章类型:1 文章 2草稿 + private String type; + //文章摘要 + private String summary; + //所属分类id + private Long categoryId; + //缩略图 + private String thumbnail; + //是否置顶(0否,1是) + private String isTop; + //状态(0已发布,1草稿) + private String status; + //评论数 + private Integer commentCount; + //访问量 + private Long viewCount; + //是否允许评论 1是,0否 + private String isComment; + + private Long createBy; + + private Date createTime; + + private Long updateBy; + + private Date updateTime; + //删除标志(0代表未删除,1代表已删除) + private Integer delFlag; + +} + + +~~~~ + +~~~~java +public interface ArticleMapper extends BaseMapper
{ + + +} + +~~~~ + +~~~~java +public interface ArticleService extends IService
{ +} + +~~~~ + +~~~~java +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + +} +~~~~ + + + +⑤ 创建Controller测试接口 + +​ 注意思考这些文件应该写在哪个模块下? + +~~~~java +@RestController +@RequestMapping("/article") +public class ArticleController { + + @Autowired + private ArticleService articleService; + + @GetMapping("/list") + public List
test(){ + return articleService.list(); + } +} + +~~~~ + +​ 我们可以暂时先注释掉sangeng-framework中的SpringSecurity依赖方便测试 + + + +### 3.1 热门文章列表 + +#### 3.1.0 文章表分析 + +​ 通过需求去分析需要有哪些字段。 + +#### 3.1.1 需求 + +​ 需要查询浏览量最高的前10篇文章的信息。要求展示文章标题和浏览量。把能让用户自己点击跳转到具体的文章详情进行浏览。 + +​ 注意:不能把草稿展示出来,不能把删除了的文章查询出来。要按照浏览量进行降序排序。 + +#### 3.1.2 接口设计 + +​ 见接口文档 + +#### 3.1.3 基础版本代码实现 + +①准备工作 + +统一响应类和响应枚举 + +~~~~java +package com.sangeng.domain; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.sangeng.enums.AppHttpCodeEnum; + +import java.io.Serializable; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ResponseResult implements Serializable { + private Integer code; + private String msg; + private T data; + + public ResponseResult() { + this.code = AppHttpCodeEnum.SUCCESS.getCode(); + this.msg = AppHttpCodeEnum.SUCCESS.getMsg(); + } + + public ResponseResult(Integer code, T data) { + this.code = code; + this.data = data; + } + + public ResponseResult(Integer code, String msg, T data) { + this.code = code; + this.msg = msg; + this.data = data; + } + + public ResponseResult(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + public static ResponseResult errorResult(int code, String msg) { + ResponseResult result = new ResponseResult(); + return result.error(code, msg); + } + public static ResponseResult okResult() { + ResponseResult result = new ResponseResult(); + return result; + } + public static ResponseResult okResult(int code, String msg) { + ResponseResult result = new ResponseResult(); + return result.ok(code, null, msg); + } + + public static ResponseResult okResult(Object data) { + ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getMsg()); + if(data!=null) { + result.setData(data); + } + return result; + } + + public static ResponseResult errorResult(AppHttpCodeEnum enums){ + return setAppHttpCodeEnum(enums,enums.getMsg()); + } + + public static ResponseResult errorResult(AppHttpCodeEnum enums, String msg){ + return setAppHttpCodeEnum(enums,msg); + } + + public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums){ + return okResult(enums.getCode(),enums.getMsg()); + } + + private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String msg){ + return okResult(enums.getCode(),msg); + } + + public ResponseResult error(Integer code, String msg) { + this.code = code; + this.msg = msg; + return this; + } + + public ResponseResult ok(Integer code, T data) { + this.code = code; + this.data = data; + return this; + } + + public ResponseResult ok(Integer code, T data, String msg) { + this.code = code; + this.data = data; + this.msg = msg; + return this; + } + + public ResponseResult ok(T data) { + this.data = data; + return this; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + + +} +~~~~ + +~~~~java +package com.sangeng.enums; + +public enum AppHttpCodeEnum { + // 成功 + SUCCESS(200,"操作成功"), + // 登录 + NEED_LOGIN(401,"需要登录后操作"), + NO_OPERATOR_AUTH(403,"无权限操作"), + SYSTEM_ERROR(500,"出现错误"), + USERNAME_EXIST(501,"用户名已存在"), + PHONENUMBER_EXIST(502,"手机号已存在"), EMAIL_EXIST(503, "邮箱已存在"), + REQUIRE_USERNAME(504, "必需填写用户名"), + LOGIN_ERROR(505,"用户名或密码错误"); + int code; + String msg; + + AppHttpCodeEnum(int code, String errorMessage){ + this.code = code; + this.msg = errorMessage; + } + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } +} + +~~~~ + + + +② 代码实现 + +~~~~java +@RestController +@RequestMapping("/article") +public class ArticleController { + + @Autowired + private ArticleService articleService; + + @GetMapping("/hotArticleList") + public ResponseResult hotArticleList(){ + + ResponseResult result = articleService.hotArticleList(); + return result; + } +} + +~~~~ + +~~~~java +public interface ArticleService extends IService
{ + ResponseResult hotArticleList(); +} + +~~~~ + +~~~~java +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + + @Override + public ResponseResult hotArticleList() { + //查询热门文章 封装成ResponseResult返回 + LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); + //必须是正式文章 + queryWrapper.eq(Article::getStatus,0); + //按照浏览量进行排序 + queryWrapper.orderByDesc(Article::getViewCount); + //最多只查询10条 + Page
page = new Page(1,10); + page(page,queryWrapper); + + List
articles = page.getRecords(); + return ResponseResult.okResult(articles); + } +} + +~~~~ + + + + + +③ 解决跨域问题 + +~~~~java +@Configuration +public class WebConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + // 设置允许跨域的路径 + registry.addMapping("/**") + // 设置允许跨域请求的域名 + .allowedOriginPatterns("*") + // 是否允许cookie + .allowCredentials(true) + // 设置允许的请求方式 + .allowedMethods("GET", "POST", "DELETE", "PUT") + // 设置允许的header属性 + .allowedHeaders("*") + // 跨域允许时间 + .maxAge(3600); + } + +} +~~~~ + + + + + +#### 3.1.4 使用VO优化 + +​ 目前我们的响应格式其实是不符合接口文档的标准的,多返回了很多字段。这是因为我们查询出来的结果是Article来封装的,Article中字段比较多。 + +​ 我们在项目中一般最后还要把VO来接受查询出来的结果。一个接口对应一个VO,这样即使接口响应字段要修改也只要改VO即可。 + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HotArticleVo { + private Long id; + //标题 + private String title; + + //访问量 + private Long viewCount; +} + +~~~~ + +~~~~java +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + + @Override + public ResponseResult hotArticleList() { + //查询热门文章 封装成ResponseResult返回 + LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); + //必须是正式文章 + queryWrapper.eq(Article::getStatus,0); + //按照浏览量进行排序 + queryWrapper.orderByDesc(Article::getViewCount); + //最多只查询10条 + Page
page = new Page(1,10); + page(page,queryWrapper); + + List
articles = page.getRecords(); + //bean拷贝 + List articleVos = new ArrayList<>(); + for (Article article : articles) { + HotArticleVo vo = new HotArticleVo(); + BeanUtils.copyProperties(article,vo); + articleVos.add(vo); + } + + return ResponseResult.okResult(articleVos); + } +} +~~~~ + +#### 3.1.5 字面值处理 + +​ 实际项目中都不允许直接在代码中使用字面值。都需要定义成常量来使用。这种方式有利于提高代码的可维护性。 + +~~~~java +public class SystemConstants +{ + /** + * 文章是草稿 + */ + public static final int ARTICLE_STATUS_DRAFT = 1; + /** + * 文章是正常分布状态 + */ + public static final int ARTICLE_STATUS_NORMAL = 0; + +} +~~~~ + +~~~~java +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + + @Override + public ResponseResult hotArticleList() { + //查询热门文章 封装成ResponseResult返回 + LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); + //必须是正式文章 + queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL); + //按照浏览量进行排序 + queryWrapper.orderByDesc(Article::getViewCount); + //最多只查询10条 + Page
page = new Page(1,10); + page(page,queryWrapper); + + List
articles = page.getRecords(); + //bean拷贝 + List articleVos = new ArrayList<>(); + for (Article article : articles) { + HotArticleVo vo = new HotArticleVo(); + BeanUtils.copyProperties(article,vo); + articleVos.add(vo); + } + + return ResponseResult.okResult(articleVos); + } +} +~~~~ + + + + + +### 3.2 Bean拷贝工具类封装 + +~~~~java +public class BeanCopyUtils { + + private BeanCopyUtils() { + } + + public static V copyBean(Object source,Class clazz) { + //创建目标对象 + V result = null; + try { + result = clazz.newInstance(); + //实现属性copy + BeanUtils.copyProperties(source, result); + } catch (Exception e) { + e.printStackTrace(); + } + //返回结果 + return result; + } + public static List copyBeanList(List list,Class clazz){ + return list.stream() + .map(o -> copyBean(o, clazz)) + .collect(Collectors.toList()); + } +} + +~~~~ + + + + + +### 3.2 查询分类列表 + +#### 3.2.0 分类表分析 + +​ 通过需求去分析需要有哪些字段。 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sg_category.sql + +#### 3.2.1 需求 + +![image-20220202111056036](img/image-20220202111056036-16437714601701.png) + +​ 页面上需要展示分类列表,用户可以点击具体的分类查看该分类下的文章列表。 + +​ 注意: ①要求只展示有发布正式文章的分类 ②必须是正常状态的分类 + + + +#### 3.2.2 接口设计 + +​ 见接口文档 + +#### 3.2.3 EasyCode代码模板 + +~~~~java +##导入宏定义 +$!{define.vm} + +##保存文件(宏定义) +#save("/entity", ".java") + +##包路径(宏定义) +#setPackageSuffix("entity") + +##自动导入包(全局变量) +$!{autoImport.vm} + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +##表注释(宏定义) +#tableComment("表实体类") +@SuppressWarnings("serial") +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("$!{tableInfo.obj.name}") +public class $!{tableInfo.name} { +#foreach($column in $tableInfo.pkColumn) + #if(${column.comment})//${column.comment}#end +@TableId + private $!{tool.getClsNameByFullName($column.type)} $!{column.name}; +#end + +#foreach($column in $tableInfo.otherColumn) + #if(${column.comment})//${column.comment}#end + + private $!{tool.getClsNameByFullName($column.type)} $!{column.name}; +#end + + + +} + +~~~~ + +~~~~java +##导入宏定义 +$!{define.vm} + +##设置表后缀(宏定义) +#setTableSuffix("Mapper") + +##保存文件(宏定义) +#save("/mapper", "Mapper.java") + +##包路径(宏定义) +#setPackageSuffix("mapper") + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + + +##表注释(宏定义) +#tableComment("表数据库访问层") +public interface $!{tableName} extends BaseMapper<$!tableInfo.name> { + +} + +~~~~ + +~~~~java +##导入宏定义 +$!{define.vm} + +##设置表后缀(宏定义) +#setTableSuffix("Service") + +##保存文件(宏定义) +#save("/service", "Service.java") + +##包路径(宏定义) +#setPackageSuffix("service") + +import com.baomidou.mybatisplus.extension.service.IService; + + +##表注释(宏定义) +#tableComment("表服务接口") +public interface $!{tableName} extends IService<$!tableInfo.name> { + +} + +~~~~ + + + +~~~~java +##导入宏定义 +$!{define.vm} + +##设置表后缀(宏定义) +#setTableSuffix("ServiceImpl") + +##保存文件(宏定义) +#save("/service/impl", "ServiceImpl.java") + +##包路径(宏定义) +#setPackageSuffix("service.impl") + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +##表注释(宏定义) +#tableComment("表服务实现类") +@Service("$!tool.firstLowerCase($tableInfo.name)Service") +public class $!{tableName} extends ServiceImpl<$!{tableInfo.name}Mapper, $!{tableInfo.name}> implements $!{tableInfo.name}Service { + +} + +~~~~ + + + +#### 3.2.4 代码实现 + +~~~~java +@RestController +@RequestMapping("/category") +public class CategoryController { + + @Autowired + private CategoryService categoryService; + + @GetMapping("/getCategoryList") + public ResponseResult getCategoryList(){ + return categoryService.getCategoryList(); + } +} + + +~~~~ + +~~~~java +public interface CategoryService extends IService { + + + ResponseResult getCategoryList(); + +} +~~~~ + +~~~~java +@Service("categoryService") +public class CategoryServiceImpl extends ServiceImpl implements CategoryService { + + @Autowired + private ArticleService articleService; + + @Override + public ResponseResult getCategoryList() { + //查询文章表 状态为已发布的文章 + LambdaQueryWrapper
articleWrapper = new LambdaQueryWrapper<>(); + articleWrapper.eq(Article::getStatus,SystemConstants.ARTICLE_STATUS_NORMAL); + List
articleList = articleService.list(articleWrapper); + //获取文章的分类id,并且去重 + Set categoryIds = articleList.stream() + .map(article -> article.getCategoryId()) + .collect(Collectors.toSet()); + + //查询分类表 + List categories = listByIds(categoryIds); + categories = categories.stream(). + filter(category -> SystemConstants.STATUS_NORMAL.equals(category.getStatus())) + .collect(Collectors.toList()); + //封装vo + List categoryVos = BeanCopyUtils.copyBeanList(categories, CategoryVo.class); + + return ResponseResult.okResult(categoryVos); + } +} + +~~~~ + + + +### 3.3 分页查询文章列表 + +#### 3.3.1 需求 + +​ 在首页和分类页面都需要查询文章列表。 + +​ 首页:查询所有的文章 + +​ 分类页面:查询对应分类下的文章 + +​ 要求:①只能查询正式发布的文章 ②置顶的文章要显示在最前面 + +#### 3.3.2 接口设计 + +​ 见文档 + +#### 3.3.3 代码实现 + +MP支持分页配置 + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@Configuration +public class MbatisPlusConfig { + + /** + * 3.4.0之后版本 + * @return + */ + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor(){ + MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); + mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); + return mybatisPlusInterceptor; + } +} +~~~~ + +在ArticleController中 + +~~~~java + @GetMapping("/articleList") + public ResponseResult articleList(Integer pageNum,Integer pageSize,Long categoryId){ + return articleService.articleList(pageNum,pageSize,categoryId); + } +~~~~ + +在ArticleService中 + +~~~~java +ResponseResult articleList(Integer pageNum, Integer pageSize, Long categoryId); +~~~~ + +在ArticleServiceImpl中 + +~~~~java + +@Service +public class ArticleServiceImpl extends ServiceImpl implements ArticleService { + + @Autowired + private CategoryService categoryService; + + @Override + public ResponseResult hotArticleList() { + //查询热门文章 封装成ResponseResult返回 + LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); + //必须是正式文章 + queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL); + //按照浏览量进行排序 + queryWrapper.orderByDesc(Article::getViewCount); + //最多只查询10条 + Page
page = new Page(1,10); + page(page,queryWrapper); + + List
articles = page.getRecords(); + //bean拷贝 +// List articleVos = new ArrayList<>(); +// for (Article article : articles) { +// HotArticleVo vo = new HotArticleVo(); +// BeanUtils.copyProperties(article,vo); +// articleVos.add(vo); +// } + List vs = BeanCopyUtils.copyBeanList(articles, HotArticleVo.class); + return ResponseResult.okResult(vs); + } + + @Override + public ResponseResult articleList(Integer pageNum, Integer pageSize, Long categoryId) { + //查询条件 + LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); + // 如果 有categoryId 就要 查询时要和传入的相同 + lambdaQueryWrapper.eq(Objects.nonNull(categoryId)&&categoryId>0 ,Article::getCategoryId,categoryId); + // 状态是正式发布的 + lambdaQueryWrapper.eq(Article::getStatus,SystemConstants.ARTICLE_STATUS_NORMAL); + // 对isTop进行降序 + lambdaQueryWrapper.orderByDesc(Article::getIsTop); + + //分页查询 + Page
page = new Page<>(pageNum,pageSize); + page(page,lambdaQueryWrapper); + + List
articles = page.getRecords(); + //查询categoryName + articles.stream() + .map(article -> article.setCategoryName(categoryService.getById(article.getCategoryId()).getName())) + .collect(Collectors.toList()); + //articleId去查询articleName进行设置 +// for (Article article : articles) { +// Category category = categoryService.getById(article.getCategoryId()); +// article.setCategoryName(category.getName()); +// } + + //封装查询结果 + List articleListVos = BeanCopyUtils.copyBeanList(page.getRecords(), ArticleListVo.class); + + PageVo pageVo = new PageVo(articleListVos,page.getTotal()); + return ResponseResult.okResult(pageVo); + } +} +~~~~ + + + +PageVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PageVo { + private List rows; + private Long total; +} + +~~~~ + +ArticleListVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ArticleListVo { + + private Long id; + //标题 + private String title; + //文章摘要 + private String summary; + //所属分类名 + private String categoryName; + //缩略图 + private String thumbnail; + + + //访问量 + private Long viewCount; + + private Date createTime; + + +} +~~~~ + +在Article中增加一个字段 + +~~~~java + @TableField(exist = false) + private String categoryName; +~~~~ + + + +#### 3.3.4 FastJson配置 + +~~~~java + @Bean//使用@Bean注入fastJsonHttpMessageConvert + public HttpMessageConverter fastJsonHttpMessageConverters() { + //1.需要定义一个Convert转换消息的对象 + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); + fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); + + SerializeConfig.globalInstance.put(Long.class, ToStringSerializer.instance); + + fastJsonConfig.setSerializeConfig(SerializeConfig.globalInstance); + fastConverter.setFastJsonConfig(fastJsonConfig); + HttpMessageConverter converter = fastConverter; + return converter; + } + + @Override + public void configureMessageConverters(List> converters) { + converters.add(fastJsonHttpMessageConverters()); + } +~~~~ + + + +### 3.4 文章详情接口 + +#### 3.4.1 需求 + +​ 要求在文章列表点击阅读全文时能够跳转到文章详情页面,可以让用户阅读文章正文。 + +​ 要求:①要在文章详情中展示其分类名 + +#### 3.4.2 接口设计 + +| 请求方式 | 请求路径 | +| -------- | ------------- | +| Get | /article/{id} | + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "categoryId": "1", + "categoryName": "java", + "content": "内容", + "createTime": "2022-01-23 23:20:11", + "id": "1", + "isComment": "0", + "title": "SpringSecurity从入门到精通", + "viewCount": "114" + }, + "msg": "操作成功" +} +~~~~ + +#### 3.4.3 代码实现 + +ArticleController中新增 + +~~~~java + @GetMapping("/{id}") + public ResponseResult getArticleDetail(@PathVariable("id") Long id){ + return articleService.getArticleDetail(id); + } +~~~~ + + + +Service + +~~~~java +ResponseResult getArticleDetail(Long id); +~~~~ + + + +ServiceImpl + +~~~~java + @Override + public ResponseResult getArticleDetail(Long id) { + //根据id查询文章 + Article article = getById(id); + //转换成VO + ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class); + //根据分类id查询分类名 + Long categoryId = articleDetailVo.getCategoryId(); + Category category = categoryService.getById(categoryId); + if(category!=null){ + articleDetailVo.setCategoryName(category.getName()); + } + //封装响应返回 + return ResponseResult.okResult(articleDetailVo); + } +~~~~ + + + + + +### 3.5 友联查询 + +#### 3.5.0 友链表分析 + +​ 通过需求去分析需要有哪些字段。 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sg_link.sql + +#### 3.5.1 需求 + +​ 在友链页面要查询出所有的审核通过的友链。 + +#### 3.5.2 接口设计 + +| 请求方式 | 请求路径 | +| -------- | ---------------- | +| Get | /link/getAllLink | + +响应格式: + +~~~~json +{ + "code": 200, + "data": [ + { + "address": "https://www.baidu.com", + "description": "sda", + "id": "1", + "logo": "图片url1", + "name": "sda" + }, + { + "address": "https://www.qq.com", + "description": "dada", + "id": "2", + "logo": "图片url2", + "name": "sda" + } + ], + "msg": "操作成功" +} +~~~~ + + + +#### 3.5.3 代码实现 + +Controller + +~~~~java +@RestController +@RequestMapping("/link") +public class LinkController { + + @Autowired + private LinkService linkService; + + @GetMapping("/getAllLink") + public ResponseResult getAllLink(){ + return linkService.getAllLink(); + } +} + +~~~~ + + + +Service + +~~~~java +public interface LinkService extends IService { + + ResponseResult getAllLink(); +} + + +~~~~ + + + +ServiceImpl + +~~~~java +@Service("linkService") +public class LinkServiceImpl extends ServiceImpl implements LinkService { + + @Override + public ResponseResult getAllLink() { + //查询所有审核通过的 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Link::getStatus, SystemConstants.LINK_STATUS_NORMAL); + List links = list(queryWrapper); + //转换成vo + List linkVos = BeanCopyUtils.copyBeanList(links, LinkVo.class); + //封装返回 + return ResponseResult.okResult(linkVos); + } +} + +~~~~ + + + +SystemConstants + +~~~~java + /** + * 友链状态为审核通过 + */ + public static final String LINK_STATUS_NORMAL = "0"; +~~~~ + + + + + +### 3.6 登录功能实现 + +​ 使用我们前台和后台的认证授权统一都使用SpringSecurity安全框架来实现。 + +#### 3.6.0 需求 + +​ 需要实现登录功能 + +​ 有些功能必须登录后才能使用,未登录状态是不能使用的。 + +#### 3.6.1 接口设计 + +| 请求方式 | 请求路径 | +| -------- | -------- | +| POST | /login | + +请求体: + +~~~~json +{ + "userName":"sg", + "password":"1234" +} +~~~~ + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0ODBmOThmYmJkNmI0NjM0OWUyZjY2NTM0NGNjZWY2NSIsInN1YiI6IjEiLCJpc3MiOiJzZyIsImlhdCI6MTY0Mzg3NDMxNiwiZXhwIjoxNjQzOTYwNzE2fQ.ldLBUvNIxQCGemkCoMgT_0YsjsWndTg5tqfJb77pabk", + "userInfo": { + "avatar": "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2F3bf9c263bc0f2ac5c3a7feb9e218d07475573ec8.gi", + "email": "23412332@qq.com", + "id": 1, + "nickName": "sg333", + "sex": "1" + } + }, + "msg": "操作成功" +} +~~~~ + +#### 3.6.2 表分析 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sys_user.sql + +​ 顺便生成下User和UserMapper后面会用到 + +#### 3.6.3 思路分析 + +登录 + +​ ①自定义登录接口 + +​ 调用ProviderManager的方法进行认证 如果认证通过生成jwt + +​ 把用户信息存入redis中 + +​ ②自定义UserDetailsService + +​ 在这个实现类中去查询数据库 + +​ 注意配置passwordEncoder为BCryptPasswordEncoder + +校验: + +​ ①定义Jwt认证过滤器 + +​ 获取token + +​ 解析token获取其中的userid + +​ 从redis中获取用户信息 + +​ 存入SecurityContextHolder + +#### 3.6.4 准备工作 + +①添加依赖 + +注意放开Security依赖的注释 + +~~~~xml + + + org.springframework.boot + spring-boot-starter-data-redis + + + + com.alibaba + fastjson + 1.2.33 + + + + io.jsonwebtoken + jjwt + 0.9.0 + +~~~~ + +②工具类和相关配置类 + +​ 见 :SGBlog\资源\登录功能所需资源 + +#### 3.6.5 登录接口代码实现 + +##### BlogLoginController + +~~~~java +@RestController +public class BlogLoginController { + @Autowired + private BlogLoginService blogLoginService; + + @PostMapping("/login") + public ResponseResult login(@RequestBody User user){ + return blogLoginService.login(user); + } +} + +~~~~ + + + +##### BlogLoginService + +~~~~java +public interface BlogLoginService { + ResponseResult login(User user); +} + +~~~~ + + + +##### SecurityConfig + +~~~~java +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + + http.logout().disable(); + //允许跨域 + http.cors(); + } + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } +} +~~~~ + + + +##### BlogLoginServiceImpl + +~~~~java + +@Service +public class BlogLoginServiceImpl implements BlogLoginService { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private RedisCache redisCache; + + @Override + public ResponseResult login(User user) { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword()); + Authentication authenticate = authenticationManager.authenticate(authenticationToken); + //判断是否认证通过 + if(Objects.isNull(authenticate)){ + throw new RuntimeException("用户名或密码错误"); + } + //获取userid 生成token + LoginUser loginUser = (LoginUser) authenticate.getPrincipal(); + String userId = loginUser.getUser().getId().toString(); + String jwt = JwtUtil.createJWT(userId); + //把用户信息存入redis + redisCache.setCacheObject("bloglogin:"+userId,loginUser); + + //把token和userinfo封装 返回 + //把User转换成UserInfoVo + UserInfoVo userInfoVo = BeanCopyUtils.copyBean(loginUser.getUser(), UserInfoVo.class); + BlogUserLoginVo vo = new BlogUserLoginVo(jwt,userInfoVo); + return ResponseResult.okResult(vo); + } +} +~~~~ + + + +##### UserDetailServiceImpl + +~~~~java +@Service +public class UserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private UserMapper userMapper; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + //根据用户名查询用户信息 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(User::getUserName,username); + User user = userMapper.selectOne(queryWrapper); + //判断是否查到用户 如果没查到抛出异常 + if(Objects.isNull(user)){ + throw new RuntimeException("用户不存在"); + } + //返回用户信息 + // TODO 查询权限信息封装 + return new LoginUser(user); + } +} +~~~~ + + + + + +##### LoginUser + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LoginUser implements UserDetails { + + private User user; + + + @Override + public Collection getAuthorities() { + return null; + } + + @Override + public String getPassword() { + return user.getPassword(); + } + + @Override + public String getUsername() { + return user.getUserName(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} + +~~~~ + + + + + +##### BlogUserLoginVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BlogUserLoginVo { + + private String token; + private UserInfoVo userInfo; +} +~~~~ + + + +##### UserInfoVo + +~~~~java +@Data +@Accessors(chain = true) +public class UserInfoVo { + /** + * 主键 + */ + private Long id; + + /** + * 昵称 + */ + private String nickName; + + /** + * 头像 + */ + private String avatar; + + private String sex; + + private String email; + + +} + +~~~~ + + + + + +#### 3.6.6 登录校验过滤器代码实现 + +##### 思路 + +​ ①定义Jwt认证过滤器 + +​ 获取token + +​ 解析token获取其中的userid + +​ 从redis中获取用户信息 + +​ 存入SecurityContextHolder + +##### JwtAuthenticationTokenFilter + +~~~~java +@Component +public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { + + @Autowired + private RedisCache redisCache; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + //获取请求头中的token + String token = request.getHeader("token"); + if(!StringUtils.hasText(token)){ + //说明该接口不需要登录 直接放行 + filterChain.doFilter(request, response); + return; + } + //解析获取userid + Claims claims = null; + try { + claims = JwtUtil.parseJWT(token); + } catch (Exception e) { + e.printStackTrace(); + //token超时 token非法 + //响应告诉前端需要重新登录 + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + WebUtils.renderString(response, JSON.toJSONString(result)); + return; + } + String userId = claims.getSubject(); + //从redis中获取用户信息 + LoginUser loginUser = redisCache.getCacheObject("bloglogin:" + userId); + //如果获取不到 + if(Objects.isNull(loginUser)){ + //说明登录过期 提示重新登录 + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + WebUtils.renderString(response, JSON.toJSONString(result)); + return; + } + //存入SecurityContextHolder + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,null); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + + filterChain.doFilter(request, response); + } + + +} +~~~~ + +##### SecurityConfig + +~~~~java +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Autowired + private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + //jwt过滤器测试用,如果测试没有问题吧这里删除了 + .antMatchers("/link/getAllLink").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } +} + +~~~~ + + + +### 3.7 认证授权失败处理 + +​ 目前我们的项目在认证出错或者权限不足的时候响应回来的Json是Security的异常处理结果。但是这个响应的格式肯定是不符合我们项目的接口规范的。所以需要自定义异常处理。 + + + +​ AuthenticationEntryPoint 认证失败处理器 + +​ AccessDeniedHandler 授权失败处理器 + + + +~~~~java +@Component +public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { + authException.printStackTrace(); + //InsufficientAuthenticationException + //BadCredentialsException + ResponseResult result = null; + if(authException instanceof BadCredentialsException){ + result = ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_ERROR.getCode(),authException.getMessage()); + }else if(authException instanceof InsufficientAuthenticationException){ + result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + }else{ + result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),"认证或授权失败"); + } + //响应给前端 + WebUtils.renderString(response, JSON.toJSONString(result)); + } +} + +~~~~ + + + +~~~~java +@Component +public class AccessDeniedHandlerImpl implements AccessDeniedHandler { + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { + accessDeniedException.printStackTrace(); + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH); + //响应给前端 + WebUtils.renderString(response, JSON.toJSONString(result)); + } +} + +~~~~ + + + +配置Security异常处理器 + +~~~~java +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Autowired + private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; + @Autowired + AuthenticationEntryPoint authenticationEntryPoint; + @Autowired + AccessDeniedHandler accessDeniedHandler; + + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + //jwt过滤器测试用,如果测试没有问题吧这里删除了 + .antMatchers("/link/getAllLink").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } +} + +~~~~ + +### 3.8 统一异常处理 + +​ 实际我们在开发过程中可能需要做很多的判断校验,如果出现了非法情况我们是期望响应对应的提示的。但是如果我们每次都自己手动去处理就会非常麻烦。我们可以选择直接抛出异常的方式,然后对异常进行统一处理。把异常中的信息封装成ResponseResult响应给前端。 + +​ + +SystemException + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +public class SystemException extends RuntimeException{ + + private int code; + + private String msg; + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } + + public SystemException(AppHttpCodeEnum httpCodeEnum) { + super(httpCodeEnum.getMsg()); + this.code = httpCodeEnum.getCode(); + this.msg = httpCodeEnum.getMsg(); + } + +} + +~~~~ + +GlobalExceptionHandler + +~~~~java +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(SystemException.class) + public ResponseResult systemExceptionHandler(SystemException e){ + //打印异常信息 + log.error("出现了异常! {}",e); + //从异常对象中获取提示信息封装返回 + return ResponseResult.errorResult(e.getCode(),e.getMsg()); + } + + + @ExceptionHandler(Exception.class) + public ResponseResult exceptionHandler(Exception e){ + //打印异常信息 + log.error("出现了异常! {}",e); + //从异常对象中获取提示信息封装返回 + return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),e.getMessage()); + } +} + +~~~~ + + + +### 3.9 退出登录接口 + +#### 3.9.1 接口设计 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | --------------- | +| POST | /logout | 需要token请求头 | + +响应格式: + +~~~~json +{ + "code": 200, + "msg": "操作成功" +} +~~~~ + + + +#### 3.9.2 代码实现 + +要实现的操作: + +​ 删除redis中的用户信息 + +BlogLoginController + +~~~~java + @PostMapping("/logout") + public ResponseResult logout(){ + return blogLoginService.logout(); + } +~~~~ + +BlogLoginService + +~~~~java +ResponseResult logout(); +~~~~ + +BlogLoginServiceImpl + +~~~~java + @Override + public ResponseResult logout() { + //获取token 解析获取userid + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + //获取userid + Long userId = loginUser.getUser().getId(); + //删除redis中的用户信息 + redisCache.deleteObject("bloglogin:"+userId); + return ResponseResult.okResult(); + } +~~~~ + +SecurityConfig + +要关闭默认的退出登录功能。并且要配置我们的退出登录接口需要认证才能访问 + +~~~~java + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + //注销接口需要认证才能访问 + .antMatchers("/logout").authenticated() + //jwt过滤器测试用,如果测试没有问题吧这里删除了 + .antMatchers("/link/getAllLink").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + //关闭默认的注销功能 + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } +~~~~ + + + +### 3.10 查询评论列表接口 + +#### 3.10.1 需求 + +​ 文章详情页面要展示这篇文章下的评论列表。 + +​ 效果如下: + +![image-20220208214106296](img/image-20220208214106296.png) + + + + + +#### 3.10.2 评论表分析 + +​ 通过需求去分析需要有哪些字段。 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sg_comment.sql + +​ **顺便生成下对应的代码** + +#### 3.10.3 接口设计 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------------------- | ----------------- | +| GET | /comment/commentList | 不需要token请求头 | + +Query格式请求参数: + +articleId:文章id + +pageNum: 页码 + +pageSize: 每页条数 + + + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "rows": [ + { + "articleId": "1", + "children": [ + { + "articleId": "1", + "content": "你说啥?", + "createBy": "1", + "createTime": "2022-01-30 10:06:21", + "id": "20", + "rootId": "1", + "toCommentId": "1", + "toCommentUserId": "1", + "toCommentUserName": "sg333", + "username": "sg333" + } + ], + "content": "asS", + "createBy": "1", + "createTime": "2022-01-29 07:59:22", + "id": "1", + "rootId": "-1", + "toCommentId": "-1", + "toCommentUserId": "-1", + "username": "sg333" + } + ], + "total": "15" + }, + "msg": "操作成功" +} +~~~~ + + + +#### 3.10.4 代码实现 + +##### 3.10.4.1 不考虑子评论 + +CommentController + +~~~~java +@RestController +@RequestMapping("/comment") +public class CommentController { + + @Autowired + private CommentService commentService; + + @GetMapping("/commentList") + public ResponseResult commentList(Long articleId,Integer pageNum,Integer pageSize){ + return commentService.commentList(articleId,pageNum,pageSize); + } +} + +~~~~ + + + +CommentService + +~~~~java +public interface CommentService extends IService { + + ResponseResult commentList(Long articleId, Integer pageNum, Integer pageSize); +} + +~~~~ + + + +CommentServiceImpl + +~~~~java +@Service("commentService") +public class CommentServiceImpl extends ServiceImpl implements CommentService { + + @Autowired + private UserService userService; + + @Override + public ResponseResult commentList(Long articleId, Integer pageNum, Integer pageSize) { + //查询对应文章的根评论 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //对articleId进行判断 + queryWrapper.eq(Comment::getArticleId,articleId); + //根评论 rootId为-1 + queryWrapper.eq(Comment::getRootId,-1); + + //分页查询 + Page page = new Page(pageNum,pageSize); + page(page,queryWrapper); + + List commentVoList = toCommentVoList(page.getRecords()); + + return ResponseResult.okResult(new PageVo(commentVoList,page.getTotal())); + } + + private List toCommentVoList(List list){ + List commentVos = BeanCopyUtils.copyBeanList(list, CommentVo.class); + //遍历vo集合 + for (CommentVo commentVo : commentVos) { + //通过creatyBy查询用户的昵称并赋值 + String nickName = userService.getById(commentVo.getCreateBy()).getNickName(); + commentVo.setUsername(nickName); + //通过toCommentUserId查询用户的昵称并赋值 + //如果toCommentUserId不为-1才进行查询 + if(commentVo.getToCommentUserId()!=-1){ + String toCommentUserName = userService.getById(commentVo.getToCommentUserId()).getNickName(); + commentVo.setToCommentUserName(toCommentUserName); + } + } + return commentVos; + } +} + + +~~~~ + + + +CommentVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CommentVo { + private Long id; + //文章id + private Long articleId; + //根评论id + private Long rootId; + //评论内容 + private String content; + //所回复的目标评论的userid + private Long toCommentUserId; + private String toCommentUserName; + //回复目标评论id + private Long toCommentId; + + private Long createBy; + + private Date createTime; + + private String username; +} + +~~~~ + + + +##### 3.10.4.2 查询子评论 + +CommentVo在之前的基础上增加了 private List children; + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CommentVo { + private Long id; + //文章id + private Long articleId; + //根评论id + private Long rootId; + //评论内容 + private String content; + //所回复的目标评论的userid + private Long toCommentUserId; + private String toCommentUserName; + //回复目标评论id + private Long toCommentId; + + private Long createBy; + + private Date createTime; + + private String username; + + private List children; +} + +~~~~ + + + +CommentServiceImpl + +~~~~java +@Service("commentService") +public class CommentServiceImpl extends ServiceImpl implements CommentService { + + @Autowired + private UserService userService; + + @Override + public ResponseResult commentList(Long articleId, Integer pageNum, Integer pageSize) { + //查询对应文章的根评论 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //对articleId进行判断 + queryWrapper.eq(Comment::getArticleId,articleId); + //根评论 rootId为-1 + queryWrapper.eq(Comment::getRootId,-1); + + //分页查询 + Page page = new Page(pageNum,pageSize); + page(page,queryWrapper); + + List commentVoList = toCommentVoList(page.getRecords()); + + //查询所有根评论对应的子评论集合,并且赋值给对应的属性 + for (CommentVo commentVo : commentVoList) { + //查询对应的子评论 + List children = getChildren(commentVo.getId()); + //赋值 + commentVo.setChildren(children); + } + + return ResponseResult.okResult(new PageVo(commentVoList,page.getTotal())); + } + + /** + * 根据根评论的id查询所对应的子评论的集合 + * @param id 根评论的id + * @return + */ + private List getChildren(Long id) { + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Comment::getRootId,id); + queryWrapper.orderByAsc(Comment::getCreateTime); + List comments = list(queryWrapper); + + List commentVos = toCommentVoList(comments); + return commentVos; + } + + private List toCommentVoList(List list){ + List commentVos = BeanCopyUtils.copyBeanList(list, CommentVo.class); + //遍历vo集合 + for (CommentVo commentVo : commentVos) { + //通过creatyBy查询用户的昵称并赋值 + String nickName = userService.getById(commentVo.getCreateBy()).getNickName(); + commentVo.setUsername(nickName); + //通过toCommentUserId查询用户的昵称并赋值 + //如果toCommentUserId不为-1才进行查询 + if(commentVo.getToCommentUserId()!=-1){ + String toCommentUserName = userService.getById(commentVo.getToCommentUserId()).getNickName(); + commentVo.setToCommentUserName(toCommentUserName); + } + } + return commentVos; + } +} +~~~~ + + + + + +### 3.11 发表评论接口 + +#### 3.11.1 需求 + +​ 用户登录后可以对文章发表评论,也可以对评论进行回复。 + +​ 用户登录后也可以在友链页面进行评论。 + +#### 3.11.2 接口设计 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | ----------- | +| POST | /comment | 需要token头 | + +##### 请求体: + +回复了文章: + +~~~~json +{"articleId":1,"type":0,"rootId":-1,"toCommentId":-1,"toCommentUserId":-1,"content":"评论了文章"} +~~~~ +回复了某条评论: +~~~~json +{"articleId":1,"type":0,"rootId":"3","toCommentId":"3","toCommentUserId":"1","content":"回复了某条评论"} +~~~~ + + + +如果是友链评论,type应该为1 + + + +##### 响应格式: + +~~~~java +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +#### 3.11.3 代码实现 + +CommentController + +~~~~java + @PostMapping + public ResponseResult addComment(@RequestBody Comment comment){ + return commentService.addComment(comment); + } +~~~~ + +CommentService + +~~~~java +ResponseResult addComment(Comment comment); +~~~~ + +CommentServiceImpl + +~~~~java + @Override + public ResponseResult addComment(Comment comment) { + //评论内容不能为空 + if(!StringUtils.hasText(comment.getContent())){ + throw new SystemException(AppHttpCodeEnum.CONTENT_NOT_NULL); + } + save(comment); + return ResponseResult.okResult(); + } +~~~~ + + + +SecurityUtils + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +public class SecurityUtils +{ + + /** + * 获取用户 + **/ + public static LoginUser getLoginUser() + { + return (LoginUser) getAuthentication().getPrincipal(); + } + + /** + * 获取Authentication + */ + public static Authentication getAuthentication() { + return SecurityContextHolder.getContext().getAuthentication(); + } + + public static Boolean isAdmin(){ + Long id = getLoginUser().getUser().getId(); + return id != null && 1L == id; + } + + public static Long getUserId() { + return getLoginUser().getUser().getId(); + } +} +~~~~ + +配置MP字段自动填充 + +~~~~java +@Component +public class MyMetaObjectHandler implements MetaObjectHandler { + @Override + public void insertFill(MetaObject metaObject) { + Long userId = null; + try { + userId = SecurityUtils.getUserId(); + } catch (Exception e) { + e.printStackTrace(); + userId = -1L;//表示是自己创建 + } + this.setFieldValByName("createTime", new Date(), metaObject); + this.setFieldValByName("createBy",userId , metaObject); + this.setFieldValByName("updateTime", new Date(), metaObject); + this.setFieldValByName("updateBy", userId, metaObject); + } + + @Override + public void updateFill(MetaObject metaObject) { + this.setFieldValByName("updateTime", new Date(), metaObject); + this.setFieldValByName(" ", SecurityUtils.getUserId(), metaObject); + } +} +~~~~ + +用注解标识哪些字段在什么情况下需要自动填充 + +~~~~java + /** + * 创建人的用户id + */ + @TableField(fill = FieldFill.INSERT) + private Long createBy; + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + /** + * 更新人 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; +~~~~ + + + + + +### 3.12 友联评论列表 + +#### 3.12.1 需求 + +​ 友链页面也需要查询对应的评论列表。 + + + +#### 3.12.2 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------------------ | ----------------- | +| GET | /comment/linkCommentList | 不需要token请求头 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "rows": [ + { + "articleId": "1", + "children": [ + { + "articleId": "1", + "content": "回复友链评论3", + "createBy": "1", + "createTime": "2022-01-30 10:08:50", + "id": "23", + "rootId": "22", + "toCommentId": "22", + "toCommentUserId": "1", + "toCommentUserName": "sg333", + "username": "sg333" + } + ], + "content": "友链评论2", + "createBy": "1", + "createTime": "2022-01-30 10:08:28", + "id": "22", + "rootId": "-1", + "toCommentId": "-1", + "toCommentUserId": "-1", + "username": "sg333" + } + ], + "total": "1" + }, + "msg": "操作成功" +} +~~~~ + + + + + +#### 3.12.3 代码实现 + +CommentController 修改了之前的文章评论列表接口,并且增加了新的友联评论接口 + +~~~~java + @GetMapping("/commentList") + public ResponseResult commentList(Long articleId,Integer pageNum,Integer pageSize){ + return commentService.commentList(SystemConstants.ARTICLE_COMMENT,articleId,pageNum,pageSize); + } + @GetMapping("/linkCommentList") + public ResponseResult linkCommentList(Integer pageNum,Integer pageSize){ + return commentService.commentList(SystemConstants.LINK_COMMENT,null,pageNum,pageSize); + } +~~~~ + + + +SystemConstants增加了两个常量 + +~~~~java + /** + * 评论类型为:文章评论 + */ + public static final String ARTICLE_COMMENT = "0"; + /** + * 评论类型为:友联评论 + */ + public static final String LINK_COMMENT = "1"; +~~~~ + + + + + +CommentService修改了commentList方法,增加了一个参数commentType + +~~~~java +ResponseResult commentList(String commentType, Long articleId, Integer pageNum, Integer pageSize); +~~~~ + + + +CommentServiceImpl修改commentList方法的代码,必须commentType为0的时候才增加articleId的判断,并且增加了一个评论类型的添加。 + +~~~~java + @Override + public ResponseResult commentList(String commentType, Long articleId, Integer pageNum, Integer pageSize) { + //查询对应文章的根评论 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + //对articleId进行判断 + queryWrapper.eq(SystemConstants.ARTICLE_COMMENT.equals(commentType),Comment::getArticleId,articleId); + //根评论 rootId为-1 + queryWrapper.eq(Comment::getRootId,-1); + + //评论类型 + queryWrapper.eq(Comment::getType,commentType); + + //分页查询 + Page page = new Page(pageNum,pageSize); + page(page,queryWrapper); + + List commentVoList = toCommentVoList(page.getRecords()); + + //查询所有根评论对应的子评论集合,并且赋值给对应的属性 + for (CommentVo commentVo : commentVoList) { + //查询对应的子评论 + List children = getChildren(commentVo.getId()); + //赋值 + commentVo.setChildren(children); + } + + return ResponseResult.okResult(new PageVo(commentVoList,page.getTotal())); + } +~~~~ + + + + + +### 3.13 个人信息查询接口 + +#### 3.13.1 需求 + +​ 进入个人中心的时候需要能够查看当前用户信息 + +#### 3.13.2 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------------- | --------------- | +| GET | /user/userInfo | 需要token请求头 | + +不需要参数 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "avatar":"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2F3bf9c263bc0f2ac5c3a7feb9e218d07475573ec8.gi", + "email":"23412332@qq.com", + "id":"1", + "nickName":"sg333", + "sex":"1" + }, + "msg":"操作成功" +} +~~~~ + + + +#### 3.13.3 代码实现 + + + +UserController + +~~~~java +@RestController +@RequestMapping("/user") +public class UserController { + + @Autowired + private UserService userService; + + @GetMapping("/userInfo") + public ResponseResult userInfo(){ + return userService.userInfo(); + } +} + +~~~~ + + + +UserService增加方法定义 + +~~~~java +public interface UserService extends IService { + + ResponseResult userInfo(); + +} + +~~~~ + + + +UserServiceImpl实现userInfo方法 + +~~~~java + @Override + public ResponseResult userInfo() { + //获取当前用户id + Long userId = SecurityUtils.getUserId(); + //根据用户id查询用户信息 + User user = getById(userId); + //封装成UserInfoVo + UserInfoVo vo = BeanCopyUtils.copyBean(user,UserInfoVo.class); + return ResponseResult.okResult(vo); + } +~~~~ + + + +SecurityConfig配置该接口必须认证后才能访问 + +~~~~java + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/login").anonymous() + //注销接口需要认证才能访问 + .antMatchers("/logout").authenticated() + //个人信息接口必须登录后才能访问 + .antMatchers("/user/userInfo").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + //关闭默认的注销功能 + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } +~~~~ + + + +### 3.14 头像上传接口 + +#### 3.14.1 需求 + +​ 在个人中心点击编辑的时候可以上传头像图片。上传完头像后,可以用于更新个人信息接口。 + + + +#### 3.14.2 OSS + +##### 3.14.2.1 为什么要使用OSS + +​ 因为如果把图片视频等文件上传到自己的应用的Web服务器,在读取图片的时候会占用比较多的资源。影响应用服务器的性能。 + +​ 所以我们一般使用OSS(Object Storage Service对象存储服务)存储图片或视频。 + + + +##### 3.14.2.2 七牛云基本使用测试 + +![image-20220227224537701](img/image-20220227224537701.png) + +![image-20220227224443813](img/image-20220227224443813.png) + + + +秘钥 + +![image-20220228230512598](img/image-20220228230512598.png) + +![image-20220228230933808](img/image-20220228230933808.png) + + + +##### 3.14.2.3 七牛云测试代码编写 + +①添加依赖 + +~~~~xml + + com.qiniu + qiniu-java-sdk + [7.7.0, 7.7.99] + +~~~~ + + + +②复制修改案例代码 + +application.yml + +~~~~yml +oss: + accessKey: xxxx + secretKey: xxxx + bucket: sg-blog +~~~~ + +OSSTest.java + +~~~~java +@SpringBootTest +@ConfigurationProperties(prefix = "oss") +public class OSSTest { + + private String accessKey; + private String secretKey; + private String bucket; + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public void setBucket(String bucket) { + this.bucket = bucket; + } + + @Test + public void testOss(){ + //构造一个带指定 Region 对象的配置类 + Configuration cfg = new Configuration(Region.autoRegion()); + //...其他参数参考类注释 + + UploadManager uploadManager = new UploadManager(cfg); + //...生成上传凭证,然后准备上传 +// String accessKey = "your access key"; +// String secretKey = "your secret key"; +// String bucket = "sg-blog"; + + //默认不指定key的情况下,以文件内容的hash值作为文件名 + String key = "2022/sg.png"; + + try { +// byte[] uploadBytes = "hello qiniu cloud".getBytes("utf-8"); +// ByteArrayInputStream byteInputStream=new ByteArrayInputStream(uploadBytes); + + + InputStream inputStream = new FileInputStream("C:\\Users\\root\\Desktop\\Snipaste_2022-02-28_22-48-37.png"); + Auth auth = Auth.create(accessKey, secretKey); + String upToken = auth.uploadToken(bucket); + + try { + Response response = uploadManager.put(inputStream,key,upToken,null, null); + //解析上传成功的结果 + DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); + System.out.println(putRet.key); + System.out.println(putRet.hash); + } catch (QiniuException ex) { + Response r = ex.response; + System.err.println(r.toString()); + try { + System.err.println(r.bodyString()); + } catch (QiniuException ex2) { + //ignore + } + } + } catch (Exception ex) { + //ignore + } + + } +} +~~~~ + + + +#### 3.14.2 接口设计 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | --------- | +| POST | /upload | 需要token | + +参数: + +​ img,值为要上传的文件 + +请求头: + +​ Content-Type :multipart/form-data; + + + +响应格式: + +~~~~json +{ + "code": 200, + "data": "文件访问链接", + "msg": "操作成功" +} +~~~~ + +#### 3.14.3 代码实现 + +~~~~java +@RestController +public class UploadController { + @Autowired + private UploadService uploadService; + + @PostMapping("/upload") + public ResponseResult uploadImg(MultipartFile img){ + return uploadService.uploadImg(img); + } +} + +~~~~ + +~~~~java +public interface UploadService { + ResponseResult uploadImg(MultipartFile img); +} + +~~~~ + + + +~~~~java +@Service +@Data +@ConfigurationProperties(prefix = "oss") +public class OssUploadService implements UploadService { + @Override + public ResponseResult uploadImg(MultipartFile img) { + //判断文件类型 + //获取原始文件名 + String originalFilename = img.getOriginalFilename(); + //对原始文件名进行判断 + if(!originalFilename.endsWith(".png")){ + throw new SystemException(AppHttpCodeEnum.FILE_TYPE_ERROR); + } + + //如果判断通过上传文件到OSS + String filePath = PathUtils.generateFilePath(originalFilename); + String url = uploadOss(img,filePath);// 2099/2/3/wqeqeqe.png + return ResponseResult.okResult(url); + } + + private String accessKey; + private String secretKey; + private String bucket; + + + private String uploadOss(MultipartFile imgFile, String filePath){ + //构造一个带指定 Region 对象的配置类 + Configuration cfg = new Configuration(Region.autoRegion()); + //...其他参数参考类注释 + UploadManager uploadManager = new UploadManager(cfg); + //默认不指定key的情况下,以文件内容的hash值作为文件名 + String key = filePath; + try { + InputStream inputStream = imgFile.getInputStream(); + Auth auth = Auth.create(accessKey, secretKey); + String upToken = auth.uploadToken(bucket); + try { + Response response = uploadManager.put(inputStream,key,upToken,null, null); + //解析上传成功的结果 + DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); + System.out.println(putRet.key); + System.out.println(putRet.hash); + return "http://r7yxkqloa.bkt.clouddn.com/"+key; + } catch (QiniuException ex) { + Response r = ex.response; + System.err.println(r.toString()); + try { + System.err.println(r.bodyString()); + } catch (QiniuException ex2) { + //ignore + } + } + } catch (Exception ex) { + //ignore + } + return "www"; + } +} + +~~~~ + + + +PathUtils + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +public class PathUtils { + + public static String generateFilePath(String fileName){ + //根据日期生成路径 2022/1/15/ + SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/"); + String datePath = sdf.format(new Date()); + //uuid作为文件名 + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + //后缀和文件后缀一致 + int index = fileName.lastIndexOf("."); + // test.jpg -> .jpg + String fileType = fileName.substring(index); + return new StringBuilder().append(datePath).append(uuid).append(fileType).toString(); + } +} + +~~~~ + + + +### 3.15 更新个人信息接口 + +#### 3.15.1 需求 + +​ 在编辑完个人资料后点击保存会对个人资料进行更新。 + +#### 3.15.2 接口设计 + +​ + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------------- | --------------- | +| PUT | /user/userInfo | 需要token请求头 | + +参数 + +请求体中json格式数据: + +~~~~json +{ + "avatar":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/31/948597e164614902ab1662ba8452e106.png", + "email":"23412332@qq.com", + "id":"1", + "nickName":"sg333", + "sex":"1" +} +~~~~ + + + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 3.15.3 代码实现 + +UserController + +~~~~java + @PutMapping("/userInfo") + public ResponseResult updateUserInfo(@RequestBody User user){ + return userService.updateUserInfo(user); + } +~~~~ + +UserService + +~~~~java +ResponseResult updateUserInfo(User user); +~~~~ + + + +UserServiceImpl + +~~~~java + @Override + public ResponseResult updateUserInfo(User user) { + updateById(user); + return ResponseResult.okResult(); + } +~~~~ + +### 3.16 用户注册 + +#### 3.16.1 需求 + +​ 要求用户能够在注册界面完成用户的注册。要求用户名,昵称,邮箱不能和数据库中原有的数据重复。如果某项重复了注册失败并且要有对应的提示。并且要求用户名,密码,昵称,邮箱都不能为空。 + +​ 注意:密码必须密文存储到数据库中。 + +#### 3.16.2 接口设计 + +​ + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------------- | ----------------- | +| POST | /user/register | 不需要token请求头 | + +参数 + +请求体中json格式数据: + +~~~~json +{ + "email": "string", + "nickName": "string", + "password": "string", + "userName": "string" +} +~~~~ + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +#### 3.16.3 代码实现 + +UserController + +~~~~java + @PostMapping("/register") + public ResponseResult register(@RequestBody User user){ + return userService.register(user); + } +~~~~ + +UserService + +~~~~java +ResponseResult register(User user); +~~~~ + +UserServiceImpl + +~~~~java + @Autowired + private PasswordEncoder passwordEncoder; + @Override + public ResponseResult register(User user) { + //对数据进行非空判断 + if(!StringUtils.hasText(user.getUserName())){ + throw new SystemException(AppHttpCodeEnum.USERNAME_NOT_NULL); + } + if(!StringUtils.hasText(user.getPassword())){ + throw new SystemException(AppHttpCodeEnum.PASSWORD_NOT_NULL); + } + if(!StringUtils.hasText(user.getEmail())){ + throw new SystemException(AppHttpCodeEnum.EMAIL_NOT_NULL); + } + if(!StringUtils.hasText(user.getNickName())){ + throw new SystemException(AppHttpCodeEnum.NICKNAME_NOT_NULL); + } + //对数据进行是否存在的判断 + if(userNameExist(user.getUserName())){ + throw new SystemException(AppHttpCodeEnum.USERNAME_EXIST); + } + if(nickNameExist(user.getNickName())){ + throw new SystemException(AppHttpCodeEnum.NICKNAME_EXIST); + } + //... + //对密码进行加密 + String encodePassword = passwordEncoder.encode(user.getPassword()); + user.setPassword(encodePassword); + //存入数据库 + save(user); + return ResponseResult.okResult(); + } + +~~~~ + +~~~~java +public enum AppHttpCodeEnum { + // 成功 + SUCCESS(200,"操作成功"), + // 登录 + NEED_LOGIN(401,"需要登录后操作"), + NO_OPERATOR_AUTH(403,"无权限操作"), + SYSTEM_ERROR(500,"出现错误"), + USERNAME_EXIST(501,"用户名已存在"), + PHONENUMBER_EXIST(502,"手机号已存在"), EMAIL_EXIST(503, "邮箱已存在"), + REQUIRE_USERNAME(504, "必需填写用户名"), + CONTENT_NOT_NULL(506, "评论内容不能为空"), + FILE_TYPE_ERROR(507, "文件类型错误,请上传png文件"), + USERNAME_NOT_NULL(508, "用户名不能为空"), + NICKNAME_NOT_NULL(509, "昵称不能为空"), + PASSWORD_NOT_NULL(510, "密码不能为空"), + EMAIL_NOT_NULL(511, "邮箱不能为空"), + NICKNAME_EXIST(512, "昵称已存在"), + LOGIN_ERROR(505,"用户名或密码错误"); + int code; + String msg; + + AppHttpCodeEnum(int code, String errorMessage){ + this.code = code; + this.msg = errorMessage; + } + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } +} + +~~~~ + + + + + + + +### 3.17 AOP实现日志记录 + +#### 3.17.1 需求 + +​ 需要通过日志记录接口调用信息。便于后期调试排查。并且可能有很多接口都需要进行日志的记录。 + +​ 接口被调用时日志打印格式如下: + +![image-20220313133714102](img/image-20220313133714102.png) + + + +#### 3.17.2 思路分析 + +​ 相当于是对原有的功能进行增强。并且是批量的增强,这个时候就非常适合用AOP来进行实现。 + +​ + +#### 3.17.3 代码实现 + +日志打印格式 + +~~~~java + log.info("=======Start======="); + // 打印请求 URL + log.info("URL : {}",); + // 打印描述信息 + log.info("BusinessName : {}", ); + // 打印 Http method + log.info("HTTP Method : {}", ); + // 打印调用 controller 的全路径以及执行方法 + log.info("Class Method : {}.{}", ); + // 打印请求的 IP + log.info("IP : {}",); + // 打印请求入参 + log.info("Request Args : {}",); + // 打印出参 + log.info("Response : {}", ); + // 结束后换行 + log.info("=======End=======" + System.lineSeparator()); +~~~~ + + + + + + + +### 3.18 更新浏览次数 + +#### 3.18.1 需求 + +​ 在用户浏览博文时要实现对应博客浏览量的增加。 + +#### 3.18.2 思路分析 + +​ 我们只需要在每次用户浏览博客时更新对应的浏览数即可。 + +​ 但是如果直接操作博客表的浏览量的话,在并发量大的情况下会出现什么问题呢? + +​ 如何去优化呢? + +​ + +①在应用启动时把博客的浏览量存储到redis中 + +②更新浏览量时去更新redis中的数据 + +③每隔10分钟把Redis中的浏览量更新到数据库中 + +④读取文章浏览量时从redis读取 + + + +#### 3.18.3 铺垫知识 + +##### 3.18.3.1 CommandLineRunner实现项目启动时预处理 + +​ 如果希望在SpringBoot应用启动时进行一些初始化操作可以选择使用CommandLineRunner来进行处理。 + +​ 我们只需要实现CommandLineRunner接口,并且把对应的bean注入容器。把相关初始化的代码重新到需要重新的方法中。 + +​ 这样就会在应用启动的时候执行对应的代码。 + +~~~~java +@Component +public class TestRunner implements CommandLineRunner { + @Override + public void run(String... args) throws Exception { + System.out.println("程序初始化"); + } +} + +~~~~ + + + +##### 3.18.3.2 定时任务 + +​ 定时任务的实现方式有很多,比如XXL-Job等。但是其实核心功能和概念都是类似的,很多情况下只是调用的API不同而已。 + +​ 这里就先用SpringBoot为我们提供的定时任务的API来实现一个简单的定时任务,让大家先对定时任务里面的一些核心概念有个大致的了解。 + +实现步骤 + +① 使用@EnableScheduling注解开启定时任务功能 + +​ 我们可以在配置类上加上@EnableScheduling + +~~~~java +@SpringBootApplication +@MapperScan("com.sangeng.mapper") +@EnableScheduling +public class SanGengBlogApplication { + public static void main(String[] args) { + SpringApplication.run(SanGengBlogApplication.class,args); + } +} +~~~~ + +② 确定定时任务执行代码,并配置任务执行时间 + +​ 使用@Scheduled注解标识需要定时执行的代码。注解的cron属性相当于是任务的执行时间。目前可以使用 0/5 * * * * ? 进行测试,代表从0秒开始,每隔5秒执行一次。 + +​ 注意:对应的bean要注入容器,否则不会生效。 + +~~~~java +@Component +public class TestJob { + + @Scheduled(cron = "0/5 * * * * ?") + public void testJob(){ + //要执行的代码 + System.out.println("定时任务执行了"); + } +} + +~~~~ + + + +###### 3.18.3.2.1 cron 表达式语法 + +​ cron表达式是用来设置定时任务执行时间的表达式。 + +​ 很多情况下我们可以用 : [在线Cron表达式生成器](https://www.bejson.com/othertools/cron/) 来帮助我们理解cron表达式和书写cron表达式。 + +​ 但是我们还是有需要学习对应的Cron语法的,这样可以更有利于我们书写Cron表达式。 + + + +如上我们用到的 0/5 * * * * ? *,cron表达式由七部分组成,中间由空格分隔,这七部分从左往右依次是: + +秒(0~59),分钟(0~59),小时(0~23),日期(1-月最后一天),月份(1-12),星期几(1-7,1表示星期日),年份(一般该项不设置,直接忽略掉,即可为空值) + + + +通用特殊字符:, - * / (可以在任意部分使用) + +> * + +星号表示任意值,例如: + +``` +* * * * * ? +``` + +表示 “ 每年每月每天每时每分每秒 ” 。 + + + +> , + +可以用来定义列表,例如 : + +``` +1,2,3 * * * * ? +``` + +表示 “ 每年每月每天每时每分的每个第1秒,第2秒,第3秒 ” 。 + + + +> - + +定义范围,例如: + +``` +1-3 * * * * ? +``` + +表示 “ 每年每月每天每时每分的第1秒至第3秒 ”。 + + + +> / + +每隔多少,例如 + +``` +5/10 * * * * ? +``` + +表示 “ 每年每月每天每时每分,从第5秒开始,每10秒一次 ” 。即 “ / ” 的左侧是开始值,右侧是间隔。如果是从 “ 0 ” 开始的话,也可以简写成 “ /10 ” + + + + + + + + + +日期部分还可允许特殊字符: ? L W + +星期部分还可允许的特殊字符: ? L # + + + +> ? + +只可用在日期和星期部分。表示没有具体的值,使用?要注意冲突。日期和星期两个部分如果其中一个部分设置了值,则另一个必须设置为 “ ? ”。 + +例如: + +~~~~ +0\* * * 2 * ? + 和 +0\* * * ? * 2 +~~~~ + +同时使用?和同时不使用?都是不对的 + +例如下面写法就是错的 + +~~~~ +* * * 2 * 2 + 和 +* * * ? * ? + +~~~~ + + + + + +> W + +只能用在日期中,表示当月中最接近某天的工作日 + +``` +0 0 0 31W * ? +``` + +表示最接近31号的工作日,如果31号是星期六,则表示30号,即星期五,如果31号是星期天,则表示29号,即星期五。如果31号是星期三,则表示31号本身,即星期三。 + + + + + + + + + +> L + +表示最后(Last),只能用在日期和星期中 + + + +在日期中表示每月最后一天,在一月份中表示31号,在六月份中表示30号 + +也可以表示每月倒是第N天。例如: L-2表示每个月的倒数第2天 + + + + 0 0 0 LW * ? + LW可以连起来用,表示每月最后一个工作日,即每月最后一个星期五 + + + +在星期中表示7即星期六 + + +~~~~ +0 0 0 ? * L +表示每个星期六 +0 0 0 ? * 6L +若前面有其他值的话,则表示最后一个星期几,即每月的最后一个星期五 +~~~~ + + + + + + +> # + +只能用在星期中,表示第几个星期几 + +~~~~ +0 0 0 ? * 6#3 +表示每个月的第三个星期五。 +~~~~ + + + + + + + +#### 3.18.4 接口设计 + +​ + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------------------------- | ----------------- | +| PUT | /article/updateViewCount/{id} | 不需要token请求头 | + +参数 + +​ 请求路径中携带文章id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 3.18.5 代码实现 + +##### ①在应用启动时把博客的浏览量存储到redis中 + +​ 实现CommandLineRunner接口,在应用启动时初始化缓存。 + +~~~~java +@Component +public class ViewCountRunner implements CommandLineRunner { + + @Autowired + private ArticleMapper articleMapper; + + @Autowired + private RedisCache redisCache; + + @Override + public void run(String... args) throws Exception { + //查询博客信息 id viewCount + List
articles = articleMapper.selectList(null); + Map viewCountMap = articles.stream() + .collect(Collectors.toMap(article -> article.getId().toString(), article -> { + return article.getViewCount().intValue();// + })); + //存储到redis中 + redisCache.setCacheMap("article:viewCount",viewCountMap); + } +} + +~~~~ + + + +##### ②更新浏览量时去更新redsi中的数据 + +RedisCache增加方法 + +~~~~java + public void incrementCacheMapValue(String key,String hKey,long v){ + redisTemplate.boundHashOps(key).increment(hKey, v); + } +~~~~ + +ArticleController中增加方法更新阅读数 + +~~~~java + @PutMapping("/updateViewCount/{id}") + public ResponseResult updateViewCount(@PathVariable("id") Long id){ + return articleService.updateViewCount(id); + } +~~~~ + +ArticleService中增加方法 + +~~~~java +ResponseResult updateViewCount(Long id); +~~~~ + +ArticleServiceImpl中实现方法 + +~~~~java + @Override + public ResponseResult updateViewCount(Long id) { + //更新redis中对应 id的浏览量 + redisCache.incrementCacheMapValue("article:viewCount",id.toString(),1); + return ResponseResult.okResult(); + } +~~~~ + + + + + + + +##### ③定时任务每隔10分钟把Redis中的浏览量更新到数据库中 + +Article中增加构造方法 + +~~~~java + public Article(Long id, long viewCount) { + this.id = id; + this.viewCount = viewCount; + } +~~~~ + + + + + +~~~~java +@Component +public class UpdateViewCountJob { + + @Autowired + private RedisCache redisCache; + + @Autowired + private ArticleService articleService; + + @Scheduled(cron = "0/5 * * * * ?") + public void updateViewCount(){ + //获取redis中的浏览量 + Map viewCountMap = redisCache.getCacheMap("article:viewCount"); + + List
articles = viewCountMap.entrySet() + .stream() + .map(entry -> new Article(Long.valueOf(entry.getKey()), entry.getValue().longValue())) + .collect(Collectors.toList()); + //更新到数据库中 + articleService.updateBatchById(articles); + + } +} + +~~~~ + + + +##### ④读取文章浏览量时从redis读取 + +~~~~java + @Override + public ResponseResult getArticleDetail(Long id) { + //根据id查询文章 + Article article = getById(id); + //从redis中获取viewCount + Integer viewCount = redisCache.getCacheMapValue("article:viewCount", id.toString()); + article.setViewCount(viewCount.longValue()); + //转换成VO + ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class); + //根据分类id查询分类名 + Long categoryId = articleDetailVo.getCategoryId(); + Category category = categoryService.getById(categoryId); + if(category!=null){ + articleDetailVo.setCategoryName(category.getName()); + } + //封装响应返回 + return ResponseResult.okResult(articleDetailVo); + } + +~~~~ + + + + + +## 4. Swagger2 + +### 4.1 简介 + +​ Swagger 是一套基于 OpenAPI 规范构建的开源工具,可以帮助我们设计、构建、记录以及使用 Rest API。 + +### 4.2 为什么使用Swagger + +​ 当下很多公司都采取前后端分离的开发模式,前端和后端的工作由不同的工程师完成。在这种开发模式下,维持一份及时更新且完整的 Rest API 文档将会极大的提高我们的工作效率。传统意义上的文档都是后端开发人员手动编写的,相信大家也都知道这种方式很难保证文档的及时性,这种文档久而久之也就会失去其参考意义,反而还会加大我们的沟通成本。而 Swagger 给我们提供了一个全新的维护 API 文档的方式,下面我们就来了解一下它的优点: + +1.代码变,文档变。只需要少量的注解,Swagger 就可以根据代码自动生成 API 文档,很好的保证了文档的时效性。 +2.跨语言性,支持 40 多种语言。 +3.Swagger UI 呈现出来的是一份可交互式的 API 文档,我们可以直接在文档页面尝试 API 的调用,省去了准备复杂的调用参数的过程。 + + + +### 4.3 快速入门 + +#### 4.3.1 引入依赖 + +~~~~xml + + io.springfox + springfox-swagger2 + + + io.springfox + springfox-swagger-ui + + +~~~~ + + + +#### 4.3.2 启用Swagger2 + +​ 在启动类上或者配置类加 @EnableSwagger2 注解 + +~~~~java +@SpringBootApplication +@MapperScan("com.sangeng.mapper") +@EnableScheduling +@EnableSwagger2 +public class SanGengBlogApplication { + public static void main(String[] args) { + SpringApplication.run(SanGengBlogApplication.class,args); + } +} +~~~~ + + + +#### 4.3.3 测试 + +​ 访问:http://localhost:7777/swagger-ui.html 注意其中localhost和7777要调整成实际项目的域名和端口号。 + + + +### 4.4 具体配置 + + + +#### 4.4.1 Controller配置 + +##### 4.4.1 @Api 注解 + +属性介绍: + +tags 设置标签 + +description 设置描述信息 + +~~~~java +@RestController +@RequestMapping("/comment") +@Api(tags = "评论",description = "评论相关接口") +public class CommentController { +} +~~~~ + + + + + +#### 4.4.2 接口配置 + +##### 4.4.2.1 接口描述配置@ApiOperation + +~~~~java + @GetMapping("/linkCommentList") + @ApiOperation(value = "友链评论列表",notes = "获取一页友链评论") + public ResponseResult linkCommentList(Integer pageNum,Integer pageSize){ + return commentService.commentList(SystemConstants.LINK_COMMENT,null,pageNum,pageSize); + } +~~~~ + + + +##### 4.4.2.2 接口参数描述 + + @ApiImplicitParam 用于描述接口的参数,但是一个接口可能有多个参数,所以一般与 @ApiImplicitParams 组合使用。 + +~~~~java + @GetMapping("/linkCommentList") + @ApiOperation(value = "友链评论列表",notes = "获取一页友链评论") + @ApiImplicitParams({ + @ApiImplicitParam(name = "pageNum",value = "页号"), + @ApiImplicitParam(name = "pageSize",value = "每页大小") + } + ) + public ResponseResult linkCommentList(Integer pageNum,Integer pageSize){ + return commentService.commentList(SystemConstants.LINK_COMMENT,null,pageNum,pageSize); + } +~~~~ + + + +#### 4.4.3 实体类配置 + +##### 4.4.3.1 实体的描述配置@ApiModel + +@ApiModel用于描述实体类。 + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel(description = "添加评论dto") +public class AddCommentDto{ + //.. +} +~~~~ + + + +##### 4.4.3.2 实体的属性的描述配置@ApiModelProperty + +@ApiModelProperty用于描述实体的属性 + +~~~~java + @ApiModelProperty(notes = "评论类型(0代表文章评论,1代表友链评论)") + private String type; +~~~~ + + + + + + + +#### 4.4.4 文档信息配置 + +~~~~java +@Configuration +public class SwaggerConfig { + @Bean + public Docket customDocket() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("com.sangeng.controller")) + .build(); + } + + private ApiInfo apiInfo() { + Contact contact = new Contact("团队名", "http://www.my.com", "my@my.com"); + return new ApiInfoBuilder() + .title("文档标题") + .description("文档描述") + .contact(contact) // 联系方式 + .version("1.1.0") // 版本 + .build(); + } +} +~~~~ + + + +## 5. 博客后台 + +### 5.0 准备工作 + +前端工程启动 + +npm install + +npm run dev + + + +①创建启动类 + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@SpringBootApplication +@MapperScan("com.sangeng.mapper") +public class BlogAdminApplication { + public static void main(String[] args) { + SpringApplication.run(BlogAdminApplication.class, args); + } +} + +~~~~ + +②创建application.yml配置文件 + +~~~~yml +server: + port: 8989 +spring: + datasource: + url: jdbc:mysql://localhost:3306/sg_blog?characterEncoding=utf-8&serverTimezone=UTC + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + servlet: + multipart: + max-file-size: 2MB + max-request-size: 5MB + +mybatis-plus: + configuration: + # 日志 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + global-config: + db-config: + logic-delete-field: delFlag + logic-delete-value: 1 + logic-not-delete-value: 0 + id-type: auto + + +~~~~ + +③ SQL语句 + +​ SQL脚本:SGBlog\资源\SQL\sg_tag.sql + +④ 创建实体类,Mapper,Service + +​ 注意思考这些文件应该写在哪个模块下? + + + +Tag + +~~~~java + +@SuppressWarnings("serial") +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName("sg_tag") +public class Tag { + @TableId + private Long id; + + + private Long createBy; + + private Date createTime; + + private Long updateBy; + + private Date updateTime; + //删除标志(0代表未删除,1代表已删除) + private Integer delFlag; + //备注 + private String remark; + //标签名 + private String name; + + + +} + +~~~~ + + +TagMapper +~~~~java +/** + * 标签(Tag)表数据库访问层 + * + * @author makejava + * @since 2022-07-19 22:33:35 + */ +public interface TagMapper extends BaseMapper { + +} + + + +~~~~ + + +TagService +~~~~java +/** + * 标签(Tag)表服务接口 + * + * @author makejava + * @since 2022-07-19 22:33:38 + */ +public interface TagService extends IService { + +} + +~~~~ + + +TagServiceImpl +~~~~java +/** + * 标签(Tag)表服务实现类 + * + * @author makejava + * @since 2022-07-19 22:33:38 + */ +@Service("tagService") +public class TagServiceImpl extends ServiceImpl implements TagService { + +} + + +~~~~ + + + +⑤ 创建Controller测试接口 + +​ 注意思考这些文件应该写在哪个模块下? + +TagController /content/tag +~~~~java +@RestController +@RequestMapping("/content/tag") +public class TagController { + @Autowired + private TagService tagService; + + @GetMapping("/list") + public ResponseResult list(){ + return ResponseResult.okResult(tagService.list()); + } +} + + +~~~~ + + + +⑥添加security相关类 + +~~~~java +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + @Bean + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + + @Autowired + private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; + @Autowired + AuthenticationEntryPoint authenticationEntryPoint; + @Autowired + AccessDeniedHandler accessDeniedHandler; + + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 +// .antMatchers("/login").anonymous() +// //注销接口需要认证才能访问 +// .antMatchers("/logout").authenticated() +// .antMatchers("/user/userInfo").authenticated() +// .antMatchers("/upload").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().permitAll(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + //关闭默认的注销功能 + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } +} + +~~~~ + + + +~~~~java +@Component +public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { + + @Autowired + private RedisCache redisCache; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + //获取请求头中的token + String token = request.getHeader("token"); + if(!StringUtils.hasText(token)){ + //说明该接口不需要登录 直接放行 + filterChain.doFilter(request, response); + return; + } + //解析获取userid + Claims claims = null; + try { + claims = JwtUtil.parseJWT(token); + } catch (Exception e) { + e.printStackTrace(); + //token超时 token非法 + //响应告诉前端需要重新登录 + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + WebUtils.renderString(response, JSON.toJSONString(result)); + return; + } + String userId = claims.getSubject(); + //从redis中获取用户信息 + LoginUser loginUser = redisCache.getCacheObject("login:" + userId); + //如果获取不到 + if(Objects.isNull(loginUser)){ + //说明登录过期 提示重新登录 + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); + WebUtils.renderString(response, JSON.toJSONString(result)); + return; + } + //存入SecurityContextHolder + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,null); + SecurityContextHolder.getContext().setAuthentication(authenticationToken); + + filterChain.doFilter(request, response); + } + + +} + +~~~~ + + + +### 5.1 后台登录 + +​ 后台的认证授权也使用SpringSecurity安全框架来实现。 + +#### 5.1.0 需求 + +​ 需要实现登录功能 + +​ 后台所有功能都必须登录才能使用。 + +#### 5.1.1 接口设计 + +| 请求方式 | 请求路径 | +| -------- | ----------- | +| POST | /user/login | + +请求体: + +~~~~json +{ + "userName":"sg", + "password":"1234" +} +~~~~ + +响应格式: + +~~~~json +{ + "code": 200, + "data": { + "token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0ODBmOThmYmJkNmI0NjM0OWUyZjY2NTM0NGNjZWY2NSIsInN1YiI6IjEiLCJpc3MiOiJzZyIsImlhdCI6MTY0Mzg3NDMxNiwiZXhwIjoxNjQzOTYwNzE2fQ.ldLBUvNIxQCGemkCoMgT_0YsjsWndTg5tqfJb77pabk" + }, + "msg": "操作成功" +} +~~~~ + +#### 5.1.2 思路分析 + +登录 + +​ ①自定义登录接口 + +​ 调用ProviderManager的方法进行认证 如果认证通过生成jwt + +​ 把用户信息存入redis中 + +​ ②自定义UserDetailsService + +​ 在这个实现类中去查询数据库 + +​ 注意配置passwordEncoder为BCryptPasswordEncoder + +校验: + +​ ①定义Jwt认证过滤器 + +​ 获取token + +​ 解析token获取其中的userid + +​ 从redis中获取用户信息 + +​ 存入SecurityContextHolder + +#### 5.1.3 准备工作 + +①添加依赖 + +前面已经添加过相关依赖,不需要做什么处理 + +~~~~xml + + + org.springframework.boot + spring-boot-starter-data-redis + + + + com.alibaba + fastjson + 1.2.33 + + + + io.jsonwebtoken + jjwt + 0.9.0 + +~~~~ + + + + + +#### 5.1.4 登录接口代码实现 + +##### LoginController + +复制一份BlogLoginController ,命名为LoginController,其中注入 LoginService + +请求地址修改为/user/login即可 + + + +~~~~java +@RestController +public class LoginController { + @Autowired + private LoginService loginService; + + @PostMapping("/user/login") + public ResponseResult login(@RequestBody User user){ + if(!StringUtils.hasText(user.getUserName())){ + //提示 必须要传用户名 + throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME); + } + return loginService.login(user); + } + +} +~~~~ + + + +##### LoginService + +复制一份BlogLoginService命名为LoginService即可 + +~~~~java +public interface LoginService { + ResponseResult login(User user); + +} + +~~~~ + + + +##### SecurityConfig + +之前已经复制过了 + + + + + +##### SystemLoginServiceImpl + +复制一份,LoginServiceImpl,命名为SystemLoginServiceImpl 实现 LoginService + +login方法中存redis的key的前缀修改为login + +返回的数据中只要返回token + + + +~~~~java +@Service +public class SystemLoginServiceImpl implements LoginService { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private RedisCache redisCache; + + @Override + public ResponseResult login(User user) { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword()); + Authentication authenticate = authenticationManager.authenticate(authenticationToken); + //判断是否认证通过 + if(Objects.isNull(authenticate)){ + throw new RuntimeException("用户名或密码错误"); + } + //获取userid 生成token + LoginUser loginUser = (LoginUser) authenticate.getPrincipal(); + String userId = loginUser.getUser().getId().toString(); + String jwt = JwtUtil.createJWT(userId); + //把用户信息存入redis + redisCache.setCacheObject("login:"+userId,loginUser); + + //把token封装 返回 + Map map = new HashMap<>(); + map.put("token",jwt); + return ResponseResult.okResult(map); + } +} +~~~~ + + + +##### UserDetailServiceImpl + +复用原来的即可 + +##### LoginUser + +复用原来的即可 + + + + + +### 5.2 后台权限控制及动态路由 + +#### 需求 + +​ 后台系统需要能实现不同的用户权限可以看到不同的功能。 + +​ 用户只能使用他的权限所允许使用的功能。 + + + +#### 功能设计 + +​ 之前在我的SpringSecurity的课程中就介绍过RBAC权限模型。没有学习过的可以去看下 [RBAC权限模型](https://www.bilibili.com/video/BV1mm4y1X7Hc?p=28) 。这里我们就是在RBAC权限模型的基础上去实现这个功能。 + +​ + +#### 表分析 + +​ 通过需求去分析需要有哪些字段。 + +​ 建表SQL及初始化数据见:SGBlog\资源\SQL\sg_menu.sql + + + +#### 接口设计 + +##### getInfo接口 + +是 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | --------------- | +| GET | /getInfo | 需要token请求头 | + +请求参数: + +无 + +响应格式: + +如果用户id为1代表管理员,roles 中只需要有admin,permissions中需要有所有菜单类型为C或者F的,状态为正常的,未被删除的权限 + +~~~~json +{ + "code":200, + "data":{ + "permissions":[ + "system:user:list", + "system:role:list", + "system:menu:list", + "system:user:query", + "system:user:add" + //此次省略1000字 + ], + "roles":[ + "admin" + ], + "user":{ + "avatar":"http://r7yxkqloa.bkt.clouddn.com/2022/03/05/75fd15587811443a9a9a771f24da458d.png", + "email":"23412332@qq.com", + "id":1, + "nickName":"sg3334", + "sex":"1" + } + }, + "msg":"操作成功" +} +~~~~ + + + +##### getRouters接口 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------- | --------------- | +| GET | /getRouters | 需要token请求头 | + +请求参数: + +无 + +响应格式: + +​ 前端为了实现动态路由的效果,需要后端有接口能返回用户所能访问的菜单数据。 + +​ 注意:**返回的菜单数据需要体现父子菜单的层级关系** + +​ 如果用户id为1代表管理员,menus中需要有所有菜单类型为C或者M的,状态为正常的,未被删除的权限 + +​ 数据格式如下: + +~~~~json +{ + "code":200, + "data":{ + "menus":[ + { + "children":[], + "component":"content/article/write/index", + "createTime":"2022-01-08 11:39:58", + "icon":"build", + "id":2023, + "menuName":"写博文", + "menuType":"C", + "orderNum":"0", + "parentId":0, + "path":"write", + "perms":"content:article:writer", + "status":"0", + "visible":"0" + }, + { + "children":[ + { + "children":[], + "component":"system/user/index", + "createTime":"2021-11-12 18:46:19", + "icon":"user", + "id":100, + "menuName":"用户管理", + "menuType":"C", + "orderNum":"1", + "parentId":1, + "path":"user", + "perms":"system:user:list", + "status":"0", + "visible":"0" + }, + { + "children":[], + "component":"system/role/index", + "createTime":"2021-11-12 18:46:19", + "icon":"peoples", + "id":101, + "menuName":"角色管理", + "menuType":"C", + "orderNum":"2", + "parentId":1, + "path":"role", + "perms":"system:role:list", + "status":"0", + "visible":"0" + }, + { + "children":[], + "component":"system/menu/index", + "createTime":"2021-11-12 18:46:19", + "icon":"tree-table", + "id":102, + "menuName":"菜单管理", + "menuType":"C", + "orderNum":"3", + "parentId":1, + "path":"menu", + "perms":"system:menu:list", + "status":"0", + "visible":"0" + } + ], + "createTime":"2021-11-12 18:46:19", + "icon":"system", + "id":1, + "menuName":"系统管理", + "menuType":"M", + "orderNum":"1", + "parentId":0, + "path":"system", + "perms":"", + "status":"0", + "visible":"0" + } + ] + }, + "msg":"操作成功" +} +~~~~ + + + +#### 代码实现 + +##### 准备工作 + +​ 生成menu和role表对于的类 + +##### getInfo接口 + + + +```java +@Data +@Accessors(chain = true) +@AllArgsConstructor +@NoArgsConstructor +public class AdminUserInfoVo { + + private List permissions; + + private List roles; + + private UserInfoVo user; +} +``` + + + +~~~~java +@RestController +public class LoginController { + @Autowired + private LoginService loginService; + + @Autowired + private MenuService menuService; + + @Autowired + private RoleService roleService; + + @PostMapping("/user/login") + public ResponseResult login(@RequestBody User user){ + if(!StringUtils.hasText(user.getUserName())){ + //提示 必须要传用户名 + throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME); + } + return loginService.login(user); + } + + @GetMapping("getInfo") + public ResponseResult getInfo(){ + //获取当前登录的用户 + LoginUser loginUser = SecurityUtils.getLoginUser(); + //根据用户id查询权限信息 + List perms = menuService.selectPermsByUserId(loginUser.getUser().getId()); + //根据用户id查询角色信息 + List roleKeyList = roleService.selectRoleKeyByUserId(loginUser.getUser().getId()); + + //获取用户信息 + User user = loginUser.getUser(); + UserInfoVo userInfoVo = BeanCopyUtils.copyBean(user, UserInfoVo.class); + //封装数据返回 + + AdminUserInfoVo adminUserInfoVo = new AdminUserInfoVo(perms,roleKeyList,userInfoVo); + return ResponseResult.okResult(adminUserInfoVo); + } + +} +~~~~ + + + + + +RoleServiceImpl selectRoleKeyByUserId方法 + +~~~~java +@Service("menuService") +public class MenuServiceImpl extends ServiceImpl implements MenuService { + + @Override + public List selectPermsByUserId(Long id) { + //如果是管理员,返回所有的权限 + if(id == 1L){ + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(Menu::getMenuType,SystemConstants.MENU,SystemConstants.BUTTON); + wrapper.eq(Menu::getStatus,SystemConstants.STATUS_NORMAL); + List menus = list(wrapper); + List perms = menus.stream() + .map(Menu::getPerms) + .collect(Collectors.toList()); + return perms; + } + //否则返回所具有的权限 + return getBaseMapper().selectPermsByUserId(id); + } +} +~~~~ + +MenuMapper + +~~~~java +/** + * 菜单权限表(Menu)表数据库访问层 + * + * @author makejava + * @since 2022-08-09 22:32:07 + */ +public interface MenuMapper extends BaseMapper { + + List selectPermsByUserId(Long userId); +} + +~~~~ + +~~~~xml + + + + + + +~~~~ + + + + + +MenuServiceImpl selectPermsByUserId方法 + +~~~~java +@Service("roleService") +public class RoleServiceImpl extends ServiceImpl implements RoleService { + + @Override + public List selectRoleKeyByUserId(Long id) { + //判断是否是管理员 如果是返回集合中只需要有admin + if(id == 1L){ + List roleKeys = new ArrayList<>(); + roleKeys.add("admin"); + return roleKeys; + } + //否则查询用户所具有的角色信息 + return getBaseMapper().selectRoleKeyByUserId(id); + } +} +~~~~ + +~~~~java +public interface RoleMapper extends BaseMapper { + + List selectRoleKeyByUserId(Long userId); +} + +~~~~ + +~~~~xml + + + + + +~~~~ + + + + + +##### getRouters接口 + +RoutersVo + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RoutersVo { + + private List menus; +} + +~~~~ + + + +LoginController + +~~~~java + @GetMapping("getRouters") + public ResponseResult getRouters(){ + Long userId = SecurityUtils.getUserId(); + //查询menu 结果是tree的形式 + List menus = menuService.selectRouterMenuTreeByUserId(userId); + //封装数据返回 + return ResponseResult.okResult(new RoutersVo(menus)); + } + +~~~~ + +MenuService + +~~~~java +public interface MenuService extends IService { + + List selectPermsByUserId(Long id); + + List selectRouterMenuTreeByUserId(Long userId); +} + +~~~~ + +MenuServiceImpl + +~~~~java +@Override + public List selectRouterMenuTreeByUserId(Long userId) { + MenuMapper menuMapper = getBaseMapper(); + List menus = null; + //判断是否是管理员 + if(SecurityUtils.isAdmin()){ + //如果是 获取所有符合要求的Menu + menus = menuMapper.selectAllRouterMenu(); + }else{ + //否则 获取当前用户所具有的Menu + menus = menuMapper.selectRouterMenuTreeByUserId(userId); + } + + //构建tree + //先找出第一层的菜单 然后去找他们的子菜单设置到children属性中 + List menuTree = builderMenuTree(menus,0L); + return menuTree; + } + + private List builderMenuTree(List menus, Long parentId) { + List menuTree = menus.stream() + .filter(menu -> menu.getParentId().equals(parentId)) + .map(menu -> menu.setChildren(getChildren(menu, menus))) + .collect(Collectors.toList()); + return menuTree; + } + + /** + * 获取存入参数的 子Menu集合 + * @param menu + * @param menus + * @return + */ + private List getChildren(Menu menu, List menus) { + List childrenList = menus.stream() + .filter(m -> m.getParentId().equals(menu.getId())) + .map(m->m.setChildren(getChildren(m,menus))) + .collect(Collectors.toList()); + return childrenList; + } +~~~~ + +MenuMapper.java + +~~~~java + List selectAllRouterMenu(); + + List selectRouterMenuTreeByUserId(Long userId); +~~~~ + + + +MenuMapper.xml + +~~~~xml + + +~~~~ + + + +查询的列: + +SELECT DISTINCT m.id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status, IFNULL(m.perms,'') AS perms, m.is_frame, m.menu_type, m.icon, m.order_num, m.create_time + +注意需要按照parent_id和order_num排序 + + + + + +### 5.3 退出登录接口 + +#### 5.3.1 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------ | --------------- | +| POST | /user/logout | 需要token请求头 | + +响应格式: + +~~~~json +{ + "code": 200, + "msg": "操作成功" +} +~~~~ + + + +#### 5.3.2 代码实现 + +要实现的操作: + +​ 删除redis中的用户信息 + +LoginController + +~~~~java + @PostMapping("/user/logout") + public ResponseResult logout(){ + return loginServce.logout(); + } +~~~~ + +LoginService + +~~~~java +ResponseResult logout(); +~~~~ + +SystemLoginServiceImpl + +~~~~java + @Override + public ResponseResult logout() { + //获取当前登录的用户id + Long userId = SecurityUtils.getUserId(); + //删除redis中对应的值 + redisCache.deleteObject("login:"+userId); + return ResponseResult.okResult(); + } +~~~~ + +SecurityConfig + +要关闭默认的退出登录功能。并且要配置我们的退出登录接口需要认证才能访问 + +~~~~java + @Override + protected void configure(HttpSecurity http) throws Exception { + http + //关闭csrf + .csrf().disable() + //不通过Session获取SecurityContext + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + // 对于登录接口 允许匿名访问 + .antMatchers("/user/login").anonymous() +// //注销接口需要认证才能访问 +// .antMatchers("/logout").authenticated() +// .antMatchers("/user/userInfo").authenticated() +// .antMatchers("/upload").authenticated() + // 除上面外的所有请求全部不需要认证即可访问 + .anyRequest().authenticated(); + + //配置异常处理器 + http.exceptionHandling() + .authenticationEntryPoint(authenticationEntryPoint) + .accessDeniedHandler(accessDeniedHandler); + //关闭默认的注销功能 + http.logout().disable(); + //把jwtAuthenticationTokenFilter添加到SpringSecurity的过滤器链中 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); + //允许跨域 + http.cors(); + } +~~~~ + + + + + + + + + + + +### 5.4 查询标签列表 + +#### 5.4.0 需求 + +​ 为了方便后期对文章进行管理,需要提供标签的功能,一个文章可以有多个标签。 + +​ 在后台需要分页查询标签功能,要求能根据标签名进行分页查询。 **后期可能会增加备注查询等需求**。 + +​ 注意:不能把删除了的标签查询出来。 + +#### 5.4.1 标签表分析 + +​ 通过需求去分析需要有哪些字段。 + +#### 5.4.2 接口设计 + + + +| 请求方式 | 请求路径 | +| -------- | ---------------- | +| Get | content/tag/list | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +name:标签名 + +remark:备注 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "id":4, + "name":"Java", + "remark":"sdad" + } + ], + "total":1 + }, + "msg":"操作成功" +} +~~~~ + + + +#### 5.4.3 代码实现 + +Controller + +~~~~java +@RestController +@RequestMapping("/content/tag") +public class TagController { + @Autowired + private TagService tagService; + + @GetMapping("/list") + public ResponseResult list(Integer pageNum, Integer pageSize, TagListDto tagListDto){ + return tagService.pageTagList(pageNum,pageSize,tagListDto); + } +} + + +~~~~ + + + +Service + +```java +public interface TagService extends IService { + + ResponseResult pageTagList(Integer pageNum, Integer pageSize, TagListDto tagListDto); +} + +``` + +~~~~java +@Service("tagService") +public class TagServiceImpl extends ServiceImpl implements TagService { + + @Override + public ResponseResult pageTagList(Integer pageNum, Integer pageSize, TagListDto tagListDto) { + //分页查询 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(StringUtils.hasText(tagListDto.getName()),Tag::getName,tagListDto.getName()); + queryWrapper.eq(StringUtils.hasText(tagListDto.getRemark()),Tag::getRemark,tagListDto.getRemark()); + + Page page = new Page<>(); + page.setCurrent(pageNum); + page.setSize(pageSize); + page(page, queryWrapper); + //封装数据返回 + PageVo pageVo = new PageVo(page.getRecords(),page.getTotal()); + return ResponseResult.okResult(pageVo); + } +} +~~~~ + + + +### 5.5 新增标签 + +#### 5.5.0 需求 + +​ 点击标签管理的新增按钮可以实现新增标签的功能。 + +#### 5.5.1 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------ | --------------- | +| POST | /content/tag | 需要token请求头 | + +请求体格式: + +~~~~json +{"name":"c#","remark":"c++++"} +~~~~ + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 5.5.2 测试 + +测试时注意,添加到数据库中的记录有没有 创建时间,更新时间,创建人,更新人字段。 + + + + + +### 5.6 删除标签 + +#### 5.6.1 接口设计 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------------- | --------------- | +| DELETE | /content/tag/{id} | 需要token请求头 | + +请求参数在path中 + +例如:content/tag/6 代表删除id为6的标签数据 + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 5.6.2 测试 + +注意测试删除后在列表中是否查看不到该条数据 + +数据库中该条数据还是存在的,只是修改了逻辑删除字段的值 + + + + + +### 5.7 修改标签 + +#### 5.7.1 接口设计 + +##### 5.7.1.1 获取标签信息 + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------------- | --------------- | +| GET | /content/tag/{id} | 需要token请求头 | + +请求参数在path中 + +例如:content/tag/6 代表获取id为6的标签数据 + + + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "id":4, + "name":"Java", + "remark":"sdad" + }, + "msg":"操作成功" +} +~~~~ + + + +##### 5.7.1.2 修改标签接口 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------ | --------------- | +| PUT | /content/tag | 需要token请求头 | + +请求体格式: + +~~~~json +{"id":7,"name":"c#","remark":"c++++"} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.8 写博文 + +#### 5.8.1 需求 + +​ 需要提供写博文的功能,写博文时需要关联分类和标签。 + +​ 可以上传缩略图,也可以在正文中添加图片。 + +​ 文章可以直接发布,也可以保存到草稿箱。 + + + +#### 5.8.2 表分析 + +​ 标签和文章需要关联所以需要一张关联表。 + +​ SQL脚本:SGBlog\资源\SQL\sg_article_tag.sql + + + +#### 5.8.2 接口设计 + +​ 思考下需要哪些接口才能实现这个功能? + + + +##### 5.8.2.1 查询所有分类接口 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | --------------------------------- | --------------- | +| GET | /content/category/listAllCategory | 需要token请求头 | + +请求参数: + +​ 无 + + + + + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "description":"wsd", + "id":1, + "name":"java" + }, + { + "description":"wsd", + "id":2, + "name":"PHP" + } + ], + "msg":"操作成功" +} +~~~~ + + + +##### 5.8.2.2 查询所有标签接口 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ----------------------- | --------------- | +| GET | /content/tag/listAllTag | 需要token请求头 | + +请求参数: + +​ 无 + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "id":1, + "name":"Mybatis" + }, + { + "id":4, + "name":"Java" + } + ], + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.8.2.3 上传图片 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | -------- | --------------- | +| POST | /upload | 需要token请求头 | + +参数: + +​ img,值为要上传的文件 + +请求头: + +​ Content-Type :multipart/form-data; + + + +响应格式: + +~~~~json +{ + "code": 200, + "data": "文件访问链接", + "msg": "操作成功" +} +~~~~ + + + +##### 5.8.2.4 新增博文 + + + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ---------------- | --------------- | +| POST | /content/article | 需要token请求头 | + +请求体格式: + +~~~~json +{ + "title":"测试新增博文", + "thumbnail":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/21/4ceebc07e7484beba732f12b0d2c43a9.png", + "isTop":"0", + "isComment":"0", + "content":"# 一级标题\n## 二级标题\n![Snipaste_20220228_224837.png](https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/21/c3af554d4a0f4935b4073533a4c26ee8.png)\n正文", + "tags":[ + 1, + 4 + ], + "categoryId":1, + "summary":"哈哈", + "status":"1" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +#### 5.8.3 代码实现 + + + +##### 5.8.3.1 查询所有分类接口 + +CategoryController + + + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@RestController +@RequestMapping("/content/category") +public class CategoryController { + @Autowired + private CategoryService categoryService; + + @GetMapping("/listAllCategory") + public ResponseResult listAllCategory(){ + List list = categoryService.listAllCategory(); + return ResponseResult.okResult(list); + } + + +} + +~~~~ + + + +CategoryVo修改,增加description属性 + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CategoryVo { + + private Long id; + private String name; + //描述 + private String description; +} +~~~~ + +CategoryService增加listAllCategory方法 + +~~~~java +public interface CategoryService extends IService { + + + ResponseResult getCategoryList(); + + List listAllCategory(); +} + +~~~~ + +SystemConstants中增加常量 + +~~~~java + /** 正常状态 */ + public static final String NORMAL = "0"; +~~~~ + + + + + +CategoryServiceImpl增加方法 + +~~~~java + @Override + public List listAllCategory() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(Category::getStatus, SystemConstants.NORMAL); + List list = list(wrapper); + List categoryVos = BeanCopyUtils.copyBeanList(list, CategoryVo.class); + return categoryVos; + } +~~~~ + + + + + +##### 5.8.3.2 查询所有标签接口 + +TagVo + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TagVo { + private Long id; + + //标签名 + private String name; + + + +} + +~~~~ + + + +TagController + +~~~~java + @GetMapping("/listAllTag") + public ResponseResult listAllTag(){ + List list = tagService.listAllTag(); + return ResponseResult.okResult(list); + } +~~~~ + + + +TagService 增加listAllTag方法 + +~~~~java +List listAllTag(); + +~~~~ + +TagServiceImpl + +~~~~java + @Override + public List listAllTag() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.select(Tag::getId,Tag::getName); + List list = list(wrapper); + List tagVos = BeanCopyUtils.copyBeanList(list, TagVo.class); + return tagVos; + } +~~~~ + + + + + +##### 5.8.3.3 上传图片接口 + +在sangeng-admin中增加UploadController + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@RestController +public class UploadController { + + @Autowired + private UploadService uploadService; + + @PostMapping("/upload") + public ResponseResult uploadImg(@RequestParam("img") MultipartFile multipartFile) { + try { + return uploadService.uploadImg(multipartFile); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException("文件上传上传失败"); + } + } +} +~~~~ + + + + + + + +##### 5.8.3.4 新增博文接口 + + + +ArticleController + +~~~~java +/** + * @Author 三更 B站: https://space.bilibili.com/663528522 + */ +@RestController +@RequestMapping("/content/article") +public class ArticleController { + + @Autowired + private ArticleService articleService; + + @PostMapping + public ResponseResult add(@RequestBody AddArticleDto article){ + return articleService.add(article); + } + + +} + +~~~~ + + + +AddArticleDto + +注意增加tags属性用于接收文章关联标签的id + +~~~~java +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AddArticleDto { + + private Long id; + //标题 + private String title; + //文章内容 + private String content; + //文章摘要 + private String summary; + //所属分类id + private Long categoryId; + + //缩略图 + private String thumbnail; + //是否置顶(0否,1是) + private String isTop; + //状态(0已发布,1草稿) + private String status; + //访问量 + private Long viewCount; + //是否允许评论 1是,0否 + private String isComment; + private List tags; + +} + +~~~~ + + + + + + + +Article 修改这样创建时间创建人修改时间修改人可以自动填充 + +~~~~java + @TableField(fill = FieldFill.INSERT) + private Long createBy; + @TableField(fill = FieldFill.INSERT) + private Date createTime; + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; +~~~~ + + + + + +ArticleService增加方法 + +~~~~java +ResponseResult add(AddArticleDto article); +~~~~ + + + +创建ArticleTag表相关的实体类,mapper,service,serviceimpl等 + +```java +@TableName(value="sg_article_tag") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ArticleTag implements Serializable { + private static final long serialVersionUID = 625337492348897098L; + + /** + * 文章id + */ + private Long articleId; + /** + * 标签id + */ + private Long tagId; + + + +} +``` + + + + + +ArticleServiceImpl增加如下代码 + +~~~~java + @Autowired + private ArticleTagService articleTagService; + + @Override + @Transactional + public ResponseResult add(AddArticleDto articleDto) { + //添加 博客 + Article article = BeanCopyUtils.copyBean(articleDto, Article.class); + save(article); + + + List articleTags = articleDto.getTags().stream() + .map(tagId -> new ArticleTag(article.getId(), tagId)) + .collect(Collectors.toList()); + + //添加 博客和标签的关联 + articleTagService.saveBatch(articleTags); + return ResponseResult.okResult(); + } +~~~~ + + + + + + + +### 5.9 导出所有分类到Excel + +#### 5.9.1 需求 + + + +​ 在分类管理中点击导出按钮可以把所有的分类导出到Excel文件中。 + +​ + +#### 5.9.2 技术方案 + +​ 使用EasyExcel实现Excel的导出操作。 + +​ https://github.com/alibaba/easyexcel + +​ https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write#%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81-1 + +#### 5.9.3 接口设计 + +​ + +| 请求方式 | 请求地址 | 请求头 | +| -------- | ------------------------ | --------------- | +| GET | /content/category/export | 需要token请求头 | + +请求参数: + +​ 无 + + + + + +响应格式: + +成功的话可以直接导出一个Excel文件 + + + +失败的话响应格式如下: + +~~~~json +{ + "code":500, + "msg":"出现错误" +} +~~~~ + + + +#### 5.9.4 代码实现 + +工具类方法修改 + +WebUtils + +~~~~java + public static void setDownLoadHeader(String filename, HttpServletResponse response) throws UnsupportedEncodingException { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fname= URLEncoder.encode(filename,"UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition","attachment; filename="+fname); + } +~~~~ + + + +CategoryController + +~~~~java + @GetMapping("/export") + public void export(HttpServletResponse response){ + try { + //设置下载文件的请求头 + WebUtils.setDownLoadHeader("分类.xlsx",response); + //获取需要导出的数据 + List categoryVos = categoryService.list(); + + List excelCategoryVos = BeanCopyUtils.copyBeanList(categoryVos, ExcelCategoryVo.class); + //把数据写入到Excel中 + EasyExcel.write(response.getOutputStream(), ExcelCategoryVo.class).autoCloseStream(Boolean.FALSE).sheet("分类导出") + .doWrite(excelCategoryVos); + + } catch (Exception e) { + //如果出现异常也要响应json + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR); + WebUtils.renderString(response, JSON.toJSONString(result)); + } + } +~~~~ + + + + + +ExcelCategoryVo + +~~~~java +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ExcelCategoryVo { + @ExcelProperty("分类名") + private String name; + //描述 + @ExcelProperty("描述") + private String description; + + //状态0:正常,1禁用 + @ExcelProperty("状态0:正常,1禁用") + private String status; +} + +~~~~ + + + +### 5.10 权限控制 + +#### 5.10.1 需求 + +​ 需要对导出分类的接口做权限控制。 + +sg eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJkZGJkNjM5MWJiZTA0NmMzOTc4NDg1ZTcxNWQ3YjQ0MSIsInN1YiI6IjEiLCJpc3MiOiJzZyIsImlhdCI6MTY2MjI0NDE4NywiZXhwIjoxNjYyMzMwNTg3fQ.z4JGwFN3lWyVbOCbhikCe-O4D6SvCQFEE5eQY3jDJkw + +sangeng + +eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI0Y2I1ZjhmMTc0Mjk0NzM0YjI4Y2M1NTQzYjQ2Yjc1YyIsInN1YiI6IjYiLCJpc3MiOiJzZyIsImlhdCI6MTY2MjI0NDQzMywiZXhwIjoxNjYyMzMwODMzfQ.yEkbyGYXBp5ndnyq-3acdgpvqx2mnI8B9fK9f3Y6Jco + +#### 5.10.2 代码实现 + + + +SecurityConfig + +~~~~java +@EnableGlobalMethodSecurity(prePostEnabled = true) +~~~~ + + + + + +UserDetailsServiceImpl + +~~~~java +@Service +public class UserDetailsServiceImpl implements UserDetailsService { + + @Autowired + private UserMapper userMapper; + + @Autowired + private MenuMapper menuMapper; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + //根据用户名查询用户信息 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(User::getUserName,username); + User user = userMapper.selectOne(queryWrapper); + //判断是否查到用户 如果没查到抛出异常 + if(Objects.isNull(user)){ + throw new RuntimeException("用户不存在"); + } + //返回用户信息 + if(user.getType().equals(SystemConstants.ADMAIN)){ + List list = menuMapper.selectPermsByUserId(user.getId()); + return new LoginUser(user,list); + } + return new LoginUser(user,null); + } +} + +~~~~ + + + +LoginUser + +增加属性 + +~~~~java +private List permissions; +~~~~ + + + + + +PermissionService + +hasPermisson + +~~~~java + +@Service("ps") +public class PermissionService { + + /** + * 判断当前用户是否具有permission + * @param permission 要判断的权限 + * @return + */ + public boolean hasPermission(String permission){ + //如果是超级管理员 直接返回true + if(SecurityUtils.isAdmin()){ + return true; + } + //否则 获取当前登录用户所具有的权限列表 如何判断是否存在permission + List permissions = SecurityUtils.getLoginUser().getPermissions(); + return permissions.contains(permission); + } +} +~~~~ + + + +CategoryController + +~~~~java + + @PreAuthorize("@ps.hasPermission('content:category:export')") + @GetMapping("/export") + public void export(HttpServletResponse response){ + try { + //设置下载文件的请求头 + WebUtils.setDownLoadHeader("分类.xlsx",response); + //获取需要导出的数据 + List categoryVos = categoryService.list(); + + List excelCategoryVos = BeanCopyUtils.copyBeanList(categoryVos, ExcelCategoryVo.class); + //把数据写入到Excel中 + EasyExcel.write(response.getOutputStream(), ExcelCategoryVo.class).autoCloseStream(Boolean.FALSE).sheet("分类导出") + .doWrite(excelCategoryVos); + + } catch (Exception e) { + //如果出现异常也要响应json + ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR); + WebUtils.renderString(response, JSON.toJSONString(result)); + } + } +~~~~ + + + + + +### 5.11 文章列表 + +#### 5.10.1 需求 + +​ 为了对文章进行管理,需要提供文章列表, + +​ 在后台需要分页查询文章功能,要求能根据标题和摘要**模糊查询**。 + +​ 注意:不能把删除了的文章查询出来 + + + +#### 5.10.2 接口设计 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------------- | --------------- | +| Get | /content/article/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +title:文章标题 + +summary:文章摘要 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "categoryId":"1", + "content":"嘻嘻嘻嘻嘻嘻", + "createTime":"2022-01-24 07:20:11", + "id":"1", + "isComment":"0", + "isTop":"1", + "status":"0", + "summary":"SpringSecurity框架教程-Spring Security+JWT实现项目级前端分离认证授权", + "thumbnail":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/01/31/948597e164614902ab1662ba8452e106.png", + "title":"SpringSecurity从入门到精通", + "viewCount":"161" + } + ], + "total":"1" + }, + "msg":"操作成功" +} +~~~~ + + + +​ + +### 5.12 修改文章 + +#### 5.12.1 需求 + +​ 点击文章列表中的修改按钮可以跳转到写博文页面。回显示该文章的具体信息。 + +​ 用户可以在该页面修改文章信息。点击更新按钮后修改文章。 + + + + + +#### 5.12.2 分析 + +​ 这个功能的实现首先需要能够根据文章id查询文章的详细信息这样才能实现文章的回显。 + +​ 如何需要提供更新文章的接口。 + + + +#### 5.12.3 接口设计 + +##### 5.12.3.1 查询文章详情接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | -------------------- | --------------- | +| Get | content/article/{id} | 是 | + +Path格式请求参数: + +id: 文章id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "categoryId":"1", + "content":"xxxxxxx", + "createBy":"1", + "createTime":"2022-08-28 15:15:46", + "delFlag":0, + "id":"10", + "isComment":"0", + "isTop":"1", + "status":"0", + "summary":"啊实打实", + "tags":[ + "1", + "4", + "5" + ], + "thumbnail":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/28/7659aac2b74247fe8ebd9e054b916dbf.png", + "title":"委屈饿驱蚊器", + "updateBy":"1", + "updateTime":"2022-08-28 15:15:46", + "viewCount":"0" + }, + "msg":"操作成功" +} +~~~~ + + + +##### 5.12.3.2 更新文章接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------- | --------------- | +| PUT | content/article | 是 | + +请求体参数格式: + +~~~~json +{ + "categoryId":"1", + "content":"![Snipaste_20220228_224837.png](https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/28/f3938a0368c540ee909ba7f7079a829a.png)\n\n# 十大\n## 时代的", + "createBy":"1", + "createTime":"2022-08-28 15:15:46", + "delFlag":0, + "id":"10", + "isComment":"0", + "isTop":"1", + "status":"0", + "summary":"啊实打实2", + "tags":[ + "1", + "4", + "5" + ], + "thumbnail":"https://sg-blog-oss.oss-cn-beijing.aliyuncs.com/2022/08/28/7659aac2b74247fe8ebd9e054b916dbf.png", + "title":"委屈饿驱蚊器", + "updateBy":"1", + "updateTime":"2022-08-28 15:15:46", + "viewCount":"0" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.13 删除文章 + +#### 5.13.1 需求 + +​ 点击文章后面的删除按钮可以删除该文章 + +​ 注意:是逻辑删除不是物理删除 + +#### 5.13.2 接口设计 + +​ + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | -------------------- | --------------- | +| DELETE | content/article/{id} | 是 | + +Path请求参数: + +id:要删除的文章id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + + + +### 5.14 菜单列表 + +#### 5.14.1 需求 + +​ 需要展示菜单列表,不需要分页。 + +​ 可以针对菜单名进行模糊查询 + +​ 也可以针对菜单的状态进行查询。 + +​ 菜单要按照父菜单id和orderNum进行排序 + +#### 5.14.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| GET | system/menu/list | 是 | + +Query请求参数: + +status : 状态 + +menuName: 菜单名 + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "component":"content/article/write/index", + "icon":"build", + "id":"2023", + "isFrame":1, + "menuName":"写博文", + "menuType":"C", + "orderNum":0, + "parentId":"0", + "path":"write", + "perms":"content:article:writer", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"system", + "id":"1", + "isFrame":1, + "menuName":"系统管理", + "menuType":"M", + "orderNum":1, + "parentId":"0", + "path":"system", + "perms":"", + "remark":"系统管理目录", + "status":"0", + "visible":"0" + }, + { + "icon":"table", + "id":"2017", + "isFrame":1, + "menuName":"内容管理", + "menuType":"M", + "orderNum":4, + "parentId":"0", + "path":"content", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"system/user/index", + "icon":"user", + "id":"100", + "isFrame":1, + "menuName":"用户管理", + "menuType":"C", + "orderNum":1, + "parentId":"1", + "path":"user", + "perms":"system:user:list", + "remark":"用户管理菜单", + "status":"0", + "visible":"0" + }, + { + "component":"system/role/index", + "icon":"peoples", + "id":"101", + "isFrame":1, + "menuName":"角色管理", + "menuType":"C", + "orderNum":2, + "parentId":"1", + "path":"role", + "perms":"system:role:list", + "remark":"角色管理菜单", + "status":"0", + "visible":"0" + }, + { + "component":"system/menu/index", + "icon":"tree-table", + "id":"102", + "isFrame":1, + "menuName":"菜单管理", + "menuType":"C", + "orderNum":3, + "parentId":"1", + "path":"menu", + "perms":"system:menu:list", + "remark":"菜单管理菜单", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1001", + "isFrame":1, + "menuName":"用户查询", + "menuType":"F", + "orderNum":1, + "parentId":"100", + "path":"", + "perms":"system:user:query", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1002", + "isFrame":1, + "menuName":"用户新增", + "menuType":"F", + "orderNum":2, + "parentId":"100", + "path":"", + "perms":"system:user:add", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1003", + "isFrame":1, + "menuName":"用户修改", + "menuType":"F", + "orderNum":3, + "parentId":"100", + "path":"", + "perms":"system:user:edit", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1004", + "isFrame":1, + "menuName":"用户删除", + "menuType":"F", + "orderNum":4, + "parentId":"100", + "path":"", + "perms":"system:user:remove", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1005", + "isFrame":1, + "menuName":"用户导出", + "menuType":"F", + "orderNum":5, + "parentId":"100", + "path":"", + "perms":"system:user:export", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1006", + "isFrame":1, + "menuName":"用户导入", + "menuType":"F", + "orderNum":6, + "parentId":"100", + "path":"", + "perms":"system:user:import", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1007", + "isFrame":1, + "menuName":"重置密码", + "menuType":"F", + "orderNum":7, + "parentId":"100", + "path":"", + "perms":"system:user:resetPwd", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1008", + "isFrame":1, + "menuName":"角色查询", + "menuType":"F", + "orderNum":1, + "parentId":"101", + "path":"", + "perms":"system:role:query", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1009", + "isFrame":1, + "menuName":"角色新增", + "menuType":"F", + "orderNum":2, + "parentId":"101", + "path":"", + "perms":"system:role:add", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1010", + "isFrame":1, + "menuName":"角色修改", + "menuType":"F", + "orderNum":3, + "parentId":"101", + "path":"", + "perms":"system:role:edit", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1011", + "isFrame":1, + "menuName":"角色删除", + "menuType":"F", + "orderNum":4, + "parentId":"101", + "path":"", + "perms":"system:role:remove", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1012", + "isFrame":1, + "menuName":"角色导出", + "menuType":"F", + "orderNum":5, + "parentId":"101", + "path":"", + "perms":"system:role:export", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1013", + "isFrame":1, + "menuName":"菜单查询", + "menuType":"F", + "orderNum":1, + "parentId":"102", + "path":"", + "perms":"system:menu:query", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1014", + "isFrame":1, + "menuName":"菜单新增", + "menuType":"F", + "orderNum":2, + "parentId":"102", + "path":"", + "perms":"system:menu:add", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1015", + "isFrame":1, + "menuName":"菜单修改", + "menuType":"F", + "orderNum":3, + "parentId":"102", + "path":"", + "perms":"system:menu:edit", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"", + "icon":"#", + "id":"1016", + "isFrame":1, + "menuName":"菜单删除", + "menuType":"F", + "orderNum":4, + "parentId":"102", + "path":"", + "perms":"system:menu:remove", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"content/article/index", + "icon":"build", + "id":"2019", + "isFrame":1, + "menuName":"文章管理", + "menuType":"C", + "orderNum":0, + "parentId":"2017", + "path":"article", + "perms":"content:article:list", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"content/category/index", + "icon":"example", + "id":"2018", + "isFrame":1, + "menuName":"分类管理", + "menuType":"C", + "orderNum":1, + "parentId":"2017", + "path":"category", + "perms":"content:category:list", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"content/link/index", + "icon":"404", + "id":"2022", + "isFrame":1, + "menuName":"友链管理", + "menuType":"C", + "orderNum":4, + "parentId":"2017", + "path":"link", + "perms":"content:link:list", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "component":"content/tag/index", + "icon":"button", + "id":"2021", + "isFrame":1, + "menuName":"标签管理", + "menuType":"C", + "orderNum":6, + "parentId":"2017", + "path":"tag", + "perms":"content:tag:index", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2028", + "isFrame":1, + "menuName":"导出分类", + "menuType":"F", + "orderNum":1, + "parentId":"2018", + "path":"", + "perms":"content:category:export", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2024", + "isFrame":1, + "menuName":"友链新增", + "menuType":"F", + "orderNum":0, + "parentId":"2022", + "path":"", + "perms":"content:link:add", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2025", + "isFrame":1, + "menuName":"友链修改", + "menuType":"F", + "orderNum":1, + "parentId":"2022", + "path":"", + "perms":"content:link:edit", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2026", + "isFrame":1, + "menuName":"友链删除", + "menuType":"F", + "orderNum":1, + "parentId":"2022", + "path":"", + "perms":"content:link:remove", + "remark":"", + "status":"0", + "visible":"0" + }, + { + "icon":"#", + "id":"2027", + "isFrame":1, + "menuName":"友链查询", + "menuType":"F", + "orderNum":2, + "parentId":"2022", + "path":"", + "perms":"content:link:query", + "remark":"", + "status":"0", + "visible":"0" + } + ], + "msg":"操作成功" +} +~~~~ + + + + + +### 5.15 新增菜单 + +#### 5.15.1 需求 + +​ 可以新增菜单 + +#### 5.15.2 接口设计 + +​ + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------- | --------------- | +| POST | content/article | 是 | + +请求体参数: + +​ Menu类对应的json格式 + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +### 5.16 修改菜单 + +#### 5.16.1 需求 + +​ 能够修改菜单,但是修改的时候不能把父菜单设置为当前菜单,如果设置了需要给出相应的提示。并且修改失败。 + +#### 5.16.2 接口设计 + +##### 5.16.2.1 根据id查询菜单数据 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| Get | system/menu/{id} | 是 | + +Path格式请求参数: + +id: 菜单id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "icon":"table", + "id":"2017", + "menuName":"内容管理", + "menuType":"M", + "orderNum":"4", + "parentId":"0", + "path":"content", + "remark":"", + "status":"0", + "visible":"0" + }, + "msg":"操作成功" +} +~~~~ + + + +##### 5.16.2.2 更新菜单 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------- | --------------- | +| PUT | system/menu | 是 | + +请求体参数: + +​ Menu类对应的json格式 + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + +如果把父菜单设置为当前菜单: + +~~~~java +{ + "code":500, + "msg":"修改菜单'写博文'失败,上级菜单不能选择自己" +} +~~~~ + + + +### 5.17 删除菜单 + +#### 5.17.1 需求 + +​ 能够删除菜单,但是如果要删除的菜单有子菜单则提示:存在子菜单不允许删除 并且删除失败。 + +#### 5.17.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------------ | --------------- | +| DELETE | content/article/{menuId} | 是 | + +Path参数: + +menuId:要删除菜单的id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + +如果要删除的菜单有子菜单则 + +~~~~java +{ + "code":500, + "msg":"存在子菜单不允许删除" +} +~~~~ + + + + + +### 5.18 角色列表 + +#### 5.18.1 需求 + +​ 需要有角色列表分页查询的功能。 + +​ 要求能够针对角色名称进行模糊查询。 + +​ 要求能够针对状态进行查询。 + +​ 要求按照role_sort进行升序排列。 + +#### 5.18.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| GET | system/role/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +roleName:角色名称 + +status:状态 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "id":"12", + "roleKey":"link", + "roleName":"友链审核员", + "roleSort":"1", + "status":"0" + } + ], + "total":"1" + }, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.19 改变角色状态 + +#### 5.19.1 需求 + +​ 要求能够修改角色的停启用状态 + +#### 5.19.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------------ | --------------- | +| PUT | system/role/changeStatus | 是 | + +请求体: + +~~~~json +{"roleId":"11","status":"1"} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.20 新增角色!! + +#### 5.20.1 需求 + +​ 需要提供新增角色的功能。新增角色时能够直接设置角色所关联的菜单权限。 + +#### 5.20.2 接口设计 + +##### 5.20.2.1 获取菜单树接口 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------------- | --------------- | +| GET | /system/menu/treeselect | 是 | + +无需请求参数 + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "children":[], + "id":"2023", + "label":"写博文", + "parentId":"0" + }, + { + "children":[ + { + "children":[ + { + "children":[], + "id":"1001", + "label":"用户查询", + "parentId":"100" + }, + { + "children":[], + "id":"1002", + "label":"用户新增", + "parentId":"100" + }, + { + "children":[], + "id":"1003", + "label":"用户修改", + "parentId":"100" + }, + { + "children":[], + "id":"1004", + "label":"用户删除", + "parentId":"100" + }, + { + "children":[], + "id":"1005", + "label":"用户导出", + "parentId":"100" + }, + { + "children":[], + "id":"1006", + "label":"用户导入", + "parentId":"100" + }, + { + "children":[], + "id":"1007", + "label":"重置密码", + "parentId":"100" + } + ], + "id":"100", + "label":"用户管理", + "parentId":"1" + }, + { + "children":[ + { + "children":[], + "id":"1008", + "label":"角色查询", + "parentId":"101" + }, + { + "children":[], + "id":"1009", + "label":"角色新增", + "parentId":"101" + }, + { + "children":[], + "id":"1010", + "label":"角色修改", + "parentId":"101" + }, + { + "children":[], + "id":"1011", + "label":"角色删除", + "parentId":"101" + }, + { + "children":[], + "id":"1012", + "label":"角色导出", + "parentId":"101" + } + ], + "id":"101", + "label":"角色管理", + "parentId":"1" + }, + { + "children":[ + { + "children":[], + "id":"1013", + "label":"菜单查询", + "parentId":"102" + }, + { + "children":[], + "id":"1014", + "label":"菜单新增", + "parentId":"102" + }, + { + "children":[], + "id":"1015", + "label":"菜单修改", + "parentId":"102" + }, + { + "children":[], + "id":"1016", + "label":"菜单删除", + "parentId":"102" + } + ], + "id":"102", + "label":"菜单管理", + "parentId":"1" + } + ], + "id":"1", + "label":"系统管理", + "parentId":"0" + }, + { + "children":[ + { + "children":[], + "id":"2019", + "label":"文章管理", + "parentId":"2017" + }, + { + "children":[ + { + "children":[], + "id":"2028", + "label":"导出分类", + "parentId":"2018" + } + ], + "id":"2018", + "label":"分类管理", + "parentId":"2017" + }, + { + "children":[ + { + "children":[], + "id":"2024", + "label":"友链新增", + "parentId":"2022" + }, + { + "children":[], + "id":"2025", + "label":"友链修改", + "parentId":"2022" + }, + { + "children":[], + "id":"2026", + "label":"友链删除", + "parentId":"2022" + }, + { + "children":[], + "id":"2027", + "label":"友链查询", + "parentId":"2022" + } + ], + "id":"2022", + "label":"友链管理", + "parentId":"2017" + }, + { + "children":[], + "id":"2021", + "label":"标签管理", + "parentId":"2017" + } + ], + "id":"2017", + "label":"内容管理", + "parentId":"0" + } + ], + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.20.2.2 新增角色接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------- | --------------- | +| POST | system/role | 是 | + +请求体: + +~~~~json +{ + "roleName":"测试新增角色", + "roleKey":"wds", + "roleSort":0, + "status":"0", + "menuIds":[ + "1", + "100" + ], + "remark":"我是角色备注" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + + + +### 5.21 修改角色 + +#### 5.21.1 需求 + +​ 需要提供修改角色的功能。修改角色时可以修改角色所关联的菜单权限 + +#### 5.21.2 接口设计 + +##### 5.21.2.1 角色信息回显接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| Get | system/role/{id} | 是 | + +Path格式请求参数: + +id: 角色id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "id":"11", + "remark":"嘎嘎嘎", + "roleKey":"aggag", + "roleName":"嘎嘎嘎", + "roleSort":"5", + "status":"0" + }, + "msg":"操作成功" +} +~~~~ + +##### 5.21.2.2 加载对应角色菜单列表树接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------------------------ | --------------- | +| Get | /system/menu/roleMenuTreeselect/{id} | 是 | + +Path格式请求参数: + +id: 角色id + +响应格式: + +字段介绍 + +​ menus:菜单树。 + +​ checkedKeys:角色所关联的菜单权限id列表。 + +~~~~json +{ + "code":200, + "data":{ + "menus":[ + { + "children":[], + "id":"2023", + "label":"写博文", + "parentId":"0" + }, + { + "children":[ + { + "children":[ + { + "children":[], + "id":"1001", + "label":"用户查询", + "parentId":"100" + }, + { + "children":[], + "id":"1002", + "label":"用户新增", + "parentId":"100" + }, + { + "children":[], + "id":"1003", + "label":"用户修改", + "parentId":"100" + }, + { + "children":[], + "id":"1004", + "label":"用户删除", + "parentId":"100" + }, + { + "children":[], + "id":"1005", + "label":"用户导出", + "parentId":"100" + }, + { + "children":[], + "id":"1006", + "label":"用户导入", + "parentId":"100" + }, + { + "children":[], + "id":"1007", + "label":"重置密码", + "parentId":"100" + } + ], + "id":"100", + "label":"用户管理", + "parentId":"1" + }, + { + "children":[ + { + "children":[], + "id":"1008", + "label":"角色查询", + "parentId":"101" + }, + { + "children":[], + "id":"1009", + "label":"角色新增", + "parentId":"101" + }, + { + "children":[], + "id":"1010", + "label":"角色修改", + "parentId":"101" + }, + { + "children":[], + "id":"1011", + "label":"角色删除", + "parentId":"101" + }, + { + "children":[], + "id":"1012", + "label":"角色导出", + "parentId":"101" + } + ], + "id":"101", + "label":"角色管理", + "parentId":"1" + }, + { + "children":[ + { + "children":[], + "id":"1013", + "label":"菜单查询", + "parentId":"102" + }, + { + "children":[], + "id":"1014", + "label":"菜单新增", + "parentId":"102" + }, + { + "children":[], + "id":"1015", + "label":"菜单修改", + "parentId":"102" + }, + { + "children":[], + "id":"1016", + "label":"菜单删除", + "parentId":"102" + } + ], + "id":"102", + "label":"菜单管理", + "parentId":"1" + } + ], + "id":"1", + "label":"系统管理", + "parentId":"0" + }, + { + "children":[ + { + "children":[], + "id":"2019", + "label":"文章管理", + "parentId":"2017" + }, + { + "children":[ + { + "children":[], + "id":"2028", + "label":"导出分类", + "parentId":"2018" + } + ], + "id":"2018", + "label":"分类管理", + "parentId":"2017" + }, + { + "children":[ + { + "children":[], + "id":"2024", + "label":"友链新增", + "parentId":"2022" + }, + { + "children":[], + "id":"2025", + "label":"友链修改", + "parentId":"2022" + }, + { + "children":[], + "id":"2026", + "label":"友链删除", + "parentId":"2022" + }, + { + "children":[], + "id":"2027", + "label":"友链查询", + "parentId":"2022" + } + ], + "id":"2022", + "label":"友链管理", + "parentId":"2017" + }, + { + "children":[], + "id":"2021", + "label":"标签管理", + "parentId":"2017" + } + ], + "id":"2017", + "label":"内容管理", + "parentId":"0" + } + ], + "checkedKeys":[ + "1001" + ] + }, + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.21.2.3 更新角色信息接口 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------- | --------------- | +| PUT | system/role | 是 | + +请求体: + +~~~~json +{ + "id":"13", + "remark":"我是角色备注", + "roleKey":"wds", + "roleName":"测试新增角色", + "roleSort":0, + "status":"0", + "menuIds":[ + "1", + "100", + "1001" + ] +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + + + + + +### 5.22 删除角色 + +#### 5.22.1 需求 + +​ 删除固定的某个角色(逻辑删除) + +#### 5.22.2 接口设计 + +​ + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| DELETE | system/role/{id} | 是 | + +Path请求参数: + +id:要删除的角色id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.23 用户列表 + +#### 5.23.1 需求 + +​ 需要用户分页列表接口。 + +​ 可以根据用户名模糊搜索。 + +​ 可以进行手机号的搜索。 + +​ 可以进行状态的查询。 + +#### 5.23.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------- | --------------- | +| GET | system/user/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +userName:用户名 + +phonenumber:手机号 + +status:状态 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "avatar":"http://r7yxkqloa.bkt.clouddn.com/2022/03/05/75fd15587811443a9a9a771f24da458d.png", + "createTime":"2022-01-05 17:01:56", + "email":"23412332@qq.com", + "id":"1", + "nickName":"sg3334", + "phonenumber":"18888888888", + "sex":"1", + "status":"0", + "updateBy":"1", + "updateTime":"2022-03-13 21:36:22", + "userName":"sg" + } + ], + "total":"1" + }, + "msg":"操作成功" +} +~~~~ + + + +### 5.24 新增用户!!! + + + +#### 5.24.1 需求 + +​ 需要新增用户功能。新增用户时可以直接关联角色。 + +​ 注意:新增用户时注意密码加密存储。 + +​ 用户名不能为空,否则提示:必需填写用户名 + +​ 用户名必须之前未存在,否则提示:用户名已存在 + +​ 手机号必须之前未存在,否则提示:手机号已存在 + +​ 邮箱必须之前未存在,否则提示:邮箱已存在 + +#### 5.24.2 接口设计 + +##### 5.24.2.1 查询角色列表接口 + +注意:查询的是所有状态正常的角色 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------------ | --------------- | +| GET | /system/role/listAllRole | 是 | + + + +响应格式: + +~~~~json +{ + "code":200, + "data":[ + { + "createBy":"0", + "createTime":"2021-11-12 18:46:19", + "delFlag":"0", + "id":"1", + "remark":"超级管理员", + "roleKey":"admin", + "roleName":"超级管理员", + "roleSort":"1", + "status":"0", + "updateBy":"0" + }, + { + "createBy":"0", + "createTime":"2021-11-12 18:46:19", + "delFlag":"0", + "id":"2", + "remark":"普通角色", + "roleKey":"common", + "roleName":"普通角色", + "roleSort":"2", + "status":"0", + "updateBy":"0", + "updateTime":"2022-01-02 06:32:58" + }, + { + "createTime":"2022-01-06 22:07:40", + "delFlag":"0", + "id":"11", + "remark":"嘎嘎嘎", + "roleKey":"aggag", + "roleName":"嘎嘎嘎", + "roleSort":"5", + "status":"0", + "updateBy":"1", + "updateTime":"2022-09-12 10:00:25" + }, + { + "createTime":"2022-01-16 14:49:30", + "delFlag":"0", + "id":"12", + "roleKey":"link", + "roleName":"友链审核员", + "roleSort":"1", + "status":"0", + "updateTime":"2022-01-16 16:05:09" + } + ], + "msg":"操作成功" +} +~~~~ + + + + + + + +##### 5.24.2.2 新增用户 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------- | --------------- | +| POST | system/user | 是 | + +请求体: + +~~~~json +{ + "userName":"wqeree", + "nickName":"测试新增用户", + "password":"1234343", + "phonenumber":"18889778907", + "email":"233@sq.com", + "sex":"0", + "status":"0", + "roleIds":[ + "2" + ] +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.25 删除用户 + +#### 5.25.1 需求 + +删除固定的某个用户(逻辑删除) + +#### 5.25.2 接口设计 + +不能删除当前操作的用户 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| DELETE | /system/user/{id} | 是 | + +Path请求参数: + +id:要删除的用户id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.26 修改用户 + +#### 5.26.1 需求 + +需要提供修改用户的功能。修改用户时可以修改用户所关联的角色。 + +#### 5.26.2 接口设计 + +##### 5.26.2.1 根据id查询用户信息回显接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| Get | /system/user/{id} | 是 | + +Path格式请求参数: + +id: 用户id + +响应格式: + +roleIds:用户所关联的角色id列表 + +roles:所有角色的列表 + +user:用户信息 + +~~~~json +{ + "code":200, + "data":{ + "roleIds":[ + "11" + ], + "roles":[ + { + "createBy":"0", + "createTime":"2021-11-12 18:46:19", + "delFlag":"0", + "id":"1", + "remark":"超级管理员", + "roleKey":"admin", + "roleName":"超级管理员", + "roleSort":"1", + "status":"0", + "updateBy":"0" + }, + { + "createBy":"0", + "createTime":"2021-11-12 18:46:19", + "delFlag":"0", + "id":"2", + "remark":"普通角色", + "roleKey":"common", + "roleName":"普通角色", + "roleSort":"2", + "status":"0", + "updateBy":"0", + "updateTime":"2022-01-02 06:32:58" + }, + { + "createTime":"2022-01-06 22:07:40", + "delFlag":"0", + "id":"11", + "remark":"嘎嘎嘎", + "roleKey":"aggag", + "roleName":"嘎嘎嘎", + "roleSort":"5", + "status":"0", + "updateBy":"1", + "updateTime":"2022-09-11 20:34:49" + }, + { + "createTime":"2022-01-16 14:49:30", + "delFlag":"0", + "id":"12", + "roleKey":"link", + "roleName":"友链审核员", + "roleSort":"1", + "status":"0", + "updateTime":"2022-01-16 16:05:09" + } + ], + "user":{ + "email":"weq@2132.com", + "id":"14787164048663", + "nickName":"sg777", + "sex":"0", + "status":"0", + "userName":"sg777" + } + }, + "msg":"操作成功" +} +~~~~ + + + +##### 5.26.2.2 更新用户信息接口 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------ | --------------- | +| PUT | /system/user | 是 | + +请求体: + +~~~~json +{ + "email":"weq@2132.com", + "id":"14787164048663", + "nickName":"sg777", + "sex":"1", + "status":"0", + "userName":"sg777", + "roleIds":[ + "11" + ] +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +### 5.27 分页查询分类列表 + +#### 5.27.1 需求 + +​ 需要分页查询分类列表。 + +​ 能根据分类名称进行模糊查询。 + +​ 能根据状态进行查询。 + +#### 5.27.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------------- | --------------- | +| GET | content/category/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +name:分类名 + +status: 状态 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "description":"wsd", + "id":"1", + "name":"java", + "status":"0" + }, + { + "description":"wsd", + "id":"2", + "name":"PHP", + "status":"0" + } + ], + "total":"2" + }, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.28 新增分类 + +#### 5.28.1 需求 + +​ 需要新增分类功能 + +#### 5.28.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| POST | /content/category | 是 | + +请求体: + +~~~~json +{ + "name":"威威", + "description":"是的", + "status":"0" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.29 修改分类 + +#### 5.29.1 需求 + +​ 需要提供修改分类的功能 + +#### 5.29.2 接口设计 + +##### 5.29.2.1 根据id查询分类 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | --------------------- | --------------- | +| Get | content/category/{id} | 是 | + +Path格式请求参数: + +id: 分类id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "description":"qwew", + "id":"4", + "name":"ww", + "status":"0" + }, + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.29.2.2 更新分类 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| PUT | /content/category | 是 | + +请求体: + +~~~~json +{ + "description":"是的", + "id":"3", + "name":"威威2", + "status":"0" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.30 删除分类 + +#### 5.30.1 需求 + +​ 删除某个分类(逻辑删除) + +#### 5.30.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ---------------------- | --------------- | +| DELETE | /content/category/{id} | 是 | + +Path请求参数: + +id:要删除的分类id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + +### 5.31 分页查询友链列表 + +#### 5.31.1 需求 + +​ 需要分页查询友链列表。 + +​ 能根据友链名称进行模糊查询。 + +​ 能根据状态进行查询。 + +#### 5.31.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------ | --------------- | +| GET | /content/link/list | 是 | + +Query格式请求参数: + +pageNum: 页码 + +pageSize: 每页条数 + +name:友链名 + +status:状态 + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "rows":[ + { + "address":"https://www.baidu.com", + "description":"sda", + "id":"1", "logo":"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fn1.itc.cn%2Fimg8%2Fwb%2Frecom%2F2016%2F05%2F10%2F146286696706220328.PNG&refer=http%3A%2F%2Fn1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646205529&t=f942665181eb9b0685db7a6f59d59975", + "name":"sda", + "status":"0" + } + ], + "total":"1" + }, + "msg":"操作成功" +} +~~~~ + + + +### 5.32 新增友链 + +#### 5.32.1 需求 + +​ 需要新增友链功能 + +#### 5.32.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------- | --------------- | +| POST | /content/link | 是 | + +请求体: + +~~~~json +{ + "name":"sda", + "description":"weqw", + "address":"wewe", + "logo":"weqe", + "status":"2" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +### 5.33 修改友链 + +#### 5.33.1 需求 + +​ 需要提供修改友链的功能 + +#### 5.33.2 接口设计 + +##### 5.33.2.1 根据id查询友联 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ----------------- | --------------- | +| Get | content/link/{id} | 是 | + +Path格式请求参数: + +id: 友链id + +响应格式: + +~~~~json +{ + "code":200, + "data":{ + "address":"wewe", + "description":"weqw", + "id":"4", + "logo":"weqe", + "name":"sda", + "status":"2" + }, + "msg":"操作成功" +} +~~~~ + + + + + +##### 5.33.2.2 修改友链 + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------- | --------------- | +| PUT | /content/link | 是 | + +请求体: + +~~~~json +{ + "address":"https://www.qq.com", + "description":"dada2", + "id":"2", + "logo":"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fn1.itc.cn%2Fimg8%2Fwb%2Frecom%2F2016%2F05%2F10%2F146286696706220328.PNG&refer=http%3A%2F%2Fn1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646205529&t=f942665181eb9b0685db7a6f59d59975", + "name":"sda", + "status":"0" +} +~~~~ + + + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + +### 5.34 删除友链 + +#### 5.34.1 需求 + +​ 删除某个友链(逻辑删除) + +#### 5.34.2 接口设计 + + + +| 请求方式 | 请求路径 | 是否需求token头 | +| -------- | ------------------ | --------------- | +| DELETE | /content/link/{id} | 是 | + +Path请求参数: + +id:要删除的友链id + +响应格式: + +~~~~json +{ + "code":200, + "msg":"操作成功" +} +~~~~ + + + + + -- Gitee