본문 바로가기
MyBatis

[MyBatis] 소개, MyBatis 세팅(1/2)

by moca7 2024. 10. 10.

 

 

ㅁ Framework

- 개발자가 보다 편리한 환경에서 개발할 수 있도록 제공되는 틀, 뼈대

- 공통적으로 사용되는 라이브러리, 개발도구, 인터페이스 등을 의미한다.

 

 

(1) 프레임워크의 장점

- 처음부터 다 만들 필요가 없다. 이미 만들어진 기능을 가져다 사용만 하면 된다. 

(효율성이 높고 품질이 보장된다) 

- 개발방법이 이미 정해져있다. 프레임워크마다 자기 사이트에서 가이드라인을 제공한다.

(개발의 표준화로 생산성이 높아진다) (개발 후 유지보수 및 기능의 확장이 용이하다)

- 개발자를 위한 다양한 도구들이 지원된다.

 

- 프레임워크가 나오고부터 유지보수 전문 업체들(sm)이 생겼다. 

그 전에는 만든 사람만이 유지보수를 할 수 있었다.

프레임워크를 쓰고부터는 모든 개발자가 같은 가이드라인을 쓰기 때문에 다른사람이 유지보수를 할 수 있다.

 

 

(2) 프레임워크의 단점

- 처음 습득하는데 오랜 시간이 걸린다.

- 개발 방법이 정해져있으므로 자유롭고 유연하게 설계 및 코딩하는데 제약이 있다.

- Framework에 의존하게 되면 개발 실력이 떨어질 수 있다.

 

 

(3) 프레임워크의 필요성

- 프로젝트 규모가 커질수록 복잡도가 높아지고 다수의 개발자가 필요하다.

모든 개발자들이 "통일성있게 빠르고 안정적"으로 개발하기 위해 프레임워크가 좋은 대안이다.

 

 

 

 

 

ㅁ 프레임워크의 종류

 

 

(1) 영속성 프레임워크(persistence framework)

 

- 데이터의 CRUD를 보다 편하게 할 수 있도록 제공하는 프레임워크

- 영속성 프레임워크는 2가지로 나뉜다.

SQL Mapper(개발자가 직접 쿼리문을 작성하는 MyBatis와 Hibernate)

ORM(개발자가 쿼리문을 작성하지 않고 메소드 호출만으로 처리하는 JPA)

 

- 간단한 프로젝트가 아닌 대규모 프로젝트에서는 JPA를 사용하는 것이 어렵다.
- 한국에서는 MyBatis를 많이 사용하며, 데이터베이스 설계 시 ERD 기반으로 설계한다. (JPA는 ERD가 아닌 자바 객체 기반 설계)

 

 

(2) 자바 프레임워크

 

- 웹 애플리케이션에 초점을 맞춰 필요한 요소들을 모듈화해서 제공해주는 프레임워크

- 자바 프레임워크 중 대표적인 것이 Sping Framework다. 

- 큰 회사일수록 옛날 기술을 쓰는데 Struts를 쓸 수도 있다. 스프링을 배웠다면 그렇게 어렵진 않다.

 

 

(3) 화면구현 프레임워크

 

- Front-End를 보다 쉽게 구현할 수 있게 제공해주는 프레임워크

- BootStrap, MDL 등

 

 

(4) 기능 및 지원 프레임워크

 

- 업무 수행에 도움을 줄 수 있는 기능을 제공하는 프레임워크

- Log4j, JUnit 등

 

 

 

 

 



ㅁ MyBatis

- MyBatis도 스프링도 프레임워크 중의 하나다.

 

- 이때까지 dao단에서 JDBC과정을 진행했었다.

JDBC 과정에 필요한 객체 Connection, PreparedStatement, ResultSet 등을 가지고 쿼리문을 수행하고,

쿼리문이 미완성인 상태면 직접 값을 채웠다.

쿼리 수행 후 조회결과를 vo객체나 list에 매핑하는 것도 직접 했었다.

이게 legacy한 JDBC과정이다.

 

