티스토리 툴바


Development/Web2012/01/27 11:13

Form Study #1

kenu
2002-02-24 12:34오전

값을 넘겨주는 방식 중 많이 사용하는 3가지 방식을 논의하겠습니다. GET, POST 방식과 파일을 전송할 수 있는 multipart/form-data 에 관한 것입니다. 소스를 일단 보시죠.
formstudy.jsp
<html>
<head>
  <title>okjsp form study</title>
</head>
<body>
<%-- 입력 값을 처리하는 부분 --%>
<pre>
contentType: <%=request.getContentType()%>
contentLength: <%=request.getContentLength()%>
method: <%=request.getMethod()%>
get name: <%=request.getParameter("gname")%>
post name: <%=request.getParameter("pname")%>
mp name: <%=request.getParameter("mpname")%>
filename: <%=request.getParameter("filename")%>
</pre>
<%-- 값을 입력받는 부분 --%>
form1:
  <form method="get">
    name (get) <input type="text" name="gname">
    <br>
    <input type="submit" value="get">
  </form>
form2:
  <form method="post">
    name (post) <input type="text" name="pname">
    <br>
    <input type="submit" value="post">
  </form>
form3:
  <form method="post" enctype="multipart/form-data">
    name (multipart) <input type="text" name="mpname">
    <br>
    file <input type="file" name="filename">
    <br>
    <input type="submit" value="multipart">
  </form>
</body>
</html>

		


form 태그에 action 속성이 없다면 자기 자신을 다시 한 번 호출합니다. 즉 action="formstudy.jsp" 와 같은 결과입니다. 브라우저의 주소줄에 입력해서 서버에 요청할 경우 기본 method 는 GET 입니다. 

GET 방식의 경우 넘겨주는 값은 주소줄에 추가됩니다. 첫번째 입력창에 okjsp 라는 값을 입력한 후에 전송 버튼을 누르면 다음 화면은 다음과 같이 나오게 됩니다. 특징적인 것은 GET을 통한 값의 전달은 주소줄을 타고 전달이 됩니다. 따라서 서버마다 다르지만 대략 230바이트 이상의 값은 전달할 수 없게 됩니다. 때문에 비밀번호 같은 중요한 값들은 노출되기 쉽고, 항목이 많은 form 양식은 GET방식으로 처리하지 않을 수 밖에 없습니다. 

POST 방식은 값의 전달경로는 header 부분입니다. getContentLength() 메소드를 통해서 전달되는 값의 Byte 크기를 알 수 있습니다. 이 때 parameter 이름과 값이 = 을 사이에 두고, 항목과 항목은 & 로 구분된 문자열로 Header 를 통해서 전달이 됩니다. ^^ 주소줄에 GET 방식의 자국을 남긴채 POST 폼을 사용하면 주소줄의 파라메터도 전달이 됩니다. 두번째 입력창에 okjsppost 를 입력하고 전송하면 아래 그림과 같이 나옵니다. 

contentLength 가 15가 나왔습니다. 저 길이의 의미는 "pname=okjsppost"를 생각해보면 쉽게 이해가 갈 것입니다. getParameter("pname") 했을 경우 okjsppost 가 나오는 것은 다 아시겠죠. 그리고 contentType 이 application/x-www-form-urlencoded 인 것도 기억해두시기 바랍니다. 

