首    页 建模架构 设计模式 培训咨询 jdon框架 论坛

上一级 首页 下一级


批量分页查询快速开发

原理

批量查询由于是频繁操作,对系统性能设计要求很高,而且批量查询几乎存在每个数据库信息系统,因此,这个功能具有可重用性,Jdon框架根据Jive等传统成熟系统批量查询设计原理,总结多个应用系统,在不破坏多层情况下,抽象出批量查询子框架。

批量查询设计两个宗旨:

尽量减少数据库访问,减少数据库负载和I/O性能损耗。

由于J2EE是一个多层结构,尽量减少在多个层次之间传送的数据量。减少传送损耗。

因此,批量查询设计将涉及到两个层面:表现层和持久层,Jdon框架提供了持久层下JDBC查询操作模板(JdbcDao),这个JdbcDao可以被服务层不同服务类型(POJO ServiceSession Bean)调用。

根据批量查询设计宗旨,有下面实现要点:

使用缓存减少数据库访问

持久层不能将满足查询条件的每页所有完整数据记录传送到表现层,试想一下,如果一条数据记录有1000个字节,那么一页显示20条,那么就有2万个字节传送,目前很多批量查询设计都是这样做,存在浪费内存和性能消耗大的隐患。

缓存越靠近用户界面端,性能越好,因此,持久层如果只传送满足查询条件的数据记录主键(一个字段)集合,那么表现层可以优先从缓存中根据主键获得该数据完整数据,查询越频繁使用,缓存击中率越高,各方面消耗就越小。

根据以上设计原则,Jdon框架的批量查询设计方案如下:

对于持久层:

·            获取满足查询条件的所有数据表记录总个数。

·            获取当前页面所有数据记录主键集合(ID集合)。

·            将上述两种数据打包成一个对象(PageIterator)传送到前台

对于表现层:

·            获得后台满足查询条件的PageIterator对象。

·            遍历PageIterator对象中的主键集合,根据主键再查询后台获取完整数据对象(Model),先查询缓冲,如果没有,再访问数据库。

·            将获取的完整数据对象(Model)封装成一个集合,打包成ModelListForm对象。

·            Jsp页面再展开ModelListForm对象中Model数据集合,逐条显示出来。

批量查询的主要示意图:

图中解释:后台将满足查询条件的数据记录的主键集合(ID集合)包装成PageIterator对象,然后由服务层返回到表现层(通过ModelListAction调用服务EJBServicePOJO ServicegetPageIterator方法),表现层的ModelListAction再遍历这个ID集合,根据每个ID查询获得完整Model数据,再打包到ModelListForm对象中。

批量查询框架基于一个前提是:每个Model有一个主键,就象每个数据表设计都有主键一样,如果你的Model没有主键怎么办?那么使用强制给它一个Object ID,这可以由一个专门序列器产生。这与前面CRUD实现的前提是一致的。

重要对象PageIterator

从前面批量查询原理中看出,PageIterator实际是一个在多层之间穿梭的数据载体,前后台关系只是靠PageIterator来实现消息交互。

因此,无论后台持久层使用什么技术(JDBC、实体BeanHibernateiBatis),只要能提供一个查询结果对象PageIterator给前台就可以。

考虑到持久层技术发展极快,Jdon框架并没有在持久层的缺省实现,但提供了JDBC实现的帮助API(见包:com.jdon.model.query),具体可参考Jdon框架源码包Samples目录下JdonNewsnews.ejb.dao. JdbcDao。这个JdbcDao虽然为EJB Session Bean调用,也可以为普通的POJO服务调用,JdbcDao开发也有模板化,一般是一个Model完成三个方法,具体可见“在JBuilder下开发Struts+Jdon+EJB”章节的“批量查询持久层实现”。

Jdon-Jpetstore中,批量查询持久层实现是使用iBatis,然后在服务层将iBatisPaginatedList类转换成Jdon框架的PageIterator即可。

com.jdon.controller.model.PageIterator类代码如下:

public class PageIterator implements Iterator, Serializable {

 

  public final static Object[] EMPTY = new Object[0];

 

  private int allCount = 0; //符合查询条件的所有Model总数

  private Object[] keys; //符合查询条件的当前页面的ModelID集合

  private int currentIndex = -1; //遍历当前页面时的记录指针

