Jdon框架開發指南


Jdon框架快速開發指南

開發主要步驟如下:

  1. JdonFramework6.0以上兩步開發見這里
  2. 快速配置指南
  3. 新增/查詢/修改/刪除(CRUD);
  4. 批量查詢和分頁顯示

本文Step By Step詳細講解如何使用Jdon框架基於領域模型快速開發這兩個功能,通過Jdon框架的可以快速完成系統原型(ArcheType),使得開發者將真正精力集中在每個項目系統的特殊業務處理。

本案例源碼下載

按這里查看更詳細全面文檔

快速配置指南

Jdon框架有一個配置文件叫jdonframework.xml,其中配置的是我們編寫的Java類,格式如下:

<pojoService name="給自己類取的名稱" class="完整類的名稱"/>

配置有兩個基本項:name和class,class中寫全POJO的全名;name是供代碼中調用這個服務的名稱。

或者使用Annotation注解@Service或@Component,就無需上面這個配置。

假如我們編寫了一個類TestServicePOJOImp,代碼簡要如下:

//@Service("testService")
public class TestServicePOJOImp implements TestService{

   private JdbcDAO jdbcDao;

   public TestServicePOJOImp(JdbcDAO jdbcDao) {
         this.jdbcDao = jdbcDao;
   }

   public void createUser(EventModel em) {
      ....
   }
 }

接口TestService代碼:

public interface TestService {

   void createUser(EventModel em);

}




上面TestServicePOJOImp代碼創建完成后,下面有兩個並行步驟:

1. 如果在TestServicePOJOImp類前加上@Service注解,就可以了,無需再XML配置。

2.如果你為了更加松耦合,在未來更換類時,不再重新編譯源碼,那么可以采取XML配置這個步驟,我們在源碼目錄需要創建一個叫jdonframework.xml配置文件,內容如下:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE app PUBLIC "-//JDON//DTD Framework 2005 1.0 //EN" "http://www.jdon.com/jdonframework.dtd">
<app>
   <services>
      <pojoService name="testService"                            class="com.jdon.framework.test.service.TestServicePOJOImp"/>
   </services>
</app>


這樣,在servlet或jsp或struts的action等客戶端代碼中,我們可以使用如下代碼調用TestServicePOJOImp,注意:以下代碼沒有具體TestServicePOJOImp類:


TestService testService = (TestService) WebAppUtil.getService("testService ", request);
testService.createUser(em);

 

以上步驟,只是簡單展示框架的一個簡要步驟,你可能沒有覺得多了一個jdonframework.xml以后,好像比平常代碼沒什么不同,關鍵是:如果我們需要使用AnotherTestServicePOJOImp更換原來的TestServicePOJOImp類,只需要更改jdonframework.xml文件,而無須更改客戶端代碼,也無須重新編譯項目了。

 

 

當然,還有另外一個優點,就是Ioc/DI依賴注射,細心的人已經注意到TestServicePOJOImp有一個構造參數如下:
   public TestServicePOJOImp(JdbcDAO jdbcDao) {
         this.jdbcDao = jdbcDao;
   }
如果不傳入JdbcDAO實例,我們如何能在客戶端代碼中直接創建TestServicePOJOImp實例呢?原來只要我們在jdonframework.xml中再配置一個JdbcDAO類,概時框架就會自動幫我們創建JdbcDAO實例,並且傳入TestServicePOJOImp實例中。
新的jdonframework.xml內容如下:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE app PUBLIC "-//JDON//DTD Framework 2005 1.0 //EN" "http://www.jdon.com/jdonframework.dtd">
<app>
   <services>
      <pojoService name="testService"                            class="com.jdon.framework.test.service.TestServicePOJOImp"/>

      <!-- 新增加的配置:jdbcDAO是被TestServiceImp調用的,是為其服務的。 -->
      <component name="jdbcDAO" class="com.jdon.framework.test.dao.JdbcDAO"/>
   </services>
</app>


再進一步,如果我們經常遇到一些類中需要一些常量或參數定義,那么可以使用如下配置:


<component name="jdbcDAO" class="com.jdon.framework.test.dao.JdbcDAO">
     <constructor value="java:/TestDS"/>
