From 653345718aecbda5ac189795ccc9bd8f5344115b Mon Sep 17 00:00:00 2001 From: wxm <115806199+youfanx@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:35:40 +0800 Subject: [PATCH 1/3] up --- .../main/java/org/rx/core/CpuWatchman.java | 8 ++++-- .../src/main/java/org/rx/core/ThreadPool.java | 28 ++++++++++++++----- .../java/org/rx/io/EntityQueryLambda.java | 2 ++ .../main/java/org/rx/spring/Interceptors.java | 19 +++++++++++-- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/rxlib/src/main/java/org/rx/core/CpuWatchman.java b/rxlib/src/main/java/org/rx/core/CpuWatchman.java index 02142a4c..e4b478cf 100644 --- a/rxlib/src/main/java/org/rx/core/CpuWatchman.java +++ b/rxlib/src/main/java/org/rx/core/CpuWatchman.java @@ -232,9 +232,11 @@ private void scheduledThread(Decimal cpuLoad, ThreadPoolExecutor pool, Tuple conf.minDynamicSize && (idle <= waterMark.getHigh() || cpuLoad.gt(waterMark.getHigh()))) { diff --git a/rxlib/src/main/java/org/rx/core/ThreadPool.java b/rxlib/src/main/java/org/rx/core/ThreadPool.java index 58a3bc4e..124c269e 100644 --- a/rxlib/src/main/java/org/rx/core/ThreadPool.java +++ b/rxlib/src/main/java/org/rx/core/ThreadPool.java @@ -74,7 +74,9 @@ public boolean offer(Runnable r) { wait(500); } } - log.debug("Wait poll ok"); + if (log.isDebugEnabled()) { + log.debug("Wait poll ok"); + } } counter.incrementAndGet(); Task task = pool.setTask(r); @@ -97,7 +99,9 @@ public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException { throw e; } finally { if (ok) { - log.debug("Notify poll"); + if (log.isDebugEnabled()) { + log.debug("Notify poll"); + } doNotify(); } } @@ -108,7 +112,9 @@ public Runnable take() throws InterruptedException { try { return super.take(); } finally { - log.debug("Notify take"); + if (log.isDebugEnabled()) { + log.debug("Notify take"); + } doNotify(); } } @@ -117,7 +123,9 @@ public Runnable take() throws InterruptedException { public boolean remove(Object o) { boolean ok = super.remove(o); if (ok) { - log.debug("Notify remove"); + if (log.isDebugEnabled()) { + log.debug("Notify remove"); + } doNotify(); } return ok; @@ -612,12 +620,16 @@ protected void beforeExecute(Thread t, Runnable r) { throw new InterruptedException(String.format("SingleScope %s locked by other thread", task.id)); } ctx.incrementRefCnt(); - log.debug("CTX tryLock {} -> {}", task.id, flags.name()); + if (log.isDebugEnabled()) { + log.debug("CTX tryLock {} -> {}", task.id, flags.name()); + } } else if (flags.has(RunFlag.SYNCHRONIZED)) { RefCounter ctx = getContextForLock(task.id); ctx.incrementRefCnt(); ctx.ref.lock(); - log.debug("CTX lock {} -> {}", task.id, flags.name()); + if (log.isDebugEnabled()) { + log.debug("CTX lock {} -> {}", task.id, flags.name()); + } } if (flags.has(RunFlag.PRIORITY) && !getQueue().isEmpty()) { CpuWatchman.incrSize(this); @@ -668,7 +680,9 @@ protected void afterExecute(Runnable r, Throwable t) { taskLockMap.remove(id); doRemove = true; } - log.debug("CTX unlock{} {} -> {}", doRemove ? " & clear" : "", id, task.flags.name()); + if (log.isDebugEnabled()) { + log.debug("CTX unlock{} {} -> {}", doRemove ? " & clear" : "", id, task.flags.name()); + } ctx.ref.unlock(); } } diff --git a/rxlib/src/main/java/org/rx/io/EntityQueryLambda.java b/rxlib/src/main/java/org/rx/io/EntityQueryLambda.java index f61b9214..788f147b 100644 --- a/rxlib/src/main/java/org/rx/io/EntityQueryLambda.java +++ b/rxlib/src/main/java/org/rx/io/EntityQueryLambda.java @@ -1,5 +1,6 @@ package org.rx.io; +import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; import org.apache.commons.collections4.CollectionUtils; @@ -48,6 +49,7 @@ static void pkClaus(StringBuilder sql, String pk) { sql.append(WHERE).appendFormat(Operator.EQ.format, pk, PARAM_HOLD); } + @Getter final Class entityType; final ArrayList> conditions = new ArrayList<>(); final List, Order>> orders = new ArrayList<>(); diff --git a/rxlib/src/main/java/org/rx/spring/Interceptors.java b/rxlib/src/main/java/org/rx/spring/Interceptors.java index 5f482da5..70918089 100644 --- a/rxlib/src/main/java/org/rx/spring/Interceptors.java +++ b/rxlib/src/main/java/org/rx/spring/Interceptors.java @@ -16,7 +16,9 @@ import org.rx.util.Validator; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.stereotype.Component; +import org.springframework.validation.BindException; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; @@ -27,10 +29,13 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; import java.lang.reflect.Executable; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; import static org.rx.core.Extends.as; import static org.rx.core.Sys.logCtx; @@ -107,13 +112,23 @@ protected Tuple httpEnv() { @ExceptionHandler({Throwable.class}) @ResponseStatus(HttpStatus.OK) @ResponseBody - public Object onException(Throwable e, HttpServletRequest request) { + public Object onException(Throwable e) { String msg = null; - if (e instanceof MethodArgumentNotValidException) { + if (e instanceof ConstraintViolationException) { + ConstraintViolationException error = (ConstraintViolationException) e; + msg = error.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining()); + } else if (e instanceof MethodArgumentNotValidException) { FieldError fieldError = ((MethodArgumentNotValidException) e).getBindingResult().getFieldError(); if (fieldError != null) { msg = String.format("Field '%s' %s", fieldError.getField(), fieldError.getDefaultMessage()); } + } else if (e instanceof BindException) { + FieldError fieldError = ((BindException) e).getFieldError(); + if (fieldError != null) { + msg = String.format("Field '%s' %s", fieldError.getField(), fieldError.getDefaultMessage()); + } + } else if (e instanceof HttpMessageNotReadableException) { + msg = "Request body not readable"; } if (msg == null) { msg = ApplicationException.getMessage(e); From 5b2cf5214b3f11dd70550ee97e1aed5eb9a1d1dd Mon Sep 17 00:00:00 2001 From: wxm <115806199+youfanx@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:03:46 +0800 Subject: [PATCH 2/3] up --- .../main/java/org/rx/core/CpuWatchman.java | 12 +- rxlib/src/main/java/org/rx/core/Numbers.java | 286 ++++++++++++++++++ .../src/main/java/org/rx/core/ThreadPool.java | 5 +- rxlib/src/main/resources/rx.yml | 2 +- 4 files changed, 296 insertions(+), 9 deletions(-) diff --git a/rxlib/src/main/java/org/rx/core/CpuWatchman.java b/rxlib/src/main/java/org/rx/core/CpuWatchman.java index e4b478cf..2cf48eda 100644 --- a/rxlib/src/main/java/org/rx/core/CpuWatchman.java +++ b/rxlib/src/main/java/org/rx/core/CpuWatchman.java @@ -191,15 +191,15 @@ private void thread(Decimal cpuLoad, ThreadPoolExecutor pool, Tuple= RxConfig.INSTANCE.threadPool.samplingTimes) { - log.info("{} PoolSize={}+[{}] Threshold={}[{}-{}]% decrement to {}", prefix, - pool.getPoolSize(), pool.getQueue().size(), + log.info("{} PoolSize={}/{}+[{}] Threshold={}[{}-{}]% decrement to {}", prefix, + pool.getPoolSize(), pool.getCorePoolSize(), pool.getQueue().size(), cpuLoad, waterMark.getLow(), waterMark.getHigh(), decrSize(pool)); decrementCounter = 0; } @@ -209,8 +209,8 @@ private void thread(Decimal cpuLoad, ThreadPoolExecutor pool, Tuple= RxConfig.INSTANCE.threadPool.samplingTimes) { - log.info("{} PoolSize={}+[{}] Threshold={}[{}-{}]% increment to {}", prefix, - pool.getPoolSize(), pool.getQueue().size(), + log.info("{} PoolSize={}/{}+[{}] Threshold={}[{}-{}]% increment to {}", prefix, + pool.getPoolSize(), pool.getCorePoolSize(), pool.getQueue().size(), cpuLoad, waterMark.getLow(), waterMark.getHigh(), incrSize(pool)); incrementCounter = 0; } diff --git a/rxlib/src/main/java/org/rx/core/Numbers.java b/rxlib/src/main/java/org/rx/core/Numbers.java index e47f7726..c72e0d79 100644 --- a/rxlib/src/main/java/org/rx/core/Numbers.java +++ b/rxlib/src/main/java/org/rx/core/Numbers.java @@ -1,6 +1,9 @@ package org.rx.core; import org.apache.commons.lang3.math.NumberUtils; +import org.rx.exception.InvalidException; + +import java.math.BigDecimal; import static org.rx.core.Constants.PERCENT; @@ -29,4 +32,287 @@ public static int toPercent(double val) { public static boolean hasPrecision(double n) { return n % 1 == 0; } + + /** + * @author Andy + * @since 2023-04-23 18:45 + */ + public static class ChineseNumbers { + /** + * 中文数字 + */ + private static final char[] cnArr_a = new char[]{'零', '一', '二', '三', '四', '五', '六', '七', '八', '九'}; + private static final char[] cnArr_A = new char[]{'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'}; + private static final String allChineseNum = "零一二三四五六七八九壹贰叁肆伍陆柒捌玖十拾百佰千仟万萬亿"; + + /** + * 中文单位 + */ + private static final char[] unit_a = new char[]{'亿', '万', '千', '百', '十'}; + private static final char[] unit_A = new char[]{'亿', '萬', '仟', '佰', '拾'}; + private static final String allChineseUnit = "十拾百佰千仟万萬亿"; + + public static BigDecimal toArabicNum(String chineseNum) { + return toArabicNum(chineseNum, null); + } + + /** + * 将汉字中的数字转换为阿拉伯数字 + * (例如:三万叁仟零肆拾伍亿零贰佰萬柒仟陆佰零伍) + * + * @param chineseNum; + * @return long + */ + public static BigDecimal toArabicNum(String chineseNum, BigDecimal defaultValue) { + if (chineseNum == null || chineseNum.trim().length() == 0) { + if (defaultValue == null) { + throw new IllegalArgumentException("chineseNum"); + } + return defaultValue; + } + + // 最终返回的结果 + BigDecimal result = new BigDecimal(0); + + char firstUnit = chineseNum.charAt(0); + char lastUnit = chineseNum.charAt(chineseNum.length() - 1); + + Boolean appendUnit = true; + long lastUnitNum = 1; + if (isCnUnit(firstUnit) && chineseNum.length() > 1) { + // 两位数 + long firstNum = chnNameValue[chnUnitToValue(String.valueOf(firstUnit))].value; + if (!isCnUnit(lastUnit) && chineseNum.length() == 2) { + long number = chnStringToNumber(String.valueOf(lastUnit)); + result = result.add(BigDecimal.valueOf(firstNum).add(BigDecimal.valueOf(number))); + return result; + } else if (isCnUnit(lastUnit)) { + ChnNameValue chnValue = chnNameValue[chnUnitToValue(String.valueOf(lastUnit))]; + if (firstNum == 10 && chnValue.secUnit) { + chineseNum = "一" + chineseNum; + } else { + throw new NumberFormatException("中文数字异常"); + } + } + } + + if (isCnUnit(lastUnit)) { + chineseNum = chineseNum.substring(0, chineseNum.length() - 1); + lastUnitNum = chnNameValue[chnUnitToValue(String.valueOf(lastUnit))].value; + appendUnit = chnNameValue[chnUnitToValue(String.valueOf(lastUnit))].secUnit; + } else if (chineseNum.length() == 1) { + // 如果长度为1时 + int num = strToNum(chineseNum); + if (num != -1) { + return BigDecimal.valueOf(num); + } else if (isDigits(chineseNum)) { + return new BigDecimal(chineseNum); + } else { + if (defaultValue == null) { + throw new IllegalArgumentException("chineseNum"); + } + return defaultValue; + } + } + + // 将小写中文数字转为大写中文数字 + for (int i = 0; i < cnArr_a.length; i++) { + chineseNum = chineseNum.replaceAll(String.valueOf(cnArr_a[i]), String.valueOf(cnArr_A[i])); + } + // 将小写单位转为大写单位 + for (int i = 0; i < unit_a.length; i++) { + chineseNum = chineseNum.replaceAll(String.valueOf(unit_a[i]), String.valueOf(unit_A[i])); + } + + for (int i = 0; i < unit_A.length; i++) { + if (chineseNum.trim().length() == 0) { + break; + } + String unitUpperCase = String.valueOf(unit_A[i]); + String str = null; + if (chineseNum.contains(unitUpperCase)) { + str = chineseNum.substring(0, chineseNum.lastIndexOf(unitUpperCase) + 1); + } + if (str != null && str.trim().length() > 0) { + // 下次循环截取的基础字符串 + chineseNum = chineseNum.replaceAll(str, ""); + // 单位基础值 + long unitNum = chnNameValue[chnUnitToValue(unitUpperCase)].value; + String temp = str.substring(0, str.length() - 1); + long number = chnStringToNumber(temp); + result = result.add(BigDecimal.valueOf(number).multiply(BigDecimal.valueOf(unitNum))); + } + // 最后一次循环,被传入的数字没有处理完并且没有单位的个位数处理 + if (i + 1 == unit_a.length && !"".equals(chineseNum)) { + long number = chnStringToNumber(chineseNum); + if (!appendUnit) { + number = BigDecimal.valueOf(number).multiply(BigDecimal.valueOf(lastUnitNum)).longValue(); + } + result = result.add(BigDecimal.valueOf(number)); + } + } + // 加上单位 + if (appendUnit && lastUnitNum > 1) { + result = result.multiply(BigDecimal.valueOf(lastUnitNum)); + } else if (lastUnitNum > 0) { + if (result.compareTo(BigDecimal.ZERO) == BigDecimal.ZERO.intValue()) { + result = BigDecimal.ONE; + result = result.multiply(BigDecimal.valueOf(lastUnitNum)); + } + } + return result; + } + + /** + * 判断传入的字符串是否全是汉字数字和单位 + * + * @param chineseStr; + * @return boolean + */ + public static boolean isAllCnNum(String chineseStr) { + if (Strings.isBlank(chineseStr)) { + return true; + } + char[] charArray = chineseStr.toCharArray(); + for (char c : charArray) { + if (!allChineseNum.contains(String.valueOf(c))) { + return false; + } + } + return true; + } + + /** + * 判断传入的字符是否是汉字数字和单位 + * + * @param chineseChar; + * @return boolean + */ + public static boolean isCnNum(char chineseChar) { + return allChineseNum.contains(String.valueOf(chineseChar)); + } + + /** + * 判断是否是中文单位 + * + * @param unitStr; + * @return boolean + */ + public static boolean isCnUnit(char unitStr) { + return allChineseUnit.contains(String.valueOf(unitStr)); + } + + /** + * 中文转换成阿拉伯数字,中文字符串除了包括0-9的中文汉字,还包括十,百,千,万等权位。 + * 此处是完成对这些权位的类型定义。 + * name是指这些权位的汉字字符串。 + * value是指权位多对应的数值的大小。诸如:十对应的值的大小为10,百对应为100等 + * secUnit若为true,代表该权位为节权位,即万,亿,万亿等 + */ + static class ChnNameValue { + String name; + long value; + Boolean secUnit; + + ChnNameValue(String name, long value, Boolean secUnit) { + this.name = name; + this.value = value; + this.secUnit = secUnit; + } + } + + static ChnNameValue[] chnNameValue = { + new ChnNameValue("十", 10, false), + new ChnNameValue("拾", 10, false), + new ChnNameValue("百", 100, false), + new ChnNameValue("佰", 100, false), + new ChnNameValue("千", 1000, false), + new ChnNameValue("仟", 1000, false), + new ChnNameValue("万", 10000, true), + new ChnNameValue("萬", 10000, true), + new ChnNameValue("亿", 100000000, true) + }; + + /** + * 返回中文汉字权位在chnNameValue数组中所对应的索引号,若不为中文汉字权位,则返回-1 + * + * @param str; + * @return int + */ + private static int chnUnitToValue(String str) { + for (int i = 0; i < chnNameValue.length; i++) { + if (str.equals(chnNameValue[i].name)) { + return i; + } + } + return -1; + } + + /** + * 返回中文数字字符串所对应的int类型的阿拉伯数字 + * (千亿/12位数) + * + * @param str; + * @return long + */ + private static long chnStringToNumber(String str) { + long returnNumber = 0; + long section = 0; + int index = 0; + long number = 0; + while (index < str.length()) { + // 从左向右依次获取对应中文数字,取不到返回-1 + int num = strToNum(str.substring(index, index + 1)); + //若num>=0,代表该位置(pos),所对应的是数字不是权位。若小于0,则表示为权位 + if (num >= 0) { + number = num; + index++; + //pos是最后一位,直接将number加入到section中。 + if (index >= str.length()) { + section += number; + returnNumber += section; + break; + } + } else { + int chnNameValueIndex = chnUnitToValue(str.substring(index, index + 1)); + + if (chnNameValueIndex == -1) { + // 字符串存在除 数字和单位 以外的中文 + throw new NumberFormatException("字符串存在除 <数字和单位> 以外的中文"); + } + + //chnNameValue[chnNameValueIndex].secUnit==true,表示该位置所对应的权位是节权位, + if (chnNameValue[chnNameValueIndex].secUnit) { + section = (section + number) * chnNameValue[chnNameValueIndex].value; + returnNumber += section; + section = 0; + } else { + section += number * chnNameValue[chnNameValueIndex].value; + } + index++; + number = 0; + if (index >= str.length()) { + returnNumber += section; + break; + } + } + } + return returnNumber; + } + + /** + * 返回中文数字汉字所对应的阿拉伯数字,若str不为中文数字,则返回-1 + * + * @param string; + * @return int + */ + private static int strToNum(String string) { + for (int i = 0; i < cnArr_a.length; i++) { + if (string.length() == 1 && (string.charAt(0) == cnArr_a[i] || string.charAt(0) == cnArr_A[i])) { + return i; + } + } + return -1; + } + } } diff --git a/rxlib/src/main/java/org/rx/core/ThreadPool.java b/rxlib/src/main/java/org/rx/core/ThreadPool.java index 124c269e..4d0122e8 100644 --- a/rxlib/src/main/java/org/rx/core/ThreadPool.java +++ b/rxlib/src/main/java/org/rx/core/ThreadPool.java @@ -397,8 +397,9 @@ public ThreadPool(String poolName) { * @param queueCapacity LinkedTransferQueue 基于CAS的并发BlockingQueue的容量 */ public ThreadPool(int initSize, int queueCapacity, IntWaterMark cpuWaterMark, String poolName) { - super(checkSize(initSize), Integer.MAX_VALUE, - RxConfig.INSTANCE.threadPool.keepAliveSeconds, TimeUnit.SECONDS, new ThreadQueue(checkCapacity(queueCapacity)), newThreadFactory(poolName, Thread.NORM_PRIORITY), (r, executor) -> { + super(checkSize(initSize), RxConfig.INSTANCE.threadPool.maxDynamicSize, + RxConfig.INSTANCE.threadPool.keepAliveSeconds, TimeUnit.SECONDS, + new ThreadQueue(checkCapacity(queueCapacity)), newThreadFactory(poolName, Thread.NORM_PRIORITY), (r, executor) -> { if (executor.isShutdown()) { log.warn("ThreadPool {} is shutdown", poolName); return; diff --git a/rxlib/src/main/resources/rx.yml b/rxlib/src/main/resources/rx.yml index 7d08c772..8a94b993 100644 --- a/rxlib/src/main/resources/rx.yml +++ b/rxlib/src/main/resources/rx.yml @@ -9,7 +9,7 @@ app: samplingCpuPeriod: 30000 threadPool: initSize: 0 - keepAliveSeconds: 600 + keepAliveSeconds: 300 queueCapacity: 0 cpuWaterMark: low: 40 From 6a283d00355eb1c6f4cc4b60a28a8ee13a166a8c Mon Sep 17 00:00:00 2001 From: wxm <115806199+youfanx@users.noreply.github.com> Date: Tue, 15 Oct 2024 21:47:39 +0800 Subject: [PATCH 3/3] up --- rxlib/src/main/java/org/rx/core/Reflects.java | 7 ++++--- rxlib/src/main/java/org/rx/spring/Interceptors.java | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/rxlib/src/main/java/org/rx/core/Reflects.java b/rxlib/src/main/java/org/rx/core/Reflects.java index 99ad7181..e3c033d5 100644 --- a/rxlib/src/main/java/org/rx/core/Reflects.java +++ b/rxlib/src/main/java/org/rx/core/Reflects.java @@ -98,14 +98,15 @@ public Class getClassTrace(int depth) { throw InvalidException.sneaky(e); } + registerConvert(String.class, BigDecimal.class, (sv, tt) -> new BigDecimal(sv)); + registerConvert(String.class, UUID.class, (sv, tt) -> UUID.fromString(sv)); + registerConvert(String.class, Date.class, (sv, tt) -> DateTime.valueOf(sv)); registerConvert(Number.class, Decimal.class, (sv, tt) -> Decimal.valueOf(sv.doubleValue())); - registerConvert(NEnum.class, Integer.class, (sv, tt) -> sv.getValue()); registerConvert(Long.class, Date.class, (sv, tt) -> new Date(sv)); registerConvert(Long.class, DateTime.class, (sv, tt) -> new DateTime(sv, TimeZone.getDefault())); registerConvert(Date.class, Long.class, (sv, tt) -> sv.getTime()); registerConvert(Date.class, DateTime.class, (sv, tt) -> DateTime.of(sv)); - registerConvert(String.class, BigDecimal.class, (sv, tt) -> new BigDecimal(sv)); - registerConvert(String.class, UUID.class, (sv, tt) -> UUID.fromString(sv)); + registerConvert(NEnum.class, Integer.class, (sv, tt) -> sv.getValue()); } //region class diff --git a/rxlib/src/main/java/org/rx/spring/Interceptors.java b/rxlib/src/main/java/org/rx/spring/Interceptors.java index 70918089..7f0e39de 100644 --- a/rxlib/src/main/java/org/rx/spring/Interceptors.java +++ b/rxlib/src/main/java/org/rx/spring/Interceptors.java @@ -11,6 +11,7 @@ import org.rx.bean.Tuple; import org.rx.core.*; import org.rx.exception.ApplicationException; +import org.rx.exception.TraceHandler; import org.rx.net.http.HttpClient; import org.rx.util.Servlets; import org.rx.util.Validator; @@ -137,6 +138,7 @@ public Object onException(Throwable e) { if (SpringContext.controllerExceptionHandler != null) { return SpringContext.controllerExceptionHandler.apply(e, msg); } + TraceHandler.INSTANCE.log(e); return new ResponseEntity<>(msg, HttpStatus.INTERNAL_SERVER_ERROR); } }