forked from plusone/plusone-commons
Compare commits
2 Commits
refactor/p
...
feature/nu
Author | SHA1 | Date | |
---|---|---|---|
825a99dab6 | |||
f3218420ed |
@@ -27,6 +27,7 @@ import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.Virtual;
|
||||
import xyz.zhouxy.plusone.commons.collection.CollectionTools;
|
||||
import xyz.zhouxy.plusone.commons.util.RegexTools;
|
||||
import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
@@ -44,10 +45,30 @@ import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
*/
|
||||
public class PagingAndSortingQueryParams {
|
||||
|
||||
private static final int DEFAULT_PAGE_SIZE = 15;
|
||||
|
||||
private Integer size;
|
||||
private Long pageNum;
|
||||
private List<String> orderBy;
|
||||
|
||||
private static final Pattern SORT_STR_PATTERN = Pattern.compile("^[a-zA-Z][\\w-]{0,63}-(desc|asc|DESC|ASC)$");
|
||||
|
||||
private final Map<String, String> sortableProperties;
|
||||
|
||||
/**
|
||||
* 构造分页排序查询参数
|
||||
*
|
||||
* @param sortableProperties 可排序的属性。不可为空。
|
||||
*/
|
||||
public PagingAndSortingQueryParams(Map<String, String> sortableProperties) {
|
||||
checkArgument(CollectionTools.isNotEmpty(sortableProperties),
|
||||
"Sortable properties can not be empty.");
|
||||
sortableProperties.forEach((k, v) ->
|
||||
checkArgument(StringTools.isNotBlank(k) && StringTools.isNotBlank(v),
|
||||
"Property name must not be blank."));
|
||||
this.sortableProperties = ImmutableMap.copyOf(sortableProperties);
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
/**
|
||||
@@ -79,18 +100,56 @@ public class PagingAndSortingQueryParams {
|
||||
|
||||
// Setters end
|
||||
|
||||
/**
|
||||
* 构建分页参数
|
||||
*
|
||||
* @return {@code PagingParams} 对象
|
||||
*/
|
||||
public final PagingParams buildPagingParams() {
|
||||
final int sizeValue = this.size != null ? this.size : defaultSizeInternal();
|
||||
final long pageNumValue = this.pageNum != null ? this.pageNum : 1L;
|
||||
checkArgument(CollectionTools.isNotEmpty(this.orderBy),
|
||||
"The 'orderBy' cannot be empty");
|
||||
final List<SortableProperty> propertiesToSort = this.orderBy.stream()
|
||||
.map(this::generateSortableProperty)
|
||||
.collect(Collectors.toList());
|
||||
return new PagingParams(sizeValue, pageNumValue, propertiesToSort);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认每页大小
|
||||
*
|
||||
* <p>NOTE: 可覆写此方法</p>
|
||||
*
|
||||
* @return 默认每页大小
|
||||
*/
|
||||
@Virtual
|
||||
protected int defaultSizeInternal() {
|
||||
return DEFAULT_PAGE_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PagingAndSortingQueryParams ["
|
||||
+ "size=" + size
|
||||
+ ", pageNum=" + pageNum
|
||||
+ ", orderBy=" + orderBy
|
||||
+ ", sortableProperties=" + sortableProperties
|
||||
+ "]";
|
||||
}
|
||||
|
||||
protected static PagingParamsBuilder pagingParamsBuilder(
|
||||
int defaultSize, int maxSize, Map<String, String> sortableProperties) {
|
||||
return new PagingParamsBuilder(defaultSize, maxSize, sortableProperties);
|
||||
private SortableProperty generateSortableProperty(String orderByStr) {
|
||||
checkArgument(StringTools.isNotBlank(orderByStr));
|
||||
checkArgument(RegexTools.matches(orderByStr, SORT_STR_PATTERN));
|
||||
String[] propertyNameAndOrderType = orderByStr.split("-");
|
||||
checkArgument(propertyNameAndOrderType.length == 2);
|
||||
|
||||
String propertyName = propertyNameAndOrderType[0];
|
||||
checkArgument(sortableProperties.containsKey(propertyName),
|
||||
"The property name must be in the set of sortable properties.");
|
||||
String columnName = sortableProperties.get(propertyName);
|
||||
String orderType = propertyNameAndOrderType[1];
|
||||
return new SortableProperty(propertyName, columnName, orderType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,47 +217,4 @@ public class PagingAndSortingQueryParams {
|
||||
}
|
||||
}
|
||||
|
||||
protected static final class PagingParamsBuilder {
|
||||
private static final Pattern SORT_STR_PATTERN = Pattern.compile("^[a-zA-Z][\\w-]{0,63}-(desc|asc|DESC|ASC)$");
|
||||
|
||||
private final Map<String, String> sortableProperties;
|
||||
protected final int defaultSize;
|
||||
protected final int maxSize;
|
||||
|
||||
private PagingParamsBuilder(int defaultSize, int maxSize, Map<String, String> sortableProperties) {
|
||||
this.defaultSize = defaultSize;
|
||||
this.maxSize = maxSize;
|
||||
checkArgument(CollectionTools.isNotEmpty(sortableProperties),
|
||||
"Sortable properties can not be empty.");
|
||||
sortableProperties.forEach((k, v) ->
|
||||
checkArgument(StringTools.isNotBlank(k) && StringTools.isNotBlank(v),
|
||||
"Property name must not be blank."));
|
||||
this.sortableProperties = ImmutableMap.copyOf(sortableProperties);
|
||||
}
|
||||
|
||||
public PagingParams buildPagingParams(PagingAndSortingQueryParams params) {
|
||||
final int sizeValue = params.size != null ? params.size : this.defaultSize;
|
||||
final long pageNumValue = params.pageNum != null ? params.pageNum : 1L;
|
||||
checkArgument(CollectionTools.isNotEmpty(params.orderBy),
|
||||
"The 'orderBy' cannot be empty");
|
||||
final List<SortableProperty> propertiesToSort = params.orderBy.stream()
|
||||
.map(this::generateSortableProperty)
|
||||
.collect(Collectors.toList());
|
||||
return new PagingParams(sizeValue, pageNumValue, propertiesToSort);
|
||||
}
|
||||
|
||||
private SortableProperty generateSortableProperty(String orderByStr) {
|
||||
checkArgument(StringTools.isNotBlank(orderByStr));
|
||||
checkArgument(RegexTools.matches(orderByStr, SORT_STR_PATTERN));
|
||||
String[] propertyNameAndOrderType = orderByStr.split("-");
|
||||
checkArgument(propertyNameAndOrderType.length == 2);
|
||||
|
||||
String propertyName = propertyNameAndOrderType[0];
|
||||
checkArgument(sortableProperties.containsKey(propertyName),
|
||||
"The property name must be in the set of sortable properties.");
|
||||
String columnName = sortableProperties.get(propertyName);
|
||||
String orderType = propertyNameAndOrderType[1];
|
||||
return new SortableProperty(propertyName, columnName, orderType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,9 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public class Numbers {
|
||||
|
||||
// ================================
|
||||
// #region - sum
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 求和
|
||||
@@ -131,9 +133,13 @@ public class Numbers {
|
||||
return BigDecimals.sum(numbers);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - nullToZero
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将 {@code null} 转换为 {@code 0}
|
||||
@@ -217,7 +223,122 @@ public class Numbers {
|
||||
return BigDecimals.nullToZero(val);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
// ================================
|
||||
// #endregion - nullToZero
|
||||
// ================================
|
||||
|
||||
// ================================
|
||||
// #region - parse
|
||||
// ================================
|
||||
|
||||
/**
|
||||
* 将字符串转为对应 {@link Short},转换失败时返回 {@code defaultValue}(允许为 {@code null})。
|
||||
*
|
||||
* @param str 要转换的字符串
|
||||
* @param defaultValue 默认值
|
||||
* @return 转换结果
|
||||
*/
|
||||
@Nullable
|
||||
public static Short parseShort(@Nullable String str, @Nullable Short defaultValue) {
|
||||
if (StringTools.isBlank(str)) {
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
return Short.parseShort(str);
|
||||
}
|
||||
catch (NumberFormatException ignore) {
|
||||
// ignore
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转为 {@link Integer},转换失败时返回 {@code defaultValue}(允许为 {@code null})。
|
||||
*
|
||||
* @param str 要转换的字符串
|
||||
* @param defaultValue 默认值
|
||||
* @return 转换结果
|
||||
*/
|
||||
@Nullable
|
||||
public static Integer parseInteger(@Nullable String str, @Nullable Integer defaultValue) {
|
||||
if (StringTools.isBlank(str)) {
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(str);
|
||||
}
|
||||
catch (NumberFormatException ignore) {
|
||||
// ignore
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转为 {@link Long},转换失败时返回 {@code defaultValue}(允许为 {@code null})。
|
||||
*
|
||||
* @param str 要转换的字符串
|
||||
* @param defaultValue 默认值
|
||||
* @return 转换结果
|
||||
*/
|
||||
@Nullable
|
||||
public static Long parseLong(@Nullable String str, @Nullable Long defaultValue) {
|
||||
if (StringTools.isBlank(str)) {
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(str);
|
||||
}
|
||||
catch (NumberFormatException ignore) {
|
||||
// ignore
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转为 {@link Float},转换失败时返回 {@code defaultValue}(允许为 {@code null})。
|
||||
*
|
||||
* @param str 要转换的字符串
|
||||
* @param defaultValue 默认值
|
||||
* @return 转换结果
|
||||
*/
|
||||
@Nullable
|
||||
public static Float parseFloat(@Nullable String str, @Nullable Float defaultValue) {
|
||||
if (StringTools.isBlank(str)) {
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
return Float.parseFloat(str);
|
||||
}
|
||||
catch (NumberFormatException ignore) {
|
||||
// ignore
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串转为 {@link Double},转换失败时返回 {@code defaultValue}(允许为 {@code null})。
|
||||
*
|
||||
* @param str 要转换的字符串
|
||||
* @param defaultValue 默认值
|
||||
* @return 转换结果
|
||||
*/
|
||||
@Nullable
|
||||
public static Double parseDouble(@Nullable String str, @Nullable Double defaultValue) {
|
||||
if (StringTools.isBlank(str)) {
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
return Double.parseDouble(str);
|
||||
}
|
||||
catch (NumberFormatException ignore) {
|
||||
// ignore
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// #endregion - parse
|
||||
// ================================
|
||||
|
||||
private Numbers() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
|
@@ -231,8 +231,9 @@ class AccountQueryParams extends PagingAndSortingQueryParams {
|
||||
.put("createTime", "create_time")
|
||||
.build();
|
||||
|
||||
private static final PagingParamsBuilder PAGING_PARAMS_BUILDER = PagingAndSortingQueryParams
|
||||
.pagingParamsBuilder(20, 100, PROPERTY_COLUMN_MAP);
|
||||
public AccountQueryParams() {
|
||||
super(PROPERTY_COLUMN_MAP);
|
||||
}
|
||||
|
||||
private @Getter @Setter Long id;
|
||||
private @Getter @Setter String username;
|
||||
@@ -248,10 +249,6 @@ class AccountQueryParams extends PagingAndSortingQueryParams {
|
||||
}
|
||||
return this.createTimeEnd.plusDays(1);
|
||||
}
|
||||
|
||||
public PagingParams buildPagingParams() {
|
||||
return PAGING_PARAMS_BUILDER.buildPagingParams(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
|
@@ -26,6 +26,7 @@ import java.util.Arrays;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public
|
||||
@@ -68,9 +69,16 @@ class NumbersTests {
|
||||
|
||||
@Test
|
||||
public void sum_BigIntegerArray_ReturnsCorrectSum() {
|
||||
BigInteger[] numbers = {new BigInteger("1"), new BigInteger("2"), new BigInteger("3")};
|
||||
BigInteger[] numbers = {
|
||||
new BigInteger("1"),
|
||||
new BigInteger("2"),
|
||||
null,
|
||||
new BigInteger("3")
|
||||
};
|
||||
BigInteger result = Numbers.sum(numbers);
|
||||
assertEquals(new BigInteger("6"), result);
|
||||
|
||||
assertEquals(BigInteger.ZERO, Numbers.sum(new BigInteger[0]));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -192,6 +200,100 @@ class NumbersTests {
|
||||
assertEquals(BigDecimal.ZERO, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link Numbers#parseShort(String, Short)}.
|
||||
*/
|
||||
@Test
|
||||
public void parseShort() {
|
||||
assertEquals((short) 12345, Numbers.parseShort("12345", (short) 5));
|
||||
assertEquals((short) 5, Numbers.parseShort("1234.5", (short) 5));
|
||||
assertEquals((short) 5, Numbers.parseShort("", (short) 5));
|
||||
assertEquals((short) 5, Numbers.parseShort(null, (short) 5));
|
||||
|
||||
assertEquals((short) 12345, Numbers.parseShort("12345", null));
|
||||
assertNull(Numbers.parseShort("1234.5", null));
|
||||
assertNull(Numbers.parseShort("", null));
|
||||
assertNull(Numbers.parseShort(null, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link Numbers#parseInteger(String, Integer)}.
|
||||
*/
|
||||
@Test
|
||||
public void parseInteger() {
|
||||
assertEquals(12345, Numbers.parseInteger("12345", 5));
|
||||
assertEquals(5, Numbers.parseInteger("1234.5", 5));
|
||||
assertEquals(5, Numbers.parseInteger("", 5));
|
||||
assertEquals(5, Numbers.parseInteger(null, 5));
|
||||
|
||||
assertEquals(12345, Numbers.parseInteger("12345", null));
|
||||
assertNull(Numbers.parseInteger("1234.5", null));
|
||||
assertNull(Numbers.parseInteger("", null));
|
||||
assertNull(Numbers.parseInteger(null, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link Numbers#parseLong(String, Long)}.
|
||||
*/
|
||||
@Test
|
||||
public void parseLong() {
|
||||
assertEquals(12345L, Numbers.parseLong("12345", 5L));
|
||||
assertEquals(5L, Numbers.parseLong("1234.5", 5L));
|
||||
assertEquals(5L, Numbers.parseLong("", 5L));
|
||||
assertEquals(5L, Numbers.parseLong(null, 5L));
|
||||
|
||||
assertEquals(12345L, Numbers.parseLong("12345", null));
|
||||
assertNull(Numbers.parseLong("1234.5", null));
|
||||
assertNull(Numbers.parseLong("", null));
|
||||
assertNull(Numbers.parseLong(null, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link Numbers#parseFloat(String, Float)}.
|
||||
*/
|
||||
@Test
|
||||
public void parseFloat() {
|
||||
assertEquals(1.2345f, Numbers.parseFloat("1.2345", 5.1f));
|
||||
assertEquals(5.0f, Numbers.parseFloat("a", 5.0f));
|
||||
assertEquals(5.0f, Numbers.parseFloat("-001Z.2345", 5.0f));
|
||||
assertEquals(5.0f, Numbers.parseFloat("+001AB.2345", 5.0f));
|
||||
assertEquals(5.0f, Numbers.parseFloat("001Z.2345", 5.0f));
|
||||
assertEquals(5.0f, Numbers.parseFloat("", 5.0f));
|
||||
assertEquals(5.0f, Numbers.parseFloat(null, 5.0f));
|
||||
|
||||
assertEquals(1.2345f, Numbers.parseFloat("1.2345", null));
|
||||
assertNull(Numbers.parseFloat("a", null));
|
||||
assertNull(Numbers.parseFloat("-001Z.2345", null));
|
||||
assertNull(Numbers.parseFloat("+001AB.2345", null));
|
||||
assertNull(Numbers.parseFloat("001Z.2345", null));
|
||||
assertNull(Numbers.parseFloat("", null));
|
||||
assertNull(Numbers.parseFloat(null, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for {@link Numbers#parseDouble(String, Double)}.
|
||||
*/
|
||||
@Test
|
||||
public void parseDouble() {
|
||||
assertEquals(1.2345d, Numbers.parseDouble("1.2345", 5.1d));
|
||||
assertEquals(5.0d, Numbers.parseDouble("a", 5.0d));
|
||||
assertEquals(1.2345d, Numbers.parseDouble("001.2345", 5.1d));
|
||||
assertEquals(-1.2345d, Numbers.parseDouble("-001.2345", 5.1d));
|
||||
assertEquals(1.2345d, Numbers.parseDouble("+001.2345", 5.1d));
|
||||
assertEquals(0d, Numbers.parseDouble("000.00", 5.1d));
|
||||
assertEquals(5.1d, Numbers.parseDouble("", 5.1d));
|
||||
assertEquals(5.1d, Numbers.parseDouble((String) null, 5.1d));
|
||||
|
||||
assertEquals(1.2345d, Numbers.parseDouble("1.2345", null));
|
||||
assertEquals(null, Numbers.parseDouble("a", null));
|
||||
assertEquals(1.2345d, Numbers.parseDouble("001.2345", null));
|
||||
assertEquals(-1.2345d, Numbers.parseDouble("-001.2345", null));
|
||||
assertEquals(1.2345d, Numbers.parseDouble("+001.2345", null));
|
||||
assertEquals(0d, Numbers.parseDouble("000.00", null));
|
||||
assertEquals(null, Numbers.parseDouble("", null));
|
||||
assertEquals(null, Numbers.parseDouble((String) null, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_constructor_isNotAccessible_ThrowsIllegalStateException() {
|
||||
Constructor<?>[] constructors = Numbers.class.getDeclaredConstructors();
|
||||
|
Reference in New Issue
Block a user