Spring - ์๋ธ๋ฆฟ ์์ธ ์ฒ๋ฆฌ ( Exception )
by rlaehddnd0422์๋ฐ์์์ ์์ธ
์๋ฐ๋ main ๋ฉ์๋๋ฅผ ์ง์ ์คํํ ๋ main ์ด๋ผ๋ ์ด๋ฆ์ ์ฐ๋ ๋๊ฐ ์คํ๋ฉ๋๋ค. ์ด ๋ ์คํ ๋์ค์ try catch๋ฅผ ํตํ ํด๋น ์์ธ ์ฒ๋ฆฌ ์กฐ์ฐจ ํ์ง ๋ชปํ๊ณ ์ฒ์ ์คํํ main ๋ฉ์๋๊น์ง ์์ธ๊ฐ ๋์ด์จ ์ดํ, main ๋ฉ์๋์์ ์กฐ์ฐจ๋ ์์ธ๋ฅผ ์ฒ๋ฆฌํ์ง ๋ชปํ๋ฉด ์๋ฐ๋ ์์ธ ์ ๋ณด๋ฅผ ๋จ๊ธฐ๊ณ main ์ฐ๋ ๋๋ฅผ ์ข ๋ฃํฉ๋๋ค.
์น ์ ํ๋ฆฌ์ผ์ด์ ์์์ ์์ธ
์น ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์์ธ๋ฅผ ์ด๋ป๊ฒ ๋ค๋ฃฐ๊น์?
์น ์ ํ๋ฆฌ์ผ์ด์ ์ "์ฌ์ฉ์ ์์ฒญ๋ณ"๋ก ์ฐ๋ ๋๊ฐ ํ ๋น๋๊ณ , ์๋ธ๋ฆฟ ์ปจํ ์ด๋ ์์์ ์คํ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ด๋ถ ์ปจํธ๋กค๋ฌ์์ ์์ธ๊ฐ ๋ฐ์ํ์ ๊ฒฝ์ฐ, ๋ง์ฐฌ๊ฐ์ง๋ก try catch๋ก ์์ธ๋ฅผ ์ก์ ์ฒ๋ฆฌํ๋ฉด ๋ฌธ์ ๊ฐ ์๊ฒ ์ง๋ง, ์ปจํธ๋กค๋ฌ์์ ์์ธ๋ฅผ ์ฒ๋ฆฌํ์ง ๋ชปํ๋ฉด ์ด ์ ๋จ๊ณ์ธ ์ธํฐ์ ํธ์๊ฒ ์์ธ๊ฐ ๋๊ฒจ์ง๋๋ค. ์ธํฐ์ ํธ์์๋ ์์ธ๋ฅผ ์ฒ๋ฆฌํ์ง ๋ชปํ๋ฉด ์๋ธ๋ฆฟ .. ์๋ธ๋ฆฟ์์ ํํฐ.. ํํฐ์์ WAS ๊น์ง ์ ํ๊ฐ ๋ฉ๋๋ค.
WAS -> ํํฐ -> ์๋ธ๋ฆฟ -> ์ธํฐ์ ํฐ -> ์ปจํธ๋กค๋ฌ (์์ธ๋ฐ์)
โถ๏ธ WAS(์์ธ ์ ํ๋ฐ์) <- ํํฐ <- ์๋ธ๋ฆฟ <- ์ธํฐ์ ํฐ <- ์ปจํธ๋กค๋ฌ (์์ธ์ ํ)
๊ฒฐ๊ตญ Tomcat WAS ๊น์ง ์์ธ๊ฐ ์ ๋ฌ๋๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ผ WAS๋ ์์ธ๋ฅผ ๋ฐ์ผ๋ฉด ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊น์?
ํ ์คํธ๋ฅผ ํตํด ์์๋ณด๊ฒ ์ต๋๋ค.
์ฐธ๊ณ : ์คํ๋ง์ด ์๋ ์์ ์๋ธ๋ฆฟ ์ปจํ ์ด๋๋ ๋ ๊ฐ์ง ์์ธ ์ฒ๋ฆฌ๋ฅผ ์ง์ํฉ๋๋ค.
1. ์ง์ ์์ธ๋ฅผ ๋์ง๋ ๋ฐฉ์.
2. response.sendError(HTTP ์ํ์ฝ๋, ์ค๋ฅ ๋ฉ์์ง) : ์ง์ ์๋ฌ๋ฅผ response์ ๋ด๋ ๋ฐฉ์
@Controller
public class ServletExController {
@GetMapping("/error-ex")
public void errorEx()
{
// ๋ฐํ์ ์์ธ๋ ์๋ฒ ์๋ฌ -> 500๋ฒ๋
throw new RuntimeException("์์ธ ๋ฐ์");
}
http://localhost:8080/error-ex ์์ฒญ ์
์ด ์ ์ ์์ฃผ ๋ดค๋ ํ์ดํธ๋ผ๋ฒจ ์ค๋ฅ ํ์ด์ง๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
WAS๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์ธ๋ฅผ ๋ฐ์์ ๊ฒฝ์ฐ ์คํ๋ง ๋ถํธ๊ฐ ์ ๊ณตํ๋ ํ์ดํธ ๋ผ๋ฒจ ์ค๋ฅ ํ์ด์ง๋ฅผ ์ถ๋ ฅํ๊ฒ ๋๋๋ฐ์. ํ์ดํธ๋ผ๋ฒจ ํ์ด์ง๊ฐ ์๋ Tomcat์ด ์ ๊ณตํ๋ ์ค๋ฅ ํ๋ฉด์ ๋ณผ ์ ์๋๋ก ์ค์ ํ๋ ค๋ฉด application.properties์ ์๋ ์ต์ ์ ์ถ๊ฐํด ์ฃผ์๋ฉด ๋ฉ๋๋ค.
server.error.whitelabel.enabled=false
ํฐ์บฃ์ด ์ง์ํ๋ ์ค๋ฅํ๋ฉด์ด๋ ์คํ๋ง์ด ์ง์ํ๋ ์ค๋ฅํ๋ฉด์ด๋ ํด๋ผ์ด์ธํธ ์ ์ฅ์์ ๋ณด์์ ๋ ๋ชจ๋ ์นํ์ ์ด์ง ์์์.
ํ์ง๋ง ์๋ธ๋ฆฟ์ ์ค๋ฅํ๋ฉด์ ์ปค์คํ ํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์ปค์คํ ๋ฐฉ๋ฒ
@Component
public class WebServerCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
@Override
public void customize(ConfigurableWebServerFactory factory) {
ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error-page/404");
ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/error-page/500");
ErrorPage errorPageEx = new ErrorPage(RuntimeException.class,"/error-page/500");
factory.addErrorPages(errorPage404,errorPage500,errorPageEx);
}
}
- WebServerFactoryCustomizer<ConfigurableWebServerFactory> ์ธํฐํ์ด์ค ์์ ๋ฐ์ ํด๋์ค ์์ฑ ํ ์ปจํ ์ด๋์ ๋ฑ๋ก
- customize() ๋ฉ์๋ ์ค๋ฒ๋ผ์ด๋ฉ ํฉ๋๋ค.
- customize ๋ฉ์๋ ๋ด๋ถ์ ErrorPage๋ฅผ ์์ฑํฉ๋๋ค. / ErrorPage(code, path) : code์ ์ค๋ฅ ๋ฐ์ ์ path ๊ฒฝ๋ก๋ฅผ request
- factory์ ์์ฑํ ErrorPage๋ฅผ ์ถ๊ฐํด ์ค๋๋ค. / factory.addErrorPage(์์ฑํ ErrorPage .. )
@RequestMapping("/error-page/404")
public String errorPage404(HttpServletRequest request, HttpServletResponse response)
{
log.info("errorPage 404");
return "error-page/404";
}
์ปจํธ๋กค๋ฌ์์๋ ์ปค์คํฐ๋ง์ด์ ์ ๋ฑ๋กํ path๋ฅผ ํตํด error-page/404 ๋ทฐ ํ ํ๋ฆฟ์ผ๋ก ์ด๋ํ๋๋ก ์ค์ ํ์ต๋๋ค.
์ด๋ ๊ฒ ๋๋ฉด ํ ๋ฒ์ ์์ฒญ์ ํตํด WAS๋ ๋ ๋ฒ์ ์์ ์ ํ๊ฒ๋ฉ๋๋ค.
1. WAS("/error-ex"ํธ์ถ) -> ํํฐ -> ์๋ธ๋ฆฟ -> ์ธํฐ์ ํฐ -> ์ปจํธ๋กค๋ฌ (์์ธ๋ฐ์)
2. WAS(์์ธ ์ ํ๋ฐ์) <- ํํฐ <- ์๋ธ๋ฆฟ <- ์ธํฐ์ ํฐ <- ์ปจํธ๋กค๋ฌ (์์ธ์ ํ)
3. โถ๏ธ WAS( WebServerCustomizer๋ฅผ ํตํด ์์ธ์ ๋งคํ๋ URI๋ฅผ ํตํด ์ด๋ํฐ(@RequestMapping("/error-page/500") ํธ์ถ) -> ํํฐ -> ์๋ธ๋ฆฟ -> ์ธํฐ์ ํฐ -> ์ด๋ํฐ์ ๋งคํ๋ ์ปจํธ๋กค๋ฌ(errorPage404) ํธ์ถ -> ๋ทฐ ํ ํ๋ฆฟ ๋ฆฌํด
โ๏ธ๋น์ฐํ ์ด์ผ๊ธฐ์ง๋ง ํด๋ผ์ด์ธํธ๋ ์๋ฒ ๋ด๋ถ์์ ์ด๋ ๊ฒ ๋ ๋ฒ ๋์ํ๋์ง ์ ์ ์์ต๋๋ค. ( WAS ์ ์์ ์ฒ๋ฆฌํ๊ณ ์ต์ข ๊ฒฐ๊ณผ์ธ ๋ทฐ๋ง ํด๋ผ์ด์ธํธ์๊ฒ ๋ฆฌํดํ๊ธฐ ๋๋ฌธ์ )
โ๏ธ์ด ๋ ์ค์ํ ์ ์ 3๋ฒ ์ฌํธ์ถ ๊ณผ์ ์์ request์ attribute์ ์ค๋ฅ ์ ๋ณด๋ฅผ ์ถ๊ฐํด์ ๋๊ฒจ์ค๋ค๋ ์ .
์ค๋ฅ ์ ๋ณด๋ RequestDispatcher์ ์์๋ก ์ ์๋์ด ์์ต๋๋ค.
- javax.servlet.error.exception : ์์ธ
- javax.servlet.error.exception_type : ์์ธ ํ์
- javax.servlet.error.message : ์ค๋ฅ ๋ฉ์์ง
- javax.servlet.error.request_uri : ํด๋ผ์ด์ธํธ ์์ฒญ URI
- javax.servlet.error.servlet_name : ์ค๋ฅ๊ฐ ๋ฐ์ํ ์๋ธ๋ฆฟ ์ด๋ฆ
- javax.servlet.error.status_code : HTTP ์ํ ์ฝ๋
@RequestMapping("/error-page/500")
public String errorPage500(HttpServletRequest request, HttpServletResponse response) {
log.info("errorPage 500");
printErrorInfo(request);
return "error-page/500";
}
private void printErrorInfo(HttpServletRequest request)
{
log.info("ERROR_EXCEPTION: ex=" ,request.getAttribute(ERROR_EXCEPTION));
log.info("ERROR_EXCEPTION_TYPE: {}",request.getAttribute(ERROR_EXCEPTION_TYPE));
log.info("ERROR_MESSAGE: {}", request.getAttribute(ERROR_MESSAGE)); // ex์ ๊ฒฝ์ฐ NestedServletException ์คํ๋ง์ด ํ๋ฒ ๊ฐ์ธ์ ๋ฐํ
log.info("ERROR_REQUEST_URI: {}",request.getAttribute(ERROR_REQUEST_URI));
log.info("ERROR_SERVLET_NAME: {}",request.getAttribute(ERROR_SERVLET_NAME));
log.info("ERROR_STATUS_CODE: {}",request.getAttribute(ERROR_STATUS_CODE));
log.info("dispatchType={}", request.getDispatcherType());
}
๋ ๋ฒ์งธ ์์ฒญ์ request์ ๋ด๊ธด ERROR ์ ๋ณด ์ถ๋ ฅ
์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ์ค๋ฅํ์ด์ง๋ฅผ ์ถ๋ ฅํ๊ธฐ ์ํด WAS ๋ด๋ถ์์ ํธ์ถ์ด ์ถ๊ฐ์ ์ผ๋ก ํ๋ฒ ๋ ์ผ์ด๋ฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ํํฐ์, ์๋ธ๋ฆฟ, ์ธํฐ์ ํฐ, ์ปจํธ๋กค๋ฌ๊ฐ ์ด ๋ ๋ฒ ํธ์ถ๋๋๊ฑด๋ฐ, ์๋ธ๋ฆฟ๊ณผ ์ปจํธ๋กค๋ฌ๋ ํ์์ ์ผ๋ก ํธ์ถํด์ผ ๋๊ธฐ ๋๋ฌธ์ ๊ทธ๋ ๋ค ์น๋๋ฐ, ํํฐ๋ ์ธํฐ์ ํฐ๋ ๊ตณ์ด ์๋์ฒ๋ผ ๋ ๋ฒ ํธ์ถํ ์ด์ ๊ฐ ์๊ฒ ์ฃ ? ์ค์ ์ ํตํด ์ค๋ณต ํธ์ถ์ ๋นผ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์๋ธ๋ฆฟ ์์ธ ์ฒ๋ฆฌ - ํํฐ ์ค๋ณต ํธ์ถ ์ ๊ฑฐ
์๋ฐ ํ์ค ์คํ์ด ์ง์ํ๋ ํํฐ์ ๊ฒฝ์ฐ์๋ ๋ฑ๋กํ ๋ dispatcherTypes ์ต์ ์ ํตํด ํํฐ๋ฅผ ์ ์ฉํ distpatcherType์ ์ค์ ํ ์ ์์ต๋๋ค.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean logFilter()
{
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new LogFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST,DispatcherType.ERROR);
return filterRegistrationBean;
}
default๋ก REQUEST๋ง ์ค์ ๋์ด ์์ต๋๋ค๋ง, setDistPatcherTypes๋ฅผ ํตํด ์ง์ ๋ฑ๋กํ ์ ์์ต๋๋ค.
ERRORS๋ฅผ ๋นผ๊ณ ์คํํ๋ฉด request์ ์ค๋ฅ์ ๋ณด๊ฐ ๋ด๊ฒจ์๋๊ฒฝ์ฐ ํํฐ๋ฅผ ์ ์ฉํ์ง ์์ต๋๋ค.
DispatcherType
REQUEST : ํด๋ผ์ด์ธํธ ์์ฒญ
ERROR : ์ค๋ฅ ์์ฒญ
FORWARD : MVC์์ ๋ฐฐ์ ๋ ์๋ธ๋ฆฟ์์ ๋ค๋ฅธ ์๋ธ๋ฆฟ์ด๋ JSP๋ฅผ ํธ์ถํ ๋
- RequestDispatcher.forward(request, response);
INCLUDE : ์๋ธ๋ฆฟ์์ ๋ค๋ฅธ ์๋ธ๋ฆฟ์ด๋ JSP์ ๊ฒฐ๊ณผ๋ฅผ ํฌํจํ ๋
- RequestDispatcher.include(request, response);
ASYNC : ์๋ธ๋ฆฟ ๋น๋๊ธฐ ํธ์ถ
์๋ธ๋ฆฟ ์์ธ ์ฒ๋ฆฌ - ์ธํฐ์ ํฐ ์ค๋ณต ํธ์ถ ์ ๊ฑฐ
์๋ฐ๊ฐ ์๋ ์คํ๋ง ๊ธฐ์ ์ธ ์ธํฐ์ ํฐ์ ๊ฒฝ์ฐ์๋ ํจ์ฌ ๊ฐ๋จํ๊ฒ ํด๊ฒฐํ ์ ์์ต๋๋ค.
๊ทธ๋ฅ ์ค๋ฅ ํ์ด์ง ๊ฒฝ๋ก๋ฅผ excluePathPatterns๋ฅผ ์ฌ์ฉํด์ ๋นผ์ฃผ๋ฉด ๋ฉ๋๋ค.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.order(1)
.addPathPatterns("/**")
.excludePathPatterns("/css/**","/*.ico","/error","/error-page/**");
}
}
์๋ธ๋ฆฟ์์ ์์ธ ํ๋ฆ์ ์์๋ณด๊ณ ํํฐ์ setDispatcherTypes์ ์ธํฐ์ ํฐ์ excludePatterns ์ต์ ์ผ๋ก ์ฌ์ฉํด ERROR๊ฐ ์๋ REQUEST์ ๋ํด์๋ง ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํด ๋ณด์์ต๋๋ค.
์ด๊ฑธ ์ ํ์ฉํ๋ค๋ฉด ํ๋ค๋ฉด ํํฐ์ ์ธํฐ์ ํฐ์ ์ค๋ณตํธ์ถ์ ๋ง์ ์ ์์ต๋๋ค!
์๋ฅผ ๋ค์ด ๋ก๊ทธ์ธ ์ธ์ฆ ์ฒดํฌ ๊ฐ์ ๊ฒฝ์ฐ ์ด๋ฏธ ํ๋ฒ ํํฐ๋, ์ธํฐ์ ํฐ์์ ๋ก๊ทธ์ธ ์ฒดํฌ๋ฅผ ์๋ฃํ๋๋ฐ ์๋ฒ ๋ด๋ถ์์ ์ค๋ฅ ํ์ด์ง๋ฅผ ํธ์ถํ์ ๋, ํด๋น ํํฐ๋ ์ธํฐ์ ํธ๊ฐ ํ๋ฒ ๋ ํธ์ถ๋๋ ๊ฒ์ ํํฐ์ setDispatcherTypes๋ ์ธํฐ์ ํฐ์ excludePathPatterns๋ฅผ ์ด์ฉํด ๋ง์ ์ ์๊ฒ ์ต๋๋ค.
<์ฐธ๊ณ ์๋ฃ>
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard
'๐ Backend > MVC Pattern' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
ํ์ ์ปจ๋ฒํฐ(Type Converter) (0) | 2023.03.29 |
---|---|
API์์์ ์์ธ ์ฒ๋ฆฌ (0) | 2023.03.28 |
ArgumentResolver ํ์ฉ (0) | 2023.03.24 |
์คํ๋ง ์ธํฐ์ ํฐ(Interceptor) (0) | 2023.03.24 |
Servlet Filter(์๋ธ๋ฆฟ ํํฐ) (0) | 2023.03.24 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422