</ component >?

這時,要求JdbcDAO構造參數有一個字符串和參數,這樣constructor的值java:/TestDS就在JdbcDAO被創建時注射到它的實例中。 JdbcDAO代碼如下:

public class JdbcDAO{

...... 
   public JdbcDAO(String jndiName){
         System.out.println("jndiname" = jndiName); 
         ......

   }

...... 
}

原來圖如下(圖中UserReposotoryInMEN相當於JdbcDAO HellpServiceImp相當於TestServicePOJOImp):

di

啟動Jdon框架

有了jdonframework.xml,我們需要在項目中啟動它,有兩種啟動方式:一個是結合struts的struts-config.xml配置方式;另外一個是不結合struts的web.xml配置方式。


第一:web.xml配置方式:
如果你不使用Struts,可以通過web.xml下列配置來啟動Jdon框架。


<context-param>
   <param-name> modelmapping-config </param-name>
   <param-value> jdonframework.xml </param-value>
</context-param>
……
<listener>
   <listener-class>com.jdon.container.startup.ServletContainerListener</listener-class>
</listener>

上述param-value可以配置多個配置,中間以逗號隔開,如下:



<context-param>
   <param-name>modelmapping-config </param-name>
   <param-value>com.jdon.framework.test.model.models.xml,
                           com.jdon.framework.test.service.services.xml,
                           com.jdon.framework.test.dao.dao.xml</param-value>? 
</context-param> 

第二:結合struts配置方式(需要struts基礎知識):

struts-config.xml中配置Plugin實現子類:


<plug-in className="com.jdon.strutsutil.InitPlugIn">
   <set-property property="modelmapping-config" value="jdonframework.xml" />
</plug-in>

按這里查看更詳細全面文檔

 

增刪改查(CRUD)和批量分頁查詢是每個系統的基本功能,下面分這兩部分描述。

CRUD開發步驟

說明:每個應用系統中存在大量重復的CRUD開發流程,通過本框架可快速完成這些基本基礎工作量,將精力集中在特殊功能設計上。 CRUD快速開發主要簡化了表現層的流程,將其固化,或者是模板化,以配置替代代碼編制,靈活而快速。每個Model一套固化CRUD流程。

CRUD開發步驟分兩個部分:代碼編寫 、配置。

CRUD代碼:

代碼只需要三步: 
1、域建模:建立UserTest類如下:

//@Model
public class UserTest extends Model {
    private String userId;
    private String name;

   public String getName() { return name; }
   public void setName(String name) { this.name = name; }

   .......
}

注意點:

  • 模型必須以@Model標注
  • 或者繼承框架的com.jdon.controller.model.Model,或者實現com.jdon.controller.model.ModelIF接口。
  • 該模型類必須有一個能夠標識其對象唯一性的主鍵,如userId,這個主鍵相當於數據表的主鍵,這個規定符合Evans DDD規定。

為了激活 Domain Model的對象實例駐留內存緩存中,在持久層模型類創建時,加入下面標注:

@Component()
@Introduce("modelCache")
public class UserDAOJdbc implements UserRepository{

   @Around
   public UserTest getUser(String Id) {

        ...... //fetch from key-value stores or relation DB

   }

}

   DCI:數據Data, 場景Context, 交互Interactions是由MVC發明者Trygve Reenskaug發明的。 見 DCI架構是什么? DCI讓我們的核心模型更加簡單,只有數據和基本行為。業務邏輯等交互行為在角色模型中 在運行時的場景,將角色的交互行為注射到數據中。

     JdonFramework的Domain Events是DCI的交互行為,在實現領域事件的同時也實現了DCI。

     為更清楚說明DCI,下面以JdonFramework案例說明。

     領域模型是DCI的Data,只有數據和基本行為,更簡單,但注意不是只有setter/getter的貧血模型。如下:

 

@Model
public class UserModel {

     private String userId;
     private String name;

     @Inject
     private ComputerRole computerRole;

 

 

