工大后院

 找回密码
 加入后院

扫一扫,访问微社区

QQ登录

只需一步,快速开始

搜索
查看: 3296|回复: 8

Jpetstore阅读心得

[复制链接]
发表于 2006-10-14 23:53 | 显示全部楼层 |阅读模式
虽然对Spring不熟悉,又不懂iBatis,还是硬着头皮开始阅读Spring包自带的Jpetstore经典J2EE例子。

开始的时候,只想从大体上理解它的结构,或者说从某个部分开始了解这个经典的宠物店。

首先可以肯定,Jpetstore是按照MVC的模式设计的。持久化层用iBatis(这个我不懂,我多么希望它是用Hibernate啊!),控制器的servlet有两个选择,一个是用Struts,另一个是Spring。这些具体的以后慢慢看,慢慢理解吧。
今天主要了解到,Jpetstore使用了门面模式、单例模式,对数据厍操作用DAO对象。
门面接口 PetStoreFacade
  1. public interface PetStoreFacade {
  2.         Account getAccount(String username);
  3.         Account getAccount(String username, String password);
  4.         void insertAccount(Account account);
  5.         void updateAccount(Account account);
  6.         List getUsernameList();
  7.         List getCategoryList();
  8.         Category getCategory(String categoryId);
  9.         List getProductListByCategory(String categoryId);
  10.         List searchProductList(String keywords);
  11.         Product getProduct(String productId);
  12.         List getItemListByProduct(String productId);
  13.         Item getItem(String itemId);
  14.         boolean isItemInStock(String itemId);
  15.         void insertOrder(Order order);
  16.         Order getOrder(int orderId);
  17.         List getOrdersByUsername(String username);
  18. }
复制代码

门面接口的实现类 PetStoreImpl

  1. public class PetStoreImpl implements PetStoreFacade, OrderService {

  2.         private AccountDao accountDao;

  3.         private CategoryDao categoryDao;

  4.         private ProductDao productDao;

  5.         private ItemDao itemDao;

  6.         private OrderDao orderDao;

  7.         // -------------------------------------------------------------------------
  8.         // Setter methods for dependency injection
  9.         // -------------------------------------------------------------------------

  10.         public void setAccountDao(AccountDao accountDao) {
  11.                 this.accountDao = accountDao;
  12.         }

  13.         public void setCategoryDao(CategoryDao categoryDao) {
  14.                 this.categoryDao = categoryDao;
  15.         }

  16.         public void setProductDao(ProductDao productDao) {
  17.                 this.productDao = productDao;
  18.         }

  19.         public void setItemDao(ItemDao itemDao) {
  20.                 this.itemDao = itemDao;
  21.         }

  22.         public void setOrderDao(OrderDao orderDao) {
  23.                 this.orderDao = orderDao;
  24.         }

  25.         // -------------------------------------------------------------------------
  26.         // Operation methods, implementing the PetStoreFacade interface
  27.         // -------------------------------------------------------------------------

  28.         public Account getAccount(String username) {
  29.                 return this.accountDao.getAccount(username);
  30.         }

  31.         public Account getAccount(String username, String password) {
  32.                 return this.accountDao.getAccount(username, password);
  33.         }

  34.         public void insertAccount(Account account) {
  35.                 this.accountDao.insertAccount(account);
  36.         }

  37.         public void updateAccount(Account account) {
  38.                 this.accountDao.updateAccount(account);
  39.         }

  40.         public List getUsernameList() {
  41.                 return this.accountDao.getUsernameList();
  42.         }

  43.         public List getCategoryList() {
  44.                 return this.categoryDao.getCategoryList();
  45.         }

  46.         public Category getCategory(String categoryId) {
  47.                 return this.categoryDao.getCategory(categoryId);
  48.         }

  49.         public List getProductListByCategory(String categoryId) {
  50.                 return this.productDao.getProductListByCategory(categoryId);
  51.         }

  52.         public List searchProductList(String keywords) {
  53.                 return this.productDao.searchProductList(keywords);
  54.         }

  55.         public Product getProduct(String productId) {
  56.                 return this.productDao.getProduct(productId);
  57.         }

  58.         public List getItemListByProduct(String productId) {
  59.                 return this.itemDao.getItemListByProduct(productId);
  60.         }

  61.         public Item getItem(String itemId) {
  62.                 return this.itemDao.getItem(itemId);
  63.         }

  64.         public boolean isItemInStock(String itemId) {
  65.                 return this.itemDao.isItemInStock(itemId);
  66.         }

  67.         public void insertOrder(Order order) {
  68.                 this.orderDao.insertOrder(order);
  69.                 this.itemDao.updateQuantity(order);
  70.         }

  71.         public Order getOrder(int orderId) {
  72.                 return this.orderDao.getOrder(orderId);
  73.         }

  74.         public List getOrdersByUsername(String username) {
  75.                 return this.orderDao.getOrdersByUsername(username);
  76.         }

  77. }
