Day07论坛2

Posted beihai2018

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Day07论坛2相关的知识,希望对你有一定的参考价值。

  1. 环境准备+版块相关功能

版块列表 1(个请求)

ForumAction.list()

显示单个版块(主题列表) 1

ForumAction.show()

------

发新帖 2

TopicAction.addUI()

TopicAction.add()

显示单个主题(主帖+回帖列表) 1

TopicAction.show()

------

回帖 2

ReplyAction.addUI()

ReplyAction.add()

步骤:创建Actionà写里面的方法(方法名,返回值) à创建页面à配置(Action注释和struts.xml)à创建serviceà配置(ServiceImpl注释和在BaseAction中注入service) à写具体的Action方法和service方法à套用静态页面

1.先实现版块列表功能:

(这里ForumAction和ForumManageAction公用service)

技术分享图片

ForumAction:

import cn.itcast.oa.base.BaseAction;

import cn.itcast.oa.domain.Forum;

@Controller

@Scope("prototype")

public class ForumAction extends BaseAction<Forum>{

 

    /** 版块列表 */

    public String list() throws Exception {

        List<Forum> forumList = forumService.findAll();

        ActionContext.getContext().put("forumList", forumList);

        return "list";

    }

    

    /** 显示单个版块(主题列表) */

    public String show() throws Exception {

        return "show";

    }

}

TopicAction:

@Controller

@Scope("prototype")

public class TopicAction extends BaseAction<Topic>{

 

    /** 显示单个主题 */

    public String show() throws Exception {

        return "show";

    }

    

    /** 发新帖页面*/

    public String addUI() throws Exception {

        return "addUI";

    }

    

    /** 发新帖 */

    public String add() throws Exception {

        return "toShow";    //转到当前这个 新主题的页面

    }    

}

 

ReplyAction:

@Controller

@Scope("prototype")

public class ReplyAction extends BaseAction<Reply>{

 

    /** 发表回复页面 */

    public String addUI() throws Exception {

        return "addUI";

    }

    

    /** 发表回复 */

    public String add() throws Exception {

        return "toTopicShow";    //转到当前回复所属的主题显示页面

    }

}

技术分享图片

(ForumAction对应的)list.jsp:

        <div class="ForumPageTableBorder" style="margin-top: 25px;">

        <s:iterator value="forumList">

            <table width="100%" border="0" cellspacing="0" cellpadding="0">

            

                <!--表头-->

                <tr align="center" valign="middle">

                    <td colspan="3" class="ForumPageTableTitleLeft">版块</td>

                    <td width="80" class="ForumPageTableTitle">主题数</td>

                    <td width="80" class="ForumPageTableTitle">文章数</td>

                    <td width="270" class="ForumPageTableTitle">最后发表的主题</td>

                </tr>

                <tr height="1" class="ForumPageTableTitleLine"><td colspan="9"></td></tr>

                <tr height="3"><td colspan="9"></td></tr>

            

                <!--版面列表-->

                <tbody class="dataContainer" datakey="forumList">

                <tr height="78" align="center" class="template">

                    <td width="3"></td>

                    <td width="75" class="ForumPageTableDataLine">

                        <img src="${pageContext.request.contextPath}/style/images/forumpage3.gif" />

                    </td>

                    <td class="ForumPageTableDataLine">

                        <ul class="ForumPageTopicUl">

                            <li class="ForumPageTopic">

                            <s:a cssClass="ForumPageTopic" action="forum_show?id=%{id}">${name}</s:a></li>

                            <li class="ForumPageTopicMemo">${description}</li>

                        </ul>

                    </td>

                    <td class="ForumPageTableDataLine"><b>${topicCount}</b></td>

                    <td class="ForumPageTableDataLine"><b>${articleCount}</b></td>

                    <td class="ForumPageTableDataLine">

                        <ul class="ForumPageTopicUl">

                            <li><font color="#444444">主题:</font>

                                <s:a cssClass="ForumTitle" action="topic_show?id=%{lastTopic.id }">${lastTopic.title}</s:a>

                            </li>

                            <li><font color="#444444">作者:</font> ${lastTopic.author.name}</li>

                            <li><font color="#444444">时间:</font> <s:date name="lastTopic.postTime" format="yyyyMMdd HH:mm:ss"/></li>

                        </ul>

                    </td>

                    <td width="3"></td>

                </tr>

                </tbody>

                <!-- 版面列表结束 -->

                

                <tr height="3"><td colspan="9"></td></tr>

            </table>

        </s:iterator>

        </div>

Struts.xml:

<!-- 论坛:版块相关 -->

    <action name="forum_*" class="forumAction" method="{1}">

        <result name="list">/WEB-INF/jsp/forumAction/list.jsp</result>

        <result name="show">/WEB-INF/jsp/forumAction/show.jsp</result>

    </action>

      

    <!-- 论坛:主题相关 -->

    <action name="topic_*" class="topicAction" method="{1}">

        <result name="show">/WEB-INF/jsp/topicAction/show.jsp</result>

        <result name="addUI">/WEB-INF/jsp/topicAction/addUI.jsp</result>

        <result name="toShow" type="redirectAction">topic_show?id=${id}</result>

    </action>

      

    <!-- 论坛:回复相关 -->

    <action name="reply_*" class="replyAction" method="{1}">

        <result name="addUI">/WEB-INF/jsp/replyAction/addUI.jsp</result>

        <result name="toTopicShow" type="redirectAction">topic_show?id=${id}</result>

    </action>


效果:

技术分享图片

2.再实现单个版块(主题列表)功能:(暂时不做分页)

ForumAction:

@Controller

@Scope("prototype")

public class ForumAction extends BaseAction<Forum>{

 

    /** 版块列表 */

    public String list() throws Exception {

        List<Forum> forumList = forumService.findAll();

        ActionContext.getContext().put("forumList", forumList);

        return "list";

    }

    

    /** 显示单个版块(主题列表) */

    public String show() throws Exception {

        //准备数据:forum

        Forum forum = forumService.getById(model.getId());

        ActionContext.getContext().put("forum", forum);

        

        //准备数据:topicList

        List<Topic> topicList = topicService.findByForum(forum);

        ActionContext.getContext().put("topicList", topicList);

        return "show";

    }

}

topicServiceImpl:

@Service

@Transactional

