SSH实战OA 11:BBS模块

《SSH实战OA》系列博客的系统管理、权限管理等内容后面再补上吧,先继续第三个模块:网上交流模块。网上交流主要做两个需求:论坛管理和论坛。

BBS的一些基本术语:

  1. 板块:也叫做“版面”、“讨论区”,用于对帖子进行分类
  2. 主题:也叫做“主贴”,表示一个新的话题,可以有很多回帖,属于某个板块。
  3. 回复:也叫做“回帖”、“跟帖”,属于某个主贴。

论坛模块的功能说明:

  1. 浏览
    • 板块列表
    • 显示单个板块(主题列表)
    • 显示单个主题(主题+回帖列表)
  2. 参与
    • 发新帖
    • 回帖
  3. 管理文章
    • 主题
      • 设置类型
      • 移动到其他板块
      • 删除
      • 修改
    • 回复
  4. 板块管理
    • 增删改查
    • 上下移动

板块管理

1.png

先来看看板块管理的需求,由上图可以看出,板块管理主要的需求有板块的新增、删除,修改,列表,上移,下移这几个需求。那么对应的Action方法如下:

@Controller
@Scope("prototype")
public class ForumManageAction extends BaseAction<Forum> {

    Log log = LogFactory.getLog(this.getClass());
    
    /**
     * @return 板块列表
     * @throws Exception
     */
    public String list() throws Exception {
        List<Forum> forumList = forumService.selectAll();
        ActionContext.getContext().put("forumList", forumList);

        return "list";
    }

    
    /**
     * @return 新增页面
     * @throws Exception
     */
    public String addUI() throws Exception {
        return "saveUI";
    }
    
    /**
     * @return 新增操作
     * @throws Exception
     */
    public String add() throws Exception {
        forumService.add(model);
        return "toList";
    }
    
    /**
     * @return 删除操作
     * @throws Exception
     */
    public String delete() throws Exception {
        forumService.delete(model.getId());
        return "toList";
    }
    
    /**
     * @return 修改页面
     * @throws Exception
     */
    public String editUI() throws Exception {
        Forum forum  = forumService.selectById(model.getId());
        ActionContext.getContext().put("forum", forum);
        
        return "saveUI";
    }
    
    /**
     * @return 修改
     * @throws Exception
     */
    public String edit() throws Exception {
        Forum forum = forumService.selectById(model.getId());
        if(forum != null) {
            forum.setDescription(model.getDescription());
            forum.setName(model.getName());
            forumService.update(forum);
        }
        
        return "toList";
    }
    
    /**
     * @return 上移
     * @throws Exception
     */
    public String moveUp() throws Exception {
        forumService.moveUp(model.getId());
        return "toList";
    }
    
    /**
     * @return 下移
     * @throws Exception
     */
    public String moveDown() throws Exception {
        forumService.moveDown(model.getId());
        return "toList";
    }
}

论坛板块ForumAction需要继承基本Action抽象类BaseAction。

public abstract class BaseAction<T> extends ActionSupport implements ModelDriven<T>{

    protected T model;
    
    @Autowired
    protected DepartmentService departmentService;
    
    @Autowired
    protected RoleService roleService;
    
    @Autowired
    protected UserService userService;
    
    @Autowired
    protected PrivilegeService privilegeService;
    
    @Autowired
    protected ForumService forumService;
    
