网站内容管理系统

  作者:板桥banq

<<Java实用系统开发指南>>

需求分析

某公司是一家处于快速发展中的中小型销售公司,他们打算架构一个网站。计划分两步走:首先做一个宣传型的网站,然后在公司规模达到一定程度时扩展为网上商店。
在第一步计划中,某公司的主要想法是通过网站能及时介绍公司的产品、服务以及其他公司相关情况;由于不断有新品上架,他们希望能通过公司市场销售人员直接来修改页面,将新的信息直接发布在网站上;同时他们也希望页面美工风格能定期地改进和更换。
某公司这样的需求其实代表了大多数公司进军电子商务的意图,因此这个案例有一定的普遍性。
分析这样的需求,他们需要的实际是一套能通过Web修改页面的网站内容管理系统。这套系统将来能挂接网上商店系统,因此在选择技术架构和系统设计上必须充分注意可拓展性。该系统的模式如图4-1所示。
1
图4-1  用例
本项目主要是网站管理者要求能够创建页面、修改页面和删除页面。仔细分析需求,网页页面其实分两个元素:网页内容和网页外观,后者也可以称为网页模板。网页模板并不是每次修改页面时都需要变更。
因此,需要把内容和显示模板完全分离,本网站内容管理系统实际分两大部分:数据内容和显示模板。在用户获得页面时,系统自动将这两部分融合在一起输出到浏览器。
一个页面可以划分为几个固定区域,如图4-2所示。
1
图4-2  页面划分区域

  • 标题栏(Header)用来放置页面头部的信息。如标题、公司名称,以及公司的LOGO或商标图片等。
  • 页尾栏(Footer)放置公司的详细地址、版权声明或其他相关信息。
  • 菜单栏(Navlink)是放置菜单的区域。菜单是页面的重要组成部分,菜单的集合定义为导航条(Navlink)。在图4-2中,菜单栏是位于页面的左边,也有可能位于页面的右边,当然,还有可能与标题栏和页尾栏在一起。这就要求在架构设计时考虑到这种灵活性,使得系统具备可扩展性。
  • 内容栏(Body)是整个网站的内容部分,这个内容有可能是以下几种类型:
    • 纯文字型: 这最容易处理,使用HTML就可以排列出一定的格式。
    • 文字和图片型:需要考虑文字和图片的排列方式,图片位于文字上方还是文字下方等。
    • 功能型:本内容有可能是系列新闻、论坛或电子购物产品列表等,这样的页面都不是静态HTML能直接处理的,需要和数据库连接,属于动态页面,功能型内容可以由专门软件去完成。

在本项目中,可以只完成文字相关的内容编辑和修改功能。在扩展性方面,需要考虑允许功能型内容的动态插入。
在进行了以上用例需求分析后,就可以依此进行架构设计和系统详细设计。

架构技术设计

根据前面的需求分析,以一个中型系统的架构来设计本项目。在设计本例架构时,应充分考虑其扩展性和通用性。
在框架技术选择上,预备完全在J2EE的Web框架里实现。这样可以充分了解熟悉J2EE的Web技术,同时又因为Web技术相对后端EJB层来说是比较成熟的,发展变化不是非常大。
因此,本例的架构可以说是一个J2EE的Web实现的标准架构,可以将它应用到更多的中小型项目中。


2.1  架构分层图

Web技术的通用框架图已经在前面的用户注册系统章节描述过。实际上,很多重要逻辑功能和核心是采用Javabeans来实现的。那么在这些Javabeans中,也不是混乱纠缠一团的,也需要有清晰的层次和功能划分。
在这样一个系统中,整个操作流程其实涉及了很多环节。如用户通过页面输入数据,页面的美化和布局等;系统接受数据后,要结合原有的数据进行一定的逻辑运算,这部分根据系统要求的复杂性不同;数据处理后要保存以备下次再用,关于数据如何在持久化介质上存储和管理也存在相当的工作。
由此可见,如果将上述这些功能都混合在一起,必然导致以后修改维护上的困难。因此将这些功能进行归类设计,划分在不同的层次来实现,在系统伸缩性、耦合性以及重用性方面有诸多好处。
分层后的设计图如图4-3所示。
1
图4-3  系统架构层次图


