Spring에서는 객체를 직접 new Service();와 같이 생성하지 않아도 사용할 수 있게 설정할 수 있다.


new Service와 같은 객체화를 Spring에 맡기는 것이다.


- 컨트롤러 -


@Controller
public class MemberController {
    // 의존성 주입용 필드 선언
    // 어노테이션 + Interface 타입
    @Autowired
    private MemberService ms;

    // 인터페이스를 상속받는 객체에 @Component나 @Service 어노테이션이 필요
    // 객체 생성 시 new Service와 같은 부분을 Spring에게 맡기는것.


}




- Service 인터페이스 -


public interface MemberService {

}


- Service -


// Component, Service 둘다 사용 가능
/*@Component*/
@Service
public class MemberServiceImpl implements MemberService {

}


위와 같은 Member java 파일들이 있다고 할 때


컨트롤러에서 객체를 자동 생성해 주는 부분은


@Autowired
private MemberService ms;


이 부분이다.


어노테이션 @Autowired를 위에 명시하고


객체화 할(MemberServiceImpl) Java 파일 상단에


서비스의 경우는


@Component


@Service


Dao의 경우는 @Repository


해당하는 어노테이션을 명시한다.







이런식으로 어노테이션을 명시해두면


@Autowired
private MemberService ms;


Autowired만으로도 MemberService가 MemberServiceImpl 자바 파일로 객체화 되어 생성된다.


Service나 Dao와 같은 Spring framework 에서 사용하는 기본 패턴의 경우는


@Component, @Service, @Repository와 같은 어노테이션으로 충분하다.


이 외에도 작성자가 계속 간단하게 사용하고 싶어서 임의로 만들고 싶다면 XML 파일에 등록해 두면 된다.










보통 Spring에서는 Service 부분에서 SqlSession 이라는 객체를 생성하여 DB에 접근하기 위한


객체를 만들게 된다.


예전에 JDBCTemplate이라고 Properties 파일을 이용해 설정을 받아


객체를 생성하여 DB를 조회한것과 유사하다.


먼저 SqlSession을 만들기 위해서 mybatis 라이브러리를 다운로드 해야한다.


pom.xml 파일을 열어


        <!-- Test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>



아래에 <dependency> 태그를 추가하자.


        <!-- jdbc 라이브러리 추가 -->
        <dependency>
            <groupId>com.jslsolucoes</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.1.0</version>
        </dependency>

        <!-- 마이바티스 라이브러리 추가 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>

        <!-- spring-jdbc 추가 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>

        <!-- 마이바티스 스프링 모듈 추가 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>

        <!-- dbcp 라이브러리 추가 -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>


이 태그를 입력하고 파일을 저장하면 Maven이 자동으로 라이브러리 다운로드를 시작한다.


Progress 탭을 보고 다운로드가 완료되면


Problems에서 빨간색으로 된 오류가 있는지 확인해보고


톰캣을 실행시켜 정상적으로 켜지는지 확인해보자.


만약 문제가 있다면 라이브러리가 다운받아지는 폴더인 repository의 폴더들을 삭제하고


프로젝트 우클릭 - Maven - 업데이트를 한번 하고 다시 시도해보자.


오류가 또 난다면 반복







라이브러리가 정상적으로 다운로드 됫다면 root-context xml 파일을 열자.


sqlSessionTemplate을 Bean에 등록하는 작업





    <!-- 데이터베이스 접속에 관련된 클래스들을 bean으로 등록할 수 있다. -->
    <!-- sqlSessionTemplate 등록 -->
    <!-- SqlSessionTemplate 기본 생성자가 비어있지 않기 때문에 아무것도 안넣으면 오류가 난다. -->
    <!-- 생성자 매개변수인 sqlSession을 추가해주자. -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg ref="sqlSession"></constructor-arg>
    </bean>
   
    <!-- sqlSession도 bean으로 등록한다. -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>
   
    <!-- dataSource 객체 bean 등록 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"></property>
        <property name="username" value="DB 계정이름을 써주세요"></property>
        <property name="password" value="DB 계정비밀번호를 써주세요"></property>
        <property name="defaultAutoCommit" value="false"></property>
    </bean>




위의 코드를 xml 파일 중간 부분에 아무대나 추가하면 된다.


자동으로 생성될 객체들의 생성자를 설정하는 부분이다.


sqlSessionTemplate은 sqlSession를 인자로 받아 생성되고


sqlSession은 dataSource를 인자로 받아 생성된다.


dataSource의 Property(매개변수 인자들)를 보면 driver 설정, url 설정, 접속계정 설정, 접속비번 설정


설정을 하고 생성하게 된다.


그리고 Auto Commit을 False로 두었을 때 여러개의 DB 작업을 하면


성공한 곳 까지는 commit이 자동으로 되기 때문에 나중에 트랜잭션(AOP를 이용) 기능을 설정해주어야 한다.




이번에는 bean 태그의 속성들을 보자


<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"></bean>


id, class를 입력받게 된다.


id는 변수명이라고 보면 되고


class의 경우는 내가 생성할 객체의 해당하는 파일의 위치를 말한다.


