发生缘由
搭建头条项目自媒体端
运行环境
- 电脑系统版本:Windows 10 64bit
- Idea:2023.2 (Ultimate Edition)
- Maven:apache-maven-3.6.0
- Docker:Docker version 26.0.0, build 2ae903e
- MinIO:加载本地镜像,不清楚版本号
- jdk版本:jdk-8
- spring.boot.version:2.3.9.RELEASE
- minio依赖:7.1.0
问题重现
数据库配置
导入表 leadnews_wemedia.sql
# 命令行导入sql文件,路径不能加上双引号
mysql> source D:\Java\IdeaProjects\lead_news\!information\day03\leadnews_wemedia.sql
CREATE DATABASE IF NOT EXISTS leadnews_wemedia DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE leadnews_wemedia;
SET NAMES utf8;
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for wm_channel
-- ----------------------------
DROP TABLE IF EXISTS `wm_channel`;
CREATE TABLE `wm_channel` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '频道名称',
`description` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '频道描述',
`is_default` tinyint(1) unsigned DEFAULT NULL COMMENT '是否默认频道',
`status` tinyint(1) unsigned DEFAULT NULL,
`ord` tinyint(3) unsigned DEFAULT NULL COMMENT '默认排序',
`created_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='频道信息表';
-- ----------------------------
-- Records of wm_channel
-- ----------------------------
INSERT INTO `wm_channel` VALUES ('0', '其他', '其他', '1', '1', '12', '2021-04-18 10:55:41');
INSERT INTO `wm_channel` VALUES ('1', 'java', '后端框架', '1', '1', '1', '2021-04-18 12:25:30');
INSERT INTO `wm_channel` VALUES ('2', 'Mysql', '轻量级数据库', '1', '1', '4', '2021-04-18 10:55:41');
INSERT INTO `wm_channel` VALUES ('3', 'Vue', '阿里前端框架', '1', '1', '5', '2021-04-18 10:55:41');
INSERT INTO `wm_channel` VALUES ('4', 'Python', '未来的语言', '1', '1', '6', '2021-04-18 10:55:41');
INSERT INTO `wm_channel` VALUES ('5', 'Weex', '向未来致敬', '1', '1', '7', '2021-04-18 10:55:41');
INSERT INTO `wm_channel` VALUES ('6', '大数据', '不会,则不要说自己是搞互联网的', '1', '1', '10', '2021-04-18 10:55:41');
-- ----------------------------
-- Table structure for wm_fans_statistics
-- ----------------------------
DROP TABLE IF EXISTS `wm_fans_statistics`;
CREATE TABLE `wm_fans_statistics` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` int(11) unsigned DEFAULT NULL COMMENT '主账号ID',
`article` int(11) unsigned DEFAULT NULL COMMENT '子账号ID',
`read_count` int(11) unsigned DEFAULT NULL,
`comment` int(11) unsigned DEFAULT NULL,
`follow` int(11) unsigned DEFAULT NULL,
`collection` int(11) unsigned DEFAULT NULL,
`forward` int(11) unsigned DEFAULT NULL,
`likes` int(11) unsigned DEFAULT NULL,
`unlikes` int(11) unsigned DEFAULT NULL,
`unfollow` int(11) unsigned DEFAULT NULL,
`burst` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_time` date DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_user_id_time` (`user_id`,`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='自媒体粉丝数据统计表';
-- ----------------------------
-- Records of wm_fans_statistics
-- ----------------------------
-- ----------------------------
-- Table structure for wm_material
-- ----------------------------
DROP TABLE IF EXISTS `wm_material`;
CREATE TABLE `wm_material` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` int(11) unsigned DEFAULT NULL COMMENT '自媒体用户ID',
`url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '图片地址',
`type` tinyint(1) unsigned DEFAULT NULL COMMENT '素材类型\r\n 0 图片\r\n 1 视频',
`is_collection` tinyint(1) DEFAULT NULL COMMENT '是否收藏',
`created_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=72 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='自媒体图文素材信息表';
-- ----------------------------
-- Records of wm_material
-- ----------------------------
INSERT INTO `wm_material` VALUES ('67', '1102', 'http://192.168.200.130:9000/leadnews/2021/04/26/a73f5b60c0d84c32bfe175055aaaac40.jpg', '0', '0', '2021-04-26 00:14:01');
INSERT INTO `wm_material` VALUES ('68', '1102', 'http://192.168.200.130:9000/leadnews/2021/04/26/d4f6ef4c0c0546e69f70bd3178a8c140.jpg', '0', '0', '2021-04-26 00:18:20');
INSERT INTO `wm_material` VALUES ('69', '1102', 'http://192.168.200.130:9000/leadnews/2021/04/26/5ddbdb5c68094ce393b08a47860da275.jpg', '0', '0', '2021-04-26 00:18:27');
INSERT INTO `wm_material` VALUES ('70', '1102', 'http://192.168.200.130:9000/leadnews/2021/04/26/9f8a93931ab646c0a754475e0c4b0a98.jpg', '0', '0', '2021-04-26 00:18:34');
INSERT INTO `wm_material` VALUES ('71', '1102', 'http://192.168.200.130:9000/leadnews/2021/04/26/ef3cbe458db249f7bd6fb4339e593e55.jpg', '0', '0', '2021-04-26 00:18:39');
-- ----------------------------
-- Table structure for wm_news
-- ----------------------------
DROP TABLE IF EXISTS `wm_news`;
CREATE TABLE `wm_news` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` int(11) unsigned DEFAULT NULL COMMENT '自媒体用户ID',
`title` varchar(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '标题',
`content` longtext COLLATE utf8mb4_unicode_ci COMMENT '图文内容',
`type` tinyint(1) unsigned DEFAULT NULL COMMENT '文章布局\r\n 0 无图文章\r\n 1 单图文章\r\n 3 多图文章',
`channel_id` int(11) unsigned DEFAULT NULL COMMENT '图文频道ID',
`labels` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_time` datetime DEFAULT NULL COMMENT '创建时间',
`submited_time` datetime DEFAULT NULL COMMENT '提交时间',
`status` tinyint(2) unsigned DEFAULT NULL COMMENT '当前状态\r\n 0 草稿\r\n 1 提交(待审核)\r\n 2 审核失败\r\n 3 人工审核\r\n 4 人工审核通过\r\n 8 审核通过(待发布)\r\n 9 已发布',
`publish_time` datetime DEFAULT NULL COMMENT '定时发布时间,不定时则为空',
`reason` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '拒绝理由',
`article_id` bigint(20) unsigned DEFAULT NULL COMMENT '发布库文章ID',
`images` longtext COLLATE utf8mb4_unicode_ci COMMENT '//图片用逗号分隔',
`enable` tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6232 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='自媒体图文内容信息表';
-- ----------------------------
-- Records of wm_news
-- ----------------------------
INSERT INTO `wm_news` VALUES ('6225', '1102', '“真”项目课程对找工作有什么帮助?', '[{\"type\":\"text\",\"value\":\"找工作,企业重点问的是项目经验,更是HR筛选的“第一门槛”,直接决定了你是否有机会进入面试环节。\\n\\n 项目经验更是评定“个人能力/技能”真实性的“证据”,反映了求职者某个方面的实际动手能力、对某个领域或某种技能的掌握程度。\"},{\"type\":\"image\",\"value\":\"http://192.168.200.130:9000/leadnews/2021/4/20210418/7d0911a41a3745efa8509a87f234813c.jpg\"},{\"type\":\"text\",\"value\":\"很多经过培训期望快速上岗的程序员,靠着培训机构“辅导”顺利经过面试官对于“项目经验”的考核上岗后,在面对“有限时间”“复杂业务”“新项目需求”等多项标签加持的工作任务,却往往不知从何下手或开发进度极其缓慢。最终结果就是:熬不过试用期。\\n\\n 从而也引发了企业对于“培训出身程序员”的“有色眼光”。你甚至也一度怀疑“IT培训班出来的人真的不行吗?”\"}]', '1', '1', '项目课程', '2021-04-19 00:08:10', '2021-04-19 00:08:10', '9', '2021-04-19 00:08:05', '审核成功', '1383828014629179393', 'http://192.168.200.130:9000/leadnews/2021/4/20210418/7d0911a41a3745efa8509a87f234813c.jpg', '1');
INSERT INTO `wm_news` VALUES ('6226', '1102', '学IT,为什么要学项目课程?', '[{\"type\":\"text\",\"value\":\"在选择IT培训机构时,你应该有注意到,很多机构都将“项目课程”作为培训中的重点。那么,为什么要学习项目课程?为什么项目课程才是IT培训课程的核心?\\n\\n 1\\n\\n 在这个靠“技术经验说话”的IT行业里,假如你是一个计算机或IT相关专业毕业生,在没有实际项目开发经验的情况下,“找到第一份全职工作”可能是你职业生涯中遇到的最大挑战。\\n\\n 为什么说找第一份工作很难?\\n\\n 主要在于:实际企业中用到的软件开发知识和在学校所学的知识是完全不同的。假设你已经在学校和同学做过周期长达2-3个月的项目,但真正工作中的团队协作与你在学校中经历的协作也有很多不同。\"},{\"type\":\"image\",\"value\":\"http://192.168.200.130:9000/leadnews/2021/4/20210418/e8113ad756a64ea6808f91130a6cd934.jpg\"},{\"type\":\"text\",\"value\":\"在实际团队中,每一位成员彼此团结一致,为项目的交付而努力,这也意味着你必须要理解好在项目中负责的那部分任务,在规定时间交付还需确保你负责的功能,在所有环境中都能很好地发挥作用,而不仅仅是你的本地机器。\\n\\n 这需要你对项目中的每一行代码严谨要求。学校练习的项目中,对bug的容忍度很大,而在实际工作中是绝对不能容忍的。项目中的任何一个环节都涉及公司利益,任何一个bug都可能影响公司的收入及形象。\"},{\"type\":\"image\",\"value\":\"http://192.168.200.130:9000/leadnews/2021/4/20210418/c7c3d36d25504cf6aecdcd5710261773.jpg\"}]', '3', '1', '项目课程', '2021-04-19 00:13:58', '2021-04-19 00:13:58', '9', '2021-04-19 00:10:48', '审核成功', '1383827995813531650', 'http://192.168.200.130:9000/leadnews/2021/4/20210418/7d0911a41a3745efa8509a87f234813c.jpg,http://192.168.200.130:9000/leadnews/2021/4/20210418/c7c3d36d25504cf6aecdcd5710261773.jpg,http://192.168.200.130:9000/leadnews/2021/4/20210418/e8113ad756a64ea6808f91130a6cd934.jpg', '1');
INSERT INTO `wm_news` VALUES ('6227', '1102', '小白如何辨别其真与伪&好与坏?', '[{\"type\":\"text\",\"value\":\"通过上篇《IT培训就业艰难,行业乱象频发,如何破解就业难题?》一文,相信大家已初步了解“项目课程”对程序员能否就业且高薪就业的重要性。\\n\\n 因此,小白在选择IT培训机构时,关注的重点就在于所学“项目课程”能否真正帮你增加就业筹码。当然,前提必须是学到“真”项目。\"},{\"type\":\"image\",\"value\":\"http://192.168.200.130:9000/leadnews/2021/4/20210418/1818283261e3401892e1383c1bd00596.jpg\"}]', '1', '1', '小白', '2021-04-19 00:15:05', '2021-04-19 00:15:05', '9', '2021-04-19 00:14:58', '审核成功', '1383827976310018049', 'http://192.168.200.130:9000/leadnews/2021/4/20210418/1818283261e3401892e1383c1bd00596.jpg', '1');
INSERT INTO `wm_news` VALUES ('6228', '1102', '工作线程数是不是设置的越大越好', '[{\"type\":\"text\",\"value\":\"根据经验来看,jdk api 一般推荐的线程数为CPU核数的2倍。但是有些书籍要求可以设置为CPU核数的8倍,也有的业务设置为CPU核数的32倍。\\n“工作线程数”的设置依据是什么,到底设置为多少能够最大化CPU性能,是本文要讨论的问题。\\n\\n工作线程数是不是设置的越大越好\\n显然不是的。使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。\\n一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生死于堆上。\\nJava中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着。\\n一个Java应用总是从main()方法开始运行,main()方法运行在一个线程内,它被称为主线程。\\n一旦创建一个新的线程,就产生一个新的调用栈。\"},{\"type\":\"image\",\"value\":\"http://192.168.200.130:9000/leadnews/2021/4/20210418/a3f0bc438c244f788f2df474ed8ecdc1.jpg\"}]', '1', '1', '11', '2021-04-19 00:16:57', '2021-04-19 00:16:57', '9', '2021-04-19 00:16:52', '审核成功', '1383827952326987778', 'http://192.168.200.130:9000/leadnews/2021/4/20210418/a3f0bc438c244f788f2df474ed8ecdc1.jpg', '1');
INSERT INTO `wm_news` VALUES ('6229', '1102', 'Base64编解码原理', '[{\"type\":\"text\",\"value\":\"我在面试过程中,问过很多高级java工程师,是否了解Base64?部分人回答了解,部分人直接回答不了解。而说了解的那部分人却回答不上来它的原理。\\n\\nBase64 的由来\\nBase64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。它是一种基于用64个可打印字符来表示二进制数据的表示方法。它通常用作存储、传输一些二进制数据编码方法!也是MIME(多用途互联网邮件扩展,主要用作电子邮件标准)中一种可打印字符表示二进制数据的常见编码方法!它其实只是定义用可打印字符传输内容一种方法,并不会产生新的字符集!\\n\\n传统的邮件只支持可见字符的传送,像ASCII码的控制字符就 不能通过邮件传送。这样用途就受到了很大的限制,比如图片二进制流的每个字节不可能全部是可见字符,所以就传送不了。最好的方法就是在不改变传统协议的情 况下,做一种扩展方案来支持二进制文件的传送。把不可打印的字符也能用可打印字符来表示,问题就解决了。Base64编码应运而生,Base64就是一种 基于64个可打印字符来表示二进制数据的表示方法。\"},{\"type\":\"image\",\"value\":\"http://192.168.200.130:9000/leadnews/2021/4/20210418/b44c65376f12498e873223d9d6fdf523.jpg\"},{\"type\":\"text\",\"value\":\"请在这里输入正文\"}]', '1', '1', '11', '2021-04-19 00:17:44', '2021-04-19 00:17:44', '9', '2021-04-19 00:17:42', '审核成功', '1383827911810011137', 'http://192.168.200.130:9000/leadnews/2021/4/20210418/b44c65376f12498e873223d9d6fdf523.jpg', '1');
INSERT INTO `wm_news` VALUES ('6230', '1102', '为什么项目经理不喜欢重构?', '[{\"type\":\"text\",\"value\":\"经常听到开发人员抱怨 ,“这么烂的代码,我来重构一下!”,“这代码怎么能这么写呢?谁来重构一下?”,“这儿有个坏味道,重构吧!”\\n\\n作为一名项目经理,每次听到“重构”两个字,既想给追求卓越代码的开发人员点个赞,同时又会感觉非常紧张,为什么又要重构?马上就要上线了,怎么还要改?是不是应该阻止开发人员做重构?\\n\\n重构几乎是开发人员最喜欢的一项实践了,可项目经理们却充满了顾虑,那么为什么项目经理不喜欢重构呢?\\n\\n老功能被破坏\\n不止一次遇到这样的场景,某一天一个老功能突然被破坏了,项目经理们感到奇怪,产品这块儿的功能已经很稳定了,也没有在这部分开发什么新功能,为什么突然出问题了呢?\"},{\"type\":\"image\",\"value\":\"http://192.168.200.130:9000/leadnews/2021/4/20210418/e8113ad756a64ea6808f91130a6cd934.jpg\"},{\"type\":\"image\",\"value\":\"http://192.168.200.130:9000/leadnews/2021/4/20210418/4a498d9cf3614570ac0cb2da3e51c164.jpg\"},{\"type\":\"text\",\"value\":\"请在这里输入正文\"}]', '1', '1', '11', '2021-04-19 00:19:23', '2021-04-19 00:19:23', '9', '2021-04-19 00:19:09', '审核成功', '1383827888816836609', 'http://192.168.200.130:9000/leadnews/2021/4/20210418/4a498d9cf3614570ac0cb2da3e51c164.jpg', '1');
INSERT INTO `wm_news` VALUES ('6231', '1102', 'Kafka文件的存储机制', '[{\"type\":\"text\",\"value\":\"Kafka文件的存储机制Kafka文件的存储机制Kafka文件的存储机制Kafka文件的存储机制Kafka文件的存储机制Kafka文件的存储机制Kafka文件的存储机制Kafka文件的存储机制Kafka文件的存储机制Kafka文件的存储机制\"},{\"type\":\"image\",\"value\":\"http://192.168.200.130:9000/leadnews/2021/4/20210418/4a498d9cf3614570ac0cb2da3e51c164.jpg\"},{\"type\":\"text\",\"value\":\"请在这里输入正文\"}]', '1', '1', '11', '2021-04-19 00:58:47', '2021-04-19 00:58:47', '9', '2021-04-19 00:20:17', '审核成功', '1383827787629252610', 'http://192.168.200.130:9000/leadnews/2021/4/20210418/4a498d9cf3614570ac0cb2da3e51c164.jpg', '1');
-- ----------------------------
-- Table structure for wm_news_material
-- ----------------------------
DROP TABLE IF EXISTS `wm_news_material`;
CREATE TABLE `wm_news_material` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`material_id` int(11) unsigned DEFAULT NULL COMMENT '素材ID',
`news_id` int(11) unsigned DEFAULT NULL COMMENT '图文ID',
`type` tinyint(1) unsigned DEFAULT NULL COMMENT '引用类型\r\n 0 内容引用\r\n 1 主图引用',
`ord` tinyint(1) unsigned DEFAULT NULL COMMENT '引用排序',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=281 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='自媒体图文引用素材信息表';
-- ----------------------------
-- Records of wm_news_material
-- ----------------------------
INSERT INTO `wm_news_material` VALUES ('255', '61', '6232', '0', '0');
INSERT INTO `wm_news_material` VALUES ('256', '61', '6232', '1', '0');
INSERT INTO `wm_news_material` VALUES ('263', '61', '6231', '0', '0');
INSERT INTO `wm_news_material` VALUES ('264', '61', '6231', '1', '0');
INSERT INTO `wm_news_material` VALUES ('265', '57', '6230', '0', '0');
INSERT INTO `wm_news_material` VALUES ('266', '61', '6230', '0', '1');
INSERT INTO `wm_news_material` VALUES ('267', '61', '6230', '1', '0');
INSERT INTO `wm_news_material` VALUES ('268', '58', '6229', '0', '0');
INSERT INTO `wm_news_material` VALUES ('269', '58', '6229', '1', '0');
INSERT INTO `wm_news_material` VALUES ('270', '62', '6228', '0', '0');
INSERT INTO `wm_news_material` VALUES ('271', '62', '6228', '1', '0');
INSERT INTO `wm_news_material` VALUES ('272', '66', '6227', '0', '0');
INSERT INTO `wm_news_material` VALUES ('273', '66', '6227', '1', '0');
INSERT INTO `wm_news_material` VALUES ('274', '57', '6226', '0', '0');
INSERT INTO `wm_news_material` VALUES ('275', '64', '6226', '0', '1');
INSERT INTO `wm_news_material` VALUES ('276', '65', '6226', '1', '0');
INSERT INTO `wm_news_material` VALUES ('277', '64', '6226', '1', '1');
INSERT INTO `wm_news_material` VALUES ('278', '57', '6226', '1', '2');
INSERT INTO `wm_news_material` VALUES ('279', '65', '6225', '0', '0');
INSERT INTO `wm_news_material` VALUES ('280', '65', '6225', '1', '0');
-- ----------------------------
-- Table structure for wm_news_statistics
-- ----------------------------
DROP TABLE IF EXISTS `wm_news_statistics`;
CREATE TABLE `wm_news_statistics` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` int(11) unsigned DEFAULT NULL COMMENT '主账号ID',
`article` int(11) unsigned DEFAULT NULL COMMENT '子账号ID',
`read_count` int(11) unsigned DEFAULT NULL COMMENT '阅读量',
`comment` int(11) unsigned DEFAULT NULL COMMENT '评论量',
`follow` int(11) unsigned DEFAULT NULL COMMENT '关注量',
`collection` int(11) unsigned DEFAULT NULL COMMENT '收藏量',
`forward` int(11) unsigned DEFAULT NULL COMMENT '转发量',
`likes` int(11) unsigned DEFAULT NULL COMMENT '点赞量',
`unlikes` int(11) unsigned DEFAULT NULL COMMENT '不喜欢',
`unfollow` int(11) unsigned DEFAULT NULL COMMENT '取消关注量',
`burst` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_time` date DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_user_id_time` (`user_id`,`created_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='自媒体图文数据统计表';
-- ----------------------------
-- Records of wm_news_statistics
-- ----------------------------
-- ----------------------------
-- Table structure for wm_user
-- ----------------------------
DROP TABLE IF EXISTS `wm_user`;
CREATE TABLE `wm_user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`ap_user_id` int(11) DEFAULT NULL,
`ap_author_id` int(11) DEFAULT NULL,
`name` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '登录用户名',
`password` varchar(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '登录密码',
`salt` varchar(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '盐',
`nickname` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '昵称',
`image` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',
`location` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '归属地',
`phone` varchar(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机号',
`status` tinyint(11) unsigned DEFAULT NULL COMMENT '状态\r\n 0 暂时不可用\r\n 1 永久不可用\r\n 9 正常可用',
`email` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '邮箱',
`type` tinyint(1) unsigned DEFAULT NULL COMMENT '账号类型\r\n 0 个人 \r\n 1 企业\r\n 2 子账号',
`score` tinyint(3) unsigned DEFAULT NULL COMMENT '运营评分',
`login_time` datetime DEFAULT NULL COMMENT '最后一次登录时间',
`created_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1120 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='自媒体用户信息表';
-- ----------------------------
-- Records of wm_user
-- ----------------------------
INSERT INTO `wm_user` VALUES ('1100', null, null, 'zhangsan', 'ab8c7c1e66a164ab6891b927550ea39a', 'abc', '小张', null, null, '13588996789', '1', null, null, null, '2020-02-17 23:51:15', '2020-02-17 23:51:18');
INSERT INTO `wm_user` VALUES ('1101', null, null, 'lisi', 'a6ecab0c246bbc87926e0fba442cc014', 'def', '小李', null, null, '13234567656', '1', null, null, null, null, null);
INSERT INTO `wm_user` VALUES ('1102', null, null, 'admin', 'a66abb5684c45962d887564f08346e8d', '123456', '管理', null, null, '13234567657', '1', null, null, null, null, '2020-03-14 09:35:13');
INSERT INTO `wm_user` VALUES ('1118', null, null, 'lisi1', '123', '123', null, null, null, null, null, null, null, null, null, null);
INSERT INTO `wm_user` VALUES ('1119', null, null, 'shaseng', '1234', null, null, null, null, null, null, null, null, null, null, null);
创建实体类
package com.linxuan.model.wemedia.dtos;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class WmLoginDto {
/**
* 用户名
*/
private String name;
/**
* 密码
*/
private String password;
}
package com.linxuan.model.wemedia.pojos;
/**
* <p>
* 自媒体用户信息表
* </p>
*/
@Data
@Builder
@TableName("wm_user")
public class WmUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField("ap_user_id")
private Integer apUserId;
@TableField("ap_author_id")
private Integer apAuthorId;
/**
* 登录用户名
*/
@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("location")
private String location;
/**
* 手机号
*/
@TableField("phone")
private String phone;
/**
* 状态
* 0 暂时不可用
* 1 永久不可用
* 9 正常可用
*/
@TableField("status")
private Integer status;
/**
* 邮箱
*/
@TableField("email")
private String email;
/**
* 账号类型
* 0 个人
* 1 企业
* 2 子账号
*/
@TableField("type")
private Integer type;
/**
* 运营评分
*/
@TableField("score")
private Integer score;
/**
* 最后一次登录时间
*/
@TableField("login_time")
private Date loginTime;
/**
* 创建时间
*/
@TableField("created_time")
private Date createdTime;
}
导入自媒体项目
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>leadnews-service</artifactId>
<groupId>com.linxuan</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>leadnews-wemedia</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
<!-- leadnews-service的pom.xml,里面定义了管理的子模块 -->
<modules>
<module>leadnews-user</module>
<module>leadnews-article</module>
<module>leadnews-wemedia</module>
</modules>
# bootstrap.yml文件配置
server:
port: 51803
spring:
application:
name: leadnews-wemedia
cloud:
nacos:
discovery:
server-addr: your.nacos.ip:8848
config:
server-addr: your.nacos.ip:8848
file-extension: yml
# 创建nacos配置leadnews-wemedia,添加如下配置信息:
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
# 自媒体库是leadnews_wemedia
url: jdbc:mysql://localhost:3306/leadnews_wemedia?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
username: your.mysql.password
password: your.mysql.password
# 设置Mapper接口所对应的XML文件位置,如果在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
# 设置别名包扫描路径,通过该属性可以给包中的类注册别名
type-aliases-package: com.linxuan.model.article.pojos
<?xml version="1.0" encoding="UTF-8"?>
<!-- logback.xml -->
<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"/>
<your.mysql.password level="info">
<!--<appender-ref ref="ASYNC"/>-->
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
</your.mysql.password>
</configuration>
package com.linxuan.wemedia;
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.linxuan.wemedia.mapper")
public class WemediaApplication {
public static void main(String[] args) {
SpringApplication.run(WemediaApplication.class,args);
}
}
package com.linxuan.wemedia.mapper;
@Mapper
public interface WmUserMapper extends BaseMapper<WmUser> {
}
package com.linxuan.wemedia.service.impl;
@Service
public class WmUserServiceImpl extends ServiceImpl<WmUserMapper, WmUser> implements WmUserService {
@Override
public ResponseResult login(WmLoginDto dto) {
// 1.检查参数
if (StringUtils.isBlank(dto.getName()) || StringUtils.isBlank(dto.getPassword())) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "用户名或密码为空");
}
// 2.查询用户
WmUser wmUser = getOne(Wrappers.<WmUser>lambdaQuery().eq(WmUser::getName, dto.getName()));
if (wmUser == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
}
// 3.比对密码
String salt = wmUser.getSalt();
String pswd = dto.getPassword();
pswd = DigestUtils.md5DigestAsHex((pswd + salt).getBytes());
if (pswd.equals(wmUser.getPassword())) {
// 4.返回数据 jwt
Map<String, Object> map = new HashMap<>();
map.put("token", AppJwtUtil.getToken(wmUser.getId().longValue()));
wmUser.setSalt("");
wmUser.setPassword("");
map.put("user", wmUser);
return ResponseResult.okResult(map);
} else {
return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
}
}
}
package com.linxuan.wemedia.controller.v1;
@RestController
@RequestMapping("/login")
public class LoginController {
@Autowired
private WmUserService wmUserService;
@PostMapping("/in")
public ResponseResult login(@RequestBody WmLoginDto dto){
return wmUserService.login(dto);
}
}
导入自媒体网关
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>leadnews-gateway</artifactId>
<groupId>com.linxuan</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!-- 项目名称 -->
<artifactId>leadnews-wemedia-gateway</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
<!-- leadnews-gateway的pom.xml,里面定义了管理的子模块 -->
<modules>
<module>leadnews-app-gateway</module>
<module>leadnews-wemedia-gateway</module>
</modules>
server:
port: 51602
spring:
application:
name: leadnews-wemedia-gateway
cloud:
nacos:
discovery:
server-addr: your.nacos.ip:8848
config:
server-addr: your.nacos.ip:8848
file-extension: yml
package com.linxuan.wemedia.gateway;
@SpringBootApplication
@EnableDiscoveryClient
public class WemediaGatewayAplication {
public static void main(String[] args) {
SpringApplication.run(WemediaGatewayAplication.class,args);
}
}
package com.linxuan.wemedia.gateway.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("linxuan") // 签发者信息
.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) throws ExpiredJwtException {
return getJws(token).getBody();
}
/**
* 获取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) throws Exception {
if (claims == null) {
return 1;
}
claims.getExpiration().before(new Date());
// 需要自动刷新TOKEN
if ((claims.getExpiration().getTime() - System.currentTimeMillis()) > REFRESH_TIME * 1000) {
return -1;
} else {
return 0;
}
}
/**
* 由字符串生成加密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;
}
}
package com.linxuan.wemedia.gateway.filter;
@Slf4j
@Component
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);
// 是否是过期
int result = AppJwtUtil.verifyToken(claimsBody);
if (result == 1 || result == 2) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
} catch (Exception e) {
e.printStackTrace();
}
// 6.放行
return chain.filter(exchange);
}
/**
* 优先级设置 值越小 优先级越高
*
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
# nacos添加配置leadnews-wemedia-gateway
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有请求
allowedOrigins: "*" #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
# 平台管理
- id: wemedia
uri: lb://leadnews-wemedia
predicates:
- Path=/wemedia/**
filters:
- StripPrefix= 1
自媒体前端搭建
# nginx-1.18.0/conf/leadnews.conf/leadnews-wemedia.conf文件
# upstream定义一组服务器,名称叫做linxuan-app-gateway
upstream linxuan-wemedia-gateway{
# 反向代理到自媒体端网关的51602端口,因为网关也部署在了本地,所以访问本地的51602端口
server localhost:51602;
}
server {
# 前端自媒体端监听端口号,访问该端口号才访问该端
listen 8802;
location / {
# 本地前端静态文件地址
your.mysql.password D:/Java/IdeaProjects/lead_news/front-workspce/wemedia-web/;
index index.html;
}
location ~/wemedia/(.*) {
proxy_pass http://linxuan-wemedia-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-1.18.0/conf/nginx.conf文件配置
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
# 引入自定义配置文件,leadnews.conf目录下面的所有配置文件全部引入
include leadnews.conf/*.conf;
}
# 查看nginx版本
E:\nginx\nginx-1.18.0>nginx -v
nginx version: nginx/1.18.0
# 启动nginx
E:\nginx\nginx-1.18.0>start nginx
# 重新加载nginx
E:\nginx\nginx-1.18.0>nginx -s reload
# 停止nginx
E:\nginx\nginx-1.18.0>nginx -s stop
启动项目,测试
问题描述
问题解决
断点测试
断点测试 leadnews-wemedia-gateway 和 leadnews-wemedia,发现断点都没有反应,也就是说项目根本没有请求到网关。
拦截器证明
package com.linxuan.wemedia.interceptor;
@Component
public class RequestUrlInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("Request URL: " + request.getRequestURL());
return true;
}
}
package com.linxuan.wemedia.config;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private RequestUrlInterceptor requestUrlInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestUrlInterceptor);
}
}
添加的拦截器同样没有打印请求 URL
修改配置文件
原始的请求路径是http://localhost:8802/wemedia/MEDIA/wemedia/login/in,而 leadnews-wemedia 控制层接收的是 /login/in 的请求,也就是说 /wemedia/MEDIA/wemedia/ 在代理的过程中要删除掉。
最后一个 /wemedia 在 leadnews-wemedia-gateway 网关路由至 leadnews-wemedia 过程被删除掉,所以 /wemedia/MEDIA/ 要在此之前被删除掉,找 nginx 的配置文件。
# nginx-1.18.0/conf/leadnews.conf/leadnews-wemedia.conf文件
# upstream定义一组服务器,名称叫做linxuan-app-gateway
upstream linxuan-wemedia-gateway{
# 反向代理到自媒体端网关的51602端口,因为网关也部署在了本地,所以访问本地的51602端口
server localhost:51602;
}
server {
# 前端自媒体端监听端口号,访问该端口号才访问该端
listen 8802;
location / {
# 本地前端静态文件地址
root D:/Java/IdeaProjects/lead_news/front-workspce/wemedia-web/;
index index.html;
}
# 问题就是这里了,原始的为~/wemedia/(.*),将其修改为~/wemedia/MEDIA/(.*)
# 请求URL路径以/wemedia/MEDIA/开头激活该代码块,(.*)匹配/wemedia/MEDIA/之后内容,通过$1引用
location ~/wemedia/MEDIA/(.*) {
# 将请求的URL代理到的目标URL,最后为http://localhost:51602/$1引用的路径
proxy_pass http://linxuan-wemedia-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; #记录代理信息
}
}
修改完之后就可以成功访问了!
标签:COMMENT,leadnews,登录,DEFAULT,wm,404NotFound,2021,NULL,头条 From: https://www.cnblogs.com/linxuannihao/p/18108302