이전에는 스프링 3.X와 4.X 버전을 사용하였다.
오늘부터는 5.X 버전에 대해서 살짝 다뤄보았다.
사용하는 버전은 아래와 같다.
JDK 1.8
STS3
Tomcat 8.5.x
Oracle 11g XE
참고)
스프링 5.X 최소 JDK 1.8
스프링 4.X 최소 JDK.1.6
스프링 3.X 최소 JDK 1.5
(SP코딩단의 코드로 배우는 스프링 웹 프로젝트(개정판) 교재를 참고하였습니다)
1. 스프링 프로젝트 생성(p30)
1) File - New - Legacy Progject로 프로젝트 생성하기
> 프로젝트명 : ex00
> top-level : org.zerock.controller
*** 프로젝트 생성 시 에러 발생 : 이클립스 종료 후 현재 사용자 폴더 내에 있는 .m2 밑에 repository 폴더의 내용물을 삭제해야 한다. 이후 이클립스를 재시작하면 자동으로 생성된 프로젝트를 점검하면서 아래와 같이 관련 라이브러리를 다운 받음
2) pom.xml
Java 버전은 1.8로 수정 Spring 버전은 5.0.7로 수정

141, 142라인의 Java 버전도 1.8로 수정

프로젝트 우클릭 -> Maven -> Update Project 클릭 후 프로젝트의 Java 버전이 1.8로 바뀌었는지 확인하기

여기까지 설정이 완료되었다면 Tomcat을 이용하여 프로젝트 실행 확인을 해보자
프로젝트 우클릭 -> Run As -> Run On Server 클릭하면 home.jsp가 보이는지 확인해보자

2. Lombox 라이브러리 설치(p38)
- Lombok이란?
Java 개발 시 자주 사용하는VO|DTO의 getter/setter, toString(), 생성자 등을 자동생성 해주는 것
아래 링크를 통해서 다운로드 받기
https://projectlombok.org/download
(주의) 실행된 이클립스 또는 STS는 종료한 후에 실행(설치)하자
cmd(명령프롬프트) 우클릭하여 관리자 권한으로 실행 후 lombok.jar 파일이 있는 곳으로 경로 이동

java -jar lombok.jar 명령어를 실행하여 설치

lombok을 설치할 이클립스나 STS 선택 후 Install/Update 클릭

Install successful이 보이면 Quit Installer 클릭하여 창 나가기

STS와 이클립스 폴더에 lombok.jar 파일이 생성되어진 것을 확인한 후 기존에 있던 바탕화면의 바로가기는 삭제 후 바탕화면의 바로가기를 다시 만들자
3. 스프링의 특징과 의존성 주입(p47 Chapter02)
1) 스프링의 역사 중 가장 눈에 띄는 변화들(p49)
- Spring 2.5 : 어노테이션 도입
- Spring 3.0 : Java 클래스 설정 파일 지원
- Spring 4.0 : 모바일 환경 + 웹 환경에서 많이 사용하는 REST 방식의 컨트롤러 지원
* REST 방식이란? 대표적으로 AJAX 처리
-Spring 5.0 : Reactor 이용한 개발 지원
2) 스프링의 주요 특징(p50)
- POJO(Plain Old Java Object) 기반의 구성 : 일반적인 Java 코드를 이용해서 객체를 구성하는 방식을 그대로 스프링에서 사용할 수 있다는 것
참고) 스프링에서 생성된 객체 : 스프링 빈
Java 객체 : POJO
- 의존성 주입(DI)을 통한 객체 간의 관계 구성
* 빈과 빈 사이의 의존관계를 처리하는 방식으로는 XML 설정, 어노테이션 설정, Java 설정 방식이 있음