     Domain Events事件或消息的生產者也就是DCI中的角色Role,比如我們有一個專門進行計數計算的角色,實際上真正計算核心因為要使用關系數據庫等底層技術架構,並不真正在此實現,而是依托消息消費者@Consumer實現,那么消息生產者可以看出是一個接口,消費者看成是接口的實現:

 

@Introduce("message")
public class ComputerRole {

     @Send("computeCount")
     public DomainMessage computeCount(UserModel user) {
          return new DomainMessage(user);
     }

     @Send("saveUser")
     public DomainMessage save(UserModel user) {
          return new DomainMessage(user);
     }

}

 

DCI第三個元素是場景Context,在這個場景下,ComputeRole將被注入到模型UserModel中,實現計數計算的業務功能:

public class ComputeContext {

    private DomainMessage ageAsyncResult;

     public void preloadData(UserModel user) {
          if (ageAsyncResult == null)
               ageAsyncResult = user.getUserDomainEvents().computeCount(user);
     }

     public int loadCountNow(UserModel user) {
          preloadData(user);
          return (Integer) ageAsyncResult.getEventResult();
     }

     public int loadCountByAsync(UserModel user) {
          if (ageAsyncResult == null)
               ageAsyncResult = user.getUserDomainEvents().computeCount(user);
          else if (ageAsyncResult != null)
               return (Integer) ageAsyncResult.getEventResult();
          return -1;

     }

}

 


2、建立Model組件服務:首先建立模型的服務接口TestService:

public interface TestService {
   void createUser(EventModel em); 
   void updateUser(EventModel em);
   void deleteUser(EventModel em);
   UserTest getUser(String userId);
}

至於TestService的具體實現子類可以在現在或者以后建立

3、建立Model的表現層邊界模型UserActionForm,必須繼承框架的ModelForm,如下:

public class UserActionForm extends ModelForm {

   private String userId;
   private String name;

   public String getName() { return name; }
   public void setName(String name) { this.name = name; }

....
}

表現層UserActionForm內容基本上是從業務層模型UserTest類中拷貝過來的,屬於界面對象,用來顯示或錄入數據。

 

一個模型的CRUD實現的代碼工作到此結束,如果有其他模型,完全按照上述三個步驟再做一次,是不是不太費腦筋?有點模板化開發味道?下面談談CRUD實現第二組成部分

CRUD配置:

兩個配置文件分別是:

  • 將前面三步編寫的類建立關系:jdonframework.xml
  • 配置界面流程:struts-config.xml

一、Jdon框架配置文件

首先我們將前面三步編寫的三個類:模型UserTest、服務TestService和界面模型UserActionForm建立起聯系,也就是告訴Jdon框架這三者是解決一個模型增刪改查CRUD功能實現的。 由於這個配置文件是告訴Jdon框架的,因此,我們取名為jdonframework.xml,當然你也可以取其他名稱,無論取什么名稱,都要告訴Jdon框架,在struts-config.xml中配置:

<plug-in className="com.jdon.strutsutil.InitPlugIn">
   <set-property property="modelmapping-config"                            value="jdonframework.xml" />
</plug-in>

jdonframework.xml配置內容如下:


<models>
   <model key="userId" 
         class ="com.jdon.framework.test.model.UserTest">
      <!-- configuration about UI Form: UserActionForm -->
      <actionForm name="userActionForm"/>
         <handler>
            <!-- configuration about the Model service : TestService -->
            <service ref="testService"> 
                  <getMethod name="getUser" />
                  <createMethod name="createUser" />
                  <updateMethod name="updateUser" />
                  <deleteMethod name="deleteUser" />
         </service>
       </handler>
   </model>

   ......
</models>
<services>
   <!-- the Ioc configuration about TestService -->
   <pojoService name="testService" 
         class="com.jdon.framework.test.service.TestServicePOJOImp"/>

