728x90
300x250

[JSP] 18. JSP/Servlet MVC2 - 페이징네이션과 검색 그리고 오라클 프로젝트 (2)


2부에서는 페이징, DB구현부, 모델, 서비스 영역에 대해서 소개하겠다.


1. [JSP] 18. JSP/Servlet MVC2 - 페이징네이션과 검색 그리고 오라클 프로젝트 (1)

https://yyman.tistory.com/1428




14. 페이징네이션 


실제경로: /target/generated-sources/annotations/com/smile/web/model

패키지명: com.smile.web.logic

파일명: Paging.java


아마 이거 하나면, 현존에 있는 페이지 기법은 충분히 소화되지 않겠냐는 생각이다.

물론 정답은 아니다. 오류가 있을 수도 있다.


이러한 복잡한 문제에 직면했을 때, 수학을 공부 많이 해야 한다고 생각한다.

머리가 좋으신 분들이 많으시니깐 더 좋은 방법이 있다면, 개선해봐도 좋을 듯 싶다.


package com.smile.web.logic;


public class Paging {

    private long pageSize; // 게시 글 수

    private long firstPageNo; // 첫 번째 페이지 번호

    private long prevPageNo; // 이전 페이지 번호

    private long startPageNo; // 시작 페이지 (페이징 네비 기준)

    private long pageNo; // 페이지 번호

    private long endPageNo; // 끝 페이지 (페이징 네비 기준)

    private long nextPageNo; // 다음 페이지 번호

    private long finalPageNo; // 마지막 페이지 번호

    private long totalCount; // 게시 글 전체 수

    private long dbStartNum; // db 조회 (시작번호)

    private long dbEndNum; // db 조회 (종료번호)


    /**

     * @return the pageSize

     */

    public long getPageSize() {

        return pageSize;

    }


    /**

     * @param pageSize the pageSize to set

     */

    public void setPageSize(long pageSize) {

        this.pageSize = pageSize;

    }


    /**

     * @return the firstPageNo

     */

    public long getFirstPageNo() {

        return firstPageNo;

    }


    /**

     * @param firstPageNo the firstPageNo to set

     */

    public void setFirstPageNo(long firstPageNo) {

        this.firstPageNo = firstPageNo;

    }


    /**

     * @return the prevPageNo

     */

    public long getPrevPageNo() {

        return prevPageNo;

    }


    /**

     * @param prevPageNo the prevPageNo to set

     */

    public void setPrevPageNo(long prevPageNo) {

        this.prevPageNo = prevPageNo;

    }


    /**

     * @return the startPageNo

     */

    public long getStartPageNo() {

        return startPageNo;

    }


    /**

     * @param startPageNo the startPageNo to set

     */

    public void setStartPageNo(long startPageNo) {

        this.startPageNo = startPageNo;

    }


    /**

     * @return the pageNo

     */

    public long getPageNo() {

        return pageNo;

    }


    /**

     * @param pageNo the pageNo to set

     */

    public void setPageNo(long pageNo) {

        this.pageNo = pageNo;

    }


    /**

     * @return the endPageNo

     */

    public long getEndPageNo() {

        return endPageNo;

    }


    /**

     * @param endPageNo the endPageNo to set

     */

    public void setEndPageNo(long endPageNo) {

        this.endPageNo = endPageNo;

    }


    /**

     * @return the nextPageNo

     */

    public long getNextPageNo() {

        return nextPageNo;

    }


    /**

     * @param nextPageNo the nextPageNo to set

     */

    public void setNextPageNo(long nextPageNo) {

        this.nextPageNo = nextPageNo;

    }


    /**

     * @return the finalPageNo

     */

    public long getFinalPageNo() {

        return finalPageNo;

    }


    /**

     * @param finalPageNo the finalPageNo to set

     */

    public void setFinalPageNo(long finalPageNo) {

        this.finalPageNo = finalPageNo;

    }


    /**

     * @return the totalCount

     */

    public long getTotalCount() {

        return totalCount;

    }


    /**

     * @param totalCount the totalCount to set

     */

    public void setTotalCount(long totalCount) {

        this.totalCount = totalCount;

        this.makePaging();

        this.makeDbPaging();

    }


    /**

     * 페이징 생성 (setTotalCount에서 호출함)

     */

    private void makePaging() {

   

        if (this.totalCount == 0) 

        return; 

        

        // 게시 글 전체 수가 없는 경우

        

        if (this.pageNo == 0) 

        this.setPageNo(1); // 기본 값 설정

        

        if (this.pageSize == 0) 

        this.setPageSize(10); // 기본 값 설정


        long finalPage = (totalCount + (pageSize - 1)) / pageSize; // 마지막 페이지

        

        if (this.pageNo > finalPage) 

        this.setPageNo(finalPage); // 기본 값 설정


        if (this.pageNo < 0 || this.pageNo > finalPage) 

        this.pageNo = 1; // 현재 페이지 유효성 체크


        boolean isNowFirst = pageNo == 1 ? true : false; // 시작 페이지 (전체)

        boolean isNowFinal = pageNo == finalPage ? true : false; // 마지막 페이지 (전체)


        long startPage = ((pageNo - 1) / 10) * 10 + 1; // 시작 페이지 (페이징 네비 기준)

        long endPage = startPage + 10 - 1; // 끝 페이지 (페이징 네비 기준)


        if (endPage > finalPage) { // [마지막 페이지 (페이징 네비 기준) > 마지막 페이지] 보다 큰 경우

            endPage = finalPage;

        }


        this.setFirstPageNo(1); // 첫 번째 페이지 번호


        if (isNowFirst) {

            this.setPrevPageNo(1);    // 이전 페이지 번호

        } else {

            this.setPrevPageNo(((pageNo - 1) < 1 ? 1 : (pageNo - 1))); // 이전 페이지 번호

        }


        this.setStartPageNo(startPage); // 시작 페이지 (페이징 네비 기준)

        this.setEndPageNo(endPage); // 끝 페이지 (페이징 네비 기준)


        if (isNowFinal) {

            this.setNextPageNo(finalPage); // 다음 페이지 번호

        } else {

            this.setNextPageNo(((pageNo + 1) > finalPage ? finalPage : (pageNo + 1))); // 다음 페이지 번호

        }


        this.setFinalPageNo(finalPage); // 마지막 페이지 번호

        

    }

    

