码迷,mamicode.com
首页 > 编程语言 > 详细

mybatis中的分页并且带了排序效果

时间:2015-04-01 17:37:25      阅读:732      评论:0      收藏:0      [点我收藏+]

标签:mybatis   分页   排序   #   拦截器   

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">今天做了一下测试,测试发现分页中存在一些问题:</span>

分页中的排序效果没有显示出来。首先看下排序中的一些注意的事项:

1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id".
2. $将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id,  如果传入的值是id,则解析成的sql为order by id.
3. #方式能够很大程度防止sql注入。
4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名.
6.一般能用#的就别用$.
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
字符串替换
默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置安全的值(比如?)。这样做很安全,很迅速也是首选做法,有时你只是想直接在SQL语句中插入一个不改变的字符串。比如,像ORDER BY,你可以这样来使用:
ORDER BY ${columnName}
这里MyBatis不会修改或转义字符串。
重要:接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。

下面的分页是一个关于贴吧的分页处理代码:


TopicController.java

package com.mogu.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.jpush.api.utils.StringUtils;

import com.mogu.common.StatusCode;
import com.mogu.exception.TopicException;
import com.mogu.model.MoguData;
import com.mogu.model.MoguPageData;
import com.mogu.model.Topic;
import com.mogu.service.topic.ITopicService;
import com.mogu.util.Base64Handler;
import com.mogu.util.LoadOfBASE64;
import com.mogu.util.ObjectUtils;
import com.mogu.util.page.PageControlData;

/**
 * 是发表文章的Controller类 ClassName:TopicController <br/>
 * Date: 2015年3月21日下午3:48:00 <br/>
 * 
 * @author 永文
 * @version
 * @see
 */
@Controller
@RequestMapping("/topic")
public class TopicController {
	Logger logger = Logger.getLogger(Topic.class);
	@Resource
	ITopicService topicService;

	@RequestMapping("/publish")
	public @ResponseBody MoguData<Topic> publish(
			@RequestBody MoguData<Topic> params) {
		MoguData<Topic> moguData = new MoguData<Topic>();
		Topic topic = params.getData();
		try {
			if (!StringUtils.isEmpty(topic.getContent())) {
				topic.setContent(URLDecoder.decode(topic.getContent(), "UTF-8"));
			}
			topic.setPosttime(new Date());
			// 对图片进行处理
			if (!StringUtils.isEmpty(topic.getImgs())) {
				String[] imgs = topic.getImgs().split(",");
				StringBuffer sb = new StringBuffer();
				for (int i = 0; i < imgs.length; i++) {
					if (!StringUtils.isEmpty(imgs[i])) {
						String imgUrl = Base64Handler
								.getInstance()
								.convertBase64DataToImg(imgs[i],
										"fileBbsImagePath", "SqlBbsImagePath");
						sb.append(imgUrl + ",");
					}
				}
				topic.setImgs(sb.toString());
			}
			int record = topicService.saveTopic(topic);
			if (record > 0) {// 插入成功
				moguData.setStatuscode(StatusCode.SUCCESS.value());
				moguData.setMessage(StatusCode.errorMsg(StatusCode.SUCCESS
						.value()));
			}
		} catch (TopicException e) {
			moguData.setStatuscode(StatusCode.PUBLISH_FAIL.value());
			moguData.setMessage(StatusCode.errorMsg(StatusCode.PUBLISH_FAIL
					.value()));
			return moguData;
		} catch (UnsupportedEncodingException e) {
			moguData.setStatuscode(StatusCode.PUBLISH_FAIL.value());
			moguData.setMessage(StatusCode.errorMsg(StatusCode.PUBLISH_FAIL
					.value()));
			return moguData;
		} catch (IOException e) {
			moguData.setStatuscode(StatusCode.PUBLISH_FAIL.value());
			moguData.setMessage(StatusCode.errorMsg(StatusCode.PUBLISH_FAIL
					.value()));
			return moguData;
		}
		return moguData;
	}