   ......
</services>

以上配置是配置模型UserTest、模型服務TestService和界面模型UserActionForm三者關系的,下面詳細說明三個部分的配置:

1、模型UserTest的配置:
這是通過第一行中的class值來指定當前Model是com.jdon.framework.test.model.UserTest:

<model key="userId" class ="com.jdon.framework.test.model.UserTest">

其中,UserTest模型的主鍵是userId,這個userId必須是UserTest類的一個字段;同時是用來唯一標識唯一的UserTest模型對象,也就是Object ID,或者可以認為是模型UserTest對應的數據表的主鍵。

2、界面模型UserActionForm配置:

<actionForm name="userActionForm"/>

可能你已經注意到:這里並沒有寫界面模型完整類:com.jdon.framework.test.web.UserActionForm, 那么配置中userActionForm名稱是從哪里來的呢?是struts-config.xml中ActionForm定義名稱,如下:

<struts-config>
   <form-beans>   
      <form-bean name="userActionForm"                            type="com.jdon.framework.test.web.UserActionForm" />
      …… 
   </form-beans>
….. 
</struts-config>

可見我們的界面模型完整類com.jdon.framework.test.web.UserActionForm是在struts-config.xml中form-beans中配置,並且命名為userActionForm,而這個userActionForm就是jdonframework.xml中的userActionForm。

3、模型服務TestService配置:
在jdonframework.xml中首先申明TestService完整實現是類com.jdon.framework.test.service.TestServicePOJOImp,並且取名為testService:
<pojoService name="testService" class="com.jdon.framework.test.service.TestServicePOJOImp"/>
這樣,我們就可以詳細將我們自己編寫的testService的CRUD方法名告訴Jdon框架了:


<handler>
   <!-- this will refer to service: testService-->   
   <service ref="testService"> 

         <!--getUser is the method name of testService -->
         <getMethod name="getUser" />

         <!--createUser is the method name of testService -->
         <createMethod name="createUser" />

         <!--updateUser is the method name of testService -->
         <updateMethod name="updateUser" />

          <!--deleteUser is the method name of testService -->
         <deleteMethod name="deleteUser" />

      </service>
</handler>

黑體字部分正是testService所指的接口TestService四個方法,可見前面代碼步驟第二步。

二、界面流程配置

界面流程主要是配置CRUD界面流程,Jdon框架CRUD流程主要分兩個部分:第一是推出供用戶新增修改刪除的頁面;第二是接受用戶提交新增修改過的數據,以便遞交到業務層保存。
這部分配置主要是配置struts-config.xml
1、配置推出CRUD頁面流程:


<action name="userActionForm" path="/userAction"          type="com.jdon.strutsutil.ModelViewAction"
         scope="request" validate="false">
                  <forward name="create" path="/user.jsp" />
                  <forward name="edit" path="/user.jsp" />
</action>

其中com.jdon.strutsutil.ModelViewAction是Jdon框架類。只要客戶端瀏覽器調用http://localhost:8080/userAction.do,通過上述配置將激活forward的name=”create”流程,就能得到一個空白表單的頁面user.jsp;如果客戶端瀏覽器調用http://localhost:8080/userAction.do?action=edit&userId=18,通過上述配置將激活forward name=”edit”流程,得到一個填滿數據的表單頁面,供用戶修改。

2、配置:接受用戶提交新增修改過的數據,以便遞交到業務層保存:


<html:form action="/userSaveAction.do" method="POST" >

<html:hidden property="action"/> <!-- this is a rule -->

userId:<html:text property="userId"/>
<br>Name:<html:text property="name"/>
<br><html:submit property="submit" value="Submit"/>
</html:form>

其實在上一步的user.jsp中已經使用到這一步的配置,在user.jsp的表單action值就是本步配置的path值:/userSaveAction.do:


<action name="userForm" path="/userSaveAction"         type="com.jdon.strutsutil.ModelSaveAction"
        scope="request" validate="true" input="/user.jsp">
                <forward name="success" path="/result.jsp" />
                <forward name="failure" path="/result.jsp" />
</action>

在上面user.jsp中一定要有<html:hidden property="action"/>一行。至此,模型UserTest的CRUD功能開發完畢。

 

批量分頁查詢實現

批量分頁查詢開發步驟也分兩個部分:代碼編寫 、配置。

批量查詢代碼實現:

代碼也分三步實現。
1、表現層編寫一個查詢Action,繼承Jdon框架的com.jdon.strutsutil.ModelListAction,該類名稱為com.jdon.framework.test.web.UserListAction,完成getPageIterator和findModelByKey兩個方法。
其中getPageIterator方法內容是業務層TestService的調用:


TestService testService = (TestService)                                  WebAppUtil.getService("testService",request);
return testService.getAllUsers(start, count);

所以TestService接口中必須有getAllUsers這個方法,主要功能是返回PageIterator對象
findModelByKey方法內容也是業務層TestService的調用:


TestService testService = (TestService)                                WebAppUtil.getService("testService", request);
return testService.getUser((String)key);

TestService接口中必須有getUser方法。

2、業務層實現TestService接口方法getAllUsers內容,一般是直接調用持久層JdbcDao方法。

3、持久層實現返回PageIterator對象:


public PageIterator getUsers(int start, int count) throws Exception {
        String GET_ALL_ITEMS_ALLCOUNT =
                "select count(1) from usertest ";//usertest是數據表名
        String GET_ALL_ITEMS = 
               "select userId from usertest ";//usertest是數據表名
        return pageIteratorSolver. getPageIterator (GET_ALL_ITEMS_ALLCOUNT, GET_ALL_ITEMS, "",start, count);
}

如果有參數,可以如下查詢:


public PageIterator getUsers(Long categoryId, int start, int count) {
       String GET_ALL_ITEMS_ALLCOUNT =
                  "select count(1) from usertest where categoryId = ? ";
       String GET_ALL_ITEMS = 
                   "select userId from usertest where categoryId = ? ";
       Collection params = new ArrayList(1);
       params.add(categoryId);//paramters will be put into Collection
       return pageIteratorSolver.getPageIterator(GET_ALL_ITEMS_ALLCOUNT,                                                  GET_ALL_ITEMS, params, start, count);
}

批量查詢配置

一、Jdon框架配置文件

本步驟主要是需要告訴jdonframework.xml我們的TestService實現子類是什么,以及調用的JdbcDao等組件,jdonframework.xml如下:


<services>
       <pojoService name="testService"                               class="com.jdon.framework.test.service.TestServicePOJOImp"/>
       <component name="jdbcDAO"                               class="com.jdon.framework.test.dao.JdbcDAO"/> 
       <component name="constants" class="com.jdon.framework.test.Constants">
              <constructor value="java:/TestDS"/>
       </component> 
</services>

因為TestServicePOJOImp類中調用了JdbcDAO,JdbcDAO中又涉及JNDI名稱,所以它們之間依賴關系靠Jdon框架的IOC容器實現。TestServicePOJOImp必須有構造器如下:


public class TestServicePOJOImp implementsTestService{

