留言,是博客系统的一个模块。当别人访问到自己的博客主页时,别人可选择查阅你的博客,可以给你博客评论,也可以给你发表留言。
要设计这个留言,就必须现有数据库。起初我们的数据库的设计是这样的。
留言表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>