版权声明:本文为博主原创文章,未经博主允许不得转载。 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,分享半个互联网人的技术与思考,感兴趣的可以关注.