본문 바로가기

Spring Framework

5. 1행만 조회하기

Controller

@PostMapping("/login")
public class MemberController{

    private Logger logger = LoggerFactory.getLogger(MemberController.class);
    
    @Autowired
    private MemberService service;
    
    public String login(@ModelAttribute Member inputMember) {
    
    	logger.info("로그인 기능 수행 중");
        
        // 아이디, 비밀번호가 일치하는 회원 정보를 조회하는 Service 호출 후 결과 반환 받기 
        Member loginMember = service.login(inputMember);
        
        return "redirect:/";
	}
}

@Autowired ? 

- 의존성 주입(DI)을 자동으로 처리하기 위하여 사용하는 어노테이션. 

  * 의존성 주입: 한 객체가 다른 객체를 사용할 때 필요한 객체를 직접 생성하는 것이 아니라, 다른 객체로부터 주입받음. 

                       이를 통해 코드의 유연성과 재사용성을 높일 수 있음. 

- 생성자, setter, 필드에 적용할 수 있음 

- bean으로 등록된 객체 중 타입이 같거나 상속 관계인 bean을 주입해 줌.

 

 

Service 

// Service Interface
public interface MemberService{
	public abstract Member login(Member inputMember);
}
// ServiceImplement Class

@Service // 비즈니스로직(데이터 가공, DB 연결)을 처리하는 클래스임을 명시 + bean으로 등록
public class MemberService implements MemberService{

    private MemberDAO dao;
    
    @Override
    public Member loign(Member inputMember){
    	Member loginMember = dao.login(inputMember);
        return loginMember;
    }

}

* Service를 하나의 클래스가 아닌, 인터페이스로 사용하는 이유 

 1. 프로젝트에 규칙성 부여 

   : Service는 비즈니스 로직을 담고 있는 기능들의 집합으로, 이를 인터페이스로 정의하여 규칙성을 부여한다. 

 2. Spring AOP

   : AOP(Aspect Oriented Programming)은, 프로그래밍에서 공통적으로 발생하는 부가적인 기능(로깅, 보안, 트랜잭션 등)을 모듈화하여 관심사의 분리를 통해 코드의 재사용성과 유지보수성을 향상시키는 프로그래밍 패러다임으로, 관심사를 중심으로 기능을 모듈화하고 이를 여러 모듈에서 공통적으로 사용할 수 있도록 한다. 

 3. 클래스 간의 결합도를 약화(유지보수성 향상) 

   :  인터페이스를 사용하면 Service 인터페이스를 구현하는 여러 클래스를 작성할 수 있고, 이를 통해 각각의 클래스는 인터페이스를 구현하면서도 자신만의 독자적인 기능을 추가할 수 있다. 그러하므로 결합성이 낮춰지면 유지보수성이 향상되고 수정이 용이해진다. 이는 객체지향프로그래밍에서 중요한 개방-폐쇄 원칙을 준수하게 되는 것이다. 

 

* Connection을 Service에서 얻어왔던 이유 

 - Service의 메서드는 하나의 요청을 처리하는 업무 단위로, 해당 업무가 끝난 후 트랜잭션을 한번에 처리하기 위하여 어쩔 수 없이 connection을 Service에서 얻어올 수밖에 없었다. 

 - 그러나, Spring에서는 Connection을 얻어오거나 반환할 때 트랜잭션 처리를 하는 구문을 적지 않아도 Spring에서 제어를 하기 때문에 Service 구문이 간단해진다. 

 

 

DAO

@Repository // 영속성을 가지는 DB, file과 연결되는 클래스임을 명시 + bean으로 등록 
public class MemberDAO {

    @Autowired
    private SqlSessionTemplate sqlSession;
    
    private Logger logger = LoggerFactory.getLogger(MemberDAO.class) 
    
    
    public Member login(Member inputMember){
    
    // 1행 조회(파라미터無) 
    // int count = sqlSession.selectOne("namespace값.id값");
    int count = sqlSession.selectOne("memberMapper.test1);
    
    // 1행 조회(파라미터有)
    String memberNickname = sqlSession.selectOne("memberMapper.test2", inputMember.getMemberEmail() );
    
    return null;
    }
    
}

 

* SqlSessionTamplate? 

 - DAO는 DB와 연결하기 위한 Connection이 공통적으로 필요하다. 일반 Servlet에서는 DB연결을 위해 Connection 객체를 생성하고, 데이터베이스와의 트랜잭션을 처리하기 위하여 Commit, Rollback 등으 메서드를 제공하였다. 

 - 이때, Spring에서는 DB연결, 트랜잭션 처리를 편리하게 할 수 있도록 지원하는 Java ORM(Object-Realation Mapping)프레임워크 중 하나인 Mybatis를 사용할 수 있다. 

  - Mybatis는 객체지향적 방식으로 SQL문을 작성하고, Mapping파일을 이용하여 SQL문과 자바 객체간의 매핑을 쉽게 처리할 수 있다. 

  - 여기서 DB와 연결을 담당하는 객체가 바로 SqlSession이고, 이 인터페이스를 구현하는 것이 바로 SqlSessionTamplate이다. 트랜잭션 관련 기능을 활용하여 SqlSession 객체를 관리한다. 