复制代码

暂时不管 OrderService 接口。
PetStoreImpl的那些setter方法正是spring的注入方法。
在配置文件中:
  1.         <bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl">
  2.                 <property name="accountDao" ref="accountDao"/>
  3.                 <property name="categoryDao" ref="categoryDao"/>
  4.                 <property name="productDao" ref="productDao"/>
  5.                 <property name="itemDao" ref="itemDao"/>
  6.                 <property name="orderDao" ref="orderDao"/>
  7.         </bean>
复制代码

单例模式的实现并没有使用特别的工厂方法。原文这样注释:
* There is one instance of this class in the JPetStore application. In Spring
* terminology, it is a "singleton". This means a per-Application Context
* singleton. The factory creates a single instance; there is no need for a
* private constructor, static factory method etc as in the traditional
* implementation of the Singleton Design Pattern.

使用Spring的BeanFactory,可以轻易实现单例的。在Struts当控制器时,它是这样实现的。
BaseAction 类,整个应用程序的action都不再直接继承自Action类,而是BaseAction 类。
  1. public abstract class BaseAction extends Action {

  2.         private PetStoreFacade petStore;

  3.         public void setServlet(ActionServlet actionServlet) {
  4.                 super.setServlet(actionServlet);
  5.                 if (actionServlet != null) {
  6.                         ServletContext servletContext = actionServlet.getServletContext();
  7.                         WebApplicationContext wac = WebApplicationContextUtils
  8.                                         .getRequiredWebApplicationContext(servletContext);
  9.                         this.petStore = (PetStoreFacade) wac.getBean("petStore");
  10.                 }
  11.         }

  12.         protected PetStoreFacade getPetStore() {
  13.                 return petStore;
  14.         }

  15. }
复制代码

暂时这么多,不知理解是否有误,以后慢慢去理解学习。
 楼主| 发表于 2006-10-15 09:45 | 显示全部楼层
对Struts的ActionForm的使用和对Action的使用类似,先写了个继承自ActionForm的类BaseActionForm,作为其它actionform的基类。

public class BaseActionForm extends ActionForm {

        /* Public Methods */

        public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
                ActionErrors actionErrors = null;
                ArrayList errorList = new ArrayList();
                doValidate(mapping, request, errorList);
                request.setAttribute("errors", errorList);
                if (!errorList.isEmpty()) {
                        actionErrors = new ActionErrors();
                        actionErrors.add(ActionErrors.GLOBAL_ERROR, new ActionError("global.error"));
                }
                return actionErrors;
        }

        public void doValidate(ActionMapping mapping, HttpServletRequest request, List errors) {
        }

        /* Protected Methods */

        protected void addErrorIfStringEmpty(List errors, String message, String value) {
                if (value == null || value.trim().length() < 1) {
                        errors.add(message);
                }
        }

}

为了需要安全检查的验证,还特别写了个SecureBaseAction的类。
  1. public abstract class SecureBaseAction extends BaseAction {

  2.         public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
  3.                         HttpServletResponse response) throws Exception {
  4.                 AccountActionForm acctForm = (AccountActionForm) request.getSession().getAttribute("accountForm");
  5.                 if (acctForm == null || acctForm.getAccount() == null) {
  6.                         String url = request.getServletPath();
  7.                         String query = request.getQueryString();
  8.                         if (query != null) {
  9.                                 request.setAttribute("signonForwardAction", url + "?" + query);
  10.                         } else {
  11.                                 request.setAttribute("signonForwardAction", url);
  12.                         }
  13.                         return mapping.findForward("global-signon");
  14.                 } else {
  15.                         return doExecute(mapping, form, request, response);
  16.                 }
  17.         }

  18.         protected abstract ActionForward doExecute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
  19.                         HttpServletResponse response) throws Exception;

  20. }
复制代码

因为它的身份验证是单一(即没有多种身份多种权限),直接在session中检查是否有帐户。
在有比较多字段需要检查的时候,就在doValidate方法内进行验证(在有些地方,作者选择了直接覆盖execute方法),其它一般都是看看是否为空,所以用了一个通用的方法 addErrorIfStringEmpty(这个方法在BaseActionForm中定义)。
回复

使用道具 举报

 楼主| 发表于 2006-10-15 18:31 | 显示全部楼层

分层结构