  private Object nextElement = null; //下一个记录

 

  private int start;  //当前页面在所有符合查询条件中开始点

  private boolean hasNext;  //是否有下一页

  //以上两个参数是有关页为单位的信息

 

  /**

   * 完整的构造器

   * allCount PageIterator重要参数

   */

  public PageIterator(int allCount, Object[] keys, int start, boolean hasNext) {

    this.allCount = allCount;

    this.keys = keys;

    this.start = start;

    this.hasNext = hasNext;

  }

 

  /**

   * 当前页面的构造器

   * allCount PageIterator重要参数,也需要赋值,

   * 因为其值对于每个页面是一样的,所以可使用本构造方法构造后,再从缓存

   * 中读取allCount 使用setAllCount延迟赋值

   */

  public PageIterator(Object[] keys, int start, boolean hasNext) {

    this.allCount = 0;

    this.keys = keys;

    this.start = start;

    this.hasNext = hasNext;

  }

 

  /**

   * 空构造器

   * 使用本构造器可防止没有符合查询条件时,Jsp页面报出nullException讨厌错误。

   */

  public PageIterator() {

      this.allCount = 0;

      this.keys = EMPTY;

      this.start = 0;

      this.hasNext = false;

    }

   …..

}

 

持久层参考APIPageIteratorSolver

Jdon框架提供了PageIterator创建的持久层创建APIcom.jdon.model.query.PageIteratorSolver,这是一个基于SQLJDBC实现,当然你完全可以其他持久层技术实现创建PageIterator

使用Jdon框架的PageIteratorSolver提供JDBC模板操作,在查询功能上几乎无需写JDBC语句。使用PageIteratorSolver可以书写很少代码就实现一种Model的批量分页查询功能,PageIteratorSolver可以被Session Bean调用,或者作为普通POJO被调用,缺省情况下PageIteratorSolver不会配置在Jdon框架容器中。

PageIteratorSolver创建有两种方式:

第一种:直接newPageIteratorSolver提供两种构造器,具体参考其API,一种构造器可以更换缓存器,另外一种是缺省的;这两种构造器都需要DataSource作为构造参数。如下:

      ServiceLocator sl = new ServiceLocator(); //Jdon框架中的ServiceLocator

      DataSource  dataSource = (DataSource) sl.getDataSource("java:/NewsDS");

      PageIteratorSolver  pageIteratorSolverOfType = new PageIteratorSolver(dataSource);

因为PageIteratorSolver中包含缓存器,因此,你可以为每个Model建立一个对应的PageIteratorSolver对象,这样,该Model更新时,只要刷新这个Model相关的缓存,具体可见下面缓存清除方法。

第二种,将PageIteratorSolver作为POJO Service配置在jdonframework,xml,然后通过组件实例方式获得(如果它的调用者是以组件服务方式获得)。

创建PageIterator

首先,根据批量查询原理,首先要查询符合查询条件的记录总数和当前页面的所有ModelID集合,这是通过PageIterator的创建实现。

PageIteratorSolver 中重要方法getPageIterator是为了创建一个PageIterator对象,需要的输入参数相当比较复杂,这里详细说明一下:

getPageIterator方法如下:

public PageIterator getPageIterator(String sqlqueryAllCount,

            String sqlquery, String queryParam, int start, int count) throws Exception

注意:PageIteratorSolvergetDatasgetPageIterator实则一样,getPageIterator名称或参数都显得易懂正规一些。

public PageIterator getDatas(String queryParam, String sqlqueryAllCount,

                               String sqlquery, int start,

                               int count) throws Exception

 

首先从String sqlqueryAllCount参数解释:

sqlqueryAllCount参数其实是一个sql语句,该sql语句用来实现查询满足条件的所有记录的总数。例如查询某个表myTablesql语句如下:

String   sqlqueryAllCount   =  "select count(1) from myTable ";

当然这是一个标准sql语句,后面可写入where等查询条件

sqlquery参数则是关键的查询语句,主要实现批量查询中查询符合条件的数据记录(Model)的主键ID集合。例如表myTable的主键是id,则

String sqlquery =  “select  id  from T_ myTable where categoryId = ?”

 

重要规定:

