JiveJdon的CQRS显示阅读部分实现

上篇

上下主题显示

ForumMessageService中有一个特殊方法实现:
PageIterator getThreadsPrevNext(Long forumId, Long currentThreadId)
当显示某个ForumThread下的所有帖子时,在上方有一个ForumThread本身前面或后面主题的遍历功能,如图:

 

这里上下主题顺序是根据前面一个操作ForumThread遍历时集合得到的,但是当前我们无法得到前面操作的ForumThread集合。
如果我们每次都直接采取基于数据库查询的策略,那么无疑增加数据库负载,使用缓存来减轻数据库的反复查询。
缓存的主键设计:一般地,我们容易是以ForumId为缓存主键,这样根据当前forumId值获得一个threadId集合,然后再在这个集合中查找符合当前的threadId,再将其前后threadId获取即可,但是,该方案缺点是:一个forumId可能有几万上十万更多threadId集合,万一有人浏览所有主题贴,这个以forumId为主键的对象集合就很大,而且无法依赖Cache的管理机制实现缓存大小控制。
我们就以当前threadId为主键,包含前后两个threadId为集合的缓存对象,这样打碎了之后,缓存机制可以在缓存即将溢满时,去除那些不经常使用的threadId集合。
在查询数据库时,我们模拟分块分页查询,这样,运气好,可以使用之前getThreads方法的结果(如果有调用的话)。
最后,我们需要实现表现层Jsp页面上下主题显示:
在后台获得的上下主题集合有多种情况:可能上主题没有;可能下主题没有;也可能上下主题都有等,在这种情况下,需要解决Jsp页面判断问题。
由于Struts的标签logic:iterator只是向一个方向遍历,因此试图通过logic:iterator实现上述各种可能性判断则就比较麻烦,我们需要的一个类似ListIterator的遍历器,能够向前或向后翻滚。
因此前期设计思路有些改变,原来的设计思路是:后台产生一个PageIterator,通过Jdon框架批量查询框架的ModelListAction输出ModelListForm视图到Jsp页面中去,然后在Jsp页面使用logic:iterator遍历结果。
现在Jsp页面需要的是ListIterator,ListIterator其实和PageIterator类似,只是PageIterator中装载的是记录ID集合,而不是完整的记录集合,需要在Service中转换以下。
首先,在持久层返回一个符合条件的主键集合,代码如下:
  public List getThreadsPrevNext(Long forumId, Long currentThreadId) {    
        String GET_ALL_ITEMS =
"select threadID  from jiveThread WHERE forumId=? ORDER BY creationDate ASC";
        Collection params = new ArrayList(1);
        params.add(forumId);        
        Block block = pageIteratorSolver.locate(GET_ALL_ITEMS, params, currentThreadId);
        if (block == null){
            return null;
        }
        return block.getList();
    }
这样,我们做一个Struts的原始Action:ThreadPrevNexListAction代码如下:
public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm,
HttpServletRequest request, HttpServletResponse response)
            throws Exception {
    List resultIds = forumMessageService.getThreadsPrevNext(new Long(forumId), currentThreadIdL);
   
   int index = resultIds.indexOf(currentThreadIdL);
    Debug.logVerbose(" found the block ,size:" + resultIds.size() + " the index=" + index, module);
//从业务层得到的是一个ForumThread ID集合。现在要编程ForumThread集合。
    List threads = new ArrayList();
    Iterator iter = resultIds.iterator();
    while (iter.hasNext()) {
         Long id = (Long) iter.next();
         threads.add(forumMessageService.getThread(id));
    }
    //在ForumThread集合将指针定位到当前ForumThread
    ListIterator li = threads.listIterator();
    Debug.logVerbose(" locate currentThreadId:" + currentThreadId, module);
    while (li.nextIndex() != index) {               
        Object o = li.next();               
    }
    request.setAttribute("ThreadsPrevNext", li); //保存在request中,以便Jsp页面获得
    return actionMapping.findForward(FormBeanUtil.FORWARD_SUCCESS_NAME);
}
最后,在Jsp页面使用稍许Java代码进行前后遍历:
<%
java.util.ListIterator iter = (java.util.ListIterator)request.getAttribute("ThreadsPrevNext");
if (iter.hasPrevious()){
   com.jdon.jivejdon.model.ForumThread    forumThread =
(com.jdon.jivejdon.model.ForumThread)iter.previous();
   request.setAttribute("forumThread", forumThread);
  // advance the iterator pointer back to the original index  
   iter.next();
  %>
     <a href ……
     上一主题
    </font>
    </a>
<%  } else { %>
    &nbsp;
<%  } %>

如果你知道Struts有标签可以作类似hasPrevious的向前遍历,只有替换该处java代码即可,从这里我们也可以看出,如果框架(如Struts和JF)不能满足我们的需求,我们可以基于最底层Jsp+JavaBeans来编程,当然这是特殊情况下不得已采取的办法。

帖子批量显示

帖子分页显示是本系统主要功能,分两种显示:扁平式显示和树状显示,前者就是将当前主题下所有帖子以时间先后显示;后者是以回帖关系显示帖子之间的父子关系。这两种显示方式除了可以单独显示以外(根据论坛设置),也可以合并显示在一个页面。
ForumMessageService中两个主要方法使用Jdon框架批量查询完成,这里不再详细说明:
PageIterator getMessages(Long threadId, int start, int count);
PageIterator getThreads(Long forumId, int start, int count);

下篇