- AOP 지원(반복적인 코드 제거)
- 트랜잭션의 지원
* 스프링은 트랜잭션의 관리를 어노테이션이나 XML로 설정할 수 있음
- 편리한 MVC 구조
- WAS의 종속적이지 않은 개발 환경
3) 의존성 주입 테스트(p53)
2번에서 lombok 라이브러리를 설치하고 설정하는 작업을 하였으니 바로 다음 설정부터 정리하겠다.
- pom.xml에 junit 버전 수정하기
: 스프링 4.X 이상의 버전을 테스트하기 위해서는 반드시 jUnit의 버전은 4.10 이상이어야 하므로 4.12로 수정

- org.zerock.sample 패키지 생성 후 Chef와 Restaurant 클래스 생성
> Resraurant 객체는 Chef 객체가 필요하므로 의존 주입을 해줄 것이다.
Chef 클래스에는 @Component 애노테이션 추가(컴포넌트 스캔 기능 사용)
@ToString 애노테이션과 @AllArgsConstructor 애노테이션으로 자동으로 toString() 메서드와 생성자를 생성해준다. 만약, Chef 클래스 안에 멤버 변수가 있었다면 변수를 받는 생성자로 작성하게 된다.
@Getter와 @Setter를 이용하면 자동으로 getter/setter도 생성할 수 있다.


Restaurant 클래스에는 @Component와 @Data 어노테이션을 추가해준다.
@Data 어노테이션으로 getter/setter, 생성자, toString 등 기본적으로 오버라이딩 하는 메서드를 전부 생성해준다.
onMethod 속성을 이용해서 작성된 setter에 @Autowired 어노테이션을 추가 => lombok으로 setter를 만들고 스프링은 setter 주입을 이용


이제 xml을 이용하여 의존성 주입을 설정해주도록 하자
root-context.xml 파일에 Namespaces에서 context 추가 후
<context:component-scan> 태그로 컴포넌트 스캔 기능 사용할 수 있도록 설정을 해주자


* Beans Graph 탭을 클릭하면 생성되는 빈 객체들을 확인할 수 있다.

* 스프링이 동작하면서 생기는 일
위에서 작성한 Chef와 Restaurant 클래스와 root-context.xml이 어떻게 동작하는지 순서대로 설명하면 다음과 같다.

1) 스프링은 프레임워크가 시작되면 먼저 스프링이 사용하는 메모리 영역을 만들고 이를 컨텍스트(context)라고 한다.
스프링에서는 ApplicationContext라는 이름의 객체가 만들어진다.
2) 스프링은 자신이 객체를 생성하고 관리해야 하는 객체들에 대한 설정이 필요하므로 이에 대한 설정을 하는 파일이 root-context.xml 파일이다.
3) root-context.xml에 설정되어 있는 <context:component-sacn> 태그의 내용을 통해서 org.zerock.sample 패키지를 스캔(scan)하기 시작
4) 해당 패키지에 있는 클래스들 중에서 스프링이 사용하는 @Component라는 어노테이션이 존재하는 클래스의 인스턴스를 생성
5) Restaurant 객체는 Chef 객체가 필요하다는 @Autowried 어노테이션 설정이 있으므로, 스프링은 Chef 객체의 레퍼런스를 Restaurant 객체에 의존 주입을 해준다.
이제 위와 같은 과정이 잘 동작하는지 확인하기 위해서 테스트 코드를 작성하여 확인해보자
4) 테스트 코드를 통한 확인(p60)
src/test/java 폴더 내에 org.zerock.sample 클래스 추가
패키지 우클릭 -> New -> JUnit Test Case 클릭하여 SamleTests 이름으로 생성하기

