【论文摘要】
J2EE即是以Java 2平台为基础的体系结构,又是一组旨在简化企业解决方案的开发、部署、运行、维护等相关复杂问题的技术规范与指南。Struts2、Spring、Hibernate是当今符合J2EE技术规范的三个流行的开源框架。本文通过对这三个框架的工作机制的分析引伸出它们在J2EE应用中的互补作用,进而讲解它们在J2EE开发中的整合。最后通过一个简单的实例演示Struts2+Spring+Hibernate的开发流程。
关键字: Struts2 Spring Hibernate J2EE
【Abstract】
J2EE is the structure base on Java 2 platform, it also a set of technical specification and guidelines to simplify the complex issues of the enterprise solutions of development, deployment, operation and maintenance of enterprise solutions. Struts2, Spring and Hibernate are three prevailing open-source framework in line with J2EE technical specification. This paper analyzes the working mechanism of these three frameworks, amplifies the complementary effect in their application of J2EE, and then introduces their integration in the development of J2EE. Finally, it demonstrates the developing process of Struts2+Spring+Hibernate through a simple case.
一 Struts2简介
(一) Struts2是什么,及在Java web开发中的作用
Struts2是一个基于J2EE平台的开源的MVC框架。它着力于Control和View,提供完善的控制方案并定制了功能强大的标签库。从某种意义上讲Struts2并不涉及Model,但它提供了访问Model的入口(execute()方法相当于访问Model的一个入口,业务逻辑层及其以下层次Struts2不涉及)。使用Struts2开发的系统具有以下多种优点:结构层次分明(MVC),可重用性高(框架正是把系统的共性部分抽取出来,提供给不同应用使用),程序健壮性(强大的验证机制与类型转换功能)、可伸缩性(动态加载插件、设计良好的抽象类、接口等)有保证,便于开发与设计分工(MVC)等。
(二) Struts2与Struts的关系及区别
Struts2不是Struts的简单的版本升级,而是本质上的飞越。事实上Struts2主要是从WebWork基础上发展起来,再吸收Struts的一些优点汇集而成的。(至于为什么叫Struts2而不叫WebWork2.x,很大程度是因为Struts在业内的知名度要比WebWork要高的原故。)
由于Struts2主要是继承于WebWrok的,所以它与Struts1的区别其实是很大的,以下列举其中几个重要方面:
Action类:Struts1要求Action类必须继承一个抽象基类(如Action、BasicAction)。Struts2也提供一个抽象基类ActionSupport实现常用的一些接口,Struts2的Action类尽管常常实现这个类,但这不是必须的,它不只可以继承一个Action类,还可以不继承Action类而实现其他接口,以便于定制一些特定的服务,增强了Action类的灵活性。
线程模式: Struts1的Action是单例模式,尽管这一定程度节约了资源的损耗,但同时要求开发者必须小心翼翼地把它设计成线程安全(需要是无状态的,即不能有可写属性)的,从而限制了Action所能做的工作。Struts2的Action即可以是单例模式,也可以是原型模式的,即可为每一个请求产生一个实例,因此没有线程安全问题。这也进一步体现了Struts2比Struts1要优雅得多。
对Servlet依赖: Struts1的Action依赖于Servlet API,当一个Action被调用时HttpServletRequest和HttpServletResponse需被传递给execute(或其它定制的)方法。Struts2的Action不依赖于容器,允许Action脱离容器单独执行(从而提高了可测性)。在需要时Struts2的Action也可以访问HttpServetRequest和HttpServletResponse。
输入捕获: Struts1的Action是单例模式(不应该出现可写属性),数据是先经过ActionForm封装再交给Action的。我认为这是Struts1设计的最大缺陷之一,ActionForm与DAO层的Doamin对象形式差不多,执行的功能也相似,只是意图不同,这种代码的冗余会给开发、维护带来一系列问题。而Struts2的Action则是原型模式,每个Action都可以有其特有的属性,从而数据不需要经由ActionForm封装便可直接获取。很明显Struts2对输入的捕获及处理过程更加易于理解、更加简洁。
(三) strust2的工作流程
strust2的工作流程可归纳为以下几个步骤
1.客户端Http请求提交。
2.strust2的总控制器FilterDispatcher通过sturts.xml分析哪个Action进行处理。
3.指定的Action执行相关的类型转换方法(可省)、setXxx()方法、validate()方法等。
4.执行execute()方法(如果有指定其它方法则调用其它方法)。
5.sturts.xml根据execute()方法(或其它方法)返回的结果字符串确定接下来的工作(通常是调用一个jsp页面,也可以是另一个Action或其它方式)。
6.Http响应客户端。
二 Spring简介
(一) Spring是什么
Spring是一个轻量级的提供控制反转(IoC)、面向切面(AOP)容器的开源框架。
Spring创始人Rod Johnson发表的《Expert one-to-one J2EE Development without EJB》剑指EJB,对EJB的各种庞大又笨重的结构进行了分析和否定,随后推出的Spring便是以简洁实用的方式替换了EJB所能完成的大部分功能(以我对EJB的一点浅薄认识,必须承认就目前而言,特别是EJB3.0的推出,在很多方面Spring还是无法企及的)。它使用基本的JavaBean来完成以前只能由EJB完成的事情。当然Spring适合的范围不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
传统J2EE应用由于分层多,而各层之间又没有合理的衔接,至使开发效率低、系统也不易维护,应用服务器厂商对各种技术的支 持 并没有真正统一,导致J2EE的应用没有真正实现一次编译及到处执行的承诺。Spring的推出简化了J2EE应用开发的复杂性,它能独立于各种应用服务器容器,致力于J2EE应用各层的解决方案,它贯穿于View、Business及DAO各层,是它们之间很好的黏合剂。Spring的作用正是能与已有的框架配合,把它们无缝地整合在一起,使整个J2EE应用开发更加顺畅。
(二) Spring相关技术介绍
1.轻量级:
Spring的轻量级并不是体现在Spring的完整代码只有那么一点点(不到3MB),而是指Spring所需的系统开销是很小的(简直不能与EJB相提并论)。另外,Spring应用中的对象并不依赖于Spring的特定类(对象无需显示的声明Spring的特定类),Spring是非侵入式的。
2.控制反转:
控制反转(IoC)技术的运用降低了各层的耦合度。这是Spring框架最核心的一个方面。IoC概括起来说就是:一个对象所依赖的其它对象会通过容器(被动的)传递(在Spring常称为“注入”)进来,而不是该对象自己创建或者查找依赖对象。可以说企业级应用各层的无逢衔接正是通过IoC实现。更进一步说,Spring抽象了服务,借助于各种J2EE API抽象,开发者能够一致地使用J2EE 技术,而不管具体的实现方式是怎样的。下面代码可以很好的说明这一点:
这是传统的服务层的实现类:
public class UserServiceImpl implements UserService{
//由于依赖对象由当前对象管理,所以这里new 需指明具体实现类。
private UserDao userDao=new UserDaoImpl();
private void add(User user)
{
userDao.add(user);
}
}
使用Spring框架后的情况:
public class PersonServiceBean implements PersonService {
//依赖注入,即通过构造器,让容器把创建好的依赖对象注入进来
//此处不需要硬编码说明具体实现类(只需在xml文件配置即可),这便是IoC的巨大优点!
private UserDao userDao;
public PersonServiceBean(UserDao userDao) {
this.UserDao=userDao;
}
private void add(User user)
{
userDao.add(user);
}
}
抽象了服务!仅此一点,足矣让绝大多数开发者兴奋不已!
3.面向切面:
Spring提供了面向切面(AOP)编程的支 持 ,允许开发者以声名方式使用企业级服务,最典型的是声明式事务管理。通过Spring提供的事务管理服务,开发者便不再需要手工管理事务,也无需处理复杂的事务传播行为。
下面还是以例子说明AOP的作用:
这是DAO层的代码:
public class UserDaoImpl implements UserDao
{
public void save(User user)
{
Session s=HibernateUtil.getSession();
Transaction tx=null;
try {
tx=s.beginTransaction(); //开启事务
s.save(user);
mit();//提交事务
}catch(Exception e){
if(tx!=null)
tx.rollback();//回滚事务
try {
throw e;
}catch (Exception e1) {
e1.printStackTrace();
}
}finally{
if(s!=null)
s.close();//关闭session
}
}
}
显然这是不好的代码。尽管事务管理属于DAO层的代码,但由于DAO各方法会以不同方式组合成同一个事务,从而事务不应该在DAO层管理,而应该交给更高一层级,于是应该去掉事务管理代码,改为:
public class UserDaoImpl implements UserDao
{
public void save(User user)
{
s=HibernateUtil.getSession();
try {
s.save(user);
}finally{
//同上,关闭session
}
}
}
然后是服务层代码:
public class UserManagerImpl implements UserManager {
private UserDao userDao;
public void saveUser(User user)
{
Session s=HibernateUtil.getSession();
Transaction tx=null;
try {
tx=s.beginTransaction();
userDao.save(user);
//其它方法
sendMessage();
sendEmail();
mit();
}catch(Exception e){
//同上,回滚事务
}finally{
//同上,关闭session
}
}
}
这是在没有Spring情况下习惯的做法,这似乎也是较为合理的做法,但事务的开启与关闭是DAO层的代码,怎么跑到服务层来了呢?显然这样做服务层一定程度耦合了DAO层,通过Spring可以得到很好的解决:
public class UserManagerImpl implements UserManager {
private UserDao userDao;
//声明事务处理方式
@Transactional(propagation=Propagation.REQUIRED)
public void saveUser(User user)
{
userDao.save(user);
//其它方法
sendMessage();
sendEmail();
<, SPAN style="mso-spacerun: yes"> }
}
不但彻底解耦,还大大简化了代码,程序显得优雅许多了。
4.容器:
Spring容器包含并管理应用对象的配置和生命周期,开发者可以通过XML配置每个bean如何被创建(默认是singleton,也可以是prototype),以及它们是如何相互关联的。
如下applicationContext.xml配置:
class="mons.dbcp.BasicDataSource">
class="org.Springframework.orm.Hibernate3.LocalSessionFactoryBean"
destroy-method="close">
可以看得出Spring自底向上把各层衔接起来。特别是在多框架整合的情况(如上面配置,即是整合了Hibernate、Struts2的典型配置方式),Spring使各框架无逢地结合到了一起。
三 Hibernate简介
(一) Hibernate是什么
Hibernate是一个开源的数据持久层框架,用于实现对象与关系之间的映射(即O/R Mapping)。它对JDBC进行了轻量级的对象封装,使Java程序员可以使用面向对象编程思想来操作数据库。它不但提供了从Java类到数据表的映射,还提供了数据查询和恢复机制。相对于使用JDBC和SQL来操作数据库,通过使用Hibernate,大量封装持久化操作的业务逻辑不再需要编写烦琐的JDBC语句,极大简化了编程实现。Hibernate是跨数据库的,因此基于Hibernate编写的代码不会因为数据库的更换而重写。
(二) 领域模型
Hibernate中领域模型(Domain)对象通过xml文件映射了数据库的一张表(或多张表),xml文件通常位于Domain对象同一个包,命名为ClassName.hbm.xml(ClassName为映射的类名),Domain对象通常只有一些属性(对应表的字段)及相应的setter、getter方法,当然还得符合以下几个条件才能成为Domain对象:
1。必须要有默认的构造方法。
2。有无意义的标识符id(主键)。
3。非final,这是使用懒加载所需的要求。(因为懒加载需要继承该类,如果加了final,该类便不可继承了。)
(三) 对象状态
在Hibernate中,对象状态也是比较重要的概念,分别有以下三种:
1.瞬时:数据库没有记录与之对应。
2.持久:数据库有记录与之对应,当前与session有关联,并且相关联的session没有关闭,事务没有提交。持久对象状态发生改变,在事务提交时会影响到数据库。
3.脱管:即脱离管理。数据库有记录与之对应,当前没有session与之关联,脱管对象状态发生改变,不会影响到数据库。
(四) HQL(Hibernate Query Language)
是Hibernate提供的用于跨数据库查询的面向对象查询语言,它是按对象名而不是按表名来查询。同时支 持 多态查询,即查询父类,会同时查询子类。比如from Object会查询所有对象,即查询所有表。
(五) 对象关系映射
Hibernate提供了一对一、多对一、一对多、多对多等对象关系映射。
但需要指出的是,由于实际系统运行时性能的需求,往往不做多对多关联(它需要对多个表进行关联查询,效率很低),甚至一对多关联也很少做。
(六) 懒加载
懒加载,即只有在要用到数据时才到数据库里读取。通过session.load()可以实现对象的懒加载,从而尽量减少数据库访问次数以缓解系统的压力。需要注意的是,能够懒加载的对象都是被改写过的代 理 对象,当相关联的session没有关闭时,访问这些懒加载对象(代 理 对象)的属性(getId、getClass除外)Hibernate会初始化这些代 理 ,或用Hibernate.initialize(proxy)来初始化代 理 对象;当相关联的session关闭后,再访问懒加载对象将出现异常。
(七) 缓存
缓存又可分为一级缓存跟二级缓存。
一级缓存,是Session级共享。save、update、saveOrUpdate、load、get、list、iterate、lock这些方法都会将对象放入一级缓存中,由于一级缓存不能控制缓存的大小,不宜操作过大的数据,否则容易造成内存溢出,为此需用session.evict(Object)、session.clear()方法清除缓存中的内容。
二级缓存,是SessionFactory级共享。Hibernate并没有实现二级缓存,而是将之交给第三方缓存组件(如:EhCache、OSCache等)实现。
四 整合Struts2、Spring、Hibe, rnate构建J2EE应用
(一) 什么是J2EE
J2EE即Java2平台企业版(Java 2 Platform Enterprise Edition),是一套以Java 2平台为基础的技术架构。包含许多组件,目的在于简化并规范应用系统的开发与部署,进而提高可移植性、安全性与再用价值。J2EE核心是一组技术规范与指南,它给开发人员提供了一个应用标准,定义了一个标准的应用体系结构,J2EE作为解决企业级应用的标准,将企业级应用划分成不同层次,便于应用开发,管理和部署。J2EE应用服务器支 持 各种组件,如Servlet、JSP、EJB等,这些组件分别安装和部署于各自的容器中,使用标准的J2EE service API连接,灵活地实现应用。
(二) J2EE多层应用分析与实现
经典的J2EE三层结构是指表示层(Presentation),业务逻辑层(Business logic)以及基础架构层(Infrastructure)。在实际项目开发中,往往会对三层体系结构做一些扩展来满足项目的需要。如今较流行的方式是将三层体系扩展为五层体系,即在表示层与业务逻辑层之间增加控制层(在某些情况下甚至还会在控制层与业务逻辑层再增加代 理 层),再把基础架构层细分为数据访问层、数据层。Struts2 + Spring + Hibernate可以实现J2EE的这种多层结构。其中Struts2用于表示层与控制层,而Spring工作的中心在业务层,同时又粘合控制层、业务层与数据访问层,Hibernate则用于数据访问与持久化工作。
(三) J2EE层次结构
1. 数据层
数据层是指提供所需数据的数据库系统。数据库里记录了系统所需要的所有数据。由于数据库系统本身的多样性,J2EE提供了JDBC接口用于数据库之上的组件能访问各种数据库系统。Hibernate则进一步封装了JDBC对数据库的操作。
2. 数据访问层
包括数据查询与持久化工作。本层将完成具体的数据处理工作,包括增、查、改、删(CRUD)。
本层运用DAO设计模式,通过使用Hibernate的ORM技术很好的解决了“阻抗不匹配”(即对象操作与关系数据库操作方式不同)的问题。DAO进一步封装了JDBC对数据库表的CRUD操作,实现了用一致的面向对象的方式操作不同数据库,同时也降低了数据操作的难度。
3. 服务层
本层是整个系统架构的核心,需完成所有业务规则的制定、业务流程的实现等与业务需求有关的系统设计。Spring的引入很大程度的简化这一层的复杂性。例如事务处理,开发者不再为事务边界控制而为难。本层把一些算法、数据处理(通过调用DAO层)等与业务相关的处理封装于一体,交由控制层调用。把服务层与控制层分离,使层次更加分明,分工更加细致,从而更方便团队调配工作。
4. 控制层
本层接受客户端的请求,转交给服务层处理,最后将处理结果返回给客户。通过引入Struts2框架,控制层会以Struts2为主导。(相对Struts1而言)Struts2作为一个Filter而不再只是Servlet,在请求到来时(在必要的情况下会)对信息进行验证、处理(如类型转换),只有验证通过的请求才会转交给业务层处理,最后将处理结果返回给客户。尽管在未引入Struts2的情况下Servlet可以做相同的事,但相比之下Struts2使这些工作规范化、模式化,开发者只需在模式化的处理(Action)类填补一些代码,甚至可以通过XML文件的配置来实现这些操作,大大简化了代码,提高了开发效率。
5. 视图层
视图层是呈现给客户的界面,通常是JSP、HTML等页面。在使用Struts2框架的应用中,会使用Struts2提供的功能丰富的标签库增强页面动态内容的输出能力。
(四) 为什么要整合Struts2、Spring、Hibernate
通过以上各层的分析,可以清楚的看到Struts2、Spring、Hibernate在整个J2EE应用中的作用以及它们相互间的协作关系。Hibernate负责底层数据库操作,Spring协调整个应用各功能组件,并在业务层中解耦该层与数据访问层,而Struts2则在控制层做主导,并对视图层页面输出能力做了增强。三个框架功能互补,让整个J2EE应用确实体现高效、易扩展、健壮。
五一个简单的应用示例
(一) 项目介绍与准备工作
为进一步分析如何通过Struts2、Spring、Hibernate构建J2EE应用,并且能在尽可能小的篇幅说明开发的过程,下面将通过项目开发中常见的“管理员登录”的例子演示它们的整合过程。与此登录过程无关的数据、设计过程、代码将不做说明。另外,以下所讲的各层,并不是真实项目开发的“步骤”,事实上正是框架的引入最大限度的使各层解耦,从而允许各层并行的开发。以下是项目的整体架构图(亦是工作流程图):
(注:Spring的ContextLoaderListener及applicationContext.xml不属于单独的某一层,而是横跨控制层、服务层、DAO层,管理各层组件。Hibernate的HibernateDaoSupport对JDBC进行了封装。)
开发、测试环境:Eclipse6.5、jdk1.6、tomcat6.0、IE6
数据库:mysql5.0
建立J2EE项目EShop2,并导入Spring、Hibernate、Struts2及整合所需相关jar包。将Spring、Struts2框架引进项目(Hibernate将由Spring引入)。(位于WebRoot\WEB-INF目录下的)web.xml需做如下配置:
Struts2
org.apache.Struts2.dispatcher.FilterDispatcher
Struts2
/*
org.Springframework.web.context.ContextLoaderListener
(二) 数据库设计
管理员表admin相关字段:
ID帐号 &, nbsp; 密码
id(int) LoginName(char(12)) loginPwd(char(12))
(三) Domain对象及O/R Mapping映射文件建立
Domain对象源文件Admin.java如下:
public class Admin {
private Integer id;
private String loginName;
private String loginPwd;
public Admin(){}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
//其它getter、setter略
}
O/R Mapping映射文件Admin.hbm.xml主要内容:
Hibernate正是通过本文件建立了对象与数据库表的映射关系,从而程序员可以通过操作对象的方式操作数据库表。
(四) DAO层
面向接口编程,这是好的做法。如下是AdminDao接口:
public interface AdminDao {
public Admin findAdminByNP(String LoginName,String LoginPwd);
//还有其它方法如saveAdmin(),removeAdmin()等略。
}
接口实现类:
//本类继承于HibernateDaoSupport,这是Hibernate提供的一个重要的类,通过它操作数据库,使代码如此简洁,以至程序无需任何注释了。
public class AdminDaoImpl extends HibernateDaoSupport implements AdminDao {
public Admin findAdminByNP(String loginName, String loginPwd) {
String hql="from Admin where LoginName=? and LoginPwd=?";
String []values={loginName, loginPwd};
List list=(List)this.getHibernateTemplate().find(hql,values);
if (list.size()>0)
{
return list.get(0);
}
return null;
}
//其它实现方法略。
}
(五) 服务层
还是面向接口,AdminService接口代码如下:
public interface AdminService {
public Admin adminLogin(String loginName,String loginPwd) throws Exception;
//其它业务方法略
}
接口实现AdminServiceImpl:
public class AdminServiceImpl implements AdminService {
private AdminDao adminDao; //服务层通过DAO层接口操作数据库
public Admin adminLogin(String loginName, String loginPwd) throws Exception {
Admin admin = adminDao.findAdminByNP(loginName, loginPwd);
return admin;
}
}
尽管服务层是项目的核心,通常也是开发过程中最复杂的一个环节,但可以看到,有了DAO层,本例程序相当简单。这似乎未见Spring的身影。好,我们扩展一下功能,设想登录时需要更新管理员的登录次数并记录日志。日志对象会对应数据库的另一个表。这样登录时将同时写两个表,出于数据一致性的考虑,这时就需要开启事务,如何管理呢?看如下代码:
//引入Spring事务注解及事务传播属性注解类
import org.Springframework.transaction.annotation.Transactional;
import org.Springframework.transaction.annotation.Propagation;
@Transactional //注解管理事务
public class AdminServiceImpl implements AdminService {
private AdminDao adminDao;
//指定本方法须在同一事务内处理
@Transactional(propagation=Propagation.REQUIRED)
public Admin adminLogin(String loginName, String loginPwd) throws Exception {
Admin admin = adminDao.findAdminByNP(loginName, loginPwd);
if (admin!=null)
{
//更新管理员登录次数,代码略
//添加管理员登录事件记录,代码略
}
return admin;
}
}
事务的创建、开启、回滚、提交等操作交由Spring管理,程序不会因为事务的引入增加多少代码(只是增加两句注解语句而已),尽管可以通过xml配置的方式管理事务,但我认为这是最优雅的做法。
(六) 控制层
控制层将以Struts2为主导,首先是Struts2配置文件struts.xml,它应位于源文件夹src根目录下(编译后将位于classes根目录下)。
核心代码如下:
error.jsp
index.jsp
login.jsp
AdminAction.java涉及相关代码:
import com.opensymphony.xwork2.ActionContext;
//通过继承ActionSupport我们的Action类将获得一些像自动成员赋值、校验、类型转换等功能。
public class AdminAction extends ActionSupport {
private Admin admin;
private AdminService adminService;
//相关getter、setter方法略
public String login() throws Exception {
String result=this.ERROR;
String loginName,loginPwd;
/**
* 领域模型的赋值是通过继承ActionSupport,由Struts2为我们做的。
* 尽管可以在此验证this.getAdmin().getLoginName()、
* this.getAdmin().getLoginPwd()值的合法性(如是否非空、长度是否
* 适合等)但这不是规范的做法,这部分工作应该交由validate()方法处理
*/
loginName=this.getAdmin().getLoginName();
loginPwd=this.getAdmin().getLoginPwd();
//调用服务层方法实现登录验证的操作,根据是否获得Admin对象确定登录成功与否
Admin admin=this.getAdminService().adminLogin(loginName, loginPwd);
if (admin!=null)
{
Map session = ActionContext.getContext().getSession();
session.put("adminId",admin.getId()); //尽管可以把整个admin对象放入session,但这不是好的做法,毕竟除了id跟LoginName其它信息基本不使用。
session.put("adminLoginName",admin.getLoginName());
result=this.SUCCESS;
}
else
{
Map request=(Map)ActionContext.getContext().get("request");
request.put("errorMessage", "用户名或密码输入不正确!");
}
return result;
}
@Override
public void validate() {
// 具体验证实现略
}
}
前面除了在业务层扩展登录方法,其它地方一直没有出现Spring,必须承认 ContextLoaderListener是很容易让人遗忘它的存在(除了在配置web.xml的时候),事实上站在开发者的角度看Spring很大程度是通过applicationContext.xml文件发挥作用的。尽管Spring不属于控制层,但控制层是它为我们的项目服务的最后一层,是时候请出我们的功臣了。如下是applicationContext.xml配置:
class="mons.dbcp.BasicDataSource">
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" destroy-method="close">
可以看出,整个开发中除了视图层Spring未涉足,从数据层到控制层,Spring一直在发挥作用。它调配好各项准备工作,使各层有机的融合在一起。
(七) 视图层
视图层是客户向服务器发起请求的窗口,表单页面login.jsp主要代码如下:
<%@ taglib uri="/Struts-tags" prefix="s" %>
<SPAN style=" Roman’?="" New="" ’Times="" Roman’;="" 宋体;="" 150%;="" 12pt;="">用户名" required="true" />
<SPAN style=" Roman’?="" New="" ’Times="" Roman’;="" 宋体;="" 150%;="" 12pt;="">密码" required="true"/>
<SPAN style=" Roman’?="" New="" ’Times="" Roman’;="" 宋体;="" 150%;="" 12pt;="">登录">
<SPAN style=" Roman’?="" New="" ’Times="" Roman’;="" 宋体;="" 150%;="" 12pt;="">重置">
另外还有一个用于显示错误报告的页面error.jsp,内容略。
(八) 程序运行
输入http://localhost:8080/EShop2/adminope/login.jsp进入登录页面:
输入不完整信息(未输入密码),程序返回登录页并提示错误:
输入验证未通过的信息(用户名或密码错误),需说明的是,因为是以dispatcher方式跳转,所以隐藏了error.jsp的真实地址(仍为表单目标地址adminLogin.action):
输入正确信息,成功登录后台:
(九) 总结
至此“管理员登录”功能已开发完毕。当然,本例所谈的开发,仅指编码,事实上它只是软件开发的一个环节。关于可行性研究、需求分析、设计、测试以及运行、维护不是本文所讨论的范畴。通过以上的分析与说明,相信读者能看出整个流程的规范化。尽管看起来有些按部就班,但事实上这正是现代软件业向大规模、群体、团队开发的必由之路。J2EE的规范以及为我们提供的指南是每个软件开发从业人员所必须深刻学习的。而Struts2、Spring、Hibernate框架的学习与整合三者构建J2EE应用,从小的方面看是帮助我们领会与实践J2EE思想、提高软件开发素质,从大的方面看是提高软件开发效率(各种框架为我们做了很多工作)、使软件易于维护(规范化的代码),进而促进软件业的发展。
参考书目:
1.《轻量级Java EE企业应用实战-struts2+spring+hibernate整合开发》 李刚 电子工业出版社
2.《spring揭秘》 王福强 人民邮电出版社
3.《Struts 2深入详解》孙鑫 电子工业出版社
4.《J2EE 企业级应用测试实践》 白胜 清华大学出版社
/newsshow/532.html