getPageIterator方法两个重要参数就是上面的sqlqueryAllCountsqlquery两条SQL语句,批量查询的事先对这两条SQL语句返回值有规定:sqlqueryAllCount中返回的必须是满足查询条件的总数(count(1))sqlquery必须是满足查询条件的所有主键集合(id)

 

 

queryParam参数则是和sqlquery参数相关,如果sqlquery语句中有查询条件“?”,如上句categoryId = ??的值就是queryParam参数,这样sqlqueryqueryParam联合起来形成一个查询语句。如果没有查询条件,那么queryParam就赋值为null""

注意,如果查询条件有多个“?”,那么就需要将这些queryParam打包成一个Collection,然后调用方法:

public PageIterator getPageIterator(String sqlqueryAllCount,

          String sqlquery, Collection queryParams, int start, int count) throws Exception

这个方法与前面的getDatas区别就是方法参数由String queryParam变成集合 queryParamsqueryParams是多个查询条件“?”的集合,注意,查询条件目前Jdon框架支持常用的几种查询参数类型:String Integer Float Long,例如,如果你的查询条件如下:

String sqlquery = select  id  from T_ myTable where categoryId = ? and name = ?

这里有两个查询参数,那么将这两个查询参数打包到数组中即可,注意顺序和问号的顺序是一样,如果问号对应的变量categoryIdValuenameValue,则如下

Collection queryParams = new ArrayList();

queryParams.add(categoryIdValue);

queryParams.add(nameValue);

 

参数startcount则是有表现层传入的,start表示当前页面是从所有符合查询条件记录中第几个开始的,而count则是从start开始查询多少条记录个数,也就是一页显示的记录数目。

单个Model查询

前面已经获得PageIterator对象,Jdon框架会在ModelListAction中遍历这个PageIterator对象中ID集合,然后根据ID先从缓存中获取完整Model数据,如果没有则从数据库获得,那么我们在持久层还需要提供单个Model查询的实现。

Jdon框架已经内置查询模板,无需使用者自己实现JDBC语句操作,直接使用模板即可,以JdonNewsModel NewsType查询一个实例为例子:

首先确定sql语句写法,如下:

String GET_TYPE = "select  * from T_NEWS_TYPE where typeid = ?";

其中typeid参数值由外界传入,因此写方法如下:

  public NewsType getNewsType(String Id) throws Exception {

    String GET_TYPE = "select  * from T_NEWS_TYPE where typeid = ?";

    List queryParams = new ArrayList();

    queryParams.add(Id); //IdGET_TYPE sql语句中的?的值

   

    …..

}

上述代码准备了JDBC模板查询两个参数:GET_TYPEqueryParams

调用PageIteratorSolver中的两个Model查询方法:

  //适合查询返回结果是单个字段,如:

  // select name from user where id=?

  public Object querySingleObject(Collection queryParams, String sqlquery)  throws Exception ;

 

  //适合查询返回结果是多个字段,而且有多项记录

  //例如:select id, name, password from user where id = ?

  public List queryMultiObject(Collection queryParams, String sqlquery)  throws Exception ;

这两个方法适合不同的查询语句,当你的查询sql语句返回不只一条数据记录,而且每条数据记录不只是一个字段,而是多个字段,使用queryMultiObjectqueryMultiObject经常使用。下面是获得一个Model查询的完整写法:

  public NewsType getNewsType(String Id) throws Exception {

    String GET_TYPE = "select  * from T_NEWS_TYPE where typeid = ?";

    List queryParams = new ArrayList();

    queryParams.add(Id);

    

    NewsType ret = null;

    try {

      List list = pageIteratorSolverOfType.queryMultiObject(queryParams, GET_TYPE);

      Iterator iter = list.iterator();

      if (iter.hasNext()) {//遍历查询结果,根据你的判断,决定这里使用ifwhile

        Map map = (Map)iter.next(); //List中每个对象是一个Map

        ret = new NewsType();

        ret.setTypeName((String)map.get("typename")); //根据字段名称从Map中获取其相应值

        ret.setTypeId(Id);

      }

    }

    catch (Exception se) {

      throw new Exception("SQLException: " + se.getMessage());

    }

    return ret;

  }

缓存清除

由于PageIteratorSolver内置了缓存,缓存两种情况:

符合查询条件的所有记录总数,这个总数第一次使用后将被缓存,不必每次都执行select count的数据操作,这是很耗费数据性能的。

