`
senton
  • 浏览: 205993 次
  • 性别: Icon_minigender_1
  • 来自: 紫禁城
社区版块
存档分类
最新评论

通用分页实现及其OO设计探讨(强烈推荐)

阅读更多
 
通用分页实现及其OO设计探讨
分页是一种常用的页面数据显示技术,分页能够通过减少页面数据处理量从而提高了系统的性能。分页应该是做WEB开发必须掌握的一个小技术。而分页却是复杂的,倒不是它的技术有多复杂;而是有太多的重复代码,这些代码都难以重用。能不能实现一个通用的分页框架?每次只需要去覆写一两个方法,通过少量的代码就能实现分页的功能?

一、一般分页应该要具有的功能有:
    1.  
灵活的设置分页大小。可以动态的设置分页大小,而不是写死到代码中。
    2.  
自动计算总页数。根据分页大小和总记录数自动计算总页数。
    3.  
获得当前页的页号。
    4.  
获得当前页的总记录数。一般是最后一页的时候可能会小于分页大小。
    5.  
判断当前页是否为第一页。
    6.  
判断当前页是否为最后一页。
    7.  
判断当前页是否有上一页。
    8.  
判断当前页是否有下一页。
    9.  
获得当前页的数据列表。
    10.
获得当前页的第一条记录的索引号
    11.
获得当前页的最后一条记录的索引号。

二、常用的分页技术
   
目前常用的分页技术有两种:
    1.
第一次访问是读取所有记录,放入session中,然后每次从session对象中读取当前页的数据
    2.
每次都访问数据库,从数据库中读取当前页的记录。
   
这两种方法都各有优缺点,当数据量比较少时,第一种方法无疑是要快一些,因为减少与数据库的连接访问。而当数据量比较大时,比如查询结果可能会是上万条,那么内存的开销是十分大的,放到session中还有一个问题是能不能及时的清除无用的对象。而且这么大数据量在网络中传输也会使系统变得很慢。
第二种方法就是专门解决这个问题的,它每次访问数据库,只读取当前页所需的记录,大大的减少网络传输量;它不会把页数据放到session中,大大提高服务器的性能。
所以第二种方式要优于第一种方法。Session不要乱用,要用也仅仅是存放一些公共变量,相对于占用空间比较少的对象。不适合存放大量的数据,否则在很多个用户同时访问时那么系统会很慢,因为服务器内存被销耗的很厉害。
三、通用分页框架需要解决的问题
作为一个通用分页框架,
1应该不依赖于任何其它框架
2应该支持多种数据库
3应该可以应用于任何web框架中,如:struts,spring等。
4应该把数据访问的具体实现留给用户去实现。
5应该实现关键的算法和过程,如:计算总页数,所需的实始化动作。
6应该减化Contrller控制器的代码,以往的分页技术在Contrller中存在太多的       if…else代码。十分难懂,应该由一个辅助类来实现。
7应该减化jsp页面的代码,页面应该没有任何与分页相关的计算。应该由分页对象来实现。
8应该支持两种分页方式,采用session或不采用session由用户控制。
 
四、具体实现
1.
通用分页接口。定义接口可以有更多不同的实现,接口只声明了分页应该具有的公共行为。
ViewPage.java
/**
*
分页接口
*/
public interface ViewPage {



/**
*
获取总页数
* @return
总页数
*/
public int getPageCount();


/**
*
获得页面大小
* @return
页面大小
*/
public int getPageSize();


/**
*
设置页面大小
* @param size
*/
public void setPageSize(int size);
/**
*
获得当前页数据
* @return
数据列表
*/
public List getPageData();


/**
*
获得当前页索引号
* @return
当前页索引号
*/
public int getPageIndex();

/**
*
获得当前页记录总数
* @return
当前页记录总数
*/
public int getPageRows();

/**
*
是否有下一页
* @return
*/
public boolean getHashNextPage();


/**
*
是否有上一页
* @return
*/
public boolean getHashPreviousPage();

/**
*
转到尾页
*
*/
public void gotoLastPage();
/**
*
转到首页
*
*/
public void gotoFirstPage();

/**
*
是否首页
* @return
*/
public boolean isFirstPage();

/**
*
是否尾页
* @return
*/
public boolean isLastPage();

/**
*
转到上一页
*
*/
public void gotoPreviousPage();

/**
*
转到下一页
*
*/
public void gotoNextPage();

/**
*
转到指定页面,pageIndex小于1时,转到第一页;pageIndex大于总页数时,转到最尾页
* @param pageIndex
指定的页号
*/
public void gotoPage(int pageIndex);

/**
*
获取当前页第一条记录的记录号
* @return int
当前页第一条记录的记录号
*/
public int getPageFirstRecord();

/**
*
获取当前页最后一条记录的记录号
* @return int
当前页最后一条记录的记录号
*/
public int getPageLastRecord();

}
 
2分页抽像实现类,实现关键的算法
AbstractViewPage.java
/**
*
分页默认抽象实现
*
初始时,分页类有下列默认值:
*
分页大小为-1,为不分页;
*
总页数为1
*
当前页为第一页
*
总记录数为0
*
当前页数据列表为没有任何记录的列表
*
*/
public abstract class AbstractViewPage implements ViewPage {

//-----------------------------------------
//
私有静态常量
//-----------------------------------------

private static final int DEFAULT_PAGE_INDEX = 1;

private static final int DEFALT_PAGE_COUNT = 1;

private static final int DEFAULT_PAGE_SIZE = -1;

private static final int DEFAULT_ROWS = 0;

//-----------------------------------------
//
私有成员变量
//-----------------------------------------

/**
当前页索引号**/
private int pageIndex = DEFAULT_PAGE_INDEX;
/**
总页数**/
private int pageCount =DEFALT_PAGE_COUNT;

/**
分页大小**/
private int pageSize = DEFAULT_PAGE_SIZE ;

/**
数据总记录数**/
private int rows = DEFAULT_ROWS;


//------------------------------------------
//
本地成员变量getter,setter方法
//------------------------------------------


/**
*
设置新页号,只有大于等于1而且小于等于总页数并且不为当前页时,才允许设置
* @param pageIndex The pageIndex to set.
*/
private void setPageIndex(int newPageIndex) {

if( newPageIndex >= this.DEFAULT_PAGE_INDEX && newPageIndex <= this.getPageCount() && newPageIndex != this.pageIndex) {
this.pageIndex = newPageIndex;
}

}

/**
* @return Returns the rows.
*/
private int getRows() {
return rows;
}

/**
* @param rows The rows to set.
*/
private void setRows(int rows) {
this.rows = rows;
}
/**
* @param pageCount The pageCount to set.
*/
private void setPageCount(int pageCount) {
this.pageCount = pageCount;
}



//--------------------------------------
//
实现Page接口方法
//--------------------------------------


/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageData()
*/
public List getPageData() {
List pageList =null;

//
获得当前页数据
pageList = this.pageList(this.getPageFirstRecord(), this.getPageRows());
//
保证不返回null
if(pageList == null) {
pageList =new ArrayList();
}
return pageList;

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageIndex()
*/
public int getPageIndex() {
return this.pageIndex;
}
/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#isFirstPage()
*/
public boolean isFirstPage() {

return this.DEFAULT_PAGE_INDEX ==this.pageIndex;
}
/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#isLastPage()
*/
public boolean isLastPage() {
//
当前页索引为总页数时为最后一页
return this.pageIndex == this.pageCount;
}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getHashNextPage()
*/
public boolean getHashNextPage() {
//
当前页索引号小于总页数
return this.pageIndex < this.pageCount ;
}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getHashPreviousPage()
*/
public boolean getHashPreviousPage() {
//
当前页索引号大于默认的初始页号,这里为1
return this.pageIndex > this.DEFAULT_PAGE_INDEX ;
}



/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageCount()
*/
public int getPageCount() {

return this.pageCount;
}



/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageSize()
*/
public int getPageSize() {

return this.pageSize;
}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageRows()
*/
public int getPageRows() {
//
当页面大小为-1 ,返回总记录数
if(this.DEFAULT_PAGE_SIZE == this.pageSize ) {
return this.rows;
}

//
不为最后一页时,返回pageSize
if(!this.isLastPage()) {
return this.pageSize;
}
//
最后一页时
return this.rows - (this.pageSize * (this.pageCount -1));
}



/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageFirstRecord()
*/
public int getPageFirstRecord() {

//
页大小为-1
if(this.DEFAULT_PAGE_SIZE== this.pageSize ) {
return 0;
}
return (this.pageIndex -1)* this.pageSize;
}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#getPageLastRecord()
*/
public int getPageLastRecord() {
//
页大小为-1,返回总记录数
if(this.DEFAULT_PAGE_SIZE == this.pageSize) {
return this.rows;
}
return this.getPageFirstRecord() + this.getPageRows() ;
}
/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoFirstPage()
*/
public void gotoFirstPage() {
this.gotoPage(this.DEFAULT_PAGE_INDEX);

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoLastPage()
*/
public void gotoLastPage() {
this.gotoPage(this.getPageCount());

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoPreviousPage()
*/
public void gotoPreviousPage() {
this.gotoPage(this.getPageIndex() -1);

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoNextPage()
*/
public void gotoNextPage() {
this.gotoPage(this.getPageIndex() + 1);

}

/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#gotoPage(int)
*/
public void gotoPage(int newPageIndex) {
if( newPageIndex >= this.DEFAULT_PAGE_INDEX && newPageIndex <= this.getPageCount() ) {
this.setPageIndex(newPageIndex);
}

}
/**
* @see com.palic.elis.pos.junit.counter.web.mvc.ViewPage#setPageSize(int)
*/
public void setPageSize(int size) {
if(size < 1) {
size = 1;
}

this.pageSize = size;

//
进行初始化
this.doInit();
}

//-----------------------------------
//
辅助方法
//-----------------------------------


/**
*
分页初始化方法,为了保证总是能正确的初始化,所以声明为final ,为了让子类可以调用声明为protected
*
*/
protected final void doInit() {
int rows = 0;

//
获得总记录数
rows= totalRows();

//
设置总记录数
this.setRows(rows);
//
设置新的总页数

//
计算并设置总页数
int pages = calculatePageCount();
this.setPageCount(pages);

//
转到第一页
this.gotoPage(this.DEFAULT_PAGE_INDEX);

onInit();
}
/**
*
记算总页数
* @return
总页数
*/
private int calculatePageCount() {

//
总记录数为0条,则返回的总页数为1
if(this.getRows() == 0) {
return this.DEFALT_PAGE_COUNT;
}

//
如果页面大小为-1,则返回的总页数为1
if(this.DEFAULT_PAGE_SIZE == this.getPageSize() ) {
return this.DEFALT_PAGE_COUNT;
}

return this.getRows() / this.getPageSize() + ( this.getRows() % this.getPageSize() ==0 ? 0 :1);
}


/**
*
获得总记录数,调用queryTotalRows(),将异常封装为non-checked 异常
* @return
总记录数
* @throws ApplicationRuntimeException
*/
private int totalRows() throws ApplicationRuntimeException{
try{
return queryTotalRows();
}
catch(Exception ex){
throw new ApplicationRuntimeException(ex);
}
}
/**
*
获得当前页数据,调用queryPageList()方法,将异常封装为non-checked异常
* @param startRow
开始记录号
* @param rowCount
记录总数
* @return
当前页数据
* @throws ApplicationRuntimeException
*/
private List pageList(int startRow, int rowCount) throws ApplicationRuntimeException{
try{
return queryPageList(startRow, rowCount);
}catch(Exception ex){
throw new ApplicationRuntimeException(ex);
}
}


//-----------------------------------------
//
子类实现的方法
//-----------------------------------------

/**
*
初始化附加方法,由子类扩展
*/
protected void onInit() {

}


/**
*
查询获得总记录数,由子类具体实现
* @return
总记录数
* @throws Exception
*/
protected abstract int queryTotalRows() throws Exception;

/**
*
查询当前页数据,startRow 开始的rowCount条记录
* @param startRow
开始记录号
* @param rowCount
记录总数
* @return
当前页数据
* @throws Exception
*/
protected abstract List queryPageList(int startRow, int rowCount) throws Exception;

}
 
3分页辅助类
ViewPageHelper.java
/**
*
分页辅助类,用于减化Controller中的代码
*/
public class ViewPageHelper {
private static final int FIRST_PAGE_VALUE = 1;

private static final int PREVIOUS_PAGE_VALUE = 2;

private static final int NEXT_PAGE_VALUE = 3;

private static final int LAST_PAGE_VALUE = 4;

private static final int SPECIAL_PAGE_VALUE = 5;

public static final String FIRST_PAGE = "FIRST_PAGE";

public static final String PREVIOUS_PAGE = "PREVIOUS_PAGE";

public static final String NEXT_PAGE = "NEXT_PAGE";

public static final String LAST_PAGE = "LAST_PAGE";

public static final String SPECIAL_PAGE = "SPECIAL_PAGE";

/**
分页动作参数名**/
public static final String PAGE_ACTION = "page_action";

/**
分页对象属性名**/
public static final String SESSION_PAGE = "session_page";

/**
页号参数名**/
public static final String PAGE_NO = "page_no";

private static Map actionMap = new HashMap();
static {
actionMap.put(FIRST_PAGE, new Integer(FIRST_PAGE_VALUE));
actionMap.put(PREVIOUS_PAGE, new Integer(PREVIOUS_PAGE_VALUE));
actionMap.put(NEXT_PAGE, new Integer(NEXT_PAGE_VALUE));
actionMap.put(LAST_PAGE, new Integer(LAST_PAGE_VALUE));
actionMap.put(SPECIAL_PAGE, new Integer(SPECIAL_PAGE_VALUE));
}
/**
*
执行分页动作
* @param page
分页对象
* @param action
分页动作参数
* @param pageIndex
页号
*/
public static void doAction(ViewPage page, String action, int pageIndex) {
int actionIndex = 0;
if (page == null) {
throw new NullPointerException("Page
对象null");
}
if (action == null || "".equals(action)) {
throw new IllegalArgumentException("
无效的分页动作参数null");
}
action = action.toUpperCase();
if (!actionMap.containsKey(action)) {
throw new UnsupportedOperationException("
不支持的分页动作参数:" + action);
}
Integer index = (Integer) actionMap.get(action);
actionIndex = index.intValue();
switch (actionIndex) {
case FIRST_PAGE_VALUE:
page.gotoFirstPage();
break;
case PREVIOUS_PAGE_VALUE:
page.gotoPreviousPage();
break;
case NEXT_PAGE_VALUE:
page.gotoNextPage();
break;
case LAST_PAGE_VALUE:
page.gotoLastPage();
break;
case SPECIAL_PAGE_VALUE:
page.gotoPage(pageIndex);
}
}

public static void doAction(ViewPage page, String action){
doAction(page, action, 1);
}
}
五、应用通用分页框架
1
.继承AbstractViewPage类,实现queryPageList(int startRow, int endRow)
queryTotalRows()
方法。

protected int queryTotalRows() throws Exception
获得查询条件的总记录数

protected List queryPageList(int startRow, int rowCount)
用于查询指定范围的数据。startRow为开始记录号, rowCount为查询的记录数

queryPageList(0,20)
为查询从第一条开始的20条记录。

使用Ibatis可以由queryPageList调用queryForList()方法。

/**
*
用户信息分页内部类
*/
class UserInfoPage extends AbstractViewPage{

//------------------------------------------------
//
实现AbstractViewPage抽象类的抽象方法
//------------------------------------------------

/**
* @see com.prs.application.ehld.web.mvc.AbstractViewPage#getPageDate(int, int)
*/
protected List queryPageList(int startRow, int endRow) throws Exception {
return sampleAction.getUserInfoList(startRow, endRow);
}

/**
* @see com.prs.application.ehld.web.mvc.AbstractViewPage#getRows()
*/
protected int queryTotalRows() throws Exception {
return sampleAction.getUserCount();
}

}



3.
Contrller中的实现
public ModelAndView listUser(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String pageAction =
RequestUtils.getStringParameter(request,ViewPageHelper.PAGE_ACTION);
Integer pageIndex =
RequestUtils.getIntParameter(request,ViewPageHelper.PAGE_NO);
//
声明分页对象
ViewPage userPage =
(ViewPage) request.getSession().getAttribute(ViewPageHelper.SESSION_PAGE);
//
第一次请求
if(pageAction == null || userPage == null){
//
构建一个新的分页对象
userPage = new UserInfoPage();
//
设置分页大小
userPage.setPageSize(2);
}else{

if(ViewPageHelper.SPECIAL_PAGE.equals(pageAction)){
//
如果页数为空,则默认为1
if (pageIndex == null)
pageIndex = new Integer(1);
ViewPageHelper.doAction(userPage,pageAction,pageIndex.intValue());
}else{
ViewPageHelper.doAction(userPage,pageAction);
}
}

//
从分页对象中获得当前页数据
List userInfoList = userPage.getPageData();

ModelAndView mav = new ModelAndView(userInfoListView);
mav.addObject(this.userInfoListKey,userInfoList);
request.getSession().setAttribute(ViewPageHelper.SESSION_PAGE,userPage);
return mav;
}
 
4. jsp页面实现

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
<%@ taglib prefix="tiles" uri="http://jakarta.apache.org/struts/tags-tiles" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<title>
显示所有员工</title>

<SCRIPT language="javaScript">
function pageNoChange(pageNo){
location.href= "ehld.sample.getuserinfolist.do?page_action=SPECIAL_PAGE&page_no="+pageNo.value;

}
</SCRIPT>
</head>

<body>
<table width="80%" border="0">
<tr>
<td bgcolor="#F0FEFF"><div align="left"> 
用户列表</div></td>
</tr>
</table>
<br>
<input name="adduser" type="submit" id="adduser" value="
新增用户" onclick="location.href='ehld.sample.edituserinfo.do'">
<table width="80%" border="0">
<tr bgcolor="#58ED64">
<th width="25%">id</th>
<th width="34%">
姓名</th>
<th colspan="2">
操作</th>
</tr>
<c:forEach items="${userInfoList}" var="userInfoDTO">
<tr bgcolor="#D6EBF8">
<td><c:out value="${userInfoDTO.userID}"/></td>
<td><c:out value="${userInfoDTO.userName}"/></td>
<td width="21%"><a href="ehld.sample.edituserinfo.do?id=<c:out value='${userInfoDTO.userID}'/>">
编辑</a></td>
<td width="20%"><a href="#">
删除</a></td>
</tr>
</c:forEach>
</table>
<c:if test="${session_page.firstPage}">
首页
</c:if>
<c:if test="${! session_page.firstPage}">
<a href="ehld.sample.getuserinfolist.do?page_action=FIRST_PAGE">
首页</a>
</c:if>
<c:if test="${! session_page.hashPreviousPage}">
上一页
</c:if>
<c:if test="${session_page.hashPreviousPage}">
<a href="ehld.sample.getuserinfolist.do?page_action=PREVIOUS_PAGE">
上一页</a>
</c:if>

<c:if test="${!session_page.hashNextPage}">
下一页
</c:if>

<c:if test="${session_page.hashNextPage}">
<a href="ehld.sample.getuserinfolist.do?page_action=NEXT_PAGE">
下一页</a>
</c:if>

<c:if test="${session_page.lastPage}">
尾页
</c:if>

<c:if test="${!session_page.lastPage}">
<a href="ehld.sample.getuserinfolist.do?page_action=LAST_PAGE">
尾页</a>
</c:if>

共有<c:out value="${session_page.pageCount}" />,

<select name = "pageNo" onChange = "java script:pageNoChange(this);">
<c:forEach begin="1" end = "${session_page.pageCount}" var = "pageIndex">
<option value="<c:out value='${pageIndex}'/>" <c:if test = "${pageIndex ==session_page.pageIndex }">selected</c:if>>
<c:out value="${pageIndex}"/>
</option>
</c:forEach>
</select>

</body>
</html>
六、设计探讨
1
.通过提供queryTotalRows() queryPageList(int startRow, int rowCount)方法,交由用户具体的去实现,所以能够支持任何数据库。
对于Ibatis用户可以使用queryForList()方法,对于用jdbc实现也可以有多种方法来支持各种数据库。
Ms sql
可以使用top 关键字,来获得指定范围的数据
ORACEL
可以使用rowid 伪列来获得指定范围的数据
具体怎么去读取数据,完全交由用户控制
2.
分页对象与具体的业务对象分离。分页对象如果不能与具体的业务对象分离那么就不可能实现分页对象的重用,不可以实现代码的最大的重用。这不符合oo的按职责来设计对象的原则。
3. ViewPageHelper
帮助类的使用有两个好处,统一为分页代码所需的字符参数进行定义,便于contrllerjsp页面代码的维护。第二便于代码重用,减少在contrller中的if分支句语。如果不使用帮助类,则在每个controller中都会产生大量相同的代码。
4. final
关键字的使用,protected final void doInit()用于分页对象的实始化,它读取并设置总记录数,计算总页数,默认为第一页等。为什么不在构造函数中来做它呢?如果在构造函数来做它,子类就不可以扩展了。像这样的初始化方法的位置应该由扩展类来灵活控制。声明为protected是不让它由外部对象来进行访问,但是子类又可以进行调用。声明为final是为了子类不能重写它,如果子类重写不当就会造成分页对象的执行逻辑错误。但是如果子类又想扩展它怎么办?子类重写protected void onInit()方法就可以了。这样就能保证父类的逻辑,又能够让子类进行扩展。
5.
异常处理的思考,queryTotalRows()queryPageList方法都是要求由子类实现的抽象类,这两个类的特点都是可能会调用业务对象去实现相应的功能,业务对象可能会访问业务数据库等,可能会抛出任何Exception,但是分页对象类去调用queryTotalRows()queryPageList的方法是不应该对这些Exception进行任何处理的,如果进行try…catch那么就会隐藏了异常的细节,这是十分可怕的。如果这些方法抛出异常,分页对象应该是不能处理的,不能处理的异常应该封装为运行时异常,所以就有了下面的实现
private List pageList(int startRow, int rowCount) throws ApplicationRuntimeException{
try{
return queryPageList(startRow, rowCount);
}catch(Exception ex){
throw new ApplicationRuntimeException(ex);
}
}

private int totalRows() throws ApplicationRuntimeException{
try{
return queryTotalRows();
}
catch(Exception ex){
throw new ApplicationRuntimeException(ex);
}
}

分页对象内部调用pageListtotalRows方法,这样就很好的解决了异常的问题,把异常交由外部调用者去决定是否处理,而不是强制调用者去处理。

5.
模板方法模式的使用,这是一个典型的模板方法模式的运用。在父类实现关键的算法代码,实现分页对象的处理逻辑,而把某些会发生改变的方法交由子类去实现,使得子类完全不用去关心父类的实现细节,子类只需要重写两个简单的方法就可以实现父类的功能。这就是模板方法带来的最大好处。模板方法模式在各种开源框架中有着广泛的运用,看看spring的源码就知道。子类只需要去实现自己最关心的细节,而父类实现那些不变的逻辑或算法。
6.
针对接口编程,而不是针对类编程。接口可以实现多重继承,而类却不能。接口有比类获得更多的好处,更利于扩展。比如说分页接口,它可以让用户有更多不同的实现,完全不依赖于任何类。只需要为它定制了共同的行为就可以了。在使用委托的时候接口比抽像类更好用。比如在装饰模式的使用中,可能需要实现一个接口,而其中还要有一个本接口的引用。如果是抽象类,则不可以实现。
7.
通用框架应该具有灵活性,不应该依懒于任何具体的框架。如果通用框架依懒于某一技术细节,某一框架,那么它就有一定的局限性。所以通用分页不应该依懒于ibatishibernate spring的某一特点。更不应该依懒于sqloralce某种数据库。
 
 
分享到:
评论

相关推荐

    通用分页实现及其OO设计探讨(2)

    本话题将深入探讨“通用分页实现及其OO设计”,结合给定的“Paginaction.jsp”文件,我们可以进一步了解在Java Web开发中如何有效地实现分页功能。 首先,我们需要理解分页的基本概念。分页是将大量数据分割成多个...

    java 通用分页 java 通用分页

    Java 通用分页详解 Java 通用分页是指在Java编程中对大量数据进行分页处理,以提高系统效率和性能。下面对Java通用分页的知识点进行详细说明: 1. 分页的必要性 在实际项目中,数据量可能非常大,直接查询所有...

    超强php分页打包 通用分页 万能分页 ajax分页 google分页

    本压缩包“超强php分页打包 通用分页 万能分页 ajax分页 google分页”提供了一系列的分页解决方案,包括了基本的PHP分页、通用的分页实现、以及结合AJAX技术的动态分页,旨在满足各种项目需求。下面将详细介绍这些...

    sql Server 通用分页存储过程

    sql Server 通用分页存储过程 sql Server 通用分页存储过程 sql Server 通用分页存储过程 sql Server 通用分页存储过程

    SSM 实现通用分页

    在这个项目中,"SSM实现通用分页"指的是通过这三个框架来实现数据的分页展示功能,这在大数据量的网页展示中尤为重要,可以有效提升用户体验并减轻服务器压力。 首先,Struts2作为MVC框架,负责处理HTTP请求和响应...

    使用SQL语句实现通用分页查询

    使用SQL语句实现通用分页查询,支持模糊查询等。

    java通用分页代码实例.rar

    这个"java通用分页代码实例"应该包含了上述概念的实现,你可以通过解压"page"文件查看具体代码,学习如何将这些理论应用到实践中。通过学习和理解这个实例,你可以更好地掌握Java中的分页技术,并将其应用于自己的...

    JAVA写的通用分页

    本文将详细探讨"JAVA写的通用分页"这一主题,结合描述中的"通用高效分页存储过程实现",我们将深入理解Java分页的原理、实现方式以及优化策略。 首先,分页的基本概念是将大量数据分块展示,而不是一次性加载所有...

    java web项目分页通用实现

    本DEMO主要展示了如何实现一个通用的分页功能,覆盖了后台和前台的处理逻辑。以下是对这个主题的详细阐述: 一、分页原理 分页的核心原理是通过限制每次查询的数据量,只获取用户当前需要查看的一部分数据,同时...

    通用分页方法接口.rar

    二、设计通用分页接口 一个通用的分页方法接口应该包含以下几个核心元素: 1. **页码(Page Number)**:表示当前请求的页面位置,通常从1开始计数。 2. **每页大小(PageSize)**:定义每一页显示的数据条目数量...

    Mybatis通用分页插件

    Mybatis通用分页插件是Java开发中广泛使用的ORM(对象关系映射)框架扩展,主要针对Mybatis进行优化,提供了高效便捷的分页功能。这个插件的目的是简化在数据库查询时的分页操作,使得开发者能够更专注于业务逻辑,...

    java 分页通用代码

    综上所述,Java实现分页通用代码主要包括创建Page对象、处理分页参数、编写分页SQL、填充Page对象及提供相关辅助方法。在实际项目中,这些组件可以抽象成一个通用的分页工具类或者服务,以提高代码复用性和可维护性...

    SSH通用分页组件 SSH分页

    SSH分页 分页 通用分页 struts2分页

    hibernate 通用分页的实现

    hibernate_mysql_struts2 实现的通用分页类.欢迎指正

    C#通用分页.rar

    描述中没有提供具体信息,但我们可以推测这个压缩包可能包含了一个示例项目或者代码库,用于演示如何在C#和ASP.NET中实现通用的分页功能。这可能包括一个数据库查询、数据绑定到分页控件,以及相关的用户界面设计。 ...

    PHP通用分页程序

    本文将深入探讨PHP分页的实现原理和具体步骤,并通过一个名为“小贤PHP通用分页程序”的实例进行详解。 1. **分页原理** 分页的基本思想是将大量数据分成多个小块(页),每次只加载一部分数据到前端展示,用户...

    封装通用的Spring3+Struts2+JPA的CRUD 通用分页实现

    "封装通用的Spring3+Struts2+JPA的CRUD 通用分页实现"是一个典型的Java Web开发实践,它结合了Spring框架的依赖注入、Struts2的MVC模式以及JPA(Java Persistence API)的数据持久层处理,来实现数据的创建、读取、...

    Java 通用分页

    本文将详细探讨Java中的通用分页实现方法。 首先,我们要理解分页的基本概念。分页主要包括两个关键参数:当前页码(Page Number)和每页显示条数(Page Size)。通过这两个参数,我们可以计算出当前页面应该显示的...

Global site tag (gtag.js) - Google Analytics