org.mybatis.spring 위치에 있는 SqlSessionTemplate 파일을 이용해서 생성한다는 의미




이와같이 root-context.xml에 명시를 하고 톰캣을 실행해보면 정상적으로 자동 생성되는 것을 확인 할 수 있다.


활용으로 자기가 만든 객체도 비슷하게 생성할 수 있다.














Spring IoC(Inversion of Control)란,


프로그램을 돌릴 때 객체 생성, 변경 등 관리를 개발자가 아닌


프로그램을 돌리는 컨테이너가 직접 관리하는 것을 말한다.


Spring Framework는 IoC 구조를 통해서 직접 관리를 수행하게 된다.


우리가 XML에 설정할 부분이 많은 이유이다.


Spring에서 관리하는 객체를 Bean이라고 하고 이 객체들을 관리하는 컨테이너를 Bean Factory라고 한다.


이러한 컨테이너들에 의해 객체의 생명주기와 의존성을 관리하고


코드의 구현시간을 단축하게 해 준다.


또한 메모리 사용에도 좀 더 효율적인 것으로 알 고 있다.







Spring DI(Dependency Injection)란


Spring에서 IoC 구현의 핵심 기술로 의존성 주입을 의미한다.


사용하는 객체들을 개발자가 생성하지 않고 개발자가 xml 파일에 설정해둔


xml 기록을 토대로 컨테이너가 객체에 연결해주는 방법이다.


이러한 방법을 사용하면 코드가 단순해지고


객체간의 결합도(종속 관계)가 느슨해진다.


결합도란 한 클래스에서 필드 객체를 생성 시 발생하는 두 객체 간의 관계를 말하며


객체간의 내용이 수정 될 경우 영향을 미치는 정도라고 한다.




이러한 방식은 프로젝트 협업 시 공동 작업을 하기 때문에 이러한 방법을 사용하면 편의성이 높아지고


모든 객체를 xml에서 간편하게 확인할 수 있다.


생성할 객체에는 꼭 getter, setter가 존재해야 한다.


그리고 자동으로 bean 객체를 찾아서(어노테이션) 생성하는 기능을 Bean Scanning이라고 한다.







MVC 구조를 이용한다.


먼저 Spring Framework의 생명주기, 쉽게 말하면 돌아가는 순서를 알아야한다.



이미지 출처 : https://terasolunaorg.github.io/guideline/1.0.1.RELEASE/en/Overview/SpringMVCOverview.html



위 그림을 Spring Framework의 생명주기라고 하는데


쉽게 말해서 그냥 돌아가는 구조를 말한다.


간단하게 Client(사용자) - Dispatcher Servlet - Controller - Service - Dao 순서로 흘러간다.


그리고 중간에 Dispatcher Servlet은 Handler Mapping의 도움을 받아 해당하는 Controller(맵핑주소)를 찾고


Controller는 DB를 조회하던 무었이던 설정해둔 코딩 그대로 역할을 하고


View로 사용자에게 결과를 리턴해준다.


해당하는 View를 찾아주는 기능은 View Resolver라고 한다.





큰 틀은 Client(사용자) - Dispatcher Servlet - Controller - Service - Dao 순서로 돌아가는데


그 외의 도움을 주는 기능들 Dispatcher Servlet, Handler Mapping, View Resolver 등을 우리가


XML 설정 파일을 이용해 설정해두어야 정상적으로 작동한다.







먼저 Java 파일의 소스를 살펴보자.


맨 처음 프로젝트를 생성 했을 때 있는 HomeController.java 파일이다.


import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HomeController {
   
    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
   
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Locale locale, Model model) {
        logger.info("Welcome home! The client locale is {}.", locale);
       
        Date date = new Date();
        DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
       
        String formattedDate = dateFormat.format(date);
       
        model.addAttribute("serverTime", formattedDate );
       
        return "home";
    }
   
}


Logger 부분은 로그 남기는 부분으로 나중에 따로 게시



먼저 @, 어노테이션을 보자.


@Controller = Spring Framework가 이 파일이 Controller인지 알기 위한 어노테이션


@RequestMapping = 핸들러 맵핑이 @RequestMapping가 써있는 메소드를 미리 찾아 value에 명시한 키워드를 기억하고 있다가


요청이 들어오면 연결시켜 준다.





보통 @RequestMapping는 뒤에 value와 method 인자를 갖고있고 (예 : (value = "/", method = RequestMethod.GET))


value 자리에는 맵핑 주소


method는 GET 방식 전달인지 POST방식 전달인지 정한다.


이 예제는 요청 주소가 '/'라면 GET 방식으로 값을 받아 동작하는 컨트롤러라는 의미이다.


함수명은 마음대로 사용해도 된다.





여기서 리턴 값은 home이라는 문자열이다.


이 리턴값을 이용해 View Resoler가 해당 페이지를 연결시켜 준다.


설정해둔 접두사 + 리턴값 + 접미사 형태로 합쳐져 url을 완성시킨다.


이 설정은 XML 파일에서 확인할 수 있다.