当前页面中所有ModelID集合,在没有新的Model被新增或删除情况下,这个ID集合几乎是不变的,因此其结果在第一次被使用后将被缓存。

但是,某个Model发生新增或删除情况下,我们要主要清除这些缓存,否则新增或删除的Model将不会出现在Model列表中,PageIteratorSolver缓存设计前提是Model的新增和删除不会很频繁,至少没有查询频繁。

PageIteratorSolverclearCache()提供主动缓存清除。

我们需要在Model的新增方法或删除方法中,在这些方法成功后,主动调用PageIteratorSolverclearCache方法。

因为Model的新增或删除方法是由程序员自己实现,如使用CMPHibernate等实现,因此需要注意加入clearCache方法。

我们建议PageIteratorSolver创建依据每个Model有一个对应的PageIteratorSolver对象,这样,这个Model变动只会清除它的有关缓存;如果所有Model共用一个PageIteratorSolver对象,一旦一个Model变动将引起所有缓存清除,降低缓存效益。

其他形式PageIterator创建

上面是使用Jdon框架的JDBC模板实现PageIterator创建,你有可能使用其他技术实现持久层,这里提供两种PageIterator创建的参考代码:

例如,productDao是封装了别的持久层技术(iBatisHibernate)。要求两步就可以完成PageIterator创建:

第一步. productDao返回符合条件的当前页面ID集合:

  List list = productDao.getProductIDsListByCategory(categoryId, start, count);

第二步. productDao返回符合条件的总数:

  int allCount = productDao.getProductIDsListByCategoryCount(categoryId);

创建PageIterator代码如下:

 int currentCount = start + list.size();//计算到当前页面已经显示记录总数

 PageIterator pageIterator = new PageIterator(allCount, list.toArray(), start,

                        (currentCount < allCount)?true:false);

 

以上代码是在服务层实现,一旦服务层能够返回一个PageIterator实例,就可以按照下面表现层实现完成批量分页查询功能。

另外一个PageIterator创建实现,假设所有数据ID或数据模型包装在一个List中,从List中创建PageIterator的代码如下:

        //计算未显示记录个数

        int offset = itemList.size() - start;

        int pageCount = (count < offset)?count:offset;

        //生成当前页面的List

        List pageList = new ArrayList(pageCount);

        //start开始遍历,遍历次数是一页显示个数

        //将当前页面要显示的数据取出来放在pageList

        for(int i=start; i< pageCount + start;i++){

            pageList.add(itemList.get(i));

        }

        int allCount = itemList.size();

        int currentCount = start + pageCount;

        PageIterator pageIterator = new PageIterator(allCount, pageList.toArray(), start,

                (currentCount < allCount)?true:false);

表现层实现:

前面章节主要谈论了批量查询的持久层实现,Jdon框架的批量查询主要在表现层封装了主要设计原理,让我们看看表现层Struts的实现步骤:

ModelListForm

 

这里以查询商品类别(Category)下所有商品(Product)列表为需求,演示批量的查询的开发步骤。

使用Jdon框架实现批量查询时,无需使用代码创建ModelFormActionForm),Jdon框架提供一个批量查询的缺省实现:com.jdon.strutsutil.ModelListForm

只要在struts-config.xml中配置这个ActionForm就可以:

 <form-bean name="productListForm" type="com.jdon.strutsutil.ModelListForm"/>

习惯地,我们将这个ActionForm命名为:

model名称+ListForm

例如,查询商品列表是显示一个商品Prodcut数据,那么这个ActionForm的名称就是productListForm

ModelListForm是一个普通的JavaBeans,主要属性如下:

public class ModelListForm extends ActionForm{

 

  private int allCount = 0;  //符合查询条件的所有记录总数

  private int start = 0;   //当前页面的开始

  private int count = 20;  //当前页面的可显示的记录数

  private boolean hasNextPage = false;  //是否有下一页

 

  /**

   * Model

   */

  private Model oneModel = null;

 

  /**

   * 批量显示的Model集合

   * 这是本类主要的属性

   */

  private Collection list = new ArrayList();

 

  ……

}

 

抽象类ModelListAction

com.jdon.strutsutil.ModelListAction.ModelListAction是一个struts的标准Action,它主要实现如下功能:

从服务层获得符合查询条件PageIterator,这是需要通过getPageIterator方法实现;

