멀티캠퍼스 백엔드 과정43일차-44일차[8월 4일, 8월 7일] - intellj, mariadb, mapper, tdd, 의존성 주입

GoldenDusk·2023년 8월 7일
0
post-thumbnail

💫 8월 4일

📌 mvc 예제

  • EL 표기법을 쓰도록 노력하자
  • test.jsp
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<html>
<head>
    <title>test</title>
</head>
<body>
<form action="calcResult.jsp" method="post">
    <input type="number" name="num1"/>
    <input type="number" name="num2"/>
    <button type="submit">send</button>
</form>
</body>
</html>
  • calcResult.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>calcResult</title>
</head>
<body>
<%
    int num1= Integer.parseInt(request.getParameter("num1"));
    int num2= Integer.parseInt(request.getParameter("num2"));
%>

결과 : <%= num1 + num2 %>

<%--원래 문자 타입인데 + 연산자가 있어서 자동으로 Integer.parseInt처리
웹 파라미터는 모두 문자열--%>
<h1>${param.num1}+${param.num2} = ${param.num1+param.num2}</h1>
<h1> sum : ${Integer.parseInt(param.num1) + Integer.parseInt(param.num2)}</h1>

</body>
</html>

📌 경로설정(자꾸 헤갈린다.)

  1. calcResult.jsp 파일이 webapp 폴더의 바로 아래에 있을 경우:
javaCopy code
req.getRequestDispatcher("/calcResult.jsp").forward(req, resp);
  1. calcResult.jsp 파일이 webapp 폴더 아래의 calc 폴더 안에 있을 경우:
javaCopy code
req.getRequestDispatcher("/calc/calcResult.jsp").forward(req, resp);
  1. calcResult.jsp 파일이 WEB-INF 폴더 아래의 calc 폴더 안에 있을 경우:
javaCopy code
req.getRequestDispatcher("/WEB-INF/calc/calcResult.jsp").forward(req, resp);
  • WEB-INF : 사용자가 데이터를 입력하는 화면만 볼 수 있게 하고, 결과창은 웹브라우저로 사용자가 볼 수 없게 넣어둔다는 의미

📌 1. 마리아 디비 설정하기

  • 사용자 관리자 추가 > 비번이랑 이름 넣고 > 객체 추가

  • 파일 > 세션관리자

📌 2. 인텔리제이 설정

  • 밑에 다운로드 누르기 > Test Connection 해보기

Maven Repository: Search/Browse/Explore

  • gradle에 붙여넣기

📌 3. jUnit 테스트, 단위 테스트

package com.multicampus.dao;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mariadb.jdbc.Driver;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;

public class ConnectTests {

    //TDD, Test 어노테이션 이용
    @Test
    public void test1(){
        int v1 = 10;
        int v2 = 20;

        // assertEquals 같다고 확신합니다라는 의미로 같아야 테스트 가능
        Assertions.assertEquals(v1, v2);
    }

    @Test
    public void testConntion() throws Exception {
        Class.forName("org.mariadb.jdbc.Driver");
        Connection connection = DriverManager.getConnection(
                "jdbc:mariadb://localhost:3306/webdb",
                "webuser",
                "webuser"
        );

        Assertions.assertNotNull(connection);
        connection.close();
    }
}

💫 8월 7일

1. 스프링과 톰캣

  • 둘은 역할을 분리해서 서버를 운영

💡 스프링은 비즈니스 로직과 데이터 액세스를 처리하고, 톰캣은 사용자 요청을 받아서 애플리케이션과 상호 작용해 동적인 웹 페이지를 제공해. 스프링은 서비스 레이어에서 비즈니스 로직을 구현하고, DAO 패턴을 이용해 데이터베이스와의 상호 작용을 캡슐화해. 이렇게 역할을 분리해서 서버를 운영하면 애플리케이션의 유지 보수성과 확장성을 향상시킬 수 있어.

