2015년 2월 24일 화요일

[주말주간]SQL기초에서실무까지(SQL기초,PLSQL,힌트,튜닝)

강좌명 SQL기초에서실무까지(SQL기초,PLSQL,힌트,튜닝)(주말주간(토/일))
오라클자바커뮤니티(www.oraclejavacommunity.co.kr) 추천 실전강좌
교재 PDF or 자체교재제공(교재비 27,000원 별도)
강좌 일정 02월28일(토) ~ 03월15일(일)((주말주간(토/일)) 10:00~17:50, 8일) 총 56시간
강의 장소 [A강의장]구로디지털단지역2번 출구 -> 미니스톱끼고 우회전 -> 100m 직진 후 골목길 끝에서 횡단보도 건너기 --> 우회전 후 구로호텔 직전 좌측길, 호텔 바로 뒤편 파트너스타워2차 301호
[약도보기]
수강절차 - 강좌내용 확인
- 전화 또는 홈페이지(www.oraclejavacommunity.com)를 통한 수강지원 및 수강료 결제(무통장입금, 온라인 카드결제)
- 고용보험 가입자(재직자)인 경우 고용보험환급 관련 서류 제출
- 수강전 : 커리큘럼 및 장소에 대해 다시 한번 공지
- 교육 전 설문 작성(간단한 개발 경력, 수강 목적, 강좌진행방식 등)
- 강좌 수강
- 수강후 : 교육 후 설문 작성
수강료 - 616,000원
* 비환급(일반)으로 지원 가능하며 근로자 개인수강지원의 경우 재직자내일배움카드 또는 고용보험 가입자로서 근로자카드 발급받으신분만 수강 가능하며, 사업주/고용주환급은 기존처럼 정보마당->자료실의 1,2번서식 근로자동의서, 훈련위탁계약서 주시고 수강료 결제하시면 됩니다.

* 채용예정(확정)된 분은 현재 고용보험 미가입이라도 입사예정인 회사명으로 교육가능 합니다. (채용예정인 기업에서 결제하고 그 기업으로 환급 됩니다.)

재직자내일배움카드 or 근로자카드 지원인 경우 해당 카드로 본인 부담액만 결제하시면 되고 근로자 카드는 고용보험 가입자라면 누구나 간단한 절차를 통해 발급받을 수 있습니다.(근로자카드제도 및 발급안내)

* 카드를 수령하지 않았더라도 근로자카드 신청 후 노동부 승인 받은 상태라면 교육수강 가능!

과정 지원을 위해 하단 지원하기 버튼을 클릭해 주시면 본원에서 연락드리겠습니다.
기타 자세한 문의는 본원(02-851-4790)으로 주세요.


[고용주환급]대기업:24만원 전후(1000인이상 기업 : 15만원 전후 ), 중소기업:37만원 전후 환급

[근로자직업능력개발훈련(기존 근로자향상개인환급, 재직자내일배움)]중소기업 정규직 20% 본인부담, 중소기업 비정규직/이직예정자/무급휴직자 무료, 대기업 정규직은 전액본인부담, 정규직50세이상/이직예정자 20% 본인부담, 비정규직/정규직무급휴직자 무료

본인 부담액을 근로자 카드를 발급받아 결제 해야 하며, 대기업(상시근로자 300인 이상 대기업)재직자(50세미만)는 근로자직업능력개발훈련(개인수강지원) 국비 지원 안됩니다.

* 휴강 :법정공휴일

[강사소개]

오라클자바커뮤니티교육센터장 직강
* 일정상 강사님은 다른 실무 강사님으로 변경 될 수도 있습니다.
수강료
입금안내
- 온/오프라인 카드결제, 계좌이체(수강안내->입금안내 참조)
문의사항 02-851-4790 번으로 연락 부탁 드립니다.
교육개요 실무에서 다 년간 SQL튜닝을 경험한 실전 DBA, SQL튜닝 전문가가 진행하는본 과정은 개발 시 흔히 겪게 되는 최적의 SQL 사용법에 중점을 둔 강좌로서 기본적인 SQL문법, SQL기본함수, 서브쿼리, 조인, 효율적인 인덱스 사용법을 세분화해서 집중적으로 학습합니다.