表现层实际是JSP部分,包括一些为JSP服务的Javabeans,因为在本例中,要完全做到JSP无Java代码,必然要引入一些Javabeans为之服务。
要实现这样的目的,有很多现成的框架技术可以选择,比如JSTL(JSP Standard Tag Libraries),JSP标签库是在JSP中使用XML格式的一些特定标签来实现动态功能的。
在本例中,将采取一种Web层框架软件Strutss,这是Apache上的一个著名的开放源代码项目,在Java世界中有很多优秀的开源项目有助于启迪设计思想、提高开发速度。
用户的数据经过表现层的简单封装处理后,将被传送到第2层的逻辑处理层,由逻辑处理层根据业务逻辑来决定如何进一步操作,在这个操作中,有可能要先读取一下其他数据。那么可以通过Cache层从内存先读取,如果Cache中没有,则直接从数据库读取。
其实,Cache层不仅可以对数据库的数据实现缓冲,在性能要求比较高时,对逻辑处理中的Javabeans也可实现缓冲。
数据层主要是实现数据持久化。自从XML技术出现以后,数据持久化多了一个非常好的选择,那就是XML格式的文件。同数据库相比,XML文件对周围环境的要求相对比较低,不需要专门的数据库服务器,非常适合小型项目的成本要求。
在本例中,也使用XML文件来实现数据的持久化。
多层架构的优点主要体现为:
良好的解耦性: 各个功能层只负责自己相应的事务,不再相互混淆在一起。每个功能层如果在将来有所变化时,不会涉及到其他功能层,因为每个功能层是相对独立的。
高度的重用性: 各个层的技术都可以移植到其他应用系统。比如表现层的框架一旦确定,可以在第二个项目中同样使用这样的技术,同时还可以提高开发速度。
灵活的扩展性: 由于表现层和核心功能分开,可以将系统从PC应用拓展到无线等应用中,所作的修改只是表现层的更改,系统核心功能无需变化。

2.2  MVC模式与Struts

