4-1 의존성 주입과 스프링
스프링 프레임워크가 가장 많이 사용되는 곳은 웹 개발 프로젝트이지만 스프링 프레임워크의 출발점은 객체지향이나 설계와 관련된 내용들이 주를 이루고 있습니다.
스프링의 시작
스프링 프레임워크는 원래 웹이라는 제한적인 용도로만 쓰이는 것이 아니라 객체지향의 의존성 주입(dependency injection) 기업을 적용할 수 있는 객체지향 프레임워크였습니다.
2000년 당시 자바 진영에서 JavaEE의 여러 가지 스펙을 정의하고 비대해지는 동안 스프링 프레임워크는 반대로 경량 프레임워크를 목표로 만들어졌습니다.
스프링 프레임워크는 가장 중요한 '코어' 역할을 하는 라이브러리와 여러 개의 추가적인 라이브러리를 결합하는 형태로 프로젝트를 구성하는데 가장 대표적으로 웹 MVC 구현을 쉽게 할 수 있는 'Spring Web MVC'나 JDBC 처리를 쉽게 할 수 있는 'MyBatis'를 연동하는 'mybatis-spring'과 같은 라이브러리가 그러한 예입니다.
의존성 주입
스프링이 객체지향 구조를 설계할 때 받아들인 개념은 '의존성 주입'이라는 사상입니다. 의존성 주입은 어떻게 하면 객체와 객체 간의 관계를 더 유연하게 유지할 것인가?에 대한 고민으로 객체의 생성과 관계를 효과적으로 분리할 수 있는 방법에 대한 고민입니다.
의존성이란 하나의 객체가 자신이 해야 하는 일을 하기 위해서 다른 객체의 도움이 필수적인 관계를 의미합니다.
과거에는 의존성을 해결하기 위해 컨트롤러에서 직접 서비스 객체를 생성하거나 하나의 객체만을 생성해서 활용하는 등의 다양한 패턴을 설계해서 적용해 왔는데 스프링 프레임워크는 바로 이런 점을 프레임워크 자체에서 지원하고 있습니다.
ApplicationContext와 빈(Bena)
테스트가 성공했다면 어떠한 과정을 통해서 이러한 결과가 발생했는지를 알아야 합니다. 이때 꼭 필요한 용어가 ApplicationContext라는 용어입니다.
서블릿이 존재하는 공간을 서블릿 컨택스트라고 했던 것처럼, 스프링에서는 빈이라고 부르는 객체들을 관리하기 위해서 ApplicationContext라는 존재를 활용합니다.
@Autowired의 의미와 필드 주입
@Autowired가 처리된 부분에 맞는 타입의 빈(Bean)이 존재하는지를 확인하고 이를 테스트 코드 실행시에 주입하게 됩니다. 멤버 변수에 직접 @Autowired를 선언하는 방식을 '필드 주입(Filed Injection)' 방식이라고 합니다.
(2) SampleDAO 주입하기
@ToString
public class SampleService {
@AutoWired
private SampleDAO sampleDAO;
}
테스트 코드를 실행하면 SampleService 객체 안에 SampleDAO 객체가 주입된 것을 확인할 수 있습니다.
(3) @Service, @Repository
- @Controller: MVC의 컨트롤러를 위한 어노테이션
- @Service: 서비스 계층의 객체를 위한 어노테이션
- @Repository: DAO와 같은 객체를 위한 어노테이션
- @Component: 일반 객체나 유틸리티 객체를 위한 어노테이션
@Repository
public class SampleDAO {
}
해당 클래스의 객체가 스프링에서 Bean으로 관리될 수 있도록 @Reopository라는 어노테이션을 추가합니다.
@Service
@ToString
public class SampleService {
@AutoWired
private SampleDAO sampleDAO;
}
<context:component-scan>
스프링을 이용할 때는 객체를 직접 생성하지 않습니다. 이 역할은 스프링 내부에서 이루어지며 ApplicationContext가 생성된 객체들을 관리하게 됩니다.
이처럼 개발자가 직접 객체를 생성하지 않는 방식은 서블릿과도 유사합니다. 서블릿을 생성하면 톰캣이 웹 애플리케이션을 실행하고 필요할 때 서블릿 객체를 만드는 것과 비슷한 방식입니다.
생성자 주입 방식
생성자 주입 방식은 다음과 같은 규칙으로 작성됩니다.
- 주입 받아야 하는 객체의 변수는 final로 작성합니다.
- 생성자를 이용해서 해당 변수를 생성자의 파라미터로 지정합니다.
생성자 주입 방식은 객체를 생성할 때 문제가 발생하는지를 미리 확인할 수 있기 때문에 필드 주입이나 Setter 주입 방식보다 선호되는 방식입니다.
Lombok에서는 생성자 주입을 보다 간단히 작성할 수 있는데 @RequiredArgsConstructor를 이용해서 필요한 생성자 함수를 자동으로 작성할 수 있기 때문입니다.
인터페이스를 이용한 느슨한 결합
스프링이 의존성 주입을 가능하게 근본적으로 유연한 프로그램을 설계하기 위해서는 인터페이스를 이용해서 나중에 다른 클래스의 객체로 쉡게 변경할 수 있도록 하는 것이 좋습니다. 인터페이스를 이용하면 실제 객체를 모르고 타입만을 이용해서 코드를 작성하는 일이 가능해집니다.
@Repository
public class SampleDAOImpl implements SampleDAO{
}
SampleDAO를 인터페이스 타입으로 수정하고 SampleImpl에서 인터페이스를 구현하고 @Repository를 달았씁니다. SampleService는 인터페이스만 바라보기 때문에 실제 객체를 알수 없지만 코드를 작성하는데에는 문제 없습니다. 이러한 방식을 느슨한 결합이라고 하며 SampleService 타입을 이용하는 코드를 수정할 일이 없기 때문에 유연한 구조가 됩니다.
@Repository
public class EventSampleDAOImpl implements SampleDAO{
}
이렇게 되면 SampleService에 필요한 SampleDAO 타입의 빈이 두개가 되기 때문에 스프링입장에서는 어떤 것을 주입해야 하는지 알수 없게 됩니다. 가장 간단하게 해결하는 방법은 @Primary를 지정해주는 것입니다.
@Qualifier 이용하기
@Qualifier("normal")
@Repository
public class SampleDAOImpl implements SampleDAO{
}
SampleDAOImple에는 'normal'을 지정해주고
@Qualifier("event")
@Repository
public class EventSampleDAOImpl implements SampleDAO{
}
EventSampleDAOImpl에는 'event'를 지정해줍니다.
@Service
@ToString
@RequiredArgsConstructor
public class SampleService {
@Qualifier("normal")
private SampleDAO sampleDAO;
}
normal 이름을 가진 SampleDAOImple이 주입되는 것을 확인할 수 있습니다.
스프링의 빈으로 지정되는 객체들
모든 클래스의 객체가 스프링의 빈으로 처리되는 것은 아닙니다. 빈은 핵심 배역을 하는 객체들입니다. DTO나 VO와 같이 데이터에 중점을 두고 설계된 객체들은 빈으로 등록되지 않습니다.
XML이나 어노테이션으로 처리하는 객체
빈으로 처리할 떄 XML 설정을 이용할 수도 있고 어노테이션을 처리할 수도 있지만 이에 대한 기준은 코드를 수정할 수 있는가로 판단하면 됩니다. 예를 들어 jar 파일로 추가되는 클래스의 객체를 빈으로 처리해야 하면 해당 코드가 존재하지 않아 어노테이션을 추가할 수 없습니다. 이러한 객체들은 XML에서 <bean>을 이용해서 처리하고 직접 작성되는 클래스는 어노테이션을 이용하는 것이 좋습니다.
웹 프로젝트를 위한 스프링 준비
스프링의 구조를 보면 Application Context라는 객체가 존재하고 빈(Bean)으로 등록된 객체들은 ApplicationContext 내에 생성되어서 관리되는 구조입니다. ApplicationContext가 웹 애플리케이션에서 동작하려면 웹 애플리케이션이 실행될 때 스프링을 로딩해서 해당 웹 애플리케이션 내부에 스프링의 ApplicationContext를 생성하는 작업이 필요하게 되는데 이를 위해서는 web.xml을 이용해서 리스너를 설정합니다.
4-2 MyBatis와 스프링 연동
스프링 프레임워크의 중요한 특징 중 하나는 다른 프레임워크들을 쉽게 결합해서 사용할 수 있다는 점입니다. 이것은 스프링 프레임워크가 웹이나 데이터베이스와 같이 특정한 영역을 구애받지 않고 시스템의 객체지향 구조를 만드는 데 이용된다는 성격 때문입니다.
MyBatis
MyBatis는 'Sql Mapping Framework'라고 표현됩니다. SQL의 실행 결과를 객체지향으로 매핑해준다는 뜻입니다.
MyBatis를 이용하면 기존의 SQL을 그대로 사용할 수 있으며 다음과 같은 점들이 편리해집니다.
- PreparedStatemnet/ResultSet의 처리 - 기존의 프로그램을 작성해서 하나씩 처리해야 하는 파라미터나 ResultSet의 getXXX()를 Mybatis가 알아서 처리해 주기 때문에 기존에 비해서 많은 양의 코드를 줄일 수 있습니다.
- Connection/PreparedStatment/ResultSet의 close()처리 - MyBatis와 스프링을 연동해서 사용하는 방식을 이용하면 자동으로 close()처리를 할 수 있습니다.
- SQL의 분리 - MyBatis를 이용하면 별도의 파일이나 어노테이션 등을 이용해서 SQL을 선언합니다. 파일을 이용하는 경우에는 SQL을 별도의 파일로 분리해서 운영이 가능합니다.
MyBatis와 스프링의 연동 방식
MyBatis는 단독으로 실행이 가능한 완전히 독릭접인 프레임워크이지만 스프링 프레임워크는 MyBatis와 연동을 쉽게 처리할 수 있는 API들을 제공합니다. 스프링에서 제공하는 라이브러리를 이용하는지 여부에 따라 다음과 같은 방식 중에 하나로 개발이 가능합니다.
- MyBatis를 단독으로 개발하고 스프링에서 DAO를 작성해서 처리하는 방식: 기존의 DAO에서 SQL의 처리를 MyBatis를 이용하는 구조로써 완전히 MyBatis와 스프링 프레임워크를 독릭접인 존재로 바라보고 개발하는 방식
- MyBatis와 스프링을 연동하고 Mapper 인터페이스만 이용하는 방식 - 스프링과 MyBatis 사이에 'mybatis-spring'이라는 라이브러리를 이용해서 스프링이 데이터베이스 전체에 대한 처리를 하고 Mybatis는 일부 기능 개발에 활용하는 방식. 개발 시에는 Mapper 인터페이라는 방식을 이용해서 인터페이스만으로 모든 개발이 가능한 방식
(1) Mapper 인터페이스 활용하기
public interface TimeMapper {
@Select("select now()");
String gettime();
}
MyBatis는 @Select 어노테이션을 이용해서 쿼리를 작성할 수 있습니다.
MyBatis와 스프링을 연동하고 인터페이스를 활용하는 방식은 개발자가 동작하는 클래스와 객체를 생성하지 않고 스프링에서 자동으로 생성되는 방식을 이용합니다. 따라서 직접 코드를 수정할 수 없다는 단점이 있지만 인터페이스만으로도 개발을 완료할 수 있다는 장점이 있습니다.
(2)XML로 SQL 분리하기
XML을 이용하는 이유는 SQL이 길어지면 이를 어노테이션으로 처리하기가 복잡하고 어노테이션이 변경되면 다시 빌드하는 작업이 필요하기 때문에 단순 파일로 사용하는 것이 편리합니다.
XML과 매퍼 인터페이스를 결합할 때는 다음과 같은 과정으로 작성합니다.
- 매퍼 인터페이스를 정의하고 메소드를 선언
- 해당 XML파일을 작성하고 <select>와 같은 태그를 이용해서 SQL작성
- <select>, <insert> 등의 태그에 id 속성값을 매퍼 인터페이스의 메소드 이름과 같게 작성
public interface TimeMapper2 {
String getNow();
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<select id="getNow" resultType="string">
select now()
</select>
</beans>
<select>태그는 반드시 resultType이나 resultMap이라는 속성을 지정해야 합니다. resultType은 select문의 결과를 어떤 타입으로 처리할지에 대한 설정입니다.
4-3 스프링 Web MVC기초
스프링 Web MVC는 기본적으로 서블릿 API들을 좀 더 추상화된 형태로 작성된 라이브러리지만 기존의 서블릿/JSP를 사용할 때 많은 기능들을 기본적으로 제공해서 개발의 생산성과 안정성을 획기적으로 높여주었습니다.
스프링 Web MVC의 특징
기본 구조에 약간의 변화를 주는 부분은 다음과 같습니다.
- Front-Controller 패턴을 이용해서 모든 흐름의 사전/사후 처리를 가능하도록 설계
- 어노테이션을 적극적으로 활용해서 최소한의 코드로 많은 처리가 가능하도록 설계
- HttpServletReqyest/HttpServletResponse를 이용하지 않아도 될만큼 추상화된 방식으로 개발
DispatcherServlet과 Front Conroller
스프링MVC에서 가장 중요한 사실은 모든 요청이 반드시 DispatcherServlet이라는 존재를 통해서 실행된다는 점입니다.
객체지향에서 이렇게 모든 흐름이 하나의 객체를 통해서 진행되는 패턴을 '퍼사드(facade)'라고 하는데 웹구조에서는 'Front-Controller 패턴'이라고 부릅니다.
Front-Controller 패턴을 이용하면 모든 요청이 반드시 하나의 객체를 지나서 처리되기 때문에 모든 공통적인 처리를 프론트 컨트롤러에서 처리할 수 있게 됩니다.
스프링 MVC에서는 DispatcherServlet이라는 객체가 프론트 컨트롤러의 역할을 수행합니다.
프론트 컨트롤러가 사전/사후에 대한 처리를 하게 되면 중간에 매번 다른 처리를 하는 부분만 별도로 처리하는 구조를 만들게 됩니다. 스프링MVC에서는 이를 컨트롤러라고 하는데 @Controller를 이용해서 처리합니다.
(1) 스프링MVC 컨트롤러
과거 많은 프레임워크들은 상속이나 인터페이스를 기반으로 구현되는 방식을 선호했다면 스프링MVC 컨트롤러들은 다음과 같은 점들이 다릅니다.
- 상속이나 인터페이스를 구현하는 방식을 사용하지 않고 어노테이션만으로 처리가 가능
- 오버라이드 없이 필요한 메소드들을 정의
- 메소드의 파라미터를 기본 자료형이나 객체 자료형을 마음대로 지정
- 메소드의 리턴타입도 void, String, 객체 등 다양한 타입을 사용할 수 있음
@Controller
@Log4j2
public class SampleController {
@GetMapping("/hello")
public void hello(){
log.info("hello....");
}
}
@Controller는 해당 클래스가 스프링 MVC에서 컨트롤러 역할을 한다는 것을 의미하고 스프링의 빈으로 처리되기 위해 사용됩니다.
@GetMapping은 GET방식으로 들어오는 요청을 처리하기 위해 사용합니다.'/hello'라는 경로를 호출할 때 동작하게 됩니다.
servlet-context.xml의 component-scan
컨트롤러 클래스들을 스프링으로 인식하기 위해서는 해당 페이지를 스캔해서 @Controller 어노테이션이 추가된 클래스들의 객체들을 스프링의 빈으로 설정되게 만들어야합니다.
@Controller
@RequestMapping("/todo")
@Log4j2
public class TodoController {
@RequestMapping("/list")
public void list(){
log.info("todo list.....");
}
@RequestMapping(value="/register",method=RequestMethod.GET)
public void register(){
log.info("todo register...");
}
}
TodoController의 @RequestMapping의 value 값은 '/todo'이고 list()는 '/list' 이므로 최종경로는 '/todo/list'입니다.
@GetMapping, @PostMapping 어노테이션만 추가되면 GET/POST 방식을 구분해서 처리가능합니다.
파라미터 자동 수집과 변환
스프링MVC가 인기를 끌게된 이유 중 하나는 개발시간을 단축할 수 있는 편리한 기능들이 많기 때문입니다.
파라미터 자동 수집은 DTO나 VO들을 메소드의 파라미터로 설정하면 자동으로 전달되는 HttpServletRequest의 파라미터들을 수집해주는 기능입니다. 단순히 문자열뿐만 아니라 숫자도 가능하며 배열이나 리스트, 첨부파일도 가능합니다. 파라미터 수집은 다음과 같은 기준으로 작동합니다.
- 기본 자료형의 경우 자동으로 형 변환처리가 가능합니다.
- 객체 자료형의 경우는 setXXX()의 동작을 통해서 처리됩니다.
- 객체 자료형의 경우 생성자가 없거나 파라미터가 없는 생성자가 필요(Java Beans)
(3) 단순 파라미터의 자동 수집
@GetMapping("/ex1");
public void ex1(String name, int age){
log.info("ex1.....");
log.info("name: "+name);
log.info("age: "+ age);
}
'/ex1?name=AAA&age=16'과 같이 호출되었을 때 자동으로 처리되는 것을 확인할 수 있습니다.
@RequestParam
스프링MVC의 파라미터는 기본적으로 요청에 전달된 파라미터 이름을 기준으로 동작하지만 간혹 파라미터가 전달되지 않으면 문제가 발생할 수 있습니다. 이런 경우 @RequestParam을 고려해 볼 수 있습니다.
@RequestParam은 defaultValue라는 속성이 있어 기본값을 지정할 수 있습니다.
@GetMapping("/ex2")
public void ex2(@RequestParam(name="name", defaultValue="AAAA")String name,
@RequestParam(name="age", defaultValue="20")int age){
log.info("ex2....");
log.info("name: "+ name);
log.info("age: "+ age);
}
'/exe2'를 실행해 보면 기본값으로 처리되는 것을 확인할 수 있습니다.
Formatter을 이용한 파라미터의 커스텀 처리
Http는 문자열로 데이터를 전달하기 때문에 컨트롤러는 문자열을 기준으로 특정한 클래스의 객체로 처리하는 작업이 진행됩니다. 이때 날짜 관련 타입이 문제입니다.
브라우저에서'2020-10-10'과 같은 형태의 문자열을 Date나 LocalDate,LocalDateTime 등으로 변환하는 작업은 많이 필요하지만 이에 대한 파라미터 수집은 에러가 발생합니다.
이런 경우 Formatter라는 것을 이용할 수 있습니다. 문자열을 포맷을 이용해서 특정한 객체로 변환하는 경우에 사용합니다.
@Override
public class LocalDateFormatter implements Formatter<LocalDateTime> {
@Override
public LocalDate parse(String text, Locale locale){
return LocalDate.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}
@Override
public String print(LocalDateTime object, Locale locale) {
return DateTimeFormatter.ofPattern("yyyy-MM-dd").format(object);
}
}
호출하면 서버에서 문제없이 파라미터가 수집되는 것을 확인할 수 있습니다.
객체 자료형의 파라미터 수집
기본 자료형과 달리 객체 자료형을 파라미터로 처리하기 위해서는 객체가 생성되고 setXXX()을 이용해서 처리합니다. Lombok을 활용한다면 @Setter나 @Data를 이용하는 것이 가장 간단합니다.
@Controller
@RequestMapping("/todo")
@Log4j2
public class TodoController {
@RequestMapping("/list")
public void list(){
log.info("todo list....");
}
@GetMapping("/list")
public void registerGET(){
log.info("GET todo register....");
}
@Getmapping("/register")
public void registerPost(TodoDTO todoDTO){
log.info("POST todo register....");
log.info(todoDTO);
}
}
registerPost()의 파라미터는 TodoDTO를 사용하도록 수정했습니다. 자동으로 형 변환이 처리되기 때문에 TodoDTO과 같이 다양한 타입의 멤버 변수들의 처리가 자동으로 이루어지게 됩니다.
Model이라는 특별한 파라미터
스프링MVC는 기본적으로 웹 MVC와 동일한 방식이므로 모델이라고 부르는 데이터를 JSP까지 전달할 필요가 있습니다. 서블릿 방식에서는 reqyest.setAttribute()를 이용해서 데이터를 담아 JSP까지 전달했지만 스프링 MVC방식에서는 Model이라는 객체를 이용해서 처리할 수 있습니다.
@GetMapping("/ex4")
public void ex4(Model model){
log.info("---------------");
model.addAttribute("message", "Hello World");
}
Model에는 addAttribute()라는 메소드를 이용해서 뷰에 전달할 이름과 값을 지정할 수 있습니다.
Java Beans와 @ModelAttribute
스프링 MVC의 컨트롤러는 파라미터로 getter/setter를 이용하는 Java Beans의 형식의 사용자 정의 클래스가 파라미터인 경우에는 자동으로 화면까지 객체를 전달합니다.
@GetMapping("/ex4")
public void ex4Extra(@ModelAttribute("dto") TodoDTO todoDTO, Model model){
log.info("todoDTO");
}
이 경우 JSP에서는 별도의 처리 없이 ${TodoDTO}를 이용할 수 있습니다. 자동으로 생성된 변수명 todoDTO라는 이름 외에 다른 이름을 사용하고 싶다면 명시적으로 @ModelAttribute()를 지정할 수 있습니다. ${dto}와 같은 이름의 변수로 처리할 수 있습니다.
RedirectAttributes와 리다이렉션
PRG패턴을 처리하기 위해서 스프링 MVC에서는 RedirectAttribytes라는 특별한 타입을 제공합니다. RedirectAttributes 역시 파라미터로 추가해주기만 하면 자동으로 생성되는 방식입니다. 중요한 메소드는 다음과 같습니다.
- addAttribute(키,값): 리다이렉트할 때 쿼리 스트링이 되는 값을 지정
- addFlashAttribute(키,값): 일회용으로만 데이터를 전달하고 삭제되는 값을 지정
addAttribyte()로 데이터를 추가하면 리다이렉트할 URL에 쿼리 스트링으로 추가되고, addFlashAttribute()를 이용하면 URL에는 보이지 않지만 JSP에서는 일회용으로 사용할 수 있습니다.
@GetMapping("/ex5")
public String ex5(RedirectAttributes redirectAttributes){
redirectAttributes.addAttribute("name", "ABC");
redirectAttributes.addFlashAttribute("result", "success");
return "redirect:/ex6";
}
@GetMapping
public void ex6(){
}
ex5()는 RedirectAttribute를 파라미터로 추가하고 addAttribute()와 addFlashAttribute()를 이용해서 name과 result라는 이름의 데이터를 전달합니다.
redirect:라는 접두어를 붙여서 문자열로 반환합니다.
- redirect: 리다이렉션을 이용하는 경우
- forward: 브라우저의 URL은 고정하고 내부적으로 다른 URL을 처리하는 경우
특별한 경우가 아니라면 forward를 이용하는 경우는 없습니다.
스프링MVC에서 주로 사용하는 어노테이션들
컨트롤러 선언부에서 사용하는 어노테이션
- @Controller: 스프링 빈의 처리됨을 명시
- @RestController: REST방식의 처리를 위한 컨트롤러임을 명시
- @RequestMapping: 특정한 URL 패턴에 맞는 컨트롤러인지를 명시
메소드 선언부에서 사용하는 어노테이션
- @GetMapping/@PostMapping/@DeleteMapping/@PutMapping..: HTTP 전송 방식에 따라 해당하는 메소드를 지정하는 경우에 사용 일반적으로 @GetMapping과 @PostMapping이 주로 사용
- @RequestMapping: GET/POST 방식 모두 지원하는 경우에 사용
- @ResponseBody: REST방식에 사용
메소드의 파라미터에 사용하는 어노테이션
- RequestParam: Request에 있는 특정한 이름의 데이터를 파라미터로 받아서 처리하는 경우에 사용
- @PahtVariable: URL 경로의 일부를 변수로 삼아서 처리하기 위해 사용
- @ModelAttribute: 해당 파라미터는 반드시 Model에 포함되어서 다시 뷰로 전달됨을 명시
스프링MVC의 예외 처리
컨트롤러에서 발생하는 예외를 처리하는 가장 일반적인 방식은 @ControllerAdvice를 이용하는 것입니다. 예외에 맞게 처리할 수 있는 기능을 제공하는데 @ControllerAdvice가 선언된 클래스 역시 스프링의 빈으로 처리됩니다.
@ExceptionHandler
@ControllerAdvice의 메소드들에는 특별하게 @ExceptionHandler라는 어노테이션을 사용할 수 있습니다. 이를 이용해서 전달되는 Execption 객체들을 지정하고 메소드의 파라미터에서는 이를 이용할 수 있습니다.
@GetMapping("ex7")
public void ex7(String p1, int p2){
log.info("p1......" + p1);
log.info("P2......" + p2);
}
ex7()은 문자열과 숫자를 파라미터로 처리합니다. 만약 숫자 대신에 알파벳을 보낸다면 에러가 발생할 것입니다.
@ControllerAdvice
@Log4j
public class CommonExceptionAdvice {
@ResponseBody
@ExceptionHandler(NumberFormatException.class)
public String exceptNumber(NumberFormatException numberFormatException){
log.error("----");
log.error(numberFormatException.getMessage());
return "NUMBER FORMAT EXCEPTION"
}
}
@ExceptionHandler가 지정되어 있고 NumberFormatException타입을 지정하고 있습니다. @ExceptionHandler를 가진 모든 메소드는 해당 타입의 예외를 파라미터로 전달받을 수 있습니다.
@ResponseBody를 이용해서 만들어진 문자열을 그대로 전송하는 방식을 사용했습니다. 예외가 발생하더라도 다른 결과가 나옵니다.
404 에러 페이지와 @ResponseStatus
서버 내부에서 생긴 문제가 아니라 잘못된 URL을 호출하면 404 예외가 발생합니다.
@ControllerAdvice에 작성하는 메소드에 @ResponseStatus를 이용하면 404상태에 맞는 화면을 별도로 작성할 수 있습니다.
@ExceptionHandler(NoHandlerFoundException.class)
@ResponseStatus(HttpStatus.NOT_Found)
public String notFound(){
return "custom404";
}
custom404.jsp파일을 추가합니다.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Oops! 페이지를 찾을 수 없습니다!</h1>
</body>
</html>
존재하지 않는 경로에 접근하면 기존과 다르게 custom404.jsp의 결과를 볼 수 있습니다.
'자바웹개발 워크북' 카테고리의 다른 글
자바웹개발 워크북(6) (1) | 2025.01.20 |
---|---|
자바웹개발 워크북(5) (0) | 2025.01.16 |
자바웹개발 워크북(3) (0) | 2025.01.02 |
자바웹개발 워크북(2) (0) | 2025.01.01 |
자바웹개발 워크북(1) (1) | 2024.12.30 |