	/**
	 * 通过页码、文章类型等来获取数据 Function: TODO. <br/>
	 * Date: 2015年3月23日上午10:42:10 <br/>
	 * 
	 * @author 永文
	 * @version
	 * @see
	 */
	@RequestMapping("/getTopicByPage")
	public @ResponseBody MoguPageData<List<Topic>> getTopicByPage(
			@RequestBody MoguPageData<Topic> params) {
		MoguPageData<List<Topic>> moguPageData = new MoguPageData<List<Topic>>();
		PageControlData<Topic> po = new PageControlData<Topic>();
		Topic ppo = params.getData();
		po.setPageSize(params.getPerPageCount());
		po.setCurrentPage(params.getCurrentPage());
		PageControlData<Topic> pageControlData = null;
		try {
			pageControlData = topicService.getTopicByPage(ppo, po);
		} catch (TopicException e) {
			e.printStackTrace();
			moguPageData.setMessage(StatusCode
					.errorMsg(StatusCode.GAIN_PAGING_FAIL.value()));
			moguPageData.setStatuscode(StatusCode.GAIN_PAGING_FAIL.value());
			return moguPageData;
		}
		moguPageData.setData(pageControlData.getResultList());
		moguPageData.setStatuscode(StatusCode.SUCCESS.value());
		moguPageData
				.setMessage(StatusCode.errorMsg(StatusCode.SUCCESS.value()));
		return moguPageData;

	}
}

TopicServiceImpl.java

package com.mogu.service.topic.impl;

import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mogu.exception.TopicException;
import com.mogu.mapper.TopicMapper;
import com.mogu.model.Topic;
import com.mogu.model.User;
import com.mogu.service.topic.ITopicService;
import com.mogu.util.LoadOfBASE64;
import com.mogu.util.ObjectUtils;
import com.mogu.util.UrlUtil;
import com.mogu.util.page.PageControlData;
import com.mogu.util.page.PageParam;

@Service
public class TopicServiceImpl implements ITopicService {
	
	Logger logger = Logger.getLogger(TopicServiceImpl.class);
	
	@Resource
	TopicMapper topicMapper;
	
	/**
	 * 确保查询出记录同时更新记录的浏览次数的记录行
	 */
	@Override
	@Transactional
	public PageControlData<Topic> getTopicByPage(Topic ppo,
			PageControlData<Topic> po) throws TopicException {
		PageParam<Topic> pageParam = new PageParam<Topic>(ppo, po);
		List<Topic> list = null;
		try {
			list = topicMapper.pageQuery(pageParam);
			if(list.size() == 0){
				return po;
			}
			int updateRecord = topicMapper.updateByTopics(list);
			if(list.size() != updateRecord){//说明没有同步更新浏览次数
				logger.info("贴吧记录更新失败");
				throw new TopicException("贴吧记录更新失败");
			}
		} catch (SQLException e) {
			e.printStackTrace();
			logger.info("贴吧记录获取失败"+e.getMessage());
			throw new TopicException("贴吧记录获取失败"+e.getMessage());
		}
		Iterator<Topic> iterator = list.iterator();
		Topic topic = null;
		User user = null;
		UrlUtil urlUtil = UrlUtil.getInstance();	
		while(iterator.hasNext()){
			topic  = iterator.next();
			String string = topic.getImgs();
			StringBuffer sb= null;
			if(ObjectUtils.validateString(string)){
				sb = new StringBuffer();
				String[] strArr = string.split(",");
				for(int i = 0 ; i < strArr.length; i ++){
					if(ObjectUtils.validateString(strArr[i])){
						if(i ==strArr.length-1)
							sb.append(urlUtil .getAbsoluteUrl(strArr[i])); 
						else 
							sb.append(urlUtil .getAbsoluteUrl(strArr[i])+",");
					}
				}
				topic.setImgs(sb.toString());
			}
			//对用户图像进行处理
			user = topic.getUser();
			user.setImg(urlUtil.getAbsoluteUrl(user.getImg()));
		}
		po.setResultList(list);
		return po;
	}

	@Override
	public int saveTopic(Topic topic) throws TopicException  {
		try {
			return topicMapper.insert(topic);
		} catch (SQLException e) {
			e.printStackTrace();
			throw new TopicException("发表贴吧失败!"+e.getMessage());
		}
	}
}

关于page相关的类,上面业务代码。

PageControlData.java

package com.mogu.util.page;

import java.io.Serializable;
import java.util.List;