    public BaseAction() {
        try {
            // 通过反射获取model的真实类型
            ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
            Class<T> clazz = (Class<T>) pt.getActualTypeArguments()[0];
            // 通过反射创建model的实例
            model = clazz.newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    @Override
    public T getModel() {
        return model;
    }
}

在暂未考虑与其他实体关联的提前下,我们的model类可以这样设计:

/**
 * @date 2017/05/06
 * @author shizongger
 * 论坛板块
 */
public class Forum {

    private Long id; //主键id
    
    private String name; //板块名称
    
    private String description; //板块描述
    
    private int position;  //板块所在位置

    //getter/settter
}

前几篇文章提到映射的pojo的主键属性id都默认为Long型,forum属性自己的属性有name,description,position。name用来记录板块名称,description是对本板块的描述,而position是记录板块的排序位置,方面上下移动的操作。

Forum.hbm.xml文件如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.shizongger.oa.domain">

    <class name="Forum" table="itcast_forum">
        <id name="id">
            <generator class="native" />
        </id>
        <property name="name" />
        <property name="description" />
        <property name="position" />

    </class>
</hibernate-mapping>

String类型的映射都用Hibernate默认的配置。别忘了在Hibernate的配置文件hiberante.cfg.xml添加本文件的位置。
<mapping resource="com/shizongger/oa/domain/Forum.hbm.xml" />

由于目前我采用的是两层架构,合并和Serivce层和Dao层,所以我把Dao层对数据库基本增删改查都抽象到DaoSupport抽象类里。这是一个泛型参数的抽象类,具体传递进来的model类型属于什么类型是在构造方法中通过java反射机制得到的。

/**
 * @author shizongger
 * @param <T> 实际操作的daomain实体
 */
@Transactional
@SuppressWarnings("unchecked")
public abstract class DaoSupportImpl<T> implements DaoSupport<T> {

    private Log log = LogFactory.getLog(this.getClass());   

    /**
     * sessionFactory工厂
     */
    @Autowired
    private SessionFactory sessionFactory;
    
    private Class<T> clazz;

    @SuppressWarnings("unchecked")
    public DaoSupportImpl() {
        // 使用反射技术得到T的真实类型
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); // 获取当前new的对象的 泛型的父类 类型
        this.clazz = (Class<T>) pt.getActualTypeArguments()[0]; // 获取第一个类型参数的真实类型
    }
    
    /**
     * 增加
     */
    @Override
    public void add(T entity) {
        log.info("add:" + entity.toString());
        getSession().save(entity);
    }

    /**
     * 删除
     */
    @Override
    public void delete(Long id) {
        Object object = selectById(id);
        if(object != null) {
            getSession().delete(object);
        }
    }

    /**
     * 修改
     */
    @Override
    public void update(T entity) {
        getSession().update(entity);
    }

    /**
     * 根据id查询
     */
    @Override
    public T selectById(Long id) {
        return (T) getSession().get(this.clazz, id);
    }
    
    /**
     * 根据id数组查找对象集合
     * @param ids id的列表
     * @return
     */
    @Override
    public List<T> getByIds(Long[] ids) {
        if (ids == null || ids.length == 0) {
            return Collections.EMPTY_LIST;
        } else {
            return getSession().createQuery(//
                    "FROM " + clazz.getSimpleName() + " WHERE id IN (:ids)")//
                    .setParameterList("ids", ids)//
                    .list();
        }
    }
    
    /**
     * 根据id数组查询
     */
    @Override
    public List<T> selectAll() {
        List<T> list = getSession().createQuery("FROM " + this.clazz.getSimpleName()).list();

        return list;
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }
}

论坛管理的Service实现类代码如下:

@Service
@Transactional
@SuppressWarnings("unchecked")
public class ForumServiceImpl extends DaoSupportImpl<Forum> implements ForumService {

    Log log = LogFactory.getLog(this.getClass());
    
    @Override
    public void add(Forum forum) {
        super.add(forum);
        forum.setPosition(forum.getId().intValue());
    }

    @Override
    public List<Forum> selectAll() {
        return getSession()
                .createQuery("FROM Forum f ORDER BY f.position")
                .list();
    }

    /**
     * 上移当前板块forum的位置position值
     */
    @Override
    public void moveUp(Long id) {
        //获取当前板块
        Forum forum = selectById(id);
        //上一个forum
        Forum prexForum = (Forum)getSession()
                            .createQuery("FROM Forum f WHERE f.position < ? ORDER BY f.position DESC")
                            .setParameter(0, forum.getPosition())
                            .setFirstResult(0)
                            .setMaxResults(1)
                            .uniqueResult();
        //最上面的不能再往上移动
        if(prexForum == null) {
            return;
        }
        
        //交换当前和上一个的position
        int position = forum.getPosition();
        forum.setPosition(prexForum.getPosition());
        prexForum.setPosition(position);
        
        //更新两个对象到数据库中
        getSession().save(forum);
        getSession().save(prexForum);
    }

    /**
     * 向下移动当前板块
     */
    @Override
    public void moveDown(Long id) {
        //获取当前板块
        Forum forum = selectById(id);
        
        //下一个forum
        Forum nextForum = (Forum)getSession()
                            .createQuery("FROM Forum f WHERE f.position > ? ORDER BY f.position ASC")
                            .setParameter(0, forum.getPosition())
                            .setFirstResult(0)
                            .setMaxResults(1)
                            .uniqueResult();    
        
        //最下面的不能再往下移
        if(nextForum == null) {
            return;
        }
        
        //交换当前forum和下一个forum的position
        int position = nextForum.getPosition();
        nextForum.setPosition(forum.getPosition());
        forum.setPosition(position);
        
        //更新两个对象到数据库中去
        getSession().save(nextForum);
        getSession().save(forum);
    }
}

增删改查功能只需要把model为Forum传递进去调用DaoSupport就行了,上移和下移的思路是jsp传递forum进来,先从数据库获得一个forum对象。如果是上移,则获取数据库中position所有小于本forum.position的那个最大的值。因为只要不是最上面的板块,小于自己position的板块可能有多个,而我们只需要最大的那个,也就是仅仅挨着自己的那个板块。然后交换两者的position值。

前端列表list.jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
    <title>版块列表</title>
    <%@ include file="/WEB-INF/jsp/public/commons.jspf" %>    
    <script type="text/javascript">
    </script>
    <style type="text/css">
        .disabled{
            color: gray;
            cursor: pointer;
        }    
    </style>
</head>
<body>

<div id="Title_bar">
    <div id="Title_bar_Head">
        <div id="Title_Head"></div>
        <div id="Title"><!--页面标题-->
            ![](${pageContext.request.contextPath }/style/images/title_arrow.gif) 版块管理
        </div>
        <div id="Title_End"></div>
    </div>
</div>

<div id="MainArea">
    <table class="TableStyle" cellspacing="0" cellpadding="0">
       
