SSH实战OA 11:BBS模块
《SSH实战OA》系列博客的系统管理、权限管理等内容后面再补上吧,先继续第三个模块:网上交流模块。网上交流主要做两个需求:论坛管理和论坛。
BBS的一些基本术语:
- 板块:也叫做“版面”、“讨论区”,用于对帖子进行分类
- 主题:也叫做“主贴”,表示一个新的话题,可以有很多回帖,属于某个板块。
- 回复:也叫做“回帖”、“跟帖”,属于某个主贴。
论坛模块的功能说明:
- 浏览
- 板块列表
- 显示单个板块(主题列表)
- 显示单个主题(主题+回帖列表)
- 参与
- 发新帖
- 回帖
- 管理文章
- 主题
- 设置类型
- 移动到其他板块
- 删除
- 修改
- 回复
- 主题
- 板块管理
- 增删改查
- 上下移动
板块管理
先来看看板块管理的需求,由上图可以看出,板块管理主要的需求有板块的新增、删除,修改,列表,上移,下移这几个需求。那么对应的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"><!--页面标题-->
<img src="${pageContext.request.contextPath }/style/images/title_arrow.gif" width="13" height="13" border="0"> 版块管理
</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 } </td>
<td>${description } </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"><img src="${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"><!--页面标题-->
<img src="${pageContext.request.contextPath }/style/images/title_arrow.gif" width="13" height="13" border="0"> 版块设置
</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);"><img src="${pageContext.request.contextPath }/style/images/goBack.png"></a>
</div>
</s:form>
</div>
<div class="Description">
说明:<br>
1,新添加的版块默认显示在最下面。<br>
</div>
</body></html>
SSH实战OA 11:BBS模块的更多相关文章
- Asp.Net Core 2.0 项目实战(11) 基于OnActionExecuting全局过滤器,页面操作权限过滤控制到按钮级
1.权限管理 权限管理的基本定义:百度百科. 基于<Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员.后台管理员同时登录>我们做过了登录认证, ...
- Python标准库笔记(11) — Operator模块
Operator--标准功能性操作符接口. 代码中使用迭代器时,有时必须要为一个简单表达式创建函数.有些情况这些函数可以用一个lambda函数实现,但是对于某些操作,根本没必要去写一个新的函数.因此o ...
- jQuery2.0应用开发:SSH框架整合jQuery2.0实战OA办公自己主动化(VSS、operamasks-UI框架)
我的qq是2059055336,对这个课程有兴趣的能够加我qq联系. 一.本课程是怎么样的一门课程(全面介绍) 1.1.课程的背景 jQuery 2.0 正式版公布.不在支持 IE 6/7/8 ...
- SSH实战 · 唯唯乐购项目(上)
前台需求分析 一:用户模块 注册 前台JS校验 使用AJAX完成对用户名(邮箱)的异步校验 后台Struts2校验 验证码 发送激活邮件 将用户信息存入到数据库 激活 点击激活邮件中的链接完成激活 根 ...
- angularJs项目实战!01:模块划分和目录组织
近日来我有幸主导了一个典型的web app开发.该项目从产品层次来说是个典型的CRUD应用,故而我毫不犹豫地采用了grunt + boilerplate + angularjs + bootstrap ...
- python实战第一天-paramiko模块并练习
操作系统 Ubuntu 15.10 IDE & editor JetBrains PyCharm 5.0.2 ipython3 Python版本 python-3.4.3 安装paramiko ...
- 每天记录一点:NetCore获得配置文件 appsettings.json vue-router页面传值及接收值 详解webpack + vue + node 打造单页面(入门篇) 30分钟手把手教你学webpack实战 vue.js+webpack模块管理及组件开发
每天记录一点:NetCore获得配置文件 appsettings.json 用NetCore做项目如果用EF ORM在网上有很多的配置连接字符串,读取以及使用方法 由于很多朋友用的其他ORM如S ...
- SSH实战 · 唯唯乐购项目(下)
后台模块 一:后台用户模块 引入后台管理页面 创建adminuser表: CREATE TABLE `adminuser` ( `uid` int(11) NOT NULL AUTO_INCREM ...
- SSH实战 · 唯唯乐购项目(中)
用户模块 三:一级分类的查询 创建一级分类表并导入基本数据 CREATE TABLE `category` ( `cid` int(11) NOT NULL AUTO_INCREMENT, ` ...
随机推荐
- Taffy Web开发,Python Flask实践详解
1. 前言 最近为Taffy自动化测试框架写了个页面,主要实现了用例管理.执行,测试报告查看管理.发送邮件及配置等功能. 2. 实现细节 页面使用Python Flask +Bootstrap开发,还 ...
- mysql数据库的安装及体系说明
第1章 MySQL介绍 1.1 数据的定义 数据是指对客观事件进行记录并可以鉴别的符号,是对客观事物的性质.状态以及相互关系等进行记载的物理符号或这些物理符号的组合,是可识别.抽象的符号 1.2 数据 ...
- Wes7 剪裁方法
1. 加载x64的 DS共享库,加载一个compatibility.xml模板 2. 导入硬件信息文件File—Import—Import PMQ 用TAP.exe工具创建.PMQ文件(.PMQ文件保 ...
- Python之编程基础(编程语言分类)
一.编程语言简介 编程语言主要从以下几个角度进行分类,编译型和解释型.静态语言和动态语言.强类型定义语言和弱类型定义语言. 1.编译型跟解释型 编译型,其实他和汇编语言是一样的,也是有一个负责翻译的程 ...
- 经验总结22--抓取HTML数据,HtmlAgilityPack(续)
假设获取的数据是HTML的话.我们就须要第三方工具有辅助获取我们须要的数据. 我选用了HtmlAgilityPack这么个工具. 首先肯定去网上下载一个,然后引用到项目中.下载地址:http://ht ...
- http get(swift and oc)
SynchonousRequest: let urlPath: String = "http://www.weather.com.cn/data/sk/101010100.html" ...
- Android之使用MediaMetadataRetriever类获取媒体信息
一.昨天.介绍了使用MediaMetadataRetriever类来获取视频第一帧:http://blog.csdn.net/u012561176/article/details/47858099,今 ...
- Linux禁用显示“缓冲调整”
Linux禁用显示"缓冲调整" youhaidong@youhaidong-ThinkPad-Edge-E545:~$ free -o total used free shared ...
- TCP服务端开发为例--web开发不同url请求走不同control方法
拿java的web开发为例子,相信有很多小伙伴是做j2EE开发的,htpp请求,json数据传输都是工作中经常用的,查询请求,添加请求,修改请求前端配个url,例如https://localhost/ ...
- linux 磁盘管理三部曲——(1)磁盘结构,认识分区
最近小编整理了磁盘管理的相关知识,发现还是挺多的,所有就分了三个部分来给大家分享一下: 1.磁盘结构,认识分区 2.管理分区,文件系统格式化 3.mount挂载,/etc/fstab配置文件 这篇就先 ...