展开遍历PageIterator,根据ID,首先从缓存中查询是否有其Model(完整数据记录),如无,则调用服务层从持久层数据库获得,这是需要通过findModelByKey方法实现。

将获得的Model集合封装在ModelListFormlist字段中。

所以,ModelListAction实际是将ID集合换算成Model集合,然后交给ModelListFormJsp页面的显示只和ModelListForm有关。

public abstract class ModelListAction extends Action {

private ModelManager modelManager;

 

//struts action的缺省execute方法

  public ActionForward execute(ActionMapping actionMapping,

                               ActionForm actionForm,

                               HttpServletRequest request,

                               HttpServletResponse response) throws Exception {

    ……

 

    //从服务层获得符合查询条件的PageIterator

    PageIterator pageIterator = getPageIterator(request, start, count);

    if (pageIterator == null) {

      throw new Exception(

          "getPageIterator's result is null, check your ModelListAction subclass");

    }

    //获得ModelListForm实例

    ModelListForm listForm = getModelListForm(actionMapping, actionForm,

                                              request, pageIterator);

    //赋值页面起始数等值到ModelListForm

    listForm.setStart(start);

    listForm.setCount(count);

    listForm.setAllCount(pageIterator.getAllCount());

    listForm.setHasNextPage(pageIterator.isNextPageAvailable());

 

    //根据pageIterator获得Model集合

    Collection c = getModelList(request, pageIterator);

    Debug.logVerbose(" listForm 's property: getList size is " + c.size(), module);

    //Model集合赋值到ModelListFormlist字段

    listForm.setList(c);

    //设置其他ModelModelListForm,以便jsp页面能显示其他Model

    listForm.setOneModel(setupOneModel(request));

    //程序员自己定义的优化ModelListForm其他动作,供实现者自己优化。

  customizeListForm(actionMapping, actionForm, request, listForm);

 

    ……

}

ModelListAction是一个抽象类,它必须有一个实现子类需要有两个方法必须实现:

获得服务层的Pageiterator,也就是getPageIterator方法

根据keyID获得单个Model的方法,findModelByKey方法。

其他可选实现的方法有:

是否激活缓存方法
protected boolean isEnableCache()
有时,批量查询实现可能不需要缓存,获得每个Model都一定要执行findModelByKey方法。通过覆盖isEnableCache方法实现。

批量查询的Jsp页面,可能不只是需要显示某一个Model的很多实例列表;还可能需要其他类型Model实例显示,可以覆盖方法:

protected Model setupOneModel(HttpServletRequest request)

自己再优化加工ModelListForm方法,覆盖方法:

public void customizeListForm(ActionMapping actionMapping,

                                    ActionForm actionForm,

                               HttpServletRequest request,

                              ModelListForm modelListForm ) throws Exception

通过以上方法覆盖实现,基本使用ModelListAction可以实现批量查询的各种复杂功能实现,如果你觉得还不行,那么干脆自己模仿ModelListAction自己实现一个标准的strutsAction子类,只要ActionForm还是ModelListForm,页面显示还是可以使用Jdon框架的页面标签库。

使用ModelListAction可以实现master details,使用setupOneModelcustomizeListForm实现MasterModelListForm则装载的多条显示的details

编写ModelListAction子类

com.jdon.strutsutil.ModelListAction.ModelListAction有两个方法需要实现:

第一.继承getPageIterator方法

public PageIterator getPageIterator(HttpServletRequest request, int start, int count)

这是从服务层获得满足查询条件的当前页面所有ModelID(主键)集合,当前页面是通过start count两个变量说明,前者表示从第几个开始;后者表示开始后需要显示多少个Model

以查询商品为例子,ProductListAction继承ModelListAction,详细方法内容如下:

public class ProductListAction extends ModelListAction {

    public PageIterator getPageIterator(HttpServletRequest request, int start,

            int count) {

        //获得一个服务

        ProductManager productManager = (ProductManager) WebAppUtil.getService(

                "productManager", request);

        //从查询参数中获得categoryId

        String categoryId = request.getParameter("categoryId");

        //调用服务的方法

        return productManager.getProductListByCategory(categoryId);

    }

 

