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

전자 도서관 프로젝트 - 도서 대출 관련 기능 구현을 위한 준비

YJ_ma 2023. 12. 3. 16:40

도서관을 이용한느 사용자가 도서를 대출하는 기능을 구현한다.

 

패키지와 클래스 생성하기

실습에 필요한 패키지와 클래스를 만들고 데이터베이스에 도서 대출 테이블(tbl_rental_book)도 생성해본다. 

com.office.library.book.user 패키지와 클래스를 다음과 같이 만든다.

※ BookVo는 com.office.library.book 패키지에 관리자와 사용자 공용으로 사용하고 있어 별도로 생성하지 않는다.

생성된 도서 대출 관련 패키지와 클래스

빈 충돌 에러

앞에서 생성한 클래스들을 스프링 IoC 컨테이너에 빈으로 등록하기 위한 설정을 한다.

package com.office.library.book.user;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/book/user")
public class BookController {

}
package com.office.library.book.user;

import org.springframework.stereotype.Service;

@Service
public class BookService {

}
package com.office.library.book.user;

import org.springframework.stereotype.Component;

@Component
public class BookDao {

}

 

컨트롤러, 서비스, DAO를 모두 만들고 프로젝트를 실행하면 다음과 같은 에러가 발생하는 것을 확인할 수 있다.

프로젝트 실행 시 에러 발생

 

이는 ConflictingBeanDefinitionException 에러로, BookController 빈이 동일한 이름으로 이미 존재해서 충돌이 발생하는 것이다.

빈은 스프링 IoC 컨테이너에 등록될 때 클래스 이름의 첫 글자를 소문자로 변경해서 빈을 구분하는 이름(ID, 아이디)으로 사용한다. 그런데 이번에 만든 BookController의 경우 com.office.library.book.admin 패키지의 BookController와 동일한 이름(bookController)이기 때문에 충돌이 발생하게 된다.

 

해결 방법 1: 빈의 아이디 다르게 설정하기

빈의 아이디를 다르게 하면 해결할 수 있다. com.office.library.book.admin과 com.office.library.book.user 패키지의 BookController의 @Controller를 다음과 같이 수정한다.

■ book.admin의 BookController.java

//@Controller
@Controller("admin.BookController")
@RequestMapping("/book/admin")
public class BookController {...}

 

■ book.user의 BookController.java

//@Controller
@Controller("user.BookController")
@RequestMapping("/book/user")
public class BookController {...}

 

이렇게 하면 book.admin과 book.user 패키지의 BookController는 서로 다른 아이디를 가지게 되어 출동을 피할 수 있다.

서비스와 DAO 역시 동일한 아이디를 갖지 않도록 수정해야 한다.

 

■ book.admin의 BookService.java

//@Service
@Service("admin.BookService")
public class BookService {...}

 

■ book.user의 BookService.java

//@Service
@Service("user.BookService")
public class BookService {...}

 

■ book.admin의 BookDao.java

//@Component
@Component("admin.BookDao")
public class BookDao {...}

 

■ book.user의 BookDao.java

//@Component
@Component("user.BookDao")
public class BookDao {...}

 

이제 프로젝트를 다시 실행하면 정상적으로 실행되는 것을 확인할 수 있다.

빈 충돌을 피해서 정상적으로 실행된 프로젝트

 

해결 방법 2: BeanNameGenerator 사용하기

스프링에는 BeanNameGenerator 인터페이스가 있다. 이 BeanNameGenerator를 이용하면 동일한 이름의 클래스를 다르게 빈으로 등록할 수 있다. 

① 우선 com.office.library.config 패키지를 생성한다.

② com.office.library.config 패키지에 LibraryBeanNameGenerator.java 클래스를 생성한다.

③ BeanNameGenerator 인터페이스를 추가하기 위해서 Interfaces의 <Add> 버튼을 클릭한다.

④ [Implemented Interfaces Selection] 창이 나오면 BeanNameGenerator를 입력하고 <OK>을 클릭한다. 

 

LibraryBeanNameGenerator.java를 다음과 같이 코딩한다.

package com.office.library.config;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;

public class LibraryBeanNameGenerator implements BeanNameGenerator {

	@Override
	public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {

		return definition.getBeanClassName();
	}

}

 

이제 빈의 아이디를 생성하는 LibraryBeanNameGenerator를 만들었으므로 스프링 컨테이너가 생성될 때 LibraryBeanNameGenerator를 이용하게 하면 된다. servlet-context.xml의 <context:component-scan>을 다음과 같이 수정한다.

● before

<context:component-scan base-package="com.office.library" />

● after

<context:component-scan base-package="com.office.library"
	name-generator="com.office.library.config.LibraryBeanNameGenerator" />

 

이제 다시 이전상태로 복원하고 프로젝트를 실행하여 정상적으로 수행되는지 확인해본다.

수행 결과

 

빈이 생성될 때 아이디가 구분된 것을 확인할 수 있다.