        <!-- 表头-->
        <thead>
            <tr id="TableTitle" valign="MIDDLE" align="CENTER">
                <td width="250px">版块名称</td>
                <td width="300px">版块说明</td>
                <td>相关操作</td>
            </tr>
        </thead>

        <!--显示数据列表-->
        <tbody id="TableData" class="dataContainer" datakey="forumList">
        
        <!-- 遍历forumList -->
        <s:iterator value="#forumList" status="status">
            <tr class="TableDetail1 demodata_record">
                <td>${name }&nbsp;</td>
                <td>${description }&nbsp;</td>
                <td>
                    <s:a action="forumManage_delete?id=%{id}" onclick="return delConfirm()">删除</s:a>
                    <s:a action="forumManage_editUI?id=%{id }">修改</s:a>
                    <!-- 最上面不能往上移 -->
                    <s:if test="#status.first">
                        <span class="disabled">上移</span>
                    </s:if>
                    <s:else>
                        <s:a action="forumManage_moveUp?id=%{id }">上移</s:a>
                    </s:else>
                    <!-- 最下面的不能再往下移动 -->
                    <s:if test="#status.last">
                        <span class="disabled">下移</span>
                    </s:if>
                    <s:else>
                        <s:a action="forumManage_moveDown?id=%{id }">下移</s:a>
                    </s:else>
                </td>
            </tr>
        </s:iterator>
        </tbody>
    </table>
    
    <!-- 其他功能超链接 -->
    <div id="TableTail">
        <div id="TableTail_inside">
            <a href="forumManage_addUI.action">![](${pageContext.request.contextPath }/style/images/createNew.png)</a>
        </div>
    </div>
</div>

<div class="Description">
    说明:<br>
    1,显示的列表按其sortOrder值升序排列。<br>
    2,可以通过上移与下移功能调整顺序。最上面的不能上移,最下面的不能下移。<br>
</div>



</body></html>

新增和修改的页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
    <title>版块设置</title>
    <%@ include file="/WEB-INF/jsp/public/commons.jspf" %>
    <script type="text/javascript">
    </script>
</head>
<body>

<!-- 标题显示 -->
<div id="Title_bar">
    <div id="Title_bar_Head">
        <div id="Title_Head"></div>
        <div id="Title"><!--页面标题-->
            ![](${pageContext.request.contextPath }/style/images/title_arrow.gif) 版块设置
        </div>
        <div id="Title_End"></div>
    </div>
</div>

<!--显示表单内容-->
<div id="MainArea">
    <s:form action="forumManage_%{id == null ? 'add' : 'edit'}">
        <!-- 隐藏表单内容 -->
        <s:hidden name="id" value="%{#request.forum.id}"></s:hidden>
        
        <div class="ItemBlock_Title1"><!-- 信息说明<DIV CLASS="ItemBlock_Title1">
            <IMG BORDER="0" WIDTH="4" HEIGHT="7" SRC="${pageContext.request.contextPath }/style/blue/images/item_point.gif" /> 版块信息 </DIV>  -->
        </div>
        
        <!-- 表单内容显示 -->
        <div class="ItemBlockBorder">
            <div class="ItemBlock">
                <table class="mainForm" cellspacing="0" cellpadding="0">
                    <tbody>
                        <tr>
                            <td width="100">版块名称</td>
                            <td><s:textfield name="name" cssClass="InputStyle" value="%{#request.forum.name}" > *</s:textfield></td>
                        </tr>
                        <tr>
                            <td>版块说明</td>
                            <td><s:textarea name="description" cssClass="TextareaStyle" value="%{#request.forum.description}"></s:textarea></td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
        
        <!-- 表单操作 -->
        <div id="InputDetailBar">
            <input src="${pageContext.request.contextPath }/style/images/save.png" type="image">
            <a href="javascript:history.go(-1);">![](${pageContext.request.contextPath }/style/images/goBack.png)</a>
        </div>
    </s:form>
</div>

<div class="Description">
    说明:<br>
    1,新添加的版块默认显示在最下面。<br>
</div>



</body></html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容