       private JdbcDAO jdbcDAO;

       public TestServicePOJOImp(JdbcDAO jdbcDAO){

              this.jdbcDAO = jdbcDAO;

       }

}

二、界面流程配置

這一步主要是struts-config.xml配置,和通常struts的ActionForm和Action配置類似:


<form-beans>
……
<form-bean name="listForm" type="com.jdon.strutsutil.ModelListForm" />
</form-beans>

其中com.jdon.strutsutil.ModelListForm是框架批量查詢特別使用的類。


<action name="listForm" path="/userListAction" 
       type="com.jdon.framework.test.web.UserListAction" 
       scope="request">
              <forward name="success" path="/userList.jsp" />
</action>

其中UserListAction是我們前面代碼編寫部分編寫的代碼。這樣,客戶端瀏覽器通過http://localhost:8080/userListAction.do就可以實現所有UserTest批量分頁查詢顯示。
注意,userList.jsp中編碼和通常Struts的Jsp編碼是一樣的,需要使用logic:iterator從ActionForm為listForm的list字段中獲取單個的UserTest對象,然后顯示這些單個UserTest對象,,如下:


<logic:iterate indexId="i" id="user" name="listForm" property="list" >

       <bean:write name="user" property="name" />

       .........

</logic:iterate

在userList.jsp中加入下面標簽庫可以自動顯示多頁,缺省一個頁面顯示30個條目。


<MultiPages:pager actionFormName="listForm"       page="/userListAction.do">