form tag 에 enctype="multipart/form-data" 일 경우 전송에 대해서 살펴봅시다. 가장 많이 질문되는 것이 왜 파일은 업로드 되는데 request.getParameter() 로 변수값을 가져오지 못하는가 입니다. (이것 질문하는 사람 100명도 더 봤습니다. 이 문제 때문에 이 강좌를 쓴 것이기도 하죠. 일종의 FAQ 라고 할 수 있죠.) 일단 multi 라는 값만 넣어서 보내면 293~300 사이의 값이 나옵니다. 왜 이리 가변적인지는 아직 저도 더 찾아봐야할 것 같구요(저도 이거 분석은 처음입니다. ^^) "mpname=multi" 외에도 뭔가 다른 것이 280바이트 이상의 정보를 같이 보낸다는 것을 감을 잡으셔야 합니다. 쉽지는 않을 것 같죠? 그렇습니다. 쉽지 않습니다. 이 값을 분석해서 뽑아내야(parsing) 하는데 직접하게 된다면 골 아플 것입니다. 다행스럽게도 무료로 공개된 MultipartRequest 라던가 문제가 좀 있지만 기능이 좋은 jspsmartupload 와 개발자가 책을 구입해야 사용권한을 얻을 수 있는 jason hunter 의 O'reilly MultipartRequest 등이 있습니다. 국내 개발자들이 공개하는 자바의꿈 님의 NewTakeUpload 등도 있구요. 중복파일처리 메소드도 있다고 합니다. 이것들의 소스를 구해서 분석해보시는 것도 나쁘지 않겠죠. 

multipart 에 대해서는 다음에 더 집중분석해보도록 하고, 여기서는 request.getParameter() 그 이상의 뭔가가 있다는 것을 아는 것으로 만족하도록 하죠. 그럼 이 값을 받을 수 있는 방법을 간단히 소개하고 마치도록 하겠습니다. jason hunter 의 MultipartRequest 에서 업로드 객체(multi)를 생성하면서 업로드를 합니다. 이 MultipartRequest 클래스에는 request 에서 사용했던 메소드들을 그대로 사용할 수 있도록 지원합니다. 따라서 request 대신 객체명(multi) 을 사용해서 원하는 파라메터값을 뽑아낼 수 있습니다. 아래 소스를 보시죠. 제가 사용하는 소스 중의 일부입니다. filename 은 다른 방식으로 뽑아내는 것도 유심히 살펴보세요.
board_write2.jsp 파일 중
...
  MultipartRequest multi =
        new MultipartRequest(request, savePath, sizeLimit);

  Enumeration files = multi.getFileNames();

  while(files.hasMoreElements()) {
    fname = (String)files.nextElement();
    f = multi.getFile(fname);
    maskname[cnt] = ""+System.currentTimeMillis()+cnt;
    filename[cnt] = multi.getFilesystemName(fname);
    filesize[cnt] = 0;
    if (f != null) {
  		filesize[cnt] = f.length();
  		up1 = new File(savePath+"/"+filename[cnt]);
   		up2 = new File(savePath+"/"+maskname[cnt]);
   		if (up1.exists()) {
         boolean rslt = up1.renameTo(up2);
   		}
   	} // end if f != null
    cnt++;
  }
...

  String name    = Kr.nchk(multi.getParameter("mpname")    );
...


      


이번 강좌는 여기서 마치겠습니다. 저도 API 를 더 보면서 공부를 좀 더 한 다음에 multipart 에 대해서 더 깊은 내용의 강좌를 준비해보고 싶습니다.(^^; 언제 강좌가 써질지는 저도... 헤헤). Jason Hunter 의 자바 서블릿 프로그래밍 개정판(한빛미디어, 이창신 번역) 책에 자세한 내용이 있으니 참고하시기 바랍니다. 

관련 사이트
http://www.servlets.com/cos/ 
Jason Hunter 의 MultipartRequest 를 구할 수 있는 곳
http://iasandcb.hihome.com/cosi/ 
MultipartRequest의 국제화버전을 구할 수 있는 곳
http://aboutjsp.com/lec/multipart.htm 
MultipartRequest사용법 aboutjsp의 이선재님 강의
http://cafe.daum.net/DOJ 
Dream Of Java 님의 NewTakeUpload 를 구할 수 있는 곳
http://okjsp.pe.kr/heogn/lecture/lec05/fileup01.htm 
FileUpload 컴포넌트 소스와 예제
http://www.kimho.pe.kr/jsp/jsp_upload.html 
Jason Pell 의 MultipartRequest 에 대한 김호님의 강좌
xml-typed document
http://okjsp.pe.kr
Posted by 모노블럭

