feat(common): add global system logging with trace support

This commit is contained in:
sol 2026-03-12 04:48:45 +08:00
parent 789f45f709
commit 7420871565
31 changed files with 496 additions and 296 deletions

View file

@ -14,7 +14,6 @@ export { BaseVoListFileEntity } from './models/BaseVoListFileEntity';
export { BaseVoListImageEntity } from './models/BaseVoListImageEntity';
export { BaseVoListVerificationResult } from './models/BaseVoListVerificationResult';
export { BaseVoListVideoEntity } from './models/BaseVoListVideoEntity';
export { BaseVoObject } from './models/BaseVoObject';
export { BaseVoPageVoFileEntity } from './models/BaseVoPageVoFileEntity';
export { BaseVoPageVoImageEntity } from './models/BaseVoPageVoImageEntity';
export { BaseVoPageVoPoiExportHistoryEntity } from './models/BaseVoPageVoPoiExportHistoryEntity';

View file

@ -1,41 +0,0 @@
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
/**
*
*/
export type BaseVoObject = {
/**
*
*/
code?: number;
/**
*
*/
message?: string;
/**
*
*/
data?: Record<string, any>;
/**
*
*/
time?: string;
/**
*
*/
type?: BaseVoObject.type;
};
export namespace BaseVoObject {
/**
*
*/
export enum type {
SUCCESS = 'SUCCESS',
WARNING = 'WARNING',
INFO = 'INFO',
ERROR = 'ERROR',
}
}

View file

@ -26,7 +26,7 @@ export class PoiService {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}

View file

@ -43,7 +43,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -65,7 +65,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -87,7 +87,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -109,7 +109,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -131,7 +131,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -153,7 +153,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -175,7 +175,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -197,7 +197,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -219,7 +219,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -242,7 +242,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -270,7 +270,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -293,7 +293,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -316,7 +316,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -339,7 +339,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -362,7 +362,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -385,7 +385,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -408,7 +408,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -431,7 +431,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -454,7 +454,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -477,7 +477,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -500,7 +500,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}

View file

@ -18,7 +18,6 @@ export { BaseVoListUserEntity } from './models/BaseVoListUserEntity';
export { BaseVoListVerificationResult } from './models/BaseVoListVerificationResult';
export { BaseVoMenuEntity } from './models/BaseVoMenuEntity';
export { BaseVoMessageEnvelopeEntityObject } from './models/BaseVoMessageEnvelopeEntityObject';
export { BaseVoObject } from './models/BaseVoObject';
export { BaseVoPageVoMessageEnvelopeEntityObject } from './models/BaseVoPageVoMessageEnvelopeEntityObject';
export { BaseVoPageVoUserEntity } from './models/BaseVoPageVoUserEntity';
export { BaseVoPermissionEntity } from './models/BaseVoPermissionEntity';

View file

@ -1,41 +0,0 @@
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
/**
*
*/
export type BaseVoObject = {
/**
*
*/
code?: number;
/**
*
*/
message?: string;
/**
*
*/
data?: Record<string, any>;
/**
*
*/
time?: string;
/**
*
*/
type?: BaseVoObject.type;
};
export namespace BaseVoObject {
/**
*
*/
export enum type {
SUCCESS = 'SUCCESS',
WARNING = 'WARNING',
INFO = 'INFO',
ERROR = 'ERROR',
}
}

View file

