首页 > 编程语言 > 详细

spring+mybatis 物理分页

时间:2016-01-05 22:18:37      阅读:265      评论:0      收藏:0      [点我收藏+]

新项目用的spring mvc 和 mybatis 分页。研究了一下,集众家之长然后形成现在的项目。我把分页部分剥离出来与大家分享。如有不妥的地方欢迎交流拍砖。

单独做了一个小项目,放到了下载区,如果有用到的朋友可以去下载。

本项目采用了拦截器,就是mybaits自带的plus功能。将每次select操作都进行拦截。

项目架构如下:

技术分享

1:首先从cotroller层出发,啥也不说,上代码。这个最实惠

package com.flydreamer.controller;  
  
import java.util.HashMap;  
import java.util.Map;  
  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Controller;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.servlet.ModelAndView;  
  
import com.flydreamer.logic.UserService;  
import com.flydreamer.page.Page;  
import com.flydreamer.page.PageContext;  
import com.flydreamer.util.web.HandlerResult;  
  
@Controller  
@RequestMapping("/user.do")  
public class UserController {  
      
    @Autowired  
    private UserService userService;  
      
    @RequestMapping(params = ("method=list"))  
    public ModelAndView listAll(HttpServletRequest request,HttpServletResponse response) {  
          
        //可以将分页参数获取封装,已达到更好的复用效果。  
        //page=2&pageSize=10&totalPages=19&totalRows=188  
        String pagec = request.getParameter("page");   
        String pageSize = request.getParameter("pageSize");   
        String totalPages = request.getParameter("totalPages");   
        String totalRows = request.getParameter("totalRows");   
          
        //方法1:将分页参数直接放到mapper接口函数参数中,也可在对象中定义名字为page的属性,反射一样可以得到  
        //后台连接直接获取  
        //Page page = new Page();  
          
        //方法2:不用进行map传参,用ThreadLocal进行传参,方便没有侵入性  
        PageContext page = PageContext.getContext();  
          
        //请自行验证  
        if(null == pagec)  
        {  
            page.setCurrentPage(1);  
            page.setPageSize(10);  
        }  
        else{  
            page.setCurrentPage(Integer.parseInt(pagec));  
            page.setPageSize(Integer.parseInt(pageSize));  
            page.setTotalPages(Integer.parseInt(totalPages));  
            page.setTotalRows(Integer.parseInt(totalRows));  
        }  
        page.setPagination(true);  
  
//      方法1用  
//      Map map = new HashMap();  
//      map.put("page", page);  
//      HandlerResult rs = userService.list(map);  
          
        //方法2用  
        HandlerResult rs = userService.list();  
          
        ModelAndView mv = new ModelAndView("/views/show.jsp");  
        mv.addObject("userList", rs.getResultObj());  
        mv.addObject("page",page);  
        return mv;  
    }  
  
}

简要说明:本文采用两种方式将page对象传入到拦截器中。第一种方式是采用参数传值,不管是用map还是在统一参数对象中名称为page的属性都可以在分页拦截器中得到page的值。第二种方式是用ThreadLocal,对service层没有侵入性。比较方便。

2:Service层代码。没啥可说的上代码

package com.flydreamer.logic;  
  
import java.util.Map;  
  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  
  
import com.flydreamer.orm.mapper.UsersMapper;  
import com.flydreamer.util.web.HandlerResult;  
  
@Service  
public class UserService {  
      
    @Autowired  
    private UsersMapper usersMappser;  
  
  
    /** 
     * 统一Service出口,方便管理 
     * @param map 
     * @return 
     */  
    public HandlerResult list(Map map){  
          
        HandlerResult rs = new HandlerResult();  
          
        rs.setResultObj(usersMappser.list(map));  
          
        return rs;  
    }  
      
    /** 
     * 采用本地线程的方式分页 
     * @return 
     */  
    public HandlerResult list(){  
          
        HandlerResult rs = new HandlerResult();  
          
        rs.setResultObj(usersMappser.list2());  
          
        return rs;  
    }  
      
  
    public UsersMapper getUsersMappser() {  
        return usersMappser;  
    }  
  
    public void setUsersMappser(UsersMapper usersMappser) {  
        this.usersMappser = usersMappser;  
    }  
}  

3:mybatis接口

package com.flydreamer.orm.mapper;  
  
import java.util.List;  
import java.util.Map;  
  
import com.flydreamer.orm.SqlMapper;  
  
public interface UsersMapper extends SqlMapper{  
      
