add:第一版测试版本。
This commit is contained in:
26
nl-common/src/main/java/org/nl/config/CorsConfig.java
Normal file
26
nl-common/src/main/java/org/nl/config/CorsConfig.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package org.nl.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
* 2025/12/13
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOriginPatterns("*")
|
||||
.allowedHeaders(CorsConfiguration.ALL)
|
||||
.allowedMethods(CorsConfiguration.ALL)
|
||||
.allowCredentials(true)
|
||||
.maxAge(3600);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.nl.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
* 2025/12/11
|
||||
*/
|
||||
@Getter
|
||||
public enum ScheduleTaskReportStatusEnum {
|
||||
|
||||
/**
|
||||
* 未上报
|
||||
*/
|
||||
NOT_REPORTED("0", "未上报", "Not reported"),
|
||||
/**
|
||||
* 已上报
|
||||
*/
|
||||
REPORTED("1", "已上报", "reported"),
|
||||
/**
|
||||
* 处理完成
|
||||
*/
|
||||
FINISH_REPORTED("2", "处理完成", "外部API");
|
||||
|
||||
private String code;
|
||||
private String name;
|
||||
private String desc;
|
||||
|
||||
|
||||
ScheduleTaskReportStatusEnum(String code, String name, String desc) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static ScheduleTaskReportStatusEnum getByCode(String code) {
|
||||
for (ScheduleTaskReportStatusEnum e : ScheduleTaskReportStatusEnum.values()) {
|
||||
if (e.code.equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
31
nl-common/src/main/java/org/nl/enums/YesOrNoEnum.java
Normal file
31
nl-common/src/main/java/org/nl/enums/YesOrNoEnum.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package org.nl.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
* 2025/12/3
|
||||
*/
|
||||
@Getter
|
||||
public enum YesOrNoEnum {
|
||||
|
||||
/**
|
||||
* 否
|
||||
*/
|
||||
NO("0", "否", "否"),
|
||||
/**
|
||||
* 执行中
|
||||
*/
|
||||
YES("1", "是", "是");
|
||||
|
||||
private String code;
|
||||
private String name;
|
||||
private String desc;
|
||||
|
||||
|
||||
YesOrNoEnum(String code, String name, String desc) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
49
nl-common/src/main/java/org/nl/exception/ApiError.java
Normal file
49
nl-common/src/main/java/org/nl/exception/ApiError.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.nl.exception;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
class ApiError {
|
||||
|
||||
private Integer code = 400;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime Date;
|
||||
private String message;
|
||||
|
||||
private ApiError() {
|
||||
Date = LocalDateTime.now();
|
||||
}
|
||||
|
||||
public static ApiError error(String message){
|
||||
ApiError apiError = new ApiError();
|
||||
apiError.setMessage(message);
|
||||
return apiError;
|
||||
}
|
||||
|
||||
public static ApiError error(Integer status, String message){
|
||||
ApiError apiError = new ApiError();
|
||||
apiError.setCode(status);
|
||||
apiError.setMessage(message);
|
||||
return apiError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.nl.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
* 2025/7/3
|
||||
*/
|
||||
@Getter
|
||||
public class BadRequestException extends RuntimeException{
|
||||
|
||||
private Integer status = BAD_REQUEST.value();
|
||||
|
||||
public BadRequestException(String msg){
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public BadRequestException(HttpStatus status, String msg){
|
||||
super(msg);
|
||||
this.status = status.value();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.nl.exception;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nl.util.ThrowableUtil;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* @author liejiu
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 处理所有不可知的异常
|
||||
*/
|
||||
@ExceptionHandler(Throwable.class)
|
||||
public ResponseEntity<ApiError> handleException(Throwable e){
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
return buildResponseEntity(ApiError.error(e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* token 无效的异常拦截
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
// @ExceptionHandler(value = NotLoginException.class)
|
||||
// public ResponseEntity<ApiError> notLoginException(Exception e) {
|
||||
//// log.error(ThrowableUtil.getStackTrace(e));
|
||||
// return buildResponseEntity(ApiError.error(401,"token 失效"));
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 处理自定义异常
|
||||
*/
|
||||
@ExceptionHandler(value = BadRequestException.class)
|
||||
public ResponseEntity<ApiError> badRequestException(BadRequestException e) {
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
log.info(e.getMessage());
|
||||
return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理所有接口数据验证异常
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ApiError> handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
|
||||
// 打印堆栈信息
|
||||
log.error(ThrowableUtil.getStackTrace(e));
|
||||
String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\.");
|
||||
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
|
||||
String msg = "不能为空";
|
||||
if(msg.equals(message)){
|
||||
message = str[1] + ":" + message;
|
||||
}
|
||||
return buildResponseEntity(ApiError.error(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一返回
|
||||
*/
|
||||
private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
|
||||
return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getCode()));
|
||||
}
|
||||
}
|
||||
15
nl-common/src/main/java/org/nl/logging/annotation/Log.java
Normal file
15
nl-common/src/main/java/org/nl/logging/annotation/Log.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package org.nl.logging.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
* 2025/11/28
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Log {
|
||||
String value() default "";
|
||||
|
||||
}
|
||||
79
nl-common/src/main/java/org/nl/logging/aspect/LogAspect.java
Normal file
79
nl-common/src/main/java/org/nl/logging/aspect/LogAspect.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package org.nl.logging.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.nl.logging.annotation.Log;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
* 2025/11/28
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
public class LogAspect {
|
||||
|
||||
/**
|
||||
* 配置切入点
|
||||
*/
|
||||
@Pointcut("@annotation(org.nl.logging.annotation.Log)")
|
||||
public void logPointCut(){}
|
||||
|
||||
/**
|
||||
* 环绕通知
|
||||
* @param point
|
||||
* @return
|
||||
* @throws Throwable
|
||||
*/
|
||||
@Around("logPointCut()")
|
||||
public Object logAround(ProceedingJoinPoint point) throws Throwable {
|
||||
Object result = null;
|
||||
long beginTime = System.currentTimeMillis();
|
||||
// 执行方法
|
||||
result = point.proceed();
|
||||
// 执行时长(毫秒)
|
||||
long time = System.currentTimeMillis() - beginTime;
|
||||
// 保存日志
|
||||
saveLog(point, time);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void saveLog(ProceedingJoinPoint joinPoint, long time) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
Log logAnnotation = method.getAnnotation(Log.class);
|
||||
// 注解上的描述
|
||||
String description = "";
|
||||
if (logAnnotation != null) {
|
||||
description = logAnnotation.value();
|
||||
}
|
||||
// 请求的方法名
|
||||
String className = joinPoint.getTarget().getClass().getName();
|
||||
String methodName = signature.getName();
|
||||
// 请求的方法参数值
|
||||
Object[] args = joinPoint.getArgs();
|
||||
// 请求的方法参数名称
|
||||
ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
|
||||
String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
|
||||
String params = "";
|
||||
if (args != null && paramNames != null) {
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
params += " " + paramNames[i] + ": " + args[i];
|
||||
}
|
||||
}
|
||||
log.info("【日志注解】开始执行 -- 描述:{} -- 类方法:{}.{}() -- 参数:{} -- 执行时长:{}毫秒", description, className, methodName, params, time);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
77
nl-common/src/main/java/org/nl/response/WebResponse.java
Normal file
77
nl-common/src/main/java/org/nl/response/WebResponse.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package org.nl.response;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
* 2025/11/26
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class WebResponse<T> {
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
private Integer code = 200;
|
||||
|
||||
/**
|
||||
* 消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 数据
|
||||
*/
|
||||
private T data;
|
||||
|
||||
/**
|
||||
* 不带数据反馈
|
||||
* @return WebResponse
|
||||
*/
|
||||
public static WebResponse requestOk() {
|
||||
return WebResponse.builder()
|
||||
.message("成功")
|
||||
.code(OK.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 带消息反馈
|
||||
* @return WebResponse
|
||||
*/
|
||||
public static WebResponse requestOk(String message) {
|
||||
return WebResponse.builder()
|
||||
.message(message)
|
||||
.code(OK.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 带数据反馈
|
||||
* @return WebResponse
|
||||
*/
|
||||
public static <T> WebResponse requestParamOk(T data) {
|
||||
return WebResponse.builder()
|
||||
.message("成功")
|
||||
.data(data)
|
||||
.code(OK.value())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 带数据和消息反馈
|
||||
* @return WebResponse
|
||||
*/
|
||||
public static <T> WebResponse requestParamOk(T data, String message) {
|
||||
return WebResponse.builder()
|
||||
.message(message)
|
||||
.data(data)
|
||||
.code(OK.value())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
11
nl-common/src/main/java/org/nl/util/IdUtil.java
Normal file
11
nl-common/src/main/java/org/nl/util/IdUtil.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package org.nl.util;
|
||||
|
||||
public class IdUtil {
|
||||
public static Long getLongId() {
|
||||
return cn.hutool.core.util.IdUtil.getSnowflake(1, 1).nextId();
|
||||
}
|
||||
|
||||
public static String getStringId() {
|
||||
return String.valueOf(IdUtil.getLongId());
|
||||
}
|
||||
}
|
||||
123
nl-common/src/main/java/org/nl/util/TaskCodeGeneratorUtil.java
Normal file
123
nl-common/src/main/java/org/nl/util/TaskCodeGeneratorUtil.java
Normal file
@@ -0,0 +1,123 @@
|
||||
package org.nl.util;
|
||||
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
* 2025/12/1
|
||||
* 任务号生成器工具类 - 时间戳 + 序列号方案
|
||||
*/
|
||||
public class TaskCodeGeneratorUtil {
|
||||
|
||||
private TaskCodeGeneratorUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
// 序列号生成器
|
||||
private static final AtomicLong SEQUENCE = new AtomicLong(0);
|
||||
// 上次时间戳
|
||||
private static volatile String LAST_TIMESTAMP = "";
|
||||
// 重入锁保证线程安全
|
||||
private static final ReentrantLock LOCK = new ReentrantLock();
|
||||
|
||||
// 日期时间格式化器(线程安全)
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
|
||||
|
||||
/**
|
||||
* 生成任务号(默认格式:yyyyMMddHHmmssSSS + 3位序列号)
|
||||
* @return 任务号字符串
|
||||
*/
|
||||
public static String generateTaskId() {
|
||||
return generateTaskId("yyyyMMddHHmmssSSS", 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成任务号(自定义时间格式)
|
||||
* @param datePattern 时间格式,如:yyyyMMddHHmmss
|
||||
* @param sequenceLength 序列号长度
|
||||
* @return 任务号字符串
|
||||
*/
|
||||
public static String generateTaskId(String datePattern, int sequenceLength) {
|
||||
LOCK.lock();
|
||||
try {
|
||||
String currentTimestamp = getCurrentTimestamp(datePattern);
|
||||
|
||||
// 检查是否是新时间单位
|
||||
if (!currentTimestamp.equals(LAST_TIMESTAMP)) {
|
||||
LAST_TIMESTAMP = currentTimestamp;
|
||||
SEQUENCE.set(0);
|
||||
}
|
||||
|
||||
// 获取并增加序列号
|
||||
long seq = SEQUENCE.getAndIncrement();
|
||||
|
||||
// 检查序列号是否超过范围
|
||||
long maxSeq = (long) Math.pow(10, sequenceLength) - 1;
|
||||
if (seq > maxSeq) {
|
||||
// 序列号超过限制,等待下一时间单位
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
// 递归调用(注意:这种情况极少发生)
|
||||
return generateTaskId(datePattern, sequenceLength);
|
||||
}
|
||||
|
||||
// 格式化成指定长度的序列号
|
||||
String sequenceFormat = "%0" + sequenceLength + "d";
|
||||
return currentTimestamp + String.format(sequenceFormat, seq);
|
||||
} finally {
|
||||
LOCK.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带前缀的任务号
|
||||
* @param prefix 任务号前缀,如:TASK、ORDER等
|
||||
* @return 带前缀的任务号
|
||||
*/
|
||||
public static String generateTaskIdWithPrefix(String prefix) {
|
||||
return prefix + "_" + generateTaskId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带前缀的自定义格式任务号
|
||||
* @param prefix 前缀
|
||||
* @param datePattern 时间格式
|
||||
* @param sequenceLength 序列号长度
|
||||
* @return 任务号
|
||||
*/
|
||||
public static String generateTaskIdWithPrefix(String prefix, String datePattern, int sequenceLength) {
|
||||
return prefix + "_" + generateTaskId(datePattern, sequenceLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间戳字符串
|
||||
*/
|
||||
private static String getCurrentTimestamp(String pattern) {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
|
||||
return LocalDateTime.now().format(formatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量生成任务号
|
||||
* @param count 生成数量
|
||||
* @return 任务号列表
|
||||
*/
|
||||
public static List<String> batchGenerateTaskId(int count) {
|
||||
List<String> taskIds = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
taskIds.add(generateTaskId());
|
||||
}
|
||||
return taskIds;
|
||||
}
|
||||
}
|
||||
22
nl-common/src/main/java/org/nl/util/ThrowableUtil.java
Normal file
22
nl-common/src/main/java/org/nl/util/ThrowableUtil.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package org.nl.util;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
|
||||
/**
|
||||
* @author liejiu
|
||||
*/
|
||||
public class ThrowableUtil {
|
||||
|
||||
/**
|
||||
* 获取堆栈信息
|
||||
*/
|
||||
public static String getStackTrace(Throwable throwable){
|
||||
StringWriter sw = new StringWriter();
|
||||
try (PrintWriter pw = new PrintWriter(sw)) {
|
||||
throwable.printStackTrace(pw);
|
||||
return sw.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
18
nl-common/src/main/java/org/nl/util/WebSocketConfig.java
Normal file
18
nl-common/src/main/java/org/nl/util/WebSocketConfig.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package org.nl.util;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
/**
|
||||
* @author dsh
|
||||
* 2025/11/26
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSocket
|
||||
public class WebSocketConfig {
|
||||
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); }
|
||||
}
|
||||
Reference in New Issue
Block a user