또한 개발하면서 자주 보게되는 스키마 객체(Schema Object, Table, Index, View, Sequence, Synonym, DBLink)들에 대해 다루며 PL/SQL, Stored Program(Procedure, Function, Oracle Cursor, Package, Trigger)을 마스터 후 오라클 옵티마이저, 실행계획, 오라클의 힌트구문를 통해 실행계획을 효율적으로 수립하는 방법을 학습하며 SQL문의 튜닝의 기본에 대해 학습 합니다.

고급SQL, 효과적인 Index사용, Oracle Hint등을 적절히 이용 한다면 데이터 검색 시 수분이상 걸리는 SQL문장을 수 초안에 데이터가 검색되도록 SQL튜닝 가능하죠^^, 개발자라면 꼭 알고 있어야 합니다! 고급 SQL 사용법, 그룹함수의 튜닝, 각종 인덱스에 대한 이해, 인덱스 활용법, 조인의 원리, 세미조인, 안티조인의 이해 및 관련된 여러가지 힌트구문을 통해 SQL튜닝에 대한 이해를 철저한 실습을 통해 이해하게 되실 것 입니다.

본 과정은 철저한 실습,실무위주의 교육으로 과정을 수료함으로써 SQL 사용에 대한 자신감 및 SQL SKILL을 향상시킬 수 있을 것 입니다.
교육목표 ○ SQL*Plus 사용법에 대한 이해
○ SQL 기본함수에 대한 이해
○ SQL 고급함수에 대한 이해
○ Join 및 Sub Query에 대한 이해
○ DML, DDL, DCL에 대한 이해
○ Oracle Index에 대한 이해
○ Oracle Schema Object 에 대한 이해
(Table, View, Index, Synonym, Trigger, DataBase Link, Sequence등)
○ Oracle Stored Program(Procedure, Function)에 대한 이해
○ 인덱스를 선정하는 기준에 대한 이해
○ 효율적인 인덱스 운영 및 관리
○ B*Tree 인덱스의 단점을 보완하기 위한 기타 인덱스에 대한 이해.
○ Bitmap, Function Based Index, Recerse Key Index에 대한 이해.
○ 대용량 데이터를 효율적으로 저장을 위한 구조에 대한 이해
○ 실행계획 해석방법의 이해
○ 통계정보의 이해
○ Optimizer 구성요소 및 작동원리에 대한 이해
○ 옵티마이저의 기능과 역할을 실행계획을 통해서 정확히 이해
○ INDEX생성, DRIVING TABLE의 ACCESS 순서 변경 및 HINT, 분석함수 등을 사용하여   SQL QUERY 의 응답 속도 향상.
○ 조인방식에 대한 이해 및 CASE별 최적의 조인메카니즘을 이해
○ 오라클 힌트 구문에 대한 이해
○ 힌트의 사용을 통한 SQL튜닝의 이해
○ 본인이 작성한 SQL문에 대하여 옵티마이저의 작동 원리를 파악하고 실행계획을 분석
○ 현실 실무에서의 튜닝 사례를 설명하고 튜닝을 위한 명확한 실무 활용기준 가이드를 제시
교육대상 초보 개발자 or DB에 관심있는 일반인
SQL에 관심있는 개발자
DB전문가가 되기 위한 개발자
선수학습 데이터베이스에 대한 이해
 