/**
 * 版权所有:@copy; 2004 ZTE Corporation.版权所有.
 * 文件编号:M00_PageControlData.java
 * 文件名称:PageControlData.java
 * 系统编号:Z0001001
 * 系统名称:市场营销管理系统(系统用户)
 * 模块编号:M02
 * 模块名称:项目管理
 * 设计文件:M02_PU02项目管理设计模型.cat,M02_PU02项目管理用例设计.cat
 * 完成日期:
 * 作        者:
 * 内容摘要:项目管理基础页面类
 */
public class PageControlData<T> implements Serializable{
	
	private static final long serialVersionUID = 1L;

	//默认页面尺寸
	private static final int DEFULT_PAGE_SIZE = 10;

	/**
	 * 原始的结果的列表
	 */
	private List<T> resultList;

	/**
	 * 页面总数
	 */
	private int pageCount;

	/**
	 * 当前页面序号
	 */
	private int currentPage;

	/**
	 * 总记录条数
	 */
	private int resultCount;

	/**
	 * 页面尺寸
	 */
	private int pageSize = DEFULT_PAGE_SIZE;

	/**
	 * 跳转到的页面序号
	 */
	private int changePageNumber;

	/**
	 * 起始的记录序号
	 */
	private int startRowNum;

	/**
	 * 终了记录序号
	 */
	private int endRowNum;
	
	/**
	 * 描述:用于排序的对象
	 */
	private SortData sort;

	public PageControlData() {
		
	}
	
	/**
	 * 方法名称: init
	 * 内容摘要: 初始化分页对象
	 */
	public void init()
	{
		//初始化页面总数
		pageCount = 0;
		//初始化当前页面序号
		currentPage = 0;
		//初始化总记录条数
		resultCount = 0;
		//初始化页面尺寸
		pageSize = DEFULT_PAGE_SIZE;
	}

	/**
	 * Access method for the resultList property.
	 *
	 * @return   the current value of the resultList property
	 */
	public List<T> getResultList()
	{
		return resultList;
	}

	/**
	 * Sets the value of the resultList property.
	 *
	 * @param aResultList the new value of the resultList property
	 */
	public void setResultList(List<T> aResultList)
	{
		resultList = aResultList;
	}

	/**
	 * Access method for the pageCount property.
	 *
	 * @return   the current value of the pageCount property
	 */
	public int getPageCount()
	{
		//判断记录总数是否能整除页尺寸
		if (resultCount % pageSize == 0)
		{
			//整除则直接取整相除
			pageCount = (resultCount / pageSize);
		}
		else
		{
			//否则取整相除后加一
			pageCount = (resultCount / pageSize) + 1;
		}
		return pageCount;
	}

	/**
	 * Sets the value of the pageCount property.
	 *
	 * @param aPageCount the new value of the pageCount property
	 */
	public void setPageCount(int aPageCount)
	{
		pageCount = aPageCount;
	}

	/**
	 * Access method for the currentPage property.
	 *
	 * @return   the current value of the currentPage property
	 */
	public int getCurrentPage()
	{
		// 判断总记录数大于零且当前也是小于一的情况
		if (currentPage < 1 && resultCount > 0)
		{
				currentPage = 1;
		}
		//判断当前页序号是否溢出
		if (currentPage > getPageCount())
		{
				currentPage = pageCount;
		}
		return currentPage;
	}

	/**
	 * Sets the value of the currentPage property.
	 *
	 * @param aCurrentPage the new value of the currentPage property
	 */
	public void setCurrentPage(int aCurrentPage)
	{
		//设置当前页序号、小于零的情况忽略
		if(aCurrentPage >= 0)
		{
			currentPage = aCurrentPage;
		}
	}

	/**
	 * Access method for the resultCount property.
	 *
	 * @return   the current value of the resultCount property
	 */
	public int getResultCount()
	{
		return resultCount;
	}

	/**
	 * Sets the value of the resultCount property.
	 *
	 * @param aResultCount the new value of the resultCount property
	 */
	public void setResultCount(int aResultCount)
	{
		//设置总记录条数
		resultCount = aResultCount;
	}

	/**
	 * Access method for the pageSize property.
	 *
	 * @return   the current value of the pageSize property
	 */
	public int getPageSize()
	{
		return pageSize;
	}

