接上篇的新闻发布系统设计思路(域模型)之后,我把相关dao的设计和逻辑层的相关设计思路发上来,请大家一起看看还有什么需要改进的地方.
dao作为域模型的一部分,被与单独的domain分开成单独的数据访问对象,并分别对应域模型的四个数据模型对象.分别为articleDao,categoryDao,articleTopTypeDao,和userDao.其中articleDao和categoryDao为主要的dao,其他的还等待扩展或者只是一个简单的占位点.
#-------------------------------------
articleDao(文章数据访问对象)
- public interface IArticleDAO {
- /** 通过一个主键得到一篇文章
- * @param s 文章主键
- **/
- public Article get(Serializable s);
- /** 通过主键来删除一篇文章,传递整个文章对象
- *@param s 整个文章对象,此对象至少含有主键id值
- */
- public void delete(Article s);
- /** 更新这个文章
- * @param article 需要更新的文章对象,此对象是在原有的文章对象基础之上改变相应值再更新其.
- * 必须保证此对象是持久化的,如果未持久化,则作相应的插入操作.
- */
- public void update(Article article);
- /** 保存这个对象
- * @param article 要保存的文章对象,此对象要求是未持久化的,即id值是未被赋值的,反之如果数据
- * 库中有此对象,则作相应的更新操作.
- */
- public void save(Article article);
- /**
- * 通过文章路径信息和其页面数值来得到一个唯一的article对象
- */
- public Article getArticleByPathMarkAndPageCurrentIndex(String pathMark, int pageCurrentIndex);
- /**
- * 通过文章路径信息得到一篇文章的页面列表,因为文章可能有多页.
- */
- public List<Article> getArticleListByPathMark(String pathMark);
- /**
- * 通过一个动态查询条件查询所有的文章对象
- */
- public List<Article> getArticleListByCriteria(DetachedCriteria criteria);
- /**
- * 通过一个动态查询条件和个分页对象相关的文章对象,此次查询只查询相关分页内的文章对象
- */
- public List<Article> getArticleListByCriteria(DetachedCriteria criteria, Page page);
- }
此接口中都是一些常用的操作,包括文章的查询和上下页的翻页等操作.其中getArticleListByPathMark(String pathMark)操作为得到某一篇文章的所有单页文章,因为如果对某一篇文章进行相应更改(如文章页数的改变等),需要对这一篇文章进行相关数据项的删除与添加.而其它操作,如动态查询,目录下文章查询等操作,都委托给getArticleListByCriteria(criteria)和getArticleListByCriteria(cirteria,page)来完成因为一个查询的条件多,如考虑删除条件,目录条件,置顶条件等.
#--------------------
categoryDao(目录数据访问对象)
- public interface ICategoryDAO {
- /** 通过主键来得到类别对象 **/
- public Category get(Serializable s);
- /** 删除类别对象 **/
- public void delete(Category s);
- /** 更新类别对象 **/
- public void update(Category category);
- /** 保存类别对象 **/
- public void save(Category category);
- /** 得到一个类别的下级类别列表 **/
- public List<Category> getCategoryListBySuperCategory(Category category);
- /** 判断一个类别是否和其同级别类别有重复的名字 **/
- public boolean hasCategory(Category category);
- }
目录操作相对简单些,除了基本操作,增加getCategoryListBySuperCategory(category)操作,由一目录来得到它的子目录(此处category我只传递了category的主键信息,当然在openSessionInView环境中,可由category.getCategoryList()方法来直接得到子目录,不要这要多发送一条上级目录的查询操作).hasCategory(category)方法,用来处理目录的同名问题,在同一目录下,不允许两个同名的目录存在(当然跨目录是可以的).
其它dao都很简单,就不要再细说了.四个数据访问对象都只对基本的数据操作作了定义,相对来说,更说的操作放在逻辑层(servie)来作.service处理的事也不多,也是把相应操作委托给dao来操作,加上一些自己的逻辑操作.相关接口定义如下(整个系统我只设计了一个servie,此service将所有dao操作聚合在一起)
- public interface IService {
- /** 保存一页文章,而不是一篇,因为一篇文章可能有多页 **/
- public void saveArticle(Article article);
- /** 得到一页文章,此方法通过主键来得到一篇文章中的其中一页 **/
- public Article getArticle(Serializable s);
- /** 通过文章的路径标记和当前页面的页面下标数(第几页)来得到实际的页面文章对象 **/
- public Article getArticleByPathMarkAndPageCurrentIndex(String pathMark, int pageCurrentIndex);
- /** 通过文章路径来得到一篇文章,一篇文章可能有多页,故返回一个文章列表 **/
- public List<Article> getArticleListByArticlePathMark(String pathMark);
- /** 更新一篇文章中的一页文章 **/
- public void updateArticle(Article article);
- /** 为一篇文章添加或者删除置顶标记,一篇文章并不是指一页文章,而是指包含几个页面的一篇文章 **/
- public void updateArticleByArticleTopType(Article article, ArticleTopType articleTopType);
- /** 为一篇文章添加或者删除审核标记 **/
- public void updateArticleByAudit(Article article, boolean auditFlag);
- /** 为一个列表文章添加或者删除置顶标记 **/
- public void updateArticleListByTop(List<Article> articleList, ArticleTopType articleTopType);
- /** 为一个列表文章添加或者删除审核标记 **/
- public void updateArticleListByAudit(List<Article> articleList, boolean auditFlag);
- /** 删除一篇文章,在实际操作中,这个方法并不使用,因为实际没有从数据库中删除记录的操作 **/
- public void deleteArticle(Article article);
- /** 第一次删除一篇文章,此操作为文章作删除标记 **/
- public void deleteFirstArticle(Article article);
- /** 最终删除一篇文章,此操作将使文章最终不可被检索,仅存在于数据库中作为备份 **/
- public void deleteShiftArticle(Article article);
- /** 保存一个类别 **/
- public void saveCategory(Category category);
- /** 取得一个类别 **/
- public Category getCategory(Serializable s);
- /** 更新类别 **/
- public void updateCategory(Category category);
- /** 删除一个类别 **/
- public void deleteCategory(Category category);
- /** 保存一个文章置顶对象,并返回这个对象的id值 **/
- public Serializable saveArticleTopType(ArticleTopType articleTopType);
- /** 根据动态查询条件和分页组件,查询相关的文章列表 **/
- public List<Article> queryArticleListByCriteria(DetachedCriteria criterion, Page page);
- /** 查询现在时间段内有次的文章置顶对象 **/
- public List<ArticleTopType> getArticleTopTypeListNowValid();
- /** 根据动态查询条件,查询相关的文章列表,查询满足条件的所有对象 **/
- public List<Article> queryArticleListByCriteria(DetachedCriteria criteria);
- /** 恢复一篇文章,这是由于先前的删除文章所作操作的逆向操作 **/
- public void updateArticleByRecover(Article article);
- /** 取得一个用户 **/
- public User getUser(Serializable s);
- /** 判断是否有一个重复的类别 **/
- public boolean hasCategory(Category category);
- /** 通过上级类别来得到其下级类别列表 **/
- public List<Category> getCategoryListBySuperCategory(Category category);
- /** 改变文章的类别 **/
- public void updateArticleByCategory(Article article, Category category);
- /** 改变一个列表文章的类别,这些文章都是同一个类别 **/
- public void updateArticleListByCategory(List<Article> articleList, Category category);
- }
service将各种操作以更形象的方式提供给action层,并在其中封装数据对象的操作过程,避免action与dao的直接交互.
在service和dao中都出现了一个page对象,这个对象用于页面分页使用.将分页操作放在特定的对象中.分页操作主要涉及到三个方面,每页文章数,当前页数,以及总文章数,其他都可以这三个参数来得到.相应分页对象代码如下:
- public class Page {
- public Page() {
- }
- /** 当前页数,默认为第一页 **/
- private int currentPage = 1;
- /** 每页显示的记录数 默认为 20条记录 **/
- private int pageSize = 20;
- /** 总记录数 **/
- private int totalCount;
- public int getCurrentPage() {
- return currentPage;
- }
- public void setCurrentPage(int currentPage) {
- if(currentPage <= 0)
- return;
- this.currentPage = currentPage;
- }
- public int getPageSize() {
- return pageSize;
- }
- public void setPageSize(int pageSize) {
- if(pageSize <= 0)
- return;
- this.pageSize = pageSize;
- }
- public int getTotalCount() {
- return totalCount;
- }
- public void setTotalCount(int totalCount) {
- this.totalCount = totalCount;
- }
- /** 得到起始记录,此记录是当前显示数据的第一条记录的前一条记录,即前一页记录页的最后一条记录
- * 因为setCurrentPage方法的存在,使得不可能出现计算得出起始记录为负数的情况,此结果返回的
- * 最小起始记录为 0
- */
- public int getStartIndex() {
- return (this.currentPage - 1) * this.pageSize;
- }
- /** 得到总的记录页面数,此结果页每页显示的记录数与总记录数之间的关系计算得出 **/
- public int getTotalPage() {
- int i = this.totalCount / this.pageSize;
- int j = this.totalCount % this.pageSize;
- return i + (j == 0 ? 0 : 1);
- }
- /** 是否有上一页 **/
- public boolean hasPreviousPage() {
- return this.currentPage > 1;
- }
- /** 是否有下一页 **/
- public boolean hasNexPage() {
- return this.currentPage < this.getTotalCount();
- }
- }
相应操作都是很简单,我也是简单地进行了些操作.由于需求的简单, 使得相应的代码都不是太长,当然逻辑操作也不是太多.在很多的小型系统的开发场合,常常把service这层去掉,而直接以dao层跟action的直接交互.这也未必不是一种方式.(这里我也有想把service层去掉,因为工作确实不多).
dao层代码和service代码放在附件中,请有意思地交流一下.看有什么可以补充的.