SQL BASIC 오라클소개
SELECT 기본
SQL*Plus 사용법
SQL Function
Join, Sub Query
Oracle Object 데이블관리
오라클 플래시 백(Flashback)
데이터무결성
참조무결성
인덱스 관리
시퀀스
동의어
데이터베이스링크
사용자 권한 제어
TCL
PL/SQL PL/SQL 개요
PL/SQL Programming 기본문법
PL/SQL 제어문, 반복문, 변수, 상수 사용법
Stored Procedure, Function
Package
Trigger
Utility 원격데이터베이스 엑세스(DBLink)
Export/Import
SQL Loader
옵티마이저 이해 OPTIMIZER 이해
OPTIMIZER 구성요소 및 동작원리에 대한 이해
OPTIMIZER MODE 및 이와 관련된 힌트구문 이해
CBO, RBO의 이해
SQL 실행계획 분석 실행계획 보기
실행계획의 유형
실행계획의 제어
B-Tree 인덱스 활용 인덱스의 구성원리
인덱스 매칭율
옵티마이저의 선택기준
인덱스와 관련된 힌트 구문 이해
order by를 대신할 힌트 구문들
인덱스의 활용 B-Tree 인덱스를 사용하지 못하는 경우
Bitmap 인덱스의 이해
Reverse Key 인덱스
Function Based 인덱스(함수기반인덱스)
각종 인덱스 생성 및 쿼리를 통한 SQL 튜닝이해
대용량 데이터에 유용한 물리구조 CLUSTER
PARTITION
PARTITION 예제
Merge, Multi Table Insert, 외부 테이블
조인에 대한 이해 및 활용 조인 원리의 파악 및 활용 비교
NESTED LOOP JOIN 원리
HASH JOIN 원리
SORT MERGE JOIN 원리
각 조인을 이용할 수 있는 힌트 구문이해
각 조인별로 생성되는실행계획 및 SQL문의 성능 실습
조인 드라이빙 테이블의 선정 드라이빙 테이블이란?
드라이빙 테이블의 중요성
RBO, CBO에서의 드라이빙 테이블 결정 방법
힌트를 이용한 드라이빙 테이블의 결정
적절한 드라이빙 테이블의 선정을 통한 SQL문 튜닝 이해 및 실습
Oracle hint Optimizer Mode변경 Hint
(RULE, FIRST_ROWS, ALL_ROWS, CHOOSE)

실행계획 SQL연산의 이해
(AND-EQUAL, CONCATENATION, COUNT, FILTER, HASH ANTI_JOIN, HASH SEMI-JOIN,
INDEXRANGE SCAN, INLIST ITERATOR, MERGE, MERGE SEMI_JOIN, MERGE ANTI_JOIN)

실행경로변경힌트 이론 및 실습
(FULL, ROWID, CLUSTER, HASH, INDEX, INDEX_ASC, INDEX_DESC, NO-INDEX, INDEX_JOIN, INDEX_FFS, INDEX_COMBINE, NATIVE_FULL_OUTER_JOIN)

조인순서변경힌트 이론 및 실습
(ORDERED, USE_NL, USE_NL_WITH_INDEX, USE_HASH, HASH_AJ, LEADING, USE_MERGE, DRIVING_SITE)

기타 힌트
(RESULT_CACHE, CACHE, NOCACHE, DYNAMIC SAMPLING)

* 위 대부분의 실습은 대량의 데이터를 테이블에 입력 후 실전과 같이 실습 예정이며, 실습을 통해 결과를 확인함으로써 이론에 대해 이해할 수 있습니다.
SQL튜닝 실전사례연구 SQL튜닝의 도구 AUTO TRACE, EXPLAIN PLAN, TKPROF에 대한 이해 및 실습
현장 사례연구
INline View, With구문을 활용한 SQL문 튜닝
ORDER BY 튜닝(INDEX_ASC, INDEX_DESC를 이용한 튜닝)
MAX, MIN 값의 튜닝(INDEX관련 힌트를 이용한 튜닝)
MINUS를 사용한 경우의 SLQ튜닝
COUNT(*) 튜닝(index_ffs를 이용한 튜닝, MVIEW를 이용한 성능 튜닝)
Query 및 오라클함수에 대한 RESULT_CACHE 힌트를 이용한 튜닝
DISTINCT의 튜닝(EXISTS)
INDEX를 이용한 튜닝(Bitmap, Function Based Index)
OR연산 튜닝
index_ss(SKIP SCANNING)을 이용한 튜닝
mview를 이용한 group by, count, max, min 튜닝
게시판 페이지 나누기 쿼리문 튜닝
 

2015년 2월 5일 목요일

#82. 오라클 뷰(Oracle View)

#82. 오라클 뷰(Oracle View)

뷰(VIEW)

 하나또는 그 이상의 테이블이나 뷰를 이용하여 생성되는 논리적인 테이블로 실제 데이터는 저장하지 않는다.
 뷰를 생성하게 되면 데이터 딕셔너리에 뷰에 대한 정의만 저장되고 뷰의 기본이 되는 테이블을 BASE TABLE 이라고 한다.
 테이블의 전체 데이터중 일부칼럼, 일부 레코드만 보여주는 역할을 한다.
 뷰를 통해 데이터를 입력, 수정, 삭제 가능하다.
 뷰의 기본이 되는 테이블의 무결성 제약조건은 상속한다.
 뷰 생성을 위해서는 CREATE VIEW 시스템 권한이 있어야 한다.
 데이터의 보안과 사용 편의성을 제공한다.

