일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- linux 배포판
- type assertion
- Redux Toolkit
- 프로세스
- Microtask Queue
- AJIT
- useLayoutEffect
- 클라이언트 상태 관리 라이브러리
- Recoil
- docker
- jotai
- Render Queue
- Sparkplug
- Headless 컴포넌트
- 타입 단언
- 암묵적 타입 변환
- CS
- 명시적 타입 변환
- TypeScript
- react
- Compound Component
- Custom Hook
- JavaScript
- zustand
- helm-chart
- 주니어개발자
- 회고
- 좋은 PR
- task queue
- prettier-plugin-tailwindcss
- Today
- Total
구리
TIL_210616_컬렉션 객체 맵핑 설정, DI 설정(어노테이션, XML 설정) 본문
목차
컬렉션 객체 설정
List 타입 맵핑
Set 타입 맵핑
Map 타입 맵핑
Properties 타입 맵핑
Spring DI 설정 방법
의존성 주입 어노테이션 (@Autowired, @Qualifier, @Resource)
어노테이션과 XML 설정 병행하여 사용
추가 어노테이션
어노테이션, XML 설정 프로젝트 예시
컬렉션 객체 설정
컬렉션 유형 | 엘리먼트 |
java.util.List, 배열 | <list> |
java.util.Set | <set> |
java.util.Map | <map> |
java.util.Properties | <props> |
List 타입 맵핑
CollectionBean.java
package com.springbook.ioc.injection;
import java.util.List;
public class CollectionBean {
private List<String> addressList;
public void setAddressList(List<String> addressList){
this.addressList = addressList;
}
public List<String> getAddressList(){
return addressList;
}
}
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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="collectionBean" class="com.springbook.ioc.injection.CollectionBean">
<property name="addressList">
<list>
<value>서울시 강남구 역삼동</value>
<value>서울시 강남구 논현동</value>
</list>
</property>
</bean>
</beans>
CollectionBeanClient.java
package com.springbook.ioc.injection;
import java.util.List;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class CollectionBeanClient {
public static void main(String[] args) {
AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
CollectionBean bean = (CollectionBean)factory.getBean("collectionBean");
List<String> addressList = bean.getAddressList();
for(String address : addressList){
System.out.println(address);
}
factory.close();
}
}
위 xml 문서를 보게 되면 두 개의 문자열 주소가 저장된 List 객체를 CollectionBean 객체의 setAddressList() 메소드 호출시 인자로 전달하여 addressList 멤버변수를 초기화하는 설정입니다.
Set 타입 맵핑
CollectionBean.java
package com.springbook.ioc.injection;
import java.util.Set;
public class CollectionBean {
private Set<String> addressList;
public void setAddressList(Set<String> addressList){
this.addressList = addressList;
}
public Set<String> getAddressList(){
return addressList;
}
}
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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="collectionBean" class="com.springbook.ioc.injection.CollectionBean">
<property name="addressList">
<set value-type="java.lang.String">
<value>서울시 강남구 역삼동</value>
<value>서울시 성동구 성수동</value>
<value>서울시 성동구 성수동</value>
</set>
</property>
</bean>
</beans>
CollectionBeanClient.java
package com.springbook.ioc.injection;
import java.util.Set;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class CollectionBeanClient {
public static void main(String[] args) {
AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
CollectionBean bean = (CollectionBean)factory.getBean("collectionBean");
Set<String> addressList = bean.getAddressList();
for(String address : addressList){
System.out.println(address);
}
factory.close();
}
}
xml 문서를 보면 setAddressList() 메소드 호출시 문자열 타입의 데이터 여러 개를 저장한 Set 컬렉션을 인자로 전달하겠다는 설정입니다. 그리고 "서울시 성동구 성수동"이라는 주소가 2번 등록되었는데 Set 컬렉션은 중복 데이터를 허용하지 않기 때문에 실제 실행된 결과값은 "서울시 성동구 성수동"이라는 주소 1개만 저장됩니다.
Map 타입 맵핑
특정 key로 데이터를 등록하고 사용할 때 java.util.Map 컬렉션 사용하여 <map> 태그 사용하여 설정 가능합니다.
CollectionBean.java
package com.springbook.ioc.injection;
import java.util.Map;
public class CollectionBean {
private Map<String, String> addressList;
public void setAddressList(Map<String, String> addressList){
this.addressList = addressList;
}
public Map<String, String> getAddressList(){
return addressList;
}
}
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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="collectionBean" class="com.springbook.ioc.injection.CollectionBean">
<property name="addressList">
<map>
<entry>
<key><value>역삼동</value></key>
<value>서울시 강남구 역삼동</value>
</entry>
<entry>
<key><value>성수동</value></key>
<value>서울시 성동구 성수동</value>
</entry>
</map>
</property>
</bean>
</beans>
CollectionBeanClient.java
package com.springbook.ioc.injection;
import java.util.Map;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class CollectionBeanClient {
public static void main(String[] args) {
AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
CollectionBean bean = (CollectionBean)factory.getBean("collectionBean");
Map<String, String> addressList = bean.getAddressList();
//객체를 하나씩 처리하기
System.out.println("총 Entry 수 : " + addressList.size());
//객체 찾기
System.out.println("역삼동의 전체 주소는? " + addressList.get("역삼동"));
System.out.println("성수동의 전체 주소는? " + addressList.get("성수동"));
}
}
위 설정 파일에서 보면 Map에 저장될 한 개의 <키,값>을 <entry> 태그로 표현하였으며 <key> 태그를 이용하여 키에 할당될 값을 지정하게 되는데 이때 <key> 태그에는 다음과 같은 태그가 위치할 수 있습니다. <값태그>에도 마찬가지로 아래와 동일한 태그를 사용해 값을 지정할 수 있습니다.
<ref> : 다른 스프링 빈 객체를 키로 사용
<bean> : 임의 빈 객체를 생성하여 키로 사용
<value> : String을 키로 사용
<null> : null값을 키로 사용
예시
<map>
<entry>
<key><value>1</value></key>
<value type="java.lang.Interger">1th</value>
</entry>
<entry>
<key><ref bean="protocol"/></key>
<ref bean="handler"/>
</entry>
</map>
<map>
<entry key="1" value="1th"/>
<entry key-ref="protocol" value-ref="handler"/>
</map>
Properties 타입 맵핑
key = value 형태의 데이터를 등록하고 싶을 때 사용하는 Properties 컬렉션으로 <props> 엘리먼트를 사용하여 설정
CollectionBean.java
package com.springbook.ioc.injection;
import java.util.Properties;
public class CollectionBean {
private Properties addressList;
public void setAddressList(Properties addressList){
this.addressList = addressList;
}
public Properties getAddressList(){
return addressList;
}
}
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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="collectionBean" class="com.springbook.ioc.injection.CollectionBean">
<property name="addressList">
<props>
<prop key="고길동">서울시 강남구 역삼동</prop>
<prop key="또치">서울시 성동구 성수동</prop>
</props>
</property>
</bean>
</beans>
CollectionBeanClient.java
package com.springbook.ioc.injection;
import java.util.Enumeration;
import java.util.Properties;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class CollectionBeanClient {
public static void main(String[] args) {
AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
CollectionBean bean = (CollectionBean)factory.getBean("collectionBean");
//Properties 타입
Properties addressList = bean.getAddressList();
// name 가져오기
Enumeration enu = addressList.propertyNames(); //keySet() 메소드와 기능이 동일
//리턴타입이 Enumeration라서 Enumeration타입의 변수에 담아줌.
while(enu.hasMoreElements()) { //hasNext()와 기능 동일
String ele = (String)enu.nextElement(); //next()와 기능 동일
System.out.println(ele + " : " + addressList.getProperty(ele));
}
}
}
Spring DI 설정 방법
1. 설정 파일 내의 <bean>으로 설정
2. 설정 파일 내에서 검색하는 방법
- 조건 : <beans> 태그에서 context Namespace 추가
- 검색될 컴포넌트(클래스)들은 선언부 상단에 @Component 어노테이션이 명시되어야 합니다
- 설정 파일 내에서는 <component-scan>을 이용해 검색이 가능합니다
- 만약 검색 범위(패키지)를 설정할 경우 base-package="" 속성을 사용하여 설정합니다
(사용하지 않을 경우 프로젝트의 모든 패키지가 스캔 대상이 됩니다)
예시
package polymorphism;
import org.springframework.stereotype.Component;
/** <bean id="tv" class="polymorphism.LgTV"> in XML 과 같은 의미 **/
@Component("tv")
public class LgTV implements TV{
public LgTV() {
System.out.println("===>LgTV 객체 생성!");
}
@Override
public void powerOn() {
System.out.println("LgTV---전원 키기");
}
@Override
public void powerOff() {
System.out.println("LgTV---전원 끄기");
}
@Override
public void volumeUp() {
System.out.println("LgTV---볼륨 높이기");
}
@Override
public void volumeDown() {
System.out.println("LgTV---볼륨 줄이기");
}
}
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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="polymorphism"></context:component-scan>
</beans>
TvUser.java
package polymorphism;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class TvUser {
public static void main(String[] args) {
AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
TV tv = (TV)factory.getBean("tv");
tv.powerOn();
tv.powerOff();
tv.volumeUp();
tv.volumeDown();
factory.close();
}
}
LgTV 클래스 선언 부분에 @Component 어노테이션을 설정해줌으로써 스프링 컨테이너는 해당 클래스를 bean으로 생성하고 관리합니다. 또한 XML 파일에서 <context:component-scan>을 설정함으로써 클래스들을 일일이 <bean> 엘리먼트로 등록할 필요도 없습니다.
Q) id나 name 미지정 시?
컨테이너가 자동으로 이름을 설정해주는데 이때 이름 규칙은 클래스 이름의 첫글자를 소문자로 변경합니다.
따라서 id나 name 속성이 설정되지 않은 경우, LgTV 객체를 요청할 경우 lgTV라는 이름을 사용하면 됩니다.
의존성 주입 어노테이션
어노테이션 | 설명 |
@Autowired | 주로 변수 위에 설졍하여 해당 타입 객체를 찾아서 자동으로 할당 |
@Qualifier | 특정 객체의 이름을 이용하여 의존성 주입할 때 사용 |
@Inject | @Autowired와 동일한 기능 |
@Resource | @Autowired와 @Qualifier의 기능을 결합한 어노테이션 |
@Autowired
생성자, 멤버변수, 메소드 위에 모두 사용할 수 있으며 대부분 멤버변수 위에 선언하여 사용합니다. 스프링 컨테이너는 멤버 변수 위에 붙은 @Autowired를 확인하는 순간 해당 ① 변수의 타입을 체크하고 그 타입의 ② 객체가 메모리에 존재하는지를 확인 후 자동으로
③ 객체를 주입합니다.
만약 NoSuchBeanDefinitionException이 발생된다면 @Autowired 대상 객체가 메모리에 존재하지 않는다는 의미입니다.
예시
package polymorphism;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/** <bean id="tv" class="polymorphism.LgTV"> in XML 과 같은 의미 **/
@Component("tv")
public class LgTV implements TV{
@Autowired
private Speaker speaker;
public LgTV() {
System.out.println("===>LgTV 객체 생성!");
}
@Override
public void powerOn() {
System.out.println("LgTV---전원 키기");
}
@Override
public void powerOff() {
System.out.println("LgTV---전원 끄기");
}
@Override
public void volumeUp() {
System.out.println("LgTV---볼륨 높이기");
}
@Override
public void volumeDown() {
System.out.println("LgTV---볼륨 줄이기");
}
}
위처럼 설정하면 Speaker 인터페이스를 구현한 클래스 객체가 메모리에 있어야하며 해당 객체를 생성하려면 다음과 같은 방법을 사용하면 됩니다.
package polymorphism;
import org.springframework.stereotype.Component;
@Component("sony")
public class SonySpeaker implements Speaker {
public SonySpeaker() {
System.out.println("===> SonySpeaker 객체 생성");
}
@Override
public void volumeUp() {
System.out.println("SonySpeaker 소리 크기 높이기 !");
}
@Override
public void volumeDown() {
System.out.println("SonySpeaker 소리 크기 줄이기...");
}
}
XML설정
<bean id="sony" class="polymorphism.SonySpeaker"></bean>
@Qualifier
만약 SonySpeaker와 AppleSpeaker 객체가 모두 메모리에 생성되어 있는 상황이라면 컨테이너는 어떤 객체를 할당할 지 스스로 판단할 수 없어서 에러가 발생하는데 이때 사용하는 어노테이션이 @Qualifier입니다.
package polymorphism;
import org.springframework.stereotype.Component;
@Component("apple")
public class AppleSpeaker implements Speaker {
public AppleSpeaker() {
System.out.println("===> AppleSpeaker 객체 생성");
}
@Override
public void volumeUp() {
System.out.println("AppleSpeaker 소리 크기 높이기 !!");
}
@Override
public void volumeDown() {
System.out.println("AppleSpeaker 소리 크기 줄이기....");
}
}
package polymorphism;
import org.springframework.stereotype.Component;
@Component("sony")
public class SonySpeaker implements Speaker {
public SonySpeaker() {
System.out.println("===> SonySpeaker 객체 생성");
}
@Override
public void volumeUp() {
System.out.println("SonySpeaker 소리 크기 높이기 !");
}
@Override
public void volumeDown() {
System.out.println("SonySpeaker 소리 크기 줄이기...");
}
}
package polymorphism;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
/** <bean id="tv" class="polymorphism.LgTV"> in XML 과 같은 의미 **/
@Component("tv")
public class LgTV implements TV{
@Autowired
@Qualifier("apple")
private Speaker speaker;
public LgTV() {
System.out.println("===>LgTV 객체 생성!");
}
@Override
public void powerOn() {
System.out.println("LgTV---전원 키기");
}
@Override
public void powerOff() {
System.out.println("LgTV---전원 끄기");
}
@Override
public void volumeUp() {
System.out.println("LgTV---볼륨 높이기");
}
@Override
public void volumeDown() {
System.out.println("LgTV---볼륨 줄이기");
}
}
@Qualifier 어노테이션을 이용하면 의존성 주입이 될 객체의 아이디나 이름을 지정할 수 있는데, 이때 Speaker 객체의 이름 (apple, sony) 중 하나를 지정하면 간단히 처리할 수 있습니다.
@Resource
@Autowired는 변수의 타입을 기준으로 객체를 검색하여 여러 클래스들이 존재한다면 @Qualifier 를 이용하여 이름을 지정하였는데 이를 합친 방법을
@Resource이라고 생각하면 됩니다.
@Resource는 객체의 이름을 이용하여 의존성 주입을 처리하며 name 속성을 사용할 수 있어서 해당 이름으로 생성된 객체를 검색하여 의존성 주입을 처리합니다.
예시
package polymorphism;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
/** <bean id="tv" class="polymorphism.LgTV"> in XML 과 같은 의미 **/
@Component("tv")
public class LgTV implements TV{
@Resource(name="apple")
private Speaker speaker;
public LgTV() {
System.out.println("===>LgTV 객체 생성!");
}
@Override
public void powerOn() {
System.out.println("LgTV---전원 키기");
}
@Override
public void powerOff() {
System.out.println("LgTV---전원 끄기");
}
@Override
public void volumeUp() {
System.out.println("LgTV---볼륨 높이기");
}
@Override
public void volumeDown() {
System.out.println("LgTV---볼륨 줄이기");
}
}
어노테이션과 XML 설정 병행하여 사용
XML 방식은 자바 코드 수정 없이 파일 설정만 변경하면 Speaker 객체를 교체할 수 있어 유지보수가 편하지만 XML 설정을 해석해야만 무슨 객체가 의존성 주입되는지를 확인할 수 있습니다.반면에 어노테이션 기반 설정은 자바 소스에 들어있어서 사용하기 편하지만 자바 소스를 수정하지 않고 Speaker를 교체할 수 없다는 문제가 생깁니다. 이 두가지 방법을 적절히 사용하는 것이 가장 좋은데 다음 예시를 통해 확인해보겠습니다.(LgTV 클래스의 speaker 변수를 원래 @Autowired 어노테이션만 설정합니다)
package polymorphism;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/** <bean id="tv" class="polymorphism.LgTV"> in XML 과 같은 의미 **/
@Component("tv")
public class LgTV implements TV{
@Autowired
private Speaker speaker;
public LgTV() {
System.out.println("===>LgTV 객체 생성!");
}
@Override
public void powerOn() {
System.out.println("LgTV---전원 키기");
}
@Override
public void powerOff() {
System.out.println("LgTV---전원 끄기");
}
@Override
public void volumeUp() {
System.out.println("LgTV---볼륨 높이기");
}
@Override
public void volumeDown() {
System.out.println("LgTV---볼륨 줄이기");
}
}
package polymorphism;
public class SonySpeaker implements Speaker {
public SonySpeaker() {
System.out.println("===> SonySpeaker 객체 생성");
}
@Override
public void volumeUp() {
System.out.println("SonySpeaker 소리 크기 높이기 !");
}
@Override
public void volumeDown() {
System.out.println("SonySpeaker 소리 크기 줄이기...");
}
}
package polymorphism;
public class AppleSpeaker implements Speaker {
public AppleSpeaker() {
System.out.println("===> AppleSpeaker 객체 생성");
}
@Override
public void volumeUp() {
System.out.println("AppleSpeaker 소리 크기 높이기 !!");
}
@Override
public void volumeDown() {
System.out.println("AppleSpeaker 소리 크기 줄이기....");
}
}
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="polymorphism"></context:component-scan>
<bean id="speaker" class="polymorphism.AppleSpeaker"></bean>
</beans>
package polymorphism;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class TvUser {
public static void main(String[] args) {
AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
TV tv = (TV)factory.getBean("tv");
tv.powerOn();
tv.powerOff();
tv.volumeUp();
tv.volumeDown();
factory.close();
}
}
SonySpeaker, AppleSpeaker 클래스에서 @Component 어노테이션을 제거한 후 XML 문서에서 직접 bean 객체를 생성한 후 주입하였습니다.만약 speaker를 변경하고 싶다면 XML 파일의 bean 태그의 class 속성값만 변경하면 되기에 편리합니다.결국 클라이언트가 요청할 LgTV는 @Component 어노테이션으로 처리하고, 의존성 주입 역시 @Autowired로 처리하는데 변경될 Speaker만 스프링 설정 파일에 bean 태그를 등록함으로써 자바 코드 수정 없이 XML 수정만으로 Speaker를 교체할 수 있습니다.즉, 변경되지 않는 객체는 어노테이션으로 설정하고 변경될 가능성이 있는 객체는 XML 설정으로 사용하는 것이 바람직합니다.(참고로 라이브러리 형태로 제공되는 클래스는 어노테이션 사용 불가 ! XML 설정만 가능)
추가 어노테이션
프레젠테이션 레이어는 사용자와의 커뮤니케이션을 담당하고, 비즈니스 레이어는 사용자의 요청에 대한 비즈니스 로직 처리를 담당합니다. 가장 핵심은 Controller, ServiceImpl, DAO 클래스로 모든 클래스에 @Component 어노테이션을 이용하면 불편하기에 @Component 를 상속한 아래의 어노테이션을 사용합니다.
어노테이션 | 위치 | 의미 |
@Service | XXXServiceImpl | 비즈니스 로직을 처리하는 Service 클래스 |
@Repository | XXXDAO | 데이터베이스 연동을 처리하는 DAO 클래스 |
@Controller | XXXController | 사용자 요청을 제어하는 Controller 클래스 |
@Controller는 해당 객체를 MVC 아키텍처에서 컨트롤러 객체로 인식하도록 해주며, @Repository는 DB 연동 과정에서 발생하는 예외를 변환해주는 특별한 기능이 추가되어 있습니다.
Q) @Service 어노테이션을 사용하는 클래스는 인터페이스를 구현한 클래스인데 왜 굳이 번거롭게 인터페이스를 생성해서 사용하는 것인가요 ?
인터페이스를 사용함으로써 결합도를 낮추고 유연성을 띄게 되기 때문입니다.
Q) @Service 와 @Repository의 차이점은 ?
@Repository > DB에 접근하는 모든 코드가 모여있으며 @Service > DB 접근 코드는 Repository 에 위임하고 비즈니스 로직만 있습니다.
프로젝트 예시(BoardService는 어노테이션, UserService는 XML 설정을 이용)
프로젝트 구성
프로젝트 코드
BoardService 관련 (어노테이션을 이용한 인젝션 주입)
package com.springbook.biz.board;
import java.sql.Date;
public class BoardVO {
private int seq;
private String title;
private String writer;
private String content;
private Date regDate;
private int cnt;
public BoardVO() {}
public int getSeq() {
return seq;
}
public void setSeq(int seq) {
this.seq = seq;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getRegDate() {
return regDate;
}
public void setRegDate(Date regDate) {
this.regDate = regDate;
}
public int getCnt() {
return cnt;
}
public void setCnt(int cnt) {
this.cnt = cnt;
}
@Override
public String toString(){
return "BoardVO [seq=" + seq + ", title=" + title + ", writer=" + writer + ",content= " + content + ", regDate = " + regDate + ", cnt = " + cnt + "]";
}
}
package com.springbook.biz.board.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.common.JDBCUtil;
@Repository("boardDAO")
public class BoardDAO {
// JDBC 관련 변수
private Connection conn = null;
private PreparedStatement stmt = null;
private ResultSet rs = null;
// sql 명령어들
private final String BOARD_INSERT = "insert into board(seq, title, writer, content) values ((select nvl(max(seq), 0)+1 from board),?,?,?)";
private final String BOARD_UPDATE = "update board set title=?, content=?, where seq=?";
private final String BOARD_DELETE = "delete from board where seq=?";
private final String BOARD_GET = "select * from board where seq=?";
private final String BOARD_LIST = "select * from board order by seq desc";
public BoardDAO() {
}
// 글 등록
public void insertBoard(BoardVO vo){
System.out.println("===> JDBC로 insertBoard() 기능 처리");
try{
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(BOARD_INSERT);
stmt.setString(1, vo.getTitle());
stmt.setString(2, vo.getWriter());
stmt.setString(3, vo.getContent());
stmt.executeUpdate();
}catch(Exception e){
System.err.println("insertBoard() ERR : " + e.getMessage());
}finally{
JDBCUtil.close(stmt, conn);
}
}
// 글 수정
public void updateBoard(BoardVO vo){
System.out.println("===> JDBC로 updateBoard() 기능 처리");
try{
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(BOARD_UPDATE);
stmt.setString(1, vo.getTitle());
stmt.setString(2, vo.getWriter());
stmt.setInt(3, vo.getSeq());
stmt.executeUpdate();
}catch(Exception e){
System.err.println("updateBoard() ERR : " + e.getMessage());
}finally{
JDBCUtil.close(stmt, conn);
}
}
// 글 삭제
public void deleteBoard(BoardVO vo){
System.out.println("===> JDBC로 deleteBoard() 기능 처리");
try{
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(BOARD_DELETE);
stmt.setInt(1, vo.getSeq());
stmt.executeUpdate();
}catch(Exception e){
System.err.println("deleteBoard() ERR : " + e.getMessage());
}finally{
JDBCUtil.close(stmt, conn);
}
}
// 글 상세 조회
public BoardVO getBoard(BoardVO vo){
System.out.println("===> JDBC로 geteBoard() 기능 처리");
BoardVO board = null;
try{
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(BOARD_GET);
stmt.setInt(1, vo.getSeq());
rs = stmt.executeQuery();
if(rs.next()){
board = new BoardVO();
board.setSeq(rs.getInt("SEQ"));
board.setTitle(rs.getString("TITLE"));
board.setWriter(rs.getString("WRITER"));
board.setContent(rs.getString("CONTENT"));
board.setRegDate(rs.getDate("REGDATE"));
board.setCnt(rs.getInt("CNT"));
}
}catch(Exception e){
System.err.println("getBoard() ERR : " + e.getMessage());
}finally{
JDBCUtil.close(rs, stmt, conn);
}
return board;
}
// 글 목록 조회
public List<BoardVO> getBoardList(BoardVO vo){
System.out.println("===> JDBC로 getBoardList() 기능 처리");
List<BoardVO> boardList = new ArrayList<BoardVO>();
try{
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(BOARD_LIST);
rs = stmt.executeQuery();
while(rs.next()){
BoardVO board = new BoardVO();
board.setSeq(rs.getInt("SEQ"));
board.setTitle(rs.getString("TITLE"));
board.setWriter(rs.getString("WRITER"));
board.setContent(rs.getString("CONTENT"));
board.setRegDate(rs.getDate("REGDATE"));
board.setCnt(rs.getInt("CNT"));
boardList.add(board);
}
}catch(Exception e){
System.err.println("getBoardList() ERR : " + e.getMessage());
}finally{
JDBCUtil.close(rs, stmt, conn);
}
return boardList;
}
}
package com.springbook.biz.board;
import java.util.List;
/** CRUD 관련된 메서드 (기능 구현) **/
public interface BoardService {
// 글 등록
void insertBoard(BoardVO vo);
// 글 수정
void updateBoard(BoardVO vo);
// 글 삭제
void deleteBoard(BoardVO vo);
// 글 목록
List<BoardVO> getBoardList(BoardVO vo);
// 글 상세
BoardVO getBoard(BoardVO vo);
}
package com.springbook.biz.board.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.springbook.biz.board.BoardService;
import com.springbook.biz.board.BoardVO;
@Service("boardSerivce")
public class BoardServiceImpl implements BoardService {
@Autowired
private BoardDAO boardDAO;
public BoardServiceImpl() {
}
public void insertBoard(BoardVO vo) {
boardDAO.insertBoard(vo);
}
public void updateBoard(BoardVO vo) {
boardDAO.updateBoard(vo);
}
public void deleteBoard(BoardVO vo) {
boardDAO.deleteBoard(vo);
}
public List<BoardVO> getBoardList(BoardVO vo) {
return boardDAO.getBoardList(vo);
}
public BoardVO getBoard(BoardVO vo) {
return boardDAO.getBoard(vo);
}
}
package com.springbook.biz.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class JDBCUtil {
public JDBCUtil() { }
/** 1. DB 접속 객체 반환 메서드 **/
public static Connection getConnection(){
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:XE";
return DriverManager.getConnection(url,"bjy","qorwjddus96");
}catch(Exception e){
System.err.println("getConnection() ERR :" + e.getMessage());
}
return null;
}
/** 각 자원 해제 메서드 **/
// 1. PreparedStatement / Connection 해제
public static void close(PreparedStatement stmt, Connection conn){
if(stmt != null){
try{
if(!stmt.isClosed())
stmt.close();
}catch(Exception e){
System.err.println("close() stmt ERR : " + e.getMessage());
}finally{
stmt = null;
}
}
if(conn != null){
try{
if(!conn.isClosed())
conn.close();
}catch(Exception e){
System.err.println("close() conn ERR : " + e.getMessage());
}finally{
conn = null;
}
}
}
// 2. ResultSet / PreparedStatement / Connection 해제
public static void close(ResultSet rs,PreparedStatement stmt, Connection conn){
if(rs != null){
try{
if(!rs.isClosed())
rs.close();
}catch(Exception e){
System.err.println("close() rs ERR : " + e.getMessage());
}finally{
rs = null;
}
}
if(stmt != null){
try{
if(!stmt.isClosed())
stmt.close();
}catch(Exception e){
System.err.println("close() stmt ERR : " + e.getMessage());
}finally{
stmt = null;
}
}
if(conn != null){
try{
if(!conn.isClosed())
conn.close();
}catch(Exception e){
System.err.println("close() conn ERR : " + e.getMessage());
}finally{
conn = null;
}
}
}
}
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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="com.springbook.biz"></context:component-scan>
<bean id="userService" class="com.springbook.biz.user.impl.UserServiceImpl">
<property name="userDAO" ref="userDAO"></property>
</bean>
<bean id="userDAO" class="com.springbook.biz.user.impl.UserDAO"></bean>
</beans>
package com.springbook.biz.board;
import java.util.List;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class BoardServiceClient {
public static void main(String[] args) {
// 1. Spring Container 구동
AbstractApplicationContext container = new GenericXmlApplicationContext("applicationContext.xml");
// 2. Spring Container로부터 BoardServiceImpl 객체를 요청(lookup)
BoardService boardService = (BoardService) container.getBean("boardSerivce");
// 3. 글 등록 기능 테스트
BoardVO vo = new BoardVO();
vo.setTitle("임시 제목");
vo.setWriter("너굴이");
vo.setContent("test 내용");
boardService.insertBoard(vo);
// 4. 글 목록 검색 기능 테스트
List<BoardVO> boardList = boardService.getBoardList(vo);
for(BoardVO board : boardList){
System.out.println("---> " + board.toString());
}
// 5. 자원 해제
container.close();
}
}
BoardServletClient 에서 프로그램을 실행하면 Spring Container가 구동되어 XML 파일의 <context:component-scan > 태그로 해당 패키지가 모두 스캔되고 lookup을 통해 @Service 어노테이션이 있는 BoardServiceImpl 객체가 생성, 해당 클래스에는 @Autowired로 BoardDAO 타입의 객체를 의존성 주입하였습니다. @Repository 어노테이션으로 인해 스프링 컨테이너에서 BoardDAO 객체 생성되었습니다.
UserService (어노테이션 사용이 아닌 Setter 인젝션으로 의존성 주입 처리)
package com.springbook.biz.user;
public class UserVO {
private String id;
private String password;
private String name;
private String role;
public UserVO() {
// TODO Auto-generated constructor stub
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String toString(){
return "UserVO [id=" +id + ",password = " + password;
}
}
package com.springbook.biz.user.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.springbook.biz.common.JDBCUtil;
import com.springbook.biz.user.UserVO;
public class UserDAO {
// JDBC 관련 변수
private Connection conn = null;
private PreparedStatement stmt = null;
private ResultSet rs = null;
private final String USER_GET = "select * from users where id=? and password=?";
public UserVO getUser(UserVO vo){
UserVO user = null;
try{
System.out.println("===> JDBC로 getUser() 기능 처리");
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(USER_GET);
stmt.setString(1, vo.getId());
stmt.setString(2, vo.getPassword());
rs = stmt.executeQuery();
if(rs.next()){
user = new UserVO();
user.setId(rs.getString("ID"));
user.setPassword(rs.getString("PASSWORD"));
user.setName(rs.getString("NAME"));
user.setRole(rs.getString("ROLE"));
}
}catch(Exception e){
System.err.println("getUser() ERR : " + e.getMessage());
}finally{
JDBCUtil.close(rs,stmt, conn);
}
return user;
}
public UserDAO() {
// TODO Auto-generated constructor stub
}
}
package com.springbook.biz.user;
public interface UserService {
public UserVO getUser(UserVO vo);
}
package com.springbook.biz.user.impl;
import com.springbook.biz.user.UserService;
import com.springbook.biz.user.UserVO;
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
public UserServiceImpl() {
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
@Override
public UserVO getUser(UserVO vo) {
return userDAO.getUser(vo);
}
}
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="com.springbook.biz"></context:component-scan>
<bean id="userService" class="com.springbook.biz.user.impl.UserServiceImpl">
<property name="userDAO" ref="userDAO"></property>
</bean>
<bean id="userDAO" class="com.springbook.biz.user.impl.UserDAO"></bean>
</beans>
package com.springbook.biz.user;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
public class UserServiceClient {
public static void main(String[] args) {
// 1. Spring 컨테이너를 구동
AbstractApplicationContext container = new GenericXmlApplicationContext("applicationContext.xml");
// 2. Spring 컨테이너로부터 UserServiceImpl 객체를 lookup한다
UserService userService = (UserService) container.getBean("userService");
// 3. 로그인 기능 테스트
UserVO vo = new UserVO();
vo.setId("test");
vo.setPassword("1234");
UserVO user = userService.getUser(vo);
if(user != null){
System.out.println(user.getName() + "님 환영합니다 ^^");
}else{
System.out.println("로그인 실패");
}
// 4. Spring 컨테이너 종료
container.close();
}
}
DB에는 데이터를 미리 삽입해놓았기에 User에 대한 정보가 조회됩니다.
어노테이션을 이용한 방식과 Setter 방식을 이용한 인젝션 주입 방식을 비교해보면서 차이점을 집중해서 보는 것이 좋습니다.
'SPRING FRAMEWORK' 카테고리의 다른 글
TIL_210617_AOP 정의, 적용하는 법, 용어, 엘리먼트 (0) | 2021.06.17 |
---|---|
TIL_210617_SpringFramwork JDBC Template 클래스 사용하여 DB 연동 (0) | 2021.06.17 |
TIL_210615_스프링 XML 설정 및 속성, 의존성 관리 종류 (0) | 2021.06.15 |
STS 설치 및 Spring Legacy Project 최초 생성, 오류 해결 (0) | 2021.06.15 |
TIL_210610_Spring Framework 개념 (0) | 2021.06.10 |