- MyBatis를 적용하면 쿼리문 가지고 CRUD하는 과정이 굉장히 간결해진다.

dao의 메소드 하나당 코드가 엄청 길었는데 MyBatis를 적용하면 한 줄로 줄어든다.

 

 

 

ㅁ MyBatis Framework

- 데이터 CRUD를 보다 편리하게 하기 위해서 xml로 구조화한 Mapper 파일을 통해 JDBC 과정을 보다 편리하게 할 수 있는 영속성 프레임워크 (persistence framework).

- 기존의 JDBC 코드의 상당부분을 차지했던 파라미터 설정(물음표 자리 채우기) 및 결과 매핑(rset으로부터 값을 뽑아서 자바객체에 담기)xml 설정을 통해 쉽게 구현 가능. 

- 내부적으로 우리가 진행했던 JDBC 과정이 진행된다.

- 동적 쿼리 기능 지원

 

- 원래는 MyBatis가 아니라 Apache재단의 ibatis였다. 팀 자체가 구글로 이동하면서 Google MyBatis로 변경되었다.

ibatis는 사라진 것은 아니고 업데이트가 끊김. 기능만 지원된다.

 

 

 

 

 

=============================================================================

 

 

 

 

ㅁ 새로운 워크스페이스와 새로운 프로젝트를 만든다.

 

 

(1) C:\workspaces에 '06_mybatis-workspace' 폴더를 만든다.

 

 

 

(2) 이클립스로 '06_mybatis-workspace' 워크스페이스를 실행한다.

 

 

 

(3) 워크스페이스 세팅, 서버세팅을 한다.

- https://moca7.tistory.com/192

 

 

 

 

 

- 추가로 한가지 세팅을 더 한다.

- Web - JSP Files - Editor - Templates - 'New JSP File (html 5)' 

 

 

 

 

- 'New JSP File (html 5)'를 edit으로 수정한다. 

- 'New JSP File (html 5)'이 우리가 이때까지 만들었던 JSP 파일의 템플릿이다. 

JSP 파일을 만들 때 템플릿을 선택할 수 있었는데 선택하지 않고 만들었었다.

알게모르게 선택된게 HTML 5로 되어있는 것이다. 그래서 항상 저 구문이 쓰여진 채로 만들어졌었다.

 

 

 

 

 

 

 

- JSP 파일 만들때 마다 상단에 taglib 지시어에 core 라이브러리를 선언하기 귀찮아서 core 라이브러리 연동 구문이 쓰여진 채로 만들어지게 설정한다.

- 첫번째로 core 라이브러리를 가져오는 taglib 지시어를 작성한다.

- 두번째로 context path를 동적으로 알아내는 구문을 작성한다.

여기서 el 구문의 $를 쓰고싶으면 달러를 두 개 써야 한다. 실제로는 달러 1개로 만들어진다. 

 

 

 

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<c:set var="contextPath" value="$${pageContext.request.contextPath}" />

 

- 오타가 있으면 안 된다. 

- 닫는 태그도 있어야 한다. <c:set>은 액션태그이기 때문에 종료태그가 필요하다.

- 이제 jsp 파일을 만들면 저 구문들도 쓰여진 채로 만들어진다.

 

 

 

- (서버 설정) 서버 포트번호는 8888, serve modules without publishing 체크하고 저장하고 껐다. 

 

 

 

 

 

 

(4) 동적 웹 프로젝트 생성

 

 

- Target runtime에 아까 만든 서버가 기본적으로 선택되어 있다.

- Dynamic web module version이 4.0인지 확인.

 

 

 

 

 

- default output folder를 src/main/webapp/WEB-INF/classes로 수정한다.

 

 

 

 

 

 

 

- context root를 mybatis로 수정한다.

- web.xml 파일도 생성되도록 체크한다.

 

 

 

 

 

 

 

 

 

 

 

 

(5) webapp/WEB-INF/lib 폴더에 라이브러리 추가하기

 

 

- c:\dev에서 ojdbc6.jar, taglibs-standard-impl-1.2.5.jar, taglibs-standard-spec-1.2.5.jar, mybatis-3.5.14.jarsrc/main/webapp/WEB-INF/lib에 추가한다.