[형식]
CREATE [OR REPLACE] [FORCE|NO FORCE] VIEW  view_name  [(alias[,alias]...)]
AS Subquery
[WITH READ ONLY]
[WITH CHECK OPTION [CONSTRAINT constraint]];

OR REPLACE : 이미 뷰가 존재 한다면 RE-CREATE 하라는 의미
FORCE : BASE TABLE의 존재유무와 관계없이 뷰 생성
NO FROCE : 기본 값이며, BASE TABLE이 존재해야 뷰 생성 가능하다.
ALIAS : BASE TABLE의 칼럼명과 다르게 주는 경우
WITH READ ONLY : 읽기 전용 뷰 생성
WITH CHECK OPTION : 뷰의 생성쿼리가 SELECT 할 수 있는 데이터만 INSERT, IPDATE, DELETE 가능
CONSTRAINT constraint : 체크 제약 조건의 이름

11.1 단순 뷰(Simple View)

 BASE TABLE이 하나인 경우이며, 뷰를 통한 DML(Update, Insert, Delete)이 가능하다.
 View가 Join 조건, Aggregate 함수, GROUP BY 구, DISTINCT를 포함하는 경우 로우를 Delete할 수 없다
 View가 Join 조건, Aggregate 함수, GROUP BY 구, DISTINCT, expression으로 정의된 Column을 포함하는 경우 로우를 Update 할 수 없다.
 View가 Join 조건, Aggregate 함수, GROUP BY 구, DISTINCT, expression으로 정의된 Column, View로 선택되지 않은 NOT NULL칼럼을 포함하는 경우 로우를 Insert 할 수 없다.


1. EMP 테이블에서 20번 부서 사원의 사번, 이름, 급여를 정의하는 v_emp20 이라는 이름의 단순뷰를 작성 하시오.

SQL> create view v_emp20
  2  as
  3  select empno, ename, sal from emp
  4  where deptno = 20;

뷰가 생성되었습니다.

SQL> select * from v_emp20;

    EMPNO ENAME            SAL
---------- ---------- ----------
      7369 SMITH            1000
      7566 JONES            2975
      7788 SCOTT            1000
      7876 ADAMS            1100
      7902 FORD            3000



11.2 복합 뷰(Complex View)

 BASE TABLE이 여러 개며 함수나 그룹함수 등을 SELECT LIST에 가진 경우.
 INSERT, UPDATE, DELETE 허용 되지 않는다.


1. EMP 테이블과 DEPT 테이블을 조인하여 10번 부서 사원들의 사번, 이름, 급여, 부서명을 정의하는 v_emp10 이라는 이름의 복합뷰를 작성 하시오.

SQL> create view v_emp10
  2  as
  3  select empno, ename, sal, dname from emp, dept
  4  where emp.deptno = 10
  5  and  emp.deptno = dept.deptno;

뷰가 생성되었습니다.

SQL> select * from v_emp30;

EMPNO ENAME            SAL DNAME
------ ---------- ---------- --------------
  7782 CLARK            2450 ACCOUNTING
  7839 KING            5000 ACCOUNTING
7934 MILLER          1300 ACCOUNTING

2. EMP 테이블에서 부서별 평균 급여와 급여의 합을 가지는 복합뷰를 생성하시오.
(함수를 이용하여 뷰를 생성하는 경우 반드시 칼럼 별명을 사용해야 한다.)

SQL> create view v_emp_sum_avg
  2  as
  3  select deptno, avg(sal), sum(sal) from emp
  4  group by deptno;
select deptno, avg(sal), sum(sal) from emp
              *
3행에 오류:
ORA-00998: 이 식은 열의 별명과 함께 지정해야 합니다


SQL> create view v_emp_sum_avg
  2  as
  3  select deptno, avg(sal) avg, sum(sal) sum from emp
  4  group by deptno;

뷰가 생성되었습니다.

SQL> select * from v_emp_sum_avg;

    DEPTNO        AVG        SUM
---------- ---------- ----------
        20      1815      9075
        10 2916.66667      8750



11.3 인라인 뷰(Inline View)

 인라인 뷰는 스키마 오브젝트는 아니지만 WHERE절의 서브쿼리, FROM절에서 SELECT를 사용하여 테이블 처럼 사용될 데이터를 정의할 때 사용한다. 임시 뷰의 형태, 이름없이 해당 SQL 라인내에 기술한다 하여 인라인 뷰라고 함.
 주로 조인 연산을 줄이기 위해, SELECT 되는 타겟 데이터의 양을 줄이기 위해, 분리된 쿼리를 하나의 쿼리에 모아서 사용하기 위해 사용한다

1. 인라인뷰를 사용하여 사원 테이블에서 부서별로 부서명, 급여의 평균, 급여의 합계를 출력 하시오.

SQL>  select dname, avg_sal, sum_sal
  2  from ( select deptno, avg(sal) avg_sal, sum(sal) sum_sal
  3            from emp
  4          group by deptno) e, dept d
  5  where e.deptno = d.deptno;

DNAME            AVG_SAL    SUM_SAL
-------------- ---------- ----------
RESEARCH            1815      9075
ACCOUNTING    2916.66667      8750




11.4 WITH CHECK OPTION

 뷰의 쿼리가 SELECT 할 수 있응 ROW에 대해 INSERT, UPDATE 가능 하다.


1. WITH CHECK OPTION 에 대하여 실습 하시오.

CREATE OR REPLACE VIEW v_emp1020
AS
SELECT *
      FROM emp
      WHERE deptno = 10
          Or deptno = 20
      WITH CHECK OPTION
        CONSTRAINT ck_emp_1020;


Select * from v_emp1020;

Update v_emp1020 set deptno = 30;

Update v_emp1020 set deptno = 30
      *
1행에 오류:
ORA-01402: 뷰의 WITH CHECK OPTION의 조건에 위배 됩니다

Insert into v_emp1020 (empno, ename, deptno) values (9998, '박정남' ,30);

Insert into v_emp1020 (empno, ename, deptno) values (9998, '박정남' ,30)
            *
1행에 오류:
ORA-01402: 뷰의 WITH CHECK OPTION의 조건에 위배 됩니다

-- 인라인 뷰에서도 with check option 사용 가능 하다.
insert into (select empno, ename, deptno from emp where deptno=30) values (9998, '박정남' ,30);

1 개의 행이 만들어졌습니다.

insert into (select empno, ename, deptno from emp where deptno=30 with check option) values (9997, '김정술' ,40);
insert into (select empno, ename, deptno from emp where deptno=30 with check option) values (9997, '김정술' ,40)
                                              *
1행에 오류:
ORA-01402: 뷰의 WITH CHECK OPTION의 조건에 위배 됩니다



11.5 DROP VIEW

 뷰를 삭제하는 명령.(USER_VIEWS 딕셔너리뷰에서 뷰 정의만 삭제됨)
 BASE TABLE은 삭제되지 않는다.


[형식]
DROP  VIEW  view_name 

#83. 오라클 동의어(Oracle Synonym)

#83. 오라클 동의어(Oracle Synonym)

동의어(Synonym)

 테이블, 뷰, 시퀀스, 프로그램 유닛에 대한 별명이며 공용(public), 전용(private) 두가지 형태로 작성 가능하다. 공용 동의어는 DBA 권한을 가진 사용자만이 생성 가능하고 모든 계정에서 접근 가능 하며, 전용 동의어는 객체에 대한 접근 권한을 얻은 사용자가 작성하는 동의어로 해당 USER에서만 사용 가능 하다.
 동의어는 Schema Object는 아니지만 스키마 오브젝트를 직접 참조한다.
 예를 들어 SCOTT 계정에서 ONJ 계정의 STUDENT 테이블을 참조할 때 ONJ.STUDENT 라고 써주어야 하는데 이는 여러 번 사용되는 경우 불편하다. 이러한 경우 ONJ.STUDENT 에 대한 동의어를 만들어서 사용하면 편리하다.

[형식]
CREATE [PUBLIC] SYNONYM [schema.]동의어명
FOR [schema.]object;

PUBLIC : 공용 동의어 정의, 생략하면 전용 동의어 정의함


SQL> conn  /  as sysdba
연결되었습니다.

SQL> select * from emp;
select * from emp
              *
1행에 오류:
ORA-00942: 테이블 또는 뷰가 존재하지 않습니다

SQL> select count(*) from scott.emp;

  COUNT(*)
----------
        9

SQL> create synonym emp for scott.emp;

동의어가 생성되었습니다.

SQL> select count(*) from emp;

  COUNT(*)
----------
        9

-- DUAL이 Public Synonum 임을 확인 하세요.

SQL> COL owner FORMAT A20
SQL> SET linesize 120
SQL> SELECT owner, synonym_name, table_owner from dba_synonyms
  2  WHERE synonym_name = 'DUAL'  ;

OWNER                SYNONYM_NAME                  TABLE_OWNER
-------------------- ------------------------------ ----------------
PUBLIC              DUAL                          SYS

SQL> drop synonym emp;

동의어가 삭제되었습니다. 

[PLSQL 반복문, LOOP, FOR, WHILE 예제]임의의 수입력받아 그수까지의 합을 구하는 예제

[PLSQL 반복문, LOOP, FOR, WHILE 예제]임의의 수입력받아 그수까지의 합을 구하는 예제

Accept를 이용하여 숫자를 입력받고 1부터 그 수까지의 합을 구하세요

- basic loop문
- for loop문
- while loop문

--------------------------------------------------------------------------------------------------

1. BASIC LOOP 이용


SQL>edit a

set serveroutput on
accept p_num prompt 'Enter a number : '
create or replace procedure sum1
is
  v_sum number := 0;
  i number := 0;
begin
 
  loop
      i := i + 1;
      v_sum := v_sum + i;
      exit when  i >= &p_num ;
  end loop;
  dbms_output.put_line(&p_num || '까지 합은 ' || v_sum);
end;
/

SQL>@a

Enter a number : 10
구  10:      exit when  i >= &p_num ;
신  10:      exit when  i >= 10 ;
구  12:    dbms_output.put_line(&p_num || '까지 합은 ' || v_sum);
신  12:    dbms_output.put_line(10 || '까지 합은 ' || v_sum);

프로시저가 생성되었습니다.

SQL> exec sum1;
10까지 합은 55

PL/SQL 처리가 정상적으로 완료되었습니다.



2. FOR LOOP 이용

SQL>edit a1

set serveroutput on
accept p_num prompt 'Enter a number : '
create or replace procedure sum2
is
  v_sum number := 0;
begin
 
  for i in 1..&p_num loop
      v_sum := v_sum + i;
  end loop;
  dbms_output.put_line(&p_num || '까지 합은 ' || v_sum);
end;
/


SQL> @a1
Enter a number : 10
구  6:    for i in 1..&p_num loop
신  6:    for i in 1..10 loop
구  9:    dbms_output.put_line(&p_num || '까지 합은 ' || v_sum);
신  9:    dbms_output.put_line(10 || '까지 합은 ' || v_sum);

프로시저가 생성되었습니다.

SQL> exec sum2;
10까지 합은 55

PL/SQL 처리가 정상적으로 완료되었습니다.


3. WHILE LOOP 이용


SQL>edit a2

set serveroutput on
accept p_num prompt 'Enter a number : '
create or replace procedure sum3
is
  i number := 0;
  v_sum number := 0;
begin 
    while (i < &p_num) loop
      i := i + 1;
      v_sum := v_sum + i;    
  end loop;
  dbms_output.put_line(&p_num || '까지 합은 ' || v_sum);
end;
/


SQL>@a2

Enter a number : 10
구  6:    while (i < &p_num) loop
신  6:    while (i < 10) loop
구  10:    dbms_output.put_line(&p_num || '까지 합은 ' || v_sum);
신  10:    dbms_output.put_line(10 || '까지 합은 ' || v_sum);

프로시저가 생성되었습니다.

SQL> exec sum3
10까지 합은 55

PL/SQL 처리가 정상적으로 완료되었습니다. 

스프링응답을 XML로(@XmlRootElement, @XmlElement,Spring @MVC)

스프링응답을 XML로(@XmlRootElement, @XmlElement,Spring @MVC)

Spring3의 <mvc:annotation-driven/>는  JAXB 라이브러리를 사용할 수 있다면, 객체 -->  XML변환을 지원한다. JAXB는 JDK에 포함되어 있으므로 별도로 라이브러리에 추가할 필요는 없다.

모델쪽에 있는 객체중 XML로 변환할 객체에 대해서는 JAXB annotation을 사용하면 되고 컨트롤러의 메소드에는 @Response 어노테이션이 추가되어 있어야 한다.
(@XmlRootElement, @XmlElement)


1. spring mvc 프로젝트 생성(mvcxml 이름으로)

- top level package명은 edu.mvc.xml로 지정

2. 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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edu.mvc</groupId>
<artifactId>xml</artifactId>
<name>mvcxml</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.6</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>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>

<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>        
</dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


3. /WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

</web-app>



4. /WEB-INF/spring/appServlet/servlet-context.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
        http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 
<context:component-scan base-package="edu.mvc.xml" /> 
<mvc:annotation-driven />
 
</beans>



5. 컨트롤러


package edu.mvc.xml;

import model.Emp;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
 
@Controller
public class HomeController {
 
@RequestMapping(value="/emp/{name}", method = RequestMethod.GET)
public @ResponseBody Emp getEmp(@PathVariable String name) {
 
Emp emp = new Emp(name, 100); 
return emp; 
}
 
}


6. 모델


package model;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "emp")
public class Emp {
 
String name;
int age;
 
public String getName() {
return name;
}
 
@XmlElement
public void setName(String name) {
this.name = name;
}
 
public int getAge() {
return age;
}
 
@XmlElement
public void setAge(int age) {
this.age = age;
}
 
public Emp(String name, int age) {
this.name = name;
this.age = age;
}
 
public Emp() {
}
 
}


7. 실행


http://localhost:8080/xml/emp/Smith

[결과]

<emp>
<age>100</age>
<name>Smith</name>
</emp>


스프링MVC Flash Attribute(RedirectAttributes, FlashMap)

스프링MVC Flash Attribute(RedirectAttributes, FlashMap)

MVC기반의 일반 웹어플리케이션에서 서버측으로 POST형태로 데이터를 전송하게되면 스프링 컨트롤로에서는 사용자 요청에서 데이터를 꺼내 데이터베이스에 저장하는 등의 일을 한다.
그런다음 사용자에게 성공한 상태정보를 보여주기위해 JSP 페이지등을 포워딩하게 된다. 이 경우 사용자가 F5키 등을 눌러 POST 방식의 요청을 여러번 보내게 되면 문제가 발생할 수도 있다.

이러한 문제점을 보완하기 위해 Spring MVC3.1 이상에서 RedirectAttributes, FlashMap을 이용하여 POST/Redirect/GET 패턴을 보완하기 위한 방법이 나왔는데 이 패턴을 이용하게되면 F5 키등을 눌러 리로드(multiple form submit)하는 경우 POST로 서버측으로 서브밋을 하는 것이 아니라 GET방식 형태로 뜬 JSP만 다시 리로드되게 할 수 있다. 

물론 이때 RedirectAttributes를 사용하여 데이터등을 저장한다면 Redirect된 후 즉시 사라지게 되고 사용자가 F5등을 눌러 리로드 하더라도 다시 서버로 다시 submit되어 저장되지 않게할 수 있다.

FlashMap, RedirectAttributes등을 이용하면 리다이렉트시 값의 전달을  쿼리스트링을 이용한 파라미터등으로 하지않고 임시 플래시메모리를 이용하여 보이지 않게 저장하고, 사용 후 삭제되도록 하는 것이다. 즉 리다이렉트시 데이터 숨겨 넘기는 방법을 제공하는 것이다.

FlashMap은 flash attribute등을 저장 할 수 있고, FlashMapManager를 이용하여  FlashMap 인스턴스등을 저장, 삭제등을 할 수 있다.

Spring MVC에서 FlashAttribute를 사용하기 위해서는 스프링3.1 이상에서만 가능하고
<mvc:annotation-driven /> 태그를 설정파일에 기술해야 한다.


0. flashattr 이라는 스프링 MVC 프로젝트 생성

   top level package명 edi.onj.flashattr 

1. 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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>edi.onj</groupId>
<artifactId>flashattr</artifactId>
<name>flashattr</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.6</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>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>

<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>        
</dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>



2. /WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>

</web-app>




3. /WEB-INF/spring/appServlet/servlet-context.xml

