留言,是博客系统的一个模块。当别人访问到自己的博客主页时,别人可选择查阅你的博客,可以给你博客评论,也可以给你发表留言。
要设计这个留言,就必须现有数据库。起初我们的数据库的设计是这样的。
留言表1:
可以看出,这个留言表还是很有问题的:
1、第一个问题。这几个属性中的id、word_title、word_content、word_sdTime都应该没什么问题,都是一个留言表中必须的。有问题的是word_author,留言的作者,留言的作者应该是其它用户,这里采用的是字符,就是说写的是作者名字。这个作者名字,就是用户表的master_name。
用户表:
我们的留言表就是通过word_author和用户表关联起来的。其实,这个word_author也是可以用word_authorID的。word_authroID就是用户表中的id,我们把这两个表通过这个id联系起来,这也是比较好一点的做法。
2、第二个问题就是,既然说留言了,那么我们的留言表的功能也太简单了,互动性不强,别人光给你留言,但是你却不能对这个留言说点什么。所以,我们这留言应该要有个回复的功能。但是这个表却无法支持我们的回复的功能。
策略1、当初我们考虑的是,在留言表里面加一个pid,这个pid就是表示回复的那一条留言的id。这样我们的结构就像下面这样:
这只是思考的一个策略。
策略2、后来又想想,我也可以加一个新表,用这个新表映射留言和回复的关系,新表有两个字段,一个是id,一个是pid,表示id是给pid的回复。然后原来的留言表就不用变动了。
后面想想,加多一个表,感觉多此一举呀。直接在留言表上加一个pid就简洁多了。
当我们写jsp的时候,把与当前登录的用户的留言表相关的数据查询出来后,我们要怎么组织这个留言,让其一条一条地显示出来,符合上下文逻辑呢。
由于我们的查出来的数据是按照时间排序的,所以应该不符合上下文逻辑。如果直接按照时间的顺序排列,那就看不出这一条回复是回复那一条留言的了。正因为有这个问题,我们就在查询出来之后,对这些数据进行重新排列,把回复放到留言下面。
不过后面还是没有用策略1的做法,到底为什么没用这就要说到第三个问题了。
3、第三个问题,我们有没有发现,这个留言表还缺了一个重要的东西,我们光有留言作者,但是我们没有留言的对象。我们这个留言到底是给谁的呀,因为在这个表中只有author,没有master,即留言的对象。不仅如此,有些其它表也有这个重大的失误。
所以后面我们又大改了一次数据库。
这个留言表的最终设计是这样子的。
策略3、前面我们也说了,原来的表中只有author,没有master,所以我们把master加了进去。我们加了word_authorID和word_masterID并把这两个设置为外键。
乍一看,这个表感觉还缺什么,没有pid,我们怎么处理回复问题?
后面想想,其实设计成这样,我们就不用加pid了,我们家pid不就是为了使我们显示留言或回复时,能够上下文衔接吗。
当一个用户登录时,那么它就是当前用户,设当前用户的id是x。当我们查询到与当前用户相关的留言数据后,我们的到的是要么word_authorID等于x的留言数据,要么word_masterID等于x的留言数据。就是说我们得到的数据是谁对x留言的数据,或x对谁留言的数据。
由于word_authorID和word_masterID其中肯定有一个,而且只有一个,是等于x的。我们何不用等于x那个来对这些数据进行分类,把相同的归为一类,然后同一类的按照时间进行排序,这样上下文顺序也就得出来了。最后我们只需要按照类别,按照排好的顺显示出来就ok了。
具体的代码如下实现:
先是replylist的产生
String URL=session.getAttribute("url").toString(); List< WordBean> wordList=(List<WordBean>)request.getAttribute("wordList"); //通过获取request里面的wordList参数,即可获得与当前用户相关的留言表的所有结果 LinkedList<WordBean> replyList=new LinkedList<WordBean>(); //用了存储把wordlist留言表按照类别,按照排好的顺序的数据排好的list, //即我们最终要在网页上显示的是replyList MasterBean masterBean = (MasterBean) session.getAttribute("masterBean"); //获取当前用户的所有信息 int id = masterBean.getId(); //获取当前用户的id int replyID = 0; for (int i = 0; i < wordList.size(); i++) { WordBean wordBean = wordList.get(i); int masterID = wordBean.getMasterID();//获取这条留言的被留言者的id int authorID = wordBean.getAuthorID();//获取这条留言的留言作者的id if (masterID == id) {//通过与当前用户的id比较 replyID = authorID; //若是masterID等于当前用户id, //那么authorID就是非当前用户的id,即留言作者的id //当前用户是被留言者 } else { replyID = masterID; //或是authorID等于当前用户id, //那么masterID就是非当前用户的id,即被留言者的id //当前用户是留言者 } //若这是留言表的第一条信息,就直接加入到回复队列里面 if (replyList.size() == 0) { replyList.add(wordBean); } else { //对接下来留言进行判断,符合条件的就加入到replyList中 int temp; for (temp = 0; temp < replyList.size(); temp++) { WordBean replyBean = replyList.get(temp); //找到插入的位置,找到后,退出循环 if (replyBean.getAuthorID() == replyID || replyBean.getMasterID() == replyID) { //比较,找到与replyID相等的,则是同一类的,找到后,退出循环 break; } } replyList.add(temp, wordBean); //找到了第一个replyID与AuthorID或MasterID相等的那 //一条数据的位置,然后在这个位置上插入这一条数据, //这样同一类的都会放在相邻的位置,因为这些数据本来 //也是按照时间的顺序来排好的,所以不需要再对其按照 //时间又排一次,我们只需要找到位置,然后不断插入就 //可以了。 //而且若是找不到与replyID与AuthorID或MasterID相等的 //数据,那么直到循环到temp等于replyList.size时,就会 //退出,然后在这个temp上插入,表示找不到与replyID与 //AuthorID或MasterID相等的数据,则在最后的位置插入。 } }
然后我们的replylist的排列大概是这样(若m是自己的id,a,b,c是其它人的id):
a对m:####(这表示对话内容)
m对a:###
a对m:#####
b对m:######
m对b:###
c对m:##
m对c:####
c对m:######
我们的replylist按照m和a对话、m和b对话、m和c对话分成了三类,然后同类的放在相邻的位置。
我们看到红色的字,这些就是m和a、m和b、m和c对话的第一句话,我们的第一句话一般就是对话的开端,后面的都是回复,所以我们的代码这样处理。
<table> <%if(replyList.size()==0){ %> <tr> <td>该文章暂时还没有留言!!!</td> </tr> <%}else{ int j; //显示留言列表 for(int k=0;k<replyList.size();k=j){ //前面的那个对话已经把其内容输出完后, //k直接从j开始,找出下一个对话的第一条留言 WordBean wordBean=replyList.get(k); //先找出当前对话的第一条留言,这个就是对话的开端,即k位置 %> <tr> <td>留言作者:</td> <td><input value="<%=wordBean.getAuthorID()%>"></td> </tr> <tr> <td>留言标题:</td> <td><input value="<%=wordBean.getWordTitle()%>"></td> </tr> <tr> <td>留言内容:</td> <td> <input value="<%=wordBean.getWordContent()%>"> </td> </tr> <tr> <td>留言时间</td> <td><input value="<%=wordBean.getWordSdTime()%>"></td> </tr> <tr> <td>留言回复</td> <td> <%for(j=k+1;j<replyList.size();j++){ WordBean reply=replyList.get(j); if((reply.getAuthorID()==wordBean.getMasterID() && reply.getMasterID()==wordBean.getAuthorID()) ||(reply.getAuthorID()==wordBean.getAuthorID() && reply.getMasterID()==wordBean.getMasterID())){ //这里做一个判断,判断一下k位置以后的那些数据, //是不是也是和k位置那一条数据一样,也是同一类的数据, //即同一个对话的数据,若是,那么则输出 %> <table> <tr> <td>回复标题:</td><td><%=reply.getWordTitle()%></td> </tr> <tr> <td><%=reply.getAuthorID() %>回复:</td><td><%=reply.getMasterID() %></td> </tr> <tr> <td>回复时间:</td><td><%=reply.getWordSdTime() %></td> </tr> <tr> <td>回复内容:</td><td><%=reply.getWordContent() %></td> </tr> <tr> <td background="<%=URL %>/images/front/line.jpg" colspan="4"></td> </tr> </table> <%}else{ break;//若不是,那么退出循环 } } %> </td> </tr> <tr> <td colspan="4"> <a href="<%=URL%>/WordAction.action?action=reply&id=<%=wordBean.getId()%>">回复留言</a> </td> </tr> <tr> <td colspan="4"> <a href="<%=URL%>/WordAction.action?action=delete&id=<%=wordBean.getId()%>">删除留言</a> </td> </tr> <tr> <td background="<%=URL%>/images/front/line.jpg" colspan="4"></td> </tr> <%} } %> </table>