	/**
	 * Sets the value of the pageSize property.
	 *
	 * @param aPageSize the new value of the pageSize property
	 */
	public void setPageSize(int aPageSize)
	{
		pageSize = aPageSize;

	}

	/**
	 * Access method for the changePageNumber property.
	 *
	 * @return   the current value of the changePageNumber property
	 */
	public int getChangePageNumber()
	{
		return changePageNumber;
	}

	/**
	 * Sets the value of the changePageNumber property.
	 *
	 * @param aChangePageNumber the new value of the changePageNumber property
	 */
	public void setChangePageNumber(int aChangePageNumber)
	{
		//设置跳转到的页面序号
		changePageNumber = aChangePageNumber;
		//设置当前页序号
		setCurrentPage(changePageNumber);
	}

	/**
	 * Determines if the isFirstPage property is true.
	 *
	 * @return   <code>true<code> if the isFirstPage property is true
	 */
	public boolean getIsFirstPage()
	{
		return currentPage <= 1 ? true : false;
	}

	/**
	 * Determines if the isLastPage property is true.
	 *
	 * @return   <code>true<code> if the isLastPage property is true
	 */
	public boolean getIsLastPage()
	{
		return pageCount <= currentPage ? true : false;
	}

	/**
	 * Access method for the startRowNum property.
	 *
	 * @return   the current value of the startRowNum property
	 */
	public int getStartRowNum()
	{
		//判断记录总数是否能整除页尺寸
		if (currentPage > getPageCount())
		{
			currentPage = pageCount;
		}
		return ((currentPage - 1) * pageSize > 0 ? (currentPage - 1) * pageSize : 0);
	}

	/**
	 * Access method for the endRowNum property.
	 *
	 * @return   the current value of the endRowNum property
	 */
	public int getEndRowNum()
	{
		//判断记录总数是否能整除页尺寸
		if (currentPage > getPageCount())
		{
			currentPage = pageCount;
		}
		//如果当前页小于一则结束序号为页面大小,否则按公式计算
		return (currentPage - 1) > 0 ? (currentPage - 1) * pageSize + pageSize : pageSize;
	}
	
	/**
	 * Sets the value of the startRowNum property.
	 *
	 * @param aStartRowNum the new value of the startRowNum property
	 */
	public void setStartRowNum(int aStartRowNum)
	{
			startRowNum = aStartRowNum;
	}
	
	/**
	 * Sets the value of the endRowNum property.
	 *
	 * @param aEndRowNum the new value of the endRowNum property
	 */
	public void setEndRowNum(int aEndRowNum)
	{
			endRowNum = aEndRowNum;
	}
	
	//获取当前页面记录数
	public int getPageDataCount(){
		if(resultList != null)
			return resultList.size();
		else
			return 0;
	}

	public SortData getSort() {
		return sort;
	}

	public void setSort(SortData sort) {
		this.sort = sort;
	}
}

PageParam.java

/**
 * 
 */
package com.mogu.util.page;

import java.util.HashMap;

/**
 * @author chenh
 * @date 2013年9月3日
 */
@SuppressWarnings("serial")
public class PageParam<T> extends HashMap<String,Object>{

	private static final String KEY_PO = "po";
	private static final String KEY_PAGE = "page";
	
	public PageParam(){
		super();
	}
	
	public PageParam(Object t,PageControlData<T> page){
		this.put(KEY_PO,t);
		this.put(KEY_PAGE, page);
	}
	
	@SuppressWarnings("unchecked")
	public T getParamObject(){
		return (T)this.get(KEY_PO);
	}
	
	@SuppressWarnings("unchecked")
	public PageControlData<T> getPage(){
		return (PageControlData<T>)this.get(KEY_PAGE);
	}
}

MysqlPageHandler.java 该类实现了PageHandler接口

/**
 * 
 */
package com.mogu.util.page;

/**
 * @author chenh
 * @date 2013年9月5日
 */
public class MysqlPageHandler implements PageHandler{

	public String handlerCountSql(String sql) {
		return "select count(*) from ("+sql+") as total";
	}

	public String handlerPageSql(String sql) {
		return sql+" limit ?,?";
	}

}

OrclcePageHander.java该类也实现了PageHandler接口

/**
 * 
 */
package com.mogu.util.page;

/**
 * @author chenh
 * @date 2013年9月3日
 */