<?xml  version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc  http://www.springframework.org/schema/mvc/spring-mvc.xsd">
         
     
    <bean id="jspViewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
     </bean>
     
    <context:component-scan base-package="edi.onj.flashattr" />
    <mvc:annotation-driven />
  
</beans>


4. 컨트롤러


package edi.onj.flashattr;

import model.Emp;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
public class HomeController {
//EMP를 입력하면 화면을 띄운다.
@RequestMapping(value="addform", method=RequestMethod.GET)
public String showForm(@ModelAttribute("emp") Emp emp) {
return "addemp";
}
//입력화면에서 "Add Emp"버튼 클릭시 호출됨
@RequestMapping(value="add", method=RequestMethod.POST)
public String add(@ModelAttribute("emp") Emp emp,
          final RedirectAttributes rAttr) {
//리다이렉트로 보내는 경우 Flash영역에 임시로 emp, msg를 저장하고 
//화면이 로드된 후에는 값이 사라진다. 결국 리로드 하는 경우라면 
//화면에 아무것도 나타나지 않는다.]
        //값을 output FlashMap에 저장한다.
rAttr.addFlashAttribute("emp", emp);
rAttr.addFlashAttribute("msg", "added success!");
return "redirect:showemp.html";   
}
@RequestMapping(value="showemp", method=RequestMethod.GET)
    public String showCustomer(@ModelAttribute("emp") Emp emp) {
//PAge를 리로드하는 경우 emp.getName, emp.getAge모두 NULL이 넘어온다.
        System.out.println("emp:" + emp.getName() + ":" + emp.getAge());
        return "showemp";
    }
}



5. 모델

package model;

public class Emp {
String name;
String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}



6. /WEB-INF/views/addemp.jsp

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<body>
    <h1>Add New Emp</h1>
    <form:form action="add.html" method="post" commandName="emp">
    <table>
        <tr>
            <td><form:label path="name">name</form:label></td>
            <td><form:input path="name" /> </td>
        </tr>
       
        <tr>
            <td><form:label path="age">Age</form:label></td>
            <td><form:input path="age" /> </td>
        </tr>
       
        <tr>
            <td colspan="2"><input type="submit" value="Add Emp" />
            </td>
        </tr>
    </table>
    </form:form>
</body>
</html>


7.  /WEB-INF/views/showmp.jsp


<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<body>
<h1>${msg}</h1>
    ${emp.name}, ${emp.age}
</body>
</html>


8. 실행

http://localhost:8080/flashattr/showemp.html






@CookieValue, @MVC(스프링컨트롤러쿠키사용예,카운터,Spring MVC)

@CookieValue, @MVC(스프링컨트롤러쿠키사용예,카운터,Spring MVC)

@CookieValue :

HTTP쿠키 값을 HttpServletRequest등을 통해 읽을 필요없이 스프링 컨트롤러에서 파라미터로 전달 받을 수 있게해주며, 쿠키가 존재하지 않으면 오류가 발생하고 required 속성 값을 이용해 필수여부 설정도 가능하고, defaultValue 속성 값을 이용해서 기본값을 지정하는 것도 가능하다.

해당하는 쿠키가 없다면 다음과 같은 오류가 발생한다.

java.lang.IllegalStateException: Missing cookie value '쿠키이름' of type java.lang.String

이를 해결하기 위해서 defaultValue를 사용하면 된다.

@RequestMapping("/hello.html")
public String hello(@CookieValue(value = "쿠키이름", defaultValue = "oraclejavacommunity")  String var) {
......
}


[예 : 쿠키를 이용한 간단한 카운터]

컨트롤러

@Controller
public class HomeController {
 
@RequestMapping(value = "/hello.html")
    public String hello(
            @CookieValue(value = "onjCounter",defaultValue = "0") Integer onjCounter,
            HttpServletResponse response) {
 
        //쿠키값을 읽어 우선 counter, 1증가
onjCounter++;
 
        // 응답에 쿠키를 셋팅
        Cookie cookie = new Cookie("onjCounter", onjCounter.toString());
        response.addCookie(cookie);
 
        // view이름
        return "home";
    }
}



JSP

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Spring MVC Cookie example</title>    
</head>
<body> 
    <h1>OracleJavaCommunity </h1>
    <h1>Spring Cookie Example</h1> 
    Page hit counter: <b> ${cookie.onjCounter.value} </b> 
</body>
</html>