SampleTests.java 파일을 설명하자면..
테스트 코드는 우선 현재 테스트 코드가 스프링을 실행하는 역할을 할 것이라는 것을 @Runwith 어노테이션으로 표시를 한다.
그 다음으로 @ContextConfiguration 어노테이션과 속성값인 문자열 설정인데
@ContextConfiguration 어노테이션은 지정된 클래스나 문자열을 이용해서 필요한 객체들을 스프링 내에 객체로 등록하게 된다(스프링 빈 등록)
@ContextConfiguration 어노테이션에 사용하는 문자열은 'classpath:'나 'file:'을 이용할 수 있으며, 이클립스에서 자동으로 생성된 root-context.xml 파일의 경로를 지정할 수 있다.
@Log4j 어노테이션은 Lombok을 이용해서 로그를 기록하는 Logger를 변수로 생성한다.
별도의 Logger 객체의 선언이 없이도 Log4j 라이브러리와 설정이 존대한다면 바로 사용할 수 있다.
Spring Legacy Project로 생성하는 경우 기본으로 Log4j와 해당 설정이 완료되는 상태이므로 별도의 처리 없이 사용이 가능하다. 로그에 대한 설정은 src/main/resources와 src/test/resources에 별도로 존재한다.
assertNotNull()은 restaurant 변수가 null이 아니어아먄 테스트가 성공한다는 것을 의미한다.
이제 해당 테스트 파일 우클릭 후 Run As > Junit Test를 실행하여 테스트 결과를 확인하자


4. 스프링과 Oracle Database 연동(p71 Chapter03)
오라클에서 새로운 계정을 만들지 않고 scott 계정을 사용할 것이다.
과거에는 오라클이 8080 포트 사용해서 Server가 충돌이 나서 Tomcat 서버의 포트 번호를 80이나 7080 등으로 변경했었다.
☞ 오라클의 포트 번호 변경(p77)을 쿼리로도 할 수 있다.
sql 디벨로퍼를 띄우고 아래 쿼리를 작성하면 된다.
현재 사용하고 있는 포트 확인하는 쿼리 : SELECT dbms_xdb.gethttpport() FROM dual;
포트를 9090으로 변경하는 쿼리 : EXEC dbms_xdb.sethttpprot(9090);
본인은 쿼리로 포트를 변경하지 않고 Tomcat 서버의 포트 번호를 7080으로 변경하여 사용하겠다.
1) ojdbc6.jar 설정(p79) 후 JDBC 테스트하기(p81)
(이전에는 mvn.exe ojdbc6.jar -> install하여 로컬저장소에 저장한 후 pom.xml에 <dependency> 태그로 설정하였음)
- 패키지 우클릭 -> Build Path -> Configure Build Path -> Libraries 탭 클릭

- Deployment Assembly -> Add 클릭 -> Java Build Path Entries에서 위에서 추가한 ojdbc6.jar 파일 선택 후 Apply and Close 클릭

☞ JDBC 테스트 코드
- src/test/java에 org.zerock.persistence 패키지 생성 후 JUnit Test Case로 JDBCTests.java 생성
JDBCTests.java에 Java와 JDBC 드라이버만으로 구현해서 먼저 테스트를 할 것이다.
DB 연결이 가능하다면 정상적으로 데이터베이스가 연결된 Conntection 객체가 출력될 것이다.


2) 커넥션 풀(Conntection Pool) 설정(p83) - HikariCP
여러 명의 사용자를 동시에 처리해야 하는 웹 애플리케이션의 경우 DB 연결을 이용할 때는 '커넥션 풀'을 이용하므로, 스프링에 아예 커넥션 풀을 등록해서 사용하는 것이 좋다.
Java에서는 DataSource라는 인터페이스를 통해서 커넥션 풀을 사용한다. DataSource를 통해 매번 DB와 연결하는 방식이 아닌 미리 연결을 맺어주고 반환하는 구조를 이용하여 성능 향상을 한다.
커넥션 풀에는 여러 종류가 있고, spring-jdbc 라이브러리를 이용하는 방식오 있지만 교재에서는 최신 유행하는 HikariCP를 사용하고 있어 따라서 사용해보도록 하겠다.
☞ pom.xml에서 HikariCP를 추가

☞ root-context.xml에 빈 객체 생성 + DataSource 생성

위와 같은 설정으로 스프링이 시작되면 root-context.xml을 읽어서 아래와 같은 형태로 id가 dataSource인 객체가 처리된다.