    public Model findModelByKey(HttpServletRequest request, Object key) {

    ……

}

所以,关键在于服务层的服务需要有个返回参数类型是方法,这是对服务层服务方法的约束要求,这个服务方法如何实现在后面章节介绍。

第二. 继承findModelByKey方法

这个方法主要也是从服务层获得一个Model实例,ProductListAction的该方法实现如下:

    public Model findModelByKey(HttpServletRequest request, Object key) {

        //获得一个服务

        ProductManager productManager = (ProductManager) WebAppUtil.getService(

                "productManager", request);

        return productManager. getProduct ((String)key);

    }

非常需要注意的是:需要搞清楚这里获得Model实例是哪个?

是商品类别Category 还是商品Product

这主要取决于你的批量查询显示的是什么,如果希望显示的是商品Product列表,当前这个案例是需要查询某个商品类别Category下的所有商品Product列表,那么这里的Model类型就是Product

搞清楚Model类型是Product后,那么我们可能对findModelByKey方法参数Object类型的key有些疑问,其实这个key就是com.jdon.controller.model. PageIterator中重要属性keys(满足查询条件的ID集合)中的一个元素,这里根据key查询获得一个完整Model,所以♂知道,PageIterator中封装的不是普通ID,而是以后需要根据这些ID能够获得唯一一个Model,所以key其实是Model主键,也是数据表的主键。

以上述案例为例:

productManager. getProduct ((String)key);

这是将key类型Object强制转换为String类型,因为PageIteratorkeysID集合)都是String类型。所以, key的类型其实是由你后台创建PageIterator时决定的。

第三其他方法:

以上面例子为例,商品批量查询除了显示多个商品Product信息外,还需要显示商品目录Category,也就是说在一个页面中,不但显示多个商品,也要显示商品目录的名称,比如商品目录名是“电器”,其下具体商品列表很多。

在一个页面中装入一个以上Model有两种方法:

1. 配置另外一个需要装入ModelActionForm,例如Category对应的ActionFormCategoryForm,只要在struts-config.xml中配置CategoryFormscopesession,同时注意CategoryForm在操作流程中要预先赋值。

2. 由于批量查询的ActionFormModelListForm,我们可以向这个ModelListForm加入一个Model,实现ModelListActioncustomizeListForm方法, 在这个方法中,实现将Category加入的语法::

public void customizeListForm(ActionMapping actionMapping,

                                    ActionForm actionForm,

                               HttpServletRequest request,

                              ModelListForm modelListForm ) throws Exception{

        ModelListForm listForm = (ModelListForm) actionForm;

        ProductManager productManager = (ProductManager) WebAppUtil.getService(

                "productManager", request);

        String categoryId = request.getParameter("categoryId");

        Category category = productManager.getCategory(categoryId);

        listForm.setOneModel(category);

}

如果加入的布置一个Model,那么可以使用DynamicModel将那些Model装载进来,然后在Jsp页面再一个个取出来。

struts-config.xml配置

批量查询与jdonframework.xml配置无关,也就是说jdonframework.xml中没有与批量查询实现相关的配置,简化了工作,这点与CRUD实现相反,CRUD更多的是jdonframework.xml配置(当然都少不了struts-config.xml配置),CRUD缺省情况下除了ModelModelForm以外可以没有表现层编码,而批量查询主要是表现层编码,由于查询条件多种多样,只有靠更多编码才能实现查询的灵活性。

上例子中,商品查询的ModelListForm配置如同一般ActionForm一样配置:

  <form-beans>

    <form-bean name="productListForm" type="com.jdon.strutsutil.ModelListForm"/>

    ……

   </form-beans>

ProductListAction配置如同一般Action一样:

<action-mappings>

            <action path="/shop/viewCategory"

      type="com.jdon.framework.samples.jpetstore.presentation.action.ProductListAction"

      name="productListForm" scope="request"

      validate="false" >

      <forward name="success" path="/catalog/Category.jsp"/>

    </action>