表现层涉及很多用户界面的元素,因此比较难以实现重用。但是,有一个宗旨是:不能将功能性的代码与显示性的代码混合在一起,否则,当需要更改页面或者扩展新功能时会带来很大的修改量,甚至破坏原有系统的稳定性。
因此,需要对表现层进行细化,可以将表现层分3个部分:
视图(View)负责显示功能。
控制器(Controller)根据Model处理结果,调节控制视图View的输出。
业务对象模型(Business Object Model)是对真实世界实体的抽象,可以是一些数据,也可以是一些处理对象或事件对象。在本项目中,业务对象就是那些包含状态和行为的Javabeans,如图4-4所示。
1
图4-4  MVC模式的流程图
图4-4是一个MVC模式的流程图。从图中可以发现一个表现层清晰的解决方案。
在MVC中,JSP实际只负责显示功能,显示功能的实现要依据客户端来确定。如果客户端是IE浏览器,那么JSP里封装的就是HTML语言;如果客户端是手机,那么JSP里封装的就是WAP语言;如果客户端是其他支持XML的客户端,那么JSP里封装的就是XML。这些客户端不同,变化的只是重新设计一套JSP,而系统的核心功能则无需任何变化,这种灵活强大的拓展性体现了MVC的魅力所在。
Servlet是控制JSP页面输出的。Servlet就像汽车调度员,可以在JSP页面非常多的情况下,实现有效清晰的流程调度管理。
使用MVC模式主要有如下好处:
良好的重用性:MVC可以使用多种类型的视图界面,而核心功能无需变化。比如视图界面可以从Web浏览器(HTTP)拓展到无线浏览器(WAP)。
极低的成本:MVC模式可以让一般水平的程序员来开发和维护用户的界面功能,降低了人员成本。
快速开发:由于将Java代码从JSP中去除,Java程序员和HTML 或者JSP程序员可以同时工作。而如果不采用MVC分离的模式,那么只有等Java程序员完成核心功能后,再交由美工和JSP程序员进一步加工。
可靠性:由于显示功能和处理功能分离,这就允许在不重新编译核心功能的情况下修改系统的视图界面和外观。
有一种观点认为只有大项目才需要采取MVC。实际上,很多时候无法确定项目的规模。因为客户的需求始终不断在变化,如果原有的基础架构不具有很强的拓展性,那么项目进行到中途时可能要再进行重新设计,很容易陷入左右为难的地步。所以,无论任何项目,用标准的架构去设计它,就如按标准的方法去做事一样,相当于成功了一半。
具体实现MVC模式的软件框架有很多,其中应用最广泛的有下列3种:
Apache Struts(http://jakarta.apache.org/Strutss/) Struts是基于JSP的框架软件,有大量文章和参考资料面世,其中《Strutss in Action》一书非常值得一读。
Apache Cocoon (http://xml.apache.org/) Cocoon是基于XML和XSLT技术的MVC模式实现框架,在Cocoon中很巧妙地利用XML技术实现了内容和模板分离的功能。
Petstore WAF(Web Application Framework)  Petstore是SUN公司推出的一个J2EE实例样本,WAF是其Web实现框架,其原理类似Struts。
由于Struts有大量实践应用,已经成为目前事实上的Web实现标准,而Cocoon是未来的一个发展趋势。本例中,使用Struts框架来构架本项目的Web层是一种实用而且理想的选择,当然也会引入更多XML技术,以能够向未来过渡。
本例另外一个关键问题是如何解决模板和内容分离。而这在Struts中,正好有Tile组件可以解决这个问题。Tile的总体思路是将页面划分成几块“碎片”,然后分别实现之。下面逐个介绍。
Struts框架是结合JSP、JSP 标签库以及Servlets的MVC模式实现。这里将简单介绍Struts的使用,进一步学习请参考相应书籍。图4-5是Struts实现MVC的流程图。
MVC模式的实现核心是控制器(Controller)部分,ActionServlet是Struts的控制器的核心,它将根据来自用户的请求,调用在Strutss-config.xml中配置好的ActionMapping,从其中寻找到相应Action具体实现类。具体实现类所要做的就是要继承实现Action类中的Execute方法(已经不推荐使用perform()方法)。
1
图4-5  Struts的流程图
在Action类的Execute方法中,要实现两个功能:
将用户输入的数据传递到后台处理,Struts已经把用户输入的数据封装在ActionForm类中,只要从其中读取数据,形成新的数据对象,递交给逻辑处理层来处理。
在后台处理完成后,需要根据使用Struts提供的ActionMapping来指定输出的视图(View)。
Struts的原理比较复杂,初学者若要迅速上手,则应该首先学会如何使用Struts,这样通过不断深入使用,会逐渐了解其原理和运行机制。
Tile是有关视图界面的组件。Tile主要是将一个页面划分成几个部分,分别对应不同的JSP,大大提高了视图界面元素的可重用性。
使用Tile有很多优点。例如在很多项目中,页面的头部和尾部都是固定的。一般会采取下面的做法:
<html>
<body>
<%-- include header --%>
<jsp:include page="/header.jsp" />
这里是Body 内容部分:
<p>
<%-- include footer --%>
<jsp:include page="/footer.jsp" />
</body>
</html>
使用include的主要问题是:
如果要修改的不只是头部和尾部,而是整个页面的布局,那么就必须逐个进行页面的修改。
大量include嵌套使用,这类似面向过程语言中的GoTO语句,会使维护扩展变得非常困难,但是因为编写简单直接,不少程序员还是可能喜欢这样做。在一个项目中开这种先河,将出现大量层层重叠的include语句,严重破坏了页面的可扩展性和可维护性,使得页面修改扩展成为整个系统的恶梦。
调试不方便。include分动态静态两种用法,静态用法调试很不方便,因为即使被include的JSP页面在一些容器中,主页面如果不修改,容器将不会重新载入新的使用“include”语句调用的子页面,除非调用者页面和被调用者页面均被修改。
如果使用Tiles来改造上面的问题,将会有一个很巧妙干净的解决方式:
<%@ taglib uri="/WEB-INF/tiles.tld" prefix="tiles" %>
<html>
<body>
<%-- include header --%>
<tiles:insert page="/header.jsp" flush="true"/>
这里是Body 内容部分:
<p>
<%-- include footer --%>
<tiles:insert page="/footer.jsp" flush="true"/>
</body>
使用tiles:insert代替了include。更深入一点,可以修改成这样:
<tiles:insert page="/layout.jsp" flush="true">
    <tiles:put name="header" value="/header.jsp"/>
    <tiles:put name="body" value="/body.jsp"/>
    <tiles:put name="footer" value="/footer.jsp"/>   
</tiles:insert>
在这段代码中,Tile将一个页面划分为4个区域,分别由对应的JSP来实现。页面布局由layout.jsp实现,这样当需要修改布局时,只要修改layout.jsp一个文件就可以了。

Tile提供的关于页面布局的解决方案非常适合应用到本项目中。

下页

使用Node.js开发简单的CMS