@ -57,7 +57,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -79,7 +79,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -101,7 +101,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -123,7 +123,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -140,7 +140,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -162,7 +162,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -184,7 +184,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -206,7 +206,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -228,7 +228,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -245,7 +245,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -267,7 +267,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -289,7 +289,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -311,7 +311,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -328,7 +328,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -350,7 +350,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -374,7 +374,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -396,7 +396,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -418,7 +418,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -440,7 +440,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -463,7 +463,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -480,7 +480,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -503,7 +503,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -520,7 +520,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -543,7 +543,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -560,7 +560,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -583,7 +583,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -600,7 +600,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -623,7 +623,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -640,7 +640,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -663,7 +663,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -680,7 +680,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -703,7 +703,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -720,7 +720,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -743,7 +743,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -766,7 +766,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -783,7 +783,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -806,7 +806,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -829,7 +829,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -846,7 +846,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -869,7 +869,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -892,7 +892,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -915,7 +915,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -938,7 +938,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}
@ -961,7 +961,7 @@ export class Service {
400: `参数校验异常`,
401: `未登录异常`,
403: `无权限异常`,
500: `业务异常`,
500: `系统异常`,
},
});
}

View file

@ -6,7 +6,6 @@ import {useUser} from "~/pinia/modules/user";
import {ElButton, ElCol, ElForm, ElFormItem, ElImage, ElInput, ElMessage, ElRow, FormInstance} from "element-plus";
import {useFormValidation} from "~/composables/FormValidationHook";
import AppHeader from "~/views/app/layout/AppHeader.vue";
import {set} from "@vueuse/core";
const loginDto = ref<UserLoginDto>({
username: '',
@ -19,15 +18,15 @@ const imageBase64 = ref<string>();
const getCaptcha = () => {
//
Service.getVerificationCode().then((res) => {
if (res.data?.captcha){
if (res.data?.captcha) {
loginDto.value.verificationCode = res.data?.captcha
needCaptcha.value = false;
}else{
} else {
needCaptcha.value = true;
}
loginDto.value.verificationCodeKey = res.data?.verificationId as string
imageBase64.value = res.data?.verificationCode as string;
setTimeout(getCaptcha,30 * 1000)
setTimeout(getCaptcha, 30 * 1000)
});
};
onMounted(() => {
@ -64,8 +63,9 @@ const login = () => {
}
}).catch(() => {
getCaptcha();
}).finally(() => {
loading.value = false;
});
})
};
const pageLoading = ref(true);
onMounted(() => {

View file

@ -38,7 +38,9 @@ public class SaTokenConfigure implements WebMvcConfigurer {
}
})
.setError(e -> {
throw new BaseException("鉴权失败");
throw BaseException.builder()
.message("鉴权失败")
.cause(e).build();
});
}

View file

@ -30,6 +30,11 @@
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
<dependency>
<groupId>cn.idev.excel</groupId>
<artifactId>fastexcel</artifactId>
<version>${fastexcel.version}</version>
</dependency>
</dependencies>
</project>

View file