댓글을 달아 주세요

Database/Oracle2012/01/25 09:14

Case When 문의 의미
Case When문이나 Decode함수를 사용하여 Select절의 결과물을 원하는 대로 변경하는 SQL은 여러 번 본 적이 있다.
하지만 주변 사람들과 이야기해보면 의외로 Select절 뿐만 아니라 Where절, Order By절, Group By절 등에 다 사용할 수 있다는 사실을 모르는 경우가 있었는데 오늘은 이런 사실에 대해 이야기해보고자 한다.

Case When문의 활용범위는 무궁무진하며, 이 것을 사용하지 않고 Static한 SQL을 사용한다는 것이 필자로서는 거의 불가능하게 느껴진다. 앞으로의 포스트에서도 줄기차게 사용할 것이므로 관심이 있으신 분들은 여러 활용방법을 제대로 알아두면 좋을 것 같다.


Case When문
간단하게는 Case When문은 Decode함수의 확장이다.
Decode함수는 Oracle에서 제공되는 SQL 내의 if/else의 조건문 역할을 하는 함수이나 = 연산만 가능하다. Case When문은 이를 확장한 것이며, 논리연산, 산술연산, 관계 연산을 다 지원하며 Oracle 뿐만 아니라 MS-SQL에서도 지원한다.
(예전에 듣기로는 My-SQL에서도 지원한다고 들은 적이 있다. Test해보지는 않았지만.)
복잡한 조건일 수록 Case When문은 Decode문에 비해 가독성이 높고, 수행속도도 빠르다고 할 수 있겠다.

사용하는 문법은 다음과 같다.
  • case when [조건1] then [결과1] when [조건2] then?[결과2] ...else [결과3] end
  • case [컬럼1] when [값1] then [결과1] when [값2] then [결과2] …  else [결과 3] end


Select 절에서의 활용
실제로 가장 많이 사용되는 활용은 Select절에서일 것이다. 실제 우리가 가지고 있는 Data로부터 우리가 원한 Data를 뽑아내는데 자주 사용된다.

Select (Case When name = ‘서울’ Then ‘수도권’  When name = ‘경기도’ Then ‘수도권’ Else ‘비수도권’ End) city_group, name From City

이 SQL은 당연히 다음과 같이도 사용가능하다.

Select (Case name When ‘서울’ Then ‘수도권’ When ‘경기도’ Then ‘수도권’ Else ‘비수도권’ End) city_group, name From City


지역이라는 Column이 없기 때문에 수도권인지 아닌지를 가져오기 위해 위와 같은 SQL을 사용하였다.
(왜 수도권에 '인천'은 없는지에 대해서 궁금해하는 사람은 없기 바란다. PT하다보면 가끔 그런 사람을 만날 수 있는데 정말 한숨만 나온다-_- 집중해야 할 곳에 집중하자.)


Group By 절에서의 활용
사례를 살펴보기 위해서 Cartesian Product(카테시안 곱) 항목에서 예로 들었던 SQL을 다시 가져와 보자.

Select (Case tbl2.no1 When 1 Then tbl1.품목 Else ‘합계’ End), Sum(수량)
From Table1 tbl1, (Select 1 no1 From dual Union All Select 2 From dual) tbl2
Group By (Case tbl2.no1 When 1 Then tbl1.품목 Else ‘합계’ End), tbl2.no1

복제된 Data에서 no1이 1인 것은 품목으로 Group by를 하였고, 2인 것은 "합계" 즉 상수로 Group by를 하였다. 따라서, 1인 경우는 품목별로 합계를 구하게 되고, 나머지 항목들은 전체 Group by가 되게 될 것이다.


Order By 절에서의 활용
회사 직원을 이름 순으로 뽑아오는 쿼리가 있다고 하자. 어느 날 직원 시스템을 한 번도 써보지 않았던 사장님이 시스템에 들어가보니 본인 이름이 중간에 있는 것을 발견하고 명색이 사장님인데 직원들 순서 중에서 내가 제일 앞에 나와야 하지 않는가 하는 의문을 제기하였다.

