参照QQ邮箱,设计一款简易版的站内信

在学习软件编程的第一天,老师就告诉我们:程序 = 数据结构 + 算法。在使用一款应用时,我们只能看到页面上展示的内容,并不知道其背后的数据结构,更不知道使用了什么算法。

在写程序时,其实涉及到两种数据结构,一种是程序运行时,数据在内存里的存储结构,这和使用的开发语言有关;另一种是数据存放在数据库里的数据结构,和数据库有关,也和数据表设计有关。

这里所说的数据结构,是存储在数据库里的数据结构,现在用的数据库大部分都是关系型数据库。现在,要做一个类似于QQ邮箱的站内信,该如何设计呢?

简要描述一下站内信的业务需求:

  1. 发送邮件给一个用户或多个用户;
  2. 接收到邮件后,可以回复邮件;
  3. 可以对一封邮件溯源,查看一封邮件的历史往返记录;
  4. 对邮件的状态进行标注,未读的、已读的、已发送的;
    备注说明:发生邮件和回复邮件均可以上传图片,最多五个;每个用户可以清楚地看到未读、已读、已发送邮件列表;

发送邮件是需要邮箱服务器发送的,这里的应用场景是站内信,那么站内信的系统就可以充当邮箱服务器的功能。

首先看看,在QQ邮箱上创建一封邮件时,页面上需要哪些元素:


在邮件创建页面,大致需要以下这些字段属性:
1)接收人
2)邮件标题
3)邮件正文
4)附件
5)发送人,默认当前登录用户

接下来,开始设计主表,站内信信息表的初步的设计如下图所示:


只有站内信一个主表貌似不够用,接收邮件的用户,有可能是一个,也有可能是多个;接收人有的查看了邮件,有的还没有查看邮件;那么每个接收人对邮件的阅读状态可就不一样了,这个该怎么处理呢?

邮件的发送人,只有一个,这个是可以保证不变的,那么邮件的发送人就可以作为邮件信息表的字段来存储。接收人是多个,每个人的阅读状态又不同,那么这个可以单独设计为一个表,每个接收人作为一条独立的记录存在;其关系图如下所示。

站内信和发件人的关系,一个站内信只能有一个发件人;一个用户却可以发送多封邮件;站内信和用户是多对一的关系;
站内信和收件人的关系,一个站内信可能有一个或一个以上的接收人;一个用户是多个站内信的接收人;站内信和收件人,是多对多的关系;
每个接收人所接收的邮件默认为未读状态,在用户读过之后,变成已读状态,不会影响其他用户邮件的阅读状态。

那么有人会看到,邮件里漏掉了附件这个字段呀?

是的,没错,邮件里没有附件,为何没有附件?

因为附件有可能上传多个,虽然也有数量限制,但是你想,如果把这个字段放在主表里,最多限制五个,你就需要在主表里加入五个附件的字段,不管用户有没有上传五个附件,都需要数据库把这个空间开辟出来空在那里,这是资源浪费呀。

没错,这里会把附件最为一个单独的表来设计,作为一个附属表来设计,附属于邮件信息这个主表;

这样设计附件好处很明显,用户上传一个附件,增加一个附件的存储空间,没有上传过附件,就不需要开辟多余的空间。
一封邮件可能有零个或多个附件,一个附件只属于一封站内信,站内信和附件是一对多的关系。

接下来还有一个问题需要解决,如何追踪一封邮件的历史往返记录,就像QQ邮箱一样?

这个也好办,一封邮件可以有零个或一个父邮件,第一次创建的邮件是没有父邮件的,每次被回复的邮件都有一个父邮件;并且,一个邮件就只能有一个父邮件;在查看一封邮件的时候,就可以根据它的父邮件往上追踪过往的邮件,其设计图如下所示:


接下来把这个CDM设计图转化为PDM设计图,看看数据结构是不是我们想要的样子,关系上对应的对不对!



把主表中冲突的email_uid改为父email_uid,主表中的用户uid指向发件人,附件表的邮件uid指向主表的邮件uid,邮件与收件人的关联关系表分别指向邮件和用户,关联关系没有错,非常完美。

接下来,再做一点特殊的需求,每个用户都有所属企业,用户不仅可以给用户发邮件,也可以给某一个企业或多个企业发邮件,还可以发给全部的用户;如果是给某个企业发送的邮件,那么这个企业下的所有用户都能接收到,这个该如何设计呢?

先增加企业表的设计,再关联一下企业与用户的关系,一个企业下面可能有多个用户,一个用户只能属于一家企业,企业与用户是一对多的关系,如下图所示:


由于邮件的接收者可以是企业,所以在主表中增加一个冗余字段,用于标识这个邮件是发给企业的,还是发给企业下的某个人,还是发送给全部用户;在主表中增加一个接收人类型,默认0,默认0,0:全部,1:企业,2:用户,如下图所示:


接收者这边该如何处理呢?

同样地,也在关系表中增加企业的唯一标识符做关联,如果是发送给企业的,那么接收人那一列空着,当企业下的用户登录时,将能看到发送给这个企业的邮件,该用户阅读完毕后,再往关系表中增加一条已读的记录,如下图所示:


也就是说,站内信发给所有用户的时候,是不需要填充关系表的,只需要根据主表的接收者类型来判断,接收者类型为0又不是自己发送的,则处于未阅读状态。

如果接收人是一个或多个企业,那么只会在关系表中新增站内信和企业的关联关系,企业用户登录后,也根据接收者类型和企业uid来获取未读的邮件。

如果接收人是一个或多个用户,那么就会在关系表中新增站内信和接收者的未读状态的关联关系,用户登录后,根据接收者类型和未读状态来获取未读邮件。

未读邮件的检索最复杂,需要三种复合条件的判断。

已读邮件就比较简单了,主表关联关系表,状态为已读的,就是已读的数据。

已发送邮件最简单,根据发送人检索便可。

在查看某一封邮件,根据父类邮件uid去获取上一封邮件,有父类邮件uid就递归获取,直到父类uid没有为止,无意中发现是这样有意思的一个图:


作为一款简单的站内信设计,相信这些功能已经足够用了,不够用再加吧,哈哈。临需而变哟~!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章