ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Mon/Feb/24 [Java/Spring/myBatis] Day38. myBatis 활용 게시판
    Study/2020 국비교육_Java 2020. 2. 24. 08:53

    Mon/Feb/24 [Java/Spring/myBatis] 

    Day38. myBatis 활용 게시판

     

    전체 코드 : https://github.com/ezerwi/lecture0224_myBatis
     

    ezerwi/lecture0224_myBatis

    lecture0224_myBatis. Contribute to ezerwi/lecture0224_myBatis development by creating an account on GitHub.

    github.com

    * 관습적으로 spring의 xml 파일명은 모두 소문자, 언더바_대신에 대시- 사용

    * Spring 사용 방식

    • 순수 eclipse + library 추가

    • 순수 eclipse에 STS 설치 ; 여기에 mybatis 플러그인 설치 가능

    • STS 설치된 eclipse 사용 ; Spring 전용 eclipse, library 사용하지 않고 library 갖고 있는 서버와 통신하기 위해 pom.xml에 사용할 libaray 지정, 인터넷이 안정적이어야 함

    * Controller

    • business logic 처리 ; 이전까지는 dao를 통해서 처리했으나, 여기서는 myBatis를 통해 처리

      • myBatis = business logic 처리하는 클래스[shopServiceImpl.java] + mybatis 이용하는 클래스[shopDaoImpl.java]

      • 일반적인 SpringMVC와는 다르게 @Controller @RequestMapping 등 annotation 사용하여 하나의 클래스에서 다수의 Method 선언으로 처리

        • GET/POST 에 따라 Method도 분리

     

    Project Explorer

    DAO 영역과 Service 영역을 완전히 분리

     - DAO에서 Query 안 씀

     

    web.xml - context-spring.xml - context-mybatis.xml 흐름

    web.xml 수정

    <servlet>
      	<servlet-name>spring</servlet-name>
      	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      	<init-param>
      		<param-name>contextConfigLocation</param-name>
      		<param-value>
      			classpath:resources/spring/context-spring.xml
      			classpath:resources/spring/context-mybatis.xml
      		</param-value>
      	</init-param>
    </servlet>
    
    <servlet-mapping>
      	<servlet-name>spring</servlet-name>
      	<url-pattern>/</url-pattern>
    </servlet-mapping>

    context - import : spring.xml, mybatis.xml 

    <init-param> initial parameter

    • <param-name> contextConfigLocation 안에 있는 두가지 xml 을

    • <param-value>를 통해 찾음

    • 대소문자/오타 절대 틀리면 안됨

    • 이 xml에서 한글 encoding 까지 해줌 - <filter> 필요

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

    한글 Encoding을 위한 Filter 지정

     

    context-spring.xml 수정

    <context:component-scan base-package="org.mybatis" />
    	<mvc:annotation-driven />
    	<mvc:default-servlet-handler />

    context 로 "org.mybatis" package 를 사용

    <mvc:default-servlet-handler> 를 통해

    viewResolver의 ​​<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView" />를 대체함

     

    context-mybatis.xml 수정

    <util:properties id="database"
    					location="classpath:resources/spring/database.properties" />
    					
    	<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
    		<property name="driverClass" value="#{database['database.driverclass']}" />
    		<property name="url" value="#{database['database.url']}" />
    		<property name="username" value="#{database['database.username']}" />
    		<property name="password" value="#{database['database.password']}" />
    	</bean>
    	
    	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    		<property name="dataSource" ref="dataSource" />
    		<property name="typeAliasesPackage" value ="org.mybatis.domain" />
    		<property name="mapperLocations" value = "classpath:resources/mybatis/*.xml" />
    	</bean>
    	
    	<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    		<constructor-arg index="0" ref="sqlSessionFactory" />
    	</bean>
    	
    	<tx:annotation-driven transaction-manager="transactionManager"/>
    	
    	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource"></property>
    	</bean>
    • 이전에 Context::Resource를 통해 JDBC 접속 지정해줬던 내용을 database.properties 파일에 저장

    • mybatis에서 properties 파일을 읽을 수 있는 util (org.springframework.jdbc.datasource.SimpleDriverDataSource)을 사용해 읽어들임

    • sqlSessionFactory : sql 관련 bean 객체를 만들 수 있는 Factory bean

      • <property>아래 3가지는 필수 요소

        • datasource : 어떤 datasource를 이용할 건지 지정

        • typeAliasesPackage : DTO 역할을 해줄 클래스 위치 지정

        • mapperLocations : myBatis SQL Query가 어디에 있는지 지정

        • 위의 Java 파일 경로 pattern 과 xml 파일 경로 pattern 다른 점 주의할 것

          • JavaClass : org.mybatis.domain ; '.'으로 구분

          • xml파일 : classpath:resources/mybatis/*.xml ; '/'로 구분

    • sqlSessionTemlplate : myBatis에서 사용하는 SQL Template

      • 위에서 만든 sqlSessionFactory 를 참조하여 주입

      • 앞으로 SQL Query를 위해 갖다 쓸 객체

    • annotation으로 transactionManager 객체 생성하고 - datasource 관리를 위해 transactionManager 사용

     

    Annotation

    •  @로 시작하는 Java의 주석문

    • Syntax : @Keyword ex)@Component

    • 역할 : Class와 연관되어 annotation과 연관있는 class를 import

    • 목적

      • 환경설정에 관한 annotation(xml에서 사용)

      • JavaCoding 간결화 (Java Code를 대신 실행)

      • 필수 요소는 아님

    • 장점

      • 시스템 복잡성이 아니라면 annotation 사용은 코드가 간결해지고 유지보수가 용이해지는 적합성을 가짐

      • 대형 시스템에서는 계층구조 파악 용이를 위해 xml 사용이 필수이므로 annotation 사용시 편리해짐

    • 단점

      • annotation 과 관련된 class와 같이 연동하며 배우지 않고서는 이해가 어려움

      • 가장 큰 단점; 뭔가 변경되면 Java Code를 뜯어고쳐야 함 ; Java Code에서 자동주입하기 때문에

    • <context:component-scan base-package="com.spring.anno.context" />

      • com.spring.anno.context 패키지를 찾아 모든 하위 class들 중 @Component 가 부여된 객체를 자동으로 Bean 객체로 등록

    • 그 외 종류

      • @Repository : 저장소 의미

      • @Service : 

      • @Controller

      • @RequestMapping(value="/shop")

      • @Resource : 객체들(DAO) 자동주입에 사용

      • @RequestMapping(value="/list", method=RequestMethod.GET)

      • @RequestMapping(value="/view/{shopNo}", method=RequestMethod.GET)

        • url pattern / 전달할 {변수명} / 전송 방식 method 설정

      • 이외에도 수십개의 annotation 들이 있음

     

    resources.mybatis > ShopMapper.xml

    <mapper namespace="org.mybatis.persistence.ShopMapper"></mapper>

    namespace 값은 전체 프로젝트에서 유일한 명칭이어야 함

    <resultMap> 

    <resultMap type="shop" id="shopResultMap">
    	<id column="SHOP_NO" property="shopNo"/>
    	<result column="SHOP_NAME" property="shopName"/>
    	<result column="SHOP_LOCATION" property="shopLocation"/>
    	<result column="SHOP_STATUS" property="shopStatus"/>
    </resultMap>

    SQL-JavaClass에서 fieldName 다름에도 자동주입 가능하도록 설정(Mapping)

    JavaCode (property)와 SQL Field (column)을 대응시켜 자동주입 가능하도록; 둘이 같으면 굳이 쓸 필요 없음

    type : shop.java 클래스 사용

    <select> select query; 목록 조회 mapping

    <select id="list" parameterType="Shop" resultMap="shopResultMap">
    	SELECT SHOP_NO, SHOP_NAME, SHOP_LOCATION, SHOP_STATUS
    	FROM SHOP
    	<where>
    		<if test="shopNo>0"> AND SHOP_NO= #{shopNo} </if>
    		<if test="shopStatus != null and shopStatus != ''"> AND SHOP_STATUS = #{shopStatus}</if>
    	</where>
    </select>

    여기에 입력되는 값이 #이라는 객체

    <insert> sequence 조회 후 insert

    <insert id="insert" parameterType="shop">
    	<selectKey keyColumn="SHOP_NO" keyProperty="shopNo" resultType="int" order="BEFORE">
    		SELECT SEQ_SHOP_NO.NEXTVAL
    		FROM DUAL
    	</selectKey>
    	INSERT INTO SHOP (SHOP_NO, SHOP_NAME, SHOP_LOCATION, SHOP_STATUS)
    	VALUES (#{shopNo}, #{shopName}, #{shopLocation}, #{shopStatus})
    </insert>

    #{shopNo} 대신에 SELECT SEQ_SHOP_NO.NEXTVAL FROM DUAL을 직접 넣어도 됨

    <select> 세부 내용 조회 query

    <select id="select" parameterType="java.lang.String" resultMap="shopResultMap">
    	SELECT SHOP_NO, SHOP_NAME, SHOP_LOCATION, SHOP_STATUS
    	FROM SHOP
    	WHERE SHOP_NO = #{shopNo}
    </select>

    parameterType은 위와 같이 shop으로 넣어도 동일

    <update> 수정 query

    <update id="update" parameterType="shop">
    	UPDATE SHOP
    	<set>
    		<if test="shopName != null">SHOP_NAME = #{shopName}, </if>
    		<if test="shopLocation != null">SHOP_LOCATION = #{shopLocation}, </if>
    		<if test="shopStatus != null">SHOP_STATUS = #{shopStatus}, </if>
    	</set>
    	WHERE SHOP_NO = #{shopNo}
    </update>

    <delete> 삭제 query

    <delete id="delete" parameterType="java.lang.String">
    	DELETE FROM SHOP
    	WHERE SHOP_NO = #{shopNo}
    </delete>

     

    org.mybatis.persistence > ShopDaoImpl.java

    import org.mybatis.spring.support.SqlSessionDaoSupport;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class ShopDaoimpl extends SqlSessionDaoSupport implements ShopDao {
    

    위의 sql 내용을 사용하기 위해

    • SqlSessionDaoSupport 상속

    • @Repository 추가

    리스트 조회 ; getSqlSession 객체 생성 - selectList Method 내부에서 알아서 ResultSet 가져옴

     

    @Override
    	public List<Shop> list(Shop shop) {
    		return getSqlSession().selectList("org.mybatis.persistence.ShopMapper.list", shop);
    	}

    나머지 query 수행도 마찬가지

    sqlSessionTemplate 를 Resource로 설정 ; 자동주입 위해, Sql 작업을 수행을 위해 모든 것을 갖고 있는 객체

    @Override
    	@Resource(name="sqlSessionTemplate")
    	public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate){
    		super.setSqlSessionTemplate(sqlSessionTemplate);
    	}

    Context-mybatis에 설정된 이름과 동일해야 함

    super = 부모 객체 ; SqlSessionDaoSupport에게 전달

     

    ShopServiceImpl.java

    ShopDaoImple.java에서 만들것을 사용하기 위한 클래스

    import org.mybatis.domain.Shop;
    import org.mybatis.persistence.ShopDao;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    /*
     * <mvc:annotation-driven />
     * <mvc:default-servlet-handler />
     */
    
    @Service
    public class ShopServiceimpl implements ShopService {

    @Service - 만들어진 것을 사용한다는 것을 표현해주는 annotation

    	@Override
    	public List<Shop> find(Shop shop) {
    		return this.shopDao.list(shop);
    	}
    
    	@Override
    	@Transactional
    	public void add(Shop shop) {
    		this.shopDao.insert(shop);
    	}

    DB 내용을 그대로 불러오는 list / select 연산과는 달리

    add / delete / update를 위해서는 기존 내용을 변경하므로 @Transactional 필요

     

    org.mybatis.presentation > ShopController.java

    일반 Spring MVC Model에서 기능별로 Controller를 만들었던 것과 다르게, 하나의 Class에 모든 기능을 담을 수 있음

    필요한 Classes import

    import java.util.List;
    
    // 사용자가 만든 classes
    // Shop Model, ShopService Interface
    import org.mybatis.domain.Shop;
    import org.mybatis.service.ShopService;
    
    // Annotation 을 위한 classes
    import javax.annotation.Resource;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    // Spring Framework 기본구조에 사용되는 classes
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.view.RedirectView;

    Methods 내용입력

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public ModelAndView list(Shop shop) throws Exception {
        
    		List<Shop> listShop = this.shopService.find(shop);
    
    		ModelAndView mav = new ModelAndView("/shop/list");
    		mav.addObject("listShop", listShop);
    
    		return mav;
    	}
        
    @RequestMapping(value = "/edit", method = RequestMethod.POST)
    public ModelAndView edit(Shop shop) throws Exception {
    
    		RedirectView rv = new RedirectView("list");
    		rv.setExposeModelAttributes(false);
    
    		this.shopService.edit(shop);
    
    		return new ModelAndView(rv);
    	}

    변수를 전달할 필요 없는 경우 RedirectView 객체 생성하고

    setExposeModelAttributes(false)로 변수 전달 안하도록 설정

     

     

    참고할 사이트 : https://mybatis.org/spring/ko/index.html MyBatis에서 직접 소개하는 MyBatis-Spring 연동
     

    mybatis-spring – 마이바티스 스프링 연동모듈 | 소개

    MyBatis-Spring 은 무엇일까? 마이바티스 스프링 연동모듈은 마이바티스와 스프링을 편하고 간단하게 연동한다. 이 모듈은 마이바티스로 하여금 스프링 트랜잭션에 쉽게 연동되도록 처리한다. 게다가 마이바티스 매퍼와 SqlSession을 다루고 다른 빈에 주입시켜준다. 마이바티스 예외를 스프링의 DataAccessException로 변환하기도 하고 마이바티스, 스프링 또는 마이바티스 스프링 연동모듈에 의존성을 없애기도 한다. 동기 부여 스프링 2.x은

    mybatis.org

     

    댓글

Designed by Tistory.