Spring & Springboot/올인원 스프링 프레임워크

학사 관리 시스템 -2

YJ_ma 2023. 9. 13. 23:11

스프링 설정 파일

src/main/resources > applicationContext.xml 파일을 생성한다.

applicationContext.xml 전체 코드는 다음과 같다.

<?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 
    https://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- InitSampleData 빈 -->
	<bean id="initSampleData"
		class="ch04_pjt_01.ems.utils.InitSampleData">
		<property name="sNums">
			<array>
				<value>hbs001</value>
				<value>hbs002</value>
				<value>hbs003</value>
				<value>hbs004</value>
				<value>hbs005</value>
			</array>
		</property>
		<property name="sIds">
			<array>
				<value>rabbit</value>
				<value>hippo</value>
				<value>raccoon</value>
				<value>elephant</value>
				<value>lion</value>
			</array>
		</property>
		<property name="sPws">
			<array>
				<value>p0001</value>
				<value>p0002</value>
				<value>p0003</value>
				<value>p0004</value>
				<value>p0005</value>
			</array>
		</property>
		<property name="sNames">
			<array>
				<value>agatha</value>
				<value>barbara</value>
				<value>chris</value>
				<value>doris</value>
				<value>elva</value>
			</array>
		</property>
		<property name="sAges">
			<array>
				<value>19</value>
				<value>22</value>
				<value>20</value>
				<value>27</value>
				<value>19</value>
			</array>
		</property>
		<property name="sGenders">
			<array>
				<value>M</value>
				<value>W</value>
				<value>W</value>
				<value>M</value>
				<value>M</value>
			</array>
		</property>
		<property name="sMajors">
			<array>
				<value>English</value>
				<value>Korean</value>
				<value>French</value>
				<value>Philosophy</value>
				<value>History</value>
			</array>
		</property>
	</bean>


	<!-- StudentDao 빈 -->
	<bean id="studentDao"
		class="ch04_pjt_01.ems.member.dao.StudentDao" />

	<!-- StudentRegisterService 빈 생성 -->
	<bean id="studentRegisterService"
		class="ch04_pjt_01.ems.member.service.StudentRegisterService">
		<constructor-arg ref="studentDao" />
	</bean>

	<!-- StudentModifyService 빈 생성 -->
	<bean id="studentModifyService"
		class="ch04_pjt_01.ems.member.service.StudentModifyService">
		<constructor-arg ref="studentDao" />
	</bean>

	<!-- StudentDeleteService 빈 생성 -->
	<bean id="studentDeleteService"
		class="ch04_pjt_01.ems.member.service.StudentDeleteService">
		<constructor-arg ref="studentDao" />
	</bean>

	<!-- StudentSelectService 빈 생성 -->
	<bean id="studentSelectService"
		class="ch04_pjt_01.ems.member.service.StudentSelectService">
		<constructor-arg ref="studentDao" />
	</bean>

	<!-- StudentAllSelectService 빈 생성 -->
	<bean id="studentAllSelectService"
		class="ch04_pjt_01.ems.member.service.StudentAllSelectService">
		<constructor-arg ref="studentDao" />
	</bean>

	<!-- PrintStudentInformationService 빈 생성 -->
	<bean id="printStudentInformationService"
		class="ch04_pjt_01.ems.member.service.PrintStudentInformationService">
		<constructor-arg ref="studentAllSelectService" />
	</bean>


	<!-- DBConnectionInfo 빈 -->
	
	<!-- 개발에 이용하는 데이터베이스 빈 생성 -->
	<bean id="dev_DBConnectionInfoDev"
		class="ch04_pjt_01.ems.member.DBConnectionInfo">
		<property name="url" value="000.000.000.000" />
		<property name="userId" value="admin" />
		<property name="userPw" value="0000" />
	</bean>

	<!-- 실제 서비스에 이용하는 데이터베이스 빈 생성 -->
	<bean id="real_DBConnectionInfo"
		class="ch04_pjt_01.ems.member.DBConnectionInfo">
		<property name="url" value="111.111.111.111" />
		<property name="userId" value="master" />
		<property name="userPw" value="1111" />
	</bean>

	<!-- EMSInformationService 빈 -->
	<bean id="eMSInformationService"
		class="ch04_pjt_01.ems.member.service.EMSInformationService">
		<property name="info"
			value="Education Management System program was developed in 2022." />
		<property name="copyRight"
			value="COPYRIGHT(C) 2022 EMS CO., LTD. ALL RIGHT RESERVED. CONTACT MASTER FOR MORE INFORMATION." />
		<property name="ver" value="The version is 1.0" />
		<property name="sYear" value="2022" />
		<property name="sMonth" value="3" />
		<property name="sDay" value="1" />
		<property name="eYear" value="2022" />
		<property name="eMonth" value="4" />
		<property name="eDay" value="30" />
		<property name="developers">
			<list>
				<value>Cheney.</value>
				<value>Eloy.</value>
				<value>Jasper.</value>
				<value>Dillon.</value>
				<value>Kian.</value>
			</list>
		</property>

		<!-- administrators 필드 초기화 -->
		<property name="administrators">
			<map>
				<entry>
					<key>
						<value>Cheney</value>
					</key>
					<value>cheney@springPjt.org</value>
				</entry>
				<entry>
					<key>
						<value>Jasper</value>
					</key>
					<value>jasper@springPjt.org</value>
				</entry>
			</map>
		</property>

		<!-- dbInfos 필드 초기화 -->
		<property name="dbInfos">
			<map>
				<entry>
					<key>
						<value>dev</value>
					</key>
					<ref bean="dev_DBConnectionInfoDev" />	// 개발용 데이터베이스 지정
				</entry>
				<entry>
					<key>
						<value>real</value>
					</key>
					<ref bean="real_DBConnectionInfo" />	// 실제 서비스 데이터베이스 지정
				</entry>
			</map>
		</property>
	</bean>