public class OraclePageHandler implements PageHandler{

	public String handlerCountSql(String sql) {
		return "SELECT COUNT(*) FROM ("+sql+")";
	}

	public String handlerPageSql(String sql) {
		return "SELECT * FROM "
				+ "(WITH RESULTTABLE AS ( "+sql+") SELECT ROWNUM AS ROW_NUM,R.* FROM RESULTTABLE R) PAGERESULT "
				+ "WHERE PAGERESULT.ROW_NUM >? AND PAGERESULT.ROW_NUM <=?";
	}
}

PageInterceptor.java

/**
 * 
 */
package com.mogu.util.page;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMapping.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.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.Configuration;
import org.apache.log4j.Logger;



/**
 * @author chenh
 * @date 2013年9月2日
 */
@Intercepts({@Signature(type= StatementHandler.class,method = "prepare",args = {Connection.class})}) 
@SuppressWarnings("unchecked")
public class PageInterceptor implements Interceptor{

	private PageHandler pageHandler;
	public static final Logger logger = Logger.getLogger(PageInterceptor.class);
	
	public Object intercept(Invocation invocation) throws Throwable {
		RoutingStatementHandler statementHandler = (RoutingStatementHandler)invocation.getTarget();
		BoundSql boundSql = statementHandler.getBoundSql();
		Object param = boundSql.getParameterObject();
		if(param instanceof PageParam){
			logger.debug("page query");			
			PageParam<Object> pageParam =(PageParam<Object>)param;
			PageControlData<Object> page = pageParam.getPage();
			//ReflectUtil.setFieldValue(boundSql, "parameterObject", pageParam.getParamObject());
			Connection connection = (Connection)invocation.getArgs()[0];
			String sql = boundSql.getSql(); 
			String sqlCount = pageHandler.handlerCountSql(sql);
			logger.debug("sqlCount: "+sqlCount);
			//通过反射获取到当前RoutingStatementHandler对象的delegate属性  
			StatementHandler delegate = (StatementHandler)ReflectUtil.getFieldValue(statementHandler, "delegate");  
			//通过反射获取delegate父类BaseStatementHandler的mappedStatement属性  
			MappedStatement mappedStatement = (MappedStatement)ReflectUtil.getFieldValue(delegate, "mappedStatement"); 
			//通过BoundSql获取对应的参数映射  
		    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();  
		    //利用Configuration、查询记录数的Sql语句countSql、参数映射关系parameterMappings和参数对象page建立查询记录数对应的BoundSql对象。  
		    BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), sqlCount, parameterMappings, param);  
		    //通过mappedStatement、参数对象page和BoundSql对象countBoundSql建立一个用于设定参数的ParameterHandler对象  
		    ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, param, countBoundSql);  
			
			PreparedStatement pstmt = null;  
			ResultSet rs = null;  
			try {  
				pstmt = connection.prepareStatement(sqlCount);
				parameterHandler.setParameters(pstmt);
				// 之后就是执行获取总记录数的Sql语句和获取结果了。
				rs = pstmt.executeQuery();
				if (rs.next()) {
					int totalRecord = rs.getInt(1);
					logger.debug("page query count: "+totalRecord);
					page.setResultCount(totalRecord);
				}
			} catch (SQLException e) {  
				logger.error(e.getMessage());
				e.printStackTrace();  
			} finally {  
				try {
					if (rs != null)
						rs.close();
					if (pstmt != null)
						pstmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}  
			Configuration configuration = (Configuration)ReflectUtil.getFieldValue(delegate, "configuration");
			if(!(parameterMappings instanceof ArrayList)){
				parameterMappings = new ArrayList<ParameterMapping>();
				ReflectUtil.setFieldValue(boundSql, "parameterMappings", parameterMappings);
			}
			parameterMappings.add(new Builder(configuration, "page.startRowNum", Object.class).build());
			//parameterMappings.add(new Builder(configuration, "page.endRowNum", Object.class).build());
			parameterMappings.add(new Builder(configuration, "page.pageSize", Object.class).build());
			String sqlPage = pageHandler.handlerPageSql(sql);
			logger.debug("sqlPage: "+sqlPage);
			//利用反射设置当前BoundSql对应的sql属性为我们建立好的分页Sql语句  
			ReflectUtil.setFieldValue(boundSql, "sql", sqlPage); 
		}
		return invocation.proceed();
	}

	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	public void setProperties(Properties properties) {
		String pageHandlerClass = (String)properties.get("pageHandler");
		logger.info("use page handler: "+pageHandlerClass);
		try {
			pageHandler = (PageHandler)Class.forName(pageHandlerClass).newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			logger.error(e.getMessage());
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			logger.error(e.getMessage());
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			logger.error(e.getMessage());
		}
	}

}