    public List list(Map para);  
      
    public List list2();  
}

4:page的拦截器

package com.flydreamer.interceptor;  
  
import java.sql.Connection;  
import java.sql.PreparedStatement;  
import java.sql.ResultSet;  
import java.sql.SQLException;  
import java.util.List;  
import java.util.Properties;  
  
import org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode;  
import org.apache.ibatis.executor.ErrorContext;  
import org.apache.ibatis.executor.Executor;  
import org.apache.ibatis.executor.ExecutorException;  
import org.apache.ibatis.logging.Log;  
import org.apache.ibatis.logging.LogFactory;  
import org.apache.ibatis.mapping.BoundSql;  
import org.apache.ibatis.mapping.MappedStatement;  
import org.apache.ibatis.mapping.ParameterMapping;  
import org.apache.ibatis.mapping.ParameterMode;  
import org.apache.ibatis.mapping.SqlSource;  
import org.apache.ibatis.mapping.MappedStatement.Builder;  
import org.apache.ibatis.plugin.Interceptor;  
import org.apache.ibatis.plugin.Intercepts;  
import org.apache.ibatis.plugin.Invocation;  
import org.apache.ibatis.plugin.Plugin;  
import org.apache.ibatis.plugin.Signature;  
import org.apache.ibatis.reflection.MetaObject;  
import org.apache.ibatis.reflection.property.PropertyTokenizer;  
import org.apache.ibatis.session.Configuration;  
import org.apache.ibatis.session.ResultHandler;  
import org.apache.ibatis.session.RowBounds;  
import org.apache.ibatis.type.TypeHandler;  
import org.apache.ibatis.type.TypeHandlerRegistry;  
  
import com.flydreamer.page.Dialect;  
import com.flydreamer.page.MySql5Dialect;  
import com.flydreamer.page.OracleDialect;  
import com.flydreamer.page.Page;  
import com.flydreamer.page.PageContext;  
import com.flydreamer.page.ReflectHelper;  
  
//只拦截select部分  
@Intercepts({@Signature(type=Executor.class,method="query",args={ MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class })})  
public class PaginationInterceptor implements Interceptor{  
      
    private final static Log log = LogFactory.getLog(PaginationInterceptor.class);     
      
    Dialect dialect = new MySql5Dialect();  
       
    public Object intercept(Invocation invocation) throws Throwable {  
          
        MappedStatement mappedStatement=(MappedStatement)invocation.getArgs()[0];         
        Object parameter = invocation.getArgs()[1];   
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);   
        String originalSql = boundSql.getSql().trim();     
        RowBounds rowBounds = (RowBounds)invocation.getArgs()[2];  
  
        Object parameterObject = boundSql.getParameterObject();  
        if(boundSql==null || boundSql.getSql()==null || "".equals(boundSql.getSql()))  
            return null;  
        //分页参数--上下文传参  
        Page page = null;  
        PageContext context=PageContext.getContext();  
          
        //map传参每次都将currentPage重置,先判读map再判断context  
        if(parameterObject!=null)  
            page = (Page)ReflectHelper.isPage(parameterObject,"page");  
          
        //分页参数--context参数里的Page传参  
        if(page==null && context.isPagination()==true)  
        {  
            page = context;  
        }  
          
        //后面用到了context的东东  
        if(page!=null && page.isPagination()==true)               
        {  
          int totpage=page.getTotalRows();    
          //得到总记录数  
          if (totpage==0)  
            {  
                StringBuffer countSql  = new StringBuffer(originalSql.length()+100 );  
                countSql.append("select count(1) from (").append(originalSql).append(") t");  
                     Connection connection=mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection()  ;            
                 PreparedStatement countStmt = connection.prepareStatement(countSql.toString());    
                 BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(),countSql.toString(),boundSql.getParameterMappings(),parameterObject);    
                 setParameters(countStmt,mappedStatement,countBS,parameterObject);    
                 ResultSet rs = countStmt.executeQuery();    
                 if (rs.next()) {    
                     totpage = rs.getInt(1);    
                 }    
                 rs.close();    
                 countStmt.close();    
                 connection.close();  
            }  
            
            //分页计算  
            page.init(totpage,page.getPageSize(),page.getCurrentPage());  
            
            if(rowBounds == null || rowBounds == RowBounds.DEFAULT){  
                rowBounds= new RowBounds(page.getPageSize()*(page.getCurrentPage()-1),page.getPageSize());  
                  
            }     
  