☞ HikariCP에서 DataSource를 얻어와지는지 테스트를 해보자!
- src/test/java 폴더 안에 org.zerock.persistence 패키지 안에 JUnit Test Case로 DataSourceTests.java 생성 후 아래와 같이 코딩한다.
테스트 코드는 스프링에 빈으로 등록된 DataSource를 이용해서 Connection을 제대로 처리할 수 있는지 확인해보는 용도이다. testConnection()을 실행해 보면 내부적으로 HikariCP가 시작되고, 종료되는 로그를 확인할 수 있다.


5. MyBatis와 스프링 연동(Chapter04 p89)
이전에도 MyBatis에 대해서 배웠지만 교재에서 정리된 내용이 있어 포함하도록 하겠다.

MyBatis는 기존의 SQL을 그대로 활용할 수 있다는 장점이 있고, 진입장벽이 낮은 편이어서 JDBC의 대안으로 많이 사용한다. 스프링 프레임워크의 특징 중 하나는 다른 프레임워크들을 배척하는 대신에 다른 프레임워크들과의 연동을 쉽게하는 추가적인 라이브러리들이 많다는 것이다.
MyBatis 역시 mybatis-spring이라는 라이브러리를 통해서 쉽겨 연동작업을 처리할 수 있다.

☞ pom.xml에 MyBatis 관련 라이브러리 4개 추가
spring-jdbc와 spring-tx 라이브러리는 스프링에서 데이터베이서 처리와 트랜잭션 처리와 관련된 라이브러리이며, mybatis와 mybatis-spring 라이브러리는 MyBatis와 스프링 연동용 라이브러리이다.
(spring-jdbc와 spring-tx는 mybaits와 연관이 없어보이지만 라이브러리를 추가하지 않으면 에러가 발생하니 꼭 추가해주자)

☞ root-context.xml에 sqlSessionFactory 빈 객체 등록
MyBatis에서 가장 핵심적인 객체는 SQLSession과 SQLSessionFactory이다.
SQLSessionFactory는 SQLSession을 만들어 주고 개발에서는 SQLSession을 통해서 Connection을 생성하거나 SQL을 전달하고 결과를 리턴 받는 구조로 작성하게 된다.

스프링에 SqlSessionFactory를 등록하는 작업은 SqlSessionFactoryBean을 이용한다.
패키지명을 살펴보면 MyBatis의 패키지가 아니라 스프링과 연동 작업을 처리하는 mybatis-spring 라이브러리의 클래스인 것을 알 수 있다.
☞ DataSourceTests에 추가하여 SqlSession 테스트하기
testMyBatis()는 설정된 SqlSessionFactory 인터페이스 타입의 SqlSessionFactoryBean을 이용해서 생성하고, 이를 이용해서 Connection까지 테스트를 한다.


5-2. 스프링과의 연동처리(p93) - Mapper
SQLSessionFactory를 이용해서 코드를 작성해도 직접 Connection을 얻어서 JDBC 코딩이 가능하지만, 좀 더 편하게 작업하기 위해서는 SQL을 어떻게 처리할 것인지를 별도의 설정을 분리해 주고, 자동으로 처리되는 방식을 이용하는 것이 좋다. 이를 위해서는 MyBatis의 Mapper라는 존재를 작성해 주어야 한다.
Mapper는 쉽게 SQL과 그에 대한 처리를 지정하는 역할을 한다.
MyBatis-Spring을 이용하는 경우에는 Mapper를 XML과 인터페이스 + 어노테이션의 형태로 작성할 수 있다.
☞ Mapper 인터페이스
Mapper를 작성하는 작업은 XML도 가능하지만 여기서는 Mapper 인터페이스를 사용해보겠다.
src/main/java 폴더 안에 org.zerock.mapper 패키지 생성 후 TimeMapper 인터페이스 생성
(@Select 애노테이션을 사용하기 때문에 Mapper.xml 파일이 필요하지 않음)
* getTimeXML은 다음에 설명할 매퍼 xml 파일 사용할 때 사용할 예정