sortData.java

package com.mogu.util.page;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import org.springframework.util.StringUtils;

public class SortData implements Iterable<SortData.OrderData>,Serializable{

	private static final long serialVersionUID = 1L;
	
	public static final Direction DEFAULT_DIRECTION = Direction.DESC;

	private final List<OrderData> orders;
	
	/**
	 * @param orders 不能是 null。
	 */
	public SortData(OrderData... orders) {
		this(Arrays.asList(orders));
	}

	/**
	 * @param orders 不能是 null,也不能包含 null。
	 */
	public SortData(List<OrderData> orders) {
		if (null == orders || orders.isEmpty()) {
			throw new IllegalArgumentException("你必须提供至少一个排序属性!");
		}

		this.orders = orders;
	}

	/**
	 * @param properties 不能是 null,也不能包含 null。
	 */
	public SortData(String... properties) {
		this(DEFAULT_DIRECTION, properties);
	}

	/**
	 * @param direction 当direction为null时,默认为DEFAULT_DIRECTION
	 * @param properties 不能是 null,也不能包含 null或空串
	 */
	public SortData(Direction direction, String... properties) {
		this(direction, properties == null ? new ArrayList<String>() : Arrays.asList(properties));
	}

	/**
	 * @param direction
	 * @param properties
	 */
	public SortData(Direction direction, List<String> properties) {
		if (properties == null || properties.isEmpty()) {
			throw new IllegalArgumentException("你必须提供至少一个排序属性!");
		}

		this.orders = new ArrayList<OrderData>(properties.size());

		for (String property : properties) {
			this.orders.add(new OrderData(direction, property));
		}
	}

	/**
	 * 返回由当前Sort与给定sort取并集后的新的Sort。
	 * 
	 * @param sort 可以为null
	 * @return
	 */
	public SortData and(SortData sort) {
		if (sort == null) {
			return this;
		}

		ArrayList<OrderData> these = new ArrayList<OrderData>(this.orders);

		for (OrderData order : sort) {
			these.add(order);
		}

		return new SortData(these);
	}

	/**
	 * 返回给定property的Order对象
	 * 
	 * @param property
	 * @return
	 */
	public OrderData getOrderFor(String property) {
		for (OrderData order : this) {
			if (order.getProperty().equals(property)) {
				return order;
			}
		}

		return null;
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Iterable#iterator()
	 */
	public Iterator<OrderData> iterator() {
		return this.orders.iterator();
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}

		if (!(obj instanceof SortData)) {
			return false;
		}

		SortData that = (SortData) obj;

		return this.orders.equals(that.orders);
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		int result = 17;
		result = 31 * result + orders.hashCode();
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return StringUtils.collectionToCommaDelimitedString(orders);
	}

	/**
	 * 排序方向的枚举类型
	 */
	public static enum Direction {
		ASC, DESC;

		/**
		 * 根据给定值返回相应枚举实例。
		 * 
		 * @param value
		 * @return
		 */
		public static Direction fromString(String value) {
			try {
				return Direction.valueOf(value.toUpperCase(Locale.US));
			} catch (Exception e) {
				throw new IllegalArgumentException(String.format("非法的值 '%s' ! 合法的值只能是 “desc”或“asc”(大小写不敏感)。", value), e);
			}
		}
	}

	/**
	 * 排序属性
	 */
	public static class OrderData implements Serializable {
		private static final long serialVersionUID = 1L;

		private final Direction direction;
		private final String property;

		/**
		 * @param direction 当direction是null时,默认为DEFAULT_DIRECTION
		 * @param property 不能是null或空串
		 */
		public OrderData(Direction direction, String property) {
			if (!StringUtils.hasText(property)) {
				throw new IllegalArgumentException("属性不能是null或空串!");
			}

			this.direction = direction == null ? DEFAULT_DIRECTION : direction;
			this.property = property;
		}

