본문 바로가기
개발입문/SPRING 게시판 만들기

[SPRING] spring 환경 구축

by 양히◡̈ 2022. 10. 12.

STS 설치 후 셋팅방법

* STS설치 후 실행하기 전에 sts.ini 파일 우클릭 편집 > JAVA VERSION을 1.8로 수정한다.

* Tomcat 서버를 등록한 후, 언어셋(encoding)은 utf-8로 설정한다.

새로운 프로젝트 생성

file > new > new Spring Legacy Project 생성 > name: prac3 > Spring MVC Project 지정

next 클릭 후, package 명은 "kr.icia.controller"로 입력

 

 

pom.xml 셋팅 (의존성 관리)

1) 자바와 스프링 버전을 변경한다.

2) dependency 셋팅 : 아래 사이트에서 아래 코드를 복사하여 pom.xml에 붙여넣는다.

스프링 저장소 ▶ Maven Repository: spring (mvnrepository.com)

- apache log4j (기존 dependency 덮어씌움)

- lombok

- HikariCP //커넥션풀

- mybatis //SQL매핑 프레임워크로, 쿼리문 작성의 간편함을 제공함 ▶ MyBatis – 마이바티스 3 | 소개

- mybatis-spring

- spring-tx

- spring-jdbc

- spring-test

- ojdbc8 //오라클 데이터베이스. 기존에는 build path에 등록되어 있었지만, dependency 형태로 변경이 가능해짐.

 

 

lombok 설치

lombok은 의존성을 추가했지만, 별도로 jar도 다운로드 해야한다.

 

Download

 

projectlombok.org

사이트에 들어가 다운로드하고 실행하여 설치한다.
프로젝트로 돌아와서 maven dependencies > lombok.kar 우클릭 후 run as java application 으로 구동한다.

 

 

 

root-context.html 에 bean 셋팅

src > main > webapp > WEB-INF > spring > root-context.xml 파일을 연다.

아래 탭의 [Namespaces] 를 눌러 나오는 화면에서 다음 사진과 같이 체크한다.

기존 내용의 코드에서 <!-- Root Context: defines shared resources visible to all other web components --> 주석 아래에 추가로 <bean>을 입력한다. 총 3개의 bean과 mybatis 태그가 추가된다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- Root Context: defines shared resources visible to all other web components -->
	<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
		<property name="driverClassName"
			value="oracle.jdbc.driver.OracleDriver">
		</property>
		<property name="jdbcUrl"
			value="jdbc:oracle:thin:@Localhost:1521:XE"></property>
		<property name="username" value="admin"></property>
		<property name="password" value="1234"></property>
	</bean>
	
	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
		<constructor-arg ref="hikariConfig"></constructor-arg>
	</bean>
	
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<mybatis-spring:scan base-package="kr.icia.mapper" />
</beans>

 

 

Mapper Interface 생성하기

인터페이스를 이용해 쿼리문을 동작할 것이다.

src/main/java 우클릭하여 new Interface 생성 > package: kr.icia.mapper / name: TimeMapper.java

package kr.icia.mapper;

import org.apache.ibatis.annotations.Select;

public interface TimeMapper {

	@Select("select sysdate from dual")
	public String getTime();
}

 

@Select

mybatis의 어노테이션으로, 데이터 검색과 관련된 쿼리를 사용하겠다는 의미.

getTime()을 호출하면 쿼리를 담아서 오라클에 전달하고, 그 결과를 호출한 곳으로 리턴한다

(MyBatis를 동작할 때 Mapper를 인식할 수 있도록 root-context.xml의 Namespaces에서 mybatis-spring을 체크해주어야 하는데, 이미 이전에 root-context.xml의 코드를 작성하면서 체크해두었다.)

스프링 프레임워크의 장점은, 이러한 인터페이스를 생성하기만 하면 인터페이스를 implements 받는 클래스를 생성하고, 몸체를 구현하는 번거로운 작업을 대신 자동으로 처리한다.

 

 

이제, 작성한 TimeMapper를 테스트하기 위한 클래스를 만들 것이다.

> src/test/java 우클릭하여 new Class 생성 > package: kr.icia.persistence / name: TimeMapperTests

package kr.icia.persistence;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import kr.icia.mapper.TimeMapper;
import lombok.Setter;
import lombok.extern.java.Log;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j   //아래 클래스 파일을 처리하면서 로그가 발생되면 log4j를 이용하겠다는 의미
public class TimeMapperTests {
	@Setter(onMethod_ = @Autowired)
	private TimeMapper timeMapper;
	
	@Test
	public void testGetTime() {
		log.info(timeMapper.getTime());
	}
}

* import는 기존 자바처럼 Ctrl + Shift + O 로 자동 생성 가능하다.

 

@log4j

아래 클래스 파일을 처리하면서 로그가 발생되면 log4j를 이용하겠다는 의미

TimeMapperTests

테스트 클래스에서는 jUnit4와 xml 설정값을 가져와서 테스트, 그러므로 @RunWith와 @ContextConiguration은 테스트 코드에 따라 붙는 규칙이 있다.

@가 붙는 부분은 어노테이션이라고 한다. 단순 주석이 아니라 컴파일러에게 보내는 sign.

@Setter(onMethod_ = @Autowired)

set000 메소드를 자동으로 만들어준다

@Autowired

필드를 초기화할 객체를 자동으로 연결시켜준다

@Test

이 메소드는 테스트용임을 알려준다

 

 

더보기

@RunWith
@ContextConfigyration
어노테이션 자동 Import가 안 되는 오류

 

코드를 작성했을 때, 위의 두 어노테이션에 빨간 밑줄이 뜨면서 Ctrl+Shift+O 에도 자동으로 임포트 되지 않으며 Problems 에 아래와 같은 오류메세지가 떴다.

여기서 예상되는 오류는 의존성 추가가 반영이 잘 안 되었을 경우로 생각해볼 수 있다.

아래 절차대로 진행하여 이 문제를 해결하였다.

상단탭 Project > Clean...

 

프로젝트 우클릭 > Maven > Update Project...

 

 

TimeMapperTests 빈 부분에서 마우스 우클릭 > Run As > 2. jUnit Test 클릭

INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.event.ApplicationEventsTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@49fc609f, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@cd2dae5, org.springframework.test.context.event.ApplicationEventsTestExecutionListener@3a883ce7, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@4973813a, org.springframework.test.context.support.DirtiesContextTestExecutionListener@6321e813, org.springframework.test.context.transaction.TransactionalTestExecutionListener@79be0360, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@22a67b4, org.springframework.test.context.event.EventPublishingTestExecutionListener@57855c9a]
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
WARN : com.zaxxer.hikari.util.DriverDataSource - Registered driver with driverClassName=oracle.jdbc.driver.OracleDriver was not found, trying direct instantiation.
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
INFO : kr.icia.persistence.TimeMapperTests - 2021-10-20 13:36:04
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.

실행시 다음과 같은 로그가 콘솔에 나타난다.

 

 
더보기

JUnit Test시 에러발생

 

이번에는 JUnit 테스트를 해보았을 때 다음과 같이 에러가 발생했다.

Caused by 부분을 살펴보니, JUnit 4.12 이상 버전이 필요하다는 내용이다.

 

이를 해결하기 위해, pom.xml 에서 junit의 버전을 4.12로 바꾸어 주면 된다.

 

pom.xml 에서 "junit" 검색 <version>을 4.12로 변경

 

 

 

MyBatis를 이용해서 SQL을 처리할 때 어노테이션을 이용하는 방법이 편리하기는 하지만 SQL이 길어지는 경우 가독성이 떨어질 수 있다.

그래서 MyBatis-spring에서는 XML과 혼합하여 사용하는 방법이 선호되고 있다.

 

 

TimeMapper XML 생성하기

XML에 mybatis 쿼리를 만들고, 인터페이스에 매핑되는 메소드를 만들고, 테스트에서 해당 메소드를 호출하는 과정을 거칠 것이다.

아래와 같이 먼저 폴더를 생성하고, 그 만들어진 폴더에 Mapper.xml파일을 생성한다.

src/main/resource > new folder > kr/icia/mapper

kr/icia/mapper > new xml file 생성 > name: TimeMapper.xml