☞ Mapper 설정
MyBatis가 동작할 때 Mapper를 인식할 수 있도록 root-context.xml 추가적인 설정이 필요하다.
root-context.xml 파일에서 Namespaces 탭에서 mybatis 체크 한 뒤 source 탭 클릭하여 <mybatis-spring:scan> 태그를 추가해주자

<mybatis-spring:scan> 태그의 base-package 속성은 지정된 패키지의 모든 MyBatis 관련 어노테이션을 찾아 처리한다. Mapper를 설정하는 작업은 각각의 XML이나 Mapper 인터페이스를 설정할 수도 있지만, 매번 그러면 번거롭고 번잡하기 때문에 아래와 같이 설정하였다.

☞ Mapper 테스트해보기
src/test/java 폴더 안에 org.zerock.persistence 패키지 안에 JUnit Test Case로 TimeMapperTests.java 생성 후 아래와 같이 코딩해준다.
해당 테스트 클래스는 TimeMapper가 정상적으로 사용이 가능한지를 알아보기 위한 테스트 코드이다.
아래 코드가 정상적으로 동작한다면 스프링 내부에는 TimeMapper 타입으로 만들어진 스프링 빈 객체가 존재한다는 뜻이 된다.
timeMapper.getClass().getName()은 실제 동작하는 클래스의 이름을 확인해 준다. 실행 결과를 보면 인터페이스만 만들어 주었는데도 내부적으로 적당한 클래스가 만들어진 것을 확인할 수 있다.


☞ 매퍼 XML 파일을 같이 사용하기(p98) - 유지, 보수, 확장이 편리함
MyBatis를 이용해서 SQL을 처리할 때 어노테이션을 이용하는 방식이 훨 편리하지만, SQL이 복잡해지거나 길어지는 경우에는 어노테이션 보다는 XML을 이용하는 방식이 좋다.
MyBatis-Spring의 경우 Mapper 인터페이스와 XML을 동시에 사용할 수 있다.
XML을 작성해서 사용할 때에는 XML 파일의 위치와 XML 파일에 지정하는 namespace 속성이 중요하다.
XML 파일 위치의 경우 Mapper 인터페이스가 있는 곳에 같이 작성하거나 src/main/resources 구조에 XML을 저장할 폴더를 생성할 수 있다.
XML 파일 이름에 대한 규칙은 지정된 것은 없으나 가능하다면 Mapper 인터페이스와 같은 이름을 이용하는 것이 가독성을 높여준다.
본인은 src/main/resource 폴더 안에 아래와 같이 폴더를 생성하여 xml 파일을 추가하도록 하겠다.
src/main/resource 폴더 안에 org/zerock/mapper 폴더 추가 :
org 폴더 생성 -> zerock 폴더 생성 -> mapper 폴더 생성 -> TimeMapper.xml 매퍼 xml 파일 추가

TimeMapper 인터페이스에 getTimeXML()을 추가해주자
SQL은 XML을 이용해서 처리할 것이기 때문에 해당 메서드에는 어노테이션이 필요하지 않다.

