1,项目简介
本课题主要是基于VUE和SpringBoot框架实现一个抽奖系统服务端,该抽奖平台是一个支持多种不同的抽奖方式且支持高并发的多种用户系统,抽奖系统角色共分为四类,包括基础的抽奖用户,抽奖发布者,进行数据信息管理的后端管理员以及自动执行抽奖的抽奖执行模块。普通用户可以查看并参加抽奖;抽奖发布者可以发布抽奖,管理自己发布的抽奖信息和参加该抽奖的用户,获取系统返回的中奖用户并发奖;管理员可以通过抽奖系统后端管理现有的抽奖及用户信息;抽奖执行模块则负责自动适时执行各类抽奖。
2,开发环境
前台开发平台:web前端
后台开发平台:IntelliJ IDEA
数据库:MySQL & Redis
服务器:云服务器(BAE或SAE)
计算机硬件配置:
抓取服务器:内存1.5G以上
数据服务器:内存2G以上
3,使用的技术
前端:vue
后端
web框架:Springboot
持久层框架:JPA
认证授权框架:Shiro
分布式框架:Dubbo+Zookeeper
搜索框架:ElasticSearch
数据库:
mysql+redis
4,设计模式
4.1 八大设计原则
提到设计模式,我们首先需要了解设计模式的设计原则。
- 依赖倒置原则(DIP)
- 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定)。
- 抽象(稳定)不应该依赖于实现细节(变化),实现细节(变化)应该依赖于抽象(稳定)。
- 开放封闭原则(OCP)
- 对扩展开放,对更改封闭。
- 类模块应该是可以扩展的,但是不可修改。
- 单一职责原则(SRP)
- 一个类应该仅有一个引起它变化的原因。
- 变化的方向隐含着类的责任。
- Liskov替换原则(LSP)
- 子类必须能够替换它们的基类(IS-A)。
- 继承表达类型抽象。
- 接口隔离原则(ISP)
- 不应该强迫客户程序依赖它们不用的方法。
- 接口应该小而完备。
- 优先使用对象组合,而不是类继承
- 类继承通常为"白箱复用",对象组合通常为"黑箱复用"。
- 继承在某种程度上破坏了封装性,子类父类耦合度过高。
- 而对象组合则只要求被组合的对象具有良好定义的接口,耦合度较低。
- 封装变化点
- 使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。
- 针对接口编程,而不是针对实现编程
- 不将变量类型声明为某个特定的具体类型,而是声明为某个接口。
- 客户程序无需获知对象的具体类型,是需要知道对象所具有的接口。
- 减少系统中各部分的依赖关系,从而实现"高内聚,松耦合"的类型设计方案。
4.2 重构关键技法
- 静态 -> 动态
- 早绑定 -> 晚绑定
- 继承 -> 组合
- 编译时依赖 -> 运行时依赖
- 紧耦合 -> 松耦合
4.3 本项目中运用的设计模式
对象创建过程中使用new,new依赖具体类,耦合度高。为了避免new,减少依赖,提供封装机制避免直接new,降低耦合度。
一般的new 违背了 依赖倒置原则(依赖抽象,而不依赖具体)
例:A a = new A(); //此处的A是一个具体的类,而不是抽象
根据依赖倒置原则,我们应该尽可能的使用抽象设计,减少具体(可以降低耦合),但是抽象类是不可以实例化的(new),此时就需要一种方式来解决实例化问题。提供一个工厂接口,把创建对象的任务往后推给子类,使当前类与new隔离。该种设计模式就是工厂模式。
使用工厂模式的好处:工厂模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。一旦更改具体类型,就要更改使用者中的代码,耦合度太高,而工厂方法,降低了两者的耦合度,类型改变或增加时只需改变/增加工厂子类即可,而使用者的源码不必改变。
工厂模式的通用类图结构图:(附部分注释,希望可以帮助读者快速理解)
5,架构风格
5.1 微服务架构
“微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间相互协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务和服务之间采用轻量级的通信机制相互沟通(通常是基于HTTP的Restful API).每个服务都围绕着具体的业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。微服务架构有如下优点:
1,提升开发交流,每个服务足够内聚,足够小,代码容易理解;
2,服务独立测试、部署、升级、发布;
3,按需定制的DFX,资源利用率,每个服务可以各自进行x扩展和z扩展,而且,每个服务可以根据自己的需要部署到合适的硬件服务器上;每个服务按需要选择HA的模式,选择接受服务的实例个数;
4,容易扩大开发团队,可以针对每个服务(service)组件开发团队;
5,提高容错性(fault isolation),一个服务的内存泄露并不会让整个系统瘫痪;
6,新技术的应用,系统不会被长期限制在某个技术栈上;
5.2 分布式架构
用最简单的方式定义,分布式系统就是让终端用户把一组工作在一起的计算机当做一个单独的机器来使用。这些机器共享状态,并发操作,并且单个机器出现问题不会影响到整个系统的正常工作。架构的优势是性能高,易扩展,容错,低延时。
5.3 Restful风格
使用Restful风格可以项目的请求更加清爽,以管理员管理抽奖活动为例,说明部分请求使用Restful:
实验功能 | 请求URI | 请求方式 |
查询所有活动 | activitys | GET |
查询某个活动(来到修改页面) | activity/1 | GET |
来到添加页面 | activity | GET |
添加活动 | activity | POST |
来到修改页面(查出活动进行信息回显) | activity/1 | GET |
修改活动 | activity | PUT |
删除活动 | activity/1 | DELETE |
6,接口设计
6.1 用户界面
在用户抽奖界面以及抽奖发布者的界面,应充分考虑展示信息与用户的可交互性,在需求分析的基础上,合理展示抽奖系统为用户提供的各种信息,包括根据用户推荐的各类抽奖活动。由于前端确定采用VUE框架,因此可以基于VUE对信息进行简单排布形成基本的展示界面,再在此基础上进一步优化,尽可能降低界面和操作的学习成本。
6.2 软件接口
前端方面,可以提供前端数据接口用于接收抽奖系统服务端发送的用于显示的信息,提高前端界面的可扩展性,也易于更换或者直接扩展前端界面。服务器端则提供基本的数据库的连接接口,方便数据库的迁移、升级和更换;另外还可以提供抽奖执行模块、发奖模块的接口,实现模块化,模块之间进行解耦以提高维护性和可扩展性。
7,UML类图
8,视图
8.1,分解视图
分解是构建软件架构模型的关键步骤,分解视图也是描述软件架构模型的关键视图,一般分解视图呈现为较为明晰的分解结构(breakdown structure)特点。分解视图用软件模块勾划出系统结构,往往会通过不同抽象层级的软件模块形成层次化的结构。
8.2,依赖视图
依赖视图展现了软件模块之间的依赖关系。比如一个软件模块A调用了另一个软件模块B,那么我们说软件模块A直接依赖软件模块B。如果一个软件模块依赖另一个软件模块产生的数据,那么这两个软件模块也具有一定的依赖关系。依赖视图在项目计划中有比较典型的应用。比如它能帮助我们找到没有依赖关系的软件模块或子系统,以便独立开发和测试,同时进一步根据依赖关系确定开发和测试软件模块的先后次序。依赖视图在项目的变更和维护中也很有价值。比如它能有效帮助我们理清一个软件模块的变更对其他软件模块带来影响范围。
8.3,泛化视图
泛化视图展现了软件模块之间的一般化或具体化的关系,典型的例子就是面向对象分析和设计方法中类之间的继承关系。值得注意的是,采用对象组合替代继承关系,并不会改变类之间的泛化特征。因此泛化是指软件模块之间的一般化或具体化的关系,不能局限于继承概念的应用。泛化视图有助于描述软件的抽象层次,从而便于软件的扩展和维护。比如通过对象组合或继承很容易形成新的软件模块与原有的软件架构兼容。
8.4,执行视图
执行视图展示了系统运行时的时序结构特点,比如流程图、时序图等。执行视图中的每一个执行实体,一般称为组件(Component),都是不同于其他组件的执行实体。如果有相同或相似的执行实体那么就把它们合并成一个。执行实体可以最终分解到软件的基本元素和软件的基本结构,因而与软件代码具有比较直接的映射关系。在设计与实现过程中,我们一般将执行视图转换为伪代码之后,再进一步转换为实现代码。
8.5,实现视图
实现视图是描述软件架构与源文件之间的映射关系。比如软件架构的静态结构以包图或设计类图的方式来描述,但是这些包和类都是在哪些目录的哪些源文件中具体实现的呢?一般我们通过目录和源文件的命名来对应软件架构中的包、类等静态结构单元,这样典型的实现视图就可以由软件项目的源文件目录树来呈现。
实现视图有助于码农在海量源代码文件中找到具体的某个软件单元的实现。实现视图与软件架构的静态结构之间映射关系越是对应的一致性高,越有利于软件的维护,因此实现视图是一种非常关键的架构视图。
8.6,部署视图
部署视图是将执行实体和计算机资源建立映射关系。这里的执行实体的粒度要与所部署的计算机资源相匹配,比如以进程作为执行实体那么对应的计算机资源就是主机,这时应该描述进程对应主机所组成的网络拓扑结构,这样可以清晰地呈现进程间的网络通信和部署环境的网络结构特点。当然也可以用细粒度的执行实体对应处理器、存储器等。
部署视图有助于设计人员分析一个设计的质量属性,比如软件处理网络高并发的能力、软件对处理器的计算需求等。
8.7,工作任务分配视图
工作分配视图将系统分解成可独立完成的工作任务,以便分配给各项目团队和成员。工作分配视图有利于跟踪不同项目团队和成员的工作任务的进度,也有利于在个项目团队和成员之间合理地分配和调整项目资源,甚至在项目计划阶段工作分配视图对于进度规划、项目评估和经费预算都能起到有益的作用。
9,数据库设计
用户数据模型:User_table
属性 | 类型 | 键值 | 注释 |
Id | Int | 主键 | 记录id |
name | String | - | 用户名 |
password | String | - | 密码 |
tell | String | - | 电话 |
address | String | - | 地址 |
登录/注册数据模型:Login_table
属性 | 类型 | 键值 | 注释 |
Id | Int | 主键 | 记录id |
Name | String | - | 用户名 |
Password | String | - | 密码 |
奖品数据模型:goods_table
属性 | 类型 | 键值 | 注释 |
Id | int | 主键 | 记录id |
name | String | - | 奖品名称 |
color | String | - | 颜色 |
Price | Float | - | 价格 |
抽奖活动数据模型:activity_table
属性 | 类型 | 键值 | 注释 |
Id | int | 主键 | 记录id |
name | String | - | 活动名称 |
gId | int | 外键 | 关联奖品表 |
startTime | Date | - | 开始时间 |
stopTime | Date | - | 结束时间 |
pName | String | - | 发布者姓名 |
pTell | String | - | 发布者电话 |
pAddress | String | - | 发布者地址 |
join_table:中奖榜单
属性 | 类型 | 键值 | 注释 |
Id | int | 主键 | 记录id |
userId | int | 外键 | 中奖用户编号 |
activityId | int | 外键 | 活动编号 |
goodName | String | - | 奖品名称 |
goodPrice | float | - | 奖品价格 |
发布者发布活动
属性 | 类型 | 键值 | 注释 |
Id | int | 主键 | 记录id |
publisherId | int | 外键 | 发布者编号 |
activityId | int | 外键 | 活动编号 |
10,系统工作机制
用户通过登录进入该系统,进入后可以查看并参加各种抽奖活动,抽奖活动分为实时抽奖和定时开奖两种。参加实时抽奖的用户可以立即获取中奖信息;参加定时开奖的用户需要等开奖之后才可以查看中奖信息。用户中奖后,需要填写物流信息。抽奖发布者可以实时更改中奖概率,比如人少时,减少奖品投放,人多时增加奖品投放。管理员负责管理监视系统,比如系统的负载情况,或者是否存在违规活动等。
参考文献:
https://gitee.com/mengning997/se
https://ww.zhihu.com/question/65502802/answer/615568011