📌 스프링(Spring)

  1. 비즈니스 로직
  • 스프링은 비즈니스 로직을 담당
  • 비즈니스 로직은 애플리케이션의 핵심 로직으로 데이터 처리, 계산, 비즈니스 규칙 적용 등을 포함합니다. 스프링은 이러한 비즈니스 로직을 모듈화하고 추상화하여 높은 수준의 유연성과 재사용성을 제공합니다. 스프링은 일반적으로 서비스(Service) 레이어에서 비즈니스 로직을 구현하는 데 사용됩니다.
  1. DAO(Data Access Object): 스프링은 데이터베이스와의 상호 작용을 담당하는 DAO 패턴을 구현하는 데 도움을 줍니다. DAO는 데이터베이스와의 CRUD(Create, Read, Update, Delete) 연산을 추상화하여 데이터 액세스를 캡슐화합니다. 이렇게 하면 비즈니스 로직에서 데이터베이스 액세스와 관련된 세부 사항을 분리할 수 있습니다. 스프링은 일반적으로 DAO 패턴을 사용하여 데이터 액세스 계층을 구현하는 데 사용됩니다.

📌 톰캣(Tomcat)

  • 사용자 요청 처리: 톰캣은 웹 서버(WEB Server)와 서블릿 컨테이너(Servlet Container)의 기능을 제공합니다. 사용자가 웹 브라우저를 통해 애플리케이션에 접속하면, 톰캣은 해당 요청을 받아서 처리합니다. 톰캣은 정적인 웹 페이지와 동적인 서블릿, JSP(JavaServer Pages) 등을 처리하여 사용자에게 응답을 제공합니다. 톰캣은 스프링의 비즈니스 로직과 DAO와는 직접적인 관련이 없으며, 단지 사용자의 요청을 받고 애플리케이션과 상호 작용하는 역할을 담당합니다.

2. 오픈 소스를 활용한 스프링 프레임워크

라이브러리 추가

  • build.gradle에 dependency에 추가
  • 같은 버전으로 설치하게 유의하자

  • spring core, spring context, spring test

Maven Repository: org.springframework » spring-core

implementationgroup:'org.springframework',name:'spring-core',version:'5.3.19'
implementationgroup:'org.springframework',name:'spring-context',version:'5.3.19'
testImplementation group: 'org.springframework', name: 'spring-test', version: '5.3.19'
  • Lombok library : dao만들 때 좀 더 편안하게 작업
//Lombok library - dao만들 때 좀 더 편안하게 작업
compileOnlygroup:'org.projectlombok',name:'lombok',version:'1.18.24'
annotationProcessor'org.projectlombok:lombok:1.18.24'
testCompileOnly'org.projectlombok:lombok:1.18.24'
testAnnotationProcessor'org.projectlombok:lombok:1.18.24'
  • Log4j2 테스트 설정
//@Log4j2 테스트 설정, logging : api
    implementation group:'org.apache.logging.log4j', name:'log4j-core', version: '2.17.2'
    implementation group:'org.apache.logging.log4j', name:'log4j-api', version: '2.17.2'
    implementation group:'org.apache.logging.log4j', name:'log4j-slf4j-impl', version: '2.17.2'
  • jstl : jsp을 이용해 화면 구성하니
implementationgroup:'jstl',name:'jstl',version:'1.2'

3. 의존성 주입

📌 설정 파일을 이용해 컨테이너에 등록해주는 예제 - 필드 설정

예제

  • bean은 객체
  • root-context는 pojo를 컨테이너에게 등록하게 해주는 xml 파일 ⇒ spring_config로 만들기
    • 스프링 프레임워크에서 관리해줘야 하는 객체
  1. spring 컨테이너

  1. root-context.xml에 bean 등록

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="com.multicampus.springex.sample.SampleDAO"></bean>
    <bean class="com.multicampus.springex.sample.SampleService"></bean>
</beans>
  1. 세팅을 해줘야 함
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="com.multicampus.springex.sample.SampleDAO"></bean>
    <bean class="com.multicampus.springex.sample.SampleService"></bean>
</beans>

  1. resourse에 log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--테스트 환경 레벨을 정함-->
<Configuration status="INFO">
    <!--Appenders은 pattern으로 만들어서 console를 뿌리겠다 선언한 것-->
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <!--console에 위에 것을 등록-->
    <Loggers>
        <!--additivity="false"를 설정하면 해당 로거가 부모 로거의 설정을 상속받지 않는다., 독립적인 로그 레벨을 가지게 됨-->
        <logger name="org.springframework" level="INFO" additivity="false">
            <appender-ref ref="console"/>
        </logger>
        <logger name="com.multicampus" level="INFO" additivity="false">
            <appender-ref ref="console"/>
        </logger>

        <Root level="info" additivity="false">
            <AppenderRef ref="console"/>
        </Root>
    </Loggers>
</Configuration>
  1. 테스트 코드 작성

🍀 테스트 결과의 의미
1) 테스트 코드가 실행되기 위해 스프링 프레임워크가 동작
2) 동작하는 과정에서 필요한 객체들이 스프링에 등록
3) 의존성 주입이 필요한 객체는 자동으로 주입

  • @Autowired
💡 - spring에서 사용하는 `의존성 주입 어노테이션` - 어노테이션을 필드,생성자,메서드에 적용하여 **스프링 컨테이너**가 해당 타입의 빈(Bean) **객체를 자동으로 주입** - 해당 타입의 빈이 존재한다면 여기에 주입해주기를 바란다. 즉 ,스프링 컨테이너가 필요로 하는 빈 객체를 자동으로 주입받기 위해 사용되며, 주입받은 빈 객체를 사용하여 필드에 대한 작업을 수행할 수 있다. 이를 통해 스프링의 `IoC (Inversion of Control) 원칙을 구현`하여 객체 간의 의존성을 스프링 컨테이너가 관리하도록 한다. - 개발자가 직접 객체들과의 관계를 관리하지 않고 자동으로 관리되어서 변수의 같은 타입의 객체가 주입
  • @ExtendWith(SpringExtension.class)
    • spring-test를 이용하기 위한 설정 Junit5버전, Junit4는 @Runwith 사용
  • @ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/root-context.xml")
    • 지정된 클래스나 문자열을 이용해서 필요한 객체들을 스프링 내에 객체 등록(스프링의 빈으로 등록한다는 의미)
  • Lombok의 @Log4j2

  • Lombok 라이브러리에서 제공하는 어노테이션으로, 로깅(loggin) 기능을 자동으로 구현해주는 기능을 제공
  • 별도의 Logger 객체의 선언이 없이도 Log4j 라이브러리 설정이 존재한다면 바로 사용 가능
  • 로깅 코드를 직접 작성하지 않아도 되므로 코드가 간결해지고 유지보수가 용이
  • 자바 개발자들이 보일러플레이트 코드(중복적이고 반복적인 코드)를 줄이기 위한 라이브러리
  • 코드
package com.multcampus.springex.sample.SampleTests;

import com.multicampus.stringex.sample.SampleService;
import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@Log4j2
@ExtendWith(SpringExtension.class) //spring-test를 이용하기 위한 설정 Junit5버전, Junit4는 @Runwith 사용
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/root-context.xml")
public class SampleTests {

    @Autowired // spring에서 사용하는 의존성 주입 어노테이션
    // 어노테이션을 필드, 생성자, 메서드에 적용하여 스프링 컨테이너가 해당 타입의 빈(Bean) 객체를 자동으로 주입
    // 해당 타입의 빈이 존재한다면 여기에 주입해주기를 바란다.
    // 스프링 컨테이너가 sampleService를 넣어줌?
    private SampleService sampleService;

    @Test
    public void testService(){
        log.info(sampleService);
        Assertions.assertNotNull(sampleService);
    }

	// injection 되는지 확인하는 테스트 코드
    @Test
    public void testSampleDAO(){
        log.info(sampleDAO);
        Assertions.assertNotNull(sampleDAO);
    }
}
  1. SampleService
package com.multicampus.springex.sample;

import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@ToString
@Service
@RequiredArgsConstructor
public class SampleService {

   private SampleDAO sampleDAO; //필드 주입
}
  1. SampleDAO
package com.multicampus.springex.sample;

public class SampleDAO {
}

Application Context

  • Application Context 용어
    • 스프링이 빈들을 생성, 관리하는 공간으로 컨테이너 역학
    • 빈(bean) 자체는 스프링 애플리케이션 컨텍스트(Application Context)의 일부
    • 스프링에서 "빈(bean)"은 스프링 컨테이너에 의해 관리되는 객체를 의미합
    • 빈 객체들은 스프링 애플리케이션 컨텍스트에 등록되어 관리
    • 스프링 애플리케이션 컨텍스트는 빈들의 라이프사이클을 관리하고, 필요한 시점에 빈들을 생성하고 의존성을 주입하며, 소멸시키는 등의 작업을 수행
    • cf. 서블릿 컨텍스트(Servlet Context) : 서블릿 컨텍스트가 모여있는 공간
  • root- context에 동작원리
    1. Context[스프링에서는 ApplicationContext] : 스프링 프레임워크가 시작되면 먼저 스프링이 사용하는 메모리 영역을 만들게 됨
    2. root- context.xml : 스프링은 자신이 객체를 생성하고 관리해야 하는 객체들에 대한 설정이 필요
    3. root-context.xml에 설정되어 있는 <context:componet-scan> 태그의 내용을 통해서 ‘org.zerock.sample’에 패키지 스캔
    4. 해당 클래스에 클래스들 중에서 스프링이 사용하는 @Component라는 어노테이션이 존재하는 클래스의 인스턴스 생성
    5. @Autowired로 주입 : 해당 인스턴스 변수가 스프링으로부터 자동으로 주입해달라는 표시
  • Application Context 어노테이션
    • @Controller : MVC의 컨트롤러를 위한 어노테이션
    • @Service : 서비스 계층의 객체를 위한 어노테이션
    • @Repository : DAO 와 같은 객체를 위한 어노테이션
    • @Component : 일반 객체나 유틸리티 객체를 위한 어노테이션

어노테이션 정리

Lombok 관련 어노테이션Spring 관련 어노테이션테스트 관련 어노테이션
@Setter@Autowired@RunWith
@Data@Component@ContextConfiguration
@Log4j@Test
  1. Lombok 관련
  • 컴파일 시 흔하게 코드를 작성하는 기능 완성해주는 라이브러리
  • @Setter: setter 메서드를 만들어주는 역할
  • @Data : @ToString, @EqualsAndHashCode, @Getter/@Setter, @RequiredArgsConstructor 결합한 형태로 한 번에 자주 사용하는 모든 메서드들 생성
  • @Log4j : 설정되어 있다면 로그 객체 생성
  1. Spring 관련
  • @Component : 해당 클래스가 스프링에서 객체로 만들어서 관리하는 대상임을 명시 ⇒ 빈으로 관리
  • @Autowired : 스프링 내부에서 자신이 특정한 객체에 의존적이므로 자신에게 해당 타입의 빈을 주입하는 의미
  1. test 관련 어노테이션
  • @ContextConfiguration : 스프링이 실행되면서 어떤 설정 정보를 읽어 들여야 하는지 명시
  • @RunWith : 테스트 시 필요한 클래스 지정
  • @Test : Junit에서 해당 메서드가 JUnit 상에서 단위 테스트의 대상인지 알려준다.

📌 생성자 주입 @Autowired Setter 방식

스프링3(전자정부프레임워크) 이후 생성자 주입 (권장)

  • 주입 받아야 할 객체의 변수는 final 작성
  • 생성자를 이용해서 해당 변수를 생성자의 파라미터로 지정
    @RequiredArgsConstructor : Lombok에서 제공하는 생성자 주입 애너테이션

인터페이스를 이용한 느슨한 결합

  1. 의존성 주입
    Q. 좀 더 근본적으로 유연한 프로그램을 설계하려면?
    A. 인터페이스를 이용해서 나중에 다른 클래스의 객체로 쉽게 변경할 수 있다.
    각 계층마다 느슨한 결합을 한 서비스를 제공
    인터페이스를 이용하면 실제 객체를 모르고 타입만을 이용해서 코드 작성 가능
  2. 인터페이스 타입으로 서비스를 제공할때
    인터페이스 구현 객체가 여러개라면 특정 구현 클래스를 지정해주어야 한다.
    스프링컨테이너에게 알려줘야 한다.
    - 1개씩 직접 지정 : @Primary
    - 이름을 지정해서 특정한 이름의 객체를 주입 방식 : @Qualifier
    lombok.config 파일을 작성해서 환경셋팅

알아둬야 할 사항

Q1. 스프링의 빈(Bean)으로 지정되는 객체들은 무엇일까?
A.

  • "핵심배역" 객체들만 등록
  • 오랜 시간동안 프로그램내에 상주하면서 중요한 역할 하는 '역할'중심의 객체
  • DTO, VO ==> '데이터' 를 중점을 두고 설계 된 객체이므로 스프링빈으로 등록하지 않는다.

Q2. XML이나 애너테이션 으로 처리하는 객체 무엇일까?

  • 빈(Bean)으로 처리할때 "코드를 수정할 수 있는가" 기준으로 처리한다.
  • ex) jar파일로 추가되는 클래스의 객체를 스프링빈으로 처리해야 할때는 코드가 존재하지 않기때문에 애너테이션 처리가 불가하다.
  • XML에서 이용하여 처리해야 한다. 직접 작성되는 클래스는 애너테이션을 이용하는 것이 권장

📌 인터페이스를 이용한 느슨한 결합 예제

  1. SampleDAO -interface
package com.multicampus.springex.sample;

import org.springframework.stereotype.Repository;

public interface SampleDAO {
}
  1. 실제 구현 객체
package com.multicampus.springex.sample;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Repository;

@Repository
@Primary
public class SampleDAOImpl implements SampleDAO{
}
package com.multicampus.springex.sample;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

@Repository
@Qualifier("maria")
public class SampleDAOO_Mariadb_Impl implements SampleDAO{

}
package com.multicampus.springex.sample;

import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

@Repository
@Qualifier("oracle")
public class SampleDAOO_Oracle_Impl implements SampleDAO{
}
package com.multicampus.springex.sample;

import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@ToString
@Service
@RequiredArgsConstructor
public class SampleService {

    private  final SampleDAO sampleDAO; //객체와 객체의 의존관계의 실제 객체를 몰라도 주입이 가능하게 하는 방식 '느슨한 방식'
    // 스프링 컨테이너가 주입, set, get 필요가 없어지는
 /*   @Autowired
    *//*private SampleDAO sampleDAO; //필드 주입*/
}
  1. lombok.config
lombok.copyableannotations += org.springframework.bean.factory.annotation.Qualifier
  1. log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--테스트 환경 레벨을 정함-->
<Configuration status="INFO">
    <!--Appenders은 pattern으로 만들어서 console를 뿌리겠다 선언한 것-->
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
    </Appenders>
    <!--console에 위에 것을 등록-->
    <Loggers>
        <!--additivity="false"를 설정하면 해당 로거가 부모 로거의 설정을 상속받지 않는다., 독립적인 로그 레벨을 가지게 됨-->
        <logger name="org.springframework" level="INFO" additivity="false">
            <appender-ref ref="console"/>
        </logger>
        <logger name="com.multicampus" level="INFO" additivity="false">
            <appender-ref ref="console"/>
        </logger>

        <Root level="info" additivity="false">
            <AppenderRef ref="console"/>
        </Root>
    </Loggers>
</Configuration>
  1. 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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.multicampus.springex"/>
   </beans>
  1. build.gradle dependency에 추가
implementation group: 'org.springframework', name: 'spring-webmvc', version: '5.3.19'
  1. web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/root-context.xml</param-value>
    </context-param>

<!--    감시자를 넣음-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

4. MyBatis와 스프링 연동

📌 MyBatis란?(Sql Mapping Framework)

  • SQL 실행결과를 객체지향으로 매핑해준다는 뜻

스프링 프레임워크의 중요한 특징

  • 다른 프레임워크와 쉽게 결합해서 사용이 용이: 웹이나 데이터베이스 같이 특정한 영역을 구애받지 않고 시스템의 객체지향 구조를 만드는데 용이
  • 데이터베이스 관련 스프링프레임워크는 자체적 spring-jdbc 라이브러리가 존재하지만 MyBatis 나 JPA 프레임워크 를 이용하는 방식이 있다.

전통적인 JDBC 프로그램과 MyBatis의 차이

전통적인 JDBC 프로그램MyBatis
직접 Connection을 맺고 마지막에 close()자동으로 Connection close() 기능
PreparedStatement 직접 생성 및 처리MyBatis 내부적으로 PreparedStatement 처리
PreparendStatement의 setXXX()등에 대한 모든 작업을 개발자가 처리#{prop}와 같이 속성을 지정하면 내부적으로 자동처리
SELETCT 경우 ResultSet이 처리리턴 타입을 지정하는 경우 자동으로 객체 생성 및 ResultSet 처리

📌 마리아 디비랑 연동하기

예제

  1. build.gradle에 마리아 디비 라이브러리 작업하기
  • MariaDB 드라이버와 HikariCP 관련 라이브러리를 추가
  • MyBatis는 단독으로 실행이 가능한 프레임워크지만 mybatis-spring 라이브러리를 이용하면
    쉽게 통합해서 사용 가능
  • 과거에는 주로 별도의 DAO(Data Access Object)를 구성하고 여기서 MyBatis의 SqlSession
    이용하는 방식
  • 최근에는 MyBatis는 인터페이스를 이용하고 실제 코드는 자동으로 생성되는 방식 –
    Mapper인터페이스와 XML
  • 필요한 라이브러리
    • 스프링 관련: spring-jdbc, spring-tx
      • 스프링에서 데이터베이스 처리와 트랜잭션 처리(해당 라이브러리들은 Mybatos와 무관해보이지만 추가하지 않은 경우 에러가 발생하니 주의)
    • MyBatis 관련: mybatis, mybatis-spring
implementation 'org.mariadb.jdbc:mariadb-java-client:3.0.4'
implementation group: 'com.zaxxer', name: 'HikariCP', version: '5.0.1'
  1. datasource 등록하기 - 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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

    <!--데이터 소스 등록-->
    <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
        <property name="driverClassName" value="org.mariadb.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mariadb://localhost:3306/webdb"></property>
        <property name="username" value="webuser"></property>
        <property name="password" value="webuser"></property>
        <property name="dataSourceProperties">
            <props>
                <prop key="cachePrepStmts">true</prop>
                <prop key="prepStmtCacheSize">250</prop>
                <prop key="prepStmtCacheSqlLimit">2048</prop>
            </props>
        </property>
    </bean>

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
          destroy-method="**close"**>
        <constructor-arg ref="hikariConfig" /> 
    </bean>

    <context:component-scan base-package="com.multicampus.springex"/>

   </beans>
  1. 디비 연동 해주기

  1. myBatis와 스프링 연동 - build.gradle
//mybatis와 스프링 연동
    implementation group: 'org.springframework', name:'spring-jdbc', version: '5.3.19'
    implementation group: 'org.springframework', name:'spring-tx', version: '5.3.19'

    implementation 'org.mybatis:mybatis:3.5.9'
    implementation 'org.mybatis:mybatis-spring:2.0.7'
  1. modelmapper 등록해주기
// modelmapper
    implementation group: 'org.modelmapper', name: 'modelmapper', version: '3.0.0'
    implementation group: 'org.hibernate', name: 'hibernate-validator', version: '6.2.1.Final'
  1. MyBatis의 SqlSessionFactory 설정
  • myBatis에서 실제 sql의 처리는 SqlSessionFactory 에서 생성하는 SqlSession을 통해서 수정
  • SQLSession을 통해서 Connection을 생성하거나 원하는 SQL을 전달하고, 리턴받는 구조로 작성
  • SqlSessionFactoryBean : 스프링에 SqlSessionFactory 등록하는 작업을 해줌
  • 패키지 클래스명을 보면 알 수 있듯이 MyBatis 패키지가 아니라 스프링과 연동 작업을 처리하는 라이브러리 클래스
<!--세션에다가 connection을 연결해주겠다 = sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name=**"dataSource"** ref="dataSource"/>
    </bean>
  1. TimeMapper 인터페이스 생성
  • Mapper란 SQLSessionFactory를 이용해서 코드를 작성해도, 직접 Connection을 얻어서 JDBC 코딩이 가능하지만 좀더 편하게 작업하기 위해 SQL과 그에 대한 처리를 지정하는 역할
  • MyBatis-Spring을 이용하는 경우 Mapper를 XML과 인터페이스 + 어노테이션 형태
package com.multicampus.springex.mapper;

import org.apache.ibatis.annotations.Select;

public interface TimeMapper { //데이터베이스의 현재시각을 문자열로 받아와서 처리
    @Select("select now()") //반복되는 것을 객체처럼 만들어서 재사용, 문자열로 넘어가기 때문에 ; 지정하지 않음
    String getTime();
}
  1. root-context.xml에 인터페이스 연동
<!--timeMapper와 연결해줘, 빈에 등록할거야의 의미-->
    <context:component-scan base-package="com.multicampus.springex"/>
    <mybatis:scan base-package="com.multicampus.springex.mapper" ></mybatis:scan>
  1. 테스트 코드 - TimeMapperTest
  • 스프링에 빈으로 등록된 DataSource를 이용해서 Connection을 제대로 처리할 수 있는지를 확인해보는 용
package com.multicampus.springex.mapper;

import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@Log4j2
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/root-context.xml")
public class TimeMapperTests {
    @Autowired(required = false)
    private TimeMapper timeMapper;

    @Test
    public void testGetTime(){
        log.info(timeMapper.getTime());
    }
}

뭔가 intellJ만지다가 발견한 것 - 다이어그램으로 보기

  • webapp

  • java

📌 주의하자

💡 항상 웬만하면 오타문제다 ㅠㅠㅠㅠ 주의하자. 에러를 잘 못봐도 한 번 더 찬찬히 코드를 살펴보자

회고

오늘은 그래도 나름 열심히 복습한 느낌? 대신 이것을 잊지 않기 위해 며칠 뒤에 다시 복습하자.

오늘 트위터에서 한 기획자이자 개발자이신 분의 트위터 내용을 보고 진짜... 공감을 많이 받았다. 불안의 연속과 그럼에도 열심히해서 취업하시고 계속 성장해나가는 얘기..그리고 저장해두고 안본 강의들 많다는 것 또한 공감했으며 기획자들 만나는 자리에서 다들 대단하신 분들이 많아서 뒤쳐졌다는 생각을 하며, 엘리트 코스가 부러웠다고 한다.

나도 그런 것 같다. 1년 준비해서 비전공으로 네카라쿠배가는 사람들을 보면서 흔들리는 것 나는 몇년을 공부했는데 그 사람들보다 못하며 지금 부트캠프에서도 나만 뒤쳐지는 것 같은 것 이 불안감은 어쩔 수가 없는 것 같다. 그래도 대학생활 내내 쉬지 않고 아르바이트, 근로 하면서 공부해온 것 그것도 대단한 것 잖아.. 주변에 친한 애들도 열심히 산다고 생각하며 얘기해주는데 나는 아무것도 안한 것 같아라는 생각만 반복이다. 하지만 아예 무의미하지는 않겠지.. 그래도 열심히 살아왔잖아. 그 자리에서 남과 비교하면서 좌절하지 않으면 열심히 하면 나도 해낼 수 있지 않을까? 화이팅하자.

profile
내 지식을 기록하여, 다른 사람들과 공유하여 함께 발전하는 사람이 되고 싶다. gitbook에도 정리중 ~

0개의 댓글