PL/SQL
SQL의 확장
절차적 프로그래밍을 가능
Block 단위로 중첩 가능
모든 문장의 종결 기호는 ;을 사용
대입 연산자 는 :=
실행은 /를 이용(또는 exec)
기본 구조
[DECLARE
variables, cursor, user_defined, exception]
BEGIN
SQL,PL/SQL statements;
[EXCEPTION
actions to perform when errors occur]
END;
//////////////////////////////////////////////////////////////////
PL/SQL 기본 예제
set serveroutput on;
-- 서버쪽에서 출력되는 결과를 클라이언트 측에서 볼 수 있도록 한다는 의미
/* 여러 줄 주석 */
create table test123(
a number,
b varchar2(10)
);
declare
a number;
begin
a := 30;
dbms_output.put_line('a : ' || a);
insert into test123 values(111,'aaa');
end;
/
select * from test123;
PL/SQL은 null 연산을 하기 때문에 변수 선언시 초기화를 해주지 않으면 그 변수에 어떠한 값을 넣어도 null로 나오게 되므로 null + n을 하여도 변수에는 null이 나오게 된다.
//////////////////////////////////////////////////////////////////
PL/SQL 외부에 선언된 변수 사용하기
variable aaa number;
declare
a number := 10;
b number := 20;
begin
:aaa := a + b;
-- 외부에서 선언된 변수는 변수명 앞에 :을 사용한다.
dbms_output.put_line('두 수의 합 구하기 성공');
dbms_output.put_line('aaa : ' || :aaa);
end;
/
print aaa;
//////////////////////////////////////////////////////////////////
위와 같은 코드는 매번 실행할때마다 컴파일/러닝을 하게 된다.
그러나 실제로 사용되는 것은 아래와 같이 프로시져를 만들며 한번만 컴파일하고 만들어진 것을 이용하는 방법을 쓴다.
CREATE OR REPLACE PROCEDURE proTest
IS
a number := 10;
b number := 20;
begin
a := a + b;
-- 외부에서 선언된 변수는 변수명 앞에 :을 사용한다.
dbms_output.put_line('두 수의 합 구하기 성공');
dbms_output.put_line('aaa : ' || a);
end;
/
show error;
--컴파일 에러가 발생하면 에러 확인
생성된 프로시저를 / 말고 실행하기 하는 방법
exec proTest;
//////////////////////////////////////////////////////////////////
기본 문법
CREATE OR REPLACE procedure name
IN argument
OUT argument
IN OUT argument
IS
[변수의 선언]
BEGIN
[PL/SQL Block]
-- SQL문장, PL/SQL 제어 문장
[EXCEPTION]
-- error가 발생할 때 수행하는 문장
END;
//////////////////////////////////////////////////////////////////
agument 사용 예제
두 수를 입력받아 합을 출력하는 프로시저를 생성하라
create or replace procedure prosum(
a IN number,
b In number,
c OUT number
)is
begin
c := a + b;
dbms_output.put_line('두 수의 합 : ');
dbms_output.put_line(a || ' + ' || b || ' = ' || c);
end;
/
variable num number;
exec prosum(3, 5, :num);
print num;
//////////////////////////////////////////////////////////////////
두 수를 입력받아 두 번째 수에 합의 결과를 반환하고 출력하는 프로시저를 생성하라
create or replace procedure prosum(
a IN number,
b In OUT number
)is
temp number;
begin
temp := b;
b := a + b;
dbms_output.put_line('두 수의 합 : ');
dbms_output.put_line(a || ' + ' || temp || ' = ' || b);
end;
/
variable num number;
exec :num := 10;
exec prosum(3, :num);
print num;
//////////////////////////////////////////////////////////////////
변수
비 조합 형 변수
Scalar : 일반적인 형태의 데이터 타입
VARCHAR2(n)
NUMBER(p,s)
DATE
CHAR(n)
LONG
LONG RAW
BOOLEAN
BINARY_INTEGER
PLS_INTEGER
%Type : 특정 테이블의 컬럼에 대한 데이터 타입 또는 먼저 선언된 변수(컬럼)
%Rowtype : 특정 테이블의 모든 컬럼을 받는 데이터 타입(테이블)
//////////////////////////////////////////////////////////////////
number 변수와 integer의 차이점
create or replace procedure proTest1
is
a1 number;
a2 number;
a3 number;
b1 integer;
b2 integer;
b3 integer;
begin
a1 := 10;
a2 := 3;
a3 := a1 / a2;
dbms_output.put_line('a3 : ' || a3);
b1 :=10;
b2 :=3;
b3 := b1 / b2;
dbms_output.put_line('b3 : ' || b3);
end;
/
exec protest1;
-- integer 정수형은 소수점에 대하여서는 반올림 처리 한다.
//////////////////////////////////////////////////////////////////
boolean형 테스트
true, false, null 3가지 형태로 존재한다.
create or replace procedure proTest1
is
a1 number;
a2 number;
b boolean;
b1 boolean;
begin
a1 := 10;
a2 := 10;
b1 := true and false;
if a1 > a2 then
dbms_output.put_line('a1이 크다');
elsif a1 < a2 then
dbms_output.put_line('a2이 크다');
else
dbms_output.put_line('a1과 a2가 같다');
end if;
if b1 then
dbms_output.put_line('b1 : true');
elsif b1 = false then
dbms_output.put_line('b1 : false');
else
dbms_output.put_line('b1 : null');
end if;
end;
/
exec protest1;
and 연산
true true : true
true false : false
true null : null
false null : false
//////////////////////////////////////////////////////////////////
create or replace procedure pronull
is
a varchar2(10);
begin
-- a = b : 같다를 의미함
if a is null then
dbms_output.put_line('a : null');
else
dbms_output.put_line('is not null');
end if;
end;
/
exec pronull;
//////////////////////////////////////////////////////////////////
PL/SQL
select 사용법
select aaa, bbb into xxx, yyy
from emp where 조건절
반환되는 레코드가 한 건인 경우
반환되는 레코드가 여러 건인 경우
set serveroutput on;
create or replace procedure proSearch(
--num IN Number
num IN emp.empno%Type
)is
/*
name varchar2(10);
sal number(7,2);
*/
name emp.ename%Type;
sal emp.sal%Type;
begin
-- 사원번호를 통한 이름과 급여 검색
select ename, sal into name, sal from emp where empno = num;
dbms_output.put_line('사원번호 : ' || num);
dbms_output.put_line('이름 : ' || name);
dbms_output.put_line('급여 : ' || sal);
end;
/
exec prosearch(7521);
//////////////////////////////////////////////////////////////////
제어문
기본 문법
IF condition THEN
statements;
[ELSIF condition THEN]
statements;
[ELSE
statements;]
END IF;
//////////////////////////////////////////////////////////////////
사원번호를 입력받아 그 사원의 급여를 구하고
급여가 0~1000 사이면 일반사원
급여가 1001~2000 사이면 관리직
급여가 2001 이상이면 경영진
이라고 출력하는 프로시저를 생성하라
create or replace procedure empin(
enInput IN Number
)is
sal emp.sal%type;
msg varchar(20);
begin
select sal into sal from emp where empno = eninput;
if sal >= 0 and sal <= 1000 then
msg := '일반사원';
elsif sal >= 1001 and sal <= 2000 then
msg := '관리직';
elsif sal >= 2001 then
msg := '경영진';
else
msg := '뭘입력한거야?';
end if;
dbms_output.put('사원번호 : ' || eninput || '은 ');
dbms_output.put_line(msg || '입니다.');
end;
/
exec empin(7934);
exec empin(7839);
//////////////////////////////////////////////////////////////////
사원번호를 입력받아 그 사원의 모든 정보를 출력하라.
create or replace procedure proemp(
num IN emp.empno%type
)is
myemp emp%rowtype;
begin
select * into myemp from emp where empno = num;
dbms_output.put_line('사원번호 : ' || num);
dbms_output.put_line('이름 : ' || myemp.ename);
dbms_output.put_line('업무 : ' || myemp.job);
dbms_output.put_line('매니져 : ' || myemp.mgr);
dbms_output.put_line('입사일 : ' || myemp.hiredate);
dbms_output.put_line('급여 : ' || myemp.sal);
dbms_output.put_line('커밋 : ' || myemp.comm);
dbms_output.put_line('부서번호 : ' || myemp.deptno);
end;
/
exec proemp(7839);
//////////////////////////////////////////////////////////////////
반복문
for문
FOR index_counter IN [REVERSE] lower_bound..upper_bound LOOP
statement1;
statement2;
. . . . . .
END LOOP;
while문
WHILE condition LOOP
statement1;
statement2;
. . . . . .
END LOOP;
loop문
LOOP
statement1;
statement2;
. . . . . .
EXIT [WHEN condition];
END LOOP;
//////////////////////////////////////////////////////////////////
-- 1부터 10까지의 합을 구하는 프로시저
create or replace procedure profor
is
tot number := 0;
begin
for i in 1..10 loop
tot := tot + i;
dbms_output.put_line('i = ' || i);
end loop;
dbms_output.put_line('tot = ' || tot);
end;
/
exec profor;
//////////////////////////////////////////////////////////////////
-- 시작수와 종착수를 입력받아서
-- 합을 구하는 프로시저
create or replace procedure profor(
st number,
ed number
)is
tot number := 0;
begin
for i in st..ed loop
tot := tot + i;
dbms_output.put_line('i = ' || i);
end loop;
dbms_output.put_line('tot = ' || tot);
end;
/
exec profor(4, 20);
//////////////////////////////////////////////////////////////////
-- 구구단 시작단부터 끝단 입력받아 출력
create or replace procedure profor(
st number,
ed number
)is
tot number := 0;
begin
for i in st..ed loop
for j in 1..9 loop
tot := i*j;
dbms_output.put_line(i || ' * ' || j || ' = ' || tot);
end loop;
end loop;
end;
/
exec profor(4,7);
//////////////////////////////////////////////////////////////////
goto문 사용법(알고만 있고 쓰지 않는 것을 권장)
goto aaa;
를 하면 <<aaaa>> 삽입되어진 위치로 이동되어 진다.
하지만 <<aaaa>>가 가장 end; 직전에 들어가면 오류가 발생한다
사용하지 말아야 하는 이유는
논리적인 구조로 제어라인을 벗어나야 하는데
goto문은 제어와 상관없이 강제적으로 구조를 벗어나게 되므로
논리적 에러를 유발시킬 수 있다. 또한 속도저하를 유발한다(?)
//////////////////////////////////////////////////////////////////
-- 1부터 10까지의 수의 합을 구하시오
(단, while문을 사용)
create or replace procedure prowhile
is
tot number := 0;
i number := 1;
begin
while i < 11 loop
tot := tot + i;
i:= i + 1;
end loop;
dbms_output.put_line('tot : ' || tot);
end;
/
exec prowhile;
//////////////////////////////////////////////////////////////////
-- 위와 동일한 1에서 10까지의 합을 loop문을 사용하여 구하시오
create or replace procedure proloop
is
tot number := 0;
i number := 1;
begin
loop
tot := tot + i;
i:= i + 1;
exit when i > 10;
end loop;
dbms_output.put_line('tot : ' || tot);
end;
/
exec proloop;
//////////////////////////////////////////////////////////////////
조합형 변수
PL/SQL Record – 구조체 형태
PL/SQL Table – 배열 형태
레코드 기본 문법
TYPE type_name IS RECORD
(field_name1 {scalar_datatype|record_type} [NOT NULL] [{:= | DEFAULT} expr],
(field_name2 {scalar_datatype|record_type} [NOT NULL] [{:= | DEFAULT} expr],
. . . . . . .);
identifiee_name type_name;
테이블 기본 문법
TYPE table_type_name IS TABLE OF
{column_type | variable%TYPE
| table.column%TYPE} [NOT NULL]
identifier table_type_name;
//////////////////////////////////////////////////////////////////
테이블 변수 만들기
number 형식의 myType이라는 타입을 생성하고 arr라는 배열 변수를 생성함.
create or replace procedure protable
is
type myType is table of number index by binary_integer;
arr myType;
begin
arr(1) := 30;
arr(2) := 60;
arr(3) := 50;
arr(4) := 80;
dbms_output.put_line('arr(2) : ' || arr(2));
dbms_output.put_line('arr 테이블의 개수 : ' || arr.count);
-- count를 반복문에 사용하면 유용함. 자바의 length
arr.delete(2);
if arr.exists(2) = false then
dbms_output.put_line('2번 테이블은 없다');
end if;
dbms_output.put_line('arr 테이블의 개수 : ' || arr.count);
end;
/
exec protable;
// 확인해보면 delete하면 count는 감소하지만 해당 배열은 빈 공란으로 남겨져 있다.
자동으로 데이터가 당겨지지 않는 것을 알 수 있으므로 주의하여
exists()를 사용하여 확인하여야 한다.
//////////////////////////////////////////////////////////////////
레코드 변수 만들기
-- 사원번호를 입력받아 이름, 급여, 부서코드, 업무만 출력하라.
create or replace procedure proEmpInfo(
eno emp.empno%type
)is
type myRec is record(
iname emp.ename%type,
isal emp.sal%type,
ideptno emp.deptno%type,
ijob emp.job%type
);
arr myRec;
begin
select ename, sal, deptno, job into arr
from emp
where empno = eno;
dbms_output.put_line('사원번호:'||eno);
dbms_output.put_line('이름:'||arr.iname);
dbms_output.put_line('급여:'||arr.isal);
dbms_output.put_line('부서코드:'|| arr.ideptno);
dbms_output.put_line('업무:'||arr.ijob);
end;
/
exec proEmpInfo(7521);
//////////////////////////////////////////////////////////////////
-- 이름, 나이, 주소를 가지는 레코드 형태를 만들고
-- 세명의 정보를 입력하고
-- for문을 활용하여 내용을 출력하는 프로시저
-- (단, 테이블 제외)
create or replace procedure proRecTable
is
type myRec is record(
name varchar2(10),
age number,
addr varchar2(50)
);
type myArr is table of myRec index by binary_integer;
arr myArr;
-- 레코드 배열 형태로 만듬
begin
arr(1).name := '홍길동';
arr(1).age := 20;
arr(1).addr := '안양';
arr(2).name := '박찬호';
arr(2).age := 30;
arr(2).addr := '미국';
arr(3).name := '차승원';
arr(3).age := 35;
arr(3).addr := '서울';
for i in 1..arr.count loop
dbms_output.put('번호 : ' || i);
dbms_output.put(', 이름 : ' || arr(i).name);
dbms_output.put(', 나이 : ' || arr(i).age);
dbms_output.put_line('주소 : ' || arr(i).addr);
end loop;
end;
/
exec proRecTable;
//////////////////////////////////////////////////////////////////
case when 문법(switch case문과 유사)
create table testa(
a varchar2(10)
);
insert into testa values('A');
insert into testa values('C');
insert into testa values('A');
insert into testa values('B');
insert into testa values('B');
insert into testa values('F');
insert into testa values('A');
select a, decode(a, 'A', '사과', 'B', '바나나', 'C', '배', '몰라') as "등급"
from testa;
select a, case a
when 'A', then '사과'
when 'A', then '바나나'
when 'A', then '배'
else '몰라'
end "등급"
from testa;
위와 같은 것을 아래로도 사용 가능함.
case
when d between 90 and 100 then '90-100'
when d between 80 and 89 then '80-89'
when d between 70 and 79 then '70-79'
when d between 60 and 69 then '60-69'
else '0-69'
end
//////////////////////////////////////////////////////////////////
프로시저 소스 보기
set heading off;
set linesize 300;
set pagesize 3000;
desc user_source;
select name, text from user_source;
select distinct name, type from user_source;
select text from usr_source where name = 'PROTEST';
//////////////////////////////////////////////////////////////////
함수(Function)
기본 문법
CREATE OR REPLACE FUNCTION function name
[(argument...)]
RETURN datatype
IS
[변수 선언 부분]
BEGIN
[PL/SQL Block]
-- 블록에는 적어도 한 개의 RETURN 문이 있어야 한다.
-- 블록은 함수가 수행할 내용을 정의한 몸체부분.
END;
//////////////////////////////////////////////////////////////////////
--사원의 번호를 입력받아 그 사원의 급여를 반환하는 함수를 생성하라.
create or replace function funsal(
num emp.empno%type
)return emp.sal%type
is
isal emp.sal%type;
begin
select sal into isal from emp where num = empno;
dbms_output.put_line('정상적으로 검색됨');
return isal;
end;
/
variable aaa number;
exec :aaa := funsal(7521);
print aaa;
--프로시저 안에서 함수 호출하기
create or replace procedure samIT
is
isal emp.empno%type;
begin
isal := funsal(7521);
dbms_output.put_line('검색된 급여' || isal);
end;
/
exec samIT;
//////////////////////////////////////////////////////////////////////
설문조사 테이블(객관식)
당신이 좋아하는 계절은?
1.봄 2.여름 3.가을 4.겨울
당신이 좋아하는 과일
1.사과 2.배 3.복숭아
-- 설문에 사용할 질문 테이블
CREATE TABLE reserchT(
ino NUMBER PRIMARY KEY,
iquest VARCHAR(70) not null,
idate DATE DEFAULT sysdate,
sdate DATE,
edate DATE
);
-- 설문 개수 증가
CREATE SEQUENCE res_seq start with 1 increment by 1;
-- 설문 추가
insert into reserchT values(
res_seq.nextval, '당신이 좋아하는 과일은?', sysdate,
to_date('2009/05/22', 'YYYY/MM/DD'),
to_date('2009/05/30', 'YYYY/MM/DD')
);
-- 설문에 사용될 보기 테이블
create table reserchA(
ano number primary key,
atext varchar2(30) not null,
ino number,
constraint res_ino_fk foreign key(ino) references reserchT(ino)
);
-- 보기 개수
create sequence a_seq start with 1 increment by 1;
-- 보기 추가
insert into reserchA values(
a_seq.nextval, '사과', (select max(ino) from reserchT));
insert into reserchA values(
a_seq.nextval, '배', (select max(ino) from reserchT));
insert into reserchA values(
a_seq.nextval, '복숭아', (select max(ino) from reserchT));
-- max() 함수 말고 currval을 사용하여도 되지만 자바하고 연동시에 정상적인 값이 나오지 않을 수 있으므로 max() 함수를 이용할 수도 있다.
select * from reserchT;
-- 설문 뽑아오기
select t.ino, iquest, atext
from reserchT t, reserchA a
where t.ino = a.ino;
--투표 테이블
create table reserchR(
rno number primary key,
ino number,
ano number,
idate date default sysdate,
constraint r_ino_fk foreign key (ino) references reserchT(ino),
constraint r_ano_fk foreign key (ano) references reserchA(ano)
);
-- 투표한 사람 번호 증가
create sequence r_seq start with 1 increment by 1;
-- 투표
insert into reserchR values(r_seq.nextval, 1, 1, sysdate);
insert into reserchR values(r_seq.nextval, 1, 2, sysdate);
insert into reserchR values(r_seq.nextval, 1, 2, sysdate);
insert into reserchR values(r_seq.nextval, 1, 1, sysdate);
insert into reserchR values(r_seq.nextval, 1, 3, sysdate);
insert into reserchR values(r_seq.nextval, 1, 1, sysdate);
--1번 설문 투표 결과 확인(ano는 보기 번호, count는 투표 인원)
select ano, count(*)
from reserchR
where ino = 1
group by ano
order by ano;
-- 마지막 설문 투표 결과 확인
select ano, count(*)
from reserchR
where ino = (select max(ino) from reserchT)
group by ano
order by ano;
-- 지금까지 만든거 만든거 삭제
drop table reserchA;
drop table reserchT;
drop table reserchR;
drop sequence a_seq;
drop sequence res_seq;
drop sequence r_seq;
//////////////////////////////////////////////////////////////////////
테이블 만들때 아래와 같이 분리하여 만드는 것을 권장
1. 번호, 이름, 아이디, 비밀번호
2. 일련번호, 번호, 취미, 주소, 우편번호, 성별, 전화번호, 언어, 기타등등
1번은 자주 사용하는 컬럼이다. 자주 로그인하고 글쓰기를 하게 되면 자주 db를 사용하게 된다. 2번은 자주 사용하지는 않지만 관련이 있는 컬럼이다. 두 테이블을 하나로 합쳐서 사용하다보면, 로그인만 하는데도 기타 관련 컬럼들까지 같이 들어 있으므로 빈번한 db 사용시 효율적이지 못하다.
//////////////////////////////////////////////////////////////////////
예외처리
종류
정의된 ORACLE SERVER ERROR
정의되지 않은 ORACLE SERVER ERROR
사용자 정의 ERROR
기본 구조
BEGIN
EXCEPTION
WHEN exception1 [OR exception2, . . . .] THEN
statement1;
statement2;
. . . . . .
[WHEN exception2 [OR exception3, . . . .] THEN
statement3;
statement4;
. . . . . .]
[WHEN OTHERS THEN
statement5;
statement6;
. . . . . .]
END;
--정의되지 않은 예외
DECLARE
exception_name EXCEPTION;
PRAGMA EXCEPTION_INIT(exception_name,
error_number);
--사용자 정의 예외
DECLARE
exception_name EXCEPTION;
BEGIN
…
RAISE exception_name;
Exception ~~
END
-- RAISE는 자바의 throws와 같은 의미(예외를 발생시키는 것)
에러 함수
SQLCODE : 에러 코드에 대한 숫자를 RETURN한다.
SQLERRM : 에러 번호에 해당하는 MESSAGE를 RETURN한다.
SQL CODE값
0 : 예외가 없습니다.(NO ERROR)
1 : 사용자 정의 ERROR NUMBER
+100 : NO_DATA_FOUND 예외 -- 데이터가 없을 경우
양의 정수 : 표준 에러 번호
//////////////////////////////////////////////////////////////////////
EXCEPTION에 주로 사용되는 것들
-- NO_DATA_FOUND : 레코드가 없습니다.
-- TOO_MANY_ROWS : 반환 레코드가 여러줄임
-- OTHERS : 나머지 모든 경우
-- ZERO_DIVIDE : 0으로 나누어서 발생한 오류
//////////////////////////////////////////////////////////////////////
사원번호를 검색하여 그 이름과 급여를 출력하라
(단, 사원번호가 검색되지 않으면 예외처리하라)
CREATE or replace procedure proSearch(
num emp.empno%type
)
is
type myRec is record(
iname emp.ename%type,
isal emp.sal%type
);
idata myRec;
begin
select ename, sal into idata.iname, idata.isal from emp
where empno = num;
dbms_output.put_line('사원번호 : ' || num);
dbms_output.put_line('이름 : ' || idata.iname);
dbms_output.put_line('급여 : ' || idata.isal);
Exception
when NO_DATA_FOUND then
dbms_output.put_line('사원번호 : ' || num || '은 없습니다.');
when TOO_MANY_ROWS then
dbms_output.put_line('검색되어 반환되어진 레코드가 여러 개 입니다.');
when OTHERS then
dbms_output.put_line('기타 오류가 발생했습니다.');
end;
/
exec proSearch(7521);
exec proSearch(100);
//////////////////////////////////////////////////////////////////////
사용자 정의 익셉션 만들기
CREATE or replace procedure proSearch(
num emp.empno%type
)
is
type myRec is record(
iname emp.ename%type,
isal emp.sal%type
);
idata myRec;
myException EXCEPTION;
begin
if num < 1000 or num > 9000 then
RAISE myException;
end if;
select ename, sal into idata from emp
where empno = num;
Exception
when myException then
dbms_output.put_line('사용자 정의 오류 : 범위 입력에서 문제가 발생했습니다.');
end;
/
exec proSearch(9999);
-- 범위에서 어긋나므로 사용자 정의 예외가 발생하게 된다.
//////////////////////////////////////////////////////////////////////
커서(Cursor)
오라클 서버에 의해 실행되는 모든 SQL문은 연관된 각각의 커서(오라클이 SQL문장을 실행시키기 위한 공간)를 소유
암묵적(암시적) 커서
SQL문장이 처리되는 곳에 대한 익명의 address
속성
SQL%ROWCOUNT : 해당 SQL 문에 영향을 받는 행의 수
SQL%FOUND : 해당 SQL 영향을 받는 행의 수가 1개 이상일 경우 TRUE
SQL%NOTFOUND : 해당 SQL 문에 영향을 받는 행의 수가 없을 경우 TRUE
SQL%ISOPEN : 항상 FALSE, 암시적 커서가 열려 있는지의 여부 검색
(암시적 커서는 SQL 문이 실행되는 순간 자동으로 열림과 닫힘 실행)
명시적 커서
프로그래머에 의해 선언되며 이름이 있는 커서
커서 선언
Cursor cursor_name is SELETE 구문
커서 open
Open cursor_name
커서 패치
Fetch cursor_name is var1, var2, …
커서 닫기
Close cursor_name
속성
cursor_name%ISOPEN -커서가 OPEN되어 있으면 TRUE
cursor_name%NOTFOUND - 패치한 데이터가 행을 반환하지 않으면 TRUE
cursor_name%FOUND - 패치한 데이터가 행을 반환하면 TRUE
cursor_name%ROWCOUNT - 현재까지 반환된 모든 데이터 행의 수
//////////////////////////////////////////////////////////////////////
암묵적 커서 예제 1)
create table TestIT as select * from emp;
create or replace procedure proCur
is
cnt number;
begin
update testIT set sal = sal*1.2 where deptno = 20;
cnt := sql%rowcount;
dbms_output.put_line('수정된 레코드는 ' || cnt || '개입니다.');
end;
/
exec proCur;
암묵적 커서 예제 2)
create table TestIT as select * from emp;
create or replace procedure proCur(
num emp.empno%type
)is
cnt number;
iname emp.ename%type;
isal emp.sal%type;
begin
select ename, sal into iname, isal from emp
where empno = num;
if sql%found then
dbms_output.put_line('이름 : ' || iname || '급여 : ' || isal);
end if;
end;
/
exec proCur(7521);
//////////////////////////////////////////////////////////////////////
명시적 커서 예제 1)
-- 부서코드가 20인 사람들의 정보를 출력하는 프로시서 생성
create or replace procedure proCurA(
dnum emp.deptno%type
)
is
iname emp.ename%type;
isal emp.sal%type;
ideptno emp.deptno%type;
-- 커서의 선언
cursor myCur is select ename, sal, deptno from emp where deptno = dnum;
begin
for ia in myCur loop
dbms_output.put_line('이름 : ' || ia.ename);
dbms_output.put_line('급여 : ' || ia.sal);
dbms_output.put_line('부서코드 : ' || ia.deptno);
end loop;
/* // loop문보다 for문이 더 간결하므로 주로 사용된다.
-- 커서의 open
-open myCur;
--Fetch 실행
loop
fetch myCur into iname, isal, ideptno;
exit when myCur%notfound;
dbms_output.put_line('이름 : ' || iname);
dbms_output.put_line('급여 : ' || isal);
dbms_output.put_line('부서코드 : ' || ideptno);
end loop;
close myCur;
*/
end;
/
--부서코드를 입력받아서 출력
exec proCurA;
exec proCurA(30);
명시적 커서 예제 2)
create or replace procedure proCurB
is
iname emp.ename%type;
isal emp.sal%type;
ideptno emp.deptno%type;
-- 커서의 선언
cursor myCur(dnum emp.deptno%type) is select ename, sal, deptno from emp where deptno = dnum;
begin
dbms(output.put_line('10번 부서 코드 직원만 출력');
for ia in myCur(10) loop
dbms_output.put_line('이름 : ' || ia.ename);
dbms_output.put_line('급여 : ' || ia.sal);
dbms_output.put_line('부서코드 : ' || ia.deptno);
end loop;
end;
/
exec proCurB;
//////////////////////////////////////////////////////////////////////
-- 부서코드를 입력받아 사람의 이름과, 급여와 업무를 출력하고
-- 그 부서의 급여 합계와 평균을 출력하라
-- (단, 커서와 레코드 테이블을 이용하라)
create or replace procedure proDept(
dnum emp.deptno%type
)
is
type myRec is record(
iname emp.ename%type,
isal emp.sal%type,
ijob emp.job%type
);
type myTab is table of myRec index by binary_integer;
arr myTab;
cursor myCur is select ename, sal, job from emp where deptno = dnum;
cnt number := 0;
tot number := 0;
avr number := 0;
begin
for myi in myCur loop
cnt := cnt + 1;
arr(cnt).iname := myi.ename;
arr(cnt).isal := myi.sal;
arr(cnt).ijob := myi.job;
end loop;
for i in 1..cnt loop
tot := tot + nvl(arr(i).isal, 0);
end loop;
avr := round(tot / cnt, 0);
dbms_output.put_line('부서번호 : ' || dnum || '정보 출력');
dbms_output.put_line('--------------------------------------------');
dbms_output.put_line(' 이 름 급여 업무 ');
dbms_output.put_line('--------------------------------------------');
for i in 1..cnt loop
dbms_output.put(arr(i).iname || ' ');
dbms_output.put(arr(i).isal || ' ');
dbms_output.put_line(arr(i).ijob);
end loop;
dbms_output.put_line('--------------------------------------------');
dbms_output.put_line('총원 : ' || cnt || ' 명');
dbms_output.put_line('급여합계 : ' || to_char(tot, '999,999') || ' 원');
dbms_output.put_line('급여평균 : ' || to_char(avr, '999,999') || ' 원');
dbms_output.put_line('--------------------------------------------');
end;
/
exec proDept(30);
//////////////////////////////////////////////////////////////////////
package
1. 패키지 선언
2. 패키지 바디 구현
-- 사원번호 검색 프로시저
-- 부서코드를 입력받아 합계를 반환하는 함수
-- 사원번호와 급여를 입력받아 사원번호의 급여를 수정하는 프로시저
-- 사용하게 될 테이블 생성
create table TestIT1 as select * from emp;
-- 패키지 선언 부분
create or replace package packTest
as
procedure searchSawon(num TestIT1.empno%type);
function funSum(dnum TestIT1.deptno%type) return number;
procedure proUpdate(num TestIT1.empno%type, isal TestIT1.sal%type);
end;
/
-- 패키지 바디 구현 부분
create or replace package body packTest
as
-- 사원번호 검색 프로시저
procedure searchSawon(num TestIT1.empno%type)
is
iname TestIT1.ename%type;
isal TestIT1.sal%type;
ijob TestIT1.job%type;
begin
dbms_output.put_line('패키지 내부의 검색 실행 ');
select ename, sal, job into iname, isal, ijob
from TestIT1
where empno = num;
dbms_output.put_line('사원번호 : ' || num);
dbms_output.put_line('이름 : ' || iname);
dbms_output.put_line('급여 : ' || isal);
dbms_output.put_line('업무 : ' || ijob);
end;
--부서코드를 입력받아 합계를 반환하는 함수
function funSum(dnum TestIT1.deptno%type) return number
is
tot number;
begin
select sum(sal) into tot from TestIT1 where deptno = dnum;
dbms_output.put_line('패키지 내부의 함수 실행 ');
dbms_output.put_line(dnum || ' 부서의 합 ' || tot);
return tot;
end;
-- 사원번호와 급여를 입력받아 사원번호의 급여를 수정하는 프로시저
procedure proUpdate(num TestIT1.empno%type,
isal TestIT1.sal%type)
is
begin
dbms_output.put_line('패키지 내부의 수정 프로시저 실행 ');
update TestIT1 set sal = isal where empno = num;
if sql%rowcount > 0 then
dbms_output.put_line('레코드 정상 수정 ');
end if;
end;
end;
/
-- 확인
exec packTest.searchSawon(7521);
variable data number;
exec :data := packTest.funSum(30);
print data;
exec packTest.proUpdate(7521, 4000);
///////////////////////////////////////////////////////////////////
Trigger
어떤 이벤트(insert, update, delete)가 발생하면 자동적인 작업을 진행할 수 있도록 하는 PL/SQL 문법
그러나 트리거라는 것이 있고 이러한 사용법이라는 것을 알아두어야 하겠지만, 되도록 사용을 최소화하고 프로시저를 이용하도록 한다.
기본 문법)
create or replace trigger [triger_name]
befre / after -- 둘 중 하나 선택, insert가 일어나기 전에, 일어난 후에
insert or update on [table_name] -- table에 insert나 update 작업을 하게 되면
for each row -- 매 행마다 실행
-- after에서만 사용 가능한 변수
-- :new : trigger에서 제공되는 새로운 값 변수 :예) new.sal
-- :old : trigerr에서 제공되는 예전 값 변수 :예) old.sal
begin
dbms_output.put_line('레코드가 등록되거나 수정되었습니다.');
end;
/
trigger 사용 예제)
set serveroutput on;
-- 트리거에서 사용할 테이블 생성
create table triemp as select empno, ename, sal, deptno from emp;
-- 트리거 생성
create or replace trigger mytrigger
after
insert or update on triemp
for each row
begin
dbms_output.put_line('trigger : 레코드가 등록되거나 수정되었습니다.');
dbms_output.put_line('예전 급여 : ' || :old.sal);
dbms_output.put_line('새로운 급여 : ' || :new.sal);
end;
/
-- 트리거 확인
insert into triemp values(1234, 'Aaaa', 3000, 30);
update triemp set sal = sal*1.2 where deptno = 30;
트리거의 비 활성화 / 비활성화
alter trigger [trigger_name] disable; -- enable
Tomcat 5.5 설치
다운로드 받아서 C드라이브에 압축을 푼다.
시스템 환경변수 등록을 한다.
변수이름 : CATALINA_HOME
변수 값 : C:\apache-tomcat
변수이름 : JAVA_HOME
변수 값 : C:\Java\jdk1.6.0_13
환경변수 추가
변수이름 : CLASSPATH
변수 값 : C:\Java\jdk1.6.0_13\lib\servlet-api.jar
톰캣 포트 변경
C:\apache-tomcat\conf\server.xml
<Connector port="8080" maxHttpHeaderSize="8192"
port 8080으로 된 것을 8090으로 변경
C:\apache-tomcat\webapps\jsp-examples\WEB-INF에서
classes - 폴더
lib - 폴더
web.xml
를 복사하여
C:\apache-tomcat\webapps\test007\WEB-INF
경로에다가 붙여넣기 한다
그리고 web.xml 파일을 수정한다
///////////////////////////////////////////////////////////////////
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
</web-app>
///////////////////////////////////////////////////////////////////
내용만 남겨놓으면 된다.
그리고
톰캣 다운시켰다가 startup시킨다.
test007/ 경로에 index.html 파일을 만들고
웹브라우저로
http://127.1.1.1:8090/test007/index.html
경로로 접속하여 본다.(정상접속 ok)
C:\apache-tomcat\conf\web.xml
파일에서 아래 두 내용(invoker)이 주석되어 있는데 그 주석을 제거한다
///////////////////////////////////////////////////////////////////
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
///////////////////////////////////////////////////////////////////
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
///////////////////////////////////////////////////////////////////
invoket를 해제하는 이유는 외부 경로를 설정하기 위해서임
그리고 나서
C:\apache-tomcat\conf\Catalina\localhost\test008.xml
파일을 생성하고 내용을 넣는다
///////////////////////////////////////////////////////////////////
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="C:\test008"
privileged="true" antiResourceLocking="false" antiJARLocking="false">
</Context>
///////////////////////////////////////////////////////////////////
위와 같이하고 xml 설정 파일을 reload하기 위해 톰캣을 재시작한다.
이렇게 하면 이제 웹에서는
http://127.1.1.1:8090/test008/index.html
와 같은 경로로 하위 폴더 접근이 가능해진다.
///////////////////////////////////////////////////////////////////
JSP에서 캐릭터셋 설정
<%@ page contentType="text/html;charset=utf-8"%>
/////////////////////////////////////////////////////////////////////////
JSP 실행 3단계
JSP 컨테이너에서 실행되기 위해 3단계를 반드시 거친다.
- 변환 단계(Translation Step) : jsp가 java로 변환된다.
hellojsp.jsp가 hellojsp_jsp.java로 변환된다.
- 컴파일 단계(Compile Step) : 변환된 java파일을 컴파일 한다. hellojsp_jsp.java를 컴파일하여 class를 생성한다.
- 실행 단계(Interprete Step) : 생성된 class를 실행하여 실행된 결과를 응답처리
변환파일 저장 위치
C:\apache-tomcat\work\Catalina\localhost\test008\org\apache\jsp
/////////////////////////////////////////////////////////////////////////
JSP 일반 태그 종류
Comments : <%-- 주석 --%> : JSP 주석
Directive tag : <%@ directive %> : JSP에게 정보전달 목적으로 사용
Declaration tag : <%! 선언 %> : 변수 및 메소드 선언
Scriptlet tag : <% 코드 %> : 서비스 코드 구현
Expression tag : <%= 출력값 %> : 결과값 출력
/////////////////////////////////////////////////////////////////////////
Directive tag
-정의
JSP가 서블릿으로 변환될 때 전반적으로 영향을 줄 수 있는 정보를 제공한다.
-종류
page Directive tag : 컨테이너에서 현재 JSP페이지를 어떻게 처리할 것인가에 대한 정보를 제공하는데 사용된다. 여러가지 속성을 이용.
include Directive tag : 여러 JSP페이지에서 공통적인 내용이 있을 때 매번 공통적인 내용을 작성하지 않고 파일로 저장한 후 필요할 때 JSP페이지에서 파일을 삽입하여 사용할 수 있다.
taglib Directive tag : 사용자에 의해서 만든 tag를 이용할 때 사용된다.
/////////////////////////////////////////////////////////////////////////
page Directive tag
속성 : 기본값 - 설명
info : 없음 - 페이지를 설명해주는 문자열 지정
language : "java" - JSP페이지에서 사용할 언어 지정
contentType : "text/html" - 내용이 어떤 형태로 출력할 것인지 지정
extends : 없음 - 서블릿으로 변할 때 상속받을 클래스 지정
import : 없음 - 다른 packgage의 클래스를 import
session : " true" - HTTPSession 객체 사용 여부
buffer : "8kb" - 출력크기를 지정
autoFlush : "true" - 내용들이 출력되기 전 버퍼가 다 찰 경우 동작을 지정
isThreadSafe : "true" - 멀티 스레드 동작 여부
errorPage : 없음 - 예외발생시 예외처리 담당 페이지 지정
isErrorPage : "false" - 예외 담당 페이지의 설정 여부
pageEncoding : "ISO-8859-1" - 사용하는 문자 인코딩 지정
isELIgnored : JSP 버전에 따라 다르다. - JSP2.0에 추가된 속성으로 EL 사용 유무.
<%@ page contentType="text/html;charset=utf-8" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.sql.*" %>
<%@ page language="java" %>
<%@ page session="true" %>
<%@ page buffer="8kb" %>
<%@ page autoFlush="true" %>
<%@ page isThreadSafe="true" %>
<%@ page info="JSP 페이지" %>
<%@ page isErrorPage="false" %>
<%@ page errorPage="hello.jsp" %>
/////////////////////////////////////////////////////////////////////////
include Directive tag
특징
재사용할 수 있다.
유지 보수가 쉽다.
<%@ include file ="hello.jsp"%>
hello.jsp에는 include하는 파일의 인코딩과 같게 설정해주어야 한다.
인클루드 디렉티브 태그(include driective tag)
<%@ include file ="hello.jsp"%>
정적인 페이지를 include할 때 사용하고(변수의 선언 모음)
원 페이지에 include 페이지까지 합쳐서 하나의 페이지로 만들고 나서 컴파일되어 하나의 파일만 생성되게 된다.
인클루드 액션 태그(include action tag)
<jsp:include page ="hello.jsp"/>
동적인 페이지를 include할 때 사용한다.(include한 페이지가 바뀐다거나, 다른 프레임을 변경시키는 작업을 하여야 하는 경우)
원 페이지와 include 페이지가 각각 컴파일되어서 두개의 파일이 생성된다.
/////////////////////////////////////////////////////////////////////////
taglib directive tag
Cannot fine the tag library descriptor for "http://java.sun.com/jsp/jstl/core"
/////////////////////////////////////////////////////////////////////////
param Action tag
test.jsp 파일
<jsp:include page="incl.jsp" flush="true">
<jsp:param name="key" value="Duke"/>
</jsp:include>
incl.jsp 파일
<%
request.setCharacterEncoding("utf-8");
String name =request.getParameter("key");
%>
안녕하세요 <%= name%>입니다. ^^
setCharacterEncoding은 매개변수로 전달받은 파라미터에 대하여 인코딩 설정하여 글자깨짐을 방지한다.
/////////////////////////////////////////////////////////////////////////
GET 방식 매개변수 전달
out.print("<a href=\"view.jsp?num="+ num +"\">" + num +"</a>");
형식으로 get 방식으로 값을 넘겨도 받을때엔
request.setCharacterEncoding("utf-8");
String num =request.getParameter("num");
으로 받으면 된다.(무조건 String 형으로 전달된다)
@주의 : get 방식은 setCharacterEncoding 설정하여도 한글은 깨지므로 POST 사용하라.
또는 환경설정을 하여야 한다.
/////////////////////////////////////////////////////////////////////////
POST 방식 매개변수 전달
out.print("<form method=\"post\" action=\"modify.jsp\">");
out.print("번호 : ");
out.println("<INPUT TYPE=\"text\" NAME=\"num\" value=" + num +" disabled><br>");
out.print("이름 : ");
out.println("<INPUT TYPE=\"text\" NAME=\"name\"num value=" + name +"><br>");
out.print("폰번호 : ");
out.println("<INPUT TYPE=\"text\" NAME=\"tel\" value=" + tel +"><br>");
out.print("주소 : ");
out.println("<INPUT TYPE=\"text\" NAME=\"addr\" value=" + addr +"><br>");
out.print("메모 : ");
out.println("<INPUT TYPE=\"text\" NAME=\"memo\" value=" + memo +"><br>");
out.print("<input type=\"submit\" value=\"진짜로수정하기\"></form>");
받을땐
request.setCharacterEncoding("utf-8");
String num =request.getParameter("num");
/////////////////////////////////////////////////////////////////////////
웹표준? 어긋남?
<input type="button" value="목록보기"onclick="location.href='./list.jsp'">
/////////////////////////////////////////////////////////////////////////
INPUT 태그에서 disabled
disabled해놓으면 버튼이나 텍스트상자에 비활성화만 되는게 아니라
값의 전달도 되지 않는다.
/////////////////////////////////////////////////////////////////////////
페이지 리다이렉트(Redirect)
<%
if(cnt == 1){
response.sendRedirect("list.jsp");
}else{
response.sendRedirect("back.jsp");
}
%>
cnt가 1인 경우 list.jsp로 리다이렉트되고, 그 외의 경우엔 back.jsp로 리다이렉트 된다.
/////////////////////////////////////////////////////////////////////////
스크립트 요소의 이해
선언문
멤버변수의 의미
변수형 선언문
<% String str = "선언문"; %>
메소드형 선언문
<%
public String asdfasf(){
return str;
}
%>
스크립트릿
지역변수의 의미. 되도록 스크립트릿에서 변수를 사용하자.
<% String scriptlet = "스크립트릿 연습"; %>
<%=scriptlet%>
표현식
<%=코드%>
표현식에서는 ;를 생략한다.
/////////////////////////////////////////////////////////////////////////
HTTP 메소드
1. GET
HTTP header에 정보를 실어 보냄
URL 뒤에 매개변수 전달
256Byte가 한계
전달 속도가 빠름
적은 양의 데이터 전송시 좋음
2. POST
HTTP body에 정보를 실어 보냄
데이터 사이즈에 제한이 없음
보안에 좋다(안보이므로)
3. Head
Header의 정보만 온다.
4. Put
Resource를 저장할 때 사용
5. Delete
Resource를 제거할 때 사용
Put과 Delete를 허용하면 서버의 보안 측면상 좋지 못함
6. Trace
클라이언트에서 서버까지 가는 경로 추적
7. Option
서버의 성능 등
/////////////////////////////////////////////////////////////////////////
인덱스 페이지 설정(welcome file 지정)
C:\apache-tomcat\conf\web.xml
페이지에서 최하단에
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
라는 부분이 존재함.
welcom-file 부분에 설정하여 두면, 인덱스 페이지로 활용 가능함
이는 톰캣 서버에 전역적인 설정이고,
C:\test008\WEB-INF\web.xml
에 삽입하게 되면 서브디렉토리 내에서 사용 가능함
/////////////////////////////////////////////////////////////////////////
액션 태그의 개요
JSP에서 스크립트, 주석, 디렉티브와 함께 JSP 페이지를 이루고 있는 요소
액션 태그 : 페이지와 페이지 사이의 제어를 이동시킬수 있고, 다른 페이지의 실행 결과를 현재 페이지에 포함시킬 수 있으며, 자바빈도 JSP페이지에서 사용할 수 있는 기능을 제공한다. 또한 웹브라우저에서 자바 애플릿을 실행시킬 수 있도록 지원.
/////////////////////////////////////////////////////////////////////////
액션 태그의 종류
include - 페이지를 모듈화 할 때 <jsp:include> 액션 태그 사용
forward - 페이지의 흐름을 제어할 때 <jsp:forward>액션 태그 사용
plug-in - <jsp:plug-in>액션 태그는 애플릿을 사용할 때
useBean - 자바빈을 사용할 때(자바빈 객체 생성시) <jsp:useBean>
setProperty - 자바빈의 속성 값을 저장할 때
getProperty - 자바빈의 속성값을 읽어올 때
/////////////////////////////////////////////////////////////////////////
forward action tag(포워드 액션 태그)
<jsp:forward page="이동할 페이지명"/>
URL은 변경되지 않지만, 해당 페이지의 내용은 "이동할 페이지명"으로 바뀌게 된다.
파라미터 전달 방법
<jsp:forward page="이동할 페이지명">
<jsp:param name="paramName1"> values="var1"/>
<jsp:param name="paramName2"> values="var2"/>
</jsp:forward>
포워드 액션 태그는 버퍼를 비운다.
/////////////////////////////////////////////////////////////////////////
useBean Action tag
<jsp:useBean id="빈참조변수" class="패키지를 포함한자바빈" scope="4가지"/>
spoce는 page, request, session, appication
<jsp:useBean id="m" class="test.web.MemberBean"/>
<jsp:setProperty name="m" property="name" value="<%=request.getParameter("name")%>"/>
<jsp:setProperty name="m" property="name" param="name"/>
위의 getParameter 역할을 param이 대신한다.(같은 역할)
<jsp:setProperty name="m" property="name"/>
파람이 같은 경우 생략도 가능하다
<jsp:setProperty name="m" property="*"/>
하게 되면 모든걸 한방에 넣을 수 있다.
/////////////////////////////////////////////////////////////////////////
[ERROR] ... quoted with " which must be escaped when used within the value ...
< JSP 웹어플리케이션 구동시 따옴표사용에러 해결방법 >
1.유닉스 또는 리눅스
startup.sh 중에 "export CATALINA_OPTS"부분
-Dorg.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING=false
를 추가한다.
2. 이클립스
Run - RunConfiguration (또는 DebugConfiguration) - tomcat VM Argument
-Dorg.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING=false
를 추가한다.
useBean Action tag 사용시 param이 아닌 value를 사용하여 매개변수를 받을 때, 데이터의 type이 다를 경우 발생한다.(ParseInt나 valueOf를 사용하여 변환을 해줘도 안먹힘)
/////////////////////////////////////////////////////////////////////////
Expression tag(표현식)
request : 웹브라우저에서 JSP페이지로 전달되는 정보의 모임. HTTP헤더와 HTTP 바디로 구성
response : 웹 브라우저로 응답할 응답 정보를 가지고 있음
out : JSP 페이지가 생성한 결과를 웹브라우저에 전송해주는 출력 스트림
pageContext : JSP 페이지의 컨텍스트를 나타내며, 주로 다른 내장객체를 구하거나, 페이지 흐름제어 그리고 에러 데이터를 얻어낼 때 사용
session : 요청한 웹브라우저에 관한 정보를 저장하고 관리
application : 서버의 설정 정보 및 자원에 대한 정보를 얻어내거나 어플리케이션이 실행되고 있는 동안에 발생할 수 있는 이벤트 로그 정보와 관련된 기능들을 제공
config : 서블릿이 초기화되는 동안 참조해야 할 정보를 전달해주는 역할
page : JSP 페이지 그 자체를 나타내는 객체(this로 자기 자신을 참조할 수 있음)
exception : JSP 페이지에서 예외가 발생하였을 경우, 예외를 처리할 페이지를 지정하였을 때 예외 페이지에 전달되는 객체
/////////////////////////////////////////////////////////////////////////
EL(Expression Language) 표현 언어
기본 문법
${}
${num + 1}
${article.num + 1}
${article['num']+1} 또는 ${article["num"]+1} ''와 "" 모두 유효함(.(dot) 대신 [](브라켓(bracket) 연산자를 사용 가능)
<%@ page isELIgnored="false" %>
옵션이 주어져 있어야 한다.(생략도 가능하지만 true일 경우에는 안됨)
<%=%> 인 expression tag를 대신하는 효과를 가질 수 있다.
<jsp:setProperty name="id" value="${aName}" />
aName 변수의 값을 value로 넣어주고 있다.
EL은 null값을 가지는 변수에 대해 좀 더 관대하고, 데이터 형 변환을 조금 더 자동적으로 해준다.
EL 표현식은 다음과 같은 기능을 가진다.
- 변수와 연산자를 포함한다.
- JSP 영역(page, request, session, application)에 저장된 어떤 속성 및 자바빈이라도 EL의 변수로 사용 가능
- 내장 객체 지원
EL의 내장 객체
pageScope : 모든 page 영역 객체들에 대한 컬렉션
requestScope : 모든 equest 영역 객체에 대한 컬렉션
sessionScope : 모든 session 영역 객체들에 대한 컬렉션
applicationScope : 모든 application 영역 객체에 대한 컬렉션
param : 모든 request 파라미터들을 문자열로 가진 컬렉션
paramValues : 모든 request 파라미터들을 파라미터당 문자열 배열로 가진 컬렉션
header : HTTP 요청 헤더를 문자열로 가진 컬렉션
headerValues : HTTP 요청 헤더들을 헤더당 문자열 배열로 가진 컬렉션
cookie : 모든 쿠키의 컬렉션
initParam : 모든 어플리케이션의 초기화 파라미터의 이름 컬렉션
pageContext : 현재 페이지를 위한 javax.servlet.jsp.PageContext
/////////////////////////////////////////////////////////////////////////
Cannot find the tag library descriptor for http://java.sun.com/jsp/jstl/core
<%@ taglib prefix="c" uri = "http://java.sun.com/jsp/jstl/core" %>
를 하였을때 위와 같은 에러가 나온다면 톰캣 lib에서 default로 jstl.jar와 standard.jar 파일이 로드되지 않기 때문에 복사하여 lib 경로에 넣어줘야 한다.
C:\apache-tomcat\webapps\jsp-examples\WEB-INF\lib
경로에 존재하는 standard.jar, jstl.jar 파일을
C:\apache-tomcat\common\lib 경로에 복사하여 붙여넣기하고
톰캣을 restart 시키면 된다.
/////////////////////////////////////////////////////////////////////////
EL 변수 선언과 사용
<%@ taglib prefix="c" uri = "http://java.sun.com/jsp/jstl/core" %>
를 선언하고
<c:set var="kkk" value="999" />
${kkk} = ${kkk+1}
하여 사용할 수 있다 kkk 라는 변수를 만들고 출력하면 999 = 1000이 나온다.
/////////////////////////////////////////////////////////////////////////
자바 스크립트(Java Script)
<script language="javascript">
<!--
//함수의 선언
function test(){
document.write("test");
}
function test1(num){
document.write("<br>" +num + "을 출력합니다.<br>");
}
function test2(num){
return num + "을 출력합니다.<br>";
}
-->
</script>
와 같은 형태로 자바스크립트 내에서 함수를 선언하여 사용할 수 있다.
for문은 java 문법과 동일하다.
변수는 var 변수명= ""; 형태로 선언이 가능하고, ""로 문자열과 숫자를 구분한다.
alert("경고"); // 경고창을 띄운다(확인 버튼만 가능)
comfirm("확인/취소를 선택해"); // 확인 취소 버튼 선택이 가능
document.write("html 에 적용될 문자열"); // 자바스크립트문법 내에서 html 페이지 내에 사용될 문자열 또는 태그를 적용시킬 수 있다.
prompt("값을 입력해줘", "3"); // 입력받을 수 있는 창을 띄운다.
eval("3+2"); // 문자열이지만 수치형으로 계산하여 5라는 값을 return 하여 준다.
isNaN("111"); // 문자열인지 숫자인지 구분하여 true,false로 리턴
isFinite(11); 숫자가 유한의 숫자이면 true, 아니면 false
배열 사용법
arr = new Array(3);
arr[0] = "장나라";
arr[1] = "최홍만";
arr[2] = "최민수";
/////////////////////////////////////////////////////////////////////////
response.sendRedirect는 페이지 url이 변경된다.
import javax.servlet.http.HttpServlet;
RequestDispatcher dispatcher = request.getRequestDispatcher("list.jsp");
dispatcher.forward(request, response);
는 페이지 url이 변경되지 않는다.
sendRedirect는 dispatcher보다 성능이 떨어진다.
요청시 바인딩된 데이터가 지속되지 못한다.
/////////////////////////////////////////////////////////////////////////
import java.io.PrintWriter;
PrintWriter out = response.getWriter();
/////////////////////////////////////////////////////////////////////////
바인딩(Binding)
정의
실행시 필요한 자원을 컨테이너가 인식할 수 있도록 등록하는 작업을 의미
등록된 자원은 서블릿이나 JSP에서 사용 가능
용도
모듈화된 컴포넌트간의 자원공유가 필요로 할 때 사용
MVC 모델 Model과 View 컴포넌트 간의 자원 공유시 사용
방법
setAttribute(String name, Object obj) 메소드로 바인딩
getAttribute(String name) 메소드로 자원 사용
removeAttribute(String name) 메소드로 자원 삭제
/////////////////////////////////////////////////////////////////////////
============== 서블릿 ==================
** 서블릿 만들기
1. 다이나믹웹프로젝트에서 패키지생성
2. 패키지안에 서블릿 파일 생성
- WebContent>Web-Inf안에 web.xml안에 servlet을 설정해줌
(이클립스는 자동으로 생성하므로, 다른 프로그램일때는 이를 직접 써 넣어야 함)
3. servlet파일의 doGet()/ doPost()에 전달받은 값을 넣음
- doGet()/doPost() 둘 중 어느 것으로 받아도 전달 받을 수 있도록 doProcess()메소드를 만들어 doGet()/doPost()에서
doProcess(request, responce)로 메소드를 불러 사용
4. 사용순서
1) setAttribute로 값을 넣는다.
2) dispatch로 페이지와 값을 넘겨준다.
3) getAttribute로 값을 받아 온다. (꼭 캐스팅 해주어야 함)
** 클라이언트에서 서버로 데이터가 전달되는 방식
1. GET방식
- 데이터 수에 제한
- 보안이 취약(id, password가 다 보임)
- form 에서 default로 method가 get방식으로 되어있음
2. POST방식
- 보안 문제발생이 적음
=>get/post 중 하나로 보내면 servlet에서 doget()이나 dopost()로 받아야 함
** 서블릿의 binding
1. setAttribute
- 구현
: request.setAttribute(String name, Object obj); : request.setAttribute("name", "홍길동");
2. getAttribute : 넘어오는 값은 꼭 캐스팅 해주어야 함(ex> String)
3. removeAttribute
=> 값을 넘겨주기 위해서는 redirect로 넘기지 말고 dispatche로 넘겨주어야 한다.!!!
** 서블릿의 forward
1. redirect
- 구현
: response.sendRedirect("aaa.jsp")
파라미터를 넘길 수 없고 페이지만 호출한다.
2. dispatche
- 구현(객체 생성 후 사용)
: RequestDispatcher dispatcher = request.getRequestDispatcher("aaa"); : aaa라는 servlet호출
dispatcher.forward(request, response);
=> aaa라는 servlet이 있고, web.xml에 mapping되어 있을 때 사용
** servletcontext
1. 서블릿과 컨테이너간에 통신하기 위해 사용
2. context마다 하나의 serveltcontext가 생성(공유가능)
ServletContext 객체는 컨테이너와 동일한 LifeCycle를 갖는다.
3. 구현
- 여러 servlet에서 가져와 사용할 수 있다.
1) web.xml에서 지정되지 않은 servlet 안에
<context-param>
<param-name></param-name>
<param-value></param-valude>
</context-param>
2) servlet 파일에 객체를 생성한 후 변수에 값을 넣어 출력
ServletContext context = getServletContext();
String driver = context.getInitParameter("driver");
용도
서블릿에서 파일접근시 사용된다.
자원을 바인딩 할 때 사용된다.
로그파일 작성시 사용된다.
context 파라미터를 이용 할 때 사용된다.
////////////////////////////////////////////////////////////////////////
예제)
web.xml 에 아래 내용 추가
<context-param>
<param-name>driver</param-name>
<param-value>oracle.jdbc.driver.OracleDriver</param-value>
</context-param>
<context-param>
<param-name>url</param-name>
<param-value>oracle:thin:@localhost:1521:darkhi</param-value>
</context-param>
<context-param>
<param-name>user</param-name>
<param-value>scott</param-value>
</context-param>
<context-param>
<param-name>pass</param-name>
<param-value>tiger</param-value>
</context-param>
java 서블릿 파일에서 아래와 같이 사용.
import java.io.PrintWriter;
import javax.servlet.ServletContext;
response.setContentType("text/html;charset=euc-kr");
PrintWriter out = response.getWriter();
String driver = getInitParameter("driver");
String url = getInitParameter("url");
String user = getInitParameter("user");
String pass = getInitParameter("pass");
out.print("driver : "+driver +"<br>");
out.print("url : "+url +"<br>");
out.print("user : "+user +"<br>");
out.print("pass : "+pass +"<br>");
////////////////////////////////////////////////////////////////////////
- 파일에서 가져올 때(.txt)
1) web-inf안에 txt로 파일을 만듦
2) servlet파일에 객체 생성 후 txt파일로 저장된 경로를 가져와 뿌려준다.
ServletContext context = getServletContext();
InputStream is = context.getResourceAsStream("/WEB-INF/servletTest.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
3) 읽어온 자료를 구분자로 잘라 뽑아 낸다.
while((s=br.readLine()) !=null ){
StringTokenizer tk = new StringTokenizer(s, "&"); : token 대신 split("&")사용해도 됨
driver = tk.nextToken(); }
////////////////////////////////////////////////////////////////////////
파일로 저장된 변수를 가지고 오기.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;
protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
response.setContentType("text/html;charset=euc-kr");
PrintWriter out = response.getWriter();
ServletContext context = getServletContext();
InputStream is = context.getResourceAsStream("/WEB-INF/servletTest.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String s = null;
String driver = null;
String url = null;
String user = null;
String pass = null;
while((s = br.readLine()) != null){
StringTokenizer tk = new StringTokenizer(s, "&");
driver = tk.nextToken();
url = tk.nextToken();
user = tk.nextToken();
pass = tk.nextToken();
}
out.print("driver : " + driver + "<br>");
out.print("url : " + url + "<br>");
out.print("user : " + user + "<br>");
out.print("pass : " + pass + "<br>");
}
/WEB-INF/servletTest.txt 경로에 아래 내용의 servletText.txt 파일을 생성
oracle.jdbc.driver.OracleDriver&jdbc:oracle:thin:@localhost:1521:darkhi&java&java
&를 구분자로 하여 파일의 내용을 리드 받는다.
////////////////////////////////////////////////////////////////////////
** servletconfig
1. 서블릿 초기화시 필요한 정보를 컨테이너에서 제공받음
2. 서블릿마다 하나의 servletconfig가 생성
3. 구현 : initparameter(초기 파라미터)-한 servlet에서만 사용가능
1) web.xml에서 지정된 servlet안에
<init-param>
<param-name>aaaa</param-name>
<param-value>bbb</param-value>
</init-param>으로 설정
2) servlet 파일에서 값을 변수에 넣어 출력한다.
=>>컨테이너 안에 여러개의 context가 있고 그 안에 또 여러개의 servlet이 있음
4. 구현2 : context - 여러 servlet에서 가져와 사용할 수 있다.
1) web.xml에서 지정되지 않은 servlet 안에
<context-param>
<param-name></param-name>
<param-value></param-valude>
</context-param>
2) servlet 파일에 객체를 생성한 후 변수에 값을 넣어 출력
ServletContext context = getServletContext();
String driver = context.getInitParameter("driver");
5. 구현3 : 파일에서 가져올 때
1) web-inf안에 txt로 파일을 만듦
2) servlet파일에 객체 생성 후 txt파일로 저장된 경로를 가져와 뿌려준다.
ServletContext context = getServletContext();
InputStream is = context.getResourceAsStream("/WEB-INF/servletTest.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
3) 읽어온 자료를 구분자로 잘라 뽑아 낸다.
while((s=br.readLine()) !=null ){
StringTokenizer tk = new StringTokenizer(s, "&"); : token 대신 split("&")사용해도 됨
driver = tk.nextToken(); }
6. 구현4 : set/getAttribute로 servlet시킴
1) 첫번째 servlet파일 안에
ServletContext context = getServletContext();
context.setAttribute("name", "홍길동");
2) 두번째 servlet파일에
ServletContext context = getServletContext();
String name = (String)context.getAttribute("name");
<배열로 구현>
- Attribute servlet파일
ArrayList list = new ArrayList();
list.add("이순신");
list.add(new Integer(500)); // 숫자 넣는 것!!
context.setAttribute("data", list);
- Attribute1 serblet파일
ServletContext context = getServletContext();
ArrayList list = (ArrayList)context.getAttribute("data");
String name = (String)list.get(0);
int age = (Integer)list.get(1);
context.log("context에서 [이름 = " + name + " ] , [나이 = " + age + "]");
////////////////////////////////////////////////////////////////////////
context가 아닌 config별로 적용하기
web.xml 파일에 아래 내용 삽입
<servlet>
<description>
</description>
<display-name>
InitParamServlet</display-name>
<servlet-name>InitParamServlet</servlet-name>
<servlet-class>
servletTest.InitParamServlet</servlet-class>
<init-param>
<param-name>driver</param-name>
<param-value>oracle.jdbc.driver.OracleDriver</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>oracle:thin:@localhost:1521:darkhi</param-value>
</init-param>
<init-param>
<param-name>user</param-name>
<param-value>scott</param-value>
</init-param>
<init-param>
<param-name>pass</param-name>
<param-value>tiger</param-value>
</init-param>
</servlet>
로 사용
import java.io.PrintWriter;
response.setContentType("text/html;charset=euc-kr");
PrintWriter out = response.getWriter();
String driver = getInitParameter("driver");
String url = getInitParameter("url");
String user = getInitParameter("user");
String pass = getInitParameter("pass");
out.print("driver : "+driver +"<br>");
out.print("url : "+url +"<br>");
out.print("user : "+user +"<br>");
out.print("pass : "+pass +"<br>");
////////////////////////////////////////////////////////////////////////
모델 1(Model 1) vs 모델 2(Model 2)다
모델 1 : 웹브라우저의 요청을 받아들이고, 웹브라우저에 응답해주는 처리에 대해 JSP 페이지 단독으로 처리하는 구조.
View(JSP page)와 Controller가 결합되어 있고(응답요청 처리), Model(JavaBean)만 분리되어 있는 구조
장점 :
- 단순한 페이지 흐름으로 인해 개발 기간 단축
- MVC 구조에 대한 추가적인 교육이 필요 없고 개발팀의 팀원의 수준이 높지 않아도 됨
- 중소형 프로젝트에 적합
단점 :
- 웹 어플리케이션이 복잡해질수록 유지보수가 어렵다
- 디자이너와 개발자 간의 원활한 의사소통이 필요.(JSP 페이지 안의 디자인(그림, 플래시 링크 등)과 로직에 대하여 모두 감안)
모델 2 :
요청은 Controller(Servlet)가 받고 모델(JavaBean)과 데이터를 주고받으며, 응답은 Controller에서 View(JSP page)로 전달이 되어 웹브라우저로 처리된다.
장점 :
- business logic과 View의 분리로 어플리케이션이 명료해지며 유지 보수와 확장이 용이.
- 개발자와 디자이너의 작업이 분리되어져 역할과 책임 구분이 여확.
단점 :
- 개발 초기에 구조 설계를 위한 시간이 많이 소요(개발기간의 증가)
- MVC 구조에 대한 개발자들의 이해가 필요해서 개발팀의 팀원의 높은 수준을 요구
/////////////////////////////////////////////////////////////////////////
MVC 패턴
View - JSP 페이지 또는 서블릿(Servlet)
Model - 자바빈, 자바 객체 또는 EJB(Enterprise JAva Bean)의 entityBean
Controller - Servlet, JSP 페이지 또는 EJB의 sessionBean
(1) Controller : Servlet
01) 웹브라우저의 요청을 받음
doGet(), doPost() 메소드로 요청을 받음
02) 웹브라우저(클라이언트)가 요구하느 작업을 분석
String type = request.getParameter("type");
03) 요청한 작업을 처리하기 위해 비지니스 로직을 처리하는 모델(JavaBean) 사용
Object result = null;
if (type.equals("a"){
// a 요청 처리
}
else if (type.equals("b"){
// b 요청 처리
}
04) 처리 결과를 request 또는 session의 속성에 저장
request.setAttribute("result", result);
05) 적당한 뷰(JSP page)를 선택 후 해당 뷰로 포워딩
import javax.servlet.*;
RequestDispatcher dispatcher = request.getRequestDispatcher("a.jsp");
dispatcher.forward(request, response);
(2) 뷰(View) : JSP 페이지
비지니스 로직을 가지고 있지 않은 점을 제외하고는 일반적인 JSP 페이지.
dispacher.forward()로 request, response 객체를 공유한 후, request.getAttribute("result");를 사용하여 객체를 가지고 와 화면에 보여준다.
(3) 모델(Model) : 자바빈(JavaBean)
비지니스 로직(DAO, TO)의 처리를 요청받아서 DB와 연동된다.
01) 컨트롤러(Controller)의 요청을 받는다.
02) 비지니스 로직을 처리한다.
03) 처리한 비지니스 로직의 결과를 컨트롤러(Controller)로 반환한다.
/////////////////////////////////////////////////////////////////////////
쿠키(Cookie)
HTTP 프로토콜은 웹브라우저(클라이언트)의 요청에 대한 응답을 하고 나면 연결을 지속하지 않음(Connectionless)
import javax.servlet.http.*;
(1) 쿠키 생성 및 사용
// 쿠키 생성
Cookie cookie = new Cookie(String name, String value);
// response객체에 add 시켜야함
response.addCookie(name);
// 쿠키 이름에 대응하는 값을 새롭게 지정
cookie.setValue(newValue);
// 클라이언트의 요청과 함께 전달되어져 온 쿠키를 읽어 올 때는 request 객체의 etCookies() 메소드를 사용한다. 웹브라우저에 저장된 쿠키를 모두 읽어오기 때문에 리턴 타입이 Cookie[]이다.
Cookie[] Cookies = request.getCookies();
// 쿠키의 지속시간을 설정한다.
cookie.setMaxAge(int second);
/////////////////////////////////////////////////////////////////////////
세션
session.메소드
리턴타입 : 메소드 이름 : 설명
java.lang.Object : getAttribute(String name) : name이란 해당 값의 속성을 가지고 옴
java.util.Enumeration : getAttributeNames() : 속성의 이름들을 Enumeration 객체 타입으로 리턴
long : getCreationTime() : 1970년 1월 1일 자정을 기준으로 하여 현재 세션이 생성된 시간까지의 지난 시간을 계산하여 1/1000초로 리턴
String : getId() : 세션에 할당된 고유ID를 String 타입으로 리턴
int : getMaxInactioveInterval() : 현재 생성된 세션을 유지하기 위해 설정된 최대 시간을 정수형으로 리턴
void : invalidate() : 현재 생성된 세션을 무효화
void : removeAttribute(String name) : name으로 지정한 속성의 값을 제거
void : setAttribute(String name, Object value) : name으로 지정한 속성에 value를 저장
void : setMaxInactiveInterval(Int interval) : 세션의 최대 유지시간을 초 단위로 설정
기본 사용 예제
session.setAttribute("id", "asdfasdf");
String id = (String) session.getAttribute("id");
session.removeAttribute("id");
session.invalidate();
web.xml 파일에 아래와 같이 추가해 주면 분 단위로 전체설정 할수 있으며 페이지에 또는 web.xml 에 추가하지 않았을 경우에는 기본 30분 (1800초)이다.
<session-config>
<session-timeout>10</session-timeout>
</session-config>
/////////////////////////////////////////////////////////////////////////
Zakarta DBCP API를 이용한 Connection Pool 사용
데이터베이스를 연결하기 위한 Connection은 객체이다. 이 객체는 새롭게 만들어질 때 많은 시스템 자원이 요구된다.
커넥션 객체를 생성하고 관리하는 방법
(1) service method(doGet,doPost)에서 커넥션 객체를 생성
작성은 쉬우나, 많은 문제점이 존재.
이 경우 (요청)Request 당 한 개의 커넥션 객체를 생성하므로 시스템으 부하가 커지고 메모리가 낭비 된다.(Local variable)
(2) init method에서 커넥션 객체 생성
이 방법은 서비스 될 때 단 한번만 사용하는 init method에서 커넥션 객체를 생성한다.
connection 시간이 안 걸리나 하나의 커넥션을 사용하면 커넥션에 쿼리가 쌓이게 되어 응답 시간이 증가한다.(Member variable)
(3) 커넥션 풀에서 커넥션 객체 생성 및 관리하기
자원을 쓰고 회수하는 방법.
한번 만들어져서 사용된 커넥션 객체는 다시 커넥션 풀로 회수.
커넥션 생성의 개수를 결정할 수 있다.
설치 세팅
(1) 필요 파일 다운로드
commons.apache.org사이트에서 collections, dbcp, pool 다운로드
commons-collections-3.2.1.jar
commons-dbcp-1.2.2.jar
commons-pool-1.4.jar
파일을 C:\apache-tomcat\common\lib에 붙여넣기
(2)
WebContent\META-INF\context.xml 파일 생성 아래 내용 삽입
<Context>
<Resource name="jdbc/darkhi"
auth="Container"
driverClassName="oracle.jdbc.driver.OracleDriver"
type="javax.sql.DataSource"
loginTimeout="10"
maxWait="5000"
maxIdle="10"
username="java"
password="java"
maxActive="20"
url="jdbc:oracle:thin:@localhost:1521/darkhi"
/>
</Context>
WebContent\WEB-INF\web.xml 파일에 아래 내용 추가
<resource-ref>
<description>Connection</description>
<res-ref-name>jdbc/darkhi</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
사용 방법
<%@ page import="java.sql.*" %>
<%@ page import="javax.sql.*" %>
<%@ page import="javax.naming.*" %>
<%
DataSource ds = null;
Connection conn = null;
try{
Context init = new InitialContext();
//Context jce = (Context)init.lookup("java:comp/env");
//ds = (DataSource)jce.lookup("jdbc/orcl");
ds = (DataSource)init.lookup("java:comp/env/jdbc/darkhi");
conn = ds.getConnection();
/////////////////////////////////////////////////////////////////////////
파일 업로드
1. 입력 폼 만들기
<form action="이동페이지" method="post" enctype="multipart/form-data">
<input type="file" name="file1">
</form>
2. 매개변수 받기
// 서버 root에 해당하는 절대 경로를 구하여 ""된 주소를 덧여 스트링 형태로 리턴한다.
String filePath = request.getSession().getServletContext().getRealPath("/data/");
// 5메가 짜리 파일 용량 제한
int fileSize = 1024 * 1024 * 5;
String encoding = "utf-8";
// DefaultRenamePolicy()는 업로드하는 경로에 파일명이 존재할 시 업로드되는 파일 이름 뒤에 1,2,3과 같은 형식으로 rename 하는 형식
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;
MultipartRequest multi = new MultipartRequest(
request, filePath, fileSize, encoding, new DefaultFileRenamePolicy());
/////////////////////////////////////////////////////////////////////////
썸네일
1. JAI API 설치
http://java.sun.com/products/java-media/jai/downloads/download-1_1_2.html
또는 구글에서 Java Advanced Imaging 검색해서 Download 찾아서 JDK용으로 받는다.
설치 경로는 C:\Java\jre6\lib\ext에 설치가 되도록 한다.
jai_codec.jar와 jai_core.jar가 lib\ext에 설치가 되어 있는지 확인한다.
2. 썸네일 이미지 생성하기
import javax.media.jai.JAI;
RenderedOp im = JAI.create("fileolad", param);
/////////////////////////////////////////////////////////////////////////
JavaMail API 사용하기
http://java.sun.com/products/javamail/downloads/index.html
에서 다운로드 받는다
압축을 풀고 mail.jar 파일을 C:\Java\jre6\lib\ext에 붙여넣기 한다.
/////////////////////////////////////////////////////////////////////////
답글 구현(댓글 아님)
글13 asdf
글14 re : asf
글15 re : re
글12
글11
위와 같은 형식으로 만들기 위한 컬럼
reply_secret(답글의 작성 가능 여부)
ref(답글임을 표시하기 위한 컬럼)
ref_level(단계)
ref_step(답글의 순서)
reply.jsp
reply_ok.jsp를 생성하여
view에서 답글 쓰기 구현
리플 작성시에 ref_step(리플의 리플 작성시 대상 리플 step의 step+1하여 리플을 작성하여야 하므로
원래의 대상 리플의 다음에 모든 리플의 step은 +1씩 증가시키고, 리플 다음번에 삽입하는 형식을 취한다.
/////////////////////////////////////////////////////////////////////////
전체의 시간 정보를 간략하게 줄여서 출력
Java.util.Date date = null;
java.text.SimpleDateFormat sdate = new SimpleDateFormet("yyyy-MM-DD");
date = new Date(b.getReg_Date().getTime());
String strdate = sdate.format(date);
/////////////////////////////////////////////////////////////////////////
오라클 rownum 사용법
select rownum, num, id form TABLE;
부분 뽑기
select rownum, num, id
from(select rownum aa, num, id from boardreply)
where aa >= 3 and aa <=5;
반드시 서브쿼리안에서 별칭을 지정해주어야 그 밖의 where 절에서 인식이 가능하다.
/////////////////////////////////////////////////////////////////////////
zipcode 추가하는 방법 2
create table zipcode(
ZIPCODE varchar2(7),
SIDO varchar(4),
GUGUN varchar2(15),
DONG varchar2(26),
RI varchar2(45),
ST_BUNJI varchar(11),
ED_BUNJI varchar(9),
SEQ number
);
sqlplus java/java 접속
@c:\zipcode.sql
하게 되면 데이터가 한 라인씩 insert된다.
zipcode.sql에는
insert into zipcode values(머머머, 머머머, 머머머);
라는 라인이 몇만건이 존재한다.
/////////////////////////////////////////////////////////////////////////
struts 프레임워크 환경설정
struts.apache.org에서 struts 1.3.10을 다운로드 받음.
압축 풀어서 struts-blank-1.3.10.war, struts-examples-1.3.10.war 파일을 복사해서 C:\Tomcat_5.5\webapps 에 붙여넣기 하고 톰캣을 재시작하면 파일명과 동일한 폴더가 생성이 된다.
예제 페이지 접속하기
http://localhost:8090/struts-examples-1.3.10/으로 접속하면 example 페이지에 접속이 가능해진다.
이클립스에서 새로운 프로젝트를 생성하고 WEB-INF에서 web.xml 파일을 삭제하고 생성된 struts-blank-1.3.10 폴더안에서 web.xml과 struts-config.xml 파일을 import시킨다.
C:\Tomcat_5.5\webapps\struts-blank-1.3.10\WEB-INF\lib 안에 있는 라이브러리 파일들을 C:\Tomcat_5.5\common\lib에 붙여넣기하거나, 이클립스의 WEB-INF\lib에 import시킨다.

not as usual