구글에서 mybatis dtd를 검색하여 첫 번째 링크로 들어간다.

 

MyBatis – 마이바티스 3 | 시작하기

 

mybatis.org

 

위 MyBatis 링크에서 "mapper.dtd" 검색하여 아래 내용을 찾는다.

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

이 부분을 복사하여, XML파일 Source화면으로 돌아와서 붙여넣기 한 후, 붙여넣기한 소스 아래에 다음과 같이 작성한다.

// mapper namespace: kr.icia.mapper.TimeMapper.java 와 매핑하는 작업-낯선 곳을 찾아갈 때 지도를 참조하는 것과 비슷하다

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

 <mapper namespace="kr.icia.mapper.TimeMapper">
  <select id="getTime2" resultType="string">    //소문자s
    select sysdate sd2 from dual
  </select>
</mapper>

 

src/main/java > kr.icia.mapper > TimeMapper.java 인터페이스 파일 소스 아래에 다음 소스를 입력한다.

// mapping 되는 method를 만드는 작업

public String getTime2();

 

src/test/java > kr.icia.persistance > timeMapperTests.java 클래스 파일 소스 아래에 다음 소스를 입력한다.
// method를 호출하여 테스트하는 작업

@Test
	public void testGetTime2() {
		log.info("xml 이용 : " + timeMapper.getTime2());
	}
 

 

작성 후 RunAs > JUnit Test 를 구동한다.

INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.event.ApplicationEventsTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener]
INFO : org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@49fc609f, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@cd2dae5, org.springframework.test.context.event.ApplicationEventsTestExecutionListener@3a883ce7, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@4973813a, org.springframework.test.context.support.DirtiesContextTestExecutionListener@6321e813, org.springframework.test.context.transaction.TransactionalTestExecutionListener@79be0360, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@22a67b4, org.springframework.test.context.event.EventPublishingTestExecutionListener@57855c9a]
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
WARN : com.zaxxer.hikari.util.DriverDataSource - Registered driver with driverClassName=oracle.jdbc.driver.OracleDriver was not found, trying direct instantiation.
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
INFO : kr.icia.persistence.TimeMapperTests - xml 이용 : 2021-10-20 13:52:57
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
INFO : com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.

콘솔에 "xml 이용 : 현재시간"이 출력되는 것을 확인한다.

 

 

 

 

log4jdbc-log4j2 설정

log4jdbc-log4j2는 로그에 ? 로 표시되어 값이 제대로 나오는지 확인하기 어려운 문제를 해결하기 위해 SQL을 변환해 로그를 제대로 볼 수 있도록 하는 라이브러리이다.

log4j2의 dependency를 메이븐에서 가져와 pom.xml에 추가한다.

라이브러리를 추가한 후에는 로그설정 파일을 추가하고, JDBC의 연결 정보를 수정해야 한다.

 

 

 

먼저 로그 설정 파일을 추가할 것이다.

src/main/resources > new File > name: log4jdbc.log4j2.properties

파일생성 후 아래 코드를 입력한다.

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator

 

다음으로, JDBC드라이버와 URL정보를 수정할 것이다.

root-context.xml 을 연다.

위와 같이 선택된 부분의 value값을 아래와 같이 수정한다.

		<property name="driverClassName"
			value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
		<property name="jdbcUrl"
			value="jdbc:log4jdbc:oracle:thin:@localhost:1521:XE"></property>

 

 

이제 출력되는 로그를 간략화하기 위해 추가 logger를 지정해서 처리하는 작업을 할 것이다.

Reference ▶ [JAVA/Spring] SQL 로그 출력하기 :: 훈잇 블로그 (tistory.com)

src/test/resources > log4j.xml 파일을 열어 <!-- Application Loggers --> 주석 바로 아래에 해당 내용을 입력한다.

<!-- TRACE > DEBUG > INFO > WARN > ERROR > FATAL -->
	<logger name="jdbc.audit">
		<level value="fatal" />
	</logger>

	<logger name="jdbc.resultset">
		<level value="warn" />
	</logger>

	<logger name="jdbc.connection">
		<level value="warn" />
	</logger>

 

 

 

 

 

댓글