		/**
		 * @param property 不能是null或空串
		 */
		public OrderData(String property) {
			this(DEFAULT_DIRECTION, property);
		}

		/**
		 * 获得当前属性的排序方向。
		 * 
		 * @return
		 */
		public Direction getDirection() {
			return direction;
		}

		/**
		 * 获得当前排序属性的字符串表示。
		 * 
		 * @return
		 */
		public String getProperty() {
			return property;
		}

		/**
		 * 返回当前排序属性是否是增序排序。
		 * 
		 * @return
		 */
		public boolean isAscending() {
			return this.direction.equals(Direction.ASC);
		}

		/**
		 * 根据给定的Direction返回一个新的Order.
		 * 
		 * @param order
		 * @return
		 */
		public OrderData with(Direction order) {
			return new OrderData(order, this.property);
		}

		/**
		 * 根据给定的properties返回一个新的Sort
		 * 
		 * @param properties
		 * @return
		 */
		public SortData withProperties(String... properties) {
			return new SortData(this.direction, properties);
		}

		/*
		 * (non-Javadoc)
		 * @see java.lang.Object#hashCode()
		 */
		@Override
		public int hashCode() {
			int result = 17;

			result = 31 * result + direction.hashCode();
			result = 31 * result + property.hashCode();

			return result;
		}

		/*
		 * (non-Javadoc)
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		@Override
		public boolean equals(Object obj) {
			if (this == obj) {
				return true;
			}

			if (!(obj instanceof OrderData)) {
				return false;
			}

			OrderData that = (OrderData) obj;

			return this.direction.equals(that.direction) && this.property.equals(that.property);
		}

		/*
		 * (non-Javadoc)
		 * @see java.lang.Object#toString()
		 */
		@Override
		public String toString() {
			return String.format("%s: %s", property, direction);
		}
	}
	
	public static void main(String[] args) {
		SortData sort = new SortData("abc", "kkk", "III");
		System.out.println(sort);
	}

}


TopicMapper.xml


  <resultMap type="com.mogu.model.Topic" id="ExtendBaseResultMap">
      <association property="user" column="userid" select="selectUser" javaType="com.mogu.model.User"></association>
  </resultMap>
  
  <sql id="Base_Column_List" >
    id, title, content, imgs, type, userId, posttime, ipAddr, location, phoneType, commentCount, 
    browseCount, praiseCount, parentId, status, create_time, create_user, update_time, 
    update_user
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from mogu_user_topic
    where id = #{id,jdbcType=INTEGER}
  </select>
  
  <!-- 分页查询 -->
	<select id="pageQuery" resultMap="ExtendBaseResultMap">
		SELECT * FROM mogu_user_topic
		<where>
			<if test="po.createTime != null">
				AND create_time=#{bo.createTime,jdbcType=TIMESTAMP}
			</if>
			<if test="po.updateTime != null">
				AND update_time=#{bo.updateTime,jdbcType=TIMESTAMP}
			</if>
	   </where>
		 <if test="page.sort != null ">
		        <foreach collection="page.sort" index="index" item="order">
		            ORDER BY #{order.property,jdbcType=VARCHAR} #{order.direction,jdbcType=VARCHAR}
		        </foreach>
		</if>
	</select>
  
	<select id="selectUser" resultType="com.mogu.model.User" parameterType="java.lang.Integer">
	    SELECT * FROM mogu_user 
	    WHERE id = #{id,jdbcType=INTEGER}
	</select>

在上面的代码中存在这样一个问题希望大家注意:

1.种

 <if test="page.sort != null ">
		        <foreach collection="page.sort" index="index" item="order">            <pre name="code" class="java">                              ORDER BY #{order.property,jdbcType=VARCHAR} #{order.direction,jdbcType=VARCHAR}
</foreach></if>

<pre name="code" class="java"> <if test="page.sort != null ">
		        <foreach collection="page.sort" index="index" item="order">            <pre name="code" class="java">                              ORDER BY #{order.property} #{order.direction}
</foreach></if>



上面的都是无效的,需要使用下面的方式来处理排序问题