</beans>

 

InitSampleData 빈

InitSampleData는 학생 5명의 샘플 정보로 <bean>을 이용해서 빈을 생성할 수 있다.

<bean>은 id class 속성을 가진다.

- id : 빈을 가리키는 레퍼런스 변수 이름

- class : 클래스 이름

※ class 속성 값에 패키지를 포함한 클래스 이름을 반드시 명시해야한다!!

기존의 객체 생성 방법 IoC 컨테이너에서 객체 생성 방법
InitSampleData initSampleData = new InitSampleData(); <bean id="initSampleData" class="ch04_pjt_01.ems.utils.InitSampleData" />

 

<bean>에는 클래스의 멤버 필드를 나타내는 하위 태그로 <property>가 있고 이를 이용하여 필드를 초기화할 수 있다.

InitSampleData에 sNums 필드를 <bean>에서 초기화하면 다음과 같다.

기존의 객체 생성 방법 IoC 컨테이너에서 객체 생성 방법
private String[] sNums = {"hbs001", "hbs002", "hbs003", "hbs004", "hbs005" }; <bean id="initSampleData" class="ch04_pjt_01.ems.utils.InitSampleData"/>
  <property name="sNums">
     <array>
        <value>hbs001</value>
        <value>hbs002</value>
        <value>hbs003</value>
        <value>hbs004</value>
        <value>hbs005</value>
     </array>
   <property>
</bean>

 

<property>의 name속성에는 필드 이름(sNums)을 명시하고, 데이터 타입이 배열인 경우 <array>와 <value>를 이용해서 값을 명시한다.

applicationContext.xml에서 sNums를 초기화 했으므로 InitSampleData에서 다시 sNums을 초기화하지 않아도 된다.

[변경 ] private String[] sNums = {"hbs001", "hbs002", "hbs003", "hbs004", "hbs005" };

[변경 ] private String[] sNums;

 

<bean>

- 빈 생성자를 위해 InitSampleData의 생성자를 이용

<property>

- sNums을 초기화하기 위해 sNums의 setter 메서드를 이용

- <property>의 <array>값은 InitSampleData의 setsNums(String[] sNums) 메서드에 전달된다!!!

<bean id="initSampleData" class="ch04_pjt_01.ems.utils.InitSampleData" /> public InitSampleData() { }
<array>
        <value>hbs001</value>
        <value>hbs002</value>
        <value>hbs003</value>
        <value>hbs004</value>
        <value>hbs005</value>
 </array>
public void setsNums(String[] sNums) {
          this.sNums = sNums;
}