    ……

</action-mappings>

 

Jsp MultiPages标签

剩余最后工作就是Jsp标签使用,通过使用strutslogic:iterator将前面配置的productListForm中的Model集合遍历出来。遍历标签语法如下:

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

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

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

</logic:iterate>

上述语法将逐个输出每行记录,如果配合Htmltable语法,输出效果如下:

批量查询输出还有一个重要功能:页面显示,如上图的“前页”和“后页”显示,这是使用Jdon框架的标签库实现的。

只要在Jsp页面中你希望显示“前页”和“后页”部位贴入下面代码即可:

<%@ taglib uri="/WEB-INF/MultiPages.tld" prefix="MultiPages" %>

 

…..

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

<MultiPages:prev>Prev</MultiPages:prev>

<MultiPages:index />

<MultiPages:next>Next</MultiPages:next>

</MultiPages:pager>

这是一个MultiPages标签,注意标签使用方法前提:

1. Jsp页面头部需要声明该标签:

<%@ taglib uri="/WEB-INF/MultiPages.tld" prefix="MultiPages" %>

2. web.xml中有声明解释该标签库文件所在位置:

<taglib>

    <taglib-uri>/WEB-INF/MultiPages.tld</taglib-uri>

    <taglib-location>/WEB-INF/MultiPages.tld</taglib-location>

  </taglib>

这表示Jsp中的uri定义/WEB-INF/MultiPages.tld实际是执行本地文件/WEB-INF/ MultiPages.tld,那么在你的Web项目的WEB-INF下必须要有MultiPages.tld文件,可以从Jdon框架源码包目录src\META-INF\tlds下将MultiPages.tld拷贝过去即可,有些开发工具如JBuilder在配置了框架功能后,会自动在建立Web项目时拷贝这些标签库的。

下面说明一下批量查询的MultiPages标签使用方法:

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

其中actionFormName是你在struts-config.xml中配置的ModelListForm名称,也就是这段配置中的name值:

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

MultiPages中的page是指当前页面是通过哪个action调用产生的,这样,在显示多页其它页面也可以调用这个action,这里是/userListAction.do,很显然,这个/userListAction.do是你的struts-config.xml中的action配置中的path值,如下:

<action name="listForm" path="/userListAction" type="com.jdon.framework.test.web.UserListAction"

scope="request">

      <forward name="success" path="/userList.jsp" />

 </action>

上述配置中的typecom.jdon.framework.test.web.UserListAction是你的ModelListAction实现子类。如果你的查询是条件的,也就是说/userListAction.do后面有查询参数,那么你也需要写在MultiPages后面,如:

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

paramId="catId" paramName="catId">

 

MultiPages标签的其它配置很简单,无需变化,如下:

<MultiPages:prev>Prev</MultiPages:prev>

<MultiPages:index />

<MultiPages:next>Next</MultiPages:next>

MultiPages:prev是显示“前页”的标签,Prev是显示“Prev”,你可以使用图标或汉字来替代Prev

<MultiPages:index/>是自动显示 1 2 3 …多个数字。目前只提供数字显示。

MultiPages:nextMultiPages:prev类似,显示“后页”字样。

MultiPages:prev MultiPages:next还有另外一种写法,如下:

<MultiPages:prev name="[Prev ]" />

使用了name属性,这样个语法的好处是:当前页面如果没有超过一页,将没有”Prev””Next”字样出现,只有超过一个页面时,才会有相应的字样出现,显示智能化。

 

 



上一级 首页 下一级


更多Jdon框架专题讨论

JdonFramework作为一个免费开源软件开发平台,可以商用开发大多数数据库应用软件和管理软件: 电子商务软件 在线教育软件 税务软件 Web快速开发软件 财务软件 购物车软件 医院帐务软件 crm software medical software 人事薪资软件payroll software 在线购物软件 销售软件 项目管理软件 房产不动产管理软件 生产软件 PDM软件 制造业软件 仓库软件 采购软件 进销存软件 危险源监控软件 物流软件 超市软件 银行软件 保险软件 汽车软件 医疗软件 电子软件 自动化软件 服装软件 烟草软件 分销管理软件 供应商管理软件

下载源码

框架文档

框架应用系统

演示运行

JiveJdon3

性能测试

Q&A 问答

技术支持

 

 

更多标签...



Jdon框架演示

JiveJdon
源码下载

VIP收费区

历史热点讨论排行榜




google yahoo 新浪ViVi 365Key网摘 天极网摘 CSDN网摘 添加到百度搜藏 POCO网摘





手机 add to google add to yahoo
联系我们 | 关于我们 | 广告联系 | 网站地图 | 设为首页

沪ICP证08026060 如有意见请与我们联系 Powered by JdonFramework
_×
您有新消息