๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ–ฅ๏ธ ๋ฐฑ์—”๋“œ/SpringBoot

[์„ค์ •] SpringBoot + MyBatis + Oracle + JSP ์—ฐ๋™ ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ ์„ค์ • ์ •๋ณด

by OR15A 2023. 12. 11.
SpringBoot๋Š” ์ฃผ๋กœ JPA์™€ Thymeleaf๋ฅผ ํŒŒํŠธ๋„ˆ๋กœ ์‚ผ์•„ ๊ฐœ๋ฐœ์ž๋“ค์—๊ฒŒ ๋„๋ฆฌ ์•Œ๋ ค์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ๊ธฐ์ˆ ์˜ ์„ธ๊ณ„์—์„œ๋Š” ์–ธ์ œ๋‚˜ ์˜ˆ์™ธ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.....
๋ณธ ๊ธ€์—์„œ๋Š” SpringBoot๋ฅผ MyBatis์™€ Oracle DB์— ์—ฐ๊ฒฐํ•˜๊ณ ,
JSP๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ทฐ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ณผ์ •์— ํ•„์š”ํ•œ ์„ค์ •๋“ค์— ๋Œ€ํ•ด ๊ธฐ๋กํ•˜์˜€์Šต๋‹ˆ๋‹ค.


ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ์€ ์ธํ…”๋ฆฌ์ œ์ด์™€ ์œˆ๋„์šฐ์ด๋ฉฐ,
๊ฒŒ์‹œํŒ์˜ ๊ธ€๋ชฉ๋ก์„ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ๊นŒ์ง€์˜ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋กœ ์ด๋ฃจ์–ด์ ธ์žˆ์Šต๋‹ˆ๋‹ค.
์Šคํ”„๋ง๋ถ€ํŠธ 2.X.X ๋ฒ„์ „, ์ž๋ฐ” 11 ๋“ฑ ๋‚ฎ์€ ๋ฒ„์ „์ผ ๋•Œ์˜ ์„ค์ •์ž…๋‹ˆ๋‹ค.

 

 

์ค€๋น„๋ฌผ: SpringBoot ํ”„๋กœ์ ํŠธ
  • ์ด ๊ธ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” build.gradle ์ž…๋‹ˆ๋‹ค. 
plugins {
	id 'org.springframework.boot' version '2.4.1'  //์Šคํ”„๋ง๋ถ€ํŠธ 2.X.X ๋ฒ„์ „
	id 'io.spring.dependency-management' version '1.0.10.RELEASE'
	id 'java'
}

group = 'com.ํ”„๋กœ์ ํŠธ.ํŒจํ‚ค์ง€์ด๋ฆ„'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'   //์ž๋ฐ” 11

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-validation'
//	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' //JSP๋ฅผ ์ด์šฉํ•˜๋ฏ€๋กœ ์ฃผ์„์ฒ˜๋ฆฌ
	implementation 'org.springframework.boot:spring-boot-starter-web'

	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.4' // MyBatis ์Šคํ”„๋ง ๋ถ€ํŠธ ์Šคํƒ€ํ„ฐ
    implementation 'com.oracle.database.jdbc:ojdbc8:21.9.0.0' // ์˜ค๋ผํด JDBC ๋“œ๋ผ์ด๋ฒ„


	implementation 'org.apache.tomcat.embed:tomcat-embed-jasper' //JSP ์ด์šฉ์„ ์œ„ํ•œ ์˜์กด์„ฑ
    implementation 'javax.servlet:jstl'  //JSTL ์ด์šฉํ•˜๊ธฐ


	compileOnly 'org.projectlombok:lombok'
//	runtimeOnly 'com.h2database:h2'

	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	//JUnit4 ์ถ”๊ฐ€
	testImplementation("org.junit.vintage:junit-vintage-engine") {
		exclude group: "org.hamcrest", module: "hamcrest-core"
	}

}

test {
	useJUnitPlatform()
}
  • ์Šคํ”„๋ง๋ถ€ํŠธ ๋ฒ„์ „, ์ž๋ฐ” ์ปดํŒŒ์ผ๋Ÿฌ ๋ฒ„์ „, MyBatis ์Šคํƒ€ํ„ฐ ๋ฒ„์ „, ์˜ค๋ผํด JDBC ๋“œ๋ผ์ด๋ฒ„ ๋ฒ„์ „์„ ํ™•์ธํ•˜์„ธ์š”
  • JSP์ด์šฉ์„ ์œ„ํ•œ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”

 

Oracle ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ†ตํ•ฉ
  • application.properties ์— ์ž์‹ ์˜ DB์ •๋ณด๋ฅผ ๋“ฑ๋กํ•ด์„œ Oracle ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค
# application.properties
spring.datasource.url=jdbc:oracle:thin:@์—ฌ๊ธฐ์—IP๋ฒˆํ˜ธ๋“ฑ๋กํ•˜๊ณ :์—ฌ๊ธฐ๋Š”ํฌํŠธ4์ž๋ฆฌ:xe
spring.datasource.username=๋””๋น„๋กœ๊ทธ์ธ์œ ์ €๋„ค์ž„
spring.datasource.password=๋””๋น„๋กœ๊ทธ์ธํŒจ์Šค์›Œ๋“œ
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect

# HikariCP 
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=MyHikariCP
spring.datasource.hikari.max-lifetime=600000
spring.datasource.hikari.connection-timeout=30000

# MyBatis 
mybatis.type-aliases-package=com.ํ”„๋กœ์ ํŠธ.ํŒจํ‚ค์ง€๋ช….domain
mybatis.mapper-locations=classpath:/mappers/**/*.xml
mybatis.configuration.map-underscore-to-camel-case=true

# 
spring.application.name=๊ฐœ์ธ๋งˆ๋‹ค๋‹ค๋ฆ„

# JSP ์œ„์น˜
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
  • ์ง์ ‘ ๋“ฑ๋กํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

MyBatis ์„ค์ •
  • ์•„๋ž˜ ๊ณ„์ธต์˜ ํ˜•ํƒœ๋กœ ํด๋” ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๊ณ , mapper.xmlํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

  • boardMapper.xml์˜ ๋‚ด์šฉ
<?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.ํ”„๋กœ์ ํŠธ.ํŒจํ‚ค์ง€๋ช….repository.BoardMapper">


    <select id="selectList" resultType="BoardDto">
        SELECT  /*+ INDEX(BOARD_STUDY idx_BOARD_STUDY_SEQ) */
                SEQ
             , MEM_NAME
             , MEM_ID
             , BOARD_SUBJECT
             , BOARD_CONTENT
             , REG_DATE
             , UPT_DATE
             , VIEW_CNT
             , USEYN
        FROM BOARD_STUDY
        WHERE ROWNUM <![CDATA[ <= ]]> 20
        ORDER BY SEQ DESC
    </select>


</mapper>
  • ํ˜„์žฌ ํŒจํ‚ค์ง€์— ํ•˜์œ„ ํŒจํ‚ค์ง€์ธ config ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ ๋‹ค. ๊ทธ ์•ˆ์— MabatisConfig ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋‹ค.

package com.ํ”„๋กœ์ ํŠธ.ํŒจํ‚ค์ง€๋ช….config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.ํ”„๋กœ์ ํŠธ.ํŒจํ‚ค์ง€๋ช….repository") // MyBatis Mapper ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ๋Š” ํŒจํ‚ค์ง€๋ฅผ ์Šค์บ”
public class MyBatisConfig {
    // ์ถ”๊ฐ€์ ์ธ MyBatis ์„ค์ • ๋ฐ ๋นˆ ์ •์˜ ํ•  ์ˆ˜ ์žˆ์Œ
}
  • repositoryํŒจํ‚ค์ง€ ์•ˆ์— BoardMapper ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

package com.ํ”„๋กœ์ ํŠธ.ํŒจํ‚ค์ง€.repository;

import com.ํ”„๋กœ์ ํŠธ.ํŒจํ‚ค์ง€.domain.BoardDto;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface BoardMapper {
    // ๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก ์กฐํšŒ
    List<BoardDto> selectList();


}
  • Repositoryํด๋ž˜์Šค์—์„œ BoardMapper๋ฅผ ์ฃผ์ž…๋ฐ›๊ณ , Mapper.xml์˜ ์ฟผ๋ฆฌ๋ฌธ์„ ์‚ฌ์šฉํ•ด์„œ DB์—์„œ ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค.
package com.ํ”„๋กœ์ ํŠธ.ํŒจํ‚ค์ง€๋ช….repository;


import com.ํ”„๋กœ์ ํŠธ.ํŒจํ‚ค์ง€๋ช….domain.BoardDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class BoardRepository {

    private final BoardMapper boardMapper;

    @Autowired
    public BoardRepository(BoardMapper boardMapper) {
            this.boardMapper = boardMapper;
        }

    public List<BoardDto> findAll() {
        return boardMapper.selectList();
    }

}

 

 

 

โ“ DTO ๋ฐ ๊ทธ ์™ธ์˜ ์ฝ”๋“œ
๋”๋ณด๊ธฐ

ํŒจํ‚ค์ง€ ๊ตฌ์กฐ

 

์ปจํŠธ๋กค๋Ÿฌ

@Controller
public class BoardController {

