13.4.3 事务管理
13.4.3 事务管理
与所有的Java EE应用类似,本系统的事务管理负责管理业务逻辑组件里的业务逻辑方法,只有对业务逻辑方法添加事务管理才有实际意义,对于单个DAO方法(基本的CRUD方法)增加事务管理是没有太大实际意义的
下面是本应用中事务管理的配置代码:
1 | <!-- JDBC事务管理器 --> |
借助于Spring Scheam所提供的tx命名空间的帮助,系统可以非常方便地为业务逻辑组件配置事务管理。其中,tx命名空间下的<tx:annotation-driven/>元素用于支持事务注解, transaction-manager属性用于指定使用哪个事务管理器。之后就可以在Java类中使用@Transactional注解给Spring的Bean添加事务管理了。
13.4.2 实现业务逻辑组件
13.4.2 实现业务逻辑组件
业务逻辑组件负责实现系统所需的业务方法,系统有多少个业务方法,业务逻辑组件就提供多少个对应方法,业务逻辑方法完全由业务逻辑组件负责实现。
业务逻辑组件只负责业务逻辑上的变化,而持久层上的变化则交给DAO层负责,因此业务逻辑组件必须依赖于DAO组件。
为了简化分页功能,设计了一个分页的JSP标签,只需要在页面使用分页标签,就可以完成所有页面的分页功能。下面是分页标签的源代码:
PageModel.java
1 | package org.fkit.hrm.util.tag; |
PagerTag.java
1 | package org.fkit.hrm.util.tag; |
要使用JSP的标签还需要在WEB-INF下增加一个tld标签文件。
page.tld
1 | <?xml version="1.0" encoding="utf-8"?> |
HrmService.java
下面是HrmService接口的源代码。
1 | package org.fkit.hrm.service; |
HrmService接口中是本系统所有业务逻辑方法的定义,下面是这些业务逻辑方法的实现:
HrmServiceImpl.java
1 | package org.fkit.hrm.service.impl; |
在HrmServiceImpl类中实现了服务接口HrmService中定义的所有业务逻辑方法并且在HrmServiceImpl类上使用了两个注解
1 | @Transactional( |
Transactional注解说明
1 | @Transactional( |
表示该类需要Spring加入事务,
propagation = Propagation.REQUIRED表示:有事务就处于当前事务中,没有事务就创建一个事务isolation = Isolation.DEFAULT表示:使用事务数据库的默认隔离级别
Service注解说明
@Service("hrmService")注解表示将该类配置成一个Spring的Bean,标识符是hrmService。
Autowired注解说明
@Autowired。在HrmServiceImpl类中业务方法的实现依赖于DAO组件,在配置文件中使用的XML:<mybatis:scan base-package="org.fkit.hrm.dao"/>会将orgfkit.hrm.dao文件夹下的所有MyBatis文件配置成Spring的Bean,Bean的id就是文件的类的名称。@Autowired注解默认使用byType自动装配将6个持久层的DAO注入给HrmServiceImpl类对应依赖的DAO组件。
13.4 实现Service持久层 13.4.1 业务逻辑组件的设计
13.4 实现Service持久层
本系统只使用了一个业务逻辑组件:HrmService。该组件作为门面封装6个DAO组件,系统使用这个业务逻辑组件将这些DAO对象封装在一起.
13.4.1 业务逻辑组件的设计
业务逻辑组件是DAO组件的门面,所以也可以理解为业务逻辑组件需要依赖于DAO组件,DAO组件与HrmService(业务逻辑组件)直接的关系如图13.3所示。

在HrmService接口中定义了大量的业务方法,这些方法的实现依赖于DAO组件。由于每个业务方法要涉及多个DAO操作,DAO操作是单条数据记录的操作,而业务逻辑方法的访问,则需要涉及多个DAO操作,因此每个业务逻辑方法可能需要涉及多条记录的访问。
业务逻辑组件面向DAO接口编程,可以让业务逻辑组件从DAO组件的实现中分离。因此业务逻辑组件只关心业务逻辑的实现,无须关心数据访问逻辑的实现。
10.7 本章小结
10.7 本章小结
本章介绍了一个完整的前端开发+后端整合项目,内容覆盖系统数据库设计,系统分析、设计,系统DAO层设计,业务逻辑层设计等。本章的应用是对传统Java EE应用的改进,而不是一个简单的前端应用。本应用还利用Spring AOP机制解决了前端控制器的权限检查问题。
此外,本应用还整合了Spring 的邮件支持和任务调度功能。当用户竞价成功后,系统会向用户发送确认邮件;任务调度模块则周期性地检查系统中的拍卖物品,一旦发现某拍卖物品超过了拍卖的最后期限,系统会修改该物品的状态。
本应用的前端综合使用了jQuery和Bootstrap两个框架。其中Bootstrap负责生成用户界面,Bootstrap提供了大量CSS样式用于简化界面开发,也提供了大量UI控件来”组装”界面;而jQuery则提供了与服务器端的异步交互能力,jQuery既可以以异步方式向服务器提交请求,也可以以异步方式从服务器获取数据,此外,jQuery的DOM支持则允许开发者动态加载、更新服务器的响应数据。
10.6.9 参与竞价
10.6.9 参与竞价
如果单击图10.22所示的物品的链接,将触发goPage()函数加载addBid.html,并将当前物品赋值给curBidItem变量,这样程序可以在竞拍页面上回显当前竞拍的物品。addBid.html页面主要用于显示当前竞拍物品的详情,并提供一个表单控件供用户输入竞价的价格。下面是addBid.html页面的代码。
1 | <script src="js/addBid.js"></script> |
该页面使用静态表单控件回显当前竞拍物品的信息,此外页面还提供了一个表单控件让用户输入竞拍价格,和一个隐藏域记录当前物品ID。而该页面加载的JS脚本将会读取curBidItem变量的信息,并将当前竞拍物品的信息回显在当前页面中。
单击某个物品名,将看到如图10.23所示的界面。
在图10.23所示的界面的下方,用户可以输入竞拍价格参与竞拍。如果单击”竞价”按钮,将会触发表单提交,但jQuery会接管表单的提交行为,改为使用异步方式提交表单。该页面的JS脚本代码如下。
程序清单:codes\10\auction\WebContent\js\addBid.js
1 | $(function () { |
该JS脚本的第一段代码读取curBidItem变量的数据,并将这些数据加载在页面中显示。
10.6.8 浏览拍卖物品
10.6.8 浏览拍卖物品
用户可以浏览当前正在拍卖的物品。在浏览正在拍卖的物品时,必须先选择想浏览的物品种类。系统通过一个列表框来显示系统中所有的物品种类,当用户单击某个物品种类时,该种类下的所有物品将显示在页面上。当用户单击”浏览拍卖物品”链接时,将进入浏览物品的模块。这时应该先获取当前物品种类,并将所有物品种类加载在页面中供用户选择。
下面是浏览拍卖物品的页面代码。
程序清单:codes\10\auction\WebContent\viewInBid.html
1 | <script src="js/viewInBid.js"></script> |
页面中的粗体字代码用于加载、显示当前系统的物品种类,当用户通过该下拉列表选择指定种类时,系统将会获取该种类下所有物品信息,并将它们加载、显示在下面的表格内。
下面是该页面所包含的JS脚本。
程序清单:codes\10\auction\WebContent\js\viewInBid.js
1 | $(function () { |
第一段代码调用jQuery的get()方法向auction/getAllKind发送请求,该地址将会返回当前系统中所有种类信息。接下来回调函数把所有物品种类加载、显示在下拉列表中。
然后为页面上下拉列表的"change"绑定事件处理函数,当用户改变下拉列表的选项时,会触发该事件处理函数。粗体字代码向auction/getItemsByKind发送请求,该地址会根据物品种类来获取拍卖物品信息,系统会将返回的指定种类下的所有物品信息加载、显示在表格中。
通过上面的代码可以看出,单击”浏览拍卖物品”链接时并未获取任何物品信息,而只是将当前的所有物品种类加载到了kindSelect 列表框中。如果用户单击”浏览拍卖物品”链接,将看到如图10.21所示的界面。
如果用户单击的物品种类下没有对应的拍卖物品,系统将弹出提示框。如果用户单击的种类下有相应的拍卖物品,将看到如图10.22所示的界面。
如图10.22所示,物品列表中的物品名是一个超链接,单击该链接将显示对应物品的详细信息,并可对该物品竞价。
10.6.7 查看自己的竞价记录
10.6.7 查看自己的竞价记录
如果当前用户已经登录,则还可以查看自己的所有竞价记录。用户单击”查看自己竞标“链接时,系统将会通过goPager()函数异步加载viewBid.html 页面,该页面只是一个简单的表格页面。该页面代码如下。
程序清单:codes\10\auction\WebContent\viewBid.html
1 | <script src="js/viewBid.js"></script> |
该页面所包含的JS将会异步获取用户所有的竞价记录,并将竞价记录动态显示在页面中。下面是该页面所包含的JS脚本代码。
程序清单:codes\10\auction\WebContent\js\viewBid.js
1 | $(function() { |
粗体字代码将会向auction/getBidByUser发送异步请求,该地址将以JSON格式返回所有的竞价记录。接下来jQuery将把所有竞价记录迭代并显示在页面上。
如果用户没有登录,则查看竞价记录时将被拦截器拦截,并弹出提示,告诉用户必须先登录系统。如果用户已经登录系统,则查看竞价记录时将看到如图10.20所示的界面。
10.6.6 查看竞得物品
10.6.6 查看竞得物品
当用户单击页面上方的”查看竞得的物品“链接时,如果用户还未登录系统,将弹出提示信息,告诉用户应先登录系统;如果用户已经登录了本系统,系统通过goPager()函数加载viewSucc.html页面。该页面只是一个简单的表格页面,用于显示用户所有赢取的物品。
该页面代码如下。
程序清单:codes\10\auction\WebContent\viewSucc.html
1 | <!-- 该js会向服务器请求数据,并更新表格 --> |
该表格只包含一个表格头,表格的内容将会由jQuery异步获取并加载。该页面所包含的viewSucc.js脚本的代码如下。
程序清单:codes\10\auction\WebContent\js\viewSucc.js
1 | $(function() { |
从上述代码可以看出,该页面向auction/getItemByWiner发送请求,该地址将会以JSON格式返回当前用户所竞得的全部物品。接下来jQuery会迭代并显示从服务器端返回的全部物品信息。
如果当前用户已经赢取了某些物品,则当用户单击”查看竞得物品”链接时,将看到如图10.19所示的界面。
10.6.5 管理物品种类
10.6.5 管理物品种类
如果用户单击页面上方的”管理种类”链接,将进入管理物品种类模块。用户在这里会先看到系统包含的所有物品种类。用户单击”管理种类”链接时,系统会调用goPager函数导航到viewCategory.html页面,该页面用于查看当前系统的所有物品种类。viewCategory.html页面代码如下。
程序清单:codes\10\auction\WebContent\viewCategory.html
1 | <script src="js/viewCategory.js"></script> |
从以上代码可以看出,该页面只是一个简单的.panel容器,该容器中包含一个表格,用于显示系统中所有的物品种类。
为了获取系统中所有的物品种类,系统会向auction/getAllKind发送请求,该请求是通过jQuery发送的异步请求。下面是该页面包含的JS脚本。
程序清单:codes\10\auction\WebContent\js\viewCategory.js
1 | // 异步加载所有物品种类 |
从粗体字代码可以看出,该JS脚本会向auction/getAllKind发送请求,该请求将会获取系统物品种类,服务器则以JSON格式返回所有物品种类。接下来jQuery会迭代所有种类信息,并将它们显示在页面上。
进入浏览物品种类的页面,可以看到如图10.17所示的界面。
如果用户单击该界面右上角的"+"按钮,将会触发goPager()函数加载addCategory.html页面,该页面是一个添加物品种类的表单页面。表单页面代码如下。
程序清单:codes\10\auction\WebContent\addCategory.html
1 | <script src="js/addCategory.js"></script> |
该页面只是一个简单的表单页面,当在页面中提交表单时,系统将会使用jQuery的post()方法向服务器发送异步请求,该过程由JS脚本完成。下面是该JS脚本代码。
程序清单:codes\10\auction\WebContent\js\viewCategory.js
1 | // 异步加载所有物品种类 |
从粗体字代码可以看出,该JS脚本会向auction/getAllKind发送请求,该请求将会获取系统物品种类,服务器则以JSON格式返回所有物品种类。接下来jQuery会迭代所有种类信息,并将它们显示在页面上。
进入浏览物品种类的页面,可以看到如图10.17所示的界面。
如果用户单击该界面右上角的"+"按钮,将会触发goPager()函数加载addCategory.html页面,该页面是一个添加物品种类的表单页面。表单页面代码如下。
程序清单:codes\10\auction\WebContent\addCategory.html
1 | <script src="js/addCategory.js"></script> |
该页面只是一个简单的表单页面,当在页面中提交表单时,系统将会使用jQuery的post()方法向服务器发送异步请求,该过程由JS脚本完成。下面是该JS脚本代码。
程序清单:codes\10\auction\WebContent\js\addCategory.js
1 | $(function () { |
该代码中采用异步请求的方式提交整个表单数据,向auction/addKind 发送异步请求,该地址则负责处理添加种类的请求。
当用户添加种类成功后,系统将弹出提示框,告诉用户添加种类成功,如图10.18所示。
如果用户单击提示框中的”确定”按钮,系统将停留在添加种类的表单页面,让用户可以继续添加种类;如果用户单击”取消”按钮,系统将返回种类列表页面,这样可以在添加种类成功后,立即在页面上看到新增的物品种类。