xml 파일에는 MyBatis의 XML 매퍼에서 이용하는 태그에 대한 설정이 필요하다.
(자세한 내용은 http://www.mybatis.org/mybatis-3/ko/sqlmap-xml.html을 통해 확인하자)
TimeMapper.xml
XML 매퍼를 이용할 때 신경 써야 하는 부분은 <mapper> 태그의 namespace 속성값이다.
MyBatis는 Mapper 인터페이스와 XML을 인터페이스의 이름과 namespace 속성값을 가지고 판단한다.
아래와 같이 org.zerock.mapper.TimeMapper 인터페이스가 존재하고, XML의 <mapper namespace="org.zerock.mapper.TimeMapper">와 같이 동일한 이름이 존재하면 이를 병합해서 처리한다.
즉, 메서드 선언은 인터페이스에 존재하고 SQL에 대한 처리는 XML을 이용하는 방식이라고 할 수 있다.
SQL을 처리하는 태그의 id 속성 값은 인터페이스에 있는 메서드의 이름과 동일하게 맞춰야 한다. select 태그의 경우 resultType 속성을 가지는데 이 값은 인터페이스에 선언된 메서드의 리턴 타입과 동일하게 작성한다.

☞ TimeMapperTests에서 테스트해보기


5-3. log4jdbc-log4j2 설정(p101)
MyBatis는 내부적으로 JDBC의 PreparedStatement를 이용해서 SQL을 처리한다.
따라서 SQL에 전달되는 파라미터는 JDBC에서와 같이 '?'로 치환되어서 처리된다.
복잡한 SQL의 경우 '?'로 나오는 값이 제대로 되어있는지 확인하기가 쉽지 않고 실행된 SQL의 내용을 정확히 확인하기 어렵다. 이런 문제를 해결하기 위해서 SQL을 변환해서 PreparedStatement에 사용된 '?'가 어떤 값으로 처리되었는지 확인하는 기능을 추가하도록하자!
SQL 로그를 제대로 보기 위해서는 log4jdbc-log4j2 라이브러리를 사용해야한다.
☞ pom.xml에 라이브러리 추가

라이브러리를 추가한 후에는 1) 로그 설정 파일을 추가하는 작업과 2) JDBC의 연결 정보를 수정해야한다.
먼저, src/test/resources 폴더 안에 log4jdbc.log4j2.properties 파일 생성 후 아래와 같이 설정하자.
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

☞ root-context.xml 수정하기
log4jdbc를 이용하는 경우는 JDBC 드라이버와 URL 정보를 수정해야 한다.
root-context.xml의 일부를 수정하러가자!
dataSource() 메서드에서 변경되는 부분은
JDBC 드라이버의 클래스를 'net.sf.log4jdbc.sql.jdbcapi.DriverSpy'로 수정하는 작업과
JDBC 연결 URL 부분에서 중간에 'log4jdbc' 문자열이 추가되는 부분이다.

2) 로그의 레벨 설정하기
테스트 코드를 실행하면 상당히 많은 양의 로그가 출력되기 때문에 로그의 레벨을 이용해서 조금 수정해 줄 필요가 있다. 테스트 코드가 실행될 때의 로그와 관련된 설정은 src/test/resources 밑에 log4j.xml을 이용한다.(main에 있는 log4j.xml 아니다)
테스트 코드가 실행될 때 보여지는 INFO... 메시지는 log4j.xml의 마지막 부분에 있는 설정에 영향을 받기 때문이다.

만일 log4jdbc에서 출력되는 로그를 조절하고 싶다면 추가적인 <logger>를 지정해서 처리해준다.

기본 설정의 로그는 info 레벨이기 때문에 warn과 같이 좀 더 높은 레벨의 로그만 기록하게 수정하면 테스트 코드를 실행할 때 이전에 비해 로그의 양이 줄어드는 것을 확인할 수 있다.
TimeMapperTests 테스트 실행 결과

로그에 대한 자세한 설명은 아래 링크를 참조하자!
http://logging.apache.org/log4j/2.x/manual/customloglevels.html
'TIL > Spring' 카테고리의 다른 글
[TIL] Spring 5.0.7_기본적인 웹 게시물 관리 (0) | 2022.07.26 |
---|---|
[TIL] Spring MVC(Spring 5.0.7 버전) (0) | 2022.07.25 |
[SIST] Spring_days10_MyBatis (0) | 2022.07.22 |
[SIST] Spring_days09_Spring Security(스프링 시큐리티) (0) | 2022.07.21 |
[SIST] Spring_days09_SpringTiles 프로젝트를 옮겨서 STS툴로 STSMVC03 만들기 + root-context와 servlet-context로 사용 (0) | 2022.07.21 |