즉, <bean>태그를 이용해서 빈이 생성되고 필드는 <property>를 이용해서 초기화한다. 

이때, <bean>은 생성자를 호출하고 <property>는 setter메서드를 호출한다.

 

어떠한 생성자도 명시하지 않으면 컴파일러가 컴파일 단계에서 자동으로 디폴트 생성자(default constructor)를 생성한다.

 

발생될 수 있는 에러 유형

1. InitSampleData에 생성자가 있는 경우 - "BeanInstantiationException : 디폴트 생성자를 찾을 수 없습니다"

InitSampleData에 다음과 같은 생성자가 있다면 컴파일러는 컴파일 단계에서 디폴트 생성자를 만들지 않는다.

<bean>은 디폴트 생성자를 호출할 수 없게 되므로 에러 발생한다.

public InitSampleData(String[] sNums){
	this.sNums = sNums;
}

 

2. 초기화하려는 필드에 setter메서드가 없는 경우 - "NotWritablePropertyException: Bean속성 sNum에 쓸 수 없거나 잘못된 setter 메서드가 있습니다."

IoC 컨테이너는 필드를 초기화할 수 없어 에러가 발생한다.

 

위와같이 applicationContext.xml에서 필드를 초기화하고 InitSampleData.java를 다음과 같이 수정해준다.

package ch04_pjt_01.ems.utils;

public class InitSampleData {
	private String[] sNums;
	private String[] sIds;
	private String[] sPws;
	private String[] sNames;
	private int[] sAges;
	private char[] sGenders;
	private String[] sMajors;

	public String[] getsNums() {
		return sNums;
	}
	public void setsNums(String[] sNums) {
		this.sNums = sNums;
	}
	public String[] getsIds() {
		return sIds;
	}
	public void setsIds(String[] sIds) {
		this.sIds = sIds;
	}
	public String[] getsPws() {
		return sPws;
	}
	public void setsPws(String[] sPws) {
		this.sPws = sPws;
	}
	public String[] getsNames() {
		return sNames;
	}
	public void setsNames(String[] sNames) {
		this.sNames = sNames;
	}
	public int[] getsAges() {
		return sAges;
	}
	public void setsAges(int[] sAges) {
		this.sAges = sAges;
	}
	public char[] getsGenders() {
		return sGenders;
	}
	public void setsGenders(char[] sGenders) {
		this.sGenders = sGenders;
	}
	public String[] getsMajors() {
		return sMajors;
	}
	public void setsMajors(String[] sMajors) {
		this.sMajors = sMajors;
	}
}

 

StudentDao 빈

StudentDao : <bean>을 이용해서 빈을 생성한다. 이때 id와 class 속성에는 initSampleData 빈을 생성할 때와 마찬가지로 id이름과 패키지를 포함한 클래스 이름을 명시한다.

<bean id="studentDao" class="ch04_pjt_01.ems.member.dao.StudentDao" />

 

모든 Service가 동일한 구조로 StudentRegisterService을 이해하면 모두 이해할 수 있다.

<bean>을 이용해서 StudentRegisterService 빈을 생성하는 코드는 다음과 같다.

<bean id="studentRegisterService" class="ch04_pjt_01.ems.member.service.StudentRegisterService"/>

 

StudentRegisterService는 객체가 생성될 때 생성자에서 studentDao 필드를 초기화하고, 이를 위해서 StudentDao를 외부에서 주입받고 있다.

즉 디폴트 생성자가 아닌 StudentDao를 주입받는 생성자를 이용해서 객체가 만들어진다.

public StudentRegisterService(StudentDao studentDao) {
	this.studentDao = studentDao;
}

따라서 Ioc 컨테이너에서 StudentRegisterService 빈을 생성할 때도 외부에서 StudentDao 객체를 주입받기 위해 <constructor-arg> 태그를 이용한다.

<constructor-arg> : 생성자 매개변수 

- ref 속성 : 외부에서 주입되는 빈의 id값을 명시

<bean id="studentRegisterService" class="ch04_pjt_01.ems.member.service.StudentRegisterService">
	<constructor-arg ref="studentDao" />
</bean>

 

<에러>

StudentRegisterService 빈을 생성할 때 <constructor-arg>가 없는 경우 - No default constructor found;

StudentRegisterService는 유일하게 StudentDao를 매개변수로 받는 생성자만 가지고 있다.

