8.3 网上书店组件设计架构
上述的SOA架构是从一个宏观的架构进行设计,具体实现时,还需要基于SOA架构进行具体的模块和组件架构设计,SOA是从业务功能来划分的。这里进一步介绍模块组件设计架构,以便读者对本章的网上书店系统有一个全面的了解。
1.组件图
Rational Rose是实际项目中最常用的设计工具。图8-11是基于Rational Rose的组件图,它反应整个应用所使用的技术。
图8-11 网上书店的组件图
l JSP组件:负责页面显示。
l Struts Action Bean:控制器部分,负责页面层和逻辑层的结合,以及页面转换。
l ClientManagerImp:负责调用后台服务的组件。
l SOA Service Integration Bus:SOA服务总线。
l Web Service:Web服务组件。
l Session Bean:负责业务逻辑。
l Entity Bean CMP:负责数据库层的操作。
2.Class类图
图8-12是基于Rational Rose所设计的网上书店系统的总的类图。
图8-12 网上书店的类图
8.4 网上书店的业务和时序图
为了让读者尽快掌握创建SOA应用的方法和步骤,下面详细介绍各个服务接口是如何实现的,包括介绍业务需求、时序图和实现步骤,使读者能尽快掌握精髓,运用到实际项目中去。
8.4.1 注册系统业务和时序图
用户需要通过注册系统来将他们的有关个人信息登记到网上书店系统中,这些个人信息是用户购书时需要的。下面将介绍具体的业务需求及实现步骤。
1.注册系统业务需求简介
做任何一个项目首先需要知道具体的业务,下面首先介绍注册系统总的业务需求。
(1)提供用户界面给用户,输入他们的Name(姓名)、Login Name(登录名)、Password(密码)、Phone(电话号码)、E-mail和Registration Fee(注册费)。
(2)提供用户界面的输入校验。
l 所有字段不能为空。
l 登录名和密码不能少于5个字符。
l 电话号码必须按888-888-8888的格式输入。
l E-mail必须按aaa@aaa.com的格式输入。
l 注册费必须输入数字。
(3)用户填完注册信息,单击【Save】按钮之后,所有的用户信息将会记录到数据库USER表和ACCOUNT表中。
(4)用户注册成功后系统将给出成功注册的信息。
2.注册系统业务及实现
下面是本章所实现的业务详解。
(1)用户输入个人信息后,系统进行页面校验。
这里通过Struts的Validator来实现页面校验,返回具体的错误信息让用户修正,如图8-13所示,在Web应用项目的WEB-INF/bkstore目录下面的bkstore- validation.xml文件中定义了对该页面的所有字段的校验规则。
页面显示层是通过Regis.jsp来实现的,业务逻辑是通过Action Bean- RegistrationAction调用模型层来实现的。
图8-13 注册页面校验错误
(2)用户根据提示的错误信息输入正确的信息。
用户输入正确的信息,如图8-14所示,页面校验通过,Action Bean将会把用户所输入的保存在Form Bean中的用户个人信息取出,存入到UserAccountDTO对象中,进而调用BookStoreMgrImp对象中的saveUserInfo方法,以调用SOA的服务总线的入站服务方法,最后将用户个人信息存入到数据库。
图8-14 注册页面输入正确信息
(3)用户注册成功后系统将给出成功注册的信息。
用户个人信息存入到数据库后,Action Form经过ActionMapping的forward方法将页面消息输出到页面,在ActionMessages对象中定义一个注册成功的消息,如图8-15所示。真正的消息内容在资源文件中,而在ActionMessages对象中存入的是一个成功信息的关键词。
图8-15 注册页面成功
(4)查看数据库USER表,如图8-16所示,检查用户的注册信息是否已经记录到数据库中。
图8-16 数据库USER表
(5)查看数据库ACCOUNT表,如图8-17所示,检查用户的注册信息是否已经记录到数据库中。
图8-17 数据库ACCOUNT表
3.实现注册系统时序图
图8-18是实现业务的时序图,显示了实现上述业务逻辑时的类之间的调用顺序关系。
图8-18 注册系统时序图
4.注册系统具体实现步骤
下面是实现如图8-18所示的时序图的具体步骤。
(1)用户单击“URL Regis.do”链接时,Struts的ActionServlet通过config.xml的配置将会指向Regis.jsp的页面。
(2)用户填写完注册信息后单击【Submit】按钮时,Struts会通过config.xml的配置调用RegistrationAction类的execute()方法,并将用户的信息存到UserAccountDTO类中。
(3)RegistrationAction类的execute()方法调用BookStoreMgrImp类的saveUserInfo()方法。
(4)BookStoreMgrImp类的saveUserInfo()方法调用WSDL所生成的接口的ServiceLocator去调用相应的SOA Service Integration Buses的入站服务。
(5)Service Integration Buses的入站服务调用相应的Web Service。
(6)Web Service调用Session Bean(BKStoreMgr)的saveUserInfo()。
(7)Session Bean调用Entity Bean CMP(UserCMP)。
8.4.2 登录系统业务和时序图
本系统是通过登录系统来实现安全管理的,有些页面(如购物车)只有用户登录后才能进入。下面将介绍具体的业务需求及实现步骤。
1.登录系统业务需求简介
下面是登录系统业务需求简介。
(1)创建用户的登录界面。
(2)对用户的用户名和密码进行校验。
(3)如用户登录失败,则需要输出错误信息。
(4)如用户登录成功,则输出成功信息,并保留用户Session,因而用户登录其他页面(如Shopping Cart购物车)时不需要再次登录。
2.登录系统业务及实现
下面是本章所实现的登录系统业务详解及实现。
(1)进入“登录”界面。
页面显示层是通过Login.jsp来实现的,如图8-19所示,业务逻辑是通过Action Bean- LoginAction调用模型层来实现的。
图8-19 “登录”界面
(2)用户输入一个系统没有注册的用户名时,系统会提示相应的错误。
程序回到后台数据库通过CMP来查询是否在数据库中有该用户名,通过findByLoginName的方法来查询。如果通过findByLoginName查不到任何记录,表示没有该loginName,服务器端会将该错误作为异常抛出到Action Bean,Action Bean截获该异常后,取出异常信息。该异常信息只是错误信息的关键词,程序将会从字样资源文件中取出该错误信息,输出到前台页面,如图8-20所示。
图8-20 输入未注册用户名
如果输入一个系统中没有的用户名时,将会出现如图8-21所示的错误。
图8-21 用户名不对或未注册造成的错误登录界面
(3)用户输入的用户名和密码不匹配时会输出错误信息。
程序回到后台数据库通过CMP来查询是否在数据库中有该用户名和密码,通过findByLoginName的方法并以loginName作为参数来查询。找出一个记录,从该记录中取出对应的密码,如果和输入的密码不一致,如图8-22所示,则服务器端抛出用户输入的用户名和密码不匹配的异常,Action Bean截获该异常后,输出到前台页面。
图8-22 输入用户名与密码不匹配
因为输入的用户名存在,但是密码不正确,所以页面输出下列错误,如图8-23所示。
图8-23 用户名和密码不一致的错误信息界面
(4)用户输入正确的用户名和密码。
程序回到后台数据库通过CMP来查询是否在数据库中有该用户名和密码,通过findByLoginName的方法并以loginName作为参数来查询。找出一个记录,从该记录中取出对应的密码,如果和输入的密码一致,则服务器端返回true到前端,Action Bean接到返回值后,通过资源文件输出校验正确的信息到前台页面,如图8-24所示。
图8-24 成功登录界面
3.登录系统时序图
图8-25是实现上面业务的时序图,显示了实现业务逻辑时的类之间的调用顺序关系。
图8-25 登录系统时序图
4.登录系统具体实现步骤
下面是实现上述时序图的具体步骤。
(1)用户单击URL Login.do链接时,Struts的ActionServlet通过config.xml的配置指向Login.jsp的页面。
(2)用户填完登录信息后单击【Submit】按钮时,Struts会通过config.xml的配置调用LoginAction类的execute()方法。
(3) LoginAction类的execute()方法调用BookStoreMgrImp类的checkUserLogin()的方法。
(4)BookStoreMgrImp类的saveUserInfo()方法调用WSDL所生成的接口的ServiceLocator去调用相应的SOA Service Integration Buses的入站服务。
(5)Service Integration Buses的入站服务调用相应的Web Service。
(6)Web Service调用Session Bean(BKStoreMgr)的checkUserLogin ()。
(7)Session Bean调用Entity Bean CMP(UserCMP)。
8.4.3 用户查询系统业务和时序图
用户查询系统将显示网上书店的所有用户及其相关信息。
1.用户查询系统的业务需求
业务需求是显示所有已经注册的用户信息。
页面显示层是通过UserList.jsp来实现的,业务逻辑是通过Action Bean- UserListAction调用模型层来实现的。
单击“用户查询”链接时,所有注册的用户信息会显示,如图8-26所示。
图8-26 “用户查询”界面
2.用户查询系统时序图
图8-27是实现上面业务的时序图,显示了实现业务逻辑的类之间的调用顺序关系。
图8-27 用户查询系统时序图
3.用户查询系统的具体实现步骤
下面是实现上述时序图的具体步骤。
(1)用户单击“URL UserListdo”链接时,Struts会通过config.xml的配置调用UserListAction类的execute()方法。
(2)UserListAction类的execute()方法调用BookStoreMgrImp类的getUserList()的方法。
(3)BookStoreMgrImp类的getUserList()方法调用WSDL所生成的接口的ServiceLocator去调用相应的SOA Service Integration Buses的入站服务。
(4)Service Integration Buses的入站服务调用相应的Web Service。
(5)Web Service调用Session Bean(BKStoreMgr)的getUserList ()。
(6)Session Bean调用Entity Bean CMP(UserCMP)。
(7)将UserList的信息返回到UserList.jsp。
8.4.4 用户账户管理系统业务和时序图
用户选中某些书,想进一步购买时,其账户中必须有足够的资金,本系统主要功能是管理用户账户资金。
1.用户账户管理系统需求和实现
用户账户管理系统需求如下。
l 显示用户账户中的存款余额。
l 用户账户可以增加新的资金。
页面显示层是通过BookMgr.jsp来实现的,业务逻辑是通过Action Bean- AccountMgrAction调用模型层来实现的。下面介绍具体的需求和实现。
(1)登录之后再单击“账户管理”链接,显示用户账户中的存款余额。
具体的实现是在Action Bean中,通过Session的信息得到用户名,然后调用用户名参数和getUserInfo的方法,得到用户的个人信息(包括资金信息),显示在AccountMgr.jsp中,如图8-28所示。
图8-28 “账户管理”界面
(2)在用户账户中注入新的资金。
如果用户注入新的资金,如图8-29所示,单击【Submit】按钮后,新的资金会存到Form Bean中传到Action Bean,Action Bean会从Form Bean中通过accountMgrForm.getString("newAmount")方法取出界面填入的资金值,存到UserAccountDTO对象中,调用updateAccountBalance的方法将用户新的资金更新到后台数据库。
图8-29 在账户里注入新资金
上面的更新数据库资金成功后,如图8-30所示,服务器端将不会报出一个异常到客户端。Action Bean将创建一个资金更新成功的信息到ActionMessages对象中,输出到前端JSP页面。
图8-30 成功更新账户
(3)显示新的用户账户中的存款余额
单击“账户管理”链接,显示用户账户中的存款余额,如图8-31所示,整个调用方法同步骤(1)。
图8-31 显示新的用户账户中的存款余额
2.用户账户管理系统时序图
图8-32是实现上面业务的时序图,显示了实现业务逻辑时的类之间的调用顺序关系。
图8-32 账户管理系统时序图
3.用户账户管理系统的具体实现步骤
下面是实现上述时序图的具体步骤。
(1) 用户单击“Account Manager”链接时,Struts的ActionServlet通过config.xml的配置指向AccoutMgr.jsp页面。
(2)用户填完新的资金后单击【Submit】按钮时,Struts会通过config.xml的配置调用AccountMgrAction类的execute()方法。
(3)AccountMgrAction类的execute()调用BookStoreMgrImp类的updateAccount- Balance()方法。
(4) BookStoreMgrImp类的updateAccountBalance()方法调用WSDL所生成的接口的ServiceLocator去调用相应的SOA Service Integration Buses入站服务。
(5)Service Integration Buses的入站服务调用相应的Web Service。
(6)Web Service调用Session Bean(BKStoreMgr)的updateAccountBalance ()。
(7)Session Bean调用Entity Bean CMP(AccountCMP)将新的资金存入数据库。
8.4.5 图书管理系统业务和时序图
网上书店数据库中的图书信息是管理人员通过图书管理系统加入的。下面将介绍具体的业务需求及实现步骤。
1.图书管理系统业务需求及实现
业务需求是提供用户界面让系统管理员将新的图书加入到数据库中,详细内容如下。
页面显示层是通过BookMgr.jsp来实现的,业务逻辑是通过Action Bean- BookMgrAction调用模型层来实现的。
(1)进入“图书管理”界面,如图8-33所示,加入新的图书的所有信息。
图8-33 “图书管理”界面
在图8-33中,用户输入图书有关的信息,单击【保存】按钮时,这些图书信息将会保存到Form Bean,并被Actionservlet送到Action Bean,Action Bean将会把存在Form Bean中的图书信息取出,存入BookDTO对象中,调用BookStoreMgrImp对象中的createBook方法,进而调用SOA的服务总线的入站服务方法,最后将图书信息存入数据库。
(2)新的图书加入后,系统返回成功加入的信息。
图书信息存入数据库后,Action Bean在ActionMessages对象中定义一个图书成功加入的消息,Action Form经过ActionMapping的forward方法将消息输出到新的转向页面,如图8-34所示。
图8-34 新书成功加入系统
(3)查看数据库表BOOK,如图8-35所示。
图8-35 数据库表BOOK
2.图书管理系统时序图
图8-36是实现上面业务的时序图,显示了实现业务逻辑时的类之间的调用顺序关系。
图8-36 图书管理系统时序图
3.图书管理系统具体实现步骤
下面是实现图8-36所示时序图的具体步骤。
(1)用户单击“BookMgr.do”链接时,Struts的ActionServlet通过config.xml的配置指向BookMgr.jsp的页面。
(2)输入图书信息后单击【Submit】按钮时,Struts会通过config.xml配置调用BookMgrAction类的execute()方法,并将用户的信息存到BookDTO类中。
(3)RegistrationAction类的execute()方法调用BookStoreMgrImp类的create- Book()的方法。
(4)BookStoreMgrImp类的createBook()方法调用WSDL所生成的接口的ServiceLocator去调用相应的SOA Service Integration Buses的入站服务。
(5)Service Integration Buses的入站服务调用相应的Web Service。
(6)Web Service调用Session Bean(BKStoreMgr)的createBook()。
(7)Session Bean调用Entity Bean CMP(BookCMP)。
8.4.6 图书查询系统业务和时序图
用户购买图书时,首先需要知道网上书店有哪些图书,下面将介绍具体的业务需求及实现步骤。
页面显示层是通过BookList.jsp来实现的,业务逻辑是通过Action Bean- BookListAction调用模型层来实现的。
1.图书查询系统业务需求
本系统的业务需求如下。
l 显示所有图书的信息。
l 用户单击某一图书的链接时,可以直接加入到购物车(Shopping Cart)。
单击“图书查询”链接,所有图书信息会显示出来,如图8-37所示。
图8-37 “图书查询”界面
2.图书查询系统时序图
图8-38是实现上面业务的时序图,显示了实现业务逻辑时的类之间的调用顺序关系。
3.图书查询系统的具体实现步骤
下面是实现图8-38所示时序图的具体步骤。
(1)用户单击“BookList.do”链接时,Struts会通过config.xml配置调用BookListAction类的execute()方法。
(2) BookListAction类的execute()方法调用BookStoreMgrImp类的getBookList()的方法。
(3)BookStoreMgrImp类的getUserList ()方法调用WSDL所生成的接口的ServiceLocator去调用相应的SOA Service Integration Buses的入站服务。
(4)Service Integration Buses的入站服务调用相应的Web Service。
(5)Web Service调用Session Bean(BKStoreMgr)的getBookList ()。
(6)Session Bean调用Entity Bean CMP(BookCMP)。
(7)将BookList的信息返回到BookList.jsp。
图8-38 图书查询系统时序图
8.4.7 购物车业务和时序图
当用户选中某些书时,需要通过购物车来购买,下面将介绍具体的业务需求及实现步骤。购物车系统是网上书店系统最复杂的一块,它本质上是实现了图书系统、用户系统和订单系统的集成。
1.购物车的业务需求及实现
购物车系统是网上书店最复杂的一个系统,其业务需求主要包括以下几个方面。
l 用户可以将自己要买的图书加入购物车。
l 用户可以将自己不想买的图书从购物车中删除。
l 用户可以修改自己所要买的图书的数量。
l 系统可以判断用户的账户中是否有足够的资金买购物车中的书。
l 购买成功后,系统将用户的购买信息存入数据库。
(1)用户从BookList中单击某一本书名的链接,如图8-39所示。
图8-39 选择图书
(2)系统显示选中书的详细内容,如果用户想买,则可单击【加入购物车】按钮。
单击书名的链接时,将指向viewBook.do,这样将调用ViewBookAction,同时把该图书的ID号也包含在请求中;ViewBookAction根据request.getParameter的方法得到该书的ID号,并将它作为参数来调用BookStoreMgrImp的getBook方法,得到该图书的所有信息,显示在下页,如图8-40所示。
图8-40 将选中图书加入购物车
(3)系统显示被选书已经加入购物车。
如果用户单击图8-40中的【加入购物车】按钮,页面将会继续提交到ViewBookAction,ViewBookAction将会根据request.getParameter("addShopCart")来确认这个请求是否真正来自“加入购物车”。如果是,将相关的图书信息从Form Bean中取出,存到一个ShoppingCartDTO实例中,因为一个用户可能会买很多书,一个ShoppingCartDTO代表所购买的一种书,将它加入到一个List中保存起来。值得说明的是,在购物车提交之前,所有购书的信息都是存在内存List中的。如果没有加入的错误信息,则通过Action Bean的saveMessages方法,将成功的信息加入到ActionMessages对象之中,再通过ActionMapping对象的findForward方法将成功信息显示到加入购物车的成功信息页面上,如图8-41所示。
图8-41 图书成功加入购物车
(4)用户可以直接从“图书查询”页将自己想买的书加入购物车,如图8-42所示。
图8-42 直接从“图书查询”页将选中图书加入购物车
直接单击“加入购物车”链接,会调用BookListAction。它首先检查是否含有一个action为addShopCart的请求,如果有,将从bookListForm中得到有关书的序号、书名、价格和折扣的信息,存到ShoppingCartDTO中,再存到前述的专门存购物车信息的缓存List之中。值得说明的是,在这个阶段,所有存到购物车之中的信息都还没有存到后台数据库,所以还可以非常方便地进行增加、删除和修改操作。
(5)用户单击“购物车”链接,进入“购物车”界面,如图8-43所示。
通过前面的操作,用户可以将他想买的书加入到购物车。在“购物车”界面,用户可以删除不想买的书,修改所要购买的书的数量;也可以看到每本书的单价、折扣和购买数量,以及购买全部图书的总价。
页面显示层是通过ShoppingCart.jsp来实现的,业务逻辑是通过Action Bean- ShoppingCartAction调用模型层来实现的。
图8-43 进入“购物车”界面
(6)删除不想买的书。
如果用户想删除不想买的图书,需要选中每种书前面的复选框checkbox,然后单击【删除】按钮,如图8-44所示,这个删除请求和所要删除的图书序号将会通过Struts的ActionServlet送到ShoppingCartAction;在ShoppingCartAction的execute方法中,将会检查是否有删除请求,如果有,则通过请求中该图书的序列号,从缓存的List中找到含有该图书序号bookID的ShoppingCartDTO,从List中删除该ShoppingCartDTO,选中图书将会从购物车中消失,如图8-45所示。
图8-44 删除所选图书
图8-45 所删除图书从购物车消失
(7)修改所要买的书的数量。
如果需要修改所买书的数量,则选中要修改数量的书,然后单击【修改数量】按钮。提交请求后,对应于每本书的数量将会在请求消息中存在,并通过ActionServlet转交给ShoppingCartAction;在ShoppingCartAction的execute方法中,它将会检查是否有“修改数量”的请求,如果有这样的请求,则取出请求中的图书数量,取出缓存List中的ShoppingCartDTO对象,修改其中的数量,如图8-46所示。
图8-46 修改购物车中所买图书的数量
(8)提交购物车。
一旦确定了所要购买的图书和数量,单击【Submit】按钮提交购物车,如图8-47所示。该请求会提交到ShoppingCartAction,它将在execute方法中检查是否有submit的请求,如果有这样的请求,它将首先从Session中取出用户的信息;接着产生一个OrderDTO的实例,将用户号、购买时间、税和总价存入到OrderDTO的实例中,然后调用BookStoreMgrImp的createOrder方法,将总的购书信息存入到数据库,并返回一个购书号。接着创建一个OrderItemDTO的数组,将每本书的书号、明细号、数量、折扣等信息存在OrderItemDTO中,调用BookStoreMgrImp的createOrder方法,将购书明细存入数据库。
图8-47 提交购物车
(9)显示用户账户里的资金不足。
提交购物车时,程序将会在服务器端检查用户的账户资金是否大于购书总价,如果账户资金小于购书总价,服务器端将会抛出账户资金不够的异常,Struts的Action Bean截获到异常后,将错误信息显示到页面上。
因为本例账户资金为300.00元,而图书的总价为358.00元,所以显示账户资金不足,如图8-48所示。
图8-48 显示账户资金不足
(10)根据用户账户中的资金修改购买数量,如图8-49所示。
图8-49 根据账户资金修改购买数量
(11)修改数量后重新提交,显示购买成功,如图8-50所示。
图8-50 购买成功
成功提交后,需要检查购书信息是否存到了数据库。
(12)ORDER表记录了总的购书信息,如图8-51所示。
图8-51 ORDER表
(13)ORDER-ITEM表记录了详细的购书信息,如图8-52所示。
图8-52 ORDER-ITEM表
2.购物车系统时序图
图8-53是实现上面业务的时序图,显示了实现业务逻辑时的类之间的调用顺序关系。
图8-53 购物车系统时序图
3.购物车系统具体实现步骤
下面是实现图8-53所示时序图的具体步骤。
(1)用户单击“shoppingCart.do”链接时,Struts的ActionServlet通过config.xml配置将会指向ShoppingCart.jsp的页面。
(2)用户单击【Submit】按钮时,Struts会通过config.xml配置调用Shopping- CartAction类的execute()方法,并将购物车信息存到OrderDTO和OrderItemDTO类中。
(3)RegistrationAction类的execute()方法调用BookStoreMgrImp类的create- Order()的方法和createOrderItem()的方法。
(4)BookStoreMgrImp类的saveUserInfo()方法调用WSDL所生成的接口的ServiceLocator去调用相应的SOA Service Integration Buses的入站服务。
(5)Service Integration Buses的入站服务调用相应的Web Service。
(6)Web Service调用Session Bean(BKStoreMgr)的createOrder ()和create- OrderItem()的方法。
(7)Session Bean调用Entity Bean CMP(OrderCMP和OrderItemCMP)将总的购书信息和详细的购书信息记录到数据库中。
8.5 在Websphere RAD上创建Entity Bean CMP、
Session Bean和Web Service
在创建了数据库和完成所有的设计工作之后,就可以用本书第7章所讲述的方法在Websphere RAD上创建相应的Entity Bean CMP和Session Bean,然后将Session Bean发布成相应的Web Service了。下面是RAD的创建结果。
RAD所创建的网上书店的Session Bean和CMP如图8-54所示。
图8-54 RAD所创建的网上书店的Session Bean和CMP