1
2
3
4
window.onload = function() {
    // scroll : yes, no, auto중 택1 가능
    window.documnet.body.scroll = "auto";    
}
cs

해당 팝업창으로 열리는 .jsp 페이지에 함수를 걸어 처리하였다.

1. 변경 이유

Apache project 팀이 Google code로 팀을 변경하게 되면서 그에 따라 iBatis에서 myBatis로 명칭이 변경되었다.



2. iBatis vs myBatis 비교

항목

iBatis

myBatis

 1) Java 요구 버전

 JDK 1.4 이상

 JDK 1.5 이상

 (myBatis 3.2 부터는 JDK 1.6 이상만 가능)

 2) 패키지 내부 구조

 com.ibatis.*

 org.apache.ibatis.*

 3) sqlMap 내부 구조

 parameterMap을 사용하지 않음

 sqlMapConfig / sqlMap / resultClass 사용

 parameterType으로 대체

 dtd 변경 (http://mybatis.org/dtd/mybatis-3/mapper.dtd)

configuration / Mapper / resultType  사용

 4) 라이브러리

 

 별도의 라이브러리 필요

 5) Annotation

 

 sqlMapClient DI 설정이 불필요해짐

 간편해짐

 Bean id sqlSessionFactory / sqlSessionTemplate만 지정하면 됨

 6) rawhandler

 

 resultHandler로 변경

 자바 @를 사용하여 xml을 사용하지 않음

 자바 코드보다 xml이 우선순위를 가지게 됨

 7) namespace

 <sqlmap namespace="User"  .../>

 <mapper namespace="mybatis.mapper.User" .../>

 필수로 입력해야 하는 항목.

 UserStatement NameSpace 설정을 제거함

 8) 동적 sql

 COLUMN_NAME = #parameter#

 COLUMN_NAME = #{parameter}

 9) 캐시 지원 여부

 X

 O



3. 세부사항

2번 표에서 간단히 요약한 사항들을 세부적으로 파헤쳐본다.

1) Java 요구 버전

2) 패키지 내부 구조

3) sqlMap 내부 구조

4) 라이브러리

5) Annotation

6) rawhandler

7) namespace

8) 동적 sql

9) 캐시 지원 여부

Oracle 8g부터 지원하며, 트리처럼 가지를 쳐 뻗어 나가는 구조를 계층형 구조라 부르며, 각 단의 상위 계층과 하위 계층의 관계를 오라클에서는 START WITH와 CONNECT BY로 조회가 가능하다.



1. 구문

- START WITH : 최상위 계층이 되는 row를 말한다. 반복 탐색에 대한 시작 지점을 말하며, AND절로 여러개의 시작 조건을 줄 수 있다. 또한 서브 쿼리를 사용할 수 있다.

- CONNECT BY : 계층형 구조가 어떤 식으로 연결되는지를 기술하는 명령어이다. 함께 쓰이는 PRIOR 키워드는 현재의 레코드를 의미한다.  함께 계층 구조로 표현이 가능하다. 서브 쿼리를 사용할 수 없다.

(ex. PRIOR 상위 = 하위 : 상위 노드로의 탐색 / PRIOR 하위 = 상위 : 하위 노드로의 탐색)


* 조건 기술시

1) 일반 쿼리 조건 : 일반 - WHERE 절 / 그룹핑한 결과에 대한 조건 - HAVING

2) 계층 쿼리 조건 : 일반 - WHERE 절 / 계층형 결과에 대한 조건 - CONNECT BY

 


2. 계층형 쿼리를 위해 필요한 3가지

1) 메뉴 순번 (numbering)

2) 해당되는 메뉴의 계층 : 상위 메뉴와 하위 메뉴를 분리함

3) 세부 메뉴의 상위 그룹에 대한 순번 : 조직 구조를 나타내기 위함



3. 계층형 쿼리의 내부 절차

1) JOIN이 있으면 먼저 처리

2) START WITH 절을 참조하여 최상위 계층의 row를 선택

3) CONNECT BY 구문을 따라 계층 관계를 파악

4) JOIN을 제외한 WHERE 절에 해당하는 row를 걸러냄 (row별로 조건에 맞지 않으면 걸러냄)

  (WHERE는 탐색을 완료한 후 데이터를 필터링하는 키워드이므로, 상황에 따라 불필요한 탐색을 줄일 시에는 CONNECT BY 절에 기술하는 것이 성능상 유리함)



3. 예제