- db 연동을 위해 ojdbc6.jar를 추가한다.

- JSTL 태그 사용을 위해 taglibs-standard-impl-1.2.5.jar, taglibs-standard-spec-1.2.5.jar를 추가한다.

- MyBatis 사용을 위해 mybatis-3.5.14.jar도 추가한다. 

 

 

 

 

 

ㅁ webapp 폴더에 index.jsp를 만든다.

 

 

 

- templates에 추가한 두 줄이 보인다.

 

 

 

 

 

 

 

ㅁ 서버에 'add and remove'로 프로젝트 올리고 서버 start하고 메인페이지 들어가보기

 

 

- http://localhost:8888/mybatis/

 

 

 

 

 

===================================================================================

 

 

 

 

ㅁ 이제부터는 views 폴더의 세부 페이지들을 webapp 폴더가 아니라, WEB-INF 폴더에 둔다.

- 나중에 sping 프로젝트하면 폴더도 기본적으로 만들어지는데, 그때 views 폴더가 WEB-INF 폴더에 만들어진다.

- 그런데 views가 WEB-INF 폴더에 들어가는 순간, url에 jsp 경로를 쳐서 직접 가볼 수가 없다.

WEB-INF 폴더는 WAS가 관리하는 폴더여서 무조건 서블릿에서 포워딩 방식으로만 볼 수 있다.

정적으로 페이지를 요청해도 볼 수 없다(404 오류뜸).

 

 

 

 

 

- src/main/webapp/WEB-INF/views에 main.jsp를 만든다.
- 세부페이지든 메인페이지든 다 views 폴더 안에 두고 싶다면, index.jsp가 로드될 때 main.jsp에 포워딩되게끔 하면 된다.

- 처음에 로드되는 페이지는 index.jsp다. 이건 정해져 있다.

index.jsp가 로드되는 순간 main.jsp로 포워딩을 시킨다. WEB-INF 폴더 안의 페이지는 무조건 포워딩으로만 볼 수 있다.

 

 

 

 

- <jsp:forward page="/WEB-INF/views/main.jsp" />

jsp에서 jsp로 포워딩하는 액션태그. page 속성의 값으로 포워딩할 페이지 경로를 작성한다. contextPath는 제외하고 작성한다.

- 포워딩의 특성상 현재 저 페이지의 경로가 url에 노출되지는 않는다.

 

 

 

 

- http://localhost:8888/mybatis/를 요청해도 index.jsp가 아닌 main.jsp가 뜬다.

 

 

 

 

 

=========================================================================

 

 

 

 

ㅁ src/main/java에 패키지 생성

 

 

com.br.mybatis.member.controller

com.br.mybatis.member.service

com.br.mybatis.member.dao

com.br.mybatis.member.dto

 

com.br.mybatis.notice.controller

com.br.mybatis.notice.service

com.br.mybatis.notice.dao

com.br.mybatis.notice.dto

 

com.br.mybatis.common.dto

com.br.mybatis.common.template

com.br.mybatis.common.handler

com.br.mybatis.common.filter

com.br.mybatis.common.utils

 

 

- vo, service, dao 앞의 model은 생략했다.

- vo패키지를 dto로 바꿨다. 

vo를 dto 클래스라고도 한다. data transper object.

회사마다 vo, dto 다르게 쓴다. 

 

 

- 패키지 구조를 첫번째와 두번째 레벨은 도메인의 역순, 세번째 레벨은 주로 애플리케이션명을 딴다.

- 스프링을 쓰면 3번째 레벨까지 프로젝트 생성시 base 패키지를 지정하는데, 3번재 레벨이 context path가 된다.

- 모든 패키지가 com.br.mybatis를 깔고 가기 때문에 이걸 베이스 패키지라고도 한다. 

 

 

 

 

 

ㅁ 폴더 만들기

- src/main/webapp/WEB-INF/views 폴더에 member, notice 폴더 생성.

 

 

 

 

