java 分页查询工具类的完整使用流程(极简版)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Mrqiang9001/article/details/84629591

1 java 分页工具类(极简版)

com.ljq.demo.util.PageUtil.java

package com.ljq.demo.util;

import lombok.Data;

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

/**
 * @Description: 分页工具(极简版)
 * @Author: junqiang.lu
 * @Date: 2018/11/28
 */
@Data
public class PageUtil<T> implements Serializable {

    private static final long serialVersionUID = -1989898212258749371L;

    /**
     * 默认总记录条数
     * 总记录条数最小值
     */
    private static final int DEFAULT_TOTAL_COUNT = 0;
    /**
     * 默认当前页数
     * 当前页数最小值
     */
    private static final int DEFAULT_CURR_PAGE = 1;
    /**
     * 默认每页记录数
     * 每页最小记录数
     */
    private static final int DEFAULT_PAGE_LIMIT = 5;

    /**
     * 总记录条数
     */
    private int totalCount;
    /**
     * 每页记录数
     */
    private int pageLimit;
    /**
     * 总页数
     */
    private int totalPage;
    /**
     * 当前页数
     */
    private int currPage;
    /**
     * 列表数据
     */
    private List<T> list;


    private PageUtil(){}

    /**
     * 有参构造方法
     *
     * @param list 列表数据
     * @param totalCount 总记录条数
     * @param pageLimit 每页记录数
     * @param currPage 当前页数
     */
    public PageUtil(List<T> list, int totalCount, int pageLimit, int currPage){
        if (totalCount < DEFAULT_TOTAL_COUNT) {
            totalCount = DEFAULT_TOTAL_COUNT;
        }
        this.totalCount = totalCount;

        if (pageLimit < DEFAULT_PAGE_LIMIT) {
            pageLimit = DEFAULT_PAGE_LIMIT;
        }
        this.pageLimit = pageLimit;

        if (currPage < DEFAULT_CURR_PAGE) {
            currPage = DEFAULT_CURR_PAGE;
        }
        this.currPage = currPage;

        int remainder = totalCount % pageLimit;
        if (remainder > 0) {
            this.totalPage = (totalCount / pageLimit + 1);
        } else {
            this.totalPage = (totalCount / pageLimit);
        }

        this.list = list;
    }

}

关于分页工具类的测试:
com.ljq.demo.util.PageUtilTest.java


package com.ljq.demo.util;