            //分页查询 本地化对象 修改数据库注意修改实现  
            String pagesql=dialect.getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit());  
            invocation.getArgs()[2] = new RowBounds(RowBounds.NO_ROW_OFFSET, RowBounds.NO_ROW_LIMIT);     
            BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), pagesql,boundSql.getParameterMappings(),boundSql.getParameterObject());     
            MappedStatement newMs = copyFromMappedStatement(mappedStatement,new BoundSqlSqlSource(newBoundSql));    
             
            invocation.getArgs()[0]= newMs;    
        }  
              
              
           return invocation.proceed();  
          
    }  
    public static class BoundSqlSqlSource implements SqlSource {    
        BoundSql boundSql;    
    
        public BoundSqlSqlSource(BoundSql boundSql) {    
            this.boundSql = boundSql;    
        }    
    
        public BoundSql getBoundSql(Object parameterObject) {    
            return boundSql;    
        }    
    }    
    public Object plugin(Object arg0) {  
         return Plugin.wrap(arg0, this);  
    }  
    public void setProperties(Properties arg0) {  
              
    }  
      
    /**  
     * 对SQL参数(?)设值,参考org.apache.ibatis.executor.parameter.DefaultParameterHandler  
     * @param ps  
     * @param mappedStatement  
     * @param boundSql  
     * @param parameterObject  
     * @throws SQLException  
     */    
    private void setParameters(PreparedStatement ps,MappedStatement mappedStatement,BoundSql boundSql,Object parameterObject) throws SQLException {    
        ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());    
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();    
        if (parameterMappings != null) {    
            Configuration configuration = mappedStatement.getConfiguration();    
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();    
            MetaObject metaObject = parameterObject == null ? null: configuration.newMetaObject(parameterObject);    
            for (int i = 0; i < parameterMappings.size(); i++) {    
                ParameterMapping parameterMapping = parameterMappings.get(i);    
                if (parameterMapping.getMode() != ParameterMode.OUT) {    
                    Object value;    
                    String propertyName = parameterMapping.getProperty();    
                    PropertyTokenizer prop = new PropertyTokenizer(propertyName);    
                    if (parameterObject == null) {    
                        value = null;    
                    } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {    
                        value = parameterObject;    
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {    
                        value = boundSql.getAdditionalParameter(propertyName);    
                    } else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX)&& boundSql.hasAdditionalParameter(prop.getName())) {    
                        value = boundSql.getAdditionalParameter(prop.getName());    
                        if (value != null) {    
                            value = configuration.newMetaObject(value).getValue(propertyName.substring(prop.getName().length()));    
                        }    
                    } else {    
                        value = metaObject == null ? null : metaObject.getValue(propertyName);    
                    }    
                    TypeHandler typeHandler = parameterMapping.getTypeHandler();    
                    if (typeHandler == null) {    
                        throw new ExecutorException("There was no TypeHandler found for parameter "+ propertyName + " of statement "+ mappedStatement.getId());    
                    }    
                    typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType());    
                }    
            }    
        }    
    }    
      
    private MappedStatement copyFromMappedStatement(MappedStatement ms,     
             SqlSource newSqlSource) {     
            Builder builder = new MappedStatement.Builder(ms.getConfiguration(),     
            ms.getId(), newSqlSource, ms.getSqlCommandType());     
            builder.resource(ms.getResource());     
            builder.fetchSize(ms.getFetchSize());     
            builder.statementType(ms.getStatementType());     
            builder.keyGenerator(ms.getKeyGenerator());     
            builder.keyProperty(ms.getKeyProperty());     
            builder.timeout(ms.getTimeout());     
             builder.parameterMap(ms.getParameterMap());     
            builder.resultMaps(ms.getResultMaps());     
            builder.cache(ms.getCache());     
            MappedStatement newMs = builder.build();     
            return newMs;     
            }          
  
} 

简要说明:刚刚忘记了,有一些查询操作是不需要分页的。可以自行修改拦截器中代码部分,加个判断啥的。

5:spring 配置

<bean id="paginationInterceptor" class="com.flydreamer.interceptor.PaginationInterceptor"></bean> 
 
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">    
        <property name="dataSource" ref="dataSource" />    
          
        <property name="plugins">  
            <ref bean="paginationInterceptor"/>  
        </property>  
</bean>

大致就是这样了。完整的可运行项目已放到这里。最近CSDN没有分了,收1分,各位童鞋见谅了~

spring+mybatis 物理分页

原文:http://www.cnblogs.com/duanxz/p/3748225.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!