欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

对标大厂的技术派方案设计,万字带你了解一个项目从0到1实现的全过程

最编程 2024-08-01 12:53:28
...

01 整体介绍

背景

这个项目诞生的背景和企业内生的需求不太一样,主要是某一天二哥说,“我们一起搞事吧”, 楼仔问,“搞什么”,然后这个项目的需求就来了

言归正传,我们主要的目的是希望打造一个切实可用的项目,依托于这个项目,将java从业者所用到的技术栈真实的展现出来,对于经验不是那么足的小伙伴,可以在一个真实的系统上,理解到自己学习的知识点是如何落地的,同时也能真实的了解一个项目是从0到1实现的全过程

系统模块介绍

系统架构

基于社区系统的分层特点,将整个系统架构划分为展示层,应用层,服务层,如下图

展示层

其中展示层主要为用户直接接触的视图层,基于用户角色,分别提供为面向普通用户的前台与面向管理员的后台

前台web

  • 采用Thymleaf模板引擎进行视图渲染
  • 对于不关心前端技术栈的小伙伴相对友好,学习成本低,只用会基本的html,css,js即可

管理后台

  • 采用成熟的前后端分离技术方案
  • 前端基于react成熟框架搭建

应用层

应用层,也可以称为业务层,强业务相关,其中每个划分出来的模块有较明显的业务边界,虽然在上图中区分了前台、后台

但是需要注意的是,后台也是同样有文章、评论、用户等业务功能的,前台与后台可使用应用主要是权限粒度管理的差异性,对于技术派系统而言,我们的应用可分为:

  • 文章
  • 专栏
  • 评论
  • 用户
  • 收藏
  • 订阅
  • 运营
  • 审核
  • 类目标签
  • 统计

服务层

我们将一些通用的、可抽离业务属性的功能模块,沉淀到服务层,作为一个一个的基础服务进行设计,比如计数服务、消息服务等,通常他们最大特点就是独立与业务之外,适用性更广,并不局限在特定的业务领域内,可以作为通用的技术方案存在

在技术派的项目设计中,我们拟定以下基础服务

  • 用户权限管理 (auth)
  • 消息中心 (mq)
  • 计数 (redis)
  • 搜索服务 (es)
  • 推荐 (recommend)
  • 监控运维 (prometheus)

平台资源层

这一层可以理解为更基础的下层支撑

  • 服务资源:数据库、redis、es、mq
  • 硬件资源:容器,ecs服务器

术语介绍

技术派整个系统中涉及到的术语并不多,也很容易理解,下面针对几个常用的进行说明

  • 用户:特指通过微信公众号扫码注册的用户,可以发布文章、阅读文章等
  • 管理员:可以登录后台的特殊用户
  • 文章:即博文
  • 专栏:由一系列相关的文章组成的一个合集
  • 订阅:专指关注用户

02 系统模块设计

针对前面技术派的业务架构拆分,技术派的实际项目划分,主要是五个模块,相反并没由将上面的每个应用、服务抽离为独立的模块,主要是为了避免过渡设计,粒度划分太细会增加整个项目的理解维护成本

这里设置五个相对独立的模块,则主要是基于边界特别清晰这一思考点进行,后续做微服务演进时,下面每个模块可以作为独立的微服务存在

用户模块

在技术派中,整个用户模块从功能角度可以分为

  • 注册登录
  • 权限管理(是的,权限管理也放在这里了)
  • 业务逻辑

注册登录

方案设计

注册登录除了常见的用户名+密码的登录方式之外,现在也有流行的手机号+验证,第三方授权登录;我们最终选择微信公众号登录方式(其最主要的目的,相信大家也知道...)

对于个人公众号,很多权限没有;因此这个登录的具体实现,有两种实现策略

  • 点击登录,登录页显示二维码 + 输入框 -> 用户关注公众号,输入 "login" 获取登录验证码 -> 在登录界面输入验证码实现登录
  • 点击登录,登录页显示二维码 + 验证码 -> 用户关注公众号,将登录页面上的验证码输入到微信公众号 -> 自动登录

其中第一种策略,类似于手机号/验证码的登录方式,主要是根据系统返回的验证码来主动登录

优点:

  • 代码实现简单,逻辑清晰

缺点:

  • 操作流程复杂,用户需要输入两次

对于第二种策略,如果是企业公众号,是可以省略输入验证码这一步骤的,借助动态二维码来直接实现扫码登录;对于我们这种个人公众号,则需要多来一步,通过输入验证码来将微信公众号的用户与需要登录的用户绑定起来

登录工作流程如下:

库表设计

基于公众号的登录方式,看一下用户登录表的设计

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `third_account_id` varchar(128) NOT NULL DEFAULT '' COMMENT '第三方用户ID',
  `user_name` varchar(64) NOT NULL DEFAULT '' COMMENT '用户名',
  `password` varchar(128) NOT NULL DEFAULT '' COMMENT '密码',
  `login_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '登录方式: 0-微信登录,1-账号密码登录',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否删除',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
  PRIMARY KEY (`id`),
  KEY `key_third_account_id` (`third_account_id`),
  KEY `key_user_name` (`user_name`),
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户登录表';

注意上面的表结构设计,我们冗余了 user_name, password 用户名密码的登录方式,主要是给管理员登录后台使用

用户首次登录之后,会在user表中插入一条数据,主要关注 third_account_id 这个字段,它记录的是微信开放平台返回的唯一用户id

权限管理

权限管理会分为两块:用户身份识别 + 鉴权

方案设计

用户身份识别:

现在用户的身份识别有非常多的方案,我们现在采用的是最基础、历史最悠久的方案,cookie + session 方式(后续会迭代为分布式session + jwt)

整体流程:

  • 用户登录成功,服务器生成sessionId -> userId 映射关系
  • 服务器返回sessionId,写到客户端的浏览器cookie
  • 后续用户请求,携带cookie
  • 服务器从cookie中获取sessionId,然后找到uesrId

服务内部身份传递:

另外一个需要考虑的点则是用户的身份如何在整个系统内传递? 对于一期我们采用的单体架构而言,借助ThreadLocal来实现

  • 自定义Filter,实现用户身份识别(即上面的流程,从cookie中拿到SessionId,转userId)
  • 定义全局上下文ReqInfoContext:将用户信息,写入全局共享的ThreadLocal中
  • 在系统内,需要获取当前用户的地方,直接通过访问 ReqInfoContext上下文获取用户信息
  • 请求返回前,销毁上下文中当前登录用户信息

鉴权

根据用户角色与接口权限要求进行判定,我们设计三种权限点类型

  • ADMIN:只有管理员才能访问的接口
  • LOGIN:只有登录了才能访问的接口
  • ALL:默认,没有权限限制

我们在需要权限判定的接口上,添加上对应的权限要求,然后借助AOP来实现权限判断

  • 当接口

推荐阅读