新闻发布系统的设计思路(域模型)

      前阵子实验室接到一个门户网站的单子.我有幸参考其中,并负责其中所有有关新闻发布的代码.本来以前自己也作过有关新闻发布的例子(客户也没有对使用的开发框架作限制),由于正在看有关SSH(spring,hibernate,struts),就想拿这个模块来练手.经过几天的捣鼓,程序算是完成了.特分享一下设计经验.
       由于客户并没有提供相关更多的材料,完全是自我发挥,所以可以用的空间很大,也产生了要把模块弄得很好的愿望.所以设计方面也是有些考虑.采用spring2.0 hibernate3,和最新的struts2.0作为开发框架.(相关源代码可参考本人发在csdn上的链接download.csdn.net/source/235683 ).
       模型设计:
             新闻发布系统主要涉及新闻,类别.此外,新闻发布用户也是需要被考虑的问题.在实际中,由于考虑到一个新闻置顶方面的问题,特特殊设计了一个关于新闻置顶的类.因此,整个domain分成四个部分:文章(article),目录(category),文章置顶对象(articleTopType)以及用户对象(user).具体设计如下:
#-------------------------
            文章(article):    

  1. public class Article implements Serializable {   
  2.     /** 主键 * */  
  3.     private int id;   
  4.   
  5.     /** 文章标题 * */  
  6.     private String title;   
  7.   
  8.     /**  
  9.      * 文章路径标识,此字段是为了配合多个页面时,以此作为查询文章的下一个或者上一个页面.或者由此  
  10.      * 来寻求文章的相关信息,如创建日期等  
  11.      */  
  12.     private String pathMark;   
  13.   
  14.     /** 是否已经被审核 * */  
  15.     private boolean audited;   
  16.   
  17.     /** 文章标题的颜色 * */  
  18.     private String titleColor = ProjectConfigureGlobals.ARTICLE_DEFAULT_TITLECOLOR;   
  19.   
  20.     /** 文章摘要 * */  
  21.     private String summary;   
  22.   
  23.     /** 文章来源 * */  
  24.     private String source;   
  25.   
  26.     /** 文章创建时间 * */  
  27.     private Date createDate;   
  28.   
  29.     /** 文章修改时间 * */  
  30.     private Date modifyDate;   
  31.   
  32.     /** 文章创建时的ip地址 * */  
  33.     private String ip;   
  34.   
  35.     /** 文章的点击次数 * */  
  36.     private int hits = 1;   
  37.   
  38.     /** 文章的详细内容,此字段通常指本页的内容,并非此文章的内容,有可能一篇文章有多页,由此字段仅指其中的一页内容 * */  
  39.     private String content;   
  40.   
  41.     /** 此篇文章的总页数,默认为1页,此数字是由创建文章时根据文章的分页的多少计算得出. * */  
  42.     private int pageCount = 1;   
  43.   
  44.     /** 此字段是显示此文章当前所在的页面,默认为第1页,此字段也可作为导向下一页/上一页的相关依据 * */  
  45.     private int pageCurrentIndex = 1;   
  46.   
  47.     /**  
  48.      * 此字段是为设置删除文章所用的  
  49.      * 文章被删除有两种情况,一为此文章的类别被删除,刚此文章无法被检索到;二为此文章被删除.这里指被二种情况删除  
  50.      */  
  51.     private boolean firstDeleted = false;   
  52.   
  53.     /**  
  54.      * 此字段是为彻底删除文章所用,虽然此种情况一般不会被发生,但保留此种情况.当为此种情况时,  
  55.      * 无法以任何方式检索出此文章,仅在数据库中留有相关的记录  
  56.      */  
  57.     private boolean shiftDeleted = false;   
  58.   
  59.     /** 此文章的置顶方式,如果为空,则此文章不置顶 * */  
  60.     private ArticleTopType articleTopType;   
  61.   
  62.     /** 创建文章的作者 * */  
  63.     private User createUser;   
  64.   
  65.     /** 修改文章的作者 * */  
  66.     private User editUser;   
  67.   
  68.     /** 此文章所属的类别 * */  
  69.     private Category category;   
  70.   
  71.     /** 文章的类别链,主要用于文章的查询 * */  
  72.     private String categoryChain;   
  73.   
  74.     /** 相关的标记,主要是一些搜索关键字 * */  
  75.     private String tags;  

这里有几个问题
1,文章是否应从数据库中彻底删除
2,文章删除后是否可以被恢复
3,对于多页文章的处理(如一篇文章分成多个页面显示)
4,对于级联目录下的文章的查找(即如windows资源管理器,在一个目录下搜索此目录及所有子目录下的文章)

对于问题1,2,我设计了一个删除firstDeleted字段和一个彻底删除shiftDeleted字段,当shiftDeleted为true时,表示此文章此被彻底删除,否则当fistDeleted为true时,表示一般删除,(此类删除在管理者页面可被查出,不过有相关标志提示,并且可以管理者页面被恢复).当firstDeleted和shiftDeleted同时为false时,表示此文章是正常文章.

对于问题4,我设计了一个categoryChain的字段,此字段保存此文章的路径信息,此路径信息由文章所在当前目录者提供,第一个目录对应一个惟一的路径信息,并且同时保留了其上下目录的级联信息.此字段的get方法被改成由目录提供,因此如果目录被删除,此文章的路径信息为null,即视为无类别文章.相应get方法如下:

  1. public String getCategoryChain() {   
  2.         return category == null ? null : category.getCategoryChain();   
  3.     }  


对于问题3,我设计了文章的页码并保存在文章属性中,由pageCount和pageCurrentIndex两个属性来完成.pageCount保存此篇文章的总页数,而pageCurrentIndex保存此篇文章当前显示的页数.并且由这两个属性来进行上一页,下一页的判断.这样,当文章被用于多页显示时,每个文章对象仅保留此页的数据,当读取下一页时,再从数据库中读取文章下一页的数据.

#---------------------------
文章类别(category)

java 代码
  1. public class Category implements Serializable {   
  2.     /** 主键 **/  
  3.     private int id;   
  4.     /** 类别名字 **/  
  5.     private String name;   
  6.     /** 类别描述 **/  
  7.     private String description;   
  8.     /** 类别创建时间 **/  
  9.     private Date createDate;   
  10.     /** 创建类别的用户 **/  
  11.     @Fly_m  
  12.     private User user;   
  13.     /** 此类别下的子类别 **/  
  14.     @Fly_m  
  15.     private List<category></category> categoryList;   
  16.     /** 此类别下的文章 **/  
  17.     @Fly_m  
  18.     private List<article></article> articleList;   
  19.     /** 此类别的上一类别,当此类别为最顶层类别时,上一类别为null **/  
  20.     @Fly_m  
  21.     private Category superCategory;   
  22.     /** 此类别的类别链,此类别链依次以上级类别的id值追加'-'值组成,此类别链的目录在于查询相应类别  
  23.      * 下的文章,因为无法保证类别的级数,故由此种方式构造一个链并将其保存在类别中,并进一步保存在  
  24.      * 文章的相应字段中,以一种简单的方式进行文章的查询  
  25.      * 追加:如果此类为顶级类别,则其类别链为当前的时间,以保证类别的唯一的性.  
  26.      **/  
  27.     private String categoryChain;  
正如代码所示,类别被设计为无限级联的,并且每一级有它的上一级和它的子级目录.且每一级都可有相应级类别的文章.想要找到某一级目录下的所有文章,通常作法是对子目录的递归.不过,我作了一个小小的偷懒,即利用categoryChain文章路径,信息这一属性来登记每个目录的详细路径,再将这一路径导向该目录下文章的categoryChain属性.再由article类,可知,article的categoryChain属性由该文章的目录决定,因此,如何处理目录的categoryChain就很重要了.此处利用了数据库本身的特点like语句.详细代码如下所示:
java 代码
  1. public String getCategoryChain() {   
  2.         return categoryChain == null ? (superCategory == null ? new SimpleDateFormat("MMddHHmmssSSS-", Locale.CHINA)   
  3.                 .format(new Date()) : (superCategory.getCategoryChain() == null ? "" : superCategory   
  4.                 .getCategoryChain()) + new SimpleDateFormat("SSS",Locale.CHINA).format(new Date()) + "-") : categoryChain;   
  5.     }  

每一级目录的categoryChain被设计为父目录链,因为顶级目录root目录被设计为时间相关,再加上子级目录被设计为毫秒相关(相同目录下,在同一毫秒内创建不同目录这一可能性很小吧,这里的毫秒相关可能需要被改写),因此,保证了每一目录有惟一的路径信息.

#-------------------
文章置顶对象(articleTopType)

java 代码
  1. public class ArticleTopType {   
  2.   
  3.     /** 主键 **/  
  4.     private int id;   
  5.   
  6.     /** 此置顶方式的相关描述 **/  
  7.     private String description;   
  8.        
  9.     /** 此置顶的开始时间段,默认为当前时间 **/  
  10.     private Date startDate;   
  11.        
  12.     /** 置顶的结束时间段 **/  
  13.     private Date endDate;   
  14.   
  15.     private Article article;  

文章置顶只是简单的作了时间相关(关于文章置顶有许多方面的考虑,如何置顶,在哪儿置顶,或者置顶颜色,置顶级别等).由于模块不要求太复杂,仅作了时间置顶,在时间内置顶,超出时间则置顶消失.

#----------------

文章用户对象(user)

java 代码
  1. public class User implements Serializable {   
  2.   
  3.     private static final long serialVersionUID = -4937427658808092834L;   
  4.     private int id;   
  5.     private String name;   
  6.     private String password;   
  7.     @Fly_m  
  8.     private List<article></article> articleList;   
  9.     @Fly_m  
  10.     private List<category></category> categoryList;  

这个用户对象,只是保存了用户基本信息( 在后期,此对象可能会被其他模块改写,但不影响此处的结构工作).

 

#------------------------------------
模型设计中,重点是目录和文章对象的设计,我觉得主要是需求的复杂性决定了对象复杂性的设计.对于小型系统,一个文章对象可能就是简单的内容+标题+类别,而在一些大型的系统,需要考虑的因素就多了.这决定于系统分析师的分析能力,在不断的实践于,自己也对分析方面有了很大的进步.而模型设计,直接关系于系统的数据存储和以后相关层的设计以及以后系统的扩展能力.在这方面要多下功夫啊.

附件中是相关域模型的源代码,及hibernate的源代码注释(我把以前基于xml的配置搬到了源代码里面,使相关配置更加简单明了).
欢迎大家指点,我会改进的
下一篇把dao这层以及service这一层写上来.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值