import org.junit.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PageUtilTest {

    @Test
    public void getPageUtil() {

        int totalCount = 24;
        int pageLimit = 5;
        List<String> strList = new ArrayList<>(16);
        for (int i = 0; i < pageLimit; i++) {
            strList.add("demo-" + (i + 1));
        }
        PageUtil pageUtil = new PageUtil(strList, totalCount, pageLimit, 0);

        System.out.println(pageUtil);

    }

运行结果:

PageUtil(totalCount=24, pageLimit=5, totalPage=5, currPage=1, list=[demo-1, demo-2, demo-3, demo-4, demo-5])

2 java 分页查询工具类(极简版)

2.1 分页查询工具类

com.ljq.demo.util.QueryUtil

package com.ljq.demo.util;

import lombok.Data;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 分页查询工具(极简版)
 * @Author: junqiang.lu
 * @Date: 2018/11/28
 */
@Data
public class QueryUtil extends HashMap<String, Object> implements Serializable {

    private static final long serialVersionUID = -731879956899505222L;

    /**
     * 默认当前页数
     * 最小当前页数
     */
    private static final int DEFAULT_PAGE = 1;

    /**
     * 默认每页显示条数
     * 最小每页显示条数
     */
    private static final int DEFAULT_LIMIT = 5;
    /**
     * 最大每页显示条数
     */
    private static final int MAX_LIMIT = 100;

    private int page = 1;

    private int limit = 5;

    private QueryUtil(){}

    /**
     * 有参构造方法
     *
     * @param queryMap 包含分页查询参数的 map 集合
     *     map 中需要包含的分页参数:
     *         currPage: 当前页数
     *         pageLimit: 每页显示条数
     *         sidx: 排序依据,如按照 "id" 排序,则 map.put("sidx","id")
     *         order: 排序规则,升序(asc)或者降序(desc),如升序排序,则 map.put("order","asc")
     * @throws Exception sql 参数不合法
     */
    public QueryUtil(Map<String, Object> queryMap) throws Exception {

        /**
         * 当前页码参数获取与校验
         */
        String currPageParam = String.valueOf(queryMap.get("currPage"));
        if (currPageParam != null && currPageParam.length() > 0) {
            int currPage = Integer.parseInt(currPageParam);
            this.page = currPage < DEFAULT_PAGE ? DEFAULT_PAGE : currPage;
        }
        /**
         * 每页显示条数参数获取与校验
         */
        String pageLimitParam = String.valueOf(queryMap.get("pageLimit"));
        if (pageLimitParam != null && pageLimitParam.length() > 0) {
            int pageLimit = Integer.parseInt(pageLimitParam);
            this.limit = pageLimit < DEFAULT_PAGE ? DEFAULT_LIMIT : pageLimit;
            this.limit = pageLimit > MAX_LIMIT ? MAX_LIMIT : pageLimit;
        }
        this.put("offset", (page - 1) * limit);
        this.put("page", page);
        this.put("limit", limit);
        /**
         * 排序规则参数获取(防止 sql 注入)
         */
        this.put("sidx", SQLCheckUtil.getSafeSQL(String.valueOf(queryMap.get("sidx"))));
        this.put("order", SQLCheckUtil.getSafeSQL(String.valueOf(queryMap.get("order"))));
    }


}

分页查询工具类测试:

com.ljq.demo.util.QueryUtilTest

package com.ljq.demo.util;

import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

public class QueryUtilTest {

    @Test
    public void createQuery() throws Exception {

        int page = -1;
        int limit = 1;
        String sidx = "insert_time";
        String order = "desc";
        Map<String, Object> queryMap = new HashMap<>(16);
        queryMap.put("currPage", page);
        queryMap.put("pageLimit", limit);
        queryMap.put("sidx", sidx);
        queryMap.put("order", order);

        QueryUtil queryUtil = new QueryUtil(queryMap);

        /**
         * 遍历 map
         */
        for (Map.Entry<String, Object> entry : queryMap.entrySet()) {
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }
        System.out.println("---------- 分割线 ----------");
        for (Map.Entry<String, Object> entry : queryUtil.entrySet()) {
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }

    }
}

测试结果:

Key = pageLimit, Value = 1
Key = currPage, Value = -1
Key = sidx, Value = insert_time
Key = order, Value = desc
---------- 分割线 ----------
Key = offset, Value = 0
Key = limit, Value = 1
Key = page, Value = 1
Key = sidx, Value = insert_time
Key = order, Value = desc

2.2 java 防止 SQL 注入工具类

com.ljq.demo.util.SQLCheckUtil


package com.ljq.demo.util;

import java.util.regex.Pattern;

/**
 * @Description: sql 校验工具
 * @Author: junqiang.lu
 * @Date: 2018/11/28
 */
public class SQLCheckUtil {

    /**
     * sql 最大长度
     */
    private static final int MAX_SQL_LENGTH = 1024 * 1024;

    private SQLCheckUtil(){}

    /**
     * 获取安全 sql 语句(防止 sql 注入)
     * 返回为空(null)的情况:
     *     1) sql 语句为空
     *     2) sql 语句中包含可能产生 sql 注入风险的关键词
     *
     * @param sql sql 语句
     * @return null or safe sql
     * @throws Exception 当 sql 语句长度超过 ${MAX_SQL_LENGTH} 字符时抛出异常
     */
    public static String getSafeSQL(String sql) throws Exception {
        if (sql == null || sql.length() <= 0) {
            return null;
        }
        if (sql.length() > MAX_SQL_LENGTH) {
            throw new Exception("Query string is too long,it must be less than 1048576 = 1024*1024.");
        }
        /**
         * 防止 sql 注入
         */
        String sqlRegex = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"
                                + "(\\b(select|update|union|and|or|delete|insert|trancate|char|"
                                + "into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";
        Pattern sqlPattern = Pattern.compile(sqlRegex, Pattern.CASE_INSENSITIVE);
        if (sqlPattern.matcher(sql).find()) {
            return null;
        }
        return sql;
    }


}

防止 sql 注入工具类测试:

com.ljq.demo.util.SQLCheckUtilTest

package com.ljq.demo.util;

import org.junit.Test;

public class SQLCheckUtilTest {

    @Test
    public void getSafeSQL() throws Exception {

        String[] sqls = {"update_time", "insert_user", "update t_user set id = 0","select * from t_user", "aa'bb",""};
        for (int i = 0; i < sqls.length; i++) {
            System.out.println("sql-" + i + ": " + SQLCheckUtil.getSafeSQL(sqls[i]));
        }
        StringBuilder sql = new StringBuilder();
        int length = 1024 * 1025;
        for (int j = 0; j < length; j++) {
            sql.append("a");
        }
        System.out.println("result: " + SQLCheckUtil.getSafeSQL(sql.toString()));


    }
}

测试结果:

sql-0: update_time
sql-1: insert_user
sql-2: null
sql-3: null
sql-4: null
sql-5: null


java.lang.Exception: Query string is too long,it must be less than 1048576 = 1024*1024.

	at com.ljq.demo.util.SQLCheckUtil.getSafeSQL(SQLCheckUtil.java:34)
	at com.ljq.demo.util.SQLCheckUtilTest.getSafeSQL(SQLCheckUtilTest.java:19)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

3 mybatis mapper 文件中分页查询应用

IntegralGoodsDao.xml

	<!-- 查询列表 -->
	<select id="queryList" parameterType="java.util.Map" resultMap="integralGoodsMap">
		select
		    <include refid="integral_goods_info_field" />
		from (
		    select
		        <include refid="integral_goods_base_field" />
		    from integral_goods
		    where del = 0
			<choose>
				<when test="sidx != null and sidx.trim() != ''">
					order by ${sidx} ${order}
				</when>
				<otherwise>
					order by id desc
				</otherwise>
			</choose>
			<if test="offset != null and limit != null">
				limit #{offset}, #{limit}
			</if>
		) ig
		LEFT JOIN integral_goods_img i
		ON ig.id = i.goods_id
		LEFT JOIN integral_goods_color gc
		ON ig.id = gc.goods_id
		LEFT JOIN t_color c
		ON gc.color_id = c.id
		where i.del = 0 and gc.del = 0 and c.del = 0
	</select>

	<!-- 统计积分商品数量 -->
 	<select id="queryCount" resultType="int">
		select count(*) from integral_goods ig where ig.del = 0
	</select>

完整 mapper 文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.demo.dao.IntegralGoodsDao">

	<!-- 查询结果封装 -->
    <resultMap type="com.demo.model.entity.IntegralGoodsEntity" id="integralGoodsMap">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="integral" column="integral"/>
        <result property="description" column="description"/>
        <result property="stockCount" column="stock_count"/>
        <result property="status" column="status"/>
        <result property="language" column="language"/>
        <result property="platform" column="platform"/>
        <result property="createTime" column="create_time"/>
        <result property="updateTime" column="update_time"/>
        <result property="versions" column="versions"/>
        <result property="del" column="del"/>
		<collection property="goodsImgList" javaType="java.util.List" ofType="com.demo.model.entity.IntegralGoodsImgEntity">
			<result property="imgUrl" column="i_img_url" />
			<result property="createTime" column="i_create_time" />
		</collection>
		<collection property="goodsColorList" javaType="java.util.List" ofType="com.demo.model.entity.Color">
			<result property="id" column="c_id" />
			<result property="name" column="c_name" />
			<result property="value" column="c_value" />
		</collection>
    </resultMap>

	<!-- 积分商品基础字段 -->
	<sql id="integral_goods_base_field">
		`id`, `name`, `integral`, `description`, `stock_count`, `status`, `language`,
		`platform`, `create_time`, `update_time`, `versions`, `del`
	</sql>

	<!-- 积分商品详细信息字段 -->
	<sql id="integral_goods_info_field">
		ig.id, ig.name, ig.integral, ig.description, ig.stock_count, ig.status, ig.language,
		ig.platform, DATE_FORMAT(ig.create_time,"%Y-%m-%d %T") as create_time,
		DATE_FORMAT(ig.update_time,"%Y-%m-%d %T") as update_time, ig.versions, ig.del,
		i.img_url i_img_url,i.create_time i_create_time,
		c.id c_id, c.name c_name,c.value c_value
	</sql>

	<!-- 查询积分商品详情 -->
	<select id="queryObject" parameterType="com.demo.model.entity.IntegralGoodsEntity" resultMap="integralGoodsMap">
		select
		    <include refid="integral_goods_info_field" />
		from integral_goods ig
		LEFT JOIN integral_goods_img i
		ON ig.id = i.goods_id
		LEFT JOIN integral_goods_color gc
		ON ig.id = gc.goods_id
		LEFT JOIN t_color c
		ON gc.color_id = c.id
		where ig.id = #{id} and i.del = 0 and gc.del = 0 and c.del = 0
	</select>

	<!-- 查询列表 -->
	<select id="queryList" parameterType="java.util.Map" resultMap="integralGoodsMap">
		select
		    <include refid="integral_goods_info_field" />
		from (
		    select
		        <include refid="integral_goods_base_field" />
		    from integral_goods
		    where del = 0
			<choose>
				<when test="sidx != null and sidx.trim() != ''">
					order by ${sidx} ${order}
				</when>
				<otherwise>
					order by id desc
				</otherwise>
			</choose>
			<if test="offset != null and limit != null">
				limit #{offset}, #{limit}
			</if>
		) ig
		LEFT JOIN integral_goods_img i
		ON ig.id = i.goods_id
		LEFT JOIN integral_goods_color gc
		ON ig.id = gc.goods_id
		LEFT JOIN t_color c
		ON gc.color_id = c.id
		where i.del = 0 and gc.del = 0 and c.del = 0
	</select>

	<!-- 统计积分商品数量 -->
 	<select id="queryCount" resultType="int">
		select count(*) from integral_goods ig where ig.del = 0
	</select>

</mapper>

4 service 层分页查询的应用

    /**
     * 实际业务中 service 实现类中应用分页查询
     * @throws Exception
     */
    @Test
    public void serviceImplQueryTest() throws Exception {

        int page = -1;
        int limit = 1;
        String sidx = "insert_time";
        String order = "desc";
        Map<String, Object> queryMap = new HashMap<>(16);
        queryMap.put("currPage", page);
        queryMap.put("pageLimit", limit);
        queryMap.put("sidx", sidx);
        queryMap.put("order", order);

        QueryUtil queryUtil = new QueryUtil(queryMap);

        /**
         * IntegralGoodsEntity,integralGoodsDao 仅作为演示,该 demo 项目中并不包含
         */
        List<IntegralGoodsEntity> integralGoodsList = integralGoodsDao.queryList(queryUtil);
        int total = integralGoodsDao.queryCount(queryUtil);
        PageUtil pageUtil = new PageUtil(integralGoodsList, total, queryUtil.getLimit(), queryUtil.getPage());

    }

github 原文: https://github.com/Flying9001/Demo

个人公众号:404Code,分享半个互联网人的技术与思考,感兴趣的可以关注.
404Code

猜你喜欢

转载自blog.csdn.net/Mrqiang9001/article/details/84629591
今日推荐