<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 [[email protected]] 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, [email protected], 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, [email protected], 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 [[email protected]] 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, [email protected], 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, [email protected], 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
所以排序时候使用$处理