       <MultiPages:prev name="[Prev ]" />
       <MultiPages:index displayCount="1" />
       <MultiPages:next name="[Next ]" />
</MultiPages:pager>

模型UserTest的批量查詢功能已經全部完成。

以上是介紹基於開源Jdon框架開發軟件系統中的CRUD和批量查詢功能步驟,遵循模板化開發,開發人員使用起來輕松而不容易出錯,適合軟件生產和嚴格的項目管理。

本案例源碼下載

按這里查看更詳細全面文檔

附件:本案例代碼結構圖:

pp

本案例全部代碼(struts+jdon+jpa/hibernate架構):

 

業務模型類代碼

@Entity
public class UserTest extends Model {

      private String userId;
      private String name;
      @Id
      public String getUserId() {
            return userId;
      }

      public String getName() {
            return name;
      }

      public void setUserId(String userId) {
      this.userId = userId;
      }

      public void setName(String name) {
      this.name = name;
      }       
}

持久層代碼

public class JdbcDAO extends DaoTemplate {

private final static Logger logger = Logger.getLogger(JdbcDAO.class);

      public JdbcDAO(CacheManager cacheManager, DaoCRUD daoCRUD) {
            super(cacheManager, daoCRUD);
      }

      public PageIterator getModels(int start, int count) throws Exception{
            String GET_ALL_ITEMS_ALLCOUNT = "select count(1) from usertest ";
            String GET_ALL_ITEMS = "select userId from usertest ";
            return pageIteratorSolver.getDatas("", GET_ALL_ITEMS_ALLCOUNT,                   GET_ALL_ITEMS, start, count);
      }

}

業務層服務代碼
基本是委托持久層操作的簡單代碼

public class TestServicePOJOImp implements TestService, Poolable{
      private final static Logger logger = Logger
            .getLogger(TestServicePOJOImp.class);
      private final static String USER_SAVE_ERROR = "USER.SAVE.ERROR";

      private JdbcDAO jdbcDao;

      public TestServicePOJOImp(JdbcDAO jdbcDao) {
            this.jdbcDao = jdbcDao;
      }

      public void createUser(EventModel em) {
            UserTest user = (UserTest) em.getModel();
            try {      
                  jdbcDao.insert(user);
            } catch (Exception ex) {
                  logger.error(ex);
                  em.setErrors(USER_SAVE_ERROR);
            }

      }

      public void updateUser(EventModel em) {
            UserTest user = (UserTest) em.getModel();
            try {
                  jdbcDao.update(user);
            } catch (Exception ex) {
                  logger.error(ex);
                  em.setErrors(USER_SAVE_ERROR);
            }

      }

      public void deleteUser(EventModel em) {
            UserTest user = (UserTest) em.getModel();
            try {
                  jdbcDao.delete(user);
            } catch (Exception ex) {
                  logger.error(ex);
                  em.setErrors(USER_SAVE_ERROR);
            }

      }      

      public UserTest getUser(String userId) {
            logger.debug(" get User from DAO + JDBC " + userId);
            return (UserTest)jdbcDao.loadModelById(UserTest.class, userId);

      }

      public PageIterator getAllUsers(int start, int count) {
            PageIterator pageIterator = null;
            try {
                  pageIterator = jdbcDao.getModels(start, count);
            } catch (Exception ex) {
                  logger.error(ex);
            }
            return pageIterator;
            }

      }

表現層代碼

public class UserListAction extends ModelListAction {
      private final static Logger logger = Logger.getLogger(UserListAction.class);

      public Model findModelByKey(HttpServletRequest request, Object key) {
            Model model = null;
            try {
                  logger.debug("get the model for primary key=" + key + " type:"+                         key.getClass().getName());
                  TestService testService = (TestService)                         WebAppUtil.getService("testService", request);
                  model = testService.getUser((String)key);
            } catch (Exception ex) {
                  logger.debug("get the model for primary key=" + key + " type:"+                               key.getClass().getName());
                  logger.error(" error: " + ex);
            }
            return model;

      }

      public PageIterator getPageIterator(HttpServletRequest request, int start,
      int count) {
            PageIterator pageIterator = null;
            try {
                  TestService testService = (TestService)                         WebAppUtil.getService("testService", request);
                  pageIterator = testService.getAllUsers(start, count);
            } catch (Exception ex) {
                  logger.error(ex);
            }
            return pageIterator;
            }
      }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM