728x90
300x250

[Spring-Framework] 40. Connection Pool - xml 정리(Oracle, MySQL, HikariCP, Apache DBCP)


root-context.xml과 같은 context.xml 파일에 빈스(Beans)로 등록해서 사용할 때 매우 요긴하게 사용될 수 있는 DataSource에 대해서 정리하였다.

의외로 정리된 자료를 찾기가 귀찮아서 정리하였으니 참고하여 잘 사용하면 된다.


연관 글은 38, 39번 Spring-Framework에도 적용해볼 수 있다.



1. 정리


많이 필요한 경우가 생긴다. 이거 찾는데 시간 허비하지 말라고 작성한다.


[추가]
     <!-- MySQL - DataSource 셋팅 -->
    <bean id="dataSource2" class="com.mysql.cj.jdbc.MysqlDataSource">
        <property name="URL" value="${ORACLE_DB_URL}" />
        <property name="user" value="${ORACLE_DB_USERNAME}"/>
        <property name="password" value="${ORACLE_DB_PASSWORD}"/>
    </bean>


    <!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> -->
 
     <!-- 2. Oracle - DataSource 셋팅 -->
    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="URL" value="${ORACLE_DB_URL}" />
        <property name="user" value="${ORACLE_DB_USERNAME}"/>
        <property name="password" value="${ORACLE_DB_PASSWORD}"/>
        <property name="connectionCachingEnabled" value="true"/>
    </bean>

    <!-- 3. Apache DBCP -->

   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
         <property name="driverClassName" value="${jdbc.driverClassName}" />
         <property name="url" value="${jdbc.url}" />
         <property name="username" value="${jdbc.username}" />
         <property name="password" value="${jdbc.password}" />
   </bean>


    <!-- 4. HikariCP -->
    <!--
    <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
         <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
         <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:xe" />
         <property name="username" value="username" />
         <property name="password" value="password" />
    </bean>
 
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
          <constructor-arg ref="hikariConfig"/>
    </bean>
     -->



    <!-- 5. MariaDB -->
    <!--
    <bean id="dataSource4" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="driverClass" value="org.mariadb.jdbc.Driver"/>
        <property name="url" value="jdbc:mariadb://localhost:3306/test"></property>
        <property name="username" value="root"/>
        <property name="password" value="test"/>
    </bean>
     -->
    
    <!-- 6. MyBatis // 트랜젝션 적용 버전 -->
    <!--
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource4"/>
        <property name="configLocation" value="classpath:mybatis/config.xml"/>
        <property name="mapperLocations" value="classpath:mybatis/sql/*.xml"></property>
    </bean>
   
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
   
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource4"/>
    </bean>
   
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
     -->





2. 공식 사이트


http://commons.apache.org/proper/commons-dbcp/

https://github.com/brettwooldridge/HikariCP

-> 메뉴얼이 다소 부족하다. 깔끔하게 잘 정리는 되어 있는데 그런 점이 없는 건 아니다. 


https://www.oracle.com/kr/

https://www.mysql.com/

https://mariadb.org/

반응형
728x90
300x250

[JSP] 20. MyBatis-3.5.5, HikariCP 3.4.2 연동 - Maven(Servlet) Spring 제거버전 (Oracle 19g) - Java 방식


JSP/Servlet 순수한 방식에서 HikariCP를 연동할 수 있는 방법에 대해서 고민을 하게 된 이유는 Spring Framework의 의존성을 줄일 수 있겠냐는 생각을 가지고 접근하게 되었다.


JSP/Servlet이 현재에도 의외로 많이 사용되고 있다. Spring-Framework 사용 안 한 형태도 동작하는 프로젝트가 많기 때문에 조금 생각해보면 효과적으로 기존 프로젝트도 개선할 수 있을 거 같아서 작성하게 되었다.


기존 프로젝트에도 MyBatis 프레임워크와 HikariCP를 적용할 수 있으니 가능성을 가지고 순수한 JSP에 대해서도 관심을 가져봤으면 하는 바람이다.


커넥션 풀은 현재의 웹 개발에서는 반드시 필요한 존재라고 본다. 

(중요성에 대해서는 별도로 시간이 나면, 조금 더 심화적인 방법으로 연재하도록 하겠다.)


* XML로 설정한 MyBatis에서는 가능한가요?

= 불가능하다. (미지원)



- IDE: Spring-Tool-Suite 4-4.7.2 Releases (2020-06 최신)

- DB: Oracle Databases 19g (2020-09 최신)

- Maven 3.6.3/1.16.0.20200610-1735 (2020-09 최신)

- JAR: javax.servlet-api.4.0.1.jar (2020-09 최신)

         ojdbc8-19.7.0.0.jar (2020-09 최신)

         MyBatis 3.5.5 (2020-09 최신)

         HikariCP 3.4.2 (2020-09 최신)



* 정말로 Spring-Framework는 사용하지 않았나요?

= 그렇다.



관련 글)

1. [JSP] 19. MyBatis-3.5.5 와 Maven / Servlet 연동하기 (Oracle 19g) - Java 방식, https://yyman.tistory.com/1434, 2020-10-01

-> 이 글의 소스 코드 이어서 계속(해당 게시글에서는 변형됨.)



1. 결과


이전의 게시글에서 동작 반응이 다소 변경되었다. (HikariConnection Pool 반응 상태를 추가하였음.



그림 1. HikariPool - 2 반응 추가


사소해보이지만, 무척 중요하다. 동시 접속했을 때, 서버가 죽느냐 사느냐를 결정할 수도 있다.

커넥션 풀은 데이터베이스 접속을 원할하게 해주는 중요한 것이라고 비유해주고 싶다.



그림 2. 프로젝트 구성 모습


* 이전의 프로젝트와 차이점: exmple 탈자를 정정하였음. (example로)

- 패키지명을 잘 조정해서 사용하면 크게 무리없이 동작할 것이다.


1. 폴더 추가

/src/main/resources 폴더가 생성되었다.

- db.properties가 추가되었다.



2. POM.xml - 설정하기


POM.xml의 변화는 HikariCP 3.4.2가 추가되었다.

바뀐 것은 없다. 그래서 잘 따라해야 하는 것이다.


<?xml version="1.0" encoding="UTF-8"?>


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>


  <groupId>com.exmplebatis</groupId>

  <artifactId>web</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>


  <name>web Maven Webapp</name>

  <!-- FIXME change it to the project's website -->

  <url>http://www.example.com</url>


  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <maven.compiler.source>1.7</maven.compiler.source>

    <maven.compiler.target>1.7</maven.compiler.target>

  </properties>


  <dependencies>

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>4.11</version>

      <scope>test</scope>

    </dependency>

    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->

<dependency>

    <groupId>javax.servlet</groupId>

    <artifactId>javax.servlet-api</artifactId>

    <version>4.0.1</version>

    <scope>provided</scope>

</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.5.5</version>

</dependency>

<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->

<dependency>

    <groupId>com.zaxxer</groupId>

    <artifactId>HikariCP</artifactId>

    <version>3.4.2</version>

</dependency>

<dependency>

<groupId>com.oracle.database.jdbc</groupId>

<artifactId>ojdbc8</artifactId>

<version>19.7.0.0</version>

</dependency>

  </dependencies>


  <build>

    <finalName>web</finalName>

    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->

      <plugins>

        <plugin>

          <artifactId>maven-clean-plugin</artifactId>

          <version>3.1.0</version>

        </plugin>

        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->

        <plugin>

          <artifactId>maven-resources-plugin</artifactId>

          <version>3.0.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-compiler-plugin</artifactId>

          <version>3.8.0</version>

        </plugin>

        <plugin>

          <artifactId>maven-surefire-plugin</artifactId>

          <version>2.22.1</version>

        </plugin>

        <plugin>

          <artifactId>maven-war-plugin</artifactId>

          <version>3.2.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-install-plugin</artifactId>

          <version>2.5.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-deploy-plugin</artifactId>

          <version>2.8.2</version>

        </plugin>

      </plugins>

    </pluginManagement>

  </build>

</project>



파일명: pom.xml


[첨부(Attachments)]

pom-update-hikaricp.zip




3. /resources/db.properties 설정하기


db.properties에 관한 것이다.



그림 3. db.properties 설정 내용


jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl

dataSourceClassName=oracle.jdbc.driver.OracleDriver

dataSource.user=UserName

dataSource.password=Password

cachePrepStmts=true

prepStmtCacheSize=250

prepStmtCacheSqlLimit=2048


파일명: db.properties


[첨부(Attachments)]

db.zip




4. SqlMapSessionFactory.java - com.example.web.db


DB 세션 영역이다.

일부 인터넷 게시글을 찾아보면, SqlSessionFactoryBeans ssfb = new SqlSessionFactoryBeans(); 객체 생성 후에 setDatasource()로 연결시키면 된다고 소개된 글들이 있다.


이 부분은 공식 메뉴얼을 찾아본 바로는 MyBatis에서 Spring을 지원하기 위해서 만든 부분이다.

JSP/Servlet 기반의 프로젝트에서는 지원하지 않는 부분이다. (Beans 처리를 미지원함.)


충분히 시간을 가지고 태스트가 완료된 코드이다.



그림 4. SqlMapSessionFactory.java - 작업 모습



package com.example.web.db;


import java.io.IOException;

import java.io.InputStream;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.util.Properties;


import javax.sql.DataSource;


import org.apache.ibatis.mapping.Environment;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.apache.ibatis.transaction.TransactionFactory;

import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;


import com.example.web.mapper.CompUsersMapper;

import com.zaxxer.hikari.HikariConfig;

import com.zaxxer.hikari.HikariDataSource;


import oracle.jdbc.pool.OracleDataSource;


public class SqlMapSessionFactory {


private static SqlMapSessionFactory factory = new SqlMapSessionFactory();


public static SqlMapSessionFactory getInstance() {

return factory;

}


public static SqlSessionFactory ssf;


    private static String CLASSNAME;

    private static String JDBC_URL;

    private static String USERNAME;

    private static String PASSWORD;

    private static String CACHE_PREP_STMTS;

    

    private HikariDataSource ds;

    private HikariConfig config;



private SqlMapSessionFactory() {

/* HikariCP 로드 */

    InputStream inputStream;

    config = new HikariConfig();

   

    String resource = "db.properties";

    Properties properties = new Properties();

    

    try {


    inputStream = getClass().getClassLoader().getResourceAsStream(resource);

        properties.load(inputStream);


        System.out.println("jdbcurl:" + properties.getProperty("jdbcUrl"));

        System.out.println("className" + properties.getProperty("dataSourceClassName"));


        CLASSNAME = properties.getProperty("dataSourceClassName");

        JDBC_URL = properties.getProperty("jdbcUrl");

        USERNAME = properties.getProperty("dataSource.user");

        PASSWORD = properties.getProperty("dataSource.password");

        CACHE_PREP_STMTS = properties.getProperty("cachePrepStmts");


        config.setDriverClassName(CLASSNAME);

        config.setJdbcUrl( JDBC_URL );

        config.setUsername( USERNAME );

        config.setPassword( PASSWORD );

        config.addDataSourceProperty( "cachePrepStmts" , CACHE_PREP_STMTS );

        config.addDataSourceProperty( "prepStmtCacheSize" , "250" );

        config.addDataSourceProperty( "prepStmtCacheSqlLimit" , "2048" );

        ds = new HikariDataSource( config );


    System.out.println("성공:" + ds);


    } catch (IOException e) {

    System.out.println("오류:" + e.getMessage());

        e.printStackTrace();

    }

    

}

   

// iBatis(MyBatis 반환)

public SqlSessionFactory getSqlSessionFactory() {

DataSource hDs = ds;

    // DataSource dataSource = getOracleDataSource();

System.out.println(hDs);

    TransactionFactory transactionFactory = new JdbcTransactionFactory();

    Environment environment = new Environment("development", transactionFactory, hDs);

    Configuration configuration = new Configuration(environment);


    configuration.addMapper(CompUsersMapper.class); // Mapper 클래스

   

//    System.out.println("성공2");

        return new SqlSessionFactoryBuilder().build(configuration);


    }


public void close(Connection conn, PreparedStatement ps, ResultSet rs) {


if ( rs != null ) {


try {

rs.close();

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}

close(conn, ps); // Recursive 구조 응용(재귀 함수)

} // end of if


}


public void close(Connection conn, PreparedStatement ps) {


if (ps != null ) {

try {

ps.close();

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}

} // end of if


if (conn != null ) {


try {

conn.close();

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}


} // end of if


}


}


파일명: SqlMapSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory-update.zip




5. FrontController.java - com.example.web.controller


FrontController에 대한 변화이다.



그림 5. FrontController.java - 작업 모습



package com.example.web.controller;


import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;


import com.example.web.db.SqlMapSessionFactory;

import com.example.web.mapper.CompUsersMapper;

import com.example.web.model.CompUsers;


public class FrontController extends HttpServlet {

private static final long serialVersionUID = 1L;

    SqlSessionFactory factory = null;

    SqlMapSessionFactory sqlMapFactory = null;


/**

* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)

*/

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doAction(request, response);

}


/**

* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)

*/

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doAction(request, response);

}


protected void doAction(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

sqlMapFactory = SqlMapSessionFactory.getInstance();

try {

factory = sqlMapFactory.getSqlSessionFactory();

} catch (Exception e) {

e.printStackTrace();

}

try (SqlSession session = factory.openSession()) {

  CompUsersMapper mapper = session.getMapper(CompUsersMapper.class);

  CompUsers user = mapper.findByUsername("user");

  

  System.out.println("계정명:" + user.getUsername());

  

}

}


}



파일명: FrontController.java


[첨부(Attachments)]

FrontController-update.zip





6. CompUsers.java - com.example.web.model (Model)


이전 게시글과는 변화는 없지만, 다시 재언급한다.


package com.example.web.model;


public class CompUsers {


private String username;

private String password;

private int enabled;

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public int getEnabled() {

return enabled;

}

public void setEnabled(int enabled) {

this.enabled = enabled;

}

}



파일명: CompUsers.java


[첨부(Attachments)]

CompUsers-updated.zip


CREATE TABLE comp_users (

username VARCHAR(50) NOT NULL,

password VARCHAR(300) NOT NULL,

enabled INT NOT NULL,

PRIMARY KEY (username)

);


-- 계정

INSERT INTO comp_users (username, password, enabled) VALUES ('user', '$2a$10$x04djNV2e9rpcPPRyXoLk.rMm6iZe2/vYdzpqHQcLeNSYdt7kc30O', 1);

INSERT INTO comp_users (username, password, enabled) VALUES ('admin', '$2a$10$QUddY3O/6ZgkYCR6MFlv9.nqA501Fm0cc/ZxQHX5pwb1o0CYCTiIS', 1);


파일명: CompUsers.sql


[첨부(Attachments)]

comp_users_sql.zip




7. CompUsersMapper.java - com.example.web.mapper (Mapper - DAO)


이전 게시글과 비교했을 때 변화는 없었다.


package com.example.web.mapper;


import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Select;


import com.example.web.model.CompUsers;


@Mapper

public interface CompUsersMapper {

  @Select("SELECT * FROM comp_users WHERE username = #{username}")

  public CompUsers findByUsername(String username);

  

}



파일명: CompUsersMapper.sql


[첨부(Attachments)]

CompUsersMapper-updated.zip




* 맺음글(Conclusion)


HikariCP 구성과 MyBatis-3.5.5 셋팅에 대해서 JSP/Servlet 방식으로 다뤄보았다.

반응형
728x90
300x250

[JSP] 19. MyBatis-3.5.5 와 Maven / Servlet 연동하기 (Oracle 19g) - Java 방식


MyBatis 관련 이전의 글을 읽어보고 실습을 해본 다음에 경험해봐도 무방할 것으로 보인다.

이번에 소개할 내용은 조금 세련된 방식으로 MyBatis를 적용하는 방법에 대해서 소개하려고 한다.


이 글을 작성하게 된 계기는 MyBatis 공식 사이트에서 제시하는 방법론에 대해서 실질적으로 어떻게 구현하는지 소개해보고 싶어서 그렇다.


이전 스타일에 익숙하다면, 새로운 스타일을 경험하시어 훨씬 생산성이 있는 방법으로 개발을 시도해보면 좋지 않겠냐는 것이다.


1. [JSP] 8. 영속프레임워크 MyBatis를 활용한 CRUD 구현 - JSP와 Oracle (XML 방식), 2020-9-19
https://yyman.tistory.com/1390 

-> XML 방식으로 구현됨.


- IDE: Spring-Tool-Suite 4-4.7.2 Releases (2020-06 최신)

- DB: Oracle Databases 19g (2020-09 최신)

- Maven 3.6.3/1.16.0.20200610-1735 (2020-09 최신)

- JAR: javax.servlet-api.4.0.1.jar (2020-09 최신)

         ojdbc8-19.7.0.0.jar (2020-09 최신)

         MyBatis 3.5.5 (2020-09 최신)



1. 결과


결과를 바탕으로 살펴보면, 이렇게 출력되면 잘 된 것이다.



그림 1. 결과 - DB 연동 모습



그림 2. 결과 - 프로젝트 구성도


작업을 할 내용이다. 매우 간결한 프로젝트 구성이다.



2. 데이터베이스 설계


Spring Security 5의 사용자 계정 테이블을 인용하여 설계하였다.

테이블의 구조는 간단한 형태이다.



그림 3. Oracle SQL Developer - 데이터베이스 설계





그림 4. Oracle SQL Developer - (데이터 내용)



그림 5. Oracle SQL Developer - COMP_USERS (Model)


CREATE TABLE comp_users (

username VARCHAR(50) NOT NULL,

password VARCHAR(300) NOT NULL,

enabled INT NOT NULL,

PRIMARY KEY (username)

);


-- 계정

INSERT INTO comp_users (username, password, enabled) VALUES ('user', '$2a$10$x04djNV2e9rpcPPRyXoLk.rMm6iZe2/vYdzpqHQcLeNSYdt7kc30O', 1);

INSERT INTO comp_users (username, password, enabled) VALUES ('admin', '$2a$10$QUddY3O/6ZgkYCR6MFlv9.nqA501Fm0cc/ZxQHX5pwb1o0CYCTiIS', 1);


파일명: comp_users.sql


[첨부(Attachments)]

comp_users.zip





3. 프로젝트 생성하기


프로젝트 생성에 대해서 소개하겠다.



그림 6. Maven Project 생성하기(1)


File -> New -> Maven Project를 클릭한다.




그림 7. Maven Project 생성하기(2)


프로젝트를 생성할 때 "org.apache.maven.archetype", "maven-archetype-webapp"을 선택한다.

Next를 클릭한다.



그림 8. Maven Project 생성하기(3)


Group Id, Artifact Id를 입력해준다.

Finish를 누른다.




4. 자바 버전 - Build Path, Project Facets 설정하기


프로젝트를 선택한다. 그리고 Properties에 들어가서 설정할 것이다.



그림 9. 프로젝트의 마우스 오른쪽 버튼의 메뉴 모습


프로젝트를 선택한 후 마우스 오른쪽 버튼을 누른다.

Properties를 클릭한다.



그림 10. 프로젝트의 Build Path


Java Build Path를 클릭한다.

JRE System Library를 14버전으로 변경해준다.

Apply를 누른다.




그림 11. 프로젝트의 Project Factes


Project Factes를 클릭한다.

Java의 버전을 14로 변경한다.

Apply를 누른다.



4. MyBatis - 공식 사이트 메뉴얼 읽어보기


공식 사이트에서 지원하는 방식에 대해서 간단하게 소개되어 있다.

아래의 공식 링크를 참고해서 적용할 것이다.


https://mybatis.org/mybatis-3/ko/getting-started.html



그림 12. MyBatis - 시작하기 (Official Site)





5. pom.xml - 설정하기


http://mvnrepository.com에서 Java Servlet API 4.0.1과 MyBatis를 찾아서 추가한다.

Oracle은 Oracle 공식 사이트나 또는 Oracle Databases 19g가 설치되어 있다면, 간단하게 Add Dependency를 통해서 pom.xml에 추가할 수 있다.



그림 13. Servlet API 4.0.1 - Mvnrepository






그림 14. MyBatis 3.5.5 - Mvnrepository



그림 15. Pom.xml 마우스 오른쪽 버튼 메뉴 모습


pom.xml을 마우스 오른쪽 버튼으로 클릭한다.

Maven->Add Dependency를 클릭한다.


(참고로 Oracle Databases 19g가 설치된 경우에서만 가능한 작업이다.)

(설치가 되지 않은 경우라면, Oracle 공식 사이트에서 Oracle JDBC를 내려받기 바란다.

그리고 lib 폴더에 넣어주고 프로젝트에서 셋팅해줘야 한다.)



그림 16. Add-Dependency


Oracle을 검색한다.

com.oracle.database.jdbc  "ojdbc8"을 선택한다.

OK를 누른다.



그림 17. STS 4.4 - pom.xml 모습


<?xml version="1.0" encoding="UTF-8"?>


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>


  <groupId>com.examplebatis</groupId>

  <artifactId>web</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>war</packaging>


  <name>web Maven Webapp</name>

  <!-- FIXME change it to the project's website -->

  <url>http://www.example.com</url>


  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <maven.compiler.source>1.7</maven.compiler.source>

    <maven.compiler.target>1.7</maven.compiler.target>

  </properties>


  <dependencies>

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>4.11</version>

      <scope>test</scope>

    </dependency>

    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->

<dependency>

    <groupId>javax.servlet</groupId>

    <artifactId>javax.servlet-api</artifactId>

    <version>4.0.1</version>

    <scope>provided</scope>

</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.5.5</version>

</dependency>


<dependency>

<groupId>com.oracle.database.jdbc</groupId>

<artifactId>ojdbc8</artifactId>

<version>19.7.0.0</version>

</dependency>

  </dependencies>


  <build>

    <finalName>web</finalName>

    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->

      <plugins>

        <plugin>

          <artifactId>maven-clean-plugin</artifactId>

          <version>3.1.0</version>

        </plugin>

        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->

        <plugin>

          <artifactId>maven-resources-plugin</artifactId>

          <version>3.0.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-compiler-plugin</artifactId>

          <version>3.8.0</version>

        </plugin>

        <plugin>

          <artifactId>maven-surefire-plugin</artifactId>

          <version>2.22.1</version>

        </plugin>

        <plugin>

          <artifactId>maven-war-plugin</artifactId>

          <version>3.2.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-install-plugin</artifactId>

          <version>2.5.2</version>

        </plugin>

        <plugin>

          <artifactId>maven-deploy-plugin</artifactId>

          <version>2.8.2</version>

        </plugin>

      </plugins>

    </pluginManagement>

  </build>

</project>



파일명: pom.xml


[첨부(Attachments)]

pom.zip




6. SqlMapSessionFactory.java - 자바 방식 연결부


자바 방식 연결부를 작성하도록 하겠다.



그림 18. Java Resources의 마우스 오른쪽 클릭 메뉴 모습


Java Resources를 마우스 오른쪽 버튼으로 클릭한다.

New->Class를 클릭한다.




그림 19. SqlMapSessionFactory.java 만들기


Package명과 Name을 입력한다. 

(예: package: com.exmple.web.db)    //    탈자(exmple로 만들었으니 알아서 참고할 것.)

(예: Name: SqlMapSessionFactory)


Finish를 누른다.



그림 20. SqlMapSessionFactory.java


코드를 수정해준다.


package com.exmple.web.db;


import java.io.IOException;

import java.io.InputStream;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;


import javax.sql.DataSource;


import org.apache.ibatis.io.Resources;

import org.apache.ibatis.mapping.Environment;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.apache.ibatis.transaction.TransactionFactory;

import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;


import com.exmple.web.mapper.CompUsersMapper;


import oracle.jdbc.pool.OracleDataSource;


public class SqlMapSessionFactory {


private static SqlMapSessionFactory factory = new SqlMapSessionFactory();


private SqlMapSessionFactory() {}


private final static String driverName = "oracle.jdbc.driver.OracleDriver";

private final static String dbUrl = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";

private final static String userName = "사용자계정명";

private final static String userPassword = "비밀번호";


public static SqlMapSessionFactory getInstance() {

return factory;

}


public static SqlSessionFactory ssf;


    static{


    DataSource dataSource = getOracleDataSource();

    TransactionFactory transactionFactory = new JdbcTransactionFactory();

   

    Environment environment = new Environment("development", transactionFactory, dataSource);

    Configuration configuration = new Configuration(environment);

   

    configuration.addMapper(CompUsersMapper.class); // Mapper 클래스

   

        ssf = new SqlSessionFactoryBuilder().build(configuration);

        

    }

    

// iBatis(MyBatis 반환)

public static SqlSessionFactory getSqlSessionFactory(){

        return ssf;

    }


/*


*     public static DataSource getMySQLDataSource() {

        Properties props = new Properties();


        FileInputStream fis = null;

        MysqlDataSource mysqlDS = null;

        

        try {

            fis = new FileInputStream("db.properties");


            props.load(fis);

            mysqlDS = new MysqlDataSource();

            mysqlDS.setURL(props.getProperty("MYSQL_DB_URL"));

            mysqlDS.setUser(props.getProperty("MYSQL_DB_USERNAME"));

            mysqlDS.setPassword(props.getProperty("MYSQL_DB_PASSWORD"));

            

        } catch (IOException e) {

            e.printStackTrace();

        }

        return mysqlDS;

        

    }

    */

/*

* Description: 순정 오라클 데이터소스

*/

    private static DataSource getOracleDataSource(){

        

    OracleDataSource oracleDS = null;

        

    try {

            oracleDS = new OracleDataSource();

            oracleDS.setURL(dbUrl);

            oracleDS.setUser(userName);

            oracleDS.setPassword(userPassword);

            

        } catch (SQLException e) {

            e.printStackTrace();

        }

        return oracleDS;


    }


public Connection connect() {


Connection conn = null;


try {

Class.forName(driverName);

conn = DriverManager.getConnection(dbUrl, userName, userPassword);

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}

return conn;

}


public void close(Connection conn, PreparedStatement ps, ResultSet rs) {


if ( rs != null ) {


try {

rs.close();

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}

close(conn, ps); // Recursive 구조 응용(재귀 함수)

} // end of if


}


public void close(Connection conn, PreparedStatement ps) {


if (ps != null ) {

try {

ps.close();

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}

} // end of if


if (conn != null ) {


try {

conn.close();

}

catch(Exception ex) {

System.out.println("오류 발생: " + ex);

}


} // end of if


}


}


파일명: SqlMapSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip


비고: MySQL의 지원에 대해서 코드를 적어놓았다.




7. Servlet - 생성하기(Controller)


서블릿을 생성해줄 것이다.


그림 21. Java Resources의 오른쪽 버튼 메뉴 모습


Java Resources를 마우스 오른쪽 버튼으로 클릭한다.

New->Servlet을 클릭한다.



그림 22. Servlet 만들기


Package명은 "com.exmple.web.controller"로 한다.

Class Name은 "FrontController"로 한다.


Finish를 누른다.


(Exmple 오타 -> Example이 맞지만, 이미 생성했으니 그냥 따르는 걸로 하겠음.)



8. web.xml - 수정 작업


Servlet 경로를 살짝 수정해주겠다.



그림 23. web.xml - 수정하기



<!DOCTYPE web-app PUBLIC

 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

 "http://java.sun.com/dtd/web-app_2_3.dtd" >


<web-app>

  <display-name>Archetype Created Web Application</display-name>

  <servlet>

  <servlet-name>FrontController</servlet-name>

  <display-name>FrontController</display-name>

  <description></description>

  <servlet-class>com.exmple.web.controller.FrontController</servlet-class>

  </servlet>

  <servlet-mapping>

  <servlet-name>FrontController</servlet-name>

  <url-pattern>/sample</url-pattern>

  </servlet-mapping>

</web-app>



파일명: web.xml


[첨부(Attachments)]

web.zip





9. CompUsers.java - Model(모델)


앞서 설계한 DB Model을 코드로 구현할 것이다.



그림 24. CompUsers.java


package com.exmple.web.model;


public class CompUsers {


private String username;

private String password;

private int enabled;

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public int getEnabled() {

return enabled;

}

public void setEnabled(int enabled) {

this.enabled = enabled;

}

}



파일명: CompUsers.java


[첨부(Attachments)]

CompUsers.zip




10. CompUsersMapper.java - Mapper(DAO)


이전 글과는 달리 공식 메뉴얼에서 제시하는 방법을 적용하도록 하겠다.



그림 25. Mapper 클래스 가이드



그림 26. Mapper 클래스 가이드 - 현실의 문제에 맞게 적용하기


package com.exmple.web.mapper;


import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Select;


import com.exmple.web.model.CompUsers;


@Mapper

public interface CompUsersMapper {

  @Select("SELECT * FROM comp_users WHERE username = #{username}")

  public CompUsers findByUsername(String username);

  

}



파일명: CompUsersMapper.java


[첨부(Attachments)]

CompUsersMapper.zip


대응하는 방식에는 XML Mapper를 적용하는 방법도 있다.
(참고로 자바방식으로 구현했다면, XML Mapper는 사용할 수 없다.)

(DB를 설계하면서 View도 만들 수도 있고 각종 조합을 할 수도 있는데, 엔터티를 잘 파악해서 구현하면 될 것 같다.)


[Spring Boot 버전의 MyBatis 핵심 사용법]


@Mapper

public interface StudentMyBatisRepository {


@Select("select * from student")

public List<Student> findAll();


@Select("SELECT * FROM student WHERE id = #{id}")

public Student findById(long id);


@Delete("DELETE FROM student WHERE id = #{id}")

public int deleteById(long id);


@Insert("INSERT INTO student(id, name, passport) VALUES (#{id}, #{name}, #{passport})")

public int insert(Student student);


@Update("Update student set name=#{name}, passport=#{passport} where id=#{id}")

public int update(Student student);


}




11. FrontController.java - Controller


FrontController의 내용을 수정하도록 하겠다.



그림 27. FrontController.java - 수정하기


package com.exmple.web.controller;


import java.io.IOException;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;


import com.exmple.web.db.SqlMapSessionFactory;

import com.exmple.web.mapper.CompUsersMapper;

import com.exmple.web.model.CompUsers;


public class FrontController extends HttpServlet {

private static final long serialVersionUID = 1L;

    SqlSessionFactory factory = SqlMapSessionFactory.getSqlSessionFactory();


/**

* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)

*/

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doAction(request, response);

}


/**

* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)

*/

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doAction(request, response);

}


protected void doAction(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

try (SqlSession session = factory.openSession()) {

  CompUsersMapper mapper = session.getMapper(CompUsersMapper.class);

  CompUsers user = mapper.findByUsername("user");

  

  System.out.println("계정명:" + user.getUsername());

  

}

}


}



파일명: FrontController.java


[첨부(Attachments)]

FrontController.zip




12. 맺음글(Conclusion)


MyBatis 3.5.5와 Maven, JSP/Servlet 그리고 Oracle Databases를 쉽고 빠르게 연동하는 방법에 대해서 소개하였다.


1. [JSP] 20. MyBatis-3.5.5, HikariCP 3.4.2 연동 - Maven(Servlet) Spring 제거버전 (Oracle 19g) - Java 방식, 2020-10-01

https://yyman.tistory.com/1435





* 참고 자료(References)


1. MyBatis - 마이바티스 3 | 시작하기, https://mybatis.org/mybatis-3/ko/getting-started.html, Accessed by 2020-10-01, Last Modified 2020-06-05.

- 비고: 사용 방법이 담겨있음.


2. [JSP] 8. 영속프레임워크 MyBatis를 활용한 CRUD 구현 - JSP와 Oracle (XML 방식), https://yyman.tistory.com/1390, Accessed by 2020-10-01, Last Modified 2020-09-19.

- 비고: MyBatis 셋팅 방법을 참고하였으며, XML 방식을 시도하였으나 안 되었다. (Spring Beans가 안 되는 것을 알게 되었음.)


3. [Spring-Framework] 22(번외). STS 4.4 - Spring Boot Starter - MyBatis(Boot용), HikariCP 3.4 사용하기, https://yyman.tistory.com/1432, Accessed by 2020-10-01, Last Modified 2020-10-01.

- 비고: HikariCP의 properties 방식에 대해서 다시 살펴보았다.

반응형
728x90
300x250

[Spring-Framework] 22(번외). STS 4.4 - Spring Boot Starter - MyBatis(Boot용), HikariCP 3.4 사용하기


이전의 JSP/servlet의 myBatis 글과 Spring Framework를 활용하여 HikariCP를 적용한 프로젝트를 소개한 적이 있다.

이 글들에 이어서 소개하려고 한다.


IDE: Spring-Tool-Suite 4-4.7.2 Releases
     - MyBatis Spring Boot Starter » 2.1.3(2020-06-05)  // pom.xml에서 이거 하나만 해주면 설치 끝남.


이 글을 읽으려면, 기존의 MyBatis 사용과는 조금 차이를 두고 구현해야 한다. (Spring Boot Starter 버전이 따로 있음.)
- 고정 관념을 먼저 깨줘야 한다.


이 글을 읽고 따라해보면, 개발에 있어서 상상 초월의 퍼포먼스를 경험할 수 있을 거라고 본다.





1. 구축하는 데 원리만 제대로 알게 되면, 매우 쉽다.


할 일이 크게 없어져버렸다고 보면 된다.

책도 많이 없을 뿐더러 자료가 다소 부족해서 그렇지만, 알게 되면 무슨 DB구축이 이렇게나 쉽냐고 당황할 수 있는 수준이라고 표현하고 싶다.


이 블로그 운영자인 필자가 자랑하는 것이 아니라, 최신 버전으로 가면 갈수록 할 게 없다. 

(커넥션 풀도 내장되어 있고, 영속 프레임워크도 기본 내장되어 있다. 굳이 JPA나 각종 Hibernate를 찾을 필요가 있는지 이런 생각이 들 정도이다.)


자료가 없어서 삽질을 다소 했지만, 진짜 쉬워졌다. 현재의 Spring Starter만 잘 활용하면, 많은 거 신경 쓸 필요가 전혀 없고, DB하고(SQL문법 등) 개발만 집중하면 된다. 아이디어만 잘 짜내서, 좋은 서비스 찍어내면 된다.(희망사항이긴 하지만.)




그림 1. 프로젝트 구성도  (Spring Boot Starer 프로젝트)


xml 맵핑 복잡하게 그런 것도 할 필요가 없어졌다.



2. 결과


REST Controller를 활용해서 JSON형태로 출력하였다.

잘 된다.


소스코드 양도 훨씬 줄었다. HikariCP하고, MyBatis Framework가 기본으로 Spring Boot에서는 사용된다고 보면 된다.



그림 2. 완성된 작업물




3. 데이터베이스 설계


먼저 DB설계를 하는 건 결코 아니다. 해당 작업을 조금 원할하게 따라할 수 있도록 미리 소개하는 것이다.

Spring Security에서 제시하는 기본 USER(회원)에 관한 설계를 인용하였다.



그림 3. COMP_USERS - Spring Security 사용자 계정



CREATE TABLE comp_users (

username VARCHAR(50) NOT NULL,

password VARCHAR(300) NOT NULL,

enabled INT NOT NULL,

PRIMARY KEY (username)

);



-- 계정

INSERT INTO comp_users (username, password, enabled) VALUES ('user', '$2a$10$x04djNV2e9rpcPPRyXoLk.rMm6iZe2/vYdzpqHQcLeNSYdt7kc30O', 1);

INSERT INTO comp_users (username, password, enabled) VALUES ('admin', '$2a$10$QUddY3O/6ZgkYCR6MFlv9.nqA501Fm0cc/ZxQHX5pwb1o0CYCTiIS', 1);


파일명: comp_users.sql


[첨부(Attachments)]

comp_user.zip




4. 프로젝트 생성하기


프로젝트 생성은 매우 간단한 방법으로 진행된다. 인터넷이 되는 환경에서 작업을 해야 한다.



그림 3. 스프링 스타터 프로젝트(1)


프로젝트 익스플로러의 빈칸에서 오른쪽 버튼을 클릭한다.

Spring Starter Project를 클릭한다.



그림 4. 스프링 스타터 프로젝트(2)


자바 버전부터 왠만한 내용은 자동으로 입력되어 있다.

환경에 맞춰서 클래스명, 그룹, Artifact 등 입력해준다.

Next를 클릭한다.


방식이 두 가지로 확장됨: Maven, Gradle 방식
- 안드로이드 스튜디오를 경험해봤으면, Gradle 방식을 접했을 수도 있다.

  Maven으로 선택한다.

  (이런 부분도 있어서 Spring Boot에 대해서 또 관심을 가져야 한다. Gradle 방식도 있기 때문이다.) 





그림 5. 스프링 스타터 프로젝트(3)


MyBatis가 내장되어 있는지, HikariCP가 내장되어 있는지 궁금하다면, "Type to search dep...."에 검색을 해보면 된다.

내장되어 있다고 나온다.


그래서 선택할 항목이 크게 많지는 않고, "MySQL Driver", "Oracle Driver", "Spring Security", "Spring Web"을 체크하였다.


참고로 작업을 진행할 때, Spring Security에 대해서 조금 익숙치 않은 경우라면, 체크를 해제해도 무방하다. 

(보안이 워낙 강해서 URL Mapping까지도 Spring Security에서 전부 제어해버리는 일이 발생하기 때문이다.)




그림 6. 스프링 스타터 프로젝트(4)



2. pom.xml 설정하기


pom 설정을 해줘야 하는 부분은 myBatis-starter 하나만 해주면 끝난다.

http://mvnrepository.com 

이 사이트가 중요하다.


Spring-Framework를 활성화 하는데 가장 큰 공헌을 한 사이트인 것 같다.




그림 6-1. MyBatis Spring Boot Starter 2.1.3 (MVNRepository.com)



 

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.4.0-SNAPSHOT</version>

<relativePath/> <!-- lookup parent from repository -->

</parent>

<groupId>com.springmvc.home</groupId>

<artifactId>demo</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>SpringBootMVCDemo</name>

<description>Demo project for Spring Boot</description>


<properties>

<java.version>15</java.version>

</properties>


<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-jdbc</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-jdbc</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-security</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web-services</artifactId>

</dependency>


<dependency>

<groupId>com.oracle.database.jdbc</groupId>

<artifactId>ojdbc8</artifactId>

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

<dependency>

<groupId>org.springframework.security</groupId>

<artifactId>spring-security-test</artifactId>

<scope>test</scope>

</dependency>

<!-- Spring 부트에서는 이거 쓰면 안 됨 -->

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->

<!-- 

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.5.5</version>

</dependency>

-->

<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->

<dependency>

    <groupId>org.mybatis.spring.boot</groupId>

    <artifactId>mybatis-spring-boot-starter</artifactId>

    <version>2.1.3</version>

</dependency>


</dependencies>


<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>


<repositories>

<repository>

<id>spring-milestones</id>

<name>Spring Milestones</name>

<url>https://repo.spring.io/milestone</url>

</repository>

<repository>

<id>spring-snapshots</id>

<name>Spring Snapshots</name>

<url>https://repo.spring.io/snapshot</url>

<snapshots>

<enabled>true</enabled>

</snapshots>

</repository>

</repositories>

<pluginRepositories>

<pluginRepository>

<id>spring-milestones</id>

<name>Spring Milestones</name>

<url>https://repo.spring.io/milestone</url>

</pluginRepository>

<pluginRepository>

<id>spring-snapshots</id>

<name>Spring Snapshots</name>

<url>https://repo.spring.io/snapshot</url>

<snapshots>

<enabled>true</enabled>

</snapshots>

</pluginRepository>

</pluginRepositories>


</project>



파일명: pom.xml


[첨부(Attachments)]

pom.zip




3. application.properties 설정하


application.properties 설정 파일을 설정해줘야 한다.



그림 7. application.properties 설정하기


spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver

#org.mariadb.jdbc.Driver

spring.datasource.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl

#jdbc:mariadb://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=UTC

spring.datasource.username=user

spring.datasource.password=password


파일명: application.properties


[첨부(Attachments)]

application.zip



이 설정 하나면, 나머지 DataSource 등 설정까지 자동 인식함.
-> 글의 맨 마지막에 Spring-Legacy Project와의 차이점을 소개하겠음. (간단하게 이야기하면, 지탱해주고 있는 라이브러리가 많아졌다.)





3. RestStarterController.java - Controller


그냥 바로 컨트롤러 작업하면 된다. 설명을 해주고 싶어도 너무 간단한 구성이어서 그렇다.

공식 사이트 예제 참고해서 다소 변경한 것이다.


https://github.com/mybatis/spring-boot-starter

공식 스타터 홈페이지를 찾는데 시간이 다소 소요되었다는 것 빼고는 쉽게 되어 있다.


package com.springmvc.home.controller;


import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;


import com.springmvc.home.mapper.CompUserMapper;

import com.springmvc.home.model.CompUser;


@RestController

@RequestMapping("/cities")

public class RestStarterController {

private final CompUserMapper compUserMapper;


public RestStarterController(CompUserMapper compUserMapper) {

this.compUserMapper = compUserMapper;

}


@GetMapping("{state}")

CompUser getCompUser(@PathVariable String state) {

CompUser user = compUserMapper.findByUsername(state);

System.out.println("계정명:" + user.getUsername());

  return compUserMapper.findByUsername(state);

  

}


}


파일명: RestStarterController.java


[첨부(Attachments)]

RestStarterController.zip



4. CompUser.java - Model


데이터베이스 설계한 내용을 그대로 해줘야 한다.

이전의 사용방법처럼 어노테이션이나 이런 거 전혀 할 필요가 전혀 없다.

자동으로 맵핑이 된다.


package com.springmvc.home.model;


public class CompUser {

private String username;

private String password;

private int enabled;

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public int getEnabled() {

return enabled;

}

public void setEnabled(int enabled) {

this.enabled = enabled;

}

}



파일명: CompUser.java


[첨부(Attachments)]

CompUser.zip




5. CompUserMapper.java - DAO 또는 Service에 해당됨.(Mapper)


진정한 생산성이라는 것을 느낄 수 있다.


package com.springmvc.home.mapper;


import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Select;


import com.springmvc.home.model.CompUser;


@Mapper

public interface CompUserMapper {

@Select("select * from comp_users where username = #{username}")

public CompUser findByUsername(String username);


}



파일명: CompUserMapper.java


[첨부(Attachments)]

CompUserMapper.zip



6. 어떤 이유 때문에 Spring Boot가 라이브러리가 많다는 건가요?


쉬워진 만큼 무언가 지탱해주고 있는 프로그램이 있다.


패키지명: com.springmvc.home

파일명: SpringBootApplication.java (자동 생성된 파일)


package com.springmvc.home;


import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication

public class SpringBootMvcDemoApplication {


public static void main(String[] args) {

SpringApplication.run(SpringBootMvcDemoApplication.class, args);

}


}



파일명: SpringBootMvcDemoApplication.java


Spring Boot는 특이한 점이 프로그램 형태로 실행을 시켜버린다.



그림 8, 그림 9, 그림 10. Spring Boot를 지탱해주는 기본 library


다소 양이 많다는 것을 알 수 있다.

쉬워진 개발환경만큼 지탱해주고 있는 jar파일은 매우 많이 늘어났다는 것이다.


자세히 깨알같은 글자를 보면,

- ojdbc-18-19.7 (Oracle JDBC 19.7)

- MySQL (8.0.21)

- spring web 5.3 RC

......


최신 라인 구성을 자랑하고 있다고 보면 된다.




7. 스프링 부트와 스프링 프레임워크의 MyBatis 차이점


간단하게 요약해보았다.



그림 11. 차이점 비교


구현에 있어서 훨씬 간단해졌다는 것이다.


[첨부(Attachments)]

mybatis-summary.zip





* 맺음글(Conclusion)


조금 당황스럽긴 하지만, 이게 글의 끝이다.

Spring Boot Starter의 DB, 커넥션 풀까지 함께 소개한 것이다. 환경 설정 몇 가지만 더 알게 되면 된다.

현재에도 Spring Legacy Project 방식으로 구현하는 이유가 있을 것으로 보인다. Spring Boot는 결과적으로는 사용하는 데 있어서 매우 간편해졌다.



* 참고자료(References)


1. Spring Boot and iBatis with H2 - A Tutorial, https://www.springboottutorial.com/spring-boot-and-iBatis-with-h2-tutorial, Accessed by 2020-09-30, Last Modified 2020-07-07.


[Spring Boot 버전의 MyBatis 핵심 사용법]


@Mapper

public interface StudentMyBatisRepository {

@Select("select * from student")

public List<Student> findAll();


@Select("SELECT * FROM student WHERE id = #{id}")

public Student findById(long id);


@Delete("DELETE FROM student WHERE id = #{id}")

public int deleteById(long id);


@Insert("INSERT INTO student(id, name, passport) VALUES (#{id}, #{name}, #{passport})")

public int insert(Student student);


@Update("Update student set name=#{name}, passport=#{passport} where id=#{id}")

public int update(Student student);

 

}


-> 이거 말고는 크게 없다. Hibernate 이거보다도 훨씬 편하게 개발할 수 있다고 주장한다.


2. GitHub - mybatis/spring-boot-starter: MyBatis integration with Spring Boot, https://github.com/mybatis/spring-boot-starter/, Accessed by 2020-09-30, Last Modified .

-> 공식 사이트에서 제공해주는 예제 가이드이니 참고하면 된다. 다 완벽하게 되어 있는 건 아니고, 프로그램 사용 방법이 적혀져 있다.

반응형
728x90
300x250

[JSP] 8. 영속프레임워크 MyBatis를 활용한 CRUD 구현 - JSP와 Oracle(XML 방식)


조금 알기 쉽게 작성하였다.

"영속 프레임워크"라고 보면 된다.

영속 프레임워크라는 것은 DAO 객체에서 데이터베이스 데이터의 처리 기능을 제공하는 프레임워크이다.


대표적인 것: myBatis, Hibernate가 있다.


* 사용되는 언어: JSP / Servlet,
* 데이터베이스: Oracle 12 이상 (Oracle 18g에서 태스트 완료 하였음.)

* 프레임워크: mybatis-3.5.5

[첨부(Attachments)]

mybatis-3.5.5.jar

mybatis-3.5.5(원본).7z



1. 최소한 관련 프레임워크에 대해서 이해해보기


프레임워크의 특징에 대해서 간단하게 작성해보았다.


[특징]


myBatis란 그나마 학습하기 쉽고, 사용방법이 간단함.

초기 셋팅을 조금한 후에 나머지는 SQL명령문과 간단한 자바 소스코드로 구현하여 사용할 수 있음.

(iBatis 프로젝트로 시작해서 현재는 Apache Foundation에서 관리하는 자바 오픈소스 프레임워크)


http://www.mybatis.org


hibernate란 ORM(Object-Relational Mapping) 프레임워크라는 영속 프레임워크로서 자바와 객체와 데이터베이스를 매핑하여 데이터를 처리하므로 엔터프라이즈 환경에 적합한 특징을 가지고 있음.

(배우기 어려움. - 객체 모델링 경험이 요구됨.)


http://hibernate.org 



[생각해보기]


생각을 조금해본다면, 꼭 반드시 웹 프로젝트에만 MyBatis를 활용할 필요가 없음.
일반적인 Swing 프로젝트 연습 등에서도 사용해볼 수도 있겠음.

- 프레임워크 사용하기 전에 고민해야 할 점

1. 기본적으로 제공하는 JDBC 구현에 대해서도 생각해보기

(이유: 자바에서 자체적으로 제공하는 jdbc 구현(예: ResultSet, prepareStatement 등)에 대해서 이해하고 있으면 좋음.)


2. 프레임워크를 사용하는 것이 만능인지, 고민하기

3. SQL Injection 등의 보안 문제에 대해서 생각하기

   (프레임워크를 사용하면, SQL Injection 문제는 간단하게 해소된다.)


결론은 좋긴 좋다. 프레임워크!!!


[코드 비교하기] 


 Mybatis 사용전 코드 방식

 Mybatis 사용후 코드 방식

 

public Entity selectFAQList(UserConnection conn, Entity param)  throws SQLException 

{

    UserStatement stmt = null; //stmt 초기값 선언
    ResultSet rslt = null; //rslt 초기값 선언
    StringBuffer sql = new StringBuffer();
    sql.append("\n SELECT *"); //
    sql.append("\n FROM"); //코드 추가
    sql.append("\n TABLE1");
    stmt = conn.prepareStatement(sql.toString());
    rslt = stmt.executeQuery();
    Entity _DATA = new Entity();
    _DATA.put("_DATA", EntityUtil.ResultSetToClobList(rslt));
    return _DATA;
}

 <?xml version="1.0" encoding="UTF-8"?>

  <ENTITY id="table.getTable1List" type="SQL" return="List">
    <![CDATA[
        SELECT *
            FROM
            TABLE1
    ]]>
    <PARAMS>    
    </PARAMS>
  </ENTITY>

// xml로 빼내서 쿼리문을 작성하면 내부적 처리는 Mybatis에서 // 모두 처리해주므로
// Entity ID값을 java에서 호출만하면 된다.




2. 초기 환경설정 셋팅하기


시중 블로그를 다수 검색하고, 교제등을 참고하였으나 왕초보 수준으로 알기 쉽게 적용하는 방법은 나오지 않은 거 같아서 작성해보려고 한다.



그림 1. 초기 셋팅해줘야 하는 프로젝트 파일


최소 못해도 기본적으로 갖춰줘야 하는 소스 파일들을 몇 개 찝어보았다.


"Address_****.파일확장자명"으로 구성된 파일은 사용자에 따라 임의적으로 구성해봐도 무방하다.


ojdbc8_g.jar은 어디에 있는가?

오라클 설치파일이 있는 폴더에 보면 jdbc 폴더가 있는데 해당 위치에 있다.



그림 2. 오라클 설치 파일이 있는 폴더



그림 3. jdbc 폴더에 있는 readme.txt



그림 4. jdbc/lib 폴더 내에 있음.



[첨부(Attachments)]

oracle12lib.z01

oracle12lib.z02

oracle12lib.zip


(참고로 반디집을 통해서 압축을 풀 수 있음.)


소스코드를 통해서 살펴보는 것이 조금 빠를 수 있다고 주장해 본다.



3. 데이터베이스 설계하기


예제 데이터베이스를 설계하도록 하겠다.


tableName(테이블명): addressbook


 키

 항목명

 속성 

 PK(기본키)

num

인덱스(ID)

 

name

nvarchar

 

address

nvarchar

 

birthdate

date




그림 5. 테이블 만들기(오라클)


그림 5는 SQL Developer를 통해서 테이블을 생성한 모습이다. 

원래 복잡하게 쿼리라는 것을 통해서 작성해야 하는데, 세상이 시간이 지나다보니 편리해진 것도 있다고 주장한다.


CREATE TABLE "C##USER"."ADDRESSBOOK" 

   ( "NUM" NUMBER(*,0) NOT NULL ENABLE, 

"NAME" NVARCHAR2(20), 

"ADDRESS" NVARCHAR2(100), 

"BIRTHDATE" DATE, 

CONSTRAINT "ADDRESSBOOK_PK" PRIMARY KEY ("NUM")



  USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS 

  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645

...............................

(중략)


ALTER TRIGGER "C##USER"."ADDRESSBOOK_TRG" ENABLE;



그림 6. SQL문으로 Create Table 구성하기


그림 6은 흔히 CRUD(Create Read Update Delete)에서의 Create를 의미하는 작업이다.

예를 들면 원래는 이렇게 복잡하게 작성해야 하는데 지금은 훨씬 편하게 만들 수 있다고 보면 된다.




4. 프로젝트 구성하기 - 과정 소개 (소스코드를 통해서 살펴보는 프로젝트 구성)


1단계 설계

SQL - 테이블 작성


2단계 기본 환경설정 작성(준비)

web.xml을 먼저 작성한다.              (암기가 되는 부분인가? 불가능. 이거 외우는 거 불가능.)

mybatis-config.xml                     (암기가 되는 부분인가? 불가능. 이거 외우는 거 불가능.)

SqlMapSessionFactory.java           (암기가 되는 부분인가? 불가능. 이거 외우는 거 불가능.)

AddressDto.java 

addressMapper.xml                    (암기가 되는 부분인가? 불가능. 이거 외우는 거 불가능.)


3단계(간단한 CRUD 템플릿 준비)

addressDao.java                       (암기가 되는 부분인가? 코드는 간단하나 2단계 셋팅이 안 되어 있으면 의미 없음.)


4단계(인터페이스 설계 및 구현부 작성)

address.java 

addressImpl.java


5단계(뷰 페이지 구성하기)

web.xml (수정 - 작업)

servlet 페이지로 진행 또는 jsp파일로 진행해도 무방




5. 소스코드


소스코드는 순서대로 소개하겠다.


(2단계 - 소스코드)


<?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_3_1.xsd"

version="3.1">


<display-name>edu-mybatis</display-name>

<welcome-file-list>

<welcome-file>index.html</welcome-file>

<welcome-file>index.htm</welcome-file>

<welcome-file>index.jsp</welcome-file>

<welcome-file>default.html</welcome-file>

<welcome-file>default.htm</welcome-file>

<welcome-file>default.jsp</welcome-file>

</welcome-file-list>

<!-- Board List -->

<servlet>

<servlet-name>boardList</servlet-name>

<servlet-class>com.edu.view.BoardListServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>boardList</servlet-name>

<url-pattern>/board/list.do</url-pattern>

</servlet-mapping>

<!-- Board Insert -->

<servlet>

<servlet-name>boardInsert</servlet-name>

<servlet-class>com.edu.view.BoardInsertServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>boardInsert</servlet-name>

<url-pattern>/board/insert.do</url-pattern>

</servlet-mapping>

<!-- Board Delete -->

<servlet>

<servlet-name>boardDelete</servlet-name>

<servlet-class>com.edu.view.BoardDeleteServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>boardDelete</servlet-name>

<url-pattern>/board/delete.do</url-pattern>

</servlet-mapping>

</web-app>


* 파일명: web.xml


[첨부(Attachments)]

web.zip



예를 들면, 이런 형태로 구성해서 사용할 수 있다.

크게 어렵게 작성하진 않았으니 참고하면 도움이 될 것 같다.


<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 

"http://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>


<environments default="development">

    <environment id="development">

      <transactionManager type="JDBC"/>

      <dataSource type="POOLED">

        <property name="driver" value="oracle.jdbc.driver.OracleDriver" />

        <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/>

        <property name="username" value="사용자 계정"/>

        <property name="password" value="비밀번호"/>

      </dataSource>

    </environment>

  </environments>


  <mappers>

    <mapper resource="com/edu/db/addressMapper.xml"/>              // 리소스 증가시 추가해서 사용해보기

  </mappers>


</configuration>


* 파일명: mybatis-config.xml



[첨부(Attachments)]

mybatis-config.zip



package com.edu.db;


import java.io.IOException;

import java.io.InputStream;

import org.apache.ibatis.io.Resources;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.session.SqlSessionFactoryBuilder;


public class SqlMapSessionFactory {

public static SqlSessionFactory ssf;


    static{


        String resource = "com/edu/db/mybatis-config.xml";

        InputStream inputStream = null;


        try {

            inputStream = Resources.getResourceAsStream(resource);

        } catch (IOException e) {

            e.printStackTrace();

        }


        ssf = new SqlSessionFactoryBuilder().build(inputStream);


    }

    

    public static SqlSessionFactory getSqlSessionFactory(){

        return ssf;

    }

    

}



* 파일명: SqlMapSessionFactory.java


[첨부(Attachments)]

SqlMapSessionFactory.zip


package com.edu.db;


import java.sql.Timestamp;


public class AddressDto {

private int num;

private String name;

private String address;

private Timestamp birthdate;

public int getNum() {

return num;

}

public void setNum(int num) {

this.num = num;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getAddress() {

return address;

}

public void setAddress(String address) {

this.address = address;

}

public Timestamp getBirthdate() {

return birthdate;

}

public void setBirthdate(Timestamp birthdate) {

this.birthdate = birthdate;

}

}



* 파일명: AddressDto.java


[첨부(Attachments)]

AddressDto.zip


<?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="com.edu.db.mappers.addressMapper">

<select id="allAddress" resultType="com.edu.db.AddressDto">

select * from addressbook

</select>


<select id="selectAddress" parameterType="Integer" resultType="com.edu.db.AddressDto">

select NUM, NAME, ADDRESS, BIRTHDATE

from addressbook

  where num=#{num}

</select>


<insert id="insertAddress" parameterType="com.edu.db.AddressDto">

insert into

addressbook(NAME, ADDRESS, BIRTHDATE)

values

(#{name},#{address},#{birthdate})

</insert>


<delete id="deleteAddress" parameterType="Integer">

DELETE FROM AddressBook

WHERE NUM = #{num}

</delete>

<update id="updateAddress" parameterType="com.edu.db.AddressDto" >

update addressbook

set birthdate = #{birthdate}, name = #{name}, address =#{address}

where num = #{num}

</update>

</mapper>


* 파일명: addressMappper.xml


[첨부(Attachments)]

addressMapper.zip


(3단계 - 소스코드)


package com.edu.db;

import java.io.*;

import java.util.*;

import org.apache.ibatis.io.*;

import org.apache.ibatis.session.*;


public class AddressDao {

private AddressDao() {}

    private static AddressDao dao;


    public static AddressDao getInstance(){


        if(dao == null){

            dao = new AddressDao();

        }


        return dao;

    }

    

    // SQL 세션 열기

    SqlSessionFactory factory = SqlMapSessionFactory.getSqlSessionFactory();


    public AddressDto selectAddress(Integer num) {


        SqlSession session = factory.openSession();


        AddressDto addressDTO = session.selectOne("com.edu.db.mappers.addressMapper.selectAddress", num);

        session.close();


        return addressDTO;


    }


 


    public int updateAddress(AddressDto addressDTO) {


        SqlSession session = factory.openSession();


        int update = session.update("com.edu.db.mappers.addressMapper.updateAddress", addressDTO);


        // update나 delete의 경우 반드시 커밋 필요.

        // session.commit();을 해주거나 factory.openSession(true);로 설정하면 자동 커밋된다.

        session.commit(); 

        session.close();


        return update;


    }

    

    

    public int insertAddress(AddressDto addressDTO) {

   

    SqlSession session = factory.openSession();

    int insert = session.insert("com.edu.db.mappers.addressMapper.insertAddress", addressDTO);

   

    session.commit();

    session.close();

   

    return insert;

   

    }

    

    public int deleteAddress(Integer num) {

   

    SqlSession session = factory.openSession();

    int delete = session.delete("com.edu.db.mappers.addressMapper.deleteAddress", num);

   

    session.commit();

    session.close();

   

    return delete;

    }


}


* 파일명: AddressDao.java


특징: Singleton 패턴을 적용함.


[첨부(Attachments)]

AddressDao.zip



(4단계 - 소스코드)


package com.edu.db;


public interface Address {


public AddressDto getAddress(Integer num);

public int updateAddress(AddressDto addressDTO);

public int insertAddress(AddressDto addressDTO); 

public int deleteAddress(Integer num);

}


* 파일명: Address.java


특징: Interface 파일


[첨부(Attachments)]

Address.zip


package com.edu.db;


public class AddressImpl implements Address {


AddressDao dao = AddressDao.getInstance();

@Override

public AddressDto getAddress(Integer num) {

return dao.selectAddress(num);

}


@Override

public int updateAddress(AddressDto addressDTO) {

return dao.updateAddress(addressDTO);

}

@Override

public int insertAddress(AddressDto addressDTO) {

return dao.insertAddress(addressDTO);

}

@Override

public int deleteAddress(Integer num) {

return dao.deleteAddress(num);

}


}


* 파일명: AddressImpl.java


특징: Address 인터페이스 구현파일


[첨부(Attachments)]

AddressImpl.zip


(5단계 - Servlet 파일 예)


package com.edu.view;


import java.io.IOException;

import java.io.PrintWriter;

import java.sql.Timestamp;

import java.text.SimpleDateFormat;


import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.edu.db.Address;

import com.edu.db.AddressDto;

import com.edu.db.AddressImpl;


/**

 * Servlet implementation class boardListServlet

 */

public class BoardListServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

       

    /**

     * @see HttpServlet#HttpServlet()

     */

    public BoardListServlet() {

        super();

    }


/**

* @see HttpServlet#doGet(HttpServletRequest req, HttpServletResponse res)

*/

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

res.setContentType("text/html;charset=UTF-8");

PrintWriter out = res.getWriter();

out.print("<br/>");

AddressImpl address = new AddressImpl();

AddressDto addressDto = address.getAddress(1);

out.println("<html><head><title>CRUD - List2</title></head>");

out.println("<body><h2>MyBatis - List</h2>");

SimpleDateFormat format1 = new SimpleDateFormat ( "yyyy-MM-dd" );

String birthdate = format1.format(addressDto.getBirthdate());

out.print(addressDto.getNum() + "/" + addressDto.getName() + "/");

out.print(addressDto.getAddress() + "/" + birthdate);

out.print("<br/>");

out.println("</body></html>");

out.close();

}

/**

* @see HttpServlet#doPost(HttpServletRequest req, HttpServletResponse res)

*/

protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

doGet(req, res);

}


}



* 파일명: boardListServlet.java


어노테이션으로 맵핑하지 않고, web.xml에 URL 맵핑하였음.


[첨부(Attachments)]

BoardListServlet.zip


package com.edu.view;


import java.io.IOException;

import java.io.PrintWriter;

import java.sql.Timestamp;


import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.edu.db.Address;

import com.edu.db.AddressDto;

import com.edu.db.AddressImpl;


/**

 * Servlet implementation class boardInsertServlet

 */

public class BoardInsertServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

       

    /**

     * @see HttpServlet#HttpServlet()

     */

    public BoardInsertServlet() {

        super();

    }


/**

* @see HttpServlet#doGet(HttpServletRequest req, HttpServletResponse res)

*/

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

res.setContentType("text/html;charset=UTF-8");

PrintWriter out = res.getWriter();

out.print("<br/>");

AddressImpl address = new AddressImpl();

AddressDto dbNode = new AddressDto(); 

dbNode.setName("도도" + serialVersionUID);

dbNode.setAddress("행복시 행복동");

// 버그1: new Date() 사용안됨. (2020을 3920으로 인식함.) 

// 버그2: new Timestamp() 사용안됨. (2020을 3920으로 인식함.)

String userDate = "2020-02-01";

java.sql.Timestamp sqlDate = java.sql.Timestamp.valueOf(userDate);

dbNode.setBirthdate(sqlDate);

int result = address.insertAddress(dbNode);

AddressDto addressDto = address.getAddress(1);

out.println("<html><head><title>CRUD - Insert</title></head>");

out.println("<body><h2>MyBatis - Insert</h2>");

out.print("<br/>");

out.print("등록여부:" + result + "</br>");

out.print("<br/>");

out.print(addressDto.getNum() + "/" + addressDto.getName() + "/");

out.print(addressDto.getAddress() + "/" + addressDto.getBirthdate());

out.println("</body></html>");

out.close();

}

/**

* @see HttpServlet#doPost(HttpServletRequest req, HttpServletResponse res)

*/

protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

doGet(req, res);

}


}


* 파일명: boardInsertServlet.java


[첨부(Attachments)]

BoardInsertServlet.zip



package com.edu.view;


import java.io.IOException;

import java.io.PrintWriter;

import java.sql.Timestamp;


import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.edu.db.Address;

import com.edu.db.AddressDto;

import com.edu.db.AddressImpl;


/**

 * Servlet implementation class boardInsertServlet

 */

public class BoardDeleteServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

       

    /**

     * @see HttpServlet#HttpServlet()

     */

    public BoardDeleteServlet() {

        super();

    }


/**

* @see HttpServlet#doGet(HttpServletRequest req, HttpServletResponse res)

*/

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

res.setContentType("text/html;charset=UTF-8");

PrintWriter out = res.getWriter();

out.print("<br/>");

AddressImpl address = new AddressImpl();

int result = address.deleteAddress(5);

AddressDto addressDto = address.getAddress(5);

out.println("<html><head><title>CRUD - Delete</title></head>");

out.println("<body><h2>MyBatis - Delete</h2>");

out.print("<br/>");

out.print("삭제여부:" + result + "</br>");

out.print("<br/>");

if ( addressDto != null ) {

out.print(addressDto.getNum() + "/" + addressDto.getName() + "/");

out.print(addressDto.getAddress() + "/" + addressDto.getBirthdate());

}

out.println("</body></html>");

out.close();

}


/**

* @see HttpServlet#doPost(HttpServletRequest req, HttpServletResponse res)

*/

protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

doGet(req, res);

}


}



* 파일명: BoardDeleteServlet.java


[첨부(Attachments)]

BoardDeleteServlet.zip



package com.edu.view;


import java.io.IOException;

import java.io.PrintWriter;

import java.sql.Timestamp;


import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import com.edu.db.AddressDto;

import com.edu.db.AddressImpl;


@WebServlet("/board/update.do")

public class BoardUpdateServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

       

    /**

     * @see HttpServlet#HttpServlet()

     */

    public BoardUpdateServlet() {

        super();

    }


/**

* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)

*/

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

res.setContentType("text/html;charset=UTF-8");

PrintWriter out = res.getWriter();

out.print("<br/>");

AddressImpl address = new AddressImpl();

AddressDto dbNode = new AddressDto();

dbNode.setNum(3);

dbNode.setName("도도수정" + serialVersionUID);

dbNode.setAddress("행복시 행복동");


// 버그1: new Date() 사용안됨. (2020을 3920으로 인식함.) 

// 버그2: new Timestamp() 사용안됨. (2020을 3920으로 인식함.)

String userDate = "2020-07-01";

java.sql.Timestamp sqlDate = java.sql.Timestamp.valueOf(userDate);

dbNode.setBirthdate(sqlDate);

int result = address.updateAddress(dbNode);

AddressDto addressDto = address.getAddress(3);

out.println("<html><head><title>CRUD - Update</title></head>");

out.println("<body><h2>MyBatis - Update</h2>");

out.print("<br/>");

out.print("수정여부:" + result + "</br>");

out.print("<br/>");

out.print(addressDto.getNum() + "/" + addressDto.getName() + "/");

out.print(addressDto.getAddress() + "/" + addressDto.getBirthdate());

out.println("</body></html>");

out.close();

}


/**

* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)

*/

protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

doGet(req, res);

}


}



* 파일명: BoardUpdateServlet.java


특징: web.xml으로 맵핑하지 않고, @WebServlet으로 어노테이션을 사용하여 매핑처리함.


[첨부(Attachments)]

BoardUpdateServlet.zip




6. 맺음글


순수한 JSP 기반의 MyBatis 프레임워크 사용방법에 대해서 소개해보았다.

많은 도움이 되었으면 좋겠다.


1. [JSP] 19. MyBatis-3.5.5 와 Maven / Servlet 연동하기 (Oracle 19g) - Java 방식, 2020-10-01

https://yyman.tistory.com/1434



[참고 자료(Reference)]


1. [Java, OpenJDK] Timestamp 형식 변환, https://infotake.tistory.com/16, Accessed by 2020-09-18, Last Modified 2018-09-13.

-> 참고 이유: Timestamp 명령 사용방법 참고함.


2. 내가 그리는 세상  DB(mysql)에 timestamp로 저장된 값 java에서 불러오기_getTimestamp(), https://yoonka.tistory.com/450, Accessed by 2020-09-18, Last Modified 2013-10-28.


3. [JSP] Mybatis 사용하기  또리야 개발하자, https://ddoriya.tistory.com/entry/JSP-Mybatis-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0, Accessed by 2020-09-17, Last Modified 2014-11-18.

-> 추천(60점 이상): 이 사이트의 글만 가지고 따라하면, 완벽하게 동작이 되진 않음. 몇 가지 보충을 해줘야 해서 추가적으로 검색하였음.
그래도 순수한 MyBatis 원리에 대해서 많은 영감을 얻었음.


4. Oracle와 mybatis 연동 실습, https://dlgkstjq623.tistory.com/228, Accessed by 2020-09-18, Last Modified 2019-06-05.

-> 추천(40점 이상): 이 사이트의 글을 이해하려면, Spring Framework 지식과 JSTL 지식이 있어야 함.

   기본적인 흐름 정도 파악하는데 참고하였음. (이론적인 느낌을 얻었음.)


5. MyBatis – 마이바티스 3 | 소개, https://mybatis.org/mybatis-3/ko/index.html, Accessed by 2020-09-18, Last Modified 2020-06-05.

-> 추천(20점 이상): 설명서가 조금 어렵게 되어 있음. 셋팅 파일을 가지고 셋팅한 후 설명서를 참고하면 도움이 될 수도 있음.


6. 4. Spring Boot Oracle DB 연동(JSP, MyBatis), https://dotheright.tistory.com/173, Accessed by 2020-09-18, Last Modified 2020-07-15.

-> 삽질하여 실패와 탐구 등의 횟수 기록이 담겨져 있음. ("삽질을 하게 된다.??" 이런 느낌을 보여줌.)

-> Spring Framework 기반으로 만든 소스코드를 소개하고 있음. (이 게시글 작성에 있어서 크게 영향을 주지 못함.)


7. [JSP] JSP에 MyBatis 연결하기, https://yuja-kong.tistory.com/8, Accessed by 2020-09-18, Last Modified 2018-04-17.

-> 추천(50점 이상): 순수한 JSP와 MyBatis 연결에 대해서 소개하고 있는데, 이 글을 작성할 수 있는 가능성을 만들어 줌.


8. JSP 서블릿 한글 세팅(한글 깨짐 해결 하기), https://developsd.tistory.com/100, Accessed by 2020-09-18, Last Modified 2019-05-18.

-> 추천(20점): 오라클DB(이하 "UTF-8 셋팅한 오라클")로 데이터를 불러오려고 했을 때, ?????라고 한글을 인식하지 못했음.

   간단한 명령어 하나로 해결하는 데 도움을 받았음. (가끔은 쉬운 게 어렵고, 어려운 게 쉬울 때도 있다는 생각이 듬.)


1. 파일의 인코딩 속성을 "UTF-8"으로 변경

2. response.setContentType("text/html;charset=UTF-8");


반응형

+ Recent posts