관련 xml 파일 : web.xml, ***-servlet.xml






web.xml 파일을 열어보면 중간에


    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/config/action-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
       
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>



라고 Servlet 설정을 해두었다.


여기서 url-pattern이 /인 경우 /WEB-INF/config/action-servlet.xml 파일의 설정을 이용한다는 의미이고


action-servlet.xml을 열어보면




    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>
   
    <context:component-scan base-package="com.kh.tsp" />




라는 구문으로 등록되어 있다.


beans:bean 태그에서 InternalResourceViewResolver 클래스를 이용(ViewResolver)


접두사 : /WEB-INF/views/


접미사 : .jsp


로 설정하고


Controller는 com.kh.tsp 패키지 경로 아래의 파일들을 모두 스캔한다.






아까 위의 HomeController를 이용해서 home이라는 문자열을 리턴받았다.


그렇다면 view resolver는 다음과 같은 결과로 url를 만든다.


"/WEB-INF/views/" + "home" + ".jsp"


"/WEB-INF/views/home.jsp"







이러한 원리로 Spring Framework에서는


Dispatcher Servlet과 Handler Mapping, Controller가 상호작용하여


작동하게 된다.







context.xml 파일들로 다양한 설정(서블릿 같은 기능을 하는 문구)들을 관리하게 되는데


한 context 파일을 사용하게 되면 설정이 너무 길어지므로


분류를 두어 나누는 것을 추천한다.


이 xml 파일들을 여러개 만들어 관리를 하지만


이 파일들을 읽어오라고 따로 명시를 해주어야 한다.


이에 대한 설정은 web.xml 이라는 파일에서 진행한다.





다음 예시는 root context를 webapp 바깥의 resources로 옮기고


WEB-INF 폴더 아래의 spring 폴더를 config로 이름을 바꾸고


servlet-context파일을 config로 옮긴 뒤 이름을 action-servlet으로 바꾼다.


위의 수정 내역을 web.xml 파일에 등록


먼저 context-param의 내용을 바꾼다.


    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:root-context.xml
        </param-value>
    </context-param>



다음으로는 Servlet 정보, servlet context 정보가 담겨있는


<servlet>태그, <servlet-mapping> 태그를 수정



    <servlet-name>action</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/config/action-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
       
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>




이와 같이 servlet-class를 통해서 Dispatcher Servlet을 사용한다고 명시하고


param name과 value를 통해 경로를 입력한다


load-on-startup는 로딩 순서이므로 그냥 적으면 되고


servlet-mapping을 통해서 맵핑 주소를 설정한다.


실행 테스트를 할 때 localhost:포트/키워드를 주소창에 입력했을때


자동으로 맨 뒤에 슬래시가 붙는데 localhost:포트/키워드/


슬래시의 맵핑 주소가 설정 된 곳으로 연결되게 된다.





또 하나의 예제로 member를 통해 맵핑 설정을 이해해보자.


    <servlet>
        <servlet-name>member</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/config/member-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>


    <servlet-mapping>
        <servlet-name>member</servlet-name>
        <url-pattern>*.me</url-pattern>
    </servlet-mapping>



*.me를 통해서 url 이 .me로 끝나는 연결은


/WEB-INF/config/member-servlet.xml 경로의 설정을 읽어서 연결을 한다.





보너스로 이와 같은 방법으로 Dispatcher Servlet을 이용하여 Encoding 타입을 바꾸는 방법은 다음과 같다.


    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>





Servlet에서는 필터 클래스를 생성하여 들어오는 모든 요청(/*)의 인코딩 타입을 UTF-8로 설정했지만


Spring에선 위와같이 명시하면 끝난다.










+ 추가 - context 파일에 들어가는 내용


Spring Framework는 객체를 생성 시 자동으로 new 객체()를 해주도록 설정 할 수 있다.


이 설정은 context.xml 파일들에서 설정하고


이러한 객체(예전에 VO 폴더에 만든 객체들)들을 bean 이라고 한다.


해당하는 서블릿으로 연결되면 bean들을 하나하나 생성 할 필요 없이 바로바로 사용 할 수 있게 설정하는 xml이다.








+ 추가 - context.xml 파일이 어떻게 맵핑 주소를 명시한 java 파일을 찾는가


context.xml의 내용을 보면


<context:component-scan base-package="패키지 명" />


context라는 태그가 존재하고 base-package라는 속성이 등록되어 있다.


base-package에 등록된 경로를 따라서 하위에 존재하는 java 파일들을 전부 스캔하여


@RequestMapping("맵핑 주소") 라는 어노테이션을 사용한 메소드들을 찾는다.


톰캣이 이를 가지고 있다가 맵핑 주소에 요청이 들어오면 해당하는 메소드에 연결해주는 방식이다.


bean 객체를 자동으로 잡아주는 방법도 있고 수동으로 등록을 해야 할 때가 있다.


자동으로 잡아주는 방식은 @Controller, @Service, @Repository와 같은 어노테이션으로 자동으로 잡히게 된다.


자세한 설명은 Autowired를 사용할때 게시합니다.





+ Recent posts