만약, <constructor-arg>가 없다면?

→ 생성자 호출에 문제가 되기 때문에 다음과 같은 에러가 발생한다.

 

DBConnectionInfo빈

DBConnectionInfo는 InitSampleData와 마찬가지로 데이터베이스 연결에 필요한 url, userId, userPw 필드만 있다.

<property>를 이용한 필드 초기화 코드를 작성한다.

 

프로젝트를 진행할 때 개발용 데이터베이스실제 서비스에 이용하는 데이터베이스를 구분해주어야한다!!

<!-- 개발에 이용하는 데이터베이스 빈 생성 -->
<bean id="dev_DBConnectionInfoDev"
    class="ch04_pjt_01.ems.member.DBConnectionInfo">
    <property name="url" value="000.000.000.000" />
    <property name="userId" value="admin" />
    <property name="userPw" value="0000" />
</bean>

<!-- 실제 서비스에 이용하는 데이터베이스 빈 생성 -->
<bean id="real_DBConnectionInfo"
    class="ch04_pjt_01.ems.member.DBConnectionInfo">
    <property name="url" value="111.111.111.111" />
    <property name="userId" value="master" />
    <property name="userPw" value="1111" />
</bean>

 

EMSInformationService 빈

EMSInformationService는 필드가 12개이고 데이터 타입고 String, int, Map, List 등 다양하다.

데이터가 한 개이면 <value> 태그를 사용하지않고 <property> 태그의 value 속성을 이용할 수 있다.

<property name="copyRight"
    value="COPYRIGHT(C) 2022 EMS CO., LTD. ALL RIGHT RESERVED. CONTACT MASTER FOR MORE INFORMATION." />
<property name="ver" value="The version is 1.0" />
<property name="sYear" value="2022" />
<property name="sMonth" value="3" />
<property name="sDay" value="1" />
<property name="eYear" value="2022" />
<property name="eMonth" value="4" />
<property name="eDay" value="30" />

데이터 타입이 기초 데이터 타입이 아닌 참조 데이터 타입인 필드를 초기화해본다.

developers는 데이터 타입이 List로, <list> 태그를 이용한다.

<property name="developers">
    <list>
        <value>Cheney.</value>
        <value>Eloy.</value>
        <value>Jasper.</value>
        <value>Dillon.</value>
        <value>Kian.</value>
    </list>
</property>

administrators는 데이터 타입이 Map으로, <map><entry> 태그를 사용한다.

그리고<key><value>태그를 이용해서 Map의 keyvalue를 입력한다.

<property name="administrators">
    <map>
        <entry>
            <key>
                <value>Cheney</value>
            </key>
            <value>cheney@springPjt.org</value>
        </entry>
        <entry>
            <key>
                <value>Jasper</value>
            </key>
            <value>jasper@springPjt.org</value>
        </entry>
    </map>
</property>

dbInfos는 데이터 타입이 Map으로 key와 value 타입은 String과 DBConnectionInfo이다.

DBConnectionInfo는 내가 만든 타입이므로 <ref>를 이용하여 DBConnectionInfo 빈을 지정할 수 있다.

<property name="dbInfos">
    <map>
        <entry>
            <key>
                <value>dev</value>
            </key>
            <ref bean="dev_DBConnectionInfoDev" />	// 개발용 데이터베이스 지정
        </entry>
        <entry>
            <key>
                <value>real</value>
            </key>
            <ref bean="real_DBConnectionInfo" />	// 실제 서비스 데이터베이스 지정
        </entry>
    </map>
</property>

 

메이븐 설정 파일

applicationContext.xml을 이용해서 IoC 컨테이너를 만드는 클래스 GenericXmlApplicationContext는 org.springframework.context.support 패키지에 있는 클래스로 pom.xml에 spring-context 모듈을 이용해서 다운로드하고 사용할 수 있다.

pom.xml 코드는 다음과 같다.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>spring5</groupId>
  <artifactId>ch04_pjt_01</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <!-- spring-context 모듈 -->
  <dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
  </dependencies>
  
  <!-- 빌드 설정 -->
  <build>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>11</source>
                <target>11</target>
                <encoding>utf-8</encoding>
            </configuration>
        </plugin>
    </plugins>
  </build>
  
</project>