新增RowBound功能

This commit is contained in:
redkale
2024-06-07 08:43:52 +08:00
parent 1c07fcc6fa
commit ba25120dea
9 changed files with 221 additions and 96 deletions

View File

@@ -5,9 +5,6 @@
*/ */
package org.redkale.net.http; package org.redkale.net.http;
import static org.redkale.util.Utility.isEmpty;
import static org.redkale.util.Utility.isNotEmpty;
import java.io.*; import java.io.*;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.net.*; import java.net.*;
@@ -22,6 +19,8 @@ import org.redkale.convert.*;
import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonConvert;
import org.redkale.net.Request; import org.redkale.net.Request;
import org.redkale.util.*; import org.redkale.util.*;
import static org.redkale.util.Utility.isEmpty;
import static org.redkale.util.Utility.isNotEmpty;
/** /**
* Http请求包 与javax.servlet.http.HttpServletRequest 基本类似。 <br> * Http请求包 与javax.servlet.http.HttpServletRequest 基本类似。 <br>
@@ -2812,6 +2811,7 @@ public class HttpRequest extends Request<HttpContext> {
* *
* @return Flipper翻页对象 * @return Flipper翻页对象
*/ */
@ClassDepends
public org.redkale.source.Flipper getFlipper() { public org.redkale.source.Flipper getFlipper() {
return getFlipper(false, 0); return getFlipper(false, 0);
} }

View File

@@ -915,12 +915,12 @@ public abstract class AbstractDataSqlSource extends AbstractDataSource
} }
protected DataNativeSqlStatement nativeParse( protected DataNativeSqlStatement nativeParse(
String nativeSql, boolean countable, Flipper flipper, Map<String, Object> params) { String nativeSql, boolean countable, RowBound round, Map<String, Object> params) {
if (nativeSqlParser == null) { if (nativeSqlParser == null) {
throw new SourceException("not found " + DataNativeSqlParser.class.getSimpleName() + " instance"); throw new SourceException("not found " + DataNativeSqlParser.class.getSimpleName() + " instance");
} }
return nativeSqlParser.parse( return nativeSqlParser.parse(
signFunc, dbtype(), nativeSql, countable, flipper, params == null ? Collections.emptyMap() : params); signFunc, dbtype(), nativeSql, countable, round, params == null ? Collections.emptyMap() : params);
} }
@ConvertDisabled @ConvertDisabled
@@ -3909,8 +3909,8 @@ public abstract class AbstractDataSqlSource extends AbstractDataSource
} }
@Override @Override
public <V> Sheet<V> nativeQuerySheet(Class<V> type, String sql, Flipper flipper, Map<String, Object> params) { public <V> Sheet<V> nativeQuerySheet(Class<V> type, String sql, RowBound round, Map<String, Object> params) {
return nativeQuerySheetAsync(type, sql, flipper, params).join(); return nativeQuerySheetAsync(type, sql, round, params).join();
} }
@Override @Override

View File