@ -1,36 +1,30 @@
package com.bgasol.common.core.base.exception;
import com.bgasol.common.core.base.vo.BaseVo;
import com.bgasol.common.core.base.vo.ResponseType;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/// 自定义通用异常
@Getter
@Slf4j
public class BaseException extends RuntimeException {
private Throwable throwable;
private final ResponseType responseType;
private final Boolean isPrimary;
private final Integer code;
private final BaseVo<?> baseVo;
public BaseException(BaseVo<?> baseVo) {
super(baseVo.getMessage());
this.baseVo = baseVo;
@Builder
public BaseException(String message, Throwable cause, ResponseType responseType, Boolean isPrimary, Integer code) {
super(message, cause);
this.responseType = responseType != null ? responseType : ResponseType.ERROR;
this.isPrimary = isPrimary != null ? isPrimary : false;
this.code = code != null ? code : -1;
}
public BaseException(String message) {
super(message);
this.baseVo = BaseVo.error(message);
this(message, null, null, null, null);
}
public BaseException(String message, Throwable throwable) {
super(message);
this.baseVo = BaseVo.error(message);
this.throwable = throwable;
}
public BaseException(String message, ResponseType type) {
super(message);
this.baseVo = BaseVo.error(message, type);
public BaseException(String message, Throwable cause) {
this(message, cause, null, null, null);
}
}

View file

@ -87,30 +87,14 @@ public class BaseVo<T> {
.build();
}
/**
* 错误响应
*
* @param data 响应数据
* @param message 响应消息
*/
static public <T> BaseVo<T> error(T data, String message) {
return BaseVo.<T>builder()
.code(500)
.data(data)
.time(new Date())
.message(message)
.type(ResponseType.ERROR)
.build();
}
/**
* 错误响应
*
* @param message 响应消息
* @param type 响应类型 前端可以根据这个类型进行不同的颜色展示
*/
static public <T> BaseVo<T> error(String message, ResponseType type) {
return BaseVo.<T>builder()
static public BaseVo<Void> error(String message, ResponseType type) {
return BaseVo.<Void>builder()
.code(500)
.time(new Date())
.message(message)

View file

@ -4,24 +4,27 @@ import com.bgasol.common.core.base.exception.BaseException;
import com.bgasol.common.core.base.exception.VerificationException;
import com.bgasol.common.core.base.vo.BaseVo;
import com.bgasol.common.core.base.vo.VerificationResult;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Path;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import static com.bgasol.common.constant.value.SystemConfigValues.REQUEST_EXCEPTION;
import static com.bgasol.common.constant.value.SystemConfigValues.REQUEST_EXCEPTION_PRIMARY;
/**
* 全局异常处理
*/
@ -30,32 +33,34 @@ import java.util.List;
@RestControllerAdvice
public class BaseExceptionHandler {
private final ObjectMapper objectMapper;
/**
* 处理业务异常
*/
@ExceptionHandler(value = BaseException.class)
@ApiResponse(description = "业务异常", responseCode = "500")
public BaseVo<?> baseExceptionHandler(BaseException e) {
log.error("业务异常", e);
return e.getBaseVo();
public BaseVo<Void> baseExceptionHandler(BaseException e, HttpServletRequest request) {
if (e.getIsPrimary()) {
request.setAttribute(REQUEST_EXCEPTION_PRIMARY, true);
}
request.setAttribute(REQUEST_EXCEPTION, ExceptionUtils.getStackTrace(e));
return BaseVo.error(e.getMessage(), e.getResponseType());
}
@ExceptionHandler(value = VerificationException.class)
@ApiResponse(description = "参数校验异常", responseCode = "400")
public BaseVo<List<VerificationResult>> verificationExceptionHandler(VerificationException e) throws JsonProcessingException {
public BaseVo<List<VerificationResult>> verificationExceptionHandler(VerificationException e, HttpServletRequest request) {
List<VerificationResult> verificationResults = e.getVerificationResults();
log.error(objectMapper.writeValueAsString(verificationResults));
request.setAttribute(REQUEST_EXCEPTION, "参数校验异常");
return BaseVo.code400(verificationResults);
}
/**
* 处理参数校验异常 方法参数级 MethodArgumentNotValidException
*/
@SneakyThrows
@ExceptionHandler(MethodArgumentNotValidException.class)
@ApiResponse(description = "参数校验异常", responseCode = "400")
public BaseVo<List<VerificationResult>> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, JsonProcessingException {
public BaseVo<List<VerificationResult>> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e, HttpServletRequest request) {
BindingResult bindingResult = e.getBindingResult();
List<ObjectError> allErrors = bindingResult.getAllErrors();
List<VerificationResult> verificationResults = new ArrayList<>();
@ -68,7 +73,7 @@ public class BaseExceptionHandler {
verificationResult.setResult(false);
verificationResults.add(verificationResult);
}
log.error(objectMapper.writeValueAsString(verificationResults));
request.setAttribute(REQUEST_EXCEPTION, "参数校验异常");
return BaseVo.code400(verificationResults);
}
@ -77,8 +82,7 @@ public class BaseExceptionHandler {
*/
@ExceptionHandler(value = ConstraintViolationException.class)
@ApiResponse(description = "参数校验异常", responseCode = "400")
public BaseVo<List<VerificationResult>> constraintViolationExceptionHandler(ConstraintViolationException e) throws JsonProcessingException {
// Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
public BaseVo<List<VerificationResult>> constraintViolationExceptionHandler(ConstraintViolationException e, HttpServletRequest request) {
List<VerificationResult> verificationResults = new ArrayList<>();
for (ConstraintViolation<?> constraintViolation : e.getConstraintViolations()) {
VerificationResult verificationResult = new VerificationResult();
@ -93,7 +97,7 @@ public class BaseExceptionHandler {
verificationResult.setResult(false);
verificationResults.add(verificationResult);
}
log.error(objectMapper.writeValueAsString(verificationResults));
request.setAttribute(REQUEST_EXCEPTION, "参数校验异常");
return BaseVo.code400(verificationResults);
}
}

View file

@ -1,38 +1,43 @@
package com.bgasol.common.core.base.handler;
import com.bgasol.common.core.base.vo.BaseVo;
import com.bgasol.common.core.base.vo.ResponseType;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.postgresql.util.PSQLException;
import org.postgresql.util.ServerErrorMessage;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import static com.bgasol.common.constant.value.SystemConfigValues.REQUEST_EXCEPTION;
/**
* PostgreSQL 异常处理转换为友好的中文提示
*/
@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class PostgreSqlExceptionHandler {
public class PgSqlExceptionHandler {
private final EntityFieldCache entityFieldCache;
@ExceptionHandler(PSQLException.class)
@ApiResponse(description = "PostgreSQL异常", responseCode = "500")
public BaseVo<String> handlePSQLException(PSQLException ex) {
logDatabaseError(ex);
public BaseVo<Void> handlePSQLException(PSQLException e, HttpServletRequest request) {
logDatabaseError(e);
String errorMsg = ex.getMessage();
ServerErrorMessage serverError = ex.getServerErrorMessage();
String errorMsg = e.getMessage();
ServerErrorMessage serverError = e.getServerErrorMessage();
String tableName = serverError != null ? serverError.getTable() : null;
String detail = serverError != null ? serverError.getDetail() : null;
String column = serverError != null ? serverError.getColumn() : null;
String message = handleMessage(errorMsg, tableName, detail, column);
return BaseVo.error(message, ResponseType.ERROR);
request.setAttribute(REQUEST_EXCEPTION, ExceptionUtils.getStackTrace(e));
return BaseVo.error(message);
}
private String handleMessage(String errorMsg, String tableName, String detail, String column) {

View file

@ -4,10 +4,13 @@ import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import com.bgasol.common.core.base.vo.BaseVo;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import static com.bgasol.common.constant.value.SystemConfigValues.REQUEST_EXCEPTION;
/**
* Sa-Token 异常处理
*/
@ -19,8 +22,8 @@ public class SaExceptionHandler {
*/
@ExceptionHandler(value = NotLoginException.class)
@ApiResponse(description = "未登录异常", responseCode = "401")
public BaseVo<Void> notLoginExceptionHandler(NotLoginException e) {
log.error("未登录异常", e);
public BaseVo<Void> notLoginExceptionHandler(NotLoginException e, HttpServletRequest request) {
request.setAttribute(REQUEST_EXCEPTION, "未登录异常");
return BaseVo.code401();
}
@ -29,8 +32,8 @@ public class SaExceptionHandler {
*/
@ExceptionHandler(value = NotPermissionException.class)
@ApiResponse(description = "无权限异常", responseCode = "403")
public BaseVo<Void> notPermissionExceptionHandler(NotPermissionException e) {
log.error("无权限异常", e);
public BaseVo<Void> notPermissionExceptionHandler(NotPermissionException e, HttpServletRequest request) {
request.setAttribute(REQUEST_EXCEPTION, "无权限异常");
return BaseVo.code403();
}
}

View file

@ -1,20 +1,32 @@
package com.bgasol.common.core.base.interceptor;
import com.bgasol.plugin.websocket.dto.WsSendMessageDto;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.dev33.satoken.stp.StpUtil;
import com.bgasol.model.system.requestLog.entity.RequestLogEntity;
import com.bgasol.common.requestLog.service.RequestLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.lang.NonNull;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import static com.bgasol.common.util.WSUtils.GetWSTopic;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID;
import static com.bgasol.common.constant.value.SystemConfigValues.REQUEST_EXCEPTION;
import static com.bgasol.common.constant.value.SystemConfigValues.REQUEST_EXCEPTION_PRIMARY;
import static com.bgasol.plugin.openfeign.interceptor.FeignInterceptor.SPAN_ID;
import static com.bgasol.plugin.openfeign.interceptor.FeignInterceptor.TRACE_ID;
/**
* 请求日志拦截器
@ -22,88 +34,107 @@ import static com.bgasol.common.util.WSUtils.GetWSTopic;
*/
@Slf4j
@Configuration
@RequiredArgsConstructor
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class RequestLoggingInterceptor implements HandlerInterceptor {
private static final String START_TIME_ATTRIBUTE = "REQUEST_START_TIME";
private static final String REQUEST_HANDLER_ATTRIBUTE = "REQUEST_HANDLER";
private static final String REQUEST_LOG = "REQUEST_LOG";
@Value("${spring.application.name}")
private String serviceName;
private final RedissonClient redissonClient;
private final ObjectMapper objectMapper;
@Value("${system.ws.open-request-log}")
private Boolean openWsRequestLog;
@Value("${system.node-name}")
private String nodeName;
@Value("${system.node-ip}")
private String nodeIp;
private static final String BUSINESS_CONTROLLER = "BUSINESS_CONTROLLER";
private static final String BUSINESS_METHOD = "BUSINESS_METHOD";
private static final String START_TIME_ATTRIBUTE = "REQUEST_START_TIME";
@Lazy
private final RequestLogService requestLogService;
@Override
public boolean preHandle(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
long startTime = System.currentTimeMillis();
String handlerInfo = getHandlerInfo(handler);
request.setAttribute(START_TIME_ATTRIBUTE, startTime);
request.setAttribute(REQUEST_HANDLER_ATTRIBUTE, handlerInfo);
public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) {
getHandlerInfo(request, handler);
String traceId = request.getHeader(TRACE_ID);
if (ObjectUtils.isEmpty(traceId)) {
request.setAttribute(TRACE_ID, UUID.randomUUID().toString());
} else {
request.setAttribute(TRACE_ID, traceId);
}
request.setAttribute(SPAN_ID, UUID.randomUUID().toString());
request.setAttribute(START_TIME_ATTRIBUTE, System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) {
public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) {
String parentSpanId = request.getHeader(SPAN_ID);
String spanId = (String) request.getAttribute(SPAN_ID);
String traceId = (String) request.getAttribute(TRACE_ID);
Long startTime = (Long) request.getAttribute(START_TIME_ATTRIBUTE);
if (startTime == null) {
return;
}
long endTime = System.currentTimeMillis();
String method = request.getMethod();
String uri = request.getRequestURI();
String queryString = request.getQueryString();
String handlerInfo = (String) request.getAttribute(REQUEST_HANDLER_ATTRIBUTE);
long endTime = System.currentTimeMillis();
int status = response.getStatus();
// 获取当前线程id
long threadId = Thread.currentThread().getId();
if (!openWsRequestLog) {
return;
}
try {
RTopic ws = redissonClient.getTopic(GetWSTopic(serviceName));
String logString = objectMapper.writeValueAsString(new RequestLog(threadId,
serviceName,
method,
uri,
startTime,
endTime,
queryString,
handlerInfo,
status,
ex != null ? ex.getMessage() : ""));
ws.publish(WsSendMessageDto.builder()
.json(logString)
.type(REQUEST_LOG).build());
} catch (Exception e) {
log.error("日志消息广播异常", e);
String businessMethod = (String) request.getAttribute(BUSINESS_METHOD);
String businessController = (String) request.getAttribute(BUSINESS_CONTROLLER);
String errorLog = null;
boolean isPrimaryErr = false;
if (ex != null) {
isPrimaryErr = true;
errorLog = ExceptionUtils.getStackTrace(ex);
log.error(ex.getMessage(), ex);
} else {
if (BooleanUtils.isTrue((Boolean) request.getAttribute(REQUEST_EXCEPTION_PRIMARY))) {
isPrimaryErr = true;
errorLog = (String) request.getAttribute(REQUEST_EXCEPTION);
}
}
requestLogService.insert(RequestLogEntity.builder()
.id(spanId)
.parentId(parentSpanId)
.createTime(new Date(startTime))
.updateTime(new Date(endTime))
.traceId(traceId)
.serviceName(serviceName)
.nodeName(nodeName)
.nodeIp(nodeIp)
.method(method)
.uri(uri)
.queryString(queryString)
.status(status)
.threadId(threadId)
.errorLog(errorLog)
.isPrimaryErr(isPrimaryErr)
.businessMethod(businessMethod)
.businessController(businessController)
.userId(StpUtil.isLogin() ? StpUtil.getLoginIdAsString() : null)
.build());
}
private record RequestLog(Long threadId,
String serviceName,
String method,
String uri,
Long startTime,
Long endTime,
String queryString,
String handlerInfo,
Integer status,
String errorMessage) {
}
private String getHandlerInfo(Object handler) {
private void getHandlerInfo(HttpServletRequest request, Object handler) {
if (handler instanceof HandlerMethod handlerMethod) {
String className = handlerMethod.getBeanType().getSimpleName();
String methodName = handlerMethod.getMethod().getName();
return className + "." + methodName + "()";
Class<?> controllerClass = handlerMethod.getBeanType();
Method method = handlerMethod.getMethod();
Operation operation = method.getAnnotation(Operation.class);
if (operation != null) {
String summary = operation.summary();
request.setAttribute(BUSINESS_METHOD, summary);
}
Tag tag = controllerClass.getAnnotation(Tag.class);
if (tag != null) {
request.setAttribute(BUSINESS_CONTROLLER, tag.name());
}
}
return null;
}
}

View file

@ -0,0 +1,9 @@
package com.bgasol.common.requestLog.mapper;
import com.bgasol.common.core.base.mapper.MyBaseMapper;
import com.bgasol.model.system.requestLog.entity.RequestLogEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RequestLogMapper extends MyBaseMapper<RequestLogEntity> {
}

View file

@ -0,0 +1,21 @@
package com.bgasol.common.requestLog.service;
import com.bgasol.common.core.base.dto.BasePageDto;
import com.bgasol.common.core.base.service.BaseTreeService;
import com.bgasol.model.system.requestLog.entity.RequestLogEntity;
import com.bgasol.common.requestLog.mapper.RequestLogMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
@Slf4j
public class RequestLogService extends BaseTreeService<RequestLogEntity, BasePageDto<RequestLogEntity>> {
private final RequestLogMapper requestLogMapper;
@Override
public RequestLogMapper commonBaseMapper() {
return requestLogMapper;
}
}

View file

@ -3,6 +3,3 @@ server:
threads:
io: 1
worker: 8
system:
ws:
open-request-log: false

View file

@ -25,4 +25,11 @@ public class SystemConfigValues {
public final static String NODE_NAME_KEY = "node-name";
public final static String NODE_IP_KEY = "node-ip";
public final static String TRACE_INFO_KEY = "Trace-Info";
public final static String REQUEST_EXCEPTION = "REQUEST_EXCEPTION";
public final static String REQUEST_EXCEPTION_PRIMARY = "REQUEST_EXCEPTION_PRIMARY";
}

View file

@ -11,6 +11,10 @@
<properties>
<jsch.version>0.1.55</jsch.version>
<rng.simple.version>1.6</rng.simple.version>
<lang3.version>3.18.0</lang3.version>
<codec.version>1.16.1</codec.version>
<pool2.version>2.12.0</pool2.version>
</properties>
<artifactId>common-util</artifactId>
@ -19,6 +23,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${lang3.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@ -28,20 +33,17 @@
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${codec.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>${pool2.version}</version>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>${jsch.version}</version>
</dependency>
<dependency>
<groupId>cn.idev.excel</groupId>
<artifactId>fastexcel</artifactId>
<version>${fastexcel.version}</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,84 @@
package com.bgasol.model.system.requestLog.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.bgasol.common.core.base.entity.BaseTreeEntity;
import com.bgasol.model.system.user.entity.UserEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Transient;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
@Setter
@Getter
@SuperBuilder
@NoArgsConstructor
@Schema(description = "系统请求日志实体类")
@TableName(value = "system_t_request_log", autoResultMap = true)
@Entity
public class RequestLogEntity extends BaseTreeEntity<RequestLogEntity> {
@Schema(description = "全局链路ID")
@TableField("trace_id")
private String traceId;
@Schema(description = "服务名")
private String serviceName;
@Schema(description = "节点名")
private String nodeName;
@Schema(description = "节点IP")
private String nodeIp;
@Schema(description = "HTTP方法")
@TableField("method")
private String method;
@Schema(description = "请求URI")
@TableField("uri")
private String uri;
@Schema(description = "请求参数")
@TableField("query_string")
private String queryString;
@Schema(description = "HTTP状态码")
@TableField("status")
private Integer status;
@Schema(description = "线程ID")
@TableField("thread_id")
private Long threadId;
@Schema(description = "异常堆栈")
@TableField("error_log")
private String errorLog;
@Schema(description = "是否是重要异常")
@TableField("is_primary_err")
private Boolean isPrimaryErr;
@Schema(description = "业务方法")
@TableField("business_method")
private String businessMethod;
@Schema(description = "业务模块/Controller")
@TableField("business_controller")
private String businessController;
@Schema(description = "用户ID")
@TableField("user_id")
@Transient
private String userId;
@Schema(description = "用户")
@TableField(exist = false)
@JoinColumn(name = "user_id")
@ManyToOne
private UserEntity userEntity;
}

View file

@ -21,5 +21,13 @@
<artifactId>sa-token-core</artifactId>
<version>${sa-token.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
</project>

View file

@ -5,15 +5,22 @@ import cn.dev33.satoken.stp.StpUtil;
import com.bgasol.common.constant.value.GatewayConfigValues;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Slf4j
@Component
@RequiredArgsConstructor
public class FeignInterceptor implements RequestInterceptor {
public static final String TRACE_ID = "TRACE_ID";
public static final String SPAN_ID = "SPAN_ID";
/**
* feign拦截器, 在feign请求发出之前加入一些操作
@ -32,12 +39,23 @@ public class FeignInterceptor implements RequestInterceptor {
if (useToken) {
requestTemplate.header(StpUtil.getTokenName(), StpUtil.getTokenValue());
}
// 添加链路信息
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
if (attributes instanceof ServletRequestAttributes servletAttributes) {
HttpServletRequest request = servletAttributes.getRequest();
String spanId = (String) request.getAttribute(SPAN_ID);
String traceId = (String) request.getAttribute(TRACE_ID);
requestTemplate.header(SPAN_ID, spanId);
requestTemplate.header(TRACE_ID, traceId);
}
}
/**
* 判断当前请求是否在web请求的下文中
*/
public static boolean InWebRequest() {
return RequestContextHolder.getRequestAttributes() != null;
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return attributes instanceof ServletRequestAttributes;
}
}

View file

@ -41,7 +41,6 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<rng.simple.version>1.6</rng.simple.version>
<fastexcel.version>1.3.0</fastexcel.version>
</properties>

View file

@ -21,7 +21,7 @@
</dependency>
<dependency>
<groupId>com.pig4cloud.plugin</groupId>
<artifactId>captcha-spring-boot-starter</artifactId>
<artifactId>captcha-core</artifactId>
<version>${captcha.version}</version>
</dependency>

View file

@ -71,7 +71,7 @@ public class UserService extends BaseService<UserEntity, UserPageDto> {
LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserEntity::getUsername, entity.getUsername());
if (userMapper.selectCount(queryWrapper) > 0) {
throw new BaseException("用户名已存在");
throw BaseException.builder().message("用户名已存在").build();
}
String password = entity.getPassword();
if (ObjectUtils.isNotEmpty(password)) {

View file

@ -6,7 +6,7 @@ system:
title: ${SYSTEM_TITLE_NAME:sol}
describe: 系统基础服务,包含用户管理权限管理等。
password:
plaintext: true # 是否明文存储密码
plaintext: ${SYSTEM_PASSWORD_PLAINTEXT:true} # 是否明文存储密码
captcha:
is-open: ${SYSTEM_CAPTCHA_IS_OPEN:true}
max: ${SYSTEM_CAPTCHA_MAX:11}

View file

@ -17,6 +17,7 @@ SYSTEM_CAPTCHA_IS_OPEN=true
SYSTEM_CAPTCHA_MAX=11
SYSTEM_CAPTCHA_LENGTH=3
SYSTEM_AUTH_ENABLED=true
SYSTEM_PASSWORD_PLAINTEXT=true
TZ=Asia/Shanghai

View file

@ -87,6 +87,7 @@ services:
SYSTEM_CAPTCHA_IS_OPEN: ${SYSTEM_CAPTCHA_IS_OPEN}
SYSTEM_CAPTCHA_MAX: ${SYSTEM_CAPTCHA_MAX}
SYSTEM_CAPTCHA_LENGTH: ${SYSTEM_CAPTCHA_LENGTH}
SYSTEM_PASSWORD_PLAINTEXT: ${SYSTEM_PASSWORD_PLAINTEXT}
POSTGRES_HOST: cloud-app-postgres
POSTGRES_PORT: 5432

View file

@ -0,0 +1,109 @@
# ---------------------------
# 请求日志表
# ---------------------------
table "system_t_request_log" {
schema = schema.public
column "id" {
type = varchar(50)
null = false
}
column "type" {
type = varchar(50)
null = true
}
column "sort" {
type = int
null = true
}
column "create_time" {
type = timestamp(6)
null = true
default = sql("now()")
}
column "update_time" {
type = timestamp(6)
null = true
}
column "description" {
type = text
null = true
}
column "parent_id" {
type = varchar(50)
null = true
}
column "trace_id" {
type = varchar(64)
null = true
}
column "service_name" {
type = varchar(100)
null = true
}
column "node_name" {
type = varchar(100)
null = true
}
column "node_ip" {
type = varchar(50)
null = true
}
column "method" {
type = varchar(10)
null = true
}
column "uri" {
type = varchar(2000)
null = true
}
column "query_string" {
type = text
null = true
}
column "status" {
type = int
null = true
}
column "thread_id" {
type = bigint
null = true
}
column "error_log" {
type = text
null = true
}
column "is_primary_err" {
type = boolean
null = true
}
column "business_method" {
type = varchar(255)
null = true
}
column "business_controller" {
type = varchar(255)
null = true
}
column "user_id" {
type = varchar(255)
null = true
}
primary_key {
columns = [column.id]
}
# 索引
index "idx_request_log_create_time" {
columns = [column.create_time]
}
index "idx_request_log_parent_id" {
columns = [column.parent_id]
}
index "idx_request_log_trace_id" {
columns = [column.trace_id]
}
}