ㅁ 클래스 만들기

 

 

(1) com.br.mybatis.member.dto에 MemberDto를 만든다.

- 이때까진 그냥 Member로 했는데 뒤에 Dto, DTO, D를 붙이곤 한다.

 

 

 

 

- 관심분야 필드를 전처럼 String 타입이 아닌 String[]로 받아본다.

컴마 구분자로 쪼개서 String[]로 바로 받을 수 있는 기능을 MyBatis에서 제공한다.

 

- sql developer에서 기존의 SERVER 계정의 MEMBER 테이블의 컬럼을 가져와서 필드들을 작성한다.

- 기본생성자, 매개변수생성자, 게터세터, toString가지 만든다.

 

 

 

 

(2) com.br.mybatis.notice.dto에 NoticeDto를 만든다.

 

 

 

- 작성일도 DATE 타입 말고 String으로 해본다. db에서 조회할 때 to_char 함수를 써서 문자열로 담는다.

 

 

 

 

 

====================================================================================

 

 

 

페이징 처리를 하기 위해서 com.br.mybatis.common.dto에 PageInfoDto를 만든다.

 

 

- 7개의 필드가 필요하다.

- 위의 4개 필드를 가지고 3개 필드를 구하는 구문을 매번 작성하기 귀찮으니까 모듈화한다.

4개 필드를 전달받아서 3개 필드를 구하고 pageInfo 객체로 생성해서 반환하는 클래스를 common.utils 패키지에 만든다.

 

 

 

 

- common.utils 패키지에 PagingUtil 클래스를 만든다.

 

 
package com.br.mybatis.common.utils;

import com.br.mybatis.common.dto.PageInfoDto;

public class PagingUtil {

    // listCount, currentPage, pageLimit, boardLimit을 전달받아
    // maxPage, startPage, endPage를 구해서
    // PageInfoDto에 담아서 반환한다.
   
    public static PageInfoDto getPageInfoDto(int listCount, int currentPage, int pageLimit, int boardLimit) {
       
        int maxPage = (int)Math.ceil((double)listCount/boardLimit); // 마지막 페이지 수(총 페이지 수)
        int startPage = (currentPage - 1) / pageLimit * pageLimit + 1;
        int endPage = startPage + pageLimit - 1;
        if(endPage > maxPage) {
            endPage = maxPage;
        }
       
        return new PageInfoDto(listCount, currentPage, pageLimit, boardLimit, maxPage, startPage, endPage);
       
    }
   
   
}
 

 

 

 

 

====================================================================================

 

 

 

ㅁ 필터 클래스를 만든다.

- 서블릿 이전에 Filter 클래스를 거쳐서 가면 서블릿마다 매번 반복되는 코드를 Filter 클래스에 작성할 수 있다.

서블릿이 실행되기 전에 매번 공통적으로 실행해야하는 구문을 필터로 정의해두고 해당 필터를 거쳐가게끔 등록할 수 있다.

이러면 매 서블릿마다 중복된 코드(post방식 - utf-8 인코딩 등)를 작성할 필요가 없다.

- Filter의 실행 시점은 서블릿의 전단계다.

- 서블릿이 다 끝나고도 Filter로 돌아오기 때문에 서블릿 실행 후에 공통적으로 작성할 코드도 Filter에 작성해도 된다.

 

 

- 서블릿처럼 일반클래스로 만들었다가 필터 역할의 클래스로 바꿔도 되지만 코드가 복잡하다.

 

 

 

 

- com.br.mybatis.common.filter 패키지에 EncodingFilter 필터 클래스(new - filter)를 만든다. 

 

 

 
package com.br.mybatis.common.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;

/**
 * Servlet Filter implementation class EncodingFilter
 */
@WebFilter("/EncodingFilter")
public class EncodingFilter extends HttpFilter implements Filter {
       
    /**
     * @see HttpFilter#HttpFilter()
     */
    public EncodingFilter() {
        super();
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        // place your code here

        // pass the request along the filter chain
        chain.doFilter(request, response);
    }

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
    }

}
 

 

 

