JiveJdon 3.0 详细设计开发
由于 JiveJdon 整个项目并未完成,本文档持续更新中….
JiveJdon 3.0 下载网址: http://www.jdon.com/jdonframework/jivejdon3/index.html
分析设计
用例图
角色设计:Anonymous 普通用户;注册用户 User;管理者 Admin;
普通用户用例功能:
浏览所有论坛;
浏览所有帖子;
浏览其他用户信息;
本系统总体设计实现思路是:首先使用基于 Model 使用 Jdon 框架将整体结构搭建
出来,实现基本功能,然后在这个基础结构上进行细化,就如同绘画,首先打出轮廓,
这样把握整体结构,然后再进入详细表达。
建模
根据用例图,找出原始模型,复杂的用例,我们可以借助四色图帮助我们分类,
本案例用例由于我们都比较熟悉,能够从用例中找出一些被操作对象,这些被操作对
象大概有几个:Account 用户 Forum 论坛 ForumMessage 帖子。
这里注意一个特殊情况,论坛不是直接并行的多个帖子组成,这些帖子之间也有
回复关系,也就是说,回复帖子肯定不是论坛的直接组成成分,这里非常类似订单案
例:订单中有多个商品,但是商品不是订单的直接组成部分,有可能有两个相同商品,
每个商品还对应一个新属性数量,商品和数量联合起来才可能是订单的组成部分,这
个联合起来的对象是订单条目,订单条目才是订单的直接组成部分。
在当前案例,论坛和帖子之间也需要一个类似订单条目的概念,订单条目可能看
不见摸不着,它的组成部分就是商品和数量,订单条目其实是一个集合概念,那么在
论坛和帖子之间其实也存在这样一个集合概念:FourmThread,如下:
ForumThread 相当于主题 Topic; 但 Topic 主要内容放入 rootMessage 中,可以说
相当于所有 rootMessage 的主题提要,包括回复 rootMessage 的最后的一个回帖,包括
rootMessage 在内的所有帖子数等,主要服务于显示一个论坛中所有 rootMessage 集合。
ForumThread 和 Forum 之间是 N:1 关系 ForumMessage 相当于帖子;ForumMessage
之间有一个父子关系,表示帖子之间回帖关系;ForumMessage 和 ForumThread 之间是
N:1 关系,和 Forum 之间也是 N:1 关系。
领域模型图如下:
Evans DDD 在领域对象的生命周期中对不变性(invariant)进行了定义,指无论何时
数据发生变化,都必须满足所有对象一致变化的规则。
围绕 ForumMessage,其组成部分 Fourm ForumThread Account 都是其核心部分,
就 像 汽 车 由 发 动 机 车 身 轮 胎 组 成 一 样 , 缺 一 不 可 。 特 别 是 ForumThread 和
ForumMessage,更是这种不变性的高度统一,ForumThread 实则是虚的,它里面实体
就是 ForumMessage,两者是高度一致的。
DDD 指出;聚合内部的不变量必须在每次事务完成时满足。这可有仓储来实现。
当然,还有一些依赖关系只能在某些特定的时刻,通过事件处理、批处理和其他
更新机制来实现,比如上图中 state 和 tag 以及 property。
不变性实现
通过仓储 Repository 工厂来实现,我们在 ForumMessage 中设置一个 embeded 来表
达该对象包括其内嵌的高聚合子对象是否被完整加载或操作。
在不变性设计中,我们还要考虑到缓存对象的一致性,因为我们所有的对象都被
缓存,但是我们取出 Message 和 Thread 有先后,而 Message 和 Thread 之间互相引用,
如何保证他们之间引用和缓存中的引用是同一个对象,这是必须构建不变性时考虑的。
在 com.jdon.jivejdon.repository. ForumBuilder 的 getMessage 方法,是这样:
ForumMessage getMessage(Long messageId, ForumThread forumThread)
这样,如果 getMessage 是被构建 Thread 是调用,那么调用者就把自己当前正在构
建的 Thread 作为 getMessage 方法参数传入,保证构建 Message 中指引的 Thread 是自己。
可变性 State
每次新增一个回帖 ForumMessage,必然对其父贴的状态发生变化,也涉及到
ForumThread 中帖子前后状态的变化。
allowEdit 则属于”特定的时刻通过事件处理“的属性,根据需求:只有帖子作者或
超级管理员才可以修改,而只有等用户注册登录后这个事件发生,我们才可以判断,
因此,allowEdit 需要由外界触发判断,可以认为是每次客户端请求都要求进行判断的
属性,可变频率更高,具体事件触发可通过服务形式被客户端请求出发。不过这种和
具体客户端有关的属性不适合放入 ForumMessageState 这样全局性对象中,需要详细
设计时更改。isEditing 之类是否正在编辑等状态属性是需要的,这样如果当前帖子正
在被编辑,那么其他用户就不能回复或修改。
其中 isLeaf 就是是否是叶子,也就是没有回帖等子贴,这是树形结构关系中一个
重要的判断依据,根据业务需求,只有没有回帖才能修改,这个属性是判断依据,这
个属性在每次回帖创建时,都要进行更新,属于 CRUD 中经常被更新项。
每次 CRUD 事件发生,特别是新帖增加和删除,还涉及到 ForumThread 状态的变
化:
ThreadState 中当前主题系列中帖子总数也是即时统计的,没有使用数据表一个字
段来表达,好处是可以避免数据表频繁修改操作,减少一个方向的操作(读操作都必
须)。
TreeModel 中是通过一个 Tree 模型,来表达帖子回帖之间形成的树形结构关系,
是保存在内存中,这样,有关树形特征都可以直接快速获取,不必频繁查询数据库。
设计细节约定
所有的时间串都是 System.currentTimeMillis()获得,并以 String 类型持久保存到数
据 库 中 , 然 后 在 显 示 时 转 换 为 特 定 的 格 式 , 使 用
com.jdon.util.UtilDateTime.getDateTimeDisp 转换成特定格式后给 Model 相应的时间赋
值。这个工作在 dao 层实现,分别向两个方向(数据表和 Model)赋值。
Property 是所有 Model 的附加属性,比如帖子的 IP 地址等附件信息。Model 和
Property 关系是 1:N。
当然,以上建模只是粗放型,在以下具体设计中会对这些类进行细化。其实在以
后的整个章节都是对业务建模不断修改的过程。
用户登陆授权模块
用户 Model
主要有下列字段:
private String userId; //主键
private String username; //登陆用户名
private String password; //登陆密码
private String email; //登陆 Email
这四个字段是用户登陆用主要字段,如果你有一个统一认证服务器,那么这四个
字段不但需要在本系统数据库持久化,还需要保存在统一认证服务器中。
在我们统一认证服务器中,我们已经一个 com.jdon.security.UserModel(存在 Jdon
框架中),因此,这里 Account 只要继承这个 UserModel,加上一些附加字段。
与统一认证服务器关系处理方案如下:
用户新注册和资料修改在本系统提供,当保存到数据库中时,进行两个数据库同
时保存,将用户相关验证信息保存到统一认证服务器中;将其他用户相关信息保存在
本系统数据库中。
以下授权验证配置都是针对统一认证服务器的数据库而言。
整个数据库分为三个部分:
forum 论坛相关部分数据表,包括 Forum Message 等实体数据。
auth 是统一认证服务器的数据表,包括上面四个字段的验证信息,Role 信息。
user 则 是 本 系 统 的 用 户 相 关 数 据 表 , 包 括 积 分 Reward ; 帖 子 调 整 等 级
Moderation。
关于 userId 序列号的获取,直接从本系统的数据表 jiveID 获取。
角色定义
角色目前定义四种:
管理员
版主
注册用户
非注册用户
角色在本系统在三个地方定义,这三个地方需要统一,如果修改就统一修改:
1. 在代码 Role.java 中定义
public interface Role {
/**
* Administrator 管理员
*/