黑马头条Day08-平台管理

一、平台管理前端

步骤①:拷贝资料中提供的前端项目到没有中文的目录下

步骤②:在leadnews.conf文件夹下新增heima-leadnews-admin.conf配置文件

内容如下:根据自己的情况更改root地址

upstream  heima-admin-gateway{
    server localhost:51603;
}

server {
	listen 8803;
	location / {
		root D:/IDEA/frontProject/admin-web/;
		index index.html;
	}
	
	location ~/service_6001/(.*) {
		proxy_pass http://heima-admin-gateway/$1;
		proxy_set_header HOST $host;  # 不改变源请求头的值
		proxy_pass_request_body on;  #开启获取请求体
		proxy_pass_request_headers on;  #开启获取请求头
		proxy_set_header X-Real-IP $remote_addr;   # 记录真实发出请求的客户端IP
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  #记录代理信息
	}
}

步骤③:重启nginx,访问 http://localhost:8803/#/login

二、登录及网关

1. 登录

步骤①:导入资料中的leadnews_admin.sql

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50721
 Source Host           : localhost:3306
 Source Schema         : leadnews_admin

 Target Server Type    : MySQL
 Target Server Version : 50721
 File Encoding         : 65001

 Date: 26/07/2021 01:45:37
*/
DROP DATABASE IF EXISTS leadnews_admin;
CREATE DATABASE leadnews_admin;
USE leadnews_admin;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for ad_article_statistics
-- ----------------------------
DROP TABLE IF EXISTS `ad_article_statistics`;
CREATE TABLE `ad_article_statistics`  (
  `id` int(11) UNSIGNED NOT NULL COMMENT '主键',
  `article_we_media` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '主账号ID',
  `article_crawlers` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '子账号ID',
  `channel_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '频道ID',
  `read_20` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '草读量',
  `read_100` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '读完量',
  `read_count` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '阅读量',
  `comment` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '评论量',
  `follow` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '关注量',
  `collection` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '收藏量',
  `forward` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '转发量',
  `likes` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '点赞量',
  `unlikes` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '不喜欢',
  `unfollow` int(11) UNSIGNED NULL DEFAULT NULL COMMENT 'unfollow',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文章数据统计表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_article_statistics
-- ----------------------------

-- ----------------------------
-- Table structure for ad_channel_label
-- ----------------------------
DROP TABLE IF EXISTS `ad_channel_label`;
CREATE TABLE `ad_channel_label`  (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
  `channel_id` int(11) UNSIGNED NULL DEFAULT NULL,
  `label_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '标签ID',
  `ord` int(5) UNSIGNED NULL DEFAULT NULL COMMENT '排序',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1118 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '频道标签信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_channel_label
-- ----------------------------
INSERT INTO `ad_channel_label` VALUES (1108, 1, 1, 0);
INSERT INTO `ad_channel_label` VALUES (1109, 1, 8, 0);
INSERT INTO `ad_channel_label` VALUES (1110, 7, 7, 0);
INSERT INTO `ad_channel_label` VALUES (1111, 7, 9, 0);
INSERT INTO `ad_channel_label` VALUES (1112, 3, 3, 0);
INSERT INTO `ad_channel_label` VALUES (1113, 7, 2, 0);
INSERT INTO `ad_channel_label` VALUES (1114, 3, 4, 0);
INSERT INTO `ad_channel_label` VALUES (1115, 5, 5, 0);
INSERT INTO `ad_channel_label` VALUES (1116, 4, 6, 0);
INSERT INTO `ad_channel_label` VALUES (1117, 6, 10, 0);

-- ----------------------------
-- Table structure for ad_function
-- ----------------------------
DROP TABLE IF EXISTS `ad_function`;
CREATE TABLE `ad_function`  (
  `id` int(11) UNSIGNED NOT NULL,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '功能名称',
  `code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '功能代码',
  `parent_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '父功能',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '登录时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '页面功能信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_function
-- ----------------------------

-- ----------------------------
-- Table structure for ad_label
-- ----------------------------
DROP TABLE IF EXISTS `ad_label`;
CREATE TABLE `ad_label`  (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '频道名称',
  `type` tinyint(1) UNSIGNED NULL DEFAULT NULL COMMENT '0系统增加\r\n            1人工增加',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `idx_name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 24237 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '标签信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_label
-- ----------------------------
INSERT INTO `ad_label` VALUES (1, 'java', 0, '2019-08-22 16:30:16');
INSERT INTO `ad_label` VALUES (2, 'docker', 0, '2019-08-22 16:30:52');
INSERT INTO `ad_label` VALUES (3, 'mysql', 0, '2019-08-22 16:31:17');
INSERT INTO `ad_label` VALUES (4, 'vue', 0, '2019-08-22 16:35:39');
INSERT INTO `ad_label` VALUES (5, 'Weex', 0, '2019-08-22 16:36:08');
INSERT INTO `ad_label` VALUES (6, 'Python', 0, '2019-08-22 16:36:34');
INSERT INTO `ad_label` VALUES (7, '大数据', 0, '2019-08-22 16:36:48');
INSERT INTO `ad_label` VALUES (8, 'spring', 0, '2019-08-22 16:39:11');
INSERT INTO `ad_label` VALUES (9, 'hbase', 0, '2019-08-22 16:39:35');
INSERT INTO `ad_label` VALUES (10, 'hive', 0, '2019-08-22 16:43:44');
INSERT INTO `ad_label` VALUES (23858, '工具', 1, '2019-08-22 16:43:55');
INSERT INTO `ad_label` VALUES (23859, 'c', 1, '2019-08-22 16:44:01');
INSERT INTO `ad_label` VALUES (23860, '电话', 1, '2019-08-22 16:44:22');
INSERT INTO `ad_label` VALUES (23861, '照片', 1, '2019-08-22 16:44:22');
INSERT INTO `ad_label` VALUES (23862, '咨询', 1, '2019-08-22 16:44:22');
INSERT INTO `ad_label` VALUES (23863, '智能', 1, '2019-08-22 16:46:00');
INSERT INTO `ad_label` VALUES (23864, '人工智能', 1, '2019-08-22 16:46:00');
INSERT INTO `ad_label` VALUES (23865, 'AI', 1, '2019-08-22 16:46:00');
INSERT INTO `ad_label` VALUES (23866, '智能协会', 1, '2019-08-22 16:46:00');
INSERT INTO `ad_label` VALUES (23867, '人工智能协会', 1, '2019-08-22 16:46:00');
INSERT INTO `ad_label` VALUES (23868, '5G', 1, '2019-08-22 16:47:21');
INSERT INTO `ad_label` VALUES (23869, '高通', 1, '2019-08-22 16:47:21');
INSERT INTO `ad_label` VALUES (23870, '苹果', 1, '2019-08-22 16:47:21');
INSERT INTO `ad_label` VALUES (23871, '英特尔', 1, '2019-08-22 16:47:21');
INSERT INTO `ad_label` VALUES (23872, '智能手机', 1, '2019-08-22 16:47:21');
INSERT INTO `ad_label` VALUES (23873, 'google', 1, '2019-08-22 16:47:49');
INSERT INTO `ad_label` VALUES (23874, '芯片', 1, '2019-08-22 16:47:49');
INSERT INTO `ad_label` VALUES (23875, '交互', 1, '2019-08-22 16:47:49');
INSERT INTO `ad_label` VALUES (23876, '智能交互', 1, '2019-08-22 16:47:49');
INSERT INTO `ad_label` VALUES (23877, '手势交互', 1, '2019-08-22 16:47:49');
INSERT INTO `ad_label` VALUES (23878, '智慧酒店', 1, '2019-08-22 16:48:54');
INSERT INTO `ad_label` VALUES (23879, '人脸识别', 1, '2019-08-22 16:49:06');
INSERT INTO `ad_label` VALUES (23880, '软硬件开发流程', 1, '2019-08-22 16:49:26');
INSERT INTO `ad_label` VALUES (23881, '软硬件结合', 1, '2019-08-22 16:50:23');
INSERT INTO `ad_label` VALUES (23882, 'React', 1, '2019-08-22 17:18:59');
INSERT INTO `ad_label` VALUES (23883, '前端技术', 1, '2019-08-22 17:18:59');
INSERT INTO `ad_label` VALUES (23903, 'IDEA', 1, '2019-08-22 17:22:21');
INSERT INTO `ad_label` VALUES (23904, 'git', 1, '2019-08-22 17:32:54');
INSERT INTO `ad_label` VALUES (23905, 'java学习', 1, '2019-08-22 17:43:34');
INSERT INTO `ad_label` VALUES (23906, '机器学习', 1, '2019-08-22 17:46:40');
INSERT INTO `ad_label` VALUES (23907, '陆奇', 1, '2019-08-22 17:46:55');
INSERT INTO `ad_label` VALUES (23908, '设计模式', 1, '2019-08-22 17:47:40');
INSERT INTO `ad_label` VALUES (23909, '谷歌', 1, '2019-08-22 17:48:11');
INSERT INTO `ad_label` VALUES (23916, '工业数字化', 1, '2019-08-22 17:49:16');
INSERT INTO `ad_label` VALUES (23949, '个人生活', 1, '2019-08-22 17:57:38');
INSERT INTO `ad_label` VALUES (23950, '安徽', 1, '2019-08-22 17:57:38');
INSERT INTO `ad_label` VALUES (23951, '黄山', 1, '2019-08-22 17:57:38');
INSERT INTO `ad_label` VALUES (23952, 'SVN信息', 1, '2019-08-22 18:00:27');
INSERT INTO `ad_label` VALUES (23953, '清除', 1, '2019-08-22 18:00:27');
INSERT INTO `ad_label` VALUES (23954, '删除', 1, '2019-08-22 18:00:27');
INSERT INTO `ad_label` VALUES (23955, 'svn', 1, '2019-08-22 18:00:27');
INSERT INTO `ad_label` VALUES (23956, '排序', 1, '2019-08-22 18:01:27');
INSERT INTO `ad_label` VALUES (23957, '快排', 1, '2019-08-22 18:01:27');
INSERT INTO `ad_label` VALUES (23958, '归并排序', 1, '2019-08-22 18:01:27');
INSERT INTO `ad_label` VALUES (23959, '程序人生', 1, '2019-08-22 18:05:25');
INSERT INTO `ad_label` VALUES (23960, '毕业一年', 1, '2019-08-22 18:05:25');
INSERT INTO `ad_label` VALUES (23961, '毕业总结', 1, '2019-08-22 18:05:25');
INSERT INTO `ad_label` VALUES (23962, '毕业感想', 1, '2019-08-22 18:05:25');
INSERT INTO `ad_label` VALUES (23979, 'dom', 1, '2019-08-22 18:09:39');
INSERT INTO `ad_label` VALUES (23980, 'javascript', 1, '2019-08-22 18:09:39');
INSERT INTO `ad_label` VALUES (23981, 'web开发', 1, '2019-08-22 18:09:39');
INSERT INTO `ad_label` VALUES (23995, 'IT', 1, '2019-08-22 18:13:50');
INSERT INTO `ad_label` VALUES (23996, '科技', 1, '2019-08-22 18:13:50');
INSERT INTO `ad_label` VALUES (23998, '自动化', 1, '2019-08-22 18:16:20');
INSERT INTO `ad_label` VALUES (23999, '运维', 1, '2019-08-22 18:16:20');
INSERT INTO `ad_label` VALUES (24000, 'ansible', 1, '2019-08-22 18:16:20');
INSERT INTO `ad_label` VALUES (24001, '入门', 1, '2019-08-22 18:16:20');
INSERT INTO `ad_label` VALUES (24002, 'c#', 1, '2019-08-22 18:16:45');
INSERT INTO `ad_label` VALUES (24003, '正则', 1, '2019-08-22 18:16:45');
INSERT INTO `ad_label` VALUES (24004, 'regex', 1, '2019-08-22 18:16:45');
INSERT INTO `ad_label` VALUES (24005, '字符串', 1, '2019-08-22 18:16:45');
INSERT INTO `ad_label` VALUES (24015, 'openstack', 1, '2019-08-22 18:19:42');
INSERT INTO `ad_label` VALUES (24016, 'k8s', 1, '2019-08-22 18:20:47');
INSERT INTO `ad_label` VALUES (24017, 'kubernetes', 1, '2019-08-22 18:20:47');
INSERT INTO `ad_label` VALUES (24018, 'kubectl', 1, '2019-08-22 18:20:47');
INSERT INTO `ad_label` VALUES (24019, 'supervisor', 1, '2019-08-22 18:24:43');
INSERT INTO `ad_label` VALUES (24020, 'linux', 1, '2019-08-22 18:24:43');
INSERT INTO `ad_label` VALUES (24021, '进程管理', 1, '2019-08-22 18:24:43');
INSERT INTO `ad_label` VALUES (24109, '百度网盘', 1, '2019-08-22 19:14:19');
INSERT INTO `ad_label` VALUES (24110, '百度云', 1, '2019-08-22 19:14:19');
INSERT INTO `ad_label` VALUES (24111, '免费', 1, '2019-08-22 19:14:19');
INSERT INTO `ad_label` VALUES (24112, '不限速', 1, '2019-08-22 19:14:19');
INSERT INTO `ad_label` VALUES (24113, '破解', 1, '2019-08-22 19:14:19');
INSERT INTO `ad_label` VALUES (24123, '脚本', 1, '2019-08-22 19:14:26');
INSERT INTO `ad_label` VALUES (24124, '作业', 1, '2019-08-22 19:14:26');
INSERT INTO `ad_label` VALUES (24125, '自动化运维', 1, '2019-08-22 19:14:26');
INSERT INTO `ad_label` VALUES (24126, '极客头条', 1, '2019-08-22 20:34:33');
INSERT INTO `ad_label` VALUES (24198, '业界新闻', 1, '2019-08-23 07:28:27');
INSERT INTO `ad_label` VALUES (24206, '杂谈', 1, '2019-08-23 07:31:09');
INSERT INTO `ad_label` VALUES (24207, '零信任网络', 1, '2019-08-23 07:33:37');
INSERT INTO `ad_label` VALUES (24208, '网络安全', 1, '2019-08-23 07:33:37');
INSERT INTO `ad_label` VALUES (24209, 'Go语言', 1, '2019-08-23 07:33:54');
INSERT INTO `ad_label` VALUES (24210, '程序员', 1, '2019-08-23 07:33:54');
INSERT INTO `ad_label` VALUES (24223, 'Android', 1, '2019-08-23 07:35:42');
INSERT INTO `ad_label` VALUES (24224, '架构', 1, '2019-08-23 07:35:42');
INSERT INTO `ad_label` VALUES (24232, 'flume', 1, '2019-08-23 07:37:05');
INSERT INTO `ad_label` VALUES (24233, 'hive优化', 1, '2019-08-23 07:37:27');
INSERT INTO `ad_label` VALUES (24234, 'parquet', 1, '2019-08-23 07:37:27');
INSERT INTO `ad_label` VALUES (24235, 'orc', 1, '2019-08-23 07:37:27');
INSERT INTO `ad_label` VALUES (24236, 'snappy', 1, '2019-08-23 07:37:27');

-- ----------------------------
-- Table structure for ad_menu
-- ----------------------------
DROP TABLE IF EXISTS `ad_menu`;
CREATE TABLE `ad_menu`  (
  `id` int(11) UNSIGNED NOT NULL,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '菜单名称',
  `code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '菜单代码',
  `parent_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '父菜单',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '登录时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单资源信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_menu
-- ----------------------------

-- ----------------------------
-- Table structure for ad_recommend_strategy
-- ----------------------------
DROP TABLE IF EXISTS `ad_recommend_strategy`;
CREATE TABLE `ad_recommend_strategy`  (
  `id` int(5) UNSIGNED NOT NULL COMMENT '主键',
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '策略名称',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '策略描述',
  `is_enable` tinyint(1) NULL DEFAULT NULL COMMENT '是否有效',
  `group_id` int(5) UNSIGNED NULL DEFAULT NULL COMMENT '分组ID',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '推荐策略信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_recommend_strategy
-- ----------------------------

-- ----------------------------
-- Table structure for ad_role
-- ----------------------------
DROP TABLE IF EXISTS `ad_role`;
CREATE TABLE `ad_role`  (
  `id` int(11) UNSIGNED NOT NULL,
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '角色名称',
  `description` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '角色描述',
  `is_enable` tinyint(1) UNSIGNED NULL DEFAULT NULL COMMENT '是否有效',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '登录时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '角色信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_role
-- ----------------------------

-- ----------------------------
-- Table structure for ad_role_auth
-- ----------------------------
DROP TABLE IF EXISTS `ad_role_auth`;
CREATE TABLE `ad_role_auth`  (
  `id` int(11) UNSIGNED NOT NULL,
  `role_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '角色ID',
  `type` tinyint(1) UNSIGNED NULL DEFAULT NULL COMMENT '资源类型\r\n            0 菜单\r\n            1 功能',
  `entry_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '资源ID',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '登录时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '角色权限信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_role_auth
-- ----------------------------

-- ----------------------------
-- Table structure for ad_strategy_group
-- ----------------------------
DROP TABLE IF EXISTS `ad_strategy_group`;
CREATE TABLE `ad_strategy_group`  (
  `id` int(5) UNSIGNED NOT NULL COMMENT '主键',
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '策略名称',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '策略描述',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '推荐策略分组信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_strategy_group
-- ----------------------------

-- ----------------------------
-- Table structure for ad_user
-- ----------------------------
DROP TABLE IF EXISTS `ad_user`;
CREATE TABLE `ad_user`  (
  `id` int(11) UNSIGNED NOT NULL COMMENT '主键',
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '登录用户名',
  `password` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '登录密码',
  `salt` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '盐',
  `nickname` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '昵称',
  `image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '头像',
  `phone` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '手机号',
  `status` tinyint(11) UNSIGNED NULL DEFAULT NULL COMMENT '状态\r\n            0 暂时不可用\r\n            1 永久不可用\r\n            9 正常可用',
  `email` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '邮箱',
  `login_time` datetime(0) NULL DEFAULT NULL COMMENT '最后一次登录时间',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '管理员用户信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_user
-- ----------------------------
INSERT INTO `ad_user` VALUES (1, 'wukong', '123', NULL, 'mo', NULL, '13320325525', 1, 'wukong@qq.com', '2019-07-30 10:16:41', '2019-07-30 10:16:43');
INSERT INTO `ad_user` VALUES (2, 'admin', '5d4e1a406d4a9edbf7b4f10c2a390405', '123abc', 'ad', NULL, '13320325528', 1, 'admin@qq.com', '2020-03-04 17:07:37', '2020-03-04 17:07:40');
INSERT INTO `ad_user` VALUES (3, 'guest', '34e20b52f5bd120db806e57e27f47ed0', '123456', 'gu', NULL, '13412345676', 1, 'guest@qq.com', '2020-07-30 15:00:03', '2020-07-30 15:00:06');

-- ----------------------------
-- Table structure for ad_user_equipment
-- ----------------------------
DROP TABLE IF EXISTS `ad_user_equipment`;
CREATE TABLE `ad_user_equipment`  (
  `id` int(11) UNSIGNED NOT NULL,
  `user_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '用户ID',
  `type` tinyint(1) UNSIGNED NULL DEFAULT NULL COMMENT '0PC\r\n            1ANDROID\r\n            2IOS\r\n            3PAD\r\n            9 其他',
  `version` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '设备版本',
  `sys` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '设备系统',
  `no` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '设备唯一号,MD5加密',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '登录时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '管理员设备信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_user_equipment
-- ----------------------------

-- ----------------------------
-- Table structure for ad_user_login
-- ----------------------------
DROP TABLE IF EXISTS `ad_user_login`;
CREATE TABLE `ad_user_login`  (
  `id` int(11) UNSIGNED NOT NULL,
  `user_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '用户ID',
  `equipment_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '登录设备ID',
  `ip` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '登录IP',
  `address` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '登录地址',
  `longitude` decimal(5, 5) NULL DEFAULT NULL COMMENT '经度',
  `latitude` decimal(5, 5) NULL DEFAULT NULL COMMENT '纬度',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '登录时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '管理员登录行为信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_user_login
-- ----------------------------

-- ----------------------------
-- Table structure for ad_user_opertion
-- ----------------------------
DROP TABLE IF EXISTS `ad_user_opertion`;
CREATE TABLE `ad_user_opertion`  (
  `id` int(11) UNSIGNED NOT NULL,
  `user_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '用户ID',
  `equipment_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '登录设备ID',
  `ip` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '登录IP',
  `address` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '登录地址',
  `type` int(5) NULL DEFAULT NULL COMMENT '操作类型',
  `description` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '操作描述',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '登录时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '管理员操作行为信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_user_opertion
-- ----------------------------

-- ----------------------------
-- Table structure for ad_user_role
-- ----------------------------
DROP TABLE IF EXISTS `ad_user_role`;
CREATE TABLE `ad_user_role`  (
  `id` int(11) UNSIGNED NOT NULL,
  `role_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '角色ID',
  `user_id` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '用户ID',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '登录时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '管理员角色信息表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_user_role
-- ----------------------------

-- ----------------------------
-- Table structure for ad_vistor_statistics
-- ----------------------------
DROP TABLE IF EXISTS `ad_vistor_statistics`;
CREATE TABLE `ad_vistor_statistics`  (
  `id` int(11) UNSIGNED NOT NULL COMMENT '主键',
  `activity` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '日活',
  `vistor` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '访问量',
  `ip` int(11) UNSIGNED NULL DEFAULT NULL COMMENT 'IP量',
  `register` int(11) UNSIGNED NULL DEFAULT NULL COMMENT '注册量',
  `created_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '访问数据统计表' ROW_FORMAT = DYNAMIC;

-- ----------------------------
-- Records of ad_vistor_statistics
-- ----------------------------

SET FOREIGN_KEY_CHECKS = 1;

②从资料中拷贝AdUser类放到admin包下

package com.heima.model.admin.pojos;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * <p>
 * 管理员用户信息表
 * </p>
 *
 * @author itheima
 */
@Data
@TableName("ad_user")
public class AdUser implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    private Integer id;

    /**
     * 登录用户名
     */
    @TableField("name")
    private String name;

    /**
     * 登录密码
     */
    @TableField("password")
    private String password;

    /**
     * 盐
     */
    @TableField("salt")
    private String salt;

    /**
     * 昵称
     */
    @TableField("nickname")
    private String nickname;

    /**
     * 头像
     */
    @TableField("image")
    private String image;

    /**
     * 手机号
     */
    @TableField("phone")
    private String phone;

    /**
     * 状态
            0 暂时不可用
            1 永久不可用
            9 正常可用
     */
    @TableField("status")
    private Integer status;

    /**
     * 邮箱
     */
    @TableField("email")
    private String email;

    /**
     * 最后一次登录时间
     */
    @TableField("login_time")
    private Date loginTime;

    /**
     * 创建时间
     */
    @TableField("created_time")
    private Date createdTime;

}

③在service模块下新建heima-leadnews-admin模块

④在admin模块新建如下

bootstrap.yml配置如下:

server:
  port: 51809
spring:
  application:
    name: leadnews-admin
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.200.130:8848
      config:
        server-addr: 192.168.200.130:8848
        file-extension: yml

logback.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>
    <!--定义日志文件的存储地址,使用绝对路径-->
    <property name="LOG_HOME" value="e:/logs"/>

    <!-- Console 输出设置 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- 按照每天生成日志文件 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <fileNamePattern>${LOG_HOME}/leadnews.%d{yyyy-MM-dd}.log</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 异步输出 -->
    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold>0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>512</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref="FILE"/>
    </appender>


    <logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>
    <logger name="org.springframework.boot" level="debug"/>
    <root level="info">
        <!--<appender-ref ref="ASYNC"/>-->
        <appender-ref ref="FILE"/>
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

在nacos配置中心创建配置文件leadnews-admin.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/leadnews_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
    username: root
    password: 123456
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.heima.model.admin.pojos

⑤接口定义

说明
接口地址/login/in
请求方式POST
参数AdUserDto
响应结果ResponseResult

新增AdUserDto

package com.heima.model.admin.dtos;

import lombok.Data;

@Data
public class AdUserDto {
    /**
     * 用户名
     */
    private String name;
    /**
     * 密码
     */
    private String password;
}

⑥新建AdUserMapper

package com.heima.admin.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.admin.pojos.AdUser;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface AdUserMapper extends BaseMapper<AdUser> {
}

⑦新增LoginController

package com.heima.admin.controller.v1;

import com.heima.admin.service.AdUserService;
import com.heima.model.admin.dtos.AdUserDto;
import com.heima.model.common.dtos.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/login")
public class LoginController {
    @Autowired
    private AdUserService adUserService;

    @PostMapping("/in")
    public ResponseResult login(@RequestBody AdUserDto dto) {
        return adUserService.login(dto);
    }
}

⑧新增AdUserService

package com.heima.admin.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.admin.dtos.AdUserDto;
import com.heima.model.admin.pojos.AdUser;
import com.heima.model.common.dtos.ResponseResult;

public interface AdUserService extends IService<AdUser> {
    /**
     * 登录
     * @param dto
     * @return
     */
    public ResponseResult login(AdUserDto dto);
}

⑨新增实现类AdUserServiceImpl

package com.heima.admin.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.admin.mapper.AdUserMapper;
import com.heima.admin.service.AdUserService;
import com.heima.model.admin.dtos.AdUserDto;
import com.heima.model.admin.pojos.AdUser;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.utils.common.AppJwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
@Transactional
public class AdUserServiceImpl extends ServiceImpl<AdUserMapper, AdUser> implements AdUserService {
    /**
     * 登录
     * @param dto
     * @return
     */
    @Override
    public ResponseResult login(AdUserDto dto) {
        // 1. 检查参数
        if(StringUtils.isBlank(dto.getName()) || StringUtils.isBlank(dto.getPassword())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "用户名或密码不能为空");
        }

        // 2. 查询用户
        AdUser user = getOne(Wrappers.<AdUser>lambdaQuery().eq(AdUser::getName, dto.getName()));
        if(user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在");
        }

        // 3. 比对密码
        String salt = user.getSalt();
        String password = dto.getPassword();
        // md5加密
        password = DigestUtils.md5DigestAsHex((password + salt).getBytes());
        if(password.equals(user.getPassword())) {
            // 4. 返回数据 - jwt
            Map<String, Object> map = new HashMap<>();
            map.put("token", AppJwtUtil.getToken(user.getId().longValue()));
            user.setSalt("");
            user.setPassword("");
            map.put("user", user);

            return ResponseResult.okResult(map);
        } else {
            // 密码错误
            return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
        }
    }
}

⑩新增引导类AdminApplication

package com.heima.admin;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@MapperScan("com.heima.admin.mapper")
@EnableDiscoveryClient
public class AdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminApplication.class, args);
    }
}

2. 网关

步骤①:创建模块heima-leadnews-admin-gateway

②在heima-leadnews-admin-gateway的resources文件夹下新增bootstrap.yml

server:
  port: 51603
spring:
  application:
    name: leadnews-admin-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.200.130:8848
      config:
        server-addr: 192.168.200.130:8848
        file-extension: yml

③新增引导类AdminGatewayApplication

package com.heima.admin.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class AdminGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminGatewayApplication.class, args);
    }
}

④在nacos配置中心添加leadnews-admin-gateway.yml

spring:
  cloud:
    gateway:
      globalcors:
        add-to-simple-url-handler-mapping: true
        corsConfigurations:
          '[/**]':
            allowedHeaders: "*"
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTION
      routes:
        # 平台管理微服务
        - id: admin
          uri: lb://leadnews-admin
          predicates:
            - Path=/admin/**
          filters:
            - StripPrefix= 1
        # 用户微服务
        - id: user
          uri: lb://leadnews-user
          predicates:
            - Path=/user/**
          filters:
            - StripPrefix= 1
        # 文章微服务
        - id: article
          uri: lb://leadnews-article
          predicates:
            - Path=/article/**
          filters:
            - StripPrefix= 1
        # 频道微服务
        - id: wemedia
          uri: lb://leadnews-wemedia
          predicates:
            - Path=/wemedia/**
          filters:
            - StripPrefix= 1
        # 敏感词微服务
        - id: sensitive
          uri: lb://leadnews-sensitive
          predicates:
            - Path=/sensitive/**
          filters:
            - StripPrefix= 1
        #搜索微服务
        - id: leadnews-search
          uri: lb://leadnews-search
          predicates:
            - Path=/search/**
          filters:
            - StripPrefix= 1

⑤拷贝一份jwt解析工具类到AppJwtUtil到admin-gateway模块下

package com.heima.admin.gateway.util;

import io.jsonwebtoken.*;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;

public class AppJwtUtil {

    // TOKEN的有效期一天(S)
    private static final int TOKEN_TIME_OUT = 3_600;
    // 加密KEY
    private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";
    // 最小刷新间隔(S)
    private static final int REFRESH_TIME = 300;

    // 生产ID
    public static String getToken(Long id){
        Map<String, Object> claimMaps = new HashMap<>();
        claimMaps.put("id",id);
        long currentTime = System.currentTimeMillis();
        return Jwts.builder()
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date(currentTime))  //签发时间
                .setSubject("system")  //说明
                .setIssuer("heima") //签发者信息
                .setAudience("app")  //接收用户
                .compressWith(CompressionCodecs.GZIP)  //数据压缩方式
                .signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式
                .setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000))  //过期时间戳
                .addClaims(claimMaps) //cla信息
                .compact();
    }

    /**
     * 获取token中的claims信息
     *
     * @param token
     * @return
     */
    private static Jws<Claims> getJws(String token) {
            return Jwts.parser()
                    .setSigningKey(generalKey())
                    .parseClaimsJws(token);
    }

    /**
     * 获取payload body信息
     *
     * @param token
     * @return
     */
    public static Claims getClaimsBody(String token) {
        try {
            return getJws(token).getBody();
        }catch (ExpiredJwtException e){
            return null;
        }
    }

    /**
     * 获取hearder body信息
     *
     * @param token
     * @return
     */
    public static JwsHeader getHeaderBody(String token) {
        return getJws(token).getHeader();
    }

    /**
     * 是否过期
     *
     * @param claims
     * @return -1:有效,0:有效,1:过期,2:过期
     */
    public static int verifyToken(Claims claims) {
        if(claims==null){
            return 1;
        }
        try {
            claims.getExpiration()
                    .before(new Date());
            // 需要自动刷新TOKEN
            if((claims.getExpiration().getTime()-System.currentTimeMillis())>REFRESH_TIME*1000){
                return -1;
            }else {
                return 0;
            }
        } catch (ExpiredJwtException ex) {
            return 1;
        }catch (Exception e){
            return 2;
        }
    }

    /**
     * 由字符串生成加密key
     *
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    public static void main(String[] args) {
       /* Map map = new HashMap();
        map.put("id","11");*/
        System.out.println(AppJwtUtil.getToken(1102L));
        Jws<Claims> jws = AppJwtUtil.getJws("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAADWLQQqEMAwA_5KzhURNt_qb1KZYQSi0wi6Lf9942NsMw3zh6AVW2DYmDGl2WabkZgreCaM6VXzhFBfJMcMARTqsxIG9Z888QLui3e3Tup5Pb81013KKmVzJTGo11nf9n8v4nMUaEY73DzTabjmDAAAA.4SuqQ42IGqCgBai6qd4RaVpVxTlZIWC826QA9kLvt9d-yVUw82gU47HDaSfOzgAcloZedYNNpUcd18Ne8vvjQA");
        Claims claims = jws.getBody();
        System.out.println(claims.get("id"));

    }

}

⑥在admin网关微服务中新建全局过滤器

package com.heima.admin.gateway.filter;

import com.heima.admin.gateway.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
@Slf4j
public class AuthorizeFilter implements Ordered, GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. 获取request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        // 2. 判断是否是登录
        if(request.getURI().getPath().contains("/login")) {
            // 放行
            return chain.filter(exchange);
        }

        // 3. 获取token
        String token = request.getHeaders().getFirst("token");

        // 4. 判断token是否存在
        if(StringUtils.isBlank(token)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        // 5. 判断token是否有效
        try {
            Claims claimsBody = AppJwtUtil.getClaimsBody(token);
            // 判断token是否过期
            int result = AppJwtUtil.verifyToken(claimsBody);
            if (result == 1 || result == 2) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }

            // 获取token解析后的用户信息
            Object userId = claimsBody.get("id");

            // 存入header中
            ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
                httpHeaders.add("userId", userId + "");
            }).build();

            // 重置请求
            exchange.mutate().request(serverHttpRequest);

        } catch (Exception e) {
            e.printStackTrace();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        // 6. 放行
        return chain.filter(exchange);
    }

    /**
     * 优先级设置:值越小,优先级越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

⑦启动AdminGatewayApplication和AdminApplication进行测试

三、频道管理

1. 新增频道

(1)需求分析

  • 前台输入内容进行频道的保存
  • 频道名称不能重复

(2)接口定义

说明
接口地址/api/v1/channel/save
请求方式POST
参数WmChannel
响应结果ResponseResult

(3)实现步骤

wemedia模块

步骤①:新增接口 - WmChannelController

    /**
     * 新增频道
     * @param adChannel
     * @return
     */
    @PostMapping("/save")
    public ResponseResult insert(@RequestBody WmChannel adChannel) {
        return wmChannelService.insert(adChannel);
    }

②业务层 - WmChannelService

    /**
     * 新增保存频道
     * @param adChannel
     * @return
     */
    ResponseResult insert(WmChannel adChannel);

③实现类 - WmChannelServiceImpl

    /**
     * 新增保存频道
     * @param adChannel
     * @return
     */
    @Override
    public ResponseResult insert(WmChannel adChannel) {
        // 1. 检查参数
        if(adChannel == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        // 检查是否存在频道名称相同的情况
        WmChannel channel = getOne(Wrappers.<WmChannel>lambdaQuery().eq(WmChannel::getName, adChannel.getName()));
        if(channel != null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST, "频道已存在");
        }

        // 2. 保存频道
        adChannel.setCreatedTime(new Date());
        save(adChannel);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

2. 查询频道列表

(1)需求分析

  • 查询需要按照创建时间倒序查询
  • 按照频道名称模糊查询
  • 可以按照状态进行精确查找(1:启用 true 0:禁用 false)
  • 分页查询

(2)接口定义

说明
接口地址/api/v1/channel/list
请求方式POST
参数ChannelDto
响应结果ResponseResult

(3)实现步骤

步骤①:新增实体类ChannelDto

package com.heima.model.wemedia.dtos;

import com.heima.model.common.dtos.PageRequestDto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
public class ChannelDto extends PageRequestDto {
    /**
     * 频道名称
     */
    @ApiModelProperty(value = "频道名称")
    private String name;
}

②WmChannelController中新增接口

    /**
     * 根据频道名称模糊分页查询
     * @param dto
     * @return
     */
    @PostMapping("/list")
    public ResponseResult findByNameAndPage(@RequestBody ChannelDto dto) {
        return wmChannelService.findByNameAndPage(dto);
    }

③WmChannelService

    /**
     * 根据频道名称模糊分页查询
     * @param dto
     * @return
     */
    ResponseResult findByNameAndPage(ChannelDto dto);

④WmChannelServiceImpl

    /**
     * 根据频道名称模糊分页查询
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findByNameAndPage(ChannelDto dto) {
        // 1. 检查参数
        if(dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 检查分页
        dto.checkParam();

        // 3. 模糊查询 + 分页
        IPage page = new Page(dto.getPage(), dto.getSize());
        // 频道名称模糊查询
        LambdaQueryWrapper<WmChannel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(StringUtils.isNotBlank(dto.getName())) {
            lambdaQueryWrapper.like(WmChannel::getName, dto.getName());
        }

        page = page(page, lambdaQueryWrapper);

        // 4. 结果返回
        ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int)page.getTotal());
        responseResult.setData(page.getRecords());

        return responseResult;
    }

⑤启动以下服务进行测试

3. 修改频道

(1)需求分析

  • 点击编辑后可以修改频道
  • 如果频道被引用则不能禁用

(2)接口定义

说明
接口地址/api/v1/channel/update
请求方式POST
参数WmChannel
响应结果ResponseResult

(3)实现步骤

步骤①:WmChannelController新增接口

    /**
     * 修改频道信息
     * @param adChannel
     * @return
     */
    @PostMapping("/update")
    public ResponseResult update(@RequestBody WmChannel adChannel) {
        return wmChannelService.update(adChannel);
    }

②WmChannelService新增业务

    /**
     * 修改频道信息
     * @param adChannel
     * @return
     */
    ResponseResult update(WmChannel adChannel);

③WmChannelServiceImpl实现业务方法

    /**
     * 修改频道信息
     * @param adChannel
     * @return
     */
    @Override
    public ResponseResult update(WmChannel adChannel) {
        // 1. 检查参数
        if(adChannel == null || adChannel.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 判断频道是否被已发布的文章引用
        int count = wmNewsService.count(Wrappers
                .<WmNews>lambdaQuery()
                .eq(WmNews::getChannelId, adChannel.getId())
                .eq(WmNews::getStatus, WmNews.Status.PUBLISHED.getCode()));

        if(count > 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "频道被引用不能修改或禁用");
        }

        // 3. 修改
        updateById(adChannel);

        // 4. 返回结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

④测试

4. 删除频道

(1)需求分析

  • 只有禁用的频道才能被删除

(2)接口定义

说明
接口地址/api/v1/channel/del/{id}
请求方式GET
参数频道id
响应结果ResponseResult

(3)实现步骤

步骤①:新增接口 - WmChannelController

    /**
     * 删除频道
     * @param id
     * @return
     */
    @GetMapping("del/{id}")
    public ResponseResult delete(@PathVariable("id") Integer id) {
        return wmChannelService.delete(id);
    }

②新增业务方法 - WmChannelService

    /**
     * 删除频道
     * @param id
     * @return
     */
    ResponseResult delete(Integer id);

③实现 - WmChannelServiceImpl

    /**
     * 删除频道
     * @param id
     * @return
     */
    @Override
    public ResponseResult delete(Integer id) {
        // 1. 检查参数
        if(id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 查询频道
        WmChannel wmChannel = getById(id);
        if(wmChannel == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        // 3. 频道是否有效 -> 启动
        if(wmChannel.getStatus()) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "频道有效,不能删除");
        }

        // 4. 判断频道是否被已发表的文章引用
        int count = wmNewsService.count(Wrappers
                .<WmNews>lambdaQuery()
                .eq(WmNews::getChannelId, wmChannel.getId())
                .eq(WmNews::getStatus, WmNews.Status.PUBLISHED.getCode()));
        if(count > 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "频道被引用,不能删除");
        }

        // 5. 删除频道
        removeById(id);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

④测试

四、敏感词管理

1. 新增敏感词

(1)需求分析

  • 弹出的输入框,输入敏感词可直接保存
  • 已存在的敏感词则不能保存

(2)接口定义

说明
接口地址/api/v1/sensitive/save
请求方式POST
参数WmSensitive
响应结果ResponseResult

(3)实现步骤

步骤①:在model模块的wemedia模块新增SentitiveDto 

package com.heima.model.wemedia.dtos;

import com.heima.model.common.dtos.PageRequestDto;
import lombok.Data;

@Data
public class SensitiveDto extends PageRequestDto {

    /**
     * 敏感词名称
     */
    private String name;
}

②wemedia模块mapper下新增WmSensitiveMapper

package com.heima.wemedia.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.wemedia.pojos.WmSensitive;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface WmSensitiveMapper extends BaseMapper<WmSensitive> {
}

③WmSensitiveController

package com.heima.wemedia.controller.v1;

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.wemedia.service.WmSensitiveService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/v1/sensitive")
public class WmSensitiveController {
    @Autowired
    private WmSensitiveService wmSensitiveService;

    /**
     * 新增敏感词
     * @param wmSensitive
     * @return
     */
    @PostMapping("/save")
    public ResponseResult insert(@RequestBody WmSensitive wmSensitive) {
        return wmSensitiveService.insert(wmSensitive);
    }

}

④WmSensitiveService

package com.heima.wemedia.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmSensitive;

public interface WmSensitiveService extends IService<WmSensitive> {

    /**
     * 新增敏感词
     * @param wmSensitive
     * @return
     */
    ResponseResult insert(WmSensitive wmSensitive);
}

⑤WmSensitiveServiceImpl

package com.heima.wemedia.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.service.WmSensitiveService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

@Service
@Slf4j
@Transactional
public class WmSensitiveServiceImpl extends ServiceImpl<WmSensitiveMapper, WmSensitive> implements WmSensitiveService {


    /**
     * 新增敏感词
     * @param wmSensitive
     * @return
     */
    @Override
    public ResponseResult insert(WmSensitive wmSensitive) {
        // 1. 检查参数
        if(wmSensitive == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 已存在的敏感词,不能保存
        WmSensitive sensitive = getOne(Wrappers
                .<WmSensitive>lambdaQuery()
                .eq(WmSensitive::getSensitives, wmSensitive.getSensitives()));
        if(sensitive != null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST, "敏感词已存在");
        }

        // 3. 保存敏感词
        wmSensitive.setCreatedTime(new Date());
        save(wmSensitive);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }
}

⑥测试

2. 查询敏感词列表

(1)需求分析

  • 查询需要按照创建时间倒序查询
  • 按照敏感词名称模糊查询
  • 分页查询

(2)接口定义

说明
接口地址/api/v1/sensitive/list
请求方式POST
参数SensitiveDto
响应结果ResponseResult

(3)实现步骤

步骤①:在WmSensitiveController新增接口

    /**
     * 查询敏感词列表
     * @param dto
     * @return
     */
    @PostMapping("/list")
    public ResponseResult list(@RequestBody SensitiveDto dto) {
        return wmSensitiveService.list(dto);
    }

②WmSensitiveService新增业务方法

    /**
     * 查询敏感词列表
     * @param dto
     * @return
     */
    ResponseResult list( SensitiveDto dto);

③WmSenstiveServiceImpl实现业务方法

    /**
     * 查询敏感词列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult list(SensitiveDto dto) {
        // 1. 检查参数
        if(dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 检查分页
        dto.checkParam();

        // 3. 模糊查询 + 分页
        IPage page = new Page(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<WmSensitive> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(StringUtils.isNotBlank(dto.getName())) {
            lambdaQueryWrapper.like(WmSensitive::getSensitives, dto.getName());
        }
        page = page(page, lambdaQueryWrapper);

        // 4. 结果返回
        ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int)page.getTotal());
        responseResult.setData(page.getRecords());
        return responseResult;
    }

④启动ScheduleApplication、AdminApplication、AdminGatewayApplication、WemediaGatewayApplication、WemediaApplication进行测试

3. 修改敏感词

(1)需求分析

(2)接口定义

说明
接口地址/api/v1/sensitive/update
请求方式POST
参数WmSensitive
响应结果ResponseResult

(3)实现步骤

步骤①:WmSensitiveController

    /**
     * 修改敏感词信息
     * @param wmSensitive
     * @return
     */
    @PostMapping("/update")
    public ResponseResult update(@RequestBody WmSensitive wmSensitive) {
        return wmSensitiveService.update(wmSensitive);
    }

②WmSensitiveService

    /**
     * 修改名称信息
     * @param wmSensitive
     * @return
     */
    ResponseResult update(WmSensitive wmSensitive);

③WmSensitiveServiceImpl

    /**
     * 修改敏感词信息
     * @param wmSensitive
     * @return
     */
    @Override
    public ResponseResult update(WmSensitive wmSensitive) {
        // 1. 检查参数
        if(wmSensitive == null || wmSensitive.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 根据id查询敏感词信息
        WmSensitive sensitive = getById(wmSensitive);
        if(sensitive == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        // 3. 修改敏感词信息
        updateById(wmSensitive);

        // 4. 结果返回
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

④测试

4. 删除敏感词

(1)需求分析

  • 直接根据敏感词id删除即可

(2)接口定义

说明
接口地址/api/v1/sensitive/del{id}
请求方式DELETE
参数敏感词id
响应结果ResponseResult

(3)实现步骤

步骤①:WmSensitiveController

    /**
     * 删除敏感词
     * @param id
     * @return
     */
    @DeleteMapping("del/{id}")
    public ResponseResult delete(@PathVariable("id") Integer id) {
        return wmSensitiveService.delete(id);
    }

②WmSensitiveService

    /**
     * 删除敏感词
     * @param id
     * @return
     */
    ResponseResult delete(Integer id);

③WmSensitiveImpl

    /**
     * 删除敏感词
     * @param id
     * @return
     */
    @Override
    public ResponseResult delete(Integer id) {
        // 1. 检查参数
        if(id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 查询敏感词
        WmSensitive wmSensitive = getById(id);
        if(wmSensitive == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        // 3. 删除
        removeById(id);

        // 4. 结果返回
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

④测试

五、用户认证审核

  • 在app端的个人中心用户可以实名认证,需要材料为:姓名、身份证号、身份证正面照、身份证反面照、手持照片、活体照片(通过微笑、眨眼、张嘴、摇头、点头等组合动作,确保操作的为真实活体人脸),当用户提交审核后就到了后端让运营人员进行审核
  • 平台运营端查看用户认证信息,进行审核,其中审核包括了用户身份审核,需要对接公安系统校验身份证信息
  • 用户通过审核后需要开通自媒体账号(该账户的用户名和密码与app端一致)

1. 分页查询认证查询列表

(1)需求分析

  • 可根据审核状态条件查询
  • 需要分页查询

(2)接口设计

说明
接口地址/api/v1/auth/list
请求方式POST
参数AuthDto
响应结果ResponseResult

(3)实现步骤

步骤①:在leadnews-user模块新增Mapper - ApUserRealnameMapper

package com.heima.user.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.user.pojos.ApUserRealname;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ApUserRealnameMapper extends BaseMapper<ApUserRealname> {
}

②在model模块的user模块下新增AuthDto实体类

package com.heima.model.user.dtos;

import com.heima.model.common.dtos.PageRequestDto;
import lombok.Data;

@Data
public class AuthDto  extends PageRequestDto {

    /**
     * 状态
     */
    private Short status;

    private Integer id;

    //驳回的信息
    private String msg;
}

③在model模块的user模块下新增ApUserRealname实体类

package com.heima.model.user.pojos;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * <p>
 * APP实名认证信息表
 * </p>
 *
 * @author itheima
 */
@Data
@TableName("ap_user_realname")
public class ApUserRealname implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 账号ID
     */
    @TableField("user_id")
    private Integer userId;

    /**
     * 用户名称
     */
    @TableField("name")
    private String name;

    /**
     * 资源名称
     */
    @TableField("idno")
    private String idno;

    /**
     * 正面照片
     */
    @TableField("font_image")
    private String fontImage;

    /**
     * 背面照片
     */
    @TableField("back_image")
    private String backImage;

    /**
     * 手持照片
     */
    @TableField("hold_image")
    private String holdImage;

    /**
     * 活体照片
     */
    @TableField("live_image")
    private String liveImage;

    /**
     * 状态
            0 创建中
            1 待审核
            2 审核失败
            9 审核通过
     */
    @TableField("status")
    private Short status;

    /**
     * 拒绝原因
     */
    @TableField("reason")
    private String reason;

    /**
     * 创建时间
     */
    @TableField("created_time")
    private Date createdTime;

    /**
     * 提交时间
     */
    @TableField("submited_time")
    private Date submitedTime;

    /**
     * 更新时间
     */
    @TableField("updated_time")
    private Date updatedTime;

}

④在leadnews-user模块下新增ApUserRealnameController

package com.heima.user.controller.v1;

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.user.dtos.AuthDto;
import com.heima.user.service.ApUserRealnameService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/v1/auth")
public class ApUserRealnameController {
    @Autowired
    private ApUserRealnameService apUserRealnameService;

    /**
     * 查询用户列表
     * @param dto
     * @return
     */
    @PostMapping("/list")
    public ResponseResult list(@RequestBody AuthDto dto) {
        return apUserRealnameService.list(dto);
    }

}

⑤ApUserRealnameService

package com.heima.user.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.user.dtos.AuthDto;
import com.heima.model.user.pojos.ApUserRealname;

public interface ApUserRealnameService extends IService<ApUserRealname> {

    /**
     * 分页查询认证列表
     * @param dto
     * @return
     */
    ResponseResult list(AuthDto dto);
}

⑥ApUserRealnameServiceImpl

package com.heima.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.AuthDto;
import com.heima.model.user.pojos.ApUserRealname;
import com.heima.user.mapper.ApUserRealnameMapper;
import com.heima.user.service.ApUserRealnameService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
@Transactional
public class ApUserRealnameServiceImpl extends ServiceImpl<ApUserRealnameMapper, ApUserRealname> implements ApUserRealnameService {

    /**
     * 分页查询认证列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult list(AuthDto dto) {
        // 1. 检查参数
        if(dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 分页条件查询
        dto.checkParam();

        // 3. 分页根据状态精确查询
        IPage page = new Page(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<ApUserRealname> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (dto.getStatus() != null) {
            lambdaQueryWrapper.eq(ApUserRealname::getStatus, dto.getStatus());
        }
        page = page(page, lambdaQueryWrapper);

        // 4. 结果返回
        ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int)page.getTotal());
        responseResult.setData(page.getRecords());

        return responseResult;
    }
}

⑦测试

2. 审核失败

(1)需求分析

  • 审核不通过,拒绝注册为自媒体用户

(2)接口设计

说明
接口地址/api/v1/auth/authFail
请求方式POST
参数AuthDto
响应结果ResponseResult

(3)实现步骤

步骤①:在common模块新增常量类 UserConstants

package com.heima.common.constants;

public class UserConstants {
    public static final Short PASS_AUTH = 9;
    public static final Short FAIL_AUTH = 2;
    public static final Integer AUTH_TYPE = 2;
}

②ApUserRealnameController

    /**
     * 审核不通过
     * @param dto
     * @return
     */
    @PostMapping("/authFail")
    public ResponseResult authFail(@RequestBody AuthDto dto) {
        return apUserRealnameService.updateByStatus(dto, UserConstants.FAIL_AUTH);
    }

③ApUserRealnameService

    /**
     * 根据审核状态更新审核结果
     * @param dto
     * @param status 2审核失败 9审核成功
     * @return
     */
    ResponseResult updateByStatus(AuthDto dto, Short status);

④ApUserRealnameServiceImpl

    /**
     * 根据状态更新审核结果
     * @param dto
     * @param status 2审核失败 9审核成功
     * @return
     */
    @Override
    public ResponseResult updateByStatus(AuthDto dto, Short status) {
        // 1. 检查参数
        if(dto == null || dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 修改认证状态
        ApUserRealname apUserRealname = new ApUserRealname();
        apUserRealname.setId(dto.getId());
        apUserRealname.setStatus(status);
        apUserRealname.setUpdatedTime(new Date());
        if(StringUtils.isNotBlank(dto.getMsg())) {
            // 审核不通过原因
            apUserRealname.setReason(dto.getMsg());
        }
        updateById(apUserRealname);

        // 3. 如果审核状态为成功->9,需要创建自媒体账户
        if(status.equals(UserConstants.PASS_AUTH)) {
            // 通过审核
            ResponseResult responseResult = createWmUserAndAuthor(dto);
            if(responseResult != null) {
                return responseResult;
            }
        }

        // 4. 返回结果
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 创建自媒体账户
     * @param dto
     * @return
     */
    private ResponseResult createWmUserAndAuthor(AuthDto dto) {
        Integer userRealnameId = dto.getId();
        // 1. 查询用户认证信息
        ApUserRealname apUserRealname = getById(userRealnameId);
        if(apUserRealname == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        // 2. 查询app端用户信息
        Integer userId = apUserRealname.getUserId();
        ApUser apUser = apUserMapper.selectById(userId);
        if(apUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        // 3. 创建自媒体用户
        WmUser wmUser =wemediaClient.findWmUserByName(apUser.getName());
        if(wmUser == null) {
            wmUser = new WmUser();
            wmUser.setApUserId(apUser.getId());
            wmUser.setCreatedTime(new Date());
            wmUser.setName(apUser.getName());
            wmUser.setPassword(apUser.getPassword());
            wmUser.setSalt(apUser.getSalt());
            wmUser.setPhone(apUser.getPhone());
            wmUser.setStatus(9);
            wemediaClient.saveWmUser(wmUser);
        }

        apUser.setFlag((short) 1);
        apUserMapper.updateById(apUser);

        return null;
    }

⑤在heima-leadnews-feign-api添加远程调用接口 - IWemediaClient

package com.heima.apis.wemedia;

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmUser;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@FeignClient("leadnews-wemedia")
public interface IWemediaClient {


    @GetMapping("/api/v1/user/findByName/{name}")
    WmUser findWmUserByName(@PathVariable("name") String name);

    @PostMapping("/api/v1/wm_user/save")
    ResponseResult saveWmUser(@RequestBody WmUser wmUser);

    @GetMapping("/api/v1/channel/list")
    public ResponseResult getChannels();
}

⑥在heima-leadnews-wemedia新增feign包,新增WemediaClient类

package com.heima.wemedia.feign;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.wemedia.IWemediaClient;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.wemedia.service.WmChannelService;
import com.heima.wemedia.service.WmUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
public class WemediaClient implements IWemediaClient {

    @Autowired
    private WmUserService wmUserService;

    @Override
    @GetMapping("/api/v1/user/findByName/{name}")
    public WmUser findWmUserByName(@PathVariable("name") String name) {
        return wmUserService.getOne(Wrappers.<WmUser>lambdaQuery().eq(WmUser::getName, name));
    }

    @Override
    @PostMapping("/api/v1/wm_user/save")
    public ResponseResult saveWmUser(@RequestBody WmUser wmUser) {
        wmUserService.save(wmUser);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Autowired
    private WmChannelService wmChannelService;

    @GetMapping("/api/v1/channel/list")
    @Override
    public ResponseResult getChannels() {
        return wmChannelService.findAll();
    }
}

⑦在user模块开启远程调用

package com.heima.user;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.user.mapper")
@EnableFeignClients(basePackages = "com.heima.apis")
public class UserApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }
}

3. 审核成功

(1)需求分析

  • 实名认证通过后,为用户新建自媒体用户账户

(2)接口设计

说明
接口地址/api/v1/auth/authPass
请求方式POST
参数AuthDto
响应结果ResponseResult

(3)实现步骤

①ApUserRealnameController

    /**
     * 审核成功
     * @param dto
     * @return
     */
    @PostMapping("/authPass")
    public ResponseResult authPass(@RequestBody AuthDto dto) {
        return apUserRealnameService.updateByStatus(dto, UserConstants.PASS_AUTH);
    }

②重启服务进行测试

ap_user_realname表

wm_user表

六、自媒体文章人工审核

自媒体文章如果没有自动审核成功,而是到了人工审核(自媒体文章状态为3),需要在admin端人工处理文章的审核:

  • 平台管理员可以查看待人工审核的文章信息,如果存在违规内容则驳回(状态修改为2,文章审核失败)
  • 平台管理员可以查看待人工审核的文章信息,如果不存在违规,则需要创建app端的文章信息,并更新自媒体文章的状态
  • 也可以通过点击查看按钮,查看文章详细信息,查看详情后可以根据内容判断是否需要通过审核

1. 查询文章列表

1)需求分析

  • 分页查询自媒体文章
  • 可以按照标题模糊查询
  • 可以按照审核状态ji进行精确检索
  • 文章查询按照创建时间倒序查询
  • 注意:需要展示作者名称

(2)接口设计

说明
接口地址/api/v1/news/list_vo
请求方式POST
参数NewsAuthDto
响应结果ResponseResult

(3)实现步骤

步骤①:在model模块下的wemedia新增实体类WmNewsVo  

package com.heima.model.wemedia.vo;

import com.heima.model.wemedia.pojos.WmNews;
import lombok.Data;

@Data
public class WmNewsVo  extends WmNews {
    /**
     * 作者名称
     */
    private String authorName;
}

②在heima-leadnews-wemedia模块新增WmNewsMapper

package com.heima.wemedia.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.wemedia.dtos.NewsAuthDto;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.vo.WmNewsVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface WmNewsMapper extends BaseMapper<WmNews> {

    List<WmNewsVo> findListAndPage(@Param("dto") NewsAuthDto dto);

    int findListCount(@Param("dto") NewsAuthDto dto);
}

③在resources/mapper下新建对应的映射文件 - WmNewsMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.heima.wemedia.mapper.WmNewsMapper">
    <select id="findListAndPage" parameterType="com.heima.model.wemedia.dtos.NewsAuthDto"
    resultType="com.heima.model.wemedia.vo.WmNewsVo">
        SELECT
            wn.*,wu.`name` authorName
        FROM
            wm_news  wn
                LEFT JOIN
            wm_user wu
            ON wn.user_id = wu.id
        <where>
            <if test="dto.title!=null and dto.title!=''">
                and wn.title like concat('%',#{dto.title},'%')
            </if>
            <if test="dto.status!=null">
                and wn.status = #{dto.status}
            </if>
        </where>
        limit #{dto.page},#{dto.size}
    </select>

    <select id="findListCount" parameterType="com.heima.model.wemedia.dtos.NewsAuthDto"
            resultType="int">
        SELECT
        count(1)
        FROM
        wm_news  wn
        LEFT JOIN
        wm_user wu
        ON wn.user_id = wu.id
        <where>
            <if test="dto.title!=null and dto.title!=''">
                and wn.title like concat('%',#{dto.title},'%')
            </if>
            <if test="dto.status!=null">
                and wn.status = #{dto.status}
            </if>
        </where>

    </select>

</mapper>

④WmNewsController新增接口

    /**
     * 查询(待审核)文章列表
     * @param dto
     * @return
     */
    @PostMapping("/list_vo")
    public ResponseResult findList(@RequestBody NewsAuthDto dto) {
        return wmNewsService.findList(dto);
    }

⑤WmNewsService新增业务方法

    /**
     * 查询文章列表
     * @param dto
     * @return
     */
    ResponseResult findList(NewsAuthDto dto);

⑥WmNewsServiceImpl实现业务方法

    @Autowired
    private WmNewsMapper wmNewsMapper;

    /**
     * 查询(待审核)文章列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findList(NewsAuthDto dto) {
        // 1. 参数检查
        dto.checkParam();

        // 2. 记录当前页
        int currentPage = dto.getPage();

        // 3. 分页查询 + count查询
        dto.setPage((dto.getPage() - 1) * dto.getSize());
        List<WmNewsVo> wmNewsVoList = wmNewsMapper.findListAndPage(dto);
        int count = wmNewsMapper.findListCount(dto);

        // 4. 结果返回
        ResponseResult responseResult = new PageResponseResult(currentPage, dto.getSize(), count);
        responseResult.setData(wmNewsVoList);
        return responseResult;
    }

⑦测试

2. 查询文章详情

1)需求分析

  • 可以查看文章详细内容
  • 注意:需要展示作者名称

(2)接口设计

说明
接口地址/api/v1/news/one_vo/{id}
请求方式GET
参数文章id
响应结果ResponseResult

(3)实现步骤

步骤①:WmNewsController

    /**
     * 查看文章详情
     * @param id
     * @return
     */
    @GetMapping("/one_vo/{id}")
    public ResponseResult findWmNewsVo(@PathVariable("id") Integer id) {
        return wmNewsService.findWmNewsVo(id);
    }

②WmNewsService

    /**
     * 查看文章详情
     * @param id
     * @return
     */
    ResponseResult findWmNewsVo(Integer id);

③WmNewsServiceImpl

    @Autowired
    private WmUserMapper wmUserMapper;


    /**
     * 查看文章详情
     * @param id
     * @return
     */
    @Override
    public ResponseResult findWmNewsVo(Integer id) {
        // 1. 检查参数
        if(id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 查询文章信息
        WmNews wmNews = getById(id);
        if(wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        // 3. 查询用户信息
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());

        // 4. 封装vo返回
        WmNewsVo vo = new WmNewsVo();
        // 属性拷贝
        BeanUtils.copyProperties(wmNews, vo);
        if(wmUser != null) {
            vo.setAuthorName(wmUser.getName());
        }

        // 5. 结果返回
        ResponseResult responseResult = new ResponseResult<>().ok(vo);
        return responseResult;
    }

⑦测试

3. 审核失败

1)需求分析

  • 拒绝以后需要给出原因,并修改文章的状态为2

(2)接口设计

说明
接口地址/api/v1/news/auth_fail
请求方式POST
参数NewsAuthDto
响应结果ResponseResult

(3)实现步骤

步骤①:在WemediaConstants添加两个常量

    public static final Short WM_NEWS_AUTH_PASS = 4;
    public static final Short WM_NEWS_AUTH_FAIL = 2;

②WmNewsController

    /**
     * 审核失败
     * @param dto
     * @return
     */
    @PostMapping("/auth_fail")
    public ResponseResult authFail(@RequestBody NewsAuthDto dto) {
        return wmNewsService.updateByStatus(WemediaConstants.WM_NEWS_AUTH_FAIL, dto);
    }

③WmNewsService

    /**
     * 文章审核,修改状态
     * @param status 2审核失败 4审核成功
     * @param dto
     * @return
     */
    ResponseResult updateByStatus(Short status, NewsAuthDto dto);

④WmNewsServiceImpl

    @Override
    public ResponseResult updateByStatus(Short status, NewsAuthDto dto) {
        // 1. 检查参数
        if(dto == null || dto.getId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 查询文章信息
        WmNews wmNews = getById(dto.getId());
        if(wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        // 3. 修改文章的状态
        wmNews.setStatus(status);
        if(StringUtils.isNotBlank(dto.getMsg())) {
            wmNews.setReason(dto.getMsg());
        }
        updateById(wmNews);

        // 4. 审核成功,则要创建app端文章数据,并修改自媒体文章
        if(status.equals(WemediaConstants.WM_NEWS_AUTH_PASS)) {
            // 创建app端文章数据
            ResponseResult responseResult = wmNewsAutoScanService.saveAppArticle(wmNews);
            if(responseResult.getCode().equals(200)) {
                wmNews.setArticleId((Long) responseResult.getData());
                wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
                updateById(wmNews);
            }
        }

        // 5. 结果返回
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

⑤WmNewsAutoScanService

    /**
     * 保存app端文章数据
     * @param wmNews
     * @return
     */
    ResponseResult saveAppArticle(WmNews wmNews);

⑥测试

4. 审核成功

1)需求分析

  • 需要创建app端的文章信息,并更新自媒体文章的状态

(2)接口设计

说明
接口地址/api/v1/news/auth_pass
请求方式POST
参数NewsAuthDto
响应结果ResponseResult

(3)实现步骤

①WmNewsController

    /**
     * 审核成功
     * @param dto
     * @return
     */
    @PostMapping("/auth_pass")
    public ResponseResult authPass(@RequestBody NewsAuthDto dto) {
        return wmNewsService.updateByStatus(WemediaConstants.WM_NEWS_AUTH_PASS, dto);
    }

②测试

可能有不对或遗漏的地方,多多谅解!!!

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值