从分层角度考虑,我把Jpetstore这样分开来看

DAO层:DAO接口(操作数据对象)
域模型层:持久化实体类(POJO对象)
业务逻辑层:(调用DAO,提供服务,似乎可以称为服务层)
注:这里没有考虑WEB层。

它的包结构如下图所示:
jpetstore.jpg
回复

使用道具 举报

 楼主| 发表于 2006-10-15 23:15 | 显示全部楼层
由于ORM框架使用我不懂的iBatis,我特意去看看它的实现,发现它的JAVABEAN没有像 hibernate 那样与数据库的表一一对应(虽然hibernate有时候不是这样,我还是这样说它)。
比如帐户(Account),在account数据表中的字段并不多,但那个JAVABEAN里属性还是很多的。因为在映射文件作了相应配置。如:
  1.   <select id="getAccountByUsername" resultMap="result">
  2.     select
  3.           signon.username as userid,
  4.           account.email,
  5.           account.firstname,
  6.           account.lastname,
  7.           account.status,
  8.           account.addr1,
  9.           account.addr2,
  10.           account.city,
  11.           account.state,
  12.           account.zip,
  13.           account.country,
  14.           account.phone,
  15.           profile.langpref,
  16.           profile.favcategory,
  17.           profile.mylistopt,
  18.           profile.banneropt,
  19.           bannerdata.bannername
  20.     from account, profile, signon, bannerdata
  21.     where account.userid = #value#
  22.       and signon.username = account.userid
  23.       and profile.userid = account.userid
  24.       and profile.favcategory = bannerdata.favcategory
  25.   </select>
复制代码

如果使用hibernate,通过配置实体的关系,然后使用面向对象的HQL查询就可以,而不用自己写这样的SQL查询语句。
我在想,如果逻辑层的BEAN的属性数据不适合在视图层使用,是否应该使用DTO呢?
虽然这是个经典的J2EE实例,但毕竟算是比较简单的,应该还有好些东西没有用到。

[ 本帖最后由 powerwind 于 2006-10-16 18:57 编辑 ]
df.jpg
回复

使用道具 举报

 楼主| 发表于 2006-10-17 22:46 | 显示全部楼层
今天并没有从Jpetstore的源码中读出什么心得,倒是从《J2EE Development without EJB》这本书的第十六章看到了些对Jpetstore的介绍。发觉我前面发的帖中内容作者都讲到了,可能是太明显重要的东西,也可能因为以前不觉意看了有点印象,然后一看源码就有那种“体会”来了。
    一开始我就希望持久层的ORM框架使用Hibernate,而作者说这样做是为了和原来用iBatis做的版本作比较而已。作者还提到:iBatis可以把不同数据表中的字段映射到单个的对象上。如果数据模型给定,这个技术就非常适合了。而Hibernate目前还不支持这种粗粒度对象。
   我猜想,如果要改成Hibernate的话,由于是细粒度对象,是不是应该要用到TDO来实现层之间的数据传输呢?我还没有打算花时间去修改练习,只能想一下。
   至于作者说到的分布式,目前还没有能力去理解,放着先。
回复

使用道具 举报

 楼主| 发表于 2006-10-18 23:57 | 显示全部楼层
一行一行地读,还是一个类一个类地读?一时间感觉没什么好读。
     于是我决定去看看它的WEB显示层,看看JSP文件。结果发现并没有什么特别,都是HTML和JSTL,极少用到Struts或Spring的标签(其实我也偏爱JSTL标签)。分页显示,只分上一页与下一页这样。看来看去,都觉得很普通。
    几乎每个JSP页面都包含一个头文件和一个尾文件。
   是了,它没有用到 titles 部局。

过两天再想想,再看看,一定还有不少值得学习的地方。
回复

使用道具 举报

发表于 2006-10-22 11:32 | 显示全部楼层
楼主是如何安装PETSTROE的?
回复

使用道具 举报

 楼主| 发表于 2006-10-22 11:57 | 显示全部楼层
很惭愧地告诉楼上的,我安装过,但没成功(登录时出现数据库错误)。
所以现在只是阅读它的代码,没有去执行程序。
回复

使用道具 举报

发表于 2006-11-2 17:25 | 显示全部楼层
楼主你的文章被转载了...
http://java.chinaitlab.com/Spring/529192.html
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入后院

本版积分规则

QQ|Archiver|手机版|小黑屋|广告业务Q|工大后院 ( 粤ICP备10013660号 )

GMT+8, 2025-5-15 07:13

Powered by Discuz! X3.5

Copyright © 2001-2024 Tencent Cloud.

快速回复 返回顶部 返回列表