2.种

	 <if test="page.sort != null ">
		        <foreach collection="page.sort" index="index" item="order">
		            ORDER BY ${order.property} ${order.direction}
		        </foreach>
		</if>

上面的在查询分页记录的时候不会出现问题 ,但是前期有个COUNT操作,会出现问题下面的问题:

2015-04-01 17:00:07,736 [main] DEBUG org.mybatis.spring.SqlSessionUtils       -Creating a new SqlSession
2015-04-01 17:00:07,743 [main] DEBUG org.mybatis.spring.SqlSessionUtils       -Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3fe45b09]
2015-04-01 17:00:07,843 [main] DEBUG ing.transaction.SpringManagedTransaction -JDBC Connection [jdbc:mysql://120.24.245.201:3306/mogubrothers?useUnicode=true&characterEncoding=utf8, UserName=root@113.116.86.173, MySQL-AB JDBC Driver] will be managed by Spring
2015-04-01 17:00:07,850 [main] DEBUG com.mogu.mapper.TopicMapper.pageQuery    -ooo Using Connection [jdbc:mysql://120.24.245.201:3306/mogubrothers?useUnicode=true&characterEncoding=utf8, UserName=root@113.116.86.173, MySQL-AB JDBC Driver]
2015-04-01 17:00:07,857 [main] DEBUG com.mogu.util.page.PageInterceptor       -page query
2015-04-01 17:00:07,857 [main] DEBUG com.mogu.util.page.PageInterceptor       -sqlCount: select count(*) from (SELECT * FROM mogu_user_topic
		  
		  
		          
		            ORDER BY ? ?) as total
2015-04-01 17:00:07,858 [main] DEBUG com.mogu.mapper.TopicMapper.pageQuery    -==>  Preparing: select count(*) from (SELECT * FROM mogu_user_topic ORDER BY ? ?) as total 
2015-04-01 17:00:07,930 [main] DEBUG com.mogu.mapper.TopicMapper.pageQuery    -==> Parameters: null, null
2015-04-01 17:00:07,935 [main] ERROR com.mogu.util.page.PageInterceptor       -You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'null) as total' at line 5
com.mysql.jdbc.exceptions.jdbc4.M

在第1种count的时候居然取不到所传递的两个值信息,而在第2.种的使用没有问题:

2015-04-01 16:55:43,580 [main] DEBUG org.mybatis.spring.SqlSessionUtils       -Creating a new SqlSession
2015-04-01 16:55:43,588 [main] DEBUG org.mybatis.spring.SqlSessionUtils       -Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2a1e41f9]
2015-04-01 16:55:43,686 [main] DEBUG ing.transaction.SpringManagedTransaction -JDBC Connection [jdbc:mysql://120.24.245.201:3306/mogubrothers?useUnicode=true&characterEncoding=utf8, UserName=root@113.116.86.173, MySQL-AB JDBC Driver] will be managed by Spring
2015-04-01 16:55:43,693 [main] DEBUG com.mogu.mapper.TopicMapper.pageQuery    -ooo Using Connection [jdbc:mysql://120.24.245.201:3306/mogubrothers?useUnicode=true&characterEncoding=utf8, UserName=root@113.116.86.173, MySQL-AB JDBC Driver]
2015-04-01 16:55:43,699 [main] DEBUG com.mogu.util.page.PageInterceptor       -page query
2015-04-01 16:55:43,699 [main] DEBUG com.mogu.util.page.PageInterceptor       -sqlCount: select count(*) from (SELECT * FROM mogu_user_topic
		  
		  
		          
		            ORDER BY posttime DESC) as total
2015-04-01 16:55:43,701 [main] DEBUG com.mogu.mapper.TopicMapper.pageQuery    -==>  Preparing: select count(*) from (SELECT * FROM mogu_user_topic ORDER BY posttime DESC) as total 
2015-04-01 16:55:43,771 [main] DEBUG com.mogu.mapper.TopicMapper.pageQuery    -==> Parameters: 
2015-04-01 16:55:43,792 [main] DEBUG com.mogu.util.page.PageInterceptor       -page query count: 19
2015-04-01 16:55:43

所以排序时候使用$处理


mybatis中的分页并且带了排序效果

标签:mybatis   分页   排序   #   拦截器   

原文地址:http://blog.csdn.net/u011218159/article/details/44808957

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!