    private void makeDbPaging() {

   

    long current = this.getPageNo();

    long weight = this.getPageSize();

    long endNum = 0;

   

    this.setDbEndNum( current * weight );

   

    endNum = this.getDbEndNum();

    this.setDbStartNum( (endNum - weight) + 1 );

   

    }


    /**

     * @return the dbStartNum

     */

public long getDbStartNum() {

return dbStartNum;

}



    /**

     * @param dbStartNum the dbStartNum to set

     */

public void setDbStartNum(long dbStartNum) {

this.dbStartNum = dbStartNum;

}


    /**

     * @return dbEndNum

     */


public long getDbEndNum() {

return dbEndNum;

}



    /**

     * @param dbEndNum the dbEndNum to set

     */

public void setDbEndNum(long dbEndNum) {

this.dbEndNum = dbEndNum;

}

    

}


파일명: Paging.java


[첨부(Attachments)]

Paging.zip




15. Board.java - 모델(Model)


실제경로: /target/generated-sources/annotations/com/smile/web/model

패키지명: com.smile.web.model

파일명: Board.java


게시판 모델에 대한 설계이다.


package com.smile.web.model;


import java.sql.Timestamp;


public class Board {


private long id;

private String name;

private String subject;

private String memo;

private long count;

private Timestamp regidate;

public long getId() {

return id;

}

public void setId(long id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getSubject() {

return subject;

}

public void setSubject(String subject) {

this.subject = subject;

}

public String getMemo() {

return memo;

}

public void setMemo(String memo) {

this.memo = memo;

}


public long getCount() {

return count;

}


public void setCount(long count) {

this.count = count;

}


public Timestamp getRegidate() {

return regidate;

}


public void setRegidate(Timestamp regidate) {

this.regidate = regidate;

}

}



파일명: Board.java


[첨부(Attachments)]

Board.zip




16. BoardService.java - Service 영역


실제경로: /target/generated-sources/annotations/com/smile/web/service

패키지명: com.smile.web.service

파일명: BoardService.java


게시판 서비스에 필요한 영역을 구현한 것이다.


package com.smile.web.service;


import java.util.List;


import com.smile.web.model.Board;


public class BoardService {

private static BoardService service = null;

private static BoardServiceImpl dao = null;

private BoardService() {}

public static BoardService getInstance() {


        if(service == null){

        service = new BoardService();

    dao = BoardServiceImpl.getInstatnce();

        }


        return service;

}

public List<Board> getBoardList(long startNum, long endNum){

return dao.getBoardList(startNum, endNum);

}

public long getTotalCount() {

return dao.getTotalCount();

}

public List<Board> getBoardKeywordList(String keyword, long startNum, long endNum){

return dao.getBoardKeywordList(keyword, startNum, endNum);

}


public long getTotalKeywordCount(String keyword) {

return dao.getTotalKeywordCount(keyword);

}

}



파일명: BoardService.java


[첨부(Attachments)]

BoardService.zip





16. BoardServiceImpl.java - Service 영역(DAO)


실제경로: /target/generated-sources/annotations/com/smile/web/service

패키지명: com.smile.web.service

파일명: BoardServiceImpl.java


DAO 영역에 관한 것이다. (실제 DB를 처리하는 영역)


package com.smile.web.service;


import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.List;


import com.smile.web.db.DBFactory;

import com.smile.web.model.Board;


public class BoardServiceImpl {

private static BoardServiceImpl boardDAO;

private static DBFactory dbPool;

private BoardServiceImpl() {}

public static BoardServiceImpl getInstatnce() {

if ( boardDAO == null ) {

boardDAO = new BoardServiceImpl();

dbPool = new DBFactory();

}

return boardDAO;

}

public List<Board> getBoardList(long startNum, long endNum){

Connection conn = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    Board node = null;

   

    List<Board> boardList = new ArrayList<Board>();


    String sql = "select * from (select /*+INDEX_DESC(tbl_board pk_board) */ rownum rn, A.*" + 

    " from board A order by id desc) " + 

    "where rn >= ? and rn <= ?";


    //System.out.println(sql);

    //System.out.println(startNum + "/" + endNum);

   

    try {

    conn = dbPool.getConnection();

    pstmt = conn.prepareStatement(sql);

    pstmt.setLong(1, startNum);

    pstmt.setLong(2, endNum);

   

    rs = pstmt.executeQuery();


    while ( rs.next() ) {

    // 데이터가 존재할 때, 노드 생성

    node = new Board();

   

    node.setId(rs.getLong(2));

    node.setSubject(rs.getNString(3));

    node.setMemo(rs.getNString(4));

    node.setName(rs.getNString(5));

   

    boardList.add(node);

   

    System.out.println("rs:" + rs.getLong(1));

   

    }


    }catch(Exception ex) {

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

    }

    finally {

    dbPool.close(conn, pstmt, rs);

    }

return boardList;

}

public List<Board> getBoardKeywordList(String keyword, long startNum, long endNum){

Connection conn = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    Board node = null;

   

    String allKeyword = "%" + keyword + "%";

   

    List<Board> boardList = new ArrayList<Board>();


    String sql = "select * " + 

    "from (select /*+INDEX_DESC(tbl_board pk_board) */ rownum rn, A.* " + 

    "from board A where subject like ? order by id desc) " + 

    "where rn >= ? and rn <= ?";

   

    //System.out.println(sql);

   

    try {

    conn = dbPool.getConnection();

    pstmt = conn.prepareStatement(sql);

    pstmt.setNString(1, allKeyword);

    pstmt.setLong(2, startNum);

    pstmt.setLong(3, endNum);

   

    rs = pstmt.executeQuery();


    while ( rs.next() ) {

    // 데이터가 존재할 때, 노드 생성

    node = new Board();

   

    node.setId(rs.getLong(2));

    node.setSubject(rs.getNString(3));

    node.setMemo(rs.getNString(4));

    node.setName(rs.getNString(5));

   

    boardList.add(node);

   

    //System.out.println("rs:" + rs.getLong(1));

   

    }


    }catch(Exception ex) {

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

    }

    finally {

    dbPool.close(conn, pstmt, rs);

    }

return boardList;

}

public long getTotalCount() {

Connection conn = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    Board node = null;

   

    long cnt = 0;


    String sql = "select count(*) from board";

   

    System.out.println("sql:" + sql);


    try {

    conn = dbPool.getConnection();

    //System.out.println( conn.getSchema() );

    pstmt = conn.prepareStatement(sql);

   

    rs = pstmt.executeQuery();

    //System.out.println( rs.getFetchSize() );


    if ( rs.next() ) {

    cnt = rs.getLong(1);

        System.out.println("전체갯수:" + cnt + "/" + rs.getLong(1));

    }


    }catch(Exception ex) {

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

    }

    finally {

    dbPool.close(conn, pstmt, rs);

    }

return cnt;

}

public long getTotalKeywordCount(String keyword) {

Connection conn = null;

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    Board node = null;

   

    String allKeyword = "%" + keyword + "%";

   

    long cnt = 0;


    String sql = "select count(*) from board where subject like ?";

   

    //System.out.println("sql:" + sql + "/키:" + keyword);


    try {

    conn = dbPool.getConnection();

    /// System.out.println( conn.getSchema() );

    pstmt = conn.prepareStatement(sql);

    pstmt.setNString(1, allKeyword);

   

    rs = pstmt.executeQuery();

    /// System.out.println( rs.getFetchSize() );


    if ( rs.next() ) {

    cnt = rs.getLong(1);

        System.out.println("특정 갯수:" + cnt + "/" + rs.getLong(1));

    }


    }catch(Exception ex) {

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

    }

    finally {

    dbPool.close(conn, pstmt, rs);

    }

return cnt;

}


}


파일명: BoardServiceImpl.java


[첨부(Attachments)]

BoardServiceImpl.zip



17. 데이터베이스 - 응용 영역


이 부분이 의외로 어려울 수 있다고 본다. 머리를 조금 써야 한다.


[개선 후 SQL 파일 내용]


-- Oracle 11 - 자동번호 생성 테이블 정의
-- Table 생성 (BOARD)
-- NEW.ID (Table의 id를 가리킴)
CREATE TABLE board
(
    id NUMBER PRIMARY KEY,
    name VARCHAR2(30),
    subject VARCHAR2(30),
    memo NCLOB,
    count NUMBER,
    regidate DATE
);

-- Sequence 정의
CREATE SEQUENCE board_sequence
START WITH 1
INCREMENT BY 1;

-- Trigger 생성
-- BEFORE INSERT on '테이블명'
CREATE OR REPLACE TRIGGER board_trigger
BEFORE INSERT
    ON board
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT board_sequence.nextval INTO :NEW.ID FROM dual;
END;


/* 데이터 추가 */
INSERT INTO board (name, subject, memo, count, regidate) VALUES ('홍길동', '안녕하세요.', '메모메모', '0', '2020-09-29 11:11:00');

/* 데이터 등록 후 커밋할 것(대량 정보 처리 후) */
COMMIT;


-- 싱글 쿼리 (페이징)
SELECT * FROM (
SELECT /*+ INDEX_DESC(Z OP_SAMPLE_PK) */ ROWNUM AS RNUM, Z.* FROM (
SELECT * from board order by id desc
) Z WHERE ROWNUM <= 10
) WHERE RNUM >= 1

-- 특정 싱글 쿼리 SQL
SELECT * FROM (
SELECT /*+ INDEX_DESC(Z OP_SAMPLE_PK) */ ROWNUM AS RNUM, Z.* FROM (
SELECT * from board where subject like '%야해해%' order by id desc
) Z WHERE ROWNUM <= 10
) WHERE RNUM >= 1


파일명: board-tbl-oracle_개선후.sql (변경해도 되는 쿼리)  /  board-tbl-oracle_개선전.sql (이 글의 16번 소스코드에 적용된 페이징 쿼리)


(16번 파일의 페이징 쿼리를 수정해서 사용해도 됨.)

-> 개선 전 쿼리라고 해서 파일을 두 개로 두었음.


[첨부(Attachments)]

board-tbl-oracle.zip (업데이트: 2020-10-11)


페이징 로직 설계가 되었다면, 다음 계획해야 할 작업이 실질적으로는 이 작업이다.

의외로 작업을 하다보면, 골치가 아픈 문제들이 많이 생긴다.


[Oracle Databases 코너에 쿼리 관련 작업에 대해서 추가로 보충하여 소개하도록 하겠다.]

- 단일 테이블 게시물 쿼리 방법, 뷰 테이블 쿼리 방법, 테이블 조인(2개 이상) 사용 방법


-> 태스트 결과로는 "Java 페이징 로직"은 크게 문제가 없다. 
    다만, 나머지 부분은 쿼리라고 본다.



[쿼리 관련 - 보충 글]
1. [Oracle Databases] 번외글 - 게시판 페이징 관련 로직 쿼리, 2020-10-11.
- https://yyman.tistory.com/1466




18. 뷰 - css


css 하나 만들어준다. 보안 영역에 만들지 말고 외부 영역에 만들어준다.



그림 23. style.css 프로젝트 위치


생성할 폴더: 

/src/main/webapp/board

/src/main/webapp/board/css


생성할 파일

/src/main/web/app/board/css/style.css


사실 style.css을 먼저 만들고 나서 작업하는 건 절대적으로 아니다.

웹 페이지를 보고 하나 하나 왕복 화면 전환 등 복합적으로 하면서 수많은 태스트과정을 거쳐서 작성하게 된다.

css 작업을 하는데 있어서도 어떻게 하면 깔끔하면서 표준을 지킬지 고민을 많이 해봐야 한다고 본다.


@charset "utf-8";


/* 1. 제목 */

h3{

font-size:20px;

font-family:'Nanum Gothic';

text-align:center;

}


/* 2. 게시판 */

/* 게시판 목록 출력 */

.board_list{

border-top:1px solid #e2e2e2;

border-bottom:1px solid #e2e2e2;

font-size:12px;

font-family:'Nanum Gothic';

width:900px;

margin:auto;

text-align:center;

}


/* 제목 */

.board_list th{


border-right:1px solid #666;

border-bottom:1px solid #666;

font-size:15px;

font-family:'Nanum Gothic';

height:20px;

text-align:center;

background-color:#eeeeee;

}


/* 내용 */

.board_list td{


border-right:1px solid #e2e2e2;

font-size:15px;

font-family:'Nanum Gothic';

height:20px;

text-align:center;

}


/* 3. 페이징 네이션 */

.paginate{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

}


.paginate .first{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


.paginate .prev{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


.paginate .next{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


.paginate .last{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


.paginate .choice{


font-size:20px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

margin-right:10px;

}


/* 4. 링크 */

a{

text-decoration:none;

color:#666;

}


/* 5. 검색 영역 */

.searchArea{


font-size:15px;

font-family:'Nanum Gothic';

font-color:#666;

text-align: center;

}


파일명: style.css


[첨부(Attachments)]

style.zip




19. 뷰(view) - jsp파일 작성하기


이번에 소개할 것은 include를 실제 적용한 코드이다.



그림 24. board 폴더 내 파일들 (작업할 부분)


생성할 폴더: 

/src/main/webapp/WEB-INF/views/

/src/main/webapp/WEB-INF/views/board


생성할 파일

/src/main/webapp/WEB-INF/views/board/list.jsp

/src/main/webapp/WEB-INF/views/board/search.jsp

/src/main/webapp/WEB-INF/views/board/paging.jsp


list.jsp를 호출하면, search.jsp, paging.jsp도 함께 호출이 된다.

기능을 전문적으로 분리하여 설계한 것이다.




20. 뷰(view) - list.jsp


list.jsp에 관한 것이다.

코드를 보고 한눈에 알 수 없는 사람들을 위해서 실제 동작 결과화면을 소개하겠다.



그림 25. list.jsp 화면 영역 구성도



<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ page import = "java.util.*" %>

<%@ page import = "com.smile.web.model.*" %>

<%@ page session="false" %>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>게시물 목록</title>

<style>

@import url('https://fonts.googleapis.com/css?family=Nanum+Gothic:400,700,800');


</style>

<link href="css/style.css" rel="stylesheet" type="text/css" />

</head>

<body>

<%

List<Board> boardList = (List<Board>)request.getAttribute("list");

%>


<h3>게시물 목록</h3>


<!-- 목록 출력 -->

<table class="board_list">

<tr>

<th style="width:15%;">

번호(Num)

</th>

<th>

제목(Subject)

</th>

<th style="width:13%;">

글쓴이(Author)

</th>

<th style="width:13%; border-right:none;">

조회수(Count)

</th>

</tr>

<%

for(Board board:boardList){

%>

<tr>

<td style="width:15%;">

<%= board.getId() %>

</td>

<td>

<%= board.getSubject() %>

</td>

<td style="width:13%;">

<%= board.getName() %>

</td>

<td style="width:13%; border-right:none;">

<%= board.getCount() %>

</td>

</tr>

<%

}

%>

</table>


<!-- 페이징 -->

<jsp:include page="/WEB-INF/views/board/paging.jsp">

<jsp:param name="customURL" value="${pagingUrl}" />

    <jsp:param name="firstPageNo" value="${paging.firstPageNo}" />

    <jsp:param name="prevPageNo" value="${paging.prevPageNo}" />

    <jsp:param name="startPageNo" value="${paging.startPageNo}" />

    <jsp:param name="pageNo" value="${paging.pageNo}" />

    <jsp:param name="endPageNo" value="${paging.endPageNo}" />

    <jsp:param name="nextPageNo" value="${paging.nextPageNo}" />

    <jsp:param name="finalPageNo" value="${paging.finalPageNo}" />

</jsp:include>


<!-- 검색 -->

<jsp:include page="/WEB-INF/views/board/search.jsp" />


</body>

</html>


파일명: list.jsp


[첨부(Attachments)]

list.zip



21. 뷰(view) - paging.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>



<div class="paginate">

    <a href="${param.customURL}page=${param.firstPageNo}" class="first">처음 페이지</a>

    <a href="${param.customURL}page=${param.prevPageNo}" class="prev">이전 페이지</a>

    <span>

        <c:forEach var="i" begin="${param.startPageNo}" end="${param.endPageNo}" step="1">

            <c:choose>

                <c:when test="${i eq param.pageNo}"><a href="${param.customURL}page=${i}" class="choice">${i}</a></c:when>

                <c:otherwise><a href="${param.customURL}page=${i}">${i}</a></c:otherwise>

            </c:choose>

        </c:forEach>

    </span>

    <a href="${param.customURL}page=${param.nextPageNo}" class="next">다음 페이지</a>

    <a href="${param.customURL}page=${param.finalPageNo}" class="last">마지막 페이지</a>

</div>



파일명: paging.jsp


[첨부(Attachments)]

paging.zip




22. 뷰(view) - search.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>


<div class="searchArea">

<form id="searchForm" action="list.do" method='get'>

<select name="type">

<option value="T">제목</option>

<option value="C">내용</option>

<option value="W">작성자</option>

</select>

<input type="text" name="keyword">

<button class="">검색</button>

</form>

</div>


파일명: search.jsp


[첨부(Attachments)]

search.zip




23. 데이터베이스 작업시 성능 - 꼭 파악하면서 작업해보기


오늘 날 게시판 뿐만 아니라 DB의 비중이 매우 중요한 시대에 직면해 있다.

성능 측정 꼭 해보기 바란다.

동작도 물론 중요한데, 결과는 정확한지 등 많이 고민하고 수 십번, 수 백법 이상 찍어봐야 한다.



그림 26. 데이터베이스 작업 모습 - 오라클 SQL Developer




* 맺음글(Conclusion)


페이징네이션 기반의 게시판 프로젝트에 대해서 살펴보았다.




* 참고자료(References)


1. [Oracle] 오라클 데이터타입(DataType) 총정리, https://coding-factory.tistory.com/416, Accessed by 2020-09-29, Last Modified 2019-11-03.


2. [JSP]include 와 forward 의 페이지 이동, https://jerryjerryjerry.tistory.com/31, Accessed by 2020-09-29, Last Modified 2018-04-13.


3. 오라클 페이징 쿼리, 오라클 paging 방법 - 개발자 삽질 일기, https://programmer93.tistory.com/4, Accessed by 2020-09-29, Last Modified 2019.


4. [OracleDB] 페이징(Paging) 처리하는 법, https://m.blog.naver.com/wideeyed/221796538283, Accessed by 2020-09-29, Last Modified 2020-02-04.

반응형
728x90
300x250

[Spring-Framework] 11. Spring MVC - HikariCP 3.4.2, Oracle 19g 연동하기(Properties, Java) - (2)


1부에서는 환경설정하는 방법에 대해서 소개하였다.

2부에서는 코드로 구현하는 방법을 위주로 소개하겠다.


[1부] [Spring-Framework] 10. Spring MVC - HikariCP 3.4.2, Oracle 19g 연동하기(Properties, Java) - (1), 2020-09-23 14:20

https://yyman.tistory.com/1410



10. Properties 방식 - DataSource.java


코드를 하나 만들어보았다.


패키지: com.springMVC.web.persistance


package com.springMVC.web.persistance;


import java.io.IOException;

import java.io.InputStream;

import java.io.Reader;

import java.util.Properties;


import java.sql.Connection;

import java.sql.SQLException;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;


import com.zaxxer.hikari.HikariConfig;

import com.zaxxer.hikari.HikariDataSource;


public class DataSource {


private static final Logger logger = LoggerFactory.getLogger(DataSource.class);


    private static String CLASSNAME;

    private static String JDBC_URL;

    private static String USERNAME;

    private static String PASSWORD;

    private static String CACHE_PREP_STMTS;

    private static HikariDataSource ds;

    

/*

(자바 방식)

    private static HikariConfig config = new HikariConfig();

    

    static {

    config.setDriverClassName("oracle.jdbc.OracleDriver");

        config.setJdbcUrl( "jdbc:oracle:thin:@localhost:1521:orcl" );

        config.setUsername( "사용자계정명" );

        config.setPassword( "비밀번호" );

        

        config.addDataSourceProperty( "cachePrepStmts" , "true" );

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

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

        ds = new HikariDataSource( config );

    }

    */

    

    private HikariConfig config;

    

    public DataSource() {

   

    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(properties.getProperty("jdbcUrl"));

            System.out.println(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 );

            

        } catch (IOException e) {

            e.printStackTrace();

        }


    }


    public Connection getConnection() throws SQLException {


        return ds.getConnection();

    }


}


파일명: DataSource.java


[첨부(Attachments)]

DataSource-java-type-properties.zip


위의 소스를 static 방식으로 간결하게 코드를 변경할 수 없는 이유는 "getClass().getClassLoader().getResourceAsStream(resource);" 이 부분이 static 변수에서는 처리가 되지 않는다.


비고: 클래스명에 대해서 "DataSource"로 해도 되나요?

       javax.sql.DataSource가 존재한다. 예제의 DataSource 클래스명은 좋은 명칭은 아니다. 

       (동작은 될 수 있겠으나 javax.sql.DataSource를 사용할 때는 명칭에 대해서 다시 생각을 해봐야 할 것이다.)



10-1. Controller - HomeController.java 수정하기(Properties 방식)


HomeController.java 파일로 작업하는 방법이다.


package com.springMVC.web.controller;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

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

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


import com.springMVC.web.dao.AddressBookDao;

import com.springMVC.web.persistance.DataSource;


/**

 * Handles requests for the application home page.

 */

@Controller

public class HomeController {

/*

// Controller 안에서만 사용가능.

@Value("#{props['dataSourceClassName']}")

private String CLASSNAME;

@Value("#{props['jdbcUrl']}")

private String JDBC_URL;

@Value("#{props['dataSource.user']}")

private String USERNAME;

@Value("#{props['dataSource.password']}")

private String PASSWORD;

*/

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

// @Value("#{props['jdbcUrl']}")

// private String url;

/**

* Simply selects the home view to render by returning its name.

*/

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

public String home(Locale locale, Model model) {

logger.info("Welcome home! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

try {

DataSource ds = new DataSource();

//ds.getConnection();

AddressBookDao dao = new AddressBookDao();

dao.allSelect();

//logger.info("URL:{}", JDBC_URL);

//dao.allSelect();

}

catch(Exception e) {

logger.info("msg: {}", e.getMessage());

}

model.addAttribute("serverTime", formattedDate );

return "home";

}

}


파일명: HomeController.java


[첨부(Attachments)]

HomeController-java-type-properties.zip




10-2. DAO - AddressBookDao.java (Properties 방식)


package com.springMVC.web.dao;


import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;


import com.springMVC.web.persistance.DataSource;


public class AddressBookDao {


private static final Logger logger = LoggerFactory.getLogger(AddressBookDao.class);


public void allSelect() {

try {

DataSource ds = new DataSource();

Connection conn = ds.getConnection();

String query = "select * from addressbook";

PreparedStatement pstmt = conn.prepareStatement(query);

ResultSet rs = pstmt.executeQuery();

while(rs.next()) {


String msg = "번호:" + rs.getString("num") + "/이름:" + rs.getString("name") + "/주소:" + rs.getString("address");

logger.info("Msg: {}.", msg);

}

rs.close();

conn.close();

} catch (SQLException e) {

logger.info("msg:{}",  e.getMessage());

}

}

}



파일명: AddressBookDao.java


[첨부(Attachments)]

AddressBookDao-type-properties.zip




11. Java 방식 - DataSource.java


앞에 Properties 방식으로 구성해봐도 되고, 자바 코드 방식으로 해도 무방하다.


package com.springMVC.web.persistance;


import java.io.IOException;

import java.io.InputStream;

import java.io.Reader;

import java.util.Properties;


import java.sql.Connection;

import java.sql.SQLException;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Value;


import com.zaxxer.hikari.HikariConfig;

import com.zaxxer.hikari.HikariDataSource;


public class DataSource {


private static final Logger logger = LoggerFactory.getLogger(DataSource.class);


    private static String CLASSNAME;

    private static String JDBC_URL;

    private static String USERNAME;

    private static String PASSWORD;

    private static String CACHE_PREP_STMTS;

    private static HikariDataSource ds;

    

    private static HikariConfig config = new HikariConfig();

    

    static {

    config.setDriverClassName("oracle.jdbc.OracleDriver");

        config.setJdbcUrl( "jdbc:oracle:thin:@localhost:1521:orcl" );

        config.setUsername( "사용자계정명" );

        config.setPassword( "비밀번호" );

        

        config.addDataSourceProperty( "cachePrepStmts" , "true" );

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

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

        ds = new HikariDataSource( config );

    }

    

    /*

    private HikariConfig config;

    

    public DataSource() {

   

    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(properties.getProperty("jdbcUrl"));

            System.out.println(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 );

            

        } catch (IOException e) {

            e.printStackTrace();

        }


    }

    

    

    */


    public static Connection getConnection() throws SQLException {


        return ds.getConnection();

    }

}


파일명: DataSource.java


[첨부(Attachments)]

DataSource-java-type-java.zip




11-1. Controller - HomeController.java 수정하기(Java 방식)


HomeController.java 파일로 작업하는 방법이다.


package com.springMVC.web.controller;


import java.text.DateFormat;

import java.util.Date;

import java.util.Locale;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

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

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


import com.springMVC.web.dao.AddressBookDao;

import com.springMVC.web.persistance.DataSource;


/**

 * Handles requests for the application home page.

 */

@Controller

public class HomeController {

/*

// Controller 안에서만 사용가능.

@Value("#{props['dataSourceClassName']}")

private String CLASSNAME;

@Value("#{props['jdbcUrl']}")

private String JDBC_URL;

@Value("#{props['dataSource.user']}")

private String USERNAME;

@Value("#{props['dataSource.password']}")

private String PASSWORD;

*/

private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

// @Value("#{props['jdbcUrl']}")

// private String url;

/**

* Simply selects the home view to render by returning its name.

*/

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

public String home(Locale locale, Model model) {

logger.info("Welcome home! The client locale is {}.", locale);

Date date = new Date();

DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

String formattedDate = dateFormat.format(date);

try {

//ds.getConnection();

AddressBookDao dao = new AddressBookDao();

dao.allSelect();

//logger.info("URL:{}", JDBC_URL);

//dao.allSelect();

}

catch(Exception e) {

logger.info("msg: {}", e.getMessage());

}

model.addAttribute("serverTime", formattedDate );

return "home";

}

}


파일명: HomeController.java


[첨부(Attachments)]

HomeController-java-type-java.zip





11-2. DAO - AddressBookDao.java (JAVA 방식)


자바 방식으로 dao를 구성하는 방법이다.


package com.springMVC.web.dao;


import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;


import com.springMVC.web.persistance.DataSource;


public class AddressBookDao {


private static final Logger logger = LoggerFactory.getLogger(AddressBookDao.class);


public void allSelect() {

try {

Connection conn = DataSource.getConnection();

String query = "select * from addressbook";

PreparedStatement pstmt = conn.prepareStatement(query);

ResultSet rs = pstmt.executeQuery();

while(rs.next()) {


String msg = "번호:" + rs.getString("num") + "/이름:" + rs.getString("name") + "/주소:" + rs.getString("address");

logger.info("Msg: {}.", msg);

}

rs.close();

conn.close();

} catch (SQLException e) {

logger.info("msg:{}",  e.getMessage());

}

}

}



파일명: AddressBookDao.java


[첨부(Attachments)]

AddressBookDao.java-Type-java.zip



12. 출력 결과


작업한 데이터베이스의 모습이다.

작업한 결과를 보면, 무슨 작업을 하려고 했는지 직관적으로 이해될 것으로 보인다.

DB를 처리하거나 호출하는 건 똑같은데, 호출할 때 미리 저장된 풀을 활용하여 부담을 줄여주는 효과가 있다.



그림 11. Oracle DB - SQL Developer 모습(Addressbook)



그림 12. Oracle DB - SQL Developer 모습(Addressbook)



그림 13. 화면 출력 결과 - STS4(Eclipse)



* 맺음글(Conclusion)


시중의 HikariCP에 대한 글이 오류가 많아서 한번 정확하게 최신 버전으로 작성해보고 싶었다.

수차례 태스트 작업을 완료하였으니 사용하는 데 지장없을 것으로 보인다.


공식 사이트: https://github.com/brettwooldridge/HikariCP

-> 공식 사이트의 메뉴얼이 다소 부족한 면이 있다.



* 참고자료(Reference)


1. [Spring] 커넥션 풀(Connection pool)이란?, https://linked2ev.github.io/spring/2019/08/14/Spring-3-%EC%BB%A4%EB%84%A5%EC%85%98-%ED%92%80%EC%9D%B4%EB%9E%80/ , Accessed by 2020-09-23, Last Modified 2019-08-14.

2. Spring-Hikari-Oracle연동 시 나는 oracle.jdbc.driver.OracleDriver not found 에러, https://apiclass.tistory.com/entry/Spring-Hikari-Oracle%EC%97%B0%EB%8F%99-%EC%8B%9C-%EB%82%98%EB%8A%94-oraclejdbcdriverOracleDriver-not-found-%EC%97%90%EB%9F%AC, Accessed by 2020-09-23, Last Modified 2019-10-16.

3. Introduction to HikariCP, https://www.baeldung.com/hikaricp, Accessed by 2020-09-23, Last Modified 2020-06-02.

4. Maven Repository: mysql » mysql-connector-java » 8.0.21, https://mvnrepository.com/artifact/mysql/mysql-connector-java/8.0.21, Accessed by 2020-09-23, Last Modified .

5. GitHub - brettwooldridge/HikariCP: 光 HikariCP・A solid, high-performance, JDBC connection pool at last., https://github.com/brettwooldridge/HikariCP, Accessed by 2020-09-23, Last Modified .

6. [Spring][04]커넥션 풀 설정(HikariCP), https://kimvampa.tistory.com/57, Accessed by 2020-09-23, Last Modified 2020-04-10.

7. [Spring] Spring Test 오류 해결 모음(SpringJUnit4ClassRunner , Resource specification), https://life-with-coding.tistory.com/373, Accessed by 2020-09-23, Last Modified 2020-07-08.

8. [오류, 에러] Spring Junit Test 환경설정 / Class<SpringJUnit4ClassRunner> cannot be resolved to a type, https://developerntraveler.tistory.com/1, Accessed by 2020-09-23, Last Modified 2020-05-14.

9. 오라클 드라이버 에러 - Registered driver with driverClassName=oracle.jdbc.driver.OracleDriver was not found, trying direct instantiation, https://wrkbr.tistory.com/410, Accessed by 2020-09-23, Last Modified 2018.

10. SpringBoot error: Registered driver with driverClassName=oracle.jdbc.driver.OracleDriver was not found, trying direct instantiation, https://stackoverflow.com/questions/52014595/springboot-error-registered-driver-with-driverclassname-oracle-jdbc-driver-orac, Accessed by 2020-09-23, Last Modified 2018.

11. Spring에서 Properties 사용, https://yookeun.github.io/java/2015/12/22/spring-properties/, Accessed by 2020-09-23, Last Modified 2015-12-22.

12. Java에서 Properties 파일 읽기, https://prettymucho.tistory.com/7, Accessed by 2020-09-23, Last Modified 2017-06-12.

반응형
728x90
300x250

[Spring-Framework] 10. Spring MVC - HikariCP 3.4.2, Oracle 19g 연동하기(Properties, Java) - (1)


Spring MVC 프로젝트로 HikariCP 3.4.2를 연동하는 방법에 대해서 소개하겠다.

Apache DBCP(커넥션 풀) 프로젝트도 있으나 최근에는 HikariCP가 성능이 더 우수하다고 한다.


양이 많은 주제이므로 2부로 나눠서 작성하였다.



1. Introduce(소개) - 커넥션 풀


1. 커넥션 풀(DBCP)이란?

웹 컨테이너(WAS)가 실행되면서 DB와 미리 connection(연결)을 해놓은 객체들을 pool에 저장해두었다가, 클라이언트 요청이 오면 connection을 빌려주고, 처리가 끝나면 다시 connection을 반납받아 pool에 저장하는 방식을 말한다.



2. 작업환경


이 글에서 사용한 작업 환경이다.


* IDE: Spring Tool-Suite 4-4.7.2 Releases(Eclipse)


* Web Server(웹서버):

Apache Tomcat 9


* 데이터베이스(Databases)

Oracle Databases 19

MySQL 8.0.21


* 프레임워크

Spring Framework 3.1.1 Releases


* 라이브러리

POM - Oracle JDBC 19

POM - MySQL 8.0.21

Maven Project - 3.6.3/1.16.0.20200610-1735


특징: MyBatis 제거 등 영속 프레임워크 미적용




3. 프로젝트 구성


작업할 프로젝트의 구성이다.



그림 1. 프로젝트 구성




4. 새 프로젝트 생성


File -> New -> Others...

                 Spring 폴더-> Spring Legacy Projects



5. pom.xml 설정





그림 2. POM.xml 수정 - 자바 버전 수정하기


[JAVA JDK 버전 오류]

오류 : Resource specification not allowed here for source level below 1.7


자바 버전을 변경하는 이유는 1.6으로는 버전이 낮아서 미지원한다고 오류가 발생하기 때문이다.

pom.xml 셋팅 후 project에서 변경을 해줘야 한다.


그림 3. POM.xml 수정 - Spring Test 영역 수정하기



그림 4. POM.xml 수정 - HikariCP, Oracle JDBC


      <properties>

<java-version>14</java-version>

<org.springframework-version>3.1.1.RELEASE</org.springframework-version>

<org.aspectj-version>1.6.10</org.aspectj-version>

<org.slf4j-version>1.6.6</org.slf4j-version>

</properties>


(중략)


<!-- spring-test -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

<version>${org.springframework-version}</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.3.0.0</version>

</dependency>    


* 파일명: pom.xml


* 참고 - MySQL 연동할 때


아래의 코드는 pom.xml에 넣어준다.


<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->

<dependency>

    <groupId>mysql</groupId>

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

    <version>8.0.21</version>

</dependency>




6. Project의 Properties의 Java Build Path 내 Libraries의 JRE 버전 바꾸기


pom.xml은 maven 환경에 대한 자바 버전 설정이었는데, 근본적인 Build Path에 관한 속성을 변경하는 작업이다.


[JAVA JDK 버전 오류]

오류 : Resource specification not allowed here for source level below 1.7



그림 5. Properties 클릭하기


프로젝트를 클릭한다.

오른쪽 버튼을 누른 후, Properties를 클릭한다.




그림 6. Java Build Path 설정하기 - Libraries


JRE System Library 1.6 버전을 Remove한다.

Add Library를 클릭하여 버전을 1.7 버전 이상으로 올려준다.



7. root-context.xml 수정하기


-> src/main/webapp/spring/root-context.xml에 있음.



그림 7. 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"

xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- Root Context: defines shared resources visible to all other web components -->

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">

<!-- Oracle 9 이상으로 작성. -->

<!-- 오라클 9 이후에 oracle.jdbc.driver.OracleDriver는 중단되었음.  -->

<!-- oracle.jdbc.pool.OracleDataSource -->

<!-- jdbc:oracle:thin:@localhost:1521:orcl -->


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

<property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:orcl"></property> 

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

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

</bean>

<bean id="datasource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">

<constructor-arg ref="hikariConfig"></constructor-arg>

</bean>

</beans>



파일명: root-context.xml (Oracle 11 이상) - 태스트 확인: Oracle 18g


* [첨부(Attachments)]

root-context-oracle.zip



* 참고 - MySQL 연동(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"

xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- Root Context: defines shared resources visible to all other web components -->

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">

  <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>

<property name="jdbcUrl" value="jdbc:mysql://localhost:{포트번호}/{DB명}?serverTimezone=UTC"></property> 

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

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

</bean>

<bean id="datasource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">

<constructor-arg ref="hikariConfig"></constructor-arg>

</bean>

</beans>


파일명: root-context.xml(mysql 버전)


* [첨부(Attachments)]

root-context-mysql.zip



* 정정: jdbc:mysql://localhost:3306/web?serverTimezone=UTC&characterEncoding=utf8



8. servlet-context.xml 파일 수정하기


servlet-context.xml 파일을 수정해준다.


파일 경로: /src/main/webapp/WEB-INF/spring/appServlet



그림 8. servlet-context.xml - 수정된 모습


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

<beans:beans xmlns="http://www.springframework.org/schema/mvc"

xmlns:util="http://www.springframework.org/schema/util"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:beans="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd

http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd

http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">


<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->

<annotation-driven />


<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->

<resources mapping="/resources/**" location="/resources/" />


<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->

<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<beans:property name="prefix" value="/WEB-INF/views/" />

<beans:property name="suffix" value=".jsp" />

</beans:bean>

<!-- 추가(Hikara4 -->

<!-- <context:property-placeholder location="classpath:/db.properties" />  -->

<util:properties id="props" location="classpath:/db.properties" />     

<context:component-scan base-package="com.springMVC.web.controller" />

</beans:beans>


파일명: servlet-context.xml


* [첨부(Attachments)]

servlet-context.zip




9. /src/main/resources/db.properties 만들기


Spring MVC 프로젝트로 작성하였으면, Resources 폴더는 생성되어 있을 것이다.

없다면, 별도로 만들어야 한다.


db.properties 파일은 존재하지 않기 때문에 따로 만들어줘야 한다.



그림 9. 파일 만들기


resources 폴더를 클릭한 후 오른쪽 버튼을 클릭한다.

New->File을 클릭한다.



그림 10. 프로젝트 구성 - dbProperties


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

dataSourceClassName=oracle.jdbc.OracleDriver

dataSource.user={username}

dataSource.password={password}

cachePrepStmts=true

prepStmtCacheSize=250

prepStmtCacheSqlLimit=2048


파일명: db.properties (oracle 버전)


[첨부(Attachments)]

db-properties-oracle.zip


jdbcUrl=jdbc:mysql://localhost:3306/web?serverTimezone=UTC

dataSourceClassName=com.mysql.cj.jdbc.Driver

dataSource.user={UserName}

dataSource.password={Password}

cachePrepStmts=true

prepStmtCacheSize=250

prepStmtCacheSqlLimit=2048


파일명: db.properties (mysql버전)


[첨부(Attachments)]

db-properties-mysql.zip



* 2부에서 만나요.


초기 셋팅은 이 정도면 끝났으니, 2부에서 연재하도록 하겠다.


[Spring-Framework] 11. Spring MVC - HikariCP 3.4.2, Oracle 19g 연동하기(Properties, Java) - (2), 2020-09-23 14:28

https://yyman.tistory.com/1411


반응형

+ Recent posts