 - 필드에 SqlSessionTamplate을 선언하여 사용하는데, 이때 @Autowired를 하여 root-context.xml에서 생성된 SqlSessionTemplate bean을 의존성 주입한다. 

 

 

root-context.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:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
	
	<!-- Root Context: defines shared resources visible to all other web components 최상위 설정을 하는 공간 -->
	<!-- 프로젝트 시작하자마자 혹은 전반적으로 사용해야 하는 것들..  -->
	<!-- 
		root-context.xml 파일 
		 - web.xml 파일에서 가장 먼저 읽어들이는 설정 파일. 
		 - 프로젝트 전반적으로 사용되는 자원을 생성(bean 등록)하고 설정하는 파일. 
		 - DB 연결 관련 정보, 트랜잭션 처리, 파일 업로드 등을 작성 
	 -->
		
	<!-- 1. DBCP 사용을 위한 DataSource를 bean으로 등록 -->
	<!-- DataSource : java에서 Connection Pool을 지원하기 위한 인터페이스(Connection 상위호환) -->	
	<!-- destroy-method="close" : 주어진 세션 자동 반환 ex) conn.close(psmt); -->
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> 
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
		<property name="username" value="community"/>
		<property name="password" value="1234"/>
		
		<!-- SQL이 수행된 후 자동으로 Commit 되는것을 지정 -->
		<property name="defaultAutoCommit" value="false"/>
		
		<!-- 커넥션 풀 설정 -->
		<property name="initialSize" value="10" /> <!-- 초기 커넥션 수, 기본 0 -->
		<property name="maxTotal" value="50" /> <!-- 최대 커넥션 수, 기본 8 -->
		<property name="maxIdle" value="20" /> <!-- 유휴 상태로 존재할 수 있는 커넥션 최대 수, 기본 8 -->
		<property name="minIdle" value="10" /> <!-- 유휴 상태로 존재할 수 있는 커넥션 최소 수, 기본 0 -->
		<property name="maxWaitMillis" value="-1" /> <!-- 예외 발생 전 커넥션이 반환 될 떄 까지 대기하는 최대 시간(ms), 기본 -1(무기한) -->
	</bean>
	
	<!-- MyBatis 관련 Bean 생 -->
	
	<!-- SqlSession : sql구문을 DB에 전달, 실행하는 객체 
			SqlSessionFactory : SqlSession을 만드는 객체 
			sqlSessionFactoryBean : mybatis 설정 파일(mybatis-config.xml)과 Connection Pool 정보를 이용하여 SqlSessionFactory를 만드는 객체 
			sqlSessionTemplate : SqlSession 객체에 트랜잭션 처리 역할이 가능하도록 하는 객체 -->

	<!-- 마이바티스 SqlSession 등록하기 (xml 방식으로 bean 등록) -->
	<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- mybatis-config.xml 설정 불러오기 -->
		<property name="configLocation" value="classpath:mybatis-config.xml" />
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- SqlSessionTemplate : 기본 SQL 실행 + 트랜잭션 관리 역할을 하는 SqlSession을 생성할 수 있게 하는 객체(Spring bean으로 등록해야함.) -->
	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg ref="sqlSessionFactoryBean" />
	</bean>

	<!-- 스프링에서 사용하는 proxy를 이용한 트랜잭션 제어가 안될 경우 추가적인 트랜잭션 매니저를 추가해서 문제 해결 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	
	<!-- <tx:annotation-driven proxy-target-class="true"/> -->
	<tx:annotation-driven transaction-manager="transactionManager"/>
	
</beans>

 

 

mapper.xml

<?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="memberMapper">

    <!--  1행 조회(파라미터無) / 조회되는 데이터 타입: int -->
    <select id="test1" resultType="_int">
    	SELECT COUNT(*) FROM MEMBER
    </select>
    
    <!--  1행 조회(파라미터有) / 파라미터 타입: String / 조회되는 데이터 타입: String -->
    <select id="test2" parameterType="string" resultType="string">
    	SELECT MEMBER_NICK FROM MEMBER
        WHERE MEMBER_EMAIL = #{memberEmail}
        AND SECESSION_FL = 'N'
    </select>
    

</mapper>

* Mybatis에서의 #{}, ${} 

 - 기존 서블릿에서는 SQL문의 플레이스홀더를 ? 로 지정하였는데, spring에선 그렇게 할 수 없다. #{} 혹은 ${}을 사용하여야 한다. 

 - #{변수명} : SQL에 값이 포함될 때 양쪽에 '' 추가됨  → 리터럴 사용(값 자체로 사용) ... ex: pstmt

 - ${변수명} : SQL에 값이 포함될 때 양쪽에 '' 추가되지 않음  → SQL구문 조합 시 사용(condition) ... ex: stmt

 

 

'Spring Framework' 카테고리의 다른 글

4. Mybatis  (0) 2023.04.25
3. 파라미터 얻어오기, 화면 전환하기  (0) 2023.04.24
2. DispatcherServlet, logger  (0) 2023.04.22
1. Spring Framework란?  (0) 2023.04.22