@@ -2838,8 +2838,8 @@ public class DataJdbcSource extends AbstractDataSqlSource {
@Override @Override
public <V> CompletableFuture<Sheet<V>> nativeQuerySheetAsync( public <V> CompletableFuture<Sheet<V>> nativeQuerySheetAsync(
Class<V> type, String sql, Flipper flipper, Map<String, Object> params) { Class<V> type, String sql, RowBound round, Map<String, Object> params) {
return supplyAsync(() -> nativeQuerySheet(type, sql, flipper, params)); return supplyAsync(() -> nativeQuerySheet(type, sql, round, params));
} }
@Deprecated @Deprecated

View File

@@ -28,7 +28,7 @@ public interface DataNativeSqlParser {
String dbType, String dbType,
String rawSql, String rawSql,
boolean countable, boolean countable,
Flipper flipper, RowBound round,
Map<String, Object> params); Map<String, Object> params);
public static DataNativeSqlParser loadFirst() { public static DataNativeSqlParser loadFirst() {

View File

@@ -32,7 +32,7 @@ public class DataNativeSqlStatement {
String dbType, String dbType,
String rawSql, String rawSql,
boolean countable, boolean countable,
Flipper flipper, RowBound round,
Map<String, Object> params) { Map<String, Object> params) {
throw new UnsupportedOperationException("No available instances found"); throw new UnsupportedOperationException("No available instances found");
} }

View File

@@ -3,13 +3,12 @@
*/ */
package org.redkale.source; package org.redkale.source;
import static org.redkale.source.DataResultSet.formatColumnValue;
import java.io.Serializable; import java.io.Serializable;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.*; import java.util.function.*;
import org.redkale.annotation.ClassDepends; import org.redkale.annotation.ClassDepends;
import static org.redkale.source.DataResultSet.formatColumnValue;
import org.redkale.util.*; import org.redkale.util.*;
/** /**
@@ -131,11 +130,11 @@ public interface DataSqlSource extends DataSource {
Map<String, Object> params); Map<String, Object> params);
@ClassDepends @ClassDepends
public <V> Sheet<V> nativeQuerySheet(Class<V> type, String sql, Flipper flipper, Map<String, Object> params); public <V> Sheet<V> nativeQuerySheet(Class<V> type, String sql, RowBound round, Map<String, Object> params);
@ClassDepends @ClassDepends
public <V> CompletableFuture<Sheet<V>> nativeQuerySheetAsync( public <V> CompletableFuture<Sheet<V>> nativeQuerySheetAsync(
Class<V> type, String sql, Flipper flipper, Map<String, Object> params); Class<V> type, String sql, RowBound round, Map<String, Object> params);
// ----------------------------- 无参数 ----------------------------- // ----------------------------- 无参数 -----------------------------
default <V> V nativeQuery(String sql, Function<DataResultSet, V> handler) { default <V> V nativeQuery(String sql, Function<DataResultSet, V> handler) {

View File

@@ -5,30 +5,21 @@
*/ */
package org.redkale.source; package org.redkale.source;
import java.io.Serializable;
import java.util.Objects; import java.util.Objects;
import org.redkale.annotation.Comment; import org.redkale.annotation.Comment;
import org.redkale.convert.ConvertColumn; import org.redkale.convert.ConvertColumn;
/** /**
* 翻页对象, offset从0开始, limit必须大于0 * 翻页+排序对象, offset从0开始, limit必须大于0
* *
* <p>详情见: https://redkale.org * <p>详情见: https://redkale.org
* *
* @author zhangjx * @author zhangjx
*/ */
public final class Flipper implements Serializable, Cloneable { public final class Flipper extends RowBound {
public static int DEFAULT_LIMIT = 20; public static int DEFAULT_LIMIT = 20;
@ConvertColumn(index = 1)
@Comment("记录行的偏移量从0开始")
private int offset = 0;
@ConvertColumn(index = 2)
@Comment("每页多少行")
private int limit = DEFAULT_LIMIT;
@ConvertColumn(index = 3) @ConvertColumn(index = 3)
@Comment("排序字段, 可多字段排序") @Comment("排序字段, 可多字段排序")
private String sort = ""; private String sort = "";
@@ -36,7 +27,7 @@ public final class Flipper implements Serializable, Cloneable {
public Flipper() {} public Flipper() {}
public Flipper(int limit) { public Flipper(int limit) {
this.limit = limit > 0 ? limit : 0; super(limit);
} }
public Flipper(String sortColumn) { public Flipper(String sortColumn) {
@@ -44,27 +35,42 @@ public final class Flipper implements Serializable, Cloneable {
} }
public Flipper(int limit, int offset) { public Flipper(int limit, int offset) {
this.limit = limit > 0 ? limit : 0; super(limit, offset);
this.offset = offset < 0 ? 0 : offset;
} }
public Flipper(int limit, String sortColumn) { public Flipper(int limit, String sortColumn) {
this.limit = limit > 0 ? limit : 0; super(limit);
this.sort = sortColumn; this.sort = sortColumn;
} }
public Flipper(int limit, int offset, String sortColumn) { public Flipper(int limit, int offset, String sortColumn) {
this.limit = limit > 0 ? limit : 0; super(limit, offset);
this.offset = offset < 0 ? 0 : offset;
this.sort = sortColumn; this.sort = sortColumn;
} }
@Override
public Flipper limit(int limit) {
super.limit(limit);
return this;
}
@Override
public Flipper maxLimit(int maxlimit) {
super.maxLimit(maxlimit);
return this;
}
@Override
public Flipper unlimit() {
super.unlimit();
return this;
}
public Flipper copyTo(Flipper copy) { public Flipper copyTo(Flipper copy) {
if (copy == null) { if (copy == null) {
return copy; return copy;
} }
copy.offset = this.offset; super.copyTo(copy);
copy.limit = this.limit;
copy.sort = this.sort; copy.sort = this.sort;
return copy; return copy;
} }
@@ -73,8 +79,7 @@ public final class Flipper implements Serializable, Cloneable {
if (copy == null) { if (copy == null) {
return this; return this;
} }
this.offset = copy.offset; super.copyFrom(copy);
this.limit = copy.limit;
this.sort = copy.sort; this.sort = copy.sort;
return this; return this;
} }
@@ -82,10 +87,11 @@ public final class Flipper implements Serializable, Cloneable {
/** /**
* 翻下一页 * 翻下一页
* *
* @return Flipper * @return RowBound
*/ */
@Override
public Flipper next() { public Flipper next() {
this.offset = getOffset() + this.limit; super.next();
return this; return this;
} }
@@ -95,8 +101,9 @@ public final class Flipper implements Serializable, Cloneable {
* @param current 页号, 从1开始 * @param current 页号, 从1开始
* @return Flipper * @return Flipper
*/ */
@Override
public Flipper current(int current) { public Flipper current(int current) {
this.offset = (current - 1) * this.limit; super.current(current);
return this; return this;
} }
@@ -108,8 +115,9 @@ public final class Flipper implements Serializable, Cloneable {
@Override @Override
public String toString() { public String toString() {
return "{offset:" + this.offset + ",limit:" + this.limit return "{\"limit\":" + this.limit + ",\"offset\":" + this.offset
+ ((sort == null || sort.isEmpty()) ? "" : (",sort:\"" + this.sort.replace('"', '\'') + "\"")) + "}"; + ((sort == null || sort.isEmpty()) ? "" : (",\"sort\":\"" + this.sort.replace('"', '\'') + "\""))
+ "}";
} }
@Override @Override
@@ -142,42 +150,6 @@ public final class Flipper implements Serializable, Cloneable {
return Objects.equals(this.sort, other.sort); return Objects.equals(this.sort, other.sort);
} }
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public Flipper limit(int limit) {
setLimit(limit);
return this;
}
public Flipper maxLimit(int maxlimit) {
setLimit(Math.max(1, Math.min(maxlimit, limit)));
return this;
}
public Flipper unlimit() {
this.limit = 0;
return this;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset < 0 ? 0 : offset;
}
public Flipper offset(int offset) {
setOffset(offset);
return this;
}
public String getSort() { public String getSort() {
return sort; return sort;
} }

View File

@@ -0,0 +1,154 @@
/*
*/
package org.redkale.source;
import java.io.Serializable;
import org.redkale.annotation.Comment;
import org.redkale.convert.ConvertColumn;
/**
* 翻页对象, offset从0开始, limit必须大于0
*
* <p>详情见: https://redkale.org
*
* @author zhangjx
* @since 2.8.0
*/
public class RowBound implements Serializable, Cloneable {
public static int DEFAULT_LIMIT = 20;
@ConvertColumn(index = 1)
@Comment("记录行的偏移量从0开始")
protected int offset = 0;
@ConvertColumn(index = 2)
@Comment("每页多少行")
protected int limit = DEFAULT_LIMIT;
public RowBound() {}
public RowBound(int limit) {
this.limit = limit > 0 ? limit : 0;
}
public RowBound(int limit, int offset) {
this.limit = limit > 0 ? limit : 0;
this.offset = offset < 0 ? 0 : offset;
}
public RowBound copyTo(RowBound copy) {
if (copy == null) {
return copy;
}
copy.offset = this.offset;
copy.limit = this.limit;
return copy;
}
public RowBound copyFrom(RowBound copy) {
if (copy == null) {
return this;
}
this.offset = copy.offset;
this.limit = copy.limit;
return this;
}
/**
* 翻下一页
*
* @return RowBound
*/
public RowBound next() {
this.offset = getOffset() + this.limit;
return this;
}
/**
* 设置当前页号页号从1开始
*
* @param current 页号, 从1开始
* @return Flipper
*/
public RowBound current(int current) {
this.offset = (current - 1) * this.limit;
return this;
}
@Override
@SuppressWarnings("CloneDoesntCallSuperClone")
public RowBound clone() {
return this.copyTo(new RowBound());
}
@Override
public String toString() {
return "{\"limit\":" + this.limit + ",\"offset\":" + this.offset + "}";
}
@Override
public int hashCode() {
int hash = 5;
hash = 37 * hash + this.offset;
hash = 37 * hash + this.limit;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final RowBound other = (RowBound) obj;
return this.offset != other.offset && this.limit != other.limit;
}
public RowBound limit(int limit) {
setLimit(limit);
return this;
}
public RowBound maxLimit(int maxlimit) {
setLimit(Math.max(1, Math.min(maxlimit, limit)));
return this;
}
public RowBound unlimit() {
this.limit = 0;
return this;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset < 0 ? 0 : offset;
}
public RowBound offset(int offset) {
setOffset(offset);
return this;
}
public static boolean validLimit(RowBound flipper) {
return flipper != null && flipper.getLimit() > 0;
}
}

View File

@@ -36,7 +36,7 @@ import org.redkale.source.DataNativeSqlParser;
import org.redkale.source.DataSqlMapper; import org.redkale.source.DataSqlMapper;
import org.redkale.source.DataSqlSource; import org.redkale.source.DataSqlSource;
import org.redkale.source.EntityBuilder; import org.redkale.source.EntityBuilder;
import org.redkale.source.Flipper; import org.redkale.source.RowBound;
import org.redkale.source.SourceException; import org.redkale.source.SourceException;
import org.redkale.util.RedkaleClassLoader; import org.redkale.util.RedkaleClassLoader;
import org.redkale.util.Sheet; import org.redkale.util.Sheet;
@@ -122,21 +122,21 @@ public final class DataSqlMapperBuilder {
AsmMethodBean methodBean = selfMethodBeans.get(AsmMethodBoost.getMethodBeanKey(method)); AsmMethodBean methodBean = selfMethodBeans.get(AsmMethodBoost.getMethodBeanKey(method));
List<String> fieldNames = methodBean.paramNameList(method); List<String> fieldNames = methodBean.paramNameList(method);
Class resultClass = resultClass(method); Class resultClass = resultClass(method);
int flipperIndex = -1; int roundIndex = -1;
if (resultClass.isAssignableFrom(Sheet.class)) { if (resultClass.isAssignableFrom(Sheet.class)) {
Class[] pts = method.getParameterTypes(); Class[] pts = method.getParameterTypes();
for (int i = 0; i < pts.length; i++) { for (int i = 0; i < pts.length; i++) {
if (pts[i] == Flipper.class) { if (RowBound.class.isAssignableFrom(pts[i])) {
flipperIndex = i; roundIndex = i;
break; break;
} }
} }
if (flipperIndex < 0) { if (roundIndex < 0) {
throw new SourceException( throw new SourceException(
mapperType.getSimpleName() + "." + method.getName() + " need Flipper type parameter on @" mapperType.getSimpleName() + "." + method.getName() + " need RowBound type parameter on @"
+ Sql.class.getSimpleName() + "(" + sql.value() + ")"); + Sql.class.getSimpleName() + "(" + sql.value() + ")");
} }
fieldNames.remove(flipperIndex); fieldNames.remove(roundIndex);
} }
if (!Utility.equalsElement(sqlInfo.getRootParamNames(), fieldNames)) { if (!Utility.equalsElement(sqlInfo.getRootParamNames(), fieldNames)) {
throw new SourceException(mapperType.getSimpleName() + "." + method.getName() throw new SourceException(mapperType.getSimpleName() + "." + method.getName()
@@ -148,13 +148,13 @@ public final class DataSqlMapperBuilder {
throw new SourceException("Update SQL must on return int method, but " + method); throw new SourceException("Update SQL must on return int method, but " + method);
} }
} }
items.add(new Item(method, sqlInfo, methodBean, flipperIndex)); items.add(new Item(method, sqlInfo, methodBean, roundIndex));
} }
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
final String utilClassName = Utility.class.getName().replace('.', '/'); final String utilClassName = Utility.class.getName().replace('.', '/');
final String sheetDesc = Type.getDescriptor(Sheet.class); final String sheetDesc = Type.getDescriptor(Sheet.class);
final String flipperDesc = Type.getDescriptor(Flipper.class); final String roundDesc = Type.getDescriptor(RowBound.class);
final String entityDesc = Type.getDescriptor(entityType); final String entityDesc = Type.getDescriptor(entityType);
final String sqlSourceName = DataSqlSource.class.getName().replace('.', '/'); final String sqlSourceName = DataSqlSource.class.getName().replace('.', '/');
final String sqlSourceDesc = Type.getDescriptor(DataSqlSource.class); final String sqlSourceDesc = Type.getDescriptor(DataSqlSource.class);
@@ -218,7 +218,7 @@ public final class DataSqlMapperBuilder {
Method method = item.method; Method method = item.method;
DataNativeSqlInfo sqlInfo = item.sqlInfo; DataNativeSqlInfo sqlInfo = item.sqlInfo;
AsmMethodBean methodBean = item.methodBean; AsmMethodBean methodBean = item.methodBean;
int flipperIndex = item.flipperIndex; int roundIndex = item.roundIndex;
Sql sql = method.getAnnotation(Sql.class); Sql sql = method.getAnnotation(Sql.class);
Class resultClass = resultClass(method); Class resultClass = resultClass(method);
Class[] componentTypes = resultComponentType(method); Class[] componentTypes = resultComponentType(method);
@@ -247,16 +247,16 @@ public final class DataSqlMapperBuilder {
} }
// 参数sql // 参数sql
mv.visitLdcInsn(sql.value()); mv.visitLdcInsn(sql.value());
if (flipperIndex >= 0) { if (roundIndex >= 0) {
mv.visitVarInsn(ALOAD, flipperIndex + 1); mv.visitVarInsn(ALOAD, roundIndex + 1);
} }
// 参数: params // 参数: params
Asms.visitInsn(mv, paramTypes.length * 2 - (flipperIndex >= 0 ? 2 : 0)); Asms.visitInsn(mv, paramTypes.length * 2 - (roundIndex >= 0 ? 2 : 0));
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
int insn = 0; int insn = 0;
for (int i = 0; i < paramTypes.length; i++) { for (int i = 0; i < paramTypes.length; i++) {
insn++; insn++;
if (i != flipperIndex) { if (i != roundIndex) {
Class pt = paramTypes[i]; Class pt = paramTypes[i];
// 参数名 // 参数名
mv.visitInsn(DUP); mv.visitInsn(DUP);
@@ -293,7 +293,7 @@ public final class DataSqlMapperBuilder {
// Map: "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/Map;" // Map: "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/Map;"
// List: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/List;" // List: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/List;"
// Sheet: // Sheet:
// "(Ljava/lang/Class;Ljava/lang/String;Lorg/redkale/source/Flipper;Ljava/util/Map;)Lorg/redkale/util/Sheet;" // "(Ljava/lang/Class;Ljava/lang/String;Lorg/redkale/source/RowRound;Ljava/util/Map;)Lorg/redkale/util/Sheet;"
// Async: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/concurrent/CompletableFuture;" // Async: "(Ljava/lang/Class;Ljava/lang/String;Ljava/util/Map;)Ljava/util/concurrent/CompletableFuture;"
if (sqlInfo.getSqlMode() == SELECT) { if (sqlInfo.getSqlMode() == SELECT) {
String queryMethodName = "nativeQueryOne"; String queryMethodName = "nativeQueryOne";
@@ -313,7 +313,7 @@ public final class DataSqlMapperBuilder {
} else if (resultClass.isAssignableFrom(Sheet.class)) { } else if (resultClass.isAssignableFrom(Sheet.class)) {
oneMode = false; oneMode = false;
queryMethodName = "nativeQuerySheet"; queryMethodName = "nativeQuerySheet";
queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/String;" + flipperDesc + "Ljava/util/Map;)" queryMethodDesc = "(Ljava/lang/Class;Ljava/lang/String;" + roundDesc + "Ljava/util/Map;)"
+ (async ? "Ljava/util/concurrent/CompletableFuture;" : sheetDesc); + (async ? "Ljava/util/concurrent/CompletableFuture;" : sheetDesc);
} }
mv.visitMethodInsn( mv.visitMethodInsn(
@@ -453,13 +453,13 @@ public final class DataSqlMapperBuilder {
public AsmMethodBean methodBean; public AsmMethodBean methodBean;
public int flipperIndex = -1; public int roundIndex = -1;
public Item(Method method, DataNativeSqlInfo sqlInfo, AsmMethodBean methodBean, int flipperIndex) { public Item(Method method, DataNativeSqlInfo sqlInfo, AsmMethodBean methodBean, int roundIndex) {
this.method = method; this.method = method;
this.sqlInfo = sqlInfo; this.sqlInfo = sqlInfo;
this.methodBean = methodBean; this.methodBean = methodBean;
this.flipperIndex = flipperIndex; this.roundIndex = roundIndex;
} }
} }
} }