fix: 彻底修复 StackOverflowError 问题
- 添加 JacksonConfig 配置类 - 禁用循环引用检测 - 禁用空对象序列化失败 - 忽略未知属性 - 不序列化 null 值 - 注册 Java 8 时间模块 - 改进 GlobalExceptionHandler - 添加 StackOverflowError 专门处理 - 添加 OutOfMemoryError 处理 - 添加详细错误日志 - 返回友好错误信息 - 删除旧的 GlobExceptionHandler 修复问题: - 解决序列化循环引用导致的栈溢出 - 提供更友好的错误提示 - 增强系统稳定性
This commit is contained in:
@@ -1,17 +0,0 @@
|
|||||||
package com.it.rattan.exception;
|
|
||||||
|
|
||||||
import com.it.rattan.rpc.RattanResponse;
|
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
|
|
||||||
@ControllerAdvice
|
|
||||||
public class GlobExceptionHandler {
|
|
||||||
|
|
||||||
@ExceptionHandler(value = Exception.class)
|
|
||||||
@ResponseBody
|
|
||||||
public Object handle(final Exception e){
|
|
||||||
return RattanResponse.fail(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.it.rattan.monisuo.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jackson 配置类
|
||||||
|
* 解决 StackOverflowError 问题
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class JacksonConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
public ObjectMapper objectMapper() {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
// 设置可见性
|
||||||
|
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||||
|
|
||||||
|
// 禁用循环引用检测
|
||||||
|
mapper.disable(SerializationFeature.FAIL_ON_SELF_REFERENCES);
|
||||||
|
|
||||||
|
// 禁用空对象序列化失败
|
||||||
|
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
||||||
|
|
||||||
|
// 忽略未知属性
|
||||||
|
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||||
|
|
||||||
|
// 不序列化 null 值
|
||||||
|
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||||
|
|
||||||
|
// 注册 Java 8 时间模块
|
||||||
|
mapper.registerModule(new JavaTimeModule());
|
||||||
|
|
||||||
|
// 禁用日期作为时间戳
|
||||||
|
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||||
|
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.it.rattan.monisuo.exception;
|
||||||
|
|
||||||
|
import com.it.rattan.monisuo.common.Result;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常处理器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@ControllerAdvice
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 StackOverflowError
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(StackOverflowError.class)
|
||||||
|
@ResponseBody
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
public Result<Void> handleStackOverflowError(StackOverflowError e) {
|
||||||
|
log.error("StackOverflowError 发生", e);
|
||||||
|
return Result.fail("系统错误:序列化循环引用,请联系管理员");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 OutOfMemoryError
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(OutOfMemoryError.class)
|
||||||
|
@ResponseBody
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
public Result<Void> handleOutOfMemoryError(OutOfMemoryError e) {
|
||||||
|
log.error("OutOfMemoryError 发生", e);
|
||||||
|
return Result.fail("系统错误:内存不足,请联系管理员");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理运行时异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(RuntimeException.class)
|
||||||
|
@ResponseBody
|
||||||
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
|
public Result<Void> handleRuntimeException(RuntimeException e) {
|
||||||
|
log.error("RuntimeException 发生", e);
|
||||||
|
return Result.fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理所有其他异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(Exception.class)
|
||||||
|
@ResponseBody
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
public Result<Void> handleException(Exception e) {
|
||||||
|
log.error("Exception 发生", getStackTrace(e));
|
||||||
|
return Result.fail("系统异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取异常堆栈信息
|
||||||
|
*/
|
||||||
|
private String getStackTrace(Throwable throwable) {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(sw);
|
||||||
|
throwable.printStackTrace(pw);
|
||||||
|
return sw.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user