- error 페이지 개발 환경용 상세 오류 정보 추가
- 스택 트레이스 및 예외 클래스 노출 로직 구현 - activeProfile 표시 및 스타일 업데이트
This commit is contained in:
@@ -11,6 +11,8 @@ import org.springframework.web.servlet.ModelAndView;
|
|||||||
|
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Sungpil Hyun
|
* Created by Sungpil Hyun
|
||||||
@@ -43,6 +45,15 @@ public class PortalErrorController implements ErrorController {
|
|||||||
modelAndView.addObject("errorTitle", resolveTitle(status));
|
modelAndView.addObject("errorTitle", resolveTitle(status));
|
||||||
modelAndView.addObject("errorDescription", resolveDescription(status));
|
modelAndView.addObject("errorDescription", resolveDescription(status));
|
||||||
modelAndView.addObject("errorMessage", resolveErrorMessage(request, status));
|
modelAndView.addObject("errorMessage", resolveErrorMessage(request, status));
|
||||||
|
modelAndView.addObject("activeProfile", resolveActiveProfile());
|
||||||
|
// include-stacktrace=always(로컬 디버깅 프로파일)일 때만 화면에 스택 트레이스까지 노출
|
||||||
|
if (isErrorDetailEnabled()) {
|
||||||
|
Throwable throwable = resolveThrowable(request);
|
||||||
|
if (throwable != null) {
|
||||||
|
modelAndView.addObject("errorException", throwable.getClass().getName());
|
||||||
|
modelAndView.addObject("errorStackTrace", stackTraceAsString(throwable));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return modelAndView;
|
return modelAndView;
|
||||||
}
|
}
|
||||||
@@ -54,6 +65,37 @@ public class PortalErrorController implements ErrorController {
|
|||||||
return environment.acceptsProfiles(Profiles.of("prod"));
|
return environment.acceptsProfiles(Profiles.of("prod"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* server.error.include-stacktrace=always 인 경우에만 화면에 스택 트레이스를 노출한다.
|
||||||
|
* (로컬 디버깅 프로파일에서만 해당 값을 always 로 설정 → 운영/스테이징에는 노출되지 않음)
|
||||||
|
*/
|
||||||
|
private boolean isErrorDetailEnabled() {
|
||||||
|
String includeStacktrace = environment.getProperty("server.error.include-stacktrace", "never");
|
||||||
|
return "always".equalsIgnoreCase(includeStacktrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveActiveProfile() {
|
||||||
|
String[] activeProfiles = environment.getActiveProfiles();
|
||||||
|
if (activeProfiles.length == 0) {
|
||||||
|
return "default";
|
||||||
|
}
|
||||||
|
return String.join(", ", activeProfiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Throwable resolveThrowable(HttpServletRequest request) {
|
||||||
|
Object exception = request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
|
||||||
|
if (exception instanceof Throwable) {
|
||||||
|
return (Throwable) exception;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String stackTraceAsString(Throwable throwable) {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
throwable.printStackTrace(new PrintWriter(stringWriter));
|
||||||
|
return stringWriter.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private String resolveTitle(Object status) {
|
private String resolveTitle(Object status) {
|
||||||
HttpStatus httpStatus = resolveHttpStatus(status);
|
HttpStatus httpStatus = resolveHttpStatus(status);
|
||||||
if (httpStatus == null) {
|
if (httpStatus == null) {
|
||||||
|
|||||||
@@ -150,6 +150,47 @@
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dev Error Detail (운영 미노출) */
|
||||||
|
.error-detail-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 14px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-dev-notice {
|
||||||
|
background-color: #fffaf0;
|
||||||
|
border: 1px solid #f6e05e;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 18px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #975a16;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-dev-notice .error-env {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-dev-notice .error-env strong {
|
||||||
|
color: #c05621;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stack Trace */
|
||||||
|
.error-stacktrace-text {
|
||||||
|
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #742a2a;
|
||||||
|
line-height: 1.5;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 360px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive */
|
/* Responsive */
|
||||||
@media screen and (max-width: 600px) {
|
@media screen and (max-width: 600px) {
|
||||||
.error-container {
|
.error-container {
|
||||||
@@ -219,10 +260,29 @@
|
|||||||
잠시 후 다시 시도해 주세요.
|
잠시 후 다시 시도해 주세요.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- Error Message (서버에서 전달된 에러 메시지가 있을 경우 표시) -->
|
<!-- 상세 오류 정보 (개발 환경 전용) - 운영(prod)에서는 표시되지 않음 -->
|
||||||
<div th:if="${errorMessage}" class="error-message-box">
|
<div th:if="${errorMessage}" class="error-detail-wrap">
|
||||||
<p class="error-message-label">오류 상세</p>
|
<!-- 운영 미노출 안내 + 현재 환경 -->
|
||||||
<p class="error-message-text" th:text="${errorMessage}"></p>
|
<p class="error-dev-notice">
|
||||||
|
⚠ 아래 상세 정보는 개발 편의를 위한 것으로,
|
||||||
|
<strong>운영 환경에서는 표시되지 않습니다.</strong>
|
||||||
|
<span class="error-env">현재 환경: <strong th:text="${activeProfile} ?: 'default'">-</strong></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- 오류 메시지 -->
|
||||||
|
<div class="error-message-box">
|
||||||
|
<p class="error-message-label">오류 상세</p>
|
||||||
|
<p class="error-message-text" th:text="${errorMessage}"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 스택 트레이스 (include-stacktrace=always 이고 예외가 있을 때만) -->
|
||||||
|
<div th:if="${errorStackTrace}" class="error-message-box">
|
||||||
|
<p class="error-message-label">
|
||||||
|
<span>스택 트레이스</span>
|
||||||
|
<span th:if="${errorException}" th:text="'(' + ${errorException} + ')'"></span>
|
||||||
|
</p>
|
||||||
|
<pre class="error-stacktrace-text" th:text="${errorStackTrace}"></pre>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
|
|||||||
Reference in New Issue
Block a user