1) 테이블 CREATE




각 지부와 그 지부에 따른 실적을 나타내는 컬럼으로 이루어진 DEPT 테이블과(부서) RESULT 테이블(실적)이 있다고 가정한다.


2) 데이터 INSERT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
-- DEPT 테이블 PK 추가
CREATE INDEX IDX_DEPT_01 ON DEPT (UPPER_DEPT_CODE);
 
-- RESULT 테이블 PK 추가
ALTER TABLE RESULT ADD CONSTRAINT PK_RESULT PRIMARY KEY (YEAR_DATE, DEPT_CODE);
 
-- DEPT 테이블 DATA INSERT
INSERT INTO DEPT
 SELECT '1000''대표이사'NULL FROM DUAL UNION ALL
 SELECT '1100''영업1본부''1000' FROM DUAL UNION ALL
 SELECT '1200''영업2본부''1000' FROM DUAL UNION ALL
 SELECT '1110''국내영업1부''1100' FROM DUAL UNION ALL
 SELECT '1120''국내영업2부''1100' FROM DUAL UNION ALL
 SELECT '1210''해외영업1부''1200' FROM DUAL UNION ALL
 SELECT '1220''해외영업2부''1200' FROM DUAL UNION ALL
 SELECT '1111''수도권지부''1110' FROM DUAL UNION ALL
 SELECT '1112''강원지부''1110' FROM DUAL UNION ALL
 SELECT '1121''호남지부''1120' FROM DUAL UNION ALL
 SELECT '1122''경남지부''1120' FROM DUAL;
 
COMMIT;
 
-- RESULT 테이블 DATA INSERT
INSERT INTO RESULT
 SELECT '2017.11''1210'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1220'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1111'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1112'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1121'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1122'1000 FROM DUAL;
 
COMMIT;
cs


3) 쿼리 조회

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH UPPER_DEPT_CODE IS NULL
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE
ORDER BY LEVEL;
cs

- 각 DEPT_CODE를 LEVEL로 계층화하여 조회


1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_CODE = (SELECT DEPT_CODE
                        FROM DEPT
                        WHERE UPPER_DEPT_CODE IS NULL
                        START WITH DEPT_CODE = '1120'
                        CONNECT BY PRIOR UPPER_DEPT_CODE = DEPT_CODE)
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE;                        
 
cs

- 최상위 노드 > 각 노드별 하위 계층 조회



4. 오라클 10g부터 계층 구조 쿼리에서 추가되는 기능

1) CONNECT_BY_ROOT : LEVEL이 가장 높은 최상위의 row 정보를 불러오는 키워드

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  CONNECT_BY_ROOT DEPT_CODE "ROOT DEPT_CODE",
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_NAME = '대표이사'
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE;
cs

DEPT_NAME = '대표이사'를 기준으로 시작하여, DEPT_CODE (부서)와 UPPER_DEPT_CODE (상위부서코드)의 관계를 계층 구조로 조회했다. 따라서 위 그림에서 적색으로 표시한 부분을 보면 부서들이 모두 최상위 코드인 1000 (대표이사)를 가리키는 것을 확인할 수 있다.


2) CONNECT_BY_ISLEAF : row의 최하위 레벨 여부를 리턴한다. 최하위 레벨이면 1, 최하위 레벨이 아니면 0이다.

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  CONNECT_BY_ISLEAF "LEAF",
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_NAME = '대표이사'
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE;
cs


DEPT_NAME = '대표이사'를 기준으로 시작하여, DEPT_CODE (부서)와 UPPER_DEPT_CODE (상위부서코드)의 관계를 계층 구조로 조회했다. 따라서 위 그림에서 적색으로 표시한 부분을 보면 부서들이 최하위에 있는 부서인 경우 1로 표기되고, 최하위에 있지 않은 부서인 경우 0으로 표기된다. (상단 조직도 참고)


3) SYS_CONNECT_BY_PATH : 현재 row까지의 경로를 쉽게 얻어올 수 있는 키워드이다.

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  SYS_CONNECT_BY_PATH(DEPT_NAME, '/'"PATH",
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_NAME = '대표이사'
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE;
cs


4) ORDER SIBLING BY : 계층구조 쿼리에서 상관 관계를 유지한 상태로 ORDER BY를 할 수 있는 키워드.

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_NAME = '대표이사'
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE
ORDER SIBLINGS BY DEPT_NAME;
cs

* ORDER BY로 정렬하면 계층구조 관계가 유지되지 않는다.


1. 한글만 입력되도록

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(function() {
    $('#hangeul').keyup(function() {
        onlyHangeul($(this));
    });
});
 
/*
 * 한글만 입력되도록 리턴(띄어쓰기 불가능)
 * ex) onlyHangeul($(this))
         $(this).val() = 나는12asdf4정말^^좋다b333
         return 나는정말좋다
 */
function onlyHangeul(obj) {
    var value = obj.val();
    obj.val(value.replace(/[^ㄱ-ㅎ가-힣]/g, '')); }
</script>
cs

 

 

2. 영문만 입력되도록

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(function() {
    $('#english').keyup(function() {
        onlyEnglish($(this));
    });
});
/*
 * 영문만 입력되도록 리턴(띄어쓰기 불가능)
 * ex) onlyHangeul($(this))
         $(this).val() = 나는12asdf4정말^^좋다b333
         return asdfb
 */
function onlyEnglish(obj) {
    var value = obj.val();
    obj.val(value.replace(/[^a-zA-Z]/g, ''));  
}
</script>
cs

 

 

3. 숫자에 자동 콤마 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type="text/javascript">
$(function() {
    $('#numberComma').keyup(function() {
        numberComma($(this));
    });
});
 
/*
 * 숫자에 콤마 생성 후 리턴(띄어쓰기 불가능)
 * ex) onlyHangeul($(this))
         $(this).val() = 나는12asdf4정말^^좋다b333
         return 124,333
 */
function numberComma(obj) {
    var str = String(obj.val().replace(/[^0-9]/g, ''));
    // 가장 처음 숫자가 0인지 체크
    if (obj.val() != 0) {
        var reStr = str.replace(/(\d)(?=(?:\d{3})+(?!\d))/g, '$1,');
    } else {
        var reStr = '';
    }
    
    obj.val(reStr);
}
</script>
cs

ㄴㅇㄹㅇㄴ

ㄹㄴㅇ

 

 

 

 

ㄴㅇㄹ

ㄹㄴㅇㄹㄴㅇ

1
2
3
4
5
SELECT
    -- 문자열 끼워넣기
    REGEXP_REPLACE('0927''(^.{2})''\1-') AS DAYDAY
FROM
    DUAL;
cs

 

 

SQL Developer에서 어느 순간부터 오라클 접속이 안되기 시작하면서, 제목과 같이 the password has expired라는 오류가 계속 뜨기 시작했다.

귀찮아서 계속 외면했으나 오라클 공부를 위해 해결법을 찾아보기로 했다.


1. Oracle sqlplus에서 문제점 해결

cmd에서 sql plus에 접속한다. 이 때, 접속하는 명령어는 다음과 같다.

 sqlplus "/as sysdba

 


접속 후, 아래의 명령어를 이용해 기간이 만료된 계정의 비밀번호를 변경한다.

 alter user (userName) identified by (password);

 

 

2. 접속 확인

다시 오라클 프로그램에 접속해 바꾼 비밀번호를 입력하고 해당 계정이 잘 접속되는지 확인한다.

jsp에서 쉽게 차트나 그래프를 표현할 수 있는 api이며, 여러 모양이나 형태로도 손쉽게 구현이 가능하다.


1. Controller에 데이터를 담음

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Controller
public class HomeController {
    
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Model model) {
        
        PercentVO percentVO = new PercentVO();
        
        percentVO.setYesPercent("40");
        percentVO.setNoPercent("60");
        
        System.out.println("debug> percentVO : " + percentVO);
        
        model.addAttribute("percentVO", percentVO);
        
        return "home";
    }    
}
cs

yesPercent에 40, noPercent에 60이라는 값이 들어있는 PercentVO 모델이 있다고 가정한다.



2. jsp Highcharts 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Highcharts Example</title>
<!-- Highchars CDN -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script type="text/javascript">
$(function() {
    // body > div 부분에 적은 id를 파라미터로 직접 넘긴다.
    Highcharts.chart('container', {
         chart: {
             plotBackgroundColor: null,
            plotBorderWidth: 0,
            plotShadow: false,
            height: 500
         },
         title: {
            text: '',
            align: 'center',
            verticalAlign: 'bottom',
            y: -300,
            x: -80
        },
        credits: {
            enabled: false
        },
        tooltip: {
            pointFormat: '{series.name}: <b>{point.percentage: 1f}%</b>'
        },
        plotOptions: {
            pie: {
                dataLabels: {
                    enabled: true,
                    distance: -50,
                    style: {
                        fontWeight: 'bold',
                        color: 'white',
                        fontSize: '15px'
                    }
                },
                startAngle: -90,
                endAngle: 90,
                center: ['50%''75%']
            }
        },
        series: [{
            // Highcharts를 pie 형태로 구현했다.
            type: 'pie',
            name'응답률',
            innerSize: '20%',
            /*    
                data: [name:'params1', value:'params2'] 의 형태이다.
                name과 value는 생략이 가능하며, 'params1'과 'params2' 값만 적어도 무방하다.
                * 주의 *
=> Highcharts로 표현하려는 값이 변수일 경우에는 반드시 JSON.parse() 함수 안에
                변수 값을 적어야 한다.
            */
            data: [
                ['YES(${percentVO.yesPercent}%)', JSON.parse('${percentVO.yesPercent}')],
                ['NO(${percentVO.noPercent}%)', JSON.parse('${percentVO.noPercent}')],
            ]
        }]
    });
});
</script>
</head>
<body>
    <div id="container" style="min-width:350px;height:200px;max-width:250px;margin:0 auto"></div>
</body>
</html>

cs

 


실제로 작업 당시 series의 data 부분에 변수를 넣어야 했는데 아무리 검색을 해도 나오지 않았고, JSON 형태로 담아야 파라미터가 출력된다는 검색 결과들에 힌트를 얻어 해결할 수 있었다.

1
2
3
4
5
6
<!-- 해당 달 날짜를 THIS_MONTH로 출력 -->
SELECT
  TRUNC (SYSDATE, 'MM'+ LEV - 1 AS THIS_MONTH
FROM (SELECT LEVEL AS LEV
      FROM DUAL
      CONNECT BY LEVEL <= TO_CHAR (LAST_DAY (SYSDATE), 'DD'));
cs






1. 24시간 조회

1
2
3
4
5
6
<!-- 24시간을 A_HOUR로 조회 -->
SELECT
  TO_CHAR(LEVEL, '00') AS A_HOUR
FROM
  DUAL
CONNECT BY LEVEL <= 24;
cs



2. 5분 단위의 분 조회 (00분 ~ 55분)

1
2
3
4
5
6
7
8
9
10
11
<!-- 5분 단위의 00분 ~ 55분을 A.MNT로 조회
    전체 범위를 0에서 55까지 구한 뒤, 5로 나눈 나머지가 0인 것들로만 받다 -->
SELECT
  A.MNT
FROM (SELECT
        TO_CHAR(LEVEL, '00') AS MNT
      FROM
        DUAL
      CONNECT BY LEVEL <= 55) A
WHERE
  MOD(A.MNT, 5= 0;
cs



1. 금주의 월~금요일과 월~금요일 날짜 조회

1
2
3
4
5
6
7
8
<!-- 금주 월 ~ 금요일을 컬럼 DAYDAY로, 금주 월 ~ 금 날짜를 WEEKLY_DT로 조회 -->
SELECT
  TO_CHAR(SYSDATE - 7 + LEVEL + (SELECT NEXT_DAY(SYSDATE, 1- SYSDATE
                                  FROM DUAL), 'DY''NLS_DATE_LANGUAGE=korean') AS DAYDAY,
  TO_CHAR(SYSDATE - 7 + LEVEL + (SELECT NEXT_DAY(SYSDATE, 1- SYSDATE
                                  FROM DUAL), 'MM/DD') AS WEEKLY_DT
FROM DUAL
CONNECT BY LEVEL <= 5;
cs




2. 금주 월~금요일 날짜 조회

1
2
3
4
5
6
<!-- 금주 월 ~ 금 날짜를 WEEKLY_DT로 조회 -->
SELECT
  TO_CHAR(SYSDATE - 7 + LEVEL + (SELECT NEXT_DAY(SYSDATE, 1- SYSDATE
                                  FROM DUAL), 'YYYY-MM-DD') AS WEEKLY_DT
FROM DUAL
CONNECT BY LEVEL <= 5;
cs


 

 

3. 해당 날짜에 맞는 요일 조회

1
2
3
4
5
SELECT
    TO_CHAR(TO_DATE('20170927''YYYYMMDD'+ LEVEL - 1'DY') DY
FROM
    DUAL
CONNECT BY LEVEL <= 1;
cs

\

 

+ Recent posts