그런-_- 이유로 고쳐야할 시스템의 요구사항은 다음과 같다.
사장님의 이름만 맨 앞으로 뽑아내고 나머지는 가나다 순으로 정렬하면 되는 것이다. 물론 일단 Data를 Client로 다 가져온 다음 프로그램 상에서 처리할 수도 있겠으나, 나중에 이 사실을 알게 된 이사님도 이의를 제기한다면? 다른 관리자들은? 이런 요구사항들을 다 Client에서 처리한다면 프로그램은 갈수록 복잡해지게 될 것이다.

따라서, 그런 요구사항의 변경은 SQL에서 적용하는 것이 가장 간단할 것이며, 이 것이 우리가 추구하고자 하는 Static SQL의 본질이다. (Static SQL이란 원하는 집합을 하나의 SQL로 뽑아내는 것을 말하며 이 문제영역에서는 사장님이 맨 앞에 나오고 다른 직원들은 이름순으로 정렬된 집합이 우리가 원하는 집합이다. 따라서, 그것을 하나의 SQL로 얻어와야 한다.)

Order by절에서는 오름차순이건, 내림차순이건 사장님의 이름만 맨 앞으로 뽑아올 수 없으나, Case When문을 사용하면 간단하다.

Select 이름
From Emp
Order By (Case When 직함 = '사장' Then 1 Else 2 End), 이름


Where절에서의 활용
외부에서 들어온 조건(:v1)에 따라 서로 다른 동작을 정의하고자 할 때 사용할 수 있다.
Select 이름
From Emp
Where (Case When Length(:v1) = 0 Then 1 Else Instr(이름, :v1) End) > 0

검색할 이름에 대한 입력이 :v1에 들어오면 이름을 검색하여 결과를 보여주고 입력이 없으면 전체 직원의 이름을 Return하는 SQL이다. Where절을 동적으로 조합하지 않고 SQL 내부에서도 이러한 방법을 통해 서로 다른 결과값을 Return할 수 있다.


결론
SQL을 작성하는 여러가지 방법을 배우는 것은 문제에 따라 다양한 Idea를 내기 위한 필요조건이다. Client에서 혹은 PL/SQL에서의 if/else를 상당부분 SQL로 옮겨올 수 있는 Case When문을 익혀두는 것은 그 중에서도 첫 걸음이 될 수 있을 것이다.

자료출처 : http://rtti.tistory.com/8

Posted by 모노블럭

댓글을 달아 주세요

Database2012/01/17 09:26

 

 

*DECODE와 CASE구문은 조건에 값을 비교하여 해당하는 조건에 알맞은 값을 반환한다는 점에서는 같지만,
DECODE의 경우 EQUAL 비교밖에 할 수 없지만, 조건문이 비교적 간단하다는 장점이 있다.
그에 비해, CASE는 RANGE 비교가 가능하다는 장점이 있지만, 조건문이 길어진다는 단점이 있다.

*사용예
 1. 사원의 성별이 남자라면 '남', 여자라면 '여'를 반환하라.
 -> SELECT DECODE(성별, '남', '남', '여') FROM DUAL

2. 점수별 구분
-> SELECT
    CASE
     WHEN SCORE >= 100 AND SCORE <90 THEN 'EXCELLENT'
     WHEN SCORE >= 90 AND SCORE <80 THEN 'VERY GOOD'
     WHEN SCORE >= 80 THEN 'GOOD'
    END AS COMMENT



DECODE() : 간단하게 데이터를 변형 시킬 때 OR
데이터를 확인 할 때 주로 사용하는 함수.
함수,EQUERS

CASE : 표현식 , 범위에대한 판단

'Database' 카테고리의 다른 글

DECODE와 CASE  (0) 2012/01/17
[DB] PARTITION BY 구문  (0) 2011/10/05
Posted by 모노블럭

댓글을 달아 주세요