- HttpFilter를 상속받고 Filter를 구현한다.

 

- 필터 객체가 생성된 후에 init() 메서드가 실행되고, doFilter 메소드가 실행된다.

- init() 메소드는 웹 애플리케이션이 시작될 때, 필터가 처음 로드될 때 한 번만 호출된다. 필터와 관련된 설정을 초기화한다.

- doFilter() 메소드는 클라이언트 요청이 들어올 때마다 실행된다.

 

 

 

- 서블릿 실행 전에 실행되어야 하는 구문이 있다면  doFilter 메소드에 작성하면 된다.

- doFilter 메소드의 주석은 다 지운다.

 

 

※ chain.doFilter(request, response)

- 이 코드는 지워서는 안 된다. 

이 코드를 지우면 필터만 실행되고 서블릿이 실행안된다.

- 지금은 필터를 하나만 두지만 여러 필터를 두는 경우 "다음 필터를 호출"한다.

필터가 이게 끝이면 "서블릿을 호출"한다.

 

- chain.doFilter(request, response); 코드를 기점으로 서블릿 실행 전에 공통적으로 실행시킬 코드서블릿 실행 후에 공통적으로 실행시킬 코드를 작성할 수 있다.

 

 

 

 

 
package com.br.mybatis.common.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;

/**
 * Servlet Filter implementation class EncodingFilter
 */
@WebFilter(filterName="encodingFilter", urlPatterns="/*")
public class EncodingFilter extends HttpFilter implements Filter {
       
    /**
     * @see HttpFilter#HttpFilter()
     */
    public EncodingFilter() {
        super();
    }

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

       
        // Servlet 실행 전에 공통적으로 실행시킬 코드
        // 요청 전송방식이 post방식일 경우 utf-8로 인코딩 처리
        if( ((HttpServletRequest)request).getMethod().equalsIgnoreCase("post") ){
            request.setCharacterEncoding("utf-8");
        }
       
       
        chain.doFilter(request, response); // 필터가 여러개일 경우 다음 필터를 호출하는 구문이 된다. 필터가 하나라면 서블릿을 호출하는 구문이 된다.
       
       
        // Servlet 실행 후에 공통적으로 실행시킬 코드
       
       
    }

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
    }

}
 

 

 

- 조건검사로 post방식일 때만 utf-8로 인코딩 처리를 한다.

- 그런데 서블릿에선 HttpServeltRequest인데 필터에서는 ServletRequest다.

ServletRequest가 HttpServeltRequest의 부모객체다.

- request 객체로부터 getMethod()를 실행하면 요청 전송방식을 알 수 있다.

그런데 getMethod()가 자식 클래스에만 정의되어 있어서 다운캐스팅한다.

- getMethod()의 반환값이 소문자, 대문자 섞여있을 수 있어서 equals 메소드 대신 equalsIgnoreCase() 메소드를 쓴다.

 

 

 

 

 

ㅁ 필터 등록

- 필터클래스를 모든 url 요청시마다 실행되게 하지 않고, 특정 url 요청시에만 이 필터를 거쳐가게끔 할 수 있다.

- 필터클래스를 만들었다고 무조건 서블릿 가기 전에 거쳐가는게 아니고, 어떤 url 요청시 이 필터를 거쳐가게 할건지 등록을 해야 한다.

 

 

ㅁ 필터 등록하는 방법

(1) web.xml에 등록하는 방법

(2) 어노테이션을 이용해서 등록하는 방법

- 둘 중 하나만 하면 된다. 어노테이션이 간단해서 어노테이션 방식으로 할 예정이다.

 

 

 

 

(1) web.xml에 등록하는 방법

 

 

- filter-name은 아무 이름이나 상관 없다.

- filter-class는 풀클래스명을 작성한다.

- filter-mapping의 url-pattern에 /*하면 모든 url 요청

- filter-mapping의 filter-name에 어떤 필터를 거쳐가게 할건지

 

- 주석처리하고 어노테이션으로 한다.

 

 

 

 

(2) 어노테이션을 이용해서 등록하는 방법