내가 실행하고 싶었던 쿼리

insert into board (seq, title, writer, content) 
values((select nvl(max(seq), 0)+1 from board),'안녕','안녕','안녕');

 

최종 수정/실행쿼리

insert into board (seq, title, writer, content) 
select coalesce(max(seq),0)+1 ,'안녕','안녕','안녕' from board;

 

** 알게된점

#1. mysql에는 nvl함수 없음
 coalesce(expr1,expr2)
  == CASE WHEN expr1 IS NOT NULL THEN expr1 ELSE expr2 END

 또는 isnull함수를 사용

 

#2. mysql에는 insert 의 values구문안에 select를 사용할 수 없음

최종 쿼리처럼 insert into 테이블명(속성) values(속성값) 가아닌,

insert into 테이블명(속성) select ~~ (속성값) from 테이블명 형식으로 써주어야 함

 

#3. 게시판 시퀀스번호 자동부여

max(seq)+1
 // 기존 seq의 최댓값 구하고 +1

어노테이션

 

어노테이션 설정 추가시, <bean>에 Context관련 namespace와 schema 문서위치 등록필요

 - namespace에서 context 체크박스 체크

자동 주소 추가됨

 

 

컴포넌트 스캔(component-scan) 설정

 - 사용할 객체들 <bean>에 등록하지 않고, 자동으로 생성할때 필요

 - <context:component-scan.>엘리먼트 정의

 - 설정 추가시, 스프링 컨테이너가 classpath에 있는 클래스 스캔해서, @Component가 설정된 클래스들 자동객체 생성함

 

src/main/resources/applicationContext.xml 

<beans>
	<!-- 해당 경로 클래스 스캔해서, @Component설정된 클래스 자동 객체 생성 -->
	<context:component-scan base-package="polymorphsim"></context:component-scan>
    
    <bean id="tv" class="polymorphsim.LgTV"></bean>
    
 </beans>

 

 

@Component

- 위에 applicationContext에 컴포넌트 스캔 설정했으면, 설정파일에 클래스들을 일일이 <bean>엘리먼트로 등록안해도됨

 - 컴포넌트 어노테이션은 클래스 위에 선언 ("변수")

package polymorphsim;

import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV{
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}
	public void powerOn() {
		System.out.println("LgTV --전원 켠다.");
	}
	public void powerOff() {
		System.out.println("LgTV --전원 끈다.");
	}
	public void volumeUp() {
		System.out.println("LgTV --소리 올린다.");
	}
	public void volumeDown() {
		System.out.println("LgTV --소리 내린다");
	}
}

 


의존성 주입 어노테이션

스프링에서 의존성 주입을 지원하는 어노테이션 

어노테이션 설명
@Autowired 변수위에 설정해서, 해당타입 객체 찾아서 자동할당
org.springframework.beans.factory.annotation.Autowired
@Qulifier 특정 객체 이름 이용, 의존성 주입시 사용
org.springframework.beans.factory.annotation.Qulifier
@Inject @Autowired와 동일기능 제공
javax.annotation.Resource
@Resource @Autowired + @Qualifier 기능 결합
javax.inject.Inject

 

 

@Autowired 

- 생성자, 메소드, 멤버변수 위에 모두 사용가능 (대부분은 멤버변수위에 선언)|
- 변수의 타입을 기준으로 객체를 검색하여 의존성 주입을 처리

- 스프링 컨테이너가 멤버변수 위에있는 어노테이션 확인하는 순간 변수타입 체크
  > 그 타입의 객체가 메모리 존재여부 확인 > 객체를 변수에 주입

- @Autowired가 붙은 객체가 메모리에 없으면, 컨테이너는 NoSuchBeanDefinitionException 발생시킴

  (=해당 어노테이션 대상 객체가 메모리에 존재하지 않음)

 ** 의존성 관계에 있는경우, 관련있는 객체가 메모리에 없는경우 에러가 발생함 (위 이미지처럼)

   관련있는 객체를 메모리에 생성하려면, applicationContext.xml에 아래 두가지 방법중 하나 

 

(1) <bean id="~" class="~"></bean> 의존관계 클래스를 bean을 명시하거나

(2) 의존관계 있는 클래스에 @Component("sony")처럼  어노테이션 설정해주기 
 > 단 <context:component-scan/>에 해당 패키지명이 명시되어있어야함

 

(예제는 컨테이너가 SonySpeaker객체를 speaker 변수에 자동 할당해준다고 )

 

 

@Qualifier

의존성 주입될 객체의 아이디나 이름을 지정할 수 있음.  

 

NoUniqueBeanDefinitionException ㅣ 의존성 주입대상 되는 Speaker타입 객체가 두개이상일때 문제  발생

SonySpeaker과, AppleSpeaker 객체가 모두 메모리에 생성되어있는 상태라면, 컨테이너는 어떤 객체를 할당할지 스스로 판별할수 없어서 에러발생 

 

 

이런경우, @Autowired되는 대상이 Speaker타입 객체가 AppleSpeaker, SonySpeaker 두개이고, 둘다 메모리에 생성된경우 발생함

해결하기 위해 @Qulifier어노테이션 사용, @AutoWired밑에 명시

 

src/main/java/polymorphsim/LgTV 

package polymorphsim;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component("tv")
public class LgTV implements TV{
	@Autowired
	@Qualifier("apple")
	private Speaker speaker;
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}
	public void powerOn() {
		System.out.println("LgTV --전원 켠다.");
	}
	public void powerOff() {
		System.out.println("LgTV --전원 끈다.");
	}
	public void volumeUp() {
		speaker.volumeUp();
		//System.out.println("LgTV --소리 올린다.");
	}
	public void volumeDown() {
		speaker.volumeDown();
		//System.out.println("LgTV --소리 내린다");
	}
}

 

실행결과

더보기

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'tv' with a different definition: replacing [Generic bean: class [polymorphsim.LgTV]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [C:\DEV\workspace_spring\BoardWeb\target\classes\polymorphsim\LgTV.class]] with [Generic bean: class [polymorphsim.LgTV]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [applicationContext.xml]]
INFO : org.springframework.context.support.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@69a10787: startup date [Wed Jan 05 00:52:33 KST 2022]; root of context hierarchy
INFO : org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
===> AppleSpeaker 객체 생성
===> LgTV 객체 생성
===> SonySpeaker 객체 생성
LgTV --전원 켠다.
AppleSpeaker-- 소리 올린다.
AppleSpeaker-- 소리 내린다.
LgTV --전원 끈다.
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@69a10787: startup date [Wed Jan 05 00:52:33 KST 2022]; root of context hierarchy

 

 

@Resource

- 객체의 이름을 이용하여 의존성 주입을 처리
 - name 속성을 사용, 스프링 컨테이너가 해당 이름으로 객체 검색해서 의존성 주입 처리

- Resource와 같은 기능의 어노테이션 @Inject 둘다 이름기반 의존성 주입

 

src/main/java/polymorphsim/LgTV 

package polymorphsim;

import org.springframework.stereotype.Component;
import javax.annotation.Resource;

@Component("tv")
public class LgTV implements TV{
	
	@Resource(name="apple")
	private Speaker speaker;
	
	public LgTV() {
		System.out.println("===> LgTV 객체 생성");
	}
	public void powerOn() {
		System.out.println("LgTV --전원 켠다.");
	}
	public void powerOff() {
		System.out.println("LgTV --전원 끈다.");
	}
	public void volumeUp() {
		speaker.volumeUp();
		//System.out.println("LgTV --소리 올린다.");
	}
	public void volumeDown() {
		speaker.volumeDown();
		//System.out.println("LgTV --소리 내린다");
	}
}

 >> apple 이름으로 메모리에 생성된 AppleSpeaker객체를 speaker변수에 할당

 

 

Spring 의존성 주입

  XML설정만 사용 Annotation 설정만 사용
장점 java소스 수정하지 않고, xml파일 설정만 변경. 유지보수 편리 - xml 설정에 대한 부담이 없음
- 의존관계에 대한 정보가 java소스에 있어서 사용하기 편리함
단점 - xml설정에 대한 부담감 있음. <bean>등록을 많이 해야함
- 의존관계 설정이 부담스러움
- java 소스에 의존관계와 메타데이터가 없어서, xml설정을 해석해야만 어떤 객체가 의존성 주입되는지 확인가능
- 의존성 주입할 객체의 이름이 자바소스에 명시되어야함.
- 소스 수정 없이 의존성 관계를 변경할 수 없음

** 결론 : 두개를 적절히 섞어서 쓰기

 변경되지 않는 객체는 어노테이션으로 설정하여 사용
 변경될 가능성이 있는 객체는 XML설정으로 사용

 

 

 

 

어노테이션 클래스 파일명 의미
@Service ~ServiceImpl  비즈니스 로직 처리 Service 클래스
@Repository ~DAO DB연동 처리 DAO 클래스
@Controller ~Controller 사용자 요청 제어 Controller 클래스

'IT > SPRING' 카테고리의 다른 글

[Spring Boot]  (0) 2023.06.02
[Spring] Interceptor  (0) 2023.06.02
[SPRING] 의존성 주입  (0) 2022.01.04
[SPRING] 스프링 컨테이너, applicationContext 설정파일  (0) 2022.01.03
[SPRING] 프레임워크 개요  (0) 2022.01.02

IoC(제어의 역행)

스프링 객체의 생성, 의존관계를 스프링에서 자동으로 관리

의존성(Dependency)는 객체와 객체와의 관계를 의미

 

Dependency Lookup : 컨테이너가 객체를 생성, 클라이언트는 생성한 객체를 검색해서 사용 (실 개발과정 미사용)

Denepdency Injection (Setter/Constructor Inection) : 컨테이너가 직접 객체들 사이에 의존관계를 처리

 - Setter과 Constructor의 공통점 : 멤버변수를 원하는 값으로 설정하는것 목적
 - 결과는 같으므로 어떤방법 쓰던지 상관없음
    단, 코딩컨벤션 따라 한가지로 통일. 대부분은 Setter사용 / Setter메소드 제공되지 않는 클래스만 생성자인젝션

 

생성자 인젝션(Constructor Injection)

 - xml에서 클래스 찾아서 객체생성시, 매개변수 없는 기본생성자를 호출

 - 기본생성자 외에 매개변수를 가지는 다른 생성자 호출하도록 생성할 수 있음

 - 생성자 인젝션을 사용해서, 생성자의 매개변수(예시:sony)로 의존관계에 있는 객체주소 정보 전달가능

 - 예시 : <constructor-arg index="0" ref="apple"></constructor-arg> <constructor-arg index="1" value="2000000"></constructor-arg>

이클립스 자동 생성자 추가

생성하려는 클래스 열고 > alt + shift + s > Generate Constructor using Fields> 초기화할 멤버변수 선택후 OK

 

 

src/main/java/polymorphsim/SonySpeaker.java

package polymorphsim;

public class SonySpeaker {
	public SonySpeaker() {
		System.out.println("===> SonySpeaker 객체 생성");
	}
	public void volumeUp() {
		System.out.println("SonySpeaker---소리 울린다.");
	}
	public void volumeDown() {
		System.out.println("SonySpeaker---소리 내린다.");
	}
}

src/main/java/polymorphsim/SamsungTV.java

package polymorphsim;

public class SamsungTV implements TV{
	private SonySpeaker speaker;
	private int price;

	public SamsungTV() {
		System.out.println("===> SamsungTV(1) 객체생성");
	}
	public SamsungTV(SonySpeaker speaker) {
		System.out.println("===> SamsungTV(2) 객체생성");
		this.speaker=speaker;
	}
	
	public SamsungTV(SonySpeaker speaker, int price) {
		System.out.println("===> SamsungTV(3) 객체생성");
		this.speaker = speaker;
		this.price = price;
	}
	public void powerOn() {
		System.out.println("SamsungTv --전원 켠다. (가격: "+price+")");
	}
	public void powerOff() {
		System.out.println("SamsungTv --전원 끈다.");
	}
	public void volumeUp() {
		speaker.volumeUp();
	}
	public void volumeDown() {
		speaker.volumeDown();
	}
}