    @Autowired
    BoardService boardService;

    @GetMapping("/boardList")
    public String boardList(Model model) throws SQLException {
        List<BoardDto> list = new ArrayList<>();

        try {
            list = boardService.findBoards();
            model.addAttribute("boardList",list);
        } catch (SQLException e){
            model.addAttribute("boardList",list);
        }
        
        return "boardList";
    }

}

 

 ์„œ๋น„์Šค

@Service
public class BoardService {

    @Autowired
    private BoardRepository boardRepository;

    //๋ณด๋“œ ๋ฆฌ์ŠคํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ
    public List<BoardDto> findBoards() throws SQLException {
        List<BoardDto> list = new ArrayList<>();
        list = boardRepository.findAll();
        return list;
    }

}

 ๊ฐ„๋‹จํ•œ ์ž‘์„ฑ์„ ์œ„ํ•ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€์  ์–‘ํ•ด๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

 

board ๊ฒŒ์‹œ๊ธ€ dto (๊ฐ์ž ๋งŒ๋“  Table์— ๋งž์ถฐ ์ˆ˜์ •ํ•˜์„ธ์š”)

@Getter @Setter
@ToString
@AllArgsConstructor
public class BoardDto {

    private int seq;
    private String mem_name;
    private String mem_id;
    private String board_subject;
    private String board_content;
    private LocalDateTime reg_date;
    private LocalDateTime upt_date;
    private String view_cnt;
    private String useyn;


}

 

 

JSP๋ฅผ ์œ„ํ•œ ๋ทฐ ์„ค์ •
  • mainํด๋” ์•„๋ž˜์— ๊ธฐ์กด์— ์žˆ๋Š” java, resources์™€ ๊ฐ™์€ ๋ ˆ๋ฒจ๋กœ webapp ํด๋”๋ฅผ ๋งŒ๋“ ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ํด๋”๋ฅผ ๋งŒ๋“คํ•˜๊ณ  jspํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค

  • JSPํŒŒ์ผ
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<head>
    <title>๊ฒŒ์‹œํŒ</title>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <script src="/resources/js/boardList.js"></script>

    <style>
    .fixed-col-title {
      width: 150px;
      background-color: cornsilk;
    }
    .fixed-col-s {
      width: 80px;
    }
    .fixed-col-m {
      width: 180px;
    }
    </style>

</head>
<body>
<p> ๊ฒŒ์‹œํŒ ๊ธ€ ๋ชฉ๋ก </p>
<table border="1">
    <thead>
    <tr>
        <th><input type="checkbox" name="allChk" id="allChk"></th>
        <th class="fixed-col-s">๊ธ€๋ฒˆํ˜ธ</th>
        <th class="fixed-col-s">์ž‘์„ฑ์ž ID</th>
        <th class="fixed-col-title">์ œ๋ชฉ</th>
        <th class="fixed-col-m">์ž‘์„ฑ์ผ</th>
        <th class="fixed-col-m">์ˆ˜์ •์ผ</th>
        <th class="fixed-col-s">์กฐํšŒ์ˆ˜</th>
    </tr>
    </thead>
    <tbody>
    <!-- List๋ฅผ ๋ฐ˜๋ณตํ•˜๋ฉด์„œ index๋ฅผ ์‚ฌ์šฉ -->

    <c:forEach items="${boardList}" var="board" varStatus="status">
        <tr name="trBoard${status.index}" id="trBoard${status.index}">
            <td><input type="checkbox" name="tdBoard${status.index}" id="tdBoard${status.index}"></td>
            <td>${board.getSeq()}</td>
            <td>${board.getMem_id()}</td>
            <td><a href="">${board.getBoard_subject()}</a></td>
            <td>${board.getReg_date()}</td>
            <td>${board.getUpt_date()}</td>
            <td>${board.getView_cnt()}</td>
        </tr>
    </c:forEach>

    <!--๋ฐ˜๋ณต ์˜ˆ์‹œ-->
    <%--    <tr>--%>
    <%--        <td><input type="checkbox" name="" id=""></td>--%>
    <%--        <td>ํ–‰ 1, ์—ด 2</td>--%>
    <%--        <td>ํ–‰ 1, ์—ด 3</td>--%>
    <%--        <td>ํ–‰ 1, ์—ด 4</td>--%>
    <%--        <td>ํ–‰ 1, ์—ด 5</td>--%>
    <%--        <td>ํ–‰ 1, ์—ด 6</td>--%>
    <%--        <td>ํ–‰ 1, ์—ด 7</td>--%>
    <%--    </tr>--%>
    <!--๋ฐ˜๋ณต ์˜ˆ์‹œ-->
    </tbody>
</table>

</body>
</html>