@SuppressWarnings("unchecked")

public class TopicServiceImpl extends DaoSupportImpl<Topic> implements TopicService{

 

    /**

     * 查询指定版块的主题列表,最新状态的排到前面,置顶帖排到最前面

     */

    public List<Topic> findByForum(Forum forum) {

        return getSession().createQuery(//

                "from Topic t where t.forum = ? order by (case t.type when 2 then 2 else 0 end) desc, t.lastUpdateTime desc")//

                .setParameter(0, forum)//

                .list();

    }

}

其中Topic.java是这样的:

/**

* 实体:主贴

* @author Tan

*

*/

public class Topic extends Article{

 

    /** 普通贴 */

    public static final int TYPE_NORMAL = 0;

    /** 精品贴 */

    public static final int TYPE_BEST = 1;

    /** 置顶贴 */

    public static final int TYPE_TOP = 2;

      

    

    private String title;    //标题

    private int type;    //类型

    private int replyCount;    //回复数量

    private Date lastUpdateTime;    //最后文章的发表时间

    

    private Forum forum;    //版块 主贴与版块:多对一

    private Set<Reply> replies = new HashSet<Reply>();    //回复 主贴与回复:多对一

    private Reply lastReply;    //最后回复

……

}

Topic还继承了Article.java:

/**

* 实体:文章

* @author Tan

*

*/

public abstract class Article {

 

    private Long id;

    private String content;    //内容(TEXT类型)

    private Date postTime;    //发表时间

    private String ipAddr;    //ip地址

    

    private User author;    //作者

……

需求页面是这样的:

技术分享图片

ForumAction中的show.jsp:

<!-- 标题显示 -->

<div id="Title_bar">

<div id="Title_bar_Head">

<div id="Title_Head"></div>

<div id="Title"><!--页面标题-->

<img border="0" width="13" height="13" src="${pageContext.request.contextPath}/style/images/title_arrow.gif"/> ${forum.name }】中的主题列表

</div>

<div id="Title_End"></div>

</div>

</div>

 

<div id="MainArea">

    <div id="PageHead"></div>

    <center>

        <div class="ItemBlock_Title1" style="width: 98%;">

            <font class="MenuPoint"> &gt; </font>

            <s:a action="forum_list">论坛</s:a>

            <font class="MenuPoint"> &gt; </font>

            ${forum.name }

            <span style="margin-left:30px;"><a href="${pageContext.request.contextPath}/BBS_Topic/saveUI.html">

                <img align="absmiddle" src="${pageContext.request.contextPath}/style/blue/images/button/publishNewTopic.png"/></a>

            </span>

        </div>

        

        <div class="ForumPageTableBorder">

            <table width="100%" border="0" cellspacing="0" cellpadding="0">

                <!--表头-->

                <tr align="center" valign="middle">

                    <td width="3" class="ForumPageTableTitleLeft">

                        <img border="0" width="1" height="1" src="${pageContext.request.contextPath}/style/images/blank.gif" />

                    </td>

                    <td width="50" class="ForumPageTableTitle"><!--状态/图标-->&nbsp;</td>

                    <td class="ForumPageTableTitle">主题</td>

                    <td width="130" class="ForumPageTableTitle">作者</td>

                    <td width="100" class="ForumPageTableTitle">回复数</td>

                    <td width="130" class="ForumPageTableTitle">最后回复</td>

                    <td width="3" class="ForumPageTableTitleRight">

                        <img border="0" width="1" height="1" src="${pageContext.request.contextPath}/style/images/blank.gif" />

                    </td>

                </tr>

                <tr height="1" class="ForumPageTableTitleLine"><td colspan="8"></td></tr>

                <tr height=3><td colspan=8></td></tr>

                    

                <!--主题列表-->

                <tbody class="dataContainer" datakey="topicList">

                <s:iterator value="topicList">

                    <tr height="35" id="d0" class="template">

                        <td></td>

                        <td class="ForumTopicPageDataLine" align="center"><img src="${pageContext.request.contextPath}/style/images/topicType_${topic.type}.gif" /></td>

                        <td class="Topic"><s:a cssClass="Default" action="topic_show?id=%{id}">${title}</s:a></td>

                        <td class="ForumTopicPageDataLine">

                            <ul class="ForumPageTopicUl">

                                <li class="Author">{author.name}</li>

                                <li class="CreateTime"><s:date name="postTime" format="yyyyMMdd HH:mm:ss"/> </li>

                            </ul>

                        </td>

                        <td class="ForumTopicPageDataLine Reply" align="center"><b>${replyCount}</b></td>

                        <td class="ForumTopicPageDataLine">

                            <ul class="ForumPageTopicUl">

                                <li class="Author">${lastReply.author.name }</li>

                                <li class="CreateTime"><s:date name="lastReply.postTime" format="yyyyMMdd HH:mm:ss"/></li>

                            </ul>

                        </td>

                        <td></td>

                    </tr>

                </s:iterator>

                </tbody>

                    <!--主题列表结束-->    

效果页面:

技术分享图片

  1. 主题相关功能

之前已经实现了版块列表和单个版块展示(主题列表)的功能,因为还没有数据,所以主题展示的功能暂且不做,先做主题添加的功能(发新帖).

主题添加(发新帖):

添加页面:

发新帖的请求是从版块的单个版块展示(主题列表)发出的:

技术分享图片

还要修改一下ForumAction对应的show.jsp中的链接地址:

<div class="ItemBlock_Title1" style="width: 98%;">

    <font class="MenuPoint"> &gt; </font>

     <s:a action="forum_list">论坛</s:a>

    <font class="MenuPoint"> &gt; </font>

            ${forum.name }

    <span style="margin-left:30px;">

<s:a action="topic_addUI?forumId=%{#forum.id }">

     <img align="absmiddle" src="${pageContext.request.contextPath}/style/blue/images/button/publishNewTopic.png"/>

</s:a>

    </span>

</div>

  • Tips: topic_addUI?forumId=%{#forum.id }

    这里要将forum的id传递给TopicAction.虽然本页面是ForumAction对应的show.jsp页面,但因为此链接要转到TopicAction,而此id并不是Topic的id,所以要写成forumId,绝不能写成Id. forumId.%{#forum.id}这是OGNL表达式,加#是因为在ForumAction,forum被put进了map域中.

Forum forum = forumService.getById(model.getId());

ActionContext.getContext().put("forum", forum);

相应的,在TopicAction中要用属性驱动的方式封装这个参数

@Controller

@Scope("prototype")

public class TopicAction extends BaseAction<Topic>{

 

    private Long forumId;

    

    /** 显示单个主题 */

    public String show() throws Exception {

        return "show";

    }

    

    /** 发新帖页面*/

    public String addUI() throws Exception {

        //准备数据:forum

        Forum forum = forumService.getById(forumId);

        ActionContext.getContext().put("forum", forum);

        return "addUI";

    }

    

    /** 发新帖 */

    public String add() throws Exception {

        return "toShow";    //转到当前这个 新主题的页面

    }

    //-----------------------------------

    public Long getForumId() {

        return forumId;

    }

 

    public void setForumId(Long forumId) {

        this.forumId = forumId;

    }

}

TopicAction对应的add UI.jsp:

……

<!--显示表单内容-->

<div id="MainArea">

<s:form action="topic_add" cssStyle="margin: 0; padding: 0;">

    <s:hidden name="forumId"></s:hidden>

    <div id="PageHead"></div>

    <center>

        <div class="ItemBlock_Title1">

            <div width=85% style="float:left">

                <font class="MenuPoint"> &gt; </font>

                <s:a action="forum_list">论坛</s:a>

                <font class="MenuPoint"> &gt; </font>

                <s:a action="forum_show?id=%{#forum.id}">${forum.name}</s:a>

                <font class="MenuPoint"> &gt;&gt; </font>

                发表新主题

            </div>

        </div>

        <div class="ItemBlockBorder">

            <table border="0" cellspacing="1" cellpadding="1" width="100%" id="InputArea">

                <tr>

                    <td class="InputAreaBg" height="30"><div class="InputTitle">标题</div></td>

                    <td class="InputAreaBg"><div class="InputContent">

                        <s:textfield name="title" cssClass="InputStyle" cssStyle="width:100%"/></div>

                    </td>

                </tr>

                <tr height="240">

                    <td class="InputAreaBg"><div class="InputTitle">内容</div></td>

                    <td class="InputAreaBg"><div class="InputContent"><s:textarea name="content" cssStyle="width:600px;height:200px"></s:textarea></div></td>

                </tr>

                <tr height="30">

                    <td class="InputAreaBg" colspan="2" align="center">

                        <input type="image" src="${pageContext.request.contextPath}/style/blue/images/button/submit.PNG" style="margin-right:15px;"/>

                        <a href="javascript:history.go(-1);"><img src="${pageContext.request.contextPath}/style/blue/images/button/goBack.png"/></a>

                    </td>

                </tr>

            </table>

        </div>

    </center>

</s:form>

……

  • Tips: <s:a action="forum_show?id=%{#forum.id}">${forum.name}</s:a>

同理,这里要将forum的id传递给ForumAction对应的show(),虽然本页面是TopicAction对应的addUI页面,但因为此链接要转到ForumAction,而此id这好是forum的id,所以写成id即可,不用再写成forumId了. %{#forum.id}这是OGNL表达式,加#是因为在TopicAction中forum被put进了map域中.

Forum forum = forumService.getById(forumId);

ActionContext.getContext().put("forum", forum);

主题添加:

在发表新主题的同时,版块的一些属性也会受到影响,所以还要维护版块的某些属性.

特殊属性的说明

Forum

topicCount

主题数量

articleCount

文章数量(主题+回复)

lastTopic

最后发表的主题

Topic

replyCount

回复数量

lastReply

最后发表的回复

lastUpdateTime

最后更新时间(主题发表的时间或最后回复的时间)

 

特殊属性的维护

  

发表新主题

发表新回复

Forum

topicCount

1

 

articleCount

1

1

lastTopic

更新为当前的新主题

 

Topic

replyCount

0

1

lastReply

null

更新为当前的新回复

lastUpdateTime

本主题的发表时间

更新为当前新回复的发表时间

TopicAction:

@Controller

@Scope("prototype")

public class TopicAction extends BaseAction<Topic>{

 

    private Long forumId;

    

    /** 显示单个主题 */

    public String show() throws Exception {

        return "show";

    }

    

    /** 发新帖页面*/

    public String addUI() throws Exception {

        //准备数据:forum

        Forum forum = forumService.getById(forumId);

        ActionContext.getContext().put("forum", forum);

        return "addUI";

    }

    

    /** 发新帖 */

    public String add() throws Exception {

        //封装对象

        Topic topic = new Topic();

        //需要在action中封装的数据:

        //>>a.表单中的参数

        topic.setTitle(model.getTitle());

        topic.setContent(model.getContent());

        topic.setForum(forumService.getById(forumId));//addUI.jsp表单中的隐藏域,forumId传递过来了

        //>>b.在显示层才能获得的数据

        topic.setAuthor(getCurrentUser());    //当前登录的用户

        topic.setIpAddr(getRequestIp());    //客户端的IP地址

        

        //调用业务方法

        topicService.save(topic);

 

        return "toShow";    //转到当前这个 新主题的页面

    }

}

Tips:

action中就封装这些属性即可:表单中的参数和在显示层才能获取到的数据,其他数据到业务层再设置.看需求页面分析从页面传递过来的值:

技术分享图片

GetCurrentUser()getRequestIp()比较常用,所以封装到BaseAction中比较好.

//--------------------工具方法----------------

    /**

     * 获取当前用户

     */

    public User getCurrentUser() throws Exception {

        return (User) ActionContext.getContext().getSession().get("user");

    }

    

    /**

     * 获取客户端的ip地址

     */

    public String getRequestIp() throws Exception {

        return ServletActionContext.getRequest().getRemoteAddr();

    }

TopicServiceImpl:

@Service

@Transactional

@SuppressWarnings("unchecked")

public class TopicServiceImpl extends DaoSupportImpl<Topic> implements TopicService{

 

    /**

     * 查询指定版块的主题列表,最新状态的排到前面,置顶帖排到最前面

     */

    public List<Topic> findByForum(Forum forum) {

        return getSession().createQuery(//

                "from Topic t where t.forum = ? order by (case t.type when 2 then 2 else 0 end) desc, t.lastUpdateTime desc")//

                .setParameter(0, forum)//

                .list();

    }

 

    

    /**

     * 重写save()

     */

    public void save(Topic topic) {

        //设置属性并保存

        topic.setType(topic.TYPE_NORMAL);    //普通帖

        topic.setReplyCount(0);

        topic.setLastReply(null);

        topic.setPostTime(new Date());    //当前时间

        topic.setLastUpdateTime(topic.getPostTime());    //默认为主题的发表时间

        

        getSession().save(topic);

            

        //更新相关信息

        Forum forum = topic.getForum();    

        forum.setTopicCount(forum.getTopicCount()+1);    //主题数量

        forum.setArticleCount(forum.getArticleCount()+1);    //回复数量(主题+回复)

        forum.setLastTopic(topic);    //最后发表主题

        

        getSession().update(forum);

    }

}

因为topicaction中的show()和对用的页面还没写,所以发完新帖后提交,显示的是空白页面,此时在空白页面中右键属性:

技术分享图片

Id为空值,所以要在TopicAction中传id过去:

    ……

/** 发新帖 */

    public String add() throws Exception {

        //封装对象

        Topic topic = new Topic();

        //需要在action中封装的数据:

        //>>a.表单中的参数

        topic.setTitle(model.getTitle());

        topic.setContent(model.getContent());

        topic.setForum(forumService.getById(forumId));

        //>>b.在显示层才能获得的数据

        topic.setAuthor(getCurrentUser());    //当前登录的用户

        topic.setIpAddr(getRequestIp());    //客户端的IP地址

        

        //调用业务方法

        topicService.save(topic);

        

        ActionContext.getContext().put("topicId", topic.getId());

        return "toShow";    //转到当前这个 新主题的页面

    }

Struts.xml:

<!-- 论坛:主题相关 -->

    <action name="topic_*" class="topicAction" method="{1}">

        <result name="show">/WEB-INF/jsp/topicAction/show.jsp</result>

        <result name="addUI">/WEB-INF/jsp/topicAction/addUI.jsp</result>

        <result name="toShow" type="redirectAction">topic_show?id=${#topicId}</result>

    </action>

这样再提交时,便有了id:

技术分享图片

显示置顶帖,精华帖,普通贴图标的小技巧:

将相应图片名称改成相应type值:

技术分享图片

技术分享图片

在ForumAction对应的show.jsp页面中引入图片时即可这么写:

<img src="${pageContext.request.contextPath}/style/images/topicType_${type}.gif" />

效果图:

技术分享图片

主题展示(TopicAction中的show()):

TopicAction:

……

public class TopicAction extends BaseAction<Topic>{

    ……

    /** 显示单个主题 */

    public String show() throws Exception {

        //准备数据:topic

        Topic topic = topicService.getById(model.getId());

        ActionContext.getContext().put("topic", topic);

        

        //准备数据:replyList

        List<Reply> replyList = topicService.findByTopic(topic);

        ActionContext.getContext().put("replyList", replyList);

        

        return "show";

    }

……

}

TopicServiceImpl:

public class TopicServiceImpl extends DaoSupportImpl<Topic> implements TopicService{

……

    /**

     * 查询指定主题的回复,最新回复排到最后

     */

    public List<Reply> findByTopic(Topic topic) {

        return getSession().createQuery(//

                "from Reply r where r.topic = ? order by r.postTime")//

                .setParameter(0, topic)//

                .list();

    }

    ……

}

对应静态页面:

技术分享图片

TopicAction对应的show.jsp:

……

<!--内容显示-->    

<div id="MainArea">

    <div id="PageHead"></div>

    <center>

        <div class="ItemBlock_Title1" style="width: 98%">

            <font class="MenuPoint"> &gt; </font>

            <s:a action="forum_list">论坛</s:a>

            <font class="MenuPoint"> &gt; </font>

            <s:a action="forum_show?id=%{#topic.forum.id}">${topic.forum.name }</s:a>

            <font class="MenuPoint"> &gt;&gt; </font>

            帖子阅读

            <span style="margin-left:30px;"><s:a action="topic_addUI?forumId=%{#topic.forum.id}">

                <img align="absmiddle" src="${pageContext.request.contextPath}/style/blue/images/button/publishNewTopic.png"/></s:a>

            </span>

        </div>

        

        <div class="ForumPageTableBorder dataContainer" datakey="replyList">

        

            <!--显示主题标题等-->

            <table width="100%" border="0" cellspacing="0" cellpadding="0">

                <tr valign="bottom">

                <td width="3" class="ForumPageTableTitleLeft">&nbsp;</td>

                    <td class="ForumPageTableTitle"><b>本帖主题:${topic.title }</b></td>

                    <td class="ForumPageTableTitle" align="right" style="padding-right:12px;">

                        <s:a class="detail" action="reply_addUI?topicId=%{#topic.id}"><img border="0" src="${pageContext.request.contextPath}/style/images/reply.gif" />回复</s:a>

                        <a href="moveUI.html"><img border="0" src="${pageContext.request.contextPath}/style/images/edit.gif" />移动到其他版块</a>

                        <a href="#" onClick="return confirm(‘要把本主题设为精华吗?‘)"><img border="0" src="${pageContext.request.contextPath}/style/images/forum_hot.gif" />精华</a>

                        <a href="#" onClick="return confirm(‘要把本主题设为置顶吗?‘)"><img border="0" src="${pageContext.request.contextPath}/style/images/forum_top.gif" />置顶</a>

                        <a href="#" onClick="return confirm(‘要把本主题设为普通吗?‘)"><img border="0" src="${pageContext.request.contextPath}/style/images/forum_comm.gif" />普通</a>

                    </td>

                    <td width="3" class="ForumPageTableTitleRight">&nbsp;</td>

                </tr>

                <tr height="1" class="ForumPageTableTitleLine"><td colspan="4"></td></tr>

            </table>

 

            <!-- ~~~~~~~~~~~~~~~ 显示主帖 ~~~~~~~~~~~~~~~ -->

            <div class="ListArea">

                <table border="0" cellpadding="0" cellspacing="1" width="100%">

                    <tr>

                        <td rowspan="3" width="130" class="PhotoArea" align="center" valign="top">

                            <!--作者头像-->

                            <div class="AuthorPhoto">

                                <img border="0" width="110" height="110" src="${pageContext.request.contextPath}/style/images/defaultAvatar.gif"

                                    onerror="this.onerror=null; this.src=‘${pageContext.request.contextPath}/style/images/defaultAvatar.gif‘;" />

                            </div>

                            <!--作者名称-->

                            <div class="AuthorName">${topic.author.name }</div>

                        </td>

                        <td align="center">

                            <ul class="TopicFunc">

                                <!--操作列表-->

                                <li class="TopicFuncLi">

                                    <a class="detail" href="${pageContext.request.contextPath}/BBS_Topic/saveUI.html"><img border="0" src="${pageContext.request.contextPath}/style/images/edit.gif" />编辑</a>

                                    <a class="detail" href="#" onClick="return confirm(‘确定要删除本帖吗?‘)"><img border="0" src="${pageContext.request.contextPath}/style/images/delete.gif" />删除</a>

                                </li>

                                <!-- 文章标题 -->

                                <li class="TopicSubject">

                                    <s:property value="#topic.title" escape="true"/>

                                </li>

                            </ul>

                        </td>

                    </tr>

                    <tr><!-- 文章内容 -->

                        <td valign="top" align="center">

                            <div class="Content">${topic.content }</div>

                        </td>

                    </tr>

                    <tr><!--显示楼层等信息-->

                        <td class="Footer" height="28" align="center" valign="bottom">

                            <ul style="margin: 0px; width: 98%;">

                                <li style="float: left; line-height:18px;"><font color=#C30000>[楼主]</font>

                                    <s:date name="#topic.postTime" format="yyyy-MM-dd HH:mm:ss"/>

                                </li>

                                <li style="float: right;"><a href="javascript:scroll(0,0)">

                                    <img border="0" src="${pageContext.request.contextPath}/style/images/top.gif" /></a>

                                </li>

                            </ul>

                        </td>

                    </tr>

                </table>

            </div>

            <!-- ~~~~~~~~~~~~~~~ 显示主帖结束 ~~~~~~~~~~~~~~~ -->

 

 

            <!-- ~~~~~~~~~~~~~~~ 显示回复列表 ~~~~~~~~~~~~~~~ -->

            <s:iterator value="replyList" status="status">

            <div class="ListArea template">

                <table border="0" cellpadding="0" cellspacing="1" width="100%">

                    <tr>

                        <td rowspan="3" width="130" class="PhotoArea" align="center" valign="top">

                            <!--作者头像-->

                            <div class="AuthorPhoto">

                                <img border="0" width="110" height="110" src="${pageContext.request.contextPath}/style/images/defaultAvatar.gif"

                                    onerror="this.onerror=null; this.src=‘${pageContext.request.contextPath}/style/images/defaultAvatar.gif‘;" />

                            </div>

                            <!--作者名称-->

                            <div class="AuthorName">${author.name }</div>

                        </td>

                        <td align="center">

                            <ul class="TopicFunc">

                                <!--操作列表-->

                                <li class="TopicFuncLi">

                                    <a class="detail" href="${pageContext.request.contextPath}/BBS_Topic/saveUI.html"><img border="0" src="${pageContext.request.contextPath}/style/images/edit.gif" />编辑</a>

                                    <a class="detail" href="#" onClick="return confirm(‘确定要删除本帖吗?‘)"><img border="0" src="${pageContext.request.contextPath}/style/images/delete.gif" />删除</a>

                                </li>

                                <%-- <!-- 文章表情与标题 -->

                                <li class="TopicSubject">

                                    <img width="19" height="19" src="${pageContext.request.contextPath}/style/images/face/${reply.faceIcon}"/>

                                    ${reply.title}

                                </li> --%>

                            </ul>

                        </td>

                    </tr>

                    <tr><!-- 文章内容 -->

                        <td valign="top" align="center">

                            <div class="Content">${content}</div>

                        </td>

                    </tr>

                    <tr><!--显示楼层等信息-->

                        <td class="Footer" height="28" align="center" valign="bottom">

                            <ul style="margin: 0px; width: 98%;">

                                <li style="float: left; line-height:18px;"><font color=#C30000>[${status.count}]</font>

                                    <s:date name="postTime" format="yyyy-MM-dd HH:mm:ss"/>

                                </li>

                                <li style="float: right;"><a href="javascript:scroll(0,0)">

                                    <img border="0" src="${pageContext.request.contextPath}/style/images/top.gif" /></a>

                                </li>

                            </ul>

                        </td>

                    </tr>

                </table>

            </div>

            </s:iterator>

            <!-- ~~~~~~~~~~~~~~~ 显示回复列表结束 ~~~~~~~~~~~~~~~ -->

        </div>

 

        <div class="ForumPageTableBorder" style="margin-top: 25px;">

            <table width="100%" border="0" cellspacing="0" cellpadding="0">

                <tr valign="bottom">

                    <td width="3" class="ForumPageTableTitleLeft">&nbsp;</td>

                    <td class="ForumPageTableTitle"><b>快速回复</b></td>

                    <td width="3" class="ForumPageTableTitleRight">&nbsp;</td>

                </tr>

                <tr height="1" class="ForumPageTableTitleLine">

                    <td colspan="3"></td>

                </tr>

            </table>

        </div>

    </center>

            

    <!--快速回复-->

    <div class="QuictReply">

    <form action="">

        <div style="padding-left: 3px;">

            <table border="0" cellspacing="1" width="98%" cellpadding="5" class="TableStyle">

                <!-- <tr height="30" class="Tint">

                    <td width="50px" class="Deep"><b>标题</b></td>

                    <td class="no_color_bg">

                        <input type="text" name="title" class="InputStyle" value="回复:昨天发现在表单里删除的图片" style="width:90%"/>

                    </td>

                </tr> -->

                <tr class="Tint" height="200">

                    <td valign="top" rowspan="2" class="Deep"><b>内容</b></td>

                    <td valign="top" class="no_color_bg">

                        <textarea name="content" style="width: 95%; height: 300px"></textarea>

                    </td>

                </tr>

                <tr height="30" class="Tint">

                    <td class="no_color_bg" colspan="2" align="center">

                        <input type="image" src="${pageContext.request.contextPath}/style/blue/images/button/submit.PNG" style="margin-right:15px;"/>

                    </td>

                </tr>

            </table>

        </div>

    </form>

    </div>

</div>

……

Tips: <s:property value="#topic.title" escape="true"/>

escape="true"这是转义的意思.

主题显示页面的顶部,有快速回复的按钮:

技术分享图片

相应链接action="reply_addUI?topicId=%{#topic.id}

既然是回复,就要指定要回复的主题.所以要传递topicId.在ReplyAction中以属性驱动的方式封装该参数:

private Long topicId;

public Long getTopicId() {

    return topicId;

}

    

public void setTopicId(Long topicId) {

    this.topicId = topicId;

}

  1. 回复

回复和发帖差不多.

ReplyAction:

@Controller

@Scope("prototype")

public class ReplyAction extends BaseAction<Reply>{

 

    private Long topicId;

 

    /** 发表回复页面 */

    public String addUI() throws Exception {

        //准备数据

        Topic topic = topicService.getById(topicId);

        ActionContext.getContext().put("topic", topic);

        return "addUI";

    }

    

    /** 发表回复 */

    public String add() throws Exception {

        Reply reply = new Reply();

        //封装对象

        //a.表单中的参数

        reply.setContent(model.getContent());

        reply.setTopic(topicService.getById(topicId));

        

        //b.在显示层才能获取的信息

        reply.setAuthor(getCurrentUser());    //当前登录的用户

        reply.setIpAddr(getRequestIp());    //客户的ip地址

        

        //调用业务方法

        replyService.save(reply);

        

        return "toTopicShow";    //转到当前回复所属的主题显示页面

    }

    

    //---------------------

    public Long getTopicId() {

        return topicId;

    }

    

    public void setTopicId(Long topicId) {

        this.topicId = topicId;

    }

}

ReplyServiceImpl:

@Service

@Transactional

public class ReplyServiceImpl extends DaoSupportImpl<Reply> implements ReplyService{

 

    /**

     * 重写save(),处理特殊属性

     */

    public void save(Reply reply) {

        reply.setPostTime(new Date());    //发表时间为当前时间

        reply.setDeleted(false);    //默认为未删除

        

        getSession().save(reply);

        //处理Forum和Topic中的特殊属性

        Topic topic = reply.getTopic();

        Forum forum = topic.getForum();

        

        forum.setArticleCount(forum.getArticleCount()+1);    //版块的文章数量(主题+回复)

        

        topic.setReplyCount(topic.getReplyCount()+1);    //主题回复数量

        topic.setLastReply(reply);    //主题的最后回复

        topic.setLastUpdateTime(reply.getPostTime());    //主题的最后更新时间 默认为最后回复时间

        

        getSession().update(forum);

        getSession().update(topic);

    }

}

页面需求: (其中表情和标题是不需要的)

技术分享图片

ReplyAction对应的addUI.jsp:

……

<!--显示表单内容-->

<div id="MainArea">

<s:form action="reply_add" sccStyle="margin: 0; padding: 0;">

    <s:hidden name="topicId"></s:hidden>

    <div id="PageHead"></div>

    <center>

        <div class="ItemBlock_Title1">

            <div width=85% style="float:left">

                <font class="MenuPoint"> &gt; </font>

                <s:a action="forum_list">论坛</s:a>

                <font class="MenuPoint"> &gt; </font>

                <s:a action="forum_show?id=%{#topic.forum.id}">${topic.forum.name }</s:a>

                <font class="MenuPoint"> &gt;&gt; </font>

                帖子回复

            </div>

        </div>

        <div class="ItemBlockBorder">

            <table border="0" cellspacing="1" cellpadding="1" width="100%" id="InputArea">

                <tr>

                    <td class="InputAreaBg" height="30"><div class="InputTitle">帖子主题</div></td>

                    <td class="InputAreaBg"><div class="InputContent">${topic.title }</div></td>

                </tr>

                <tr height="240">

                    <td class="InputAreaBg"><div class="InputTitle">内容</div></td>

                    <td class="InputAreaBg"><div class="InputContent"><s:textarea name="content" cssStyle="width:650px;height:200px;"></s:textarea></div></td>

                </tr>

                <tr height="30">

                    <td class="InputAreaBg" colspan="2" align="center">

                        <input type="image" src="${pageContext.request.contextPath}/style/blue/images/button/submit.PNG" style="margin-right:15px;"/>

                        <a href="javascript:history.go(-1);"><img src="${pageContext.request.contextPath}/style/blue/images/button/goBack.png"/></a>

                    </td>

                </tr>

            </table>

        </div>

    </center>

</s:form>

</div>

……

在主题展示列表页面的底部,有快速回复的功能,所以得修改TopicAction对应的show.jsp:

<!--快速回复-->

    <div class="QuictReply">

    <s:form action="reply_add?topicId=%{#topic.id}">

        <div style="padding-left: 3px;">

            <table border="0" cellspacing="1" width="98%" cellpadding="5" class="TableStyle">

                <tr class="Tint" height="200">

                    <td valign="top" rowspan="2" class="Deep"><b>内容</b></td>

                    <td valign="top" class="no_color_bg">

                        <s:textarea name="content" cssStyle="width: 95%; height: 300px"></s:textarea>

                    </td>

                </tr>

                <tr height="30" class="Tint">

                    <td class="no_color_bg" colspan="2" align="center">

                        <input type="image" src="${pageContext.request.contextPath}/style/blue/images/button/submit.PNG" style="margin-right:15px;"/>

                    </td>

                </tr>

            </table>

        </div>

    </s:form>

    </div>

Struts.xml:

<!-- 论坛:主题相关 -->

    <action name="topic_*" class="topicAction" method="{1}">

        <result name="show">/WEB-INF/jsp/topicAction/show.jsp</result>

        <result name="addUI">/WEB-INF/jsp/topicAction/addUI.jsp</result>

        <result name="toShow" type="redirectAction">topic_show?id=${#topicId}</result>

    </action>

      

    <!-- 论坛:回复相关 -->

    <action name="reply_*" class="replyAction" method="{1}">

        <result name="addUI">/WEB-INF/jsp/replyAction/addUI.jsp</result>

        <result name="toTopicShow" type="redirectAction">topic_show?id=${topicId}</result>

    </action>

Tips: topic_show?id=${#topicId}

这两个模块,发帖和发表回复的请求发出时,页面跳转的过程是一样的:addUI.jspàaction中的add()àshow.jsp

最后跳转到show.jsp时,都需要topic的id值.

当发表新主题时,从addUI.jsp开始,就一直没有将topic的id值传递过来(传递的是forumId),所以才在TopicAction中将topicId给put进map域中,所以取出时要加#;

而发表回复时,从addUI.jsp开始,就传递了topicId,所以直接取出来就好,不需要加#.

小技巧:eclipse有自动编译的功能,但有时候会失灵.因此某些时候,看着代码没错,但页面显示就是不对.这时可以在代码中空白位置加个空格再保存,目的是让eclipse再次自动编译,然后刷新页面就可以看到效果了.

四.在BBS中使用FCKeditor

在线编辑器:

    老版:FCKeditor(Html + Css + JavaScript + Servlet处理上传的文件)

    新版:CKeditor

就是用JS实现的一个网页版的html代码生成器,最终的结果是一段html代码。

原理是动态生成html代码。

使用步骤:

1.导入fckeditor.js文件à2.显示文本域à3.显示为FCKeditor

测试_20130706.html:

<html>

    <head>

        <meta http-equiv="content-type" content="text/html; charset=utf-8">

        

        <!-- 1,导入js文件 -->

        <script type="text/javascript" src="fckeditor.js"></script>

 

        

    </head>

    <body>

 

        <!-- 2,显示文本域 -->

        <form action="">

            <textarea name="content"> </textarea>

        

            <!-- 3,显示为FCKeditor -->

            <script type="text/javascript">

                var oFCKeditor = new FCKeditor( ‘content‘ ) ; // 参数就是提交表单时的参数名(name的值)

                

                // 必须要指定的属性。

                //用于指定fckeditor的核心文件的存放路径(editor文件夹所在的路径)。

                // 要求一定要以‘/‘结尾。

                oFCKeditor.BasePath    = "./";

 

                // 一些配置

                oFCKeditor.Height    = 300 ;

                oFCKeditor.Width    = 700 ;

                //oFCKeditor.Value    = ‘itcast‘ ;

                oFCKeditor.ToolbarSet = "bbs"; // 提定工具栏的功能项配置,默认是Default

                

                // oFCKeditor.Create() ; // 创建FCKeditor并在当前位置显示出来。

                oFCKeditor.ReplaceTextarea(); // 替换指定的textarea为FCKeditor

            </script>

 

            <br><input type="submit" value="提交">

        </form>

        <hr>

        <a href="#">return</a>

    </body>

</html>

效果如下:

技术分享图片

Tips:FCKeditor有自己默认的配置文件,要修改一些属性(比如功能选项,表情等)的话,通常都要采用这样的方式:自己建一个配置文件,如myconfig.js,在默认配置文件fckconfig.js中声明还要加载myconfig.js,然后再把想要修改的配置写到

myconfig.js中(不想改的不写),就好了.

原理:默认先加载默认配置文件,声明后还会加载自己写的配置文件,这时前面加载的配置会被后面加载的相同的配置所覆盖.

技术分享图片

在默认配置文件中声明还要加载自己写的配置文件:

技术分享图片

myonfig.js:

 

// 1. 自定义 ToolbarSet

FCKConfig.ToolbarSets["simple"] = [

    [‘Bold‘,‘Italic‘,‘Underline‘],

    [‘Link‘,‘Unlink‘],

    [‘Image‘,‘Smiley‘,‘SpecialChar‘],

    [‘FontName‘],

    [‘FontSize‘],

    [‘TextColor‘,‘BGColor‘],

] ;

 

FCKConfig.ToolbarSets["bbs"] = [

    [‘NewPage‘,‘RemoveFormat‘],

    [‘Bold‘,‘Italic‘,‘Underline‘],

    [‘Subscript‘,‘Superscript‘],

    [‘JustifyLeft‘,‘JustifyCenter‘,‘JustifyRight‘],

    [‘Link‘,‘Unlink‘],

    [‘Image‘,‘Smiley‘,‘SpecialChar‘],

    [‘Table‘],

    [‘OrderedList‘,‘UnorderedList‘,‘-‘,‘Outdent‘,‘Indent‘],

    [‘FontName‘],

    [‘FontSize‘],

    [‘TextColor‘,‘BGColor‘],

    [‘FitWindow‘]

] ;

 

FCKConfig.ToolbarSets["admin"] = [

    [‘Source‘,‘DocProps‘,‘-‘,‘Save‘,‘NewPage‘,‘Preview‘,‘-‘,‘Templates‘],

    [‘Cut‘,‘Copy‘,‘Paste‘,‘PasteText‘,‘PasteWord‘,‘-‘,‘Print‘,‘SpellCheck‘],

    [‘Undo‘,‘Redo‘,‘-‘,‘Find‘,‘Replace‘,‘-‘,‘SelectAll‘,‘RemoveFormat‘],

    [‘Bold‘,‘Italic‘,‘Underline‘,‘StrikeThrough‘,‘-‘,‘Subscript‘,‘Superscript‘],

    [‘OrderedList‘,‘UnorderedList‘,‘-‘,‘Outdent‘,‘Indent‘,‘Blockquote‘,‘CreateDiv‘],

    [‘JustifyLeft‘,‘JustifyCenter‘,‘JustifyRight‘,‘JustifyFull‘],

    [‘Form‘,‘Checkbox‘,‘Radio‘,‘TextField‘,‘Textarea‘,‘Select‘,‘Button‘,‘ImageButton‘,‘HiddenField‘],

    [‘Link‘,‘Unlink‘,‘Anchor‘],

    [‘Image‘,‘Flash‘,‘Table‘,‘Rule‘,‘Smiley‘,‘SpecialChar‘,‘PageBreak‘],

    [‘Style‘,‘FontFormat‘,‘FontName‘,‘FontSize‘],

    [‘TextColor‘,‘BGColor‘],

    [‘FitWindow‘,‘ShowBlocks‘,‘-‘,‘About‘]        // No comma for the last row.

] ;

 

// 是否开启简单功能与高级功能显示

if(typeof(FCKConfig.EnableAdvanceTable) == "undefined"){ // 在页面中调用fckeditor时指定的 EnableAdvanceTable 的值会先被调用。

    FCKConfig.EnableAdvanceTable = false; // 默认为false

}

FCKConfig.AdvanceTableNum = 0;

FCKConfig.AdvanceTable = [1,3,7,8,9,12];

 

// 2. 添加中文字体与大小

FCKConfig.FontNames     =‘宋体;楷体_GB2312;黑体;隶书;Times New Roman;Arial‘ ;

FCKConfig.FontSizes =‘9/最小;12/较小;16/中等;20/较大;36/最大;54/更大;‘;

 

// 3. 修改 "回车" 和 "shift + 回车" 的样式

FCKConfig.EnterMode = ‘br‘ ;            // p | div | br

FCKConfig.ShiftEnterMode = ‘p‘ ;    // p | div | br

 

// 4. 更换表情图片

FCKConfig.SmileyPath    = FCKConfig.BasePath + ‘images/smiley/wangwang/‘ ; // 表情图片所在的文件夹

// 列出表情图片的文件名

FCKConfig.SmileyImages    = [‘0.gif‘,‘1.gif‘,‘2.gif‘,‘3.gif‘,‘4.gif‘,‘5.gif‘,‘6.gif‘,‘7.gif‘,‘8.gif‘,‘9.gif‘,‘10.gif‘,‘11.gif‘,‘12.gif‘,‘13.gif‘,‘14.gif‘,‘15.gif‘,‘16.gif‘,‘17.gif‘,‘18.gif‘,‘19.gif‘,‘20.gif‘,‘21.gif‘,‘22.gif‘,‘23.gif‘,‘24.gif‘,‘25.gif‘,‘26.gif‘,‘27.gif‘,‘28.gif‘,‘29.gif‘,‘30.gif‘,‘31.gif‘,‘32.gif‘,‘33.gif‘,‘34.gif‘,‘35.gif‘,‘36.gif‘,‘37.gif‘,‘38.gif‘,‘39.gif‘,‘40.gif‘,‘41.gif‘,‘42.gif‘,‘43.gif‘,‘44.gif‘,‘45.gif‘,‘46.gif‘,‘47.gif‘,‘48.gif‘,‘49.gif‘,‘50.gif‘,‘51.gif‘,‘52.gif‘,‘53.gif‘,‘54.gif‘,‘55.gif‘,‘56.gif‘,‘57.gif‘,‘58.gif‘,‘59.gif‘,‘60.gif‘,‘61.gif‘,‘62.gif‘,‘63.gif‘,‘64.gif‘,‘65.gif‘,‘66.gif‘,‘67.gif‘,‘68.gif‘,‘69.gif‘,‘70.gif‘,‘71.gif‘,‘72.gif‘,‘73.gif‘,‘74.gif‘,‘75.gif‘,‘76.gif‘,‘77.gif‘,‘78.gif‘,‘79.gif‘,‘80.gif‘,‘81.gif‘,‘82.gif‘,‘83.gif‘,‘84.gif‘,‘85.gif‘,‘86.gif‘,‘87.gif‘,‘88.gif‘,‘89.gif‘,‘90.gif‘,‘91.gif‘,‘92.gif‘,‘93.gif‘,‘94.gif‘,‘95.gif‘,‘96.gif‘,‘97.gif‘,‘98.gif‘,‘test.gif‘] ;

FCKConfig.SmileyColumns = 8 ;

FCKConfig.SmileyWindowWidth        = 668 ;

FCKConfig.SmileyWindowHeight    = 480 ;

 

// 5. 设置允许上传的图片类型的扩展名列表

FCKConfig.ImageUploadAllowedExtensions    = ".(jpg|gif|jpeg|png|bmp)$" ;        // empty for all

 

// 其它需要修改的配置 ...

FCKConfig.LinkDlgHideTarget        = true; // false ;

FCKConfig.LinkDlgHideAdvanced    = true; // false ;

 

FCKConfig.ImageDlgHideLink        = true; // false ;

FCKConfig.ImageDlgHideAdvanced    = true; // false

 

FCKConfig.LinkUpload = false;

这是老师写好的myconfig.js,可以用现成的,还想要修改字体,图片等的话可以在里面自行修改.

  • 实际操作: (也就两步,都是复制粘贴的工作)

将整个fckedit文件拷贝到WebContent根目录下:

技术分享图片

技术分享图片

然后打开topicAction对应的addUI.jsp(发帖页面) ,show.jsp(主题展示页面的底部有快速回复功能) 和replyAction对应的addUI.jsp(发表回复页面),在这三个页面的顶部加入下面这些代码:

<%-- 使用FCKeditor --%>

<script type="text/javascript"

    src="${pageContext.request.contextPath}/fckeditor/fckeditor.js"></script>

<script type="text/javascript">

    $(function() {

        var oFCKeditor = new FCKeditor(content); // 参数就是提交表单时的参数名

// 必须要指定的属性。用于指定fckeditor的核心文件的存放路径(editor文件夹所在的路径)。要求一定要以‘/‘结尾。

        oFCKeditor.BasePath = "${pageContext.request.contextPath}/fckeditor/";

        oFCKeditor.Width = "90%";//指定宽度

        oFCKeditor.ToolbarSet = "bbs"; // 提定工具栏的功能项配置,默认是Default

        oFCKeditor.ReplaceTextarea(); // 替换指定的textareaFCKeditor

    });

</script>

Tips:这三个页面的文本域的name值都为content;

这段代码本来是一定要出现在文本域之后的,不然会提示找不到name值为content的文本域.之所以能这么做,是因为加了$(function(){});表明等页面加载完成之后再执行这些代码.

在eclipse自带的浏览器中显示不出来--.

效果如下:

技术分享图片

五.导入演示数据(为实现和展示分页效果为准备)

他没给演示数据….自己手动添加,,,,,-------…


以上是关于Day07论坛2的主要内容,如果未能解决你的问题,请参考以下文章

7大子论坛回顾 | PGConf.Asia亚洲技术大会DAY2精彩继续

7大子论坛回顾 | PGConf.Asia亚洲技术大会DAY2精彩继续

7大子论坛回顾 | PGConf.Asia亚洲技术大会DAY2精彩继续

中韩印尼6大子论坛齐聚 | PGConf.Asia亚洲技术大会DAY3迎来收官

中韩印尼6大子论坛齐聚 | PGConf.Asia亚洲技术大会DAY3迎来收官

DAY1主论坛回顾 | PGConf.Asia2021亚洲技术大会盛大召开