src/main/resources/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 ="tv" class="polymorphsim.SamsungTV">
		<constructor-arg index="0" ref="sony"></constructor-arg>
		<constructor-arg index="1" value="2000000"></constructor-arg>
	</bean>
	<bean id = "sony" class="polymorphsim.SonySpeaker"></bean>
    
</beans>

 

실행결과

더보기

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
INFO : org.springframework.context.support.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@290dbf45: startup date [Tue Jan 04 00:06:47 KST 2022]; root of context hierarchy
===> SonySpeaker 객체 생성
===> SamsungTV(3) 객체생성
SamsungTv --전원 켠다. (가격: 2000000)
SonySpeaker---소리 울린다.
SonySpeaker---소리 내린다.
SamsungTv --전원 끈다.
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@290dbf45: startup date [Tue Jan 04 00:06:47 KST 2022]; root of context hierarchy

 

  • 객체 생성할때, 기본생성자가 아닌, 세번째 SaumsungTV(Speaker speakr, int price) 생성자가 사용됨.
  • bean등록 순서대로 객체를 처리하는데, 생성자 인젝션으로 의존성 주입될 SonySpeaker가 먼저 객체생성SonySpeaker 객체를 매개변수로 받아들이는 생성자를 호출하여 객체 생성
  • <constructor-arg>엘리먼트의 인자로 전달될 데이터가 <bean>인 다른 객체인경우 ref속성, 고정 문자열/정수인경우는 value
  • 생성자 여러개 오버로딩 된 경우, index속성 통해 어떤값이 몇번째 매개변수로 매핑되는지 지정가능. 0부터시작

 

이클립스 자동 인터페이스 생성

생성할 인터페이스의 자식 열고 > alt + shift + T > Extract Interface> 생성할 인터페이스 이름/메소드 선택후 OK

 * 체크박스 전체해제

 

src/main/resources/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 ="tv" class="polymorphsim.SamsungTV">
		<constructor-arg index="0" ref="apple"></constructor-arg>
		<constructor-arg index="1" value="2000000"></constructor-arg>
	</bean>
	<bean id = "sony" class="polymorphsim.SonySpeaker"></bean>
	<bean id = "apple" class="polymorphsim.AppleSpeaker"></bean>
    
</beans>

자바코드 수정없이, <constructor-arg 의 ref를 "sony"대신 "apple"로 변경하여 AppleSpeaker호출가능

 

<추가 생성/수정한 파일>

(interface) Speaker.java

(class) SonySpeaker.java

(class) AppleSpeaker.java

(class) SamsungTV.java >> 매개변수/멤버변수를 SonySpeaker대신, Speaker로 변경

 


Setter Injection

- Setter메소드 호출해서 의존성 주입을 처리

- 대부분 생성자 주입 보다 setter 주입 사용

- Setter메소드는 스프링 컨테이너가 자동으로 호출, 호출시점은 <bean> 객체 생성 직후
  Setter인젝션 동작하려면, Setter메소드 뿐만 아니라, 기본 생성자도 반드시 필요

- 예시 : <constructor-arg index="0" ref="apple"></constructor-arg> <constructor-arg index="1" value="2000000"></constructor-arg>

 

이클립스 자동 생성자 추가

생성하려는 클래스 열고 > alt + shift + s > Generate Getter and Setters > 초기화할 멤버변수 선택후 OK

 

src/main/resources/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 ="tv" class="polymorphsim.SamsungTV">
		 <!-- Setter 주입 -->
		 <property name="speaker" ref="apple"></property>
		 <property name="price" value="2000000"></property>
	</bean>
    
	<bean id = "sony" class="polymorphsim.SonySpeaker"></bean>
	<bean id = "apple" class="polymorphsim.AppleSpeaker"></bean>
</beans>

 

  • <property> 엘리먼트사용 필요, name속성값이 호출하려는 메소드이름
    - Setter 메소드 이름 : setSpeaker()
    - name 속성값 : name ="speaker"  (첫문자 대문자로 바꾸고 set붙인 차이..)
  • 생성자주입처럼, Setter 메소드 호출하면서 다른 <bean>객체를 인자로 넘기려면 ref속성, 기본형데이터는 value속성

