스프링으로 웹 프로젝트를 진행하면 스프링 MVC를 사용해서 진행하게 됩니다.
스프링 MVC는 모델 2 방식 구조를 이용합니다.
최근의 모든 웹 개발은 거의 모델 2 방식을 사용한다고 해도 과언이 아닙니다. 모델 2 방식은 흔히 MVC 구조를 응용한 방식이라고 하는데, 가장 핵심적인 내용은 '화면과 데이터 처리를 분리해서 재사용이 가능하도록 하는 구조' 라고 할 수 있습니다.
모델 2 구조에서는 다음과 같은 용어들이 사용됩니다.
Model : 데이터 혹은 데이터를 처리하는 영역을 의미합니다.
View : 결과 화면을 만들어 내는 데 사용하는 자원을 의미합니다.
Controller : 웹의 Request를 처리하는 존재로 뷰와 모델 사이의 중간 통신 역할을 합니다.
컨트롤러는 모델 계층과 연동해서 필요한 데이터를 처리하고, 결과를 전송하게 됩니다.
모델 2에서 모든 요청은 기본적으로 컨트롤러를 호출합니다. 각 컨트롤러는 자신을 호출하는 특정한 URI 경로를 가지고 있습니다. 과거에는 주로 호출 시에 마지막 확장자를 '*.do' 등을 이용하는 방식을 많이 사용했습니다.
모델 2 방식은 1)개발자와 웹 퍼블리셔의 영역을 분리할 수 있으며, 2) 컨트롤러의 URI를 통해서 뷰를 제어하기 때문에, 뷰의 교체나 변경과 같은 유지보수에 유용하게 사용될 수 있습니다.
모델 2에서 Front Controller 패턴으로 간 이유는 각 컨트롤러 사이의 중복적인 코드의 문제와 개발자의 개발 패턴의 차이 등의 문제로 인해 모델 2 방식은 좀 더 강제적인 형태인 Front Controller 방식을 적용하게 됩니다.
Front Controller 패턴의 가장 중요한 변화는 전체 로직의 일부만을 컨트롤러가 처리하도록 변경되었다는 점입니다.
위임(Delegation)이라고 하는데, 전체 로직의 일부를 컨트롤러에게 위임하고 모든 흐름의 제어는 앞쪽의 Front Controller가 담당하게 됩니다.
위와 같은 구조를 사용하게 될 경우 개발자가 작성하는 컨트롤러는 전체 로직의 일부분만을 처리하는 형태가 되기 때문에 개발자가 작성해야 하는 전체 코드는 줄어들게 됩니다. 또한, 모든 컨트롤러는 Front Controller의 일부분을 구현하는 형태이므로, 좀 더 규격화된 코드를 작성하게 됩니다.
(1)스프링 MVC의 구조 사용자의 모든 요청은 스프링 MVC의 Front Controller에게 전달됩니다.
(2) 전달된 요청은 적절한 컨트롤러를 찾아서 호출하게 되는데
(3)이때 사용되는 컨트롤러의 작업이 개발자의 몫으로 남겨진 일입니다. 컨트롤러는 적절한 서비스 객체를 찾아서 호출하고, 서비스는 데이터베이스의 작업을 담당하는 DAO(Data Access Object)를 이용해서 원하는 데이터를 요청하게 됩니다.
(4) DAO 객체는 MyBatis를 이용하는 Mapper를 통해서 원하는 작업을 수행하게 됩니다.
(5) 서비스가 처리한 데이터를 컨트롤러에게 전달하게 되면
(6,7) 컨트롤러는 다시 스프링 MVC 쪽으로 데이터를 전달하게 됩니다.
스프링 MVC가 처리해주는 작업
1. URI를 분석해서 적절한 컨트롤러를 찾는 작업
2. 컨트롤러에 필요한 메소드를 호출하는 작업
3. 컨트롤러의 결과 데이터를 뷰로 전달하는 작업
4. 적절한 뷰를 찾는 작업
개발자가 직접 해야 하는 작업
1. 특정 URI에 동작하는 컨트롤러를 설계하는 작업
2. 서비스 객체의 생성
3. DAO 객체의 생성
4. 컨트롤러 내에 원하는 결과를 메소드로 설계
5. 뷰에서 전달받은 데이터의 출력
스프링 MVC를 사용하면 개발의 전체 흐름은 개발자가 제어하지 않고 개발자는 필요한 부품을 끼워 넣는 형태의 작업을 하게 됩니다. 스프링 MVC의 경우네는 이 부품이 컨트롤러가 됩니다.
스프링 MVC의 컨트롤러 를 어떻게 만들고, 처리하는가 ? 무엇을 처리해주는가 ?
파라미터의 수집 : 웹에서 가장 많이 하는 작업은 사용자의 요청(request)에 필요한 데이터를 추출하고, 이를 VO(Value Object) 혹은 DTO(Data Tansfer Object)로 변환하는 파라미터의 수집 작업입니다. 스프링 MVC의 컨트롤러는 이러한 처리를 자동으로 해주기 떄문에 개발 시간을 크게 단축 할 수 있습니다.
애노테이션을 통한 간편 설정 : 스프링 MVC의 설정은 크게 XML과 애노테이션을 사용할 수 있지만, 애노테이션을 사용하는 경우가 더 많습니다. 애노테이션을 사용하기 때문에 개발자는 클래스나 메소드의 선언에 필요한 애노테이션을 추가하는 작업을 통해서 요청(request)이나 응답(response)에 필요한 모든 처리를 완료할 수 있습니다.
로직의 집중 : 기존 모델 2는 특정한 URI마다 컨트롤러를 개발하는 경우가 많았지만 스프링 MVC 컨트롤러의 경우 각 메소드마다 필요한 애노테이션을 설정할 수 있기 때문에 여러 메소드를 하나의 컨트롤러에 집중해서 작성할 수 있습니다.
테스트의 편리함 : 스프링은 테스트 모듈을 사용해서 스프링 MVC로 작성된 코드를 WAS의 실행 없이도 테스트할 수 있는 편리한 방법을 제공합니다.
스프링 MVC 컨트롤러는 상속이나 인터페이스를 구현 하지 않아도 됩니다.
기존의 프레임워크들과는 달리 스프링 MVC에서는 컨트롤러 작성 시 아무런 제약이 없습니다. 그대신 해야 하는 작업은 '@Controller'라는 애노테이션에 대한 추가 작업입니다.
메소드의 파라미터와 리턴 타입에 대한 제약이 없습니다. 클래스가 특정 부모 클래스나 인터페이스가 없으니 메소드에 대한 제약도 존재하지 않습니다. 파라미터 타입과 리턴타입에 대한 제약이 없는 관계로 기존보다 훨씬 자유로운 코드를 만들어낼 수 있습니다.
스프링 MVC가 제공하는 유용한 클래스들이 존재합니다. 스프링 MVC의 경우 다양한 클래스를 이용해서 필요한 작업을 수월하게 진행할 수 있습니다. 예를 들어 파일 업로드 처리나 유호성 검사 등을 제공하고 있기 때문에 개발자는 필요한 클래스를 이용해서 빠른 시간 내에 개발할 수 있습니다.
Spring Project의 servlet-context.xml파일은 appServlet 폴더 내에 존재하며 스프링 MVC관련 설정만을 분리하기 위해서 만들어진 파일입니다.
<annotation-driven />
<resources mapping="/resources/**" location="/resources/" />
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.dogf.www" />
<annotation-driven />의 설정은 클래스 선언에 애노테이션을 이용해서 컨트롤러를 작성할 수 있다는 선업입니다.
InternalResourceViewResolver 부분은 뷰를 어떻게 처리하는가에 대한 설정입니다. 경로가 'WEB-INF/views/'라는 경로는 절대로 부라우저에서 직접 접근할 수 없는 경로이기 떄문에 컨트롤러의 호출이 우선되는 모델 2 방식에 맞는 구조가 됩니다.
<resources>는 웹에서 이미지나 CSS, JavaScript 파일과 같이 고정된 자원들의 위치를 의미합니다.
<component-scan> 의미도 상당히 중요하는 의미를 가지는데 component-scan은 base-package 속성값에 해당하는 패키지 내부의 클래스들을 조사한다는 뜻입니다. 이는 <anotation-driven>과 같이 결합해서 해당 패키지에 애노테이션 처리가 된 컨트롤러를 작성만 해주면 자동으로 인식되게 합니다.
스프링 MVC에서 주로 사용하는 애노테이션의 종류 @Controller : 컨트롤러 객체임을 명시 / @Repository : DAO 객체 / @Service : 서비스 객체 / @RequestMapping : 특정 URI에 매칭되는 클래스나 메소드임을 명시 / @RequestParam 요청(rquest)에서 특정한 파라미터의 값을 찾아낼 때 사용 / @ModelAttribute 자동으로 해당 객체를 뷰까지 전달 / @ResponseBody : 리턴 타입이 HTTP의 응답 메시지로 전송 / @RequestBody : 요청 (request) 문자열이 그대로 파라미터로 전달 @SessionAttribute : 세션상에서 모델의 정보를 유지하고 싶은 경우에 사용
프로젝트 생성 시 마지막 패키지의 이름이 경로가 된다.
메소드의 리턴 타입이 void인 경우에는 스프링 MVC는 현재 경로에 해당하는 JSP 파일을 실행하게 됩니다.
String이 리턴 타입인 경우에는 '문자열' + .jsp 파일을 찾아서 실행 하게 됩니다.
@ModelAttribute는 요청 시 이름의 파라미터를 문자열로 처리해 주고, 자동으로 해당 객체를 뷰까지 전달합니다.
이작업이 자동으로 이루어지기 때문에 개발자는 별도의 코드를 작성할 필요가 없습니다.
컨트롤러를 제작하면서 가장 많이 하는 작업은 다른 객체의 도움을 받아 만들어진 데이터를 뷰로 전달하는 일을 하는 것입니다. / 이때는 스프링 MVC의 Model 객체를 사용해서 간편하게 처리할 수 있습니다.
Model 클래스는 import 구문에서 보듯이 스프링 MVC에서 기본적으로 제공되는 클래스 입니다. 이 클래스의 용도는 뷰에 원하는 데이터를 전달하는 일종의 컨테이너나 상자의 역할을 한다고 생각하면 됩니다.
doD() 메소드의 내부에서 ProductVO 클래스의 객체를 하나 생성하는 것이 보입니다. 이 객체를 Model이라는 객체를 이용해서 필요한 데이터를 담은 후 뷰(jsp)로 전달하게 됩니다.
AoVO클래스의 객체 생성 이후에 addAttribute() 라는 메소드를 이용해서 AoVO 객체를 보관 시킬 수 있습니다. addAttribute()는 크게 두 가지 형태로 사용합니다.
addAttribute("이름", 객체): 객체에 특별한 이름을 부여해 뷰에서 이름값을 이용하여 객체 처리를 한다.
addAttribute(객체): 이름을 지정하지 않는 경우에는 자동으로 저장되는 객체의 클래스명 앞 글자를 소문자로 처리한 클래스 명을 이름으로 간주할 수 있다.
위 코드의 경우라면 AoVO를 이름 없이 저장했기 때문에 뷰에서의 이름은 aoVO가 됩니다.
리다이렉트를 해야 하는 경우 가끔은 특정한 컨트롤러의 로직을 처리할 때 다른 경로를 호출해야 하는 경우가 있습니다. 이 경우에는 스프링 MVC의 특별한 문자열인 'redirect:'를 이용하는데 ':'을 이용하는 것을 주의 할 필요가 있습니다.
리다이렉트를 하는 경우 RedirectAttributes라는 클래스를 파라미터로 같이 사용하게 되면 리다이렉트 시점에 원하는 데이터를 임시로 추가해서 넘기는 작업이 가능합니다.
메소드의 파라미터 선언에 RedirectAttributes를 파라미터로 사용하는 점을 주목할 필요가 있습니다.
메소드의 결과로 리다이렉트 시점에 문자열 정보를 하나 더 전달하고 싶었기 이름이 있는 데이터를 추가 했습니다. 이대 addFlashAttribute()는 임시 데이터를 전달합니다.
스프링 MVC의 장점 중 하나는 최근 프로그래밍에서 많이 사용되는 JSON(JavaScript Object Notation) 데이터에 대한 처리를 간단하게 처리할 수 있다는 것입니다. 이를 위해서는 pom.xml을 사용해서 jackson-databind 라이브러리를 추가해야합니다. 스프링 MVC의 컨트롤러에서 JSON 데이터를 생성하기 위해서 사용자는 적절한 객체를 반환해 주고, @ResponseBody 애노테이션을 추가해 주는 작업만 하면 됩니다.
메소드 선언에 사용된 리턴 타입에 @ResponseBody 애노테이션을 사용할 수 있는데 리턴 타입 역시 일반 객체로 넣을 수 있습니다. 메소드의 실행 결과로 객체를 리턴하고 있는대 이것만으로 JSON의 처리가 끝납니다.
실행된 결과를 보면 응답된 데이터가 application/json 타입으로 올바르게 처리되는 것을 확인 할 수 있습니다.
위의 URI를 실행할 때는 반드시 STS내에 내장된 브라우저가 아닌 일반 브라우저로 확인해야 합니다 STS 내장 브라우저의 경우 JSON 데이터를 처리할 수 없기 때문 자동으로 다운로드 하는 화면이 보여지게 됩니다.
WAS 없이 컨트롤러를 테스트 할 수 있습니다.
웹페이지를 테스트 하려면 매번 입력 항목을 입력해서 제대로 동작하는지를 확인하는데, 이때 여러 번 웹 페이지에서 입력하는 것보다 테스트 코드를 통해서 처리하는 것이 개발 시간을 훨씬 단축시킬 수 있습니다.
JSP 등에서 발생하는 에러를 해결하는 과정에서 매번 WAS에 ㅂ만들어진 컨트롤러 코드를 수정해서 배포하는 작업은 많은 시간을 소모하게 됩니다.
컨트롤러에서 결과 데이터만을 확인 할 수 있기 때문에 문제의 발생 시 원인을 파악 할 수 있는 시간이 절약됩니다.
XML만을 이용해서 SQL문을 설정, DAO에서는 XML을 찾아서 실행하는 코드를 작성하는 방식
장점 : SQL 문은 별도의 XML로 작성되기 떄문에 SQL문의 수정이나 유지보수에 적합하다.
단점 : 개발 시 코드의 양이 많아지고, 복잡성이 증가한다.
애노테이션과 인터페이스만을 이용해서 SQL문을 설정
장점 : 별도의 DAO없이도 개발이 가능하기 때문에 생산성이 크게 증가한다.
단점 : SQL문을 애노테이션으로 작성하므로, 매번 수정이 일어나는 경우 다시 컴파일 과정이 필요하다.
인터페이스와 XML로 작성된 SQL문의 활용
장점 : 간단한 SQL문은 애노테이션으로, 복잡한 SQL 문은 XML로 처리하므로, 상황에 따라서 유연하게 처리한다.
단점 : 개발자에 따라 개발 방식의 차이가 있을 수 있기 때문에, 유지보수가 중요한 프로젝트의 경우 부적합하다.
국내의 대부분 프로젝트는 XML만을 이용해서 SQL문을 작성하고, 별도의 DAO를 만드는 방식을 선호합니다. 이 방식의 최대 장점은 SQL문을 온전히 분리해서 처리하기 때문에, 향후에 SQL문의 변경이 일어날 떄, 대처가 수월하다는 점 입니다. MyBatis를 XML을 사용해서 작성하는 경우 코딩의 순서는 다음과 같습니다.
테이블 생성 및 개발 준비 > 테이블 생성 및 기타 데이터베이스 관련 설정 > 도메인 객체의 설계 및 클래스 작성 > DAO 인터페이스 작성 > 실행해야 하는 기능을 인터페이스로 정의 > XML Mapper의 생성과 SQL문 작성 > XML 작성 및 SQL 작성 > MyBatis에서 작성된 XML Mapper를 인식하도록 설정 > DAO 구현 > DAO 인터페이스를 구현한 클래스 작성 > 스프링 상에 DAO 등록 및 테스트
개발을 할 때 가장 중요한 용어가 될 만한 명사를 흔히 '도메인 (Domain)' 이라고 표현합니다.
MyBatis에서는 SQL문을 저장하는 존재를 Mapper라는 용어로 표현합니다. XML 작업 순서는 XML로 작성된 Mapper의 위치(저장 경로) 결정 > XML Mapper 파일을 작성하고 필요한 DTD 추가 > SQL 작성 순으로 진행됩니다.
XML로 작성되는 Mapper 파일의 경우 Java로 작성된 클래스와 경로를 분리해 주는 것이 유지보수에 있어서 필수적입니다. XML Mapper를 작성할 때는 namespace속성은 클래스의 패키지와 유사한 용도로, MyBatis내에서 원하는 SQL 문을 찾아서 실행할 때 동작합니다.
MyBatis가 동작하면 조금 전에 작성된 XML Mapper를 인식해야만 정상적인 동작이 가능하므로, 코드를 작성해야합니다.
변화된 설정의 핵심은 mapperLocations라는 속성을 추가하고 , 작성된 mappers 폴더 내에 어떤 폴더이건 관계없이 파일의 이름이 'Mapper.xml'로 끝나면 자동으로 인식하도록 설정하는 것입니다. DAO 인터페이스와 Mapper의 작성이 완료됐다면 실제 이를 구현하는 구현 클래스를 작성해야만 합니다. MyBatis에서 DAO를 이용하는 경우는 SqlSessionTemplate이라는 것을 이용해서 DAO를 구현하므로, 우선적으로 SqlSessionTemplate을 설정하는 작업부터 시작합니다.
DAO의 작업에서 가장 번거로운 작업은 데이터베이스와 연결을 맺고, 작업이 완료된 후에 연결을 close()하는 작업입니다. 다행 스럽게도 mybatis-spring 라이브러리에는 이것을 처리할 수 있는 SqlSessionTemplate이라는 클래스를 제공하므로, 이를 이용하면 개발자들이 직접 연결을 맺고, 정료하는 작업을 줄일 수 있습니다.
mybatis-spring에서 제공하는 SqlSessionTemplate은 / MyBatis의 SqlSession인터페이스를 구현한 클래스로 기본적인 트랜잭션의 관리나 쓰레드 처리의 안정성 등을 보장해 주고, 데이터베이스의 연결과 종료를 책임집니다.
SqlSessionTemplate은 SqlSessionFactory를 생성자로 주입해서 설정합니다.
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
<constructor-arg name = "sqlSessionFactory" ref="sqlSessionFactory" >
</constructor-arg>
</bean>
@Repository는 DAO를 스프링에 인식시키기 위해서 주로 사용합니다.
MyBatis의 SqlSession에는 SQL 문을 처리할 수 있는 다음과 같은 기능들이 존재합니다. 메소드의 이름에서 보듯이 insert, update, delete 등의 SQL 문 처리와 selectOne, selectList와 같이 select의 형태를 지원합니다.
DAOImpl이 @Repository 애노테이션이 설정되더라도 스프링에서 해당 패키지를 스캔하지 않으면 제대로 스프링의 빈으로 등록되지 못합니다. 이처리는 root-context.xml을 이용해서 아래와 같이 설정합니다.
<context:component-scan base-package="com.pcnrnd.persistence"></context:component-scan>
MyBatis의 #{ } 문법
XML Mapper를 사용하는 경우 가장 먼저 작업하는 내용은 DAO 인터페이스 입니다.
작성된 인터페이스의 메소드 이름을 기초로 XML Mapper를 작성합니다.
<insert id = "insertMember" >
insert into su_member (user_Id, user_Pw, user_Name, user_Birth, user_Gender, user_Email, user_Phone)
values(#{user_Id}, #{user_Pw}, #{user_Name}, #{user_Birth}, #{user_Gender}, #{user_Email}, #{user_Phone})
</insert>
작성된 XML Mapper는 parameterType은 생략한 채로 작성되었습니다.
MyBatis의 경우 기본적으로 PreparedStatement를 이용해서 처리됩니다. 개발자가 PreparedStatement에 들어가는 파라미터를 사용할 때는 '#{ }' 기호를 이용해서 처리합니다. '#{ }'는 다음과 같은 규칙으로 적용됩니다.
파라미터가 여러 속성을 가진 객체인 경우 '#{num}'은 getNum()혹은 setNum()을 의미합니다.
파라미터가 하나이고, 기본자료형이나 문자열인 경우 값이 그대로 전달됩니다.
파라미터가 Map 타입인 경우 '#{num}'은 Map 객체의 키 값이 'num'인 값을 찾습니다.
스프링의 경우 하나의 설정이 잘못된 경우에도 모든 동작이 실행되지 않기 때문에 단계마다 어떤 결과가 나와야 하는지를 명확히 알고 진행해야 합니다.
스프링을 처음 접하는 사람들이 고생하는 대부분은 설정과 관련된 에러입니다. 중간에 있는 테스트 코드는 처음에는 귀찮고 번잡스럽게 생각될 수 있지만 규모가 커지고, 여러명이 작업하는 경우에는 반드시 필요한 부분이므로 빠짐없이 테스트를 진행해 줘야 합니다.
'WebProgramming > SPRING' 카테고리의 다른 글
[New Lecture - Spring] 느슨한 결합력과 인터페이스 (0) | 2020.05.28 |
---|---|
[Spring Boot]2. 환경설정 (0) | 2020.05.19 |
[Spring Boot]1.Spring Boot? (0) | 2020.05.19 |
spring framework 정리 2 (0) | 2019.05.08 |
spring framework 정리 (0) | 2019.04.30 |
댓글