실행결과

더보기

INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
INFO : org.springframework.context.support.GenericXmlApplicationContext - Refreshing org.springframework.context.support.GenericXmlApplicationContext@69a10787: startup date [Tue Jan 04 00:37:45 KST 2022]; root of context hierarchy
===> SamsungTV(1) 객체생성
===> AppleSpeaker 객체 생성
===> setSpeaker() 호출
===> setPrice() 호출
===> SonySpeaker 객체 생성
SamsungTv --전원 켠다. (가격: 2000000)
AppleSpeaker-- 소리 올린다.
AppleSpeaker-- 소리 내린다.
SamsungTv --전원 끈다.
INFO : org.springframework.context.support.GenericXmlApplicationContext - Closing org.springframework.context.support.GenericXmlApplicationContext@69a10787: startup date [Tue Jan 04 00:37:45 KST 2022]; root of context hierarchy

 

p 네임스페이스 사용

applicationContext.xml에 추가

xmlns:p="http://www.springframework.org/schema/p"

 

구분 규칙
참조형 변수에 객체 할당 p:변수명-ref = "참조할 객체의 이름이나 아이디"
p:speaker-ref="sony" 
기본형이나 문자형에 직접 값 설정 p:변수명="설정할 값"
p:price='2000000"

 

(p네임스페이스 적용전)

<bean id ="tv" class="polymorphsim.SamsungTV" >
   <property name="speaker" ref="apple"></property>
   <property name="price" value="2000000"></property>
</bean>

 

(p 네임스페이스 적용후)

</bean id="tv" class="polymorphsim.samsungtv" p:speaker-ref="sony" p:price="2000000">

 

 

 sts기능으로 p네임스페이스 추가방법

 


 

컬렉션 객체 설정

스프링에서 컬렉션 매핑과 관련된 엘리먼트들을 지원. 

컬렉션 유형 엘리먼트 비고
java.util.List, 배열 <list> 리스트
java.util.Set <set> 중복미허용
java.util.Map <map> key,value
java.util.Properties <props> key=value

 

List

src/main/java/com/springbook/ioc/injection/CollectionBean.java

package com.springbook.ioc.injection;

import java.util.List;
import java.util.Set;

public class CollectionBean {
	private List<String> addressList;
	public void setAddressList(List<String> addressList) {
		this.addressList = addressList;
	}
	
}

 

 

src/main/resources/applicationContext.xml

	<bean id ="collectionBean" class="com.springbook.ioc.injection.CollectionBean">
		<property name="addressList">
			<list>
				<value>경기도</value>
				<value>서울</value>
			</list>
		</property>
	</bean>

 

--> applicationContext에도 <list>엘리먼트 사용

 

Set (중복미허용)

src/main/java/com/springbook/ioc/injection/CollectionBean.java

package com.springbook.ioc.injection;

import java.util.List;
import java.util.Set;

public class CollectionBean {
	private Set<String> addressList;
	public void setAddressList(Set<String> addressList) {
		this.addressList = addressList;
	}
	
}

 

src/main/resources/applicationContext.xml

	 <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>

--> applicationContext에도 <set value-type="java.lang.String" > 엘리먼트 사용

set이 중복 제거해주므로, 출력결과는 서울시 강남구, 서울시 강서구 2건만 나옴

 

 

main

package com.springbook.ioc.injection;

import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.Properties;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.springbook.ioc.injection.CollectionBean;

public class CollectionBeanClient {
	public static void main(String[] args) {
		
		AbstractApplicationContext factory = new GenericXmlApplicationContext("applicationContext.xml");
		CollectionBean bean = (CollectionBean) factory.getBean("collectionBean");
        // List, Set, Map, Properties에 맞게 변경
		Set<String> addressList = bean.getAddressList();
		
		for(String address : addressList) {
			System.out.println(address.toString());
		}
		factory.close();
	}
}

+ Recent posts