2012-10-31

java Framework/Linux 에서 APM(apache2.0.48)+tomcat(5.0.16) 연동하기(mod_jk2)



[펌] Linux 에서 APM(apache2.0.48)+tomcat(5.0.16) 연동하기(mod_jk2) | Unix/Linux2005/03/23 01:10
 
http://blog.naver.com/mickey109/60011163411
출처블로그 : mWorld - ccm 짜집기 java/apache/linux/php/mysql/

Linux 에서 APM(apache2.0.48)+tomcat(5.0.16) 연동하기(mod_jk2)

TOC ( Table of Content )
0.overview
1.mysql 설치
2.apache (2.0.48) 설치
3.php 설치
4.APM 연동
5.zend optimizer 설치
6.jdk의 설치
7.tomcat (5.0.16)설치
8.jk2( jakarta-tomcat connector ) 설치
9.apache 와 tomcat의 연동
10.사용자 계정에서 jsp 사용 가능하도록 context listener 추가하기
epilog
0.OverView
-- 이 글의 목적은 apache2.x.x 버전과 tocmat5.x.x 버전의 연동을 주
목적으로 하여 작성된 글이다. 따라서 APM 연동보다는 아파치 톰캣 연동에
그 비중을 두고 있으며, 이 글을 읽는 사람들은 어느정도 linux에 대한 지
식(프로그램 설치시 rpm 설치가 아닌 소스 컴파일 설치) 을 갖추었다고
가정하고 글을 진행하도록 한다.
(주1. 본 문서는 각종 사이트를 돌아다니며 읽은 글들의 조합으로 이루어져
있습니다.. 최대한 출처를 밝히겠지만 미처 밝히지 못하는 부분에 대해 원저자분
들께 대해 죄송스럽게 생각합니다.)
(주2. 존칭은 생략하도록 하겠습니다. (--) (__) )
(주3. 소스를 컴파일 하여 프로그램을 설치 하는 것이나 apache와 tomcat의 연동은
버전과 시스템에 따라 다를 수 있습니다. 따라서 이 문서를 보고 따라 하신 후의 책임은
지지 않습니다.)
APM 연동은 다음 site를 참조한다
 http://ho.dunggi.net/study_linux ( apache1.xx apache2.xx 버전에 대한 연동이 모두 나옵니다.)
1.mysql 설치
-- http://www.mysql.com 사이트에서 mysql을 다운 받는다. 안정된 버전일 경우 최신 버전을 다운 받는다.
-- 받은소스를 /usr/local/src 로 이동한다.(소스의 위치는 각자 편한곳으로 한다.)
-- 기존에  rpm으로 mysql이 설치 되 있었다면 삭제한다.

 ( rpm -qa | grpe mysql 하면 rpm으로 설치된 mysql을 확인 할 수 있고, rpm -e --nodeps mysql.xxx 하면
 삭제가 가능하다.)
-- tar xvzf mysql.xxx.tar.gz 명령으로 소스를 푼다. (xxx 는 버전을 뜻합니다.)
-- mysql.xx.xx 라는 디렉토리가 생성된다.
-- 생성된 디렉토리로 이동하여
 ./configure --prefix=/usr/local/mysql --localstatedir=/usr/local/mysql/data --with-charset=euc_kr
 라는 명령으로 mysql소스를 configuration 한다.
 (--prefix는 mysql이 생성될 디렉토리, localstatedir은 mysql의 data가 위치할 경로, charset은 한글 사용을
 위한 옵션이다. 자세한 사항은 ./configure --help 명령을 통해 확인한다.
 에러가 없다면

 make

 make install

 명령을 통해 mysql을 설치완료 한다.
 여기 까지 에러가 없다면 /usr/local/mysql 이란 디렉토리가 생성되고 그 안에 mysql 실행을 위한 명령어
 들과 library가 생겨난다. ( mysql 설치 완료  하지만 끝이 아니다!!)
-- /usr/local/mysql/bin 으로 이동한다.
 ./mysql_install_db
 라는 명령어를 실행시켜준다.(주의! 이 명령어는 한번만 실행시킨다. 여러번 실행시킬 경우 에러가 발생할 수 있다.)
-- /usr/local/mysql/share/mysql 로 이동하면 mysql.server 라는 쉘 스크립트를 볼 수 있다.
 ./mysql.server start

 라는 명렁을 통해 mysql을 실행시킨다. /usr/local/mysql/bin 으로 이동하여 mysql 명령어를 치면 mysql에
 접속할 수 있다. 어느곳에서든지 mysql 명령어를 수행시키길 원한다면 /etc/profile 의 PATH에 추가해 주면 된다.
-- 시스템 부팅과 동시에 mysql을 수행시키고자 할 경우 /etc/rc.d/init.d 디렉토리로 이동하여
 ln -s /usr/local/mysql/share/mysql/mysql.server myslqd
 라는 명령어를 통해 링크를 걸고 자신의 run level을 확인하여 해당 run level 디렉토리로 이동하여
 (run level이 3이라면 /etc/rc.d/rc3.d  , run level이 5라면 /etc/rc.d/rc5.d )
 ln -s /etc/rc.d/init.d/mysqld S80mysqld
 라는 링크를 걸어주면 시스템의 시작과 동시에 mysql서버를 구동시킬 수 있다.
 ( 해당 디렉토리로 이동하면 SxxXXX 와 KxxXXX 라는 많은 파일들이 있을 것이다. S는 시스템이 시작할 때
 수행될 명령들이고 K는 시스템이 종료될 때 수행될 명령들이다. 따라서 SxxXXX라는 명령으로 링크를 건다
 S뒤의 숫자는 기존에 있던 것들과 겹치지 않는 수로 S99local 보단 작게 한다
 자신의 run level 확인은 /etc/inittab 파일을 열어 보면 id:x:initdefault: 라는 문장을 찾을 수 있다.
 여기서 x에 해당하는 숫자가 해당 시스템의 default run level이다. 보통 3 또는 5로 지정되는데
 3이 일반적인 콘솔로 부팅시에 사용되고, 5는 X-window로 부팅될때 사용된다. 그 외의 run-level에 관한 사항은
 각자 공부하길 바란다. -- 솔직히 필자도 잘 모른다. --;;;)
-- 이로써 mysql 설치는 완료된다.

2.apache2의 설치
-- 기존에 rpm package로 설치된 아파치를 삭제한다.(mysql의 삭제와 동일)
-- http://httpd.apache.org/download.cig  httpd-2.0.48.tar.gz 을 다운받는다.
-- 소스를 /usr/local/src 로 이동한후 tar 명령을 통해압축을 푼다.
-- 소스 디렉토리로 이동한 후

 ./configure --prefix=/usr/local/apache2 --enable-rule=SHARED_CORE --enable-shared=max --enable-so --enable-module=so
 명령을 통해 configuration. (./cofigure --help를 통해 각 옵션을 확인하는 것도 좋습니다. ^^)
 make
 make install 하여 아파치를 설치한다.
-- /usr/local/apache2/bin 디렉토리로 이동하여
 ./apachectl start
 명령을 통해 아파치를 실행시킨다. 브라우저로 해당 URL에 접속하여 에러가 없다면 아파치 설치 성공!
3.php의 설치
-- 기존의 rpm package 제거
-- http://www.php.net/downloads.php 에서 php4.3.4.tar.gz을 다운 받는다.
-- /usr/local/src로 소스 이동 후 tar로 압축을 푼다.
-- 소스 디렉토리로 이동하며
 ./configure --prefix=/usr/local/php --with-apxs2=/usr/local/apache2/bin/apxs --with-apache-install=/usr/local/src/httpd-2.0.48 --with-mysql=/usr/local/mysql --with-config-file-path=/usr/local/apache2/conf --with-zlib-dir=/usr/lib --with-zlib --enable-track-vars=yes --enable-modules=so --disable-debug --enable-mbstring
 명령을 통해 configuration. --with-apache-install 옵션뒤의 디렉토리는 아파치 소스 디렉토리(각자 자신이 압축을
 해제한 디렉토리로 명시한다.(이 문서를 따라 했다면 /usr/local/src/httpd-2.0.48) --with-mysql옵션뒤의 경로는 mysql

 이 설치된 디렉토리(/usr/local/mysql)를 기술한다. 옵션이 많아서 그런지 시간이 조금 걸린다.)
 에러가 없다면
 make
 make install
-- php의 소스 디렉토리로 이동하여(/usr/local/src/php4.3.4)
 cp php.ini-dist /usr/local/apache2/conf/php.ini
 명령을 수행한다.
-- php의 설치가 완료
4. apache와 php의 연동
-- /usr/local/apache2/modules 디렉토리로 이동해 보면 libphp4.so 란 파일이 있을 것이다. 없다면 위의 과정을 천천히
 다시 수행한다 --;;
-- /usr/local/apache2/conf 에 httpd.conf 파일을 열어보면 220라인 근처에
 LoadModule  php4_module     modules/libphp4.so
 라는 문장이 있을 것이다.
 DirectoryIndex 를 찾아 index.php를 추가 시킨다.
 (ex. DirectoryIndex index.html index.php index.htm )
 그리고 880라인 근처에 보면 AddType 이란 것이 있을 것이다. 그곳에
 AddType application/x-httpd-php .php
 AddType application/x-httpd-php-source .phps
 라는 두 문장을 추가 시켜준다.
-- /usr/local/apache2/bin 으로 이동한 후
 ./apachectl start ( 이미 구동중이라면 ./apachectl restart)
 한 후
 test.php 라는 파일을 아래와 같이  작성하고
 <?
  phpinfo();
 ?>
 브라우저로 읽어서 php 설정 정보에 대한 테이블이 나오면 APM 연동은 성공!!
 만일 소스코드가 그대로 보이거나 다운로드가 되면 연동에 실패한 것이다.
# 이하의 부분은 http://kltp.kldp.org/stories.php?topic=14 의 예크디엠님 글을 참조한다.
5.Zend optimizer의 설치  (옵션. 필수사항은 아니다. Zend는 php 가속기이다.)
-- http://zend.com/store/free_download.php?pid=13 에서 리눅스용 소스파일을 다운로드 받는다.
-- /usr/local/src/로 이동후 tar로 압축 해제
-- 소스 디렉토리로 이동하여
 ./install.sh
 를 수행하면 GUI 인터페이스의 설치 환경이 나타난다. apache의 설치 경로등을 묻는데 정확히
 기입하도록 한다. 설치는 /usr/local/Zend 디렉토리로 자동으로 이루어 진다.
 설치가 이루어 지면 /usr/local/apache2/conf/php.ini 파일은 php.ini-zend_optimizer.bak 으로 변경되고

 php.ini 파일이 /usr/local/Zend/etc 안에 생성되며 /usr/local/apache2/conf 디렉토리 안에는

 /usr/local/Zend/etc/php.ini 의 symbolic link 파일이 만들어져 실제 php.ini 파일과 연결됩니다.
-- Zend optimizer 설치 완료
6.jdk의 설치
-- http://java.sun.com/webapps/download/DisplayLinks 에서 j2sdk-1_4_2-nb-3_5_1-bin-linux 를 다운 받는다.
 (확장자가 tar.gz 이 아니라고 당황하지 말자. 필자는 솔직히 당황했었다 --;;)
-- 소스를 /usr/local로 이동시킨다.
 sh j2sdk-1_4_2-nb-3_5_1-bin-linux.bin
 명령어를 수행한다.
 ( chmod 755  j2sdk-1_4_2-nb-3_5_1-bin-linux.bin 명령후  ./j2sdk-1_4_2-nb-3_5_1-bin-linux.bin 도 가능할 것 같다.)
-- /usr/local/j2sdk-1_4_2 라는 디렉토리가 생겼을 것이다. (확실치는 않다. --;; 비슷한게 생겼을 것이다.)
-- 편의를 위해 /usr/local 디렉토리에서
 ln -s /usr/local/j2sdk-1_4_2  java
 라는 링크를 걸어준다
-- /etc/profile의 PATH에 /usr/local/java/bin 을 추가해 놓으면 어디서든지 java명령이 수행가능!
--jdk 설치 완료
7.tomcat의 설치
-- java가(jdk) 미리 설치 되어 있어야 한다.
-- http://jakarta.apache.org/site/binindex.cgi 에서
 jakarta-tomcat-5.0.16.tar.gz을 다운 받는다.
-- 해당 소스를 /usr/local 로 이동한 후 tar로 압축을 해제한다.
-- 톰캣은 컴파일없이 압축만 해제하면 바로 실행가능 상태가 된다.
-- 편의를 위해  /usr/local 디렉토리에서
 ln -s /usr/local/jakarta-tomcat-5.0.16 tomcat
 명령을 통해 링크를 걸어 놓는다.
-- /usr/local/tomcat/bin 으로 이동하여
 ./catalina start
 명령을 수행한다.
 JAVA_HOME=/usr/local/java
 CATALINA_HOME=...
 ...
 ..
 이렇게 4줄이 뜨면 성공이다. 혹시 에러가 나면서
 JAVA_HOME이 정의 되지 않았다는 메시지가 출력될 경우
 /etc/profile 을 열고
 JAVA_HOME=/usr/local/java
 라는 문장을 추가 시키고 저장한 뒤
 source profile
 이라는 명령을 수행한 후 tomcat을 가동시킨다.
 에러 없이 톰캣이 뜨면
 http://xxx.xxx.xxx.xxx:8080 으로 접속하여
 고양이 그림을 볼 수 있다면 톰캣 설치에 성공한 것이다.
-- tomcat 설치 완료
8.jk2 설치
-- http://jakarta.apache.org/site/sourceindex.cgi 에서 jakarta-tomcat-connectors-jk2-src-current.tar.gz 다운
-- /usr/local에서 tar 명령을 통해 압축을 해제한다.
-- /usr/local/jakarta-tomcat-connectors-jk2-src-current/jk/native2 로 이동한다.(정확치는 않다. 아무튼 native2 디렉
 토리로 이동한다. -- 제가 작업한 머신에서 글을 작성하는게 아님을 이해해 주십시요)
-- 해당 디렉토리에서
 ./configure --with-apxs2=/usr/local/apache2/bin/apxs
 를 수행한다.(주. apxs는 perl 스크립트 입니다 perl 5.0 이상이 해당 머신에 설치되어 있어야 합니다.)
 make
 를 하면  /usr/local/jakarta-tomcat-connectors-jk2-src-current/jk/build/jk2 /apache2 디렉토리에
 mod_jk2.so 파일이 생성된다. 만일 없다면 .... 이땐 정말 에러다 --;;
 만일 mod_jk2.so 파일이 존재하지 않는다면 jk2 설치부터 make 까지의 과정을 다시 해본다.
 ( 이 부분에서 막혀서 3일간 고생했습니다. mod_jk2.so 파일이 생성이 안되서... 결국 make를 통해 mod_jk2.so 생성은
 포기를 하고 꽁수를 썼습니다. 이 부분이 하이라이트!!)
 만일 재시도 했는데도 생기지 않는다면 ...
 (저의 경우 libtool --mode=install ... 하면서 warning이 뜨더군요. 예크디엠님의 글을 보고 추측하건데
 jk2가 컴파일 되면서 libtool을 찾는 과정에서 문제가 생기는 듯합니다.)
 해당 디렉토리에 mod_jk2.xx 라는 많은 파일들이 존재할 것이다. 여기서
 gcc -shared -o mod_jk2.so *.o
 라는 명령을 통해 강제 컴파일 하여 공용 모듈을 생성해낸다.!!!!
 cp mod_jk2.so /usr/local/apache2/modules
 명령을 통해 아파치 모듈 디렉토리로 복사한다.
9. apache와 tomcat의 연동
-- /usr/local/apache2/conf/httpd.cnof 파일을 열어
 DirectoryIndex를 찾아 index.jsp를 추가한다.
 ( ex) DirectoryIndex index.html index.php index.jsp )
 LoadModule  jk2_module  modules/mod_jk2.so
 를 추가한 후 저장하고 /usr/local/apache2/bin 디렉토리로 이동하여
 ./apachectl configtest
 를 수행하여 Syntax Ok 가 뜨면 OK!!
-- /usr/local/src/jakarta-tomcat-connectors-jk2-2.0.2-src/jk/conf/workers2.properties 파일을 /usr/local/apache2/conf/workers2.properties.bak
 
 으로 복사한다.
-- 편집기로 worker2.properties 파일을 만들고 다음과 같이 편집한다.
 # Shared memory handling. Needs to be set.
 [shm]
 file=/var/log/httpd/shm.file
 size=1048576
 # Example socket channel, explicitly set port and host.
 [channel.socket:localhost:8009]
 port=8009
 host=127.0.0.1
 # define the worker
 [ajp13:localhost:8009]
 channel=channel.socket:localhost:8009
 # Announce a "status" worker
 [status:status]
 # Uri mapping
 [uri:/jsp-examples/*]
 worker=ajp13:localhost:8009
 [uri:/servlets-examples/*]
 worker=ajp13:localhost:8009
 [uri:/tomcat-docs/*]
 worker=ajp13:localhost:8009
 [uri:/*]
 worker=ajp13:localhost:8009
 [uri:/status/*]
 worker=status:status
 ( worker2.properties.bak 파일은 나중에 공부하기 위해 복사해
 놓은 것입니다. 위의 내용만 있어도 연동에는 충분합니다.)
 위의 내용을 대~~충 분석(??)해 보면 (솔직히 잘 모른다. --;;)
 shm 부분은 공유 메모리를 위한 설정이고, channel은 연동시 사용할 port와 host를 설정한다.
 당연히 80포트로 들어온 놈들은 다른 곳이 아닌 자기자신(127.0.0.1 -- loopback)에게 8009번
 포트를 이용하여 tomcat에게 넘긴다는 얘기 같다. (확신은 없다. --;;)
 uri 부분은 context mapping 관련이다. 가장 주목할 것은 [uri:/*] 해당 URL로 들어오는 모든(*)
 것들을 8009번 포트로 tomcat에게 넘긴다. 이는 나중에 보충 설명한다.
 마찬가지로 나머지 uri 부분은 해당 URL로 /jsp-examples 라는 context(??)들 달고 오는 모든(*) 것들을
 tomcat에게 넘긴다는 것이다.
 status는 jk-connector의 설정 보여준다.
 연동뒤에 http://xxx.xxx.xxx.xxx/status 하면 설정상황을  볼 수 있다.
-- /usr/local/tomcat/conf/jk2.properties 파일을 다음과 같이 수정.
 ## THIS FILE MAY BE OVERRIDEN AT RUNTIME. MAKE SURE TOMCAT IS STOPED
 ## WHEN YOU EDIT THE FILE.
 ## COMMENTS WILL BE _LOST_
 ## DOCUMENTATION OF THE FORMAT IN JkMain javadoc.
 # Set the desired handler list
 # handler.list=apr,request,channelJni
 #
 # Override the default port for the socketChannel
 channelSocket.port=8009
 # Default:
 # channelUnix.file=${jkHome}/work/jk2.socket
 # Just to check if the the config is working
 # shm.file=${jkHome}/work/jk2.shm
 shm.file=/var/log/httpd/jk2.shm
 # In order to enable jni use any channelJni directive
 # channelJni.disabled = 0
 # And one of the following directives:
 # apr.jniModeSo=/opt/apache2/modules/mod_jk2.so
 # If set to inprocess the mod_jk2 will Register natives itself
 # This will enable the starting of the Tomcat from mod_jk2
 apr.jniModeSo=inprocess

-- 이로써 모든 설정은 완료 됩니다.
-- 톰캣과 아파치가 구동중이라면 각각 해당 디렉토리의 /bin 으로 이동
 하여
 ./catalina.sh stop
 ./apachectl stop
 명령을 통해 중지 시킨다.
-- 이제 연동이 됐는지 확인.
 톰캣을 먼저 띄우고 다음에 아파치를 띄운다.
 ./catalina.sh start
 ./apachectl start
-- 브라우저로 해당 URL에 접속하여

 http://xxx.xxx.xxx.xxx/
 에 접속한다. 톰캣 메인 화면이 뜨면 OK!
 http://xxx.xxx.xxx.xxx/jsp-examples
 에 접속하여 각각의 jsp 예제파일들이 문제 없이 수행되면 OK!

-- 접속을 하면 아파치의 DocumentRoot가 아닌 tomcat main page 가 뜨는것에 의아해 하는 분들도 계실지
 모른다.(사실은 내가 그랬다 --;;) 그 이유인 즉은..
 worker2.properties 파일에서 [uri] 설정에
 [uri:/*]
 worker=ajp13:localhost:8009
 이 부분 때문이다. 즉 해당 URL로 들어오는 모든(*) 것들에 대해 톰캣에게 넘겨 주는 것이다.
 아파치의 직무 유기다. --;;
 jsp 파일만을 tomcat에게 넘기기위해서는
 저 부분을
 [uri:/*.jsp]
 worker=ajp13:localhost:8009

 라고 수정하면 된다. 하지만 필자가 저렇게 했을 때 숱한 403 에러를 만났다. --;;
  저렇게 설정을 하고 나서 브라우저로 보면 아파치의 DocumentRoot로 창이 열린다.
 문제는 DocumentRoot 밑에 test.jsp를 수행하면 tomcat으로 가지 못한다는 것이다.
 신기하게도 http://xxx.xxx.xxx.xxx/jsp-examples 하면 이것은 또 잘 열린다. --;;
 아무튼.. 저걸 해결하고자 기껏 필자가 생각해 낸것은
 아파치의 DocumentRoot와 tomcat의 ROOT를 같은 곳으로 설정 하는 방법이다.
 /usr/local/tomat/conf/server.xml 을 열어보면
 <!-- Tomcat Root Context -->
 <Context path="" docBase="ROOT" debug="0"/>
 라는 부분이 있다.
 이부분을 다음과 같이 수정한다.
 <Context path="" docBase="/usr/local/apache2/htdocs" debug="0" reloadable="true"/>
 물론 "/usr/local/apache2/htdocs" 는 각자 자신의 시스템의 DocumentRoot로 설정 하면 될 것이다.
 이렇게 설정을 하고 톰캣을 다시 띄우고, 아파치를 다시 띄우니..

 드디어 아파치의 DocumentRoot 밑에 있는 jsp 파일을 인식했다!!
 즉 , http://xxx.xxx.xxx.xxx/test.jsp 가 열리는 것이다.
 물론 깔끔한 방법은 아니다.!! tomcat의 context 추가에 대한 지식이 부족하여 저렇게 한 것이다.
 http://www.apache-korea.org/tomcat/tomcat-5.0-doc/config/context.html (영문)
 http://jakarta.apache-korea.org/tomcat/tomcat-4.1-doc/config/context.html (한글)
 ( 관심 있는 분들은 위 사이트에 접속하여 context에 관한 부분을 더 공부 하시길 바랍니다.)
 이로써 아파치와 톰캣의 연동은 성공!! 한 것이다.
10. 사용자 계정에서 jsp 사용하기
 http://jakarta.apache-korea.org/tomcat/tomcat-4.1-doc/config/host.html#User%20Web%20Applications
 위 사이트를 참조 하세요
-- 위처럼 연동이 됐다고 해서
 http://xxx.xxx.xxx.xxx/~xxx/test.jsp
 라고 했을 때 jsp 파일을 톰캣이 처리해 주지는 못한다.
 tomcat의 server.xml 파일에 Listener를 등록해 주어야 한다.
 /usr/local/tomcat/conf/server.xml 파일을 열고
 <Host name="localhost" ...> 이 부분을 찾아 아래에 다음과 같이 추가한다.
 <Listener className="org.apache.catalina.startup.UserConfig" directoryName="public_html"

 userClass="org.apache.catalina.startup.PasswdUserDatabase"/>
 이것은 linux 시스템의 경우 /etc/passwd 파일을 사용한다고 한다. 정확히 어떻게 동작하는 것은
 필자도 이해하지못했다. 다만 이렇게 설정을 한후 ,톰캣과 아파치를재시동하고
 http://xxx.xxx.xxx.xxx/~xxx/test.jsp
 를 열어보면 드디어 감격적인 jsp page를 볼 수 있다.!!

ps.  tip아닌 tip을 말씀드리면 ..모두 아실거라 생각됩니다만... 소스 다운 받으실 때
일일이 ftp로 넘기지 마시고 리눅스 console 상에서 wget을 통해 받으면 쉽습니다.
링크가 걸린 다운로드 파일에서 마우스 오른쪽 버튼 클릭하셔서 등록정보 를 클릭하시면
주소가 나옵니다 이걸복사해서
 wget http://http://mirror.apache.or.kr/httpd/httpd-2.0.48.tar.Z
 이런식으로 직접 콘솔에서 다운받으실 수 있습니다.

아파치와 톰캣의 연동후 실행 순서는 톰캣 먼저 띄운후에 아파치를 띄우게 됩니다. 이걸 리눅스
시스템 부팅과 동시에 하려면 mysql 을 하셨던것 처럼  /etc/rc.d/init.d로 이동하신 후
 아파치)
 cd /etc/rc.d/init.d
 ln -s /usr/local/apache2/bin/apachectl httpd
 run level 디렉토리로 이동 후 (/etc/rc.d/rc3.d --run level 3인 경우)

 ln -s /etc/rc.d/init.d/httpd S75httpd

 톰캣)
 cd /etc/rc.d/init.d
 ln -s /usr/local/tomcat/bin/catalina.sh tomcatd
 cd /etc/rc.d/rc3.d (run level 디렉토리)
 ln -s /etc/rc.d/init.d/tomcatd S72tomcatd
 이렇게 설정해 주시면 됩니다. 단! 톰캣의 숫자가 아파치의 숫자보다 작아야 겠지요. 그래야 부팅시
 톰캣이 먼저 구동됩니다. 다른 것들과 겹치지 않는 수중 자유롭게 쓰시면 됩니다.
 한가지 주의 하실 점은 리붓을 했는데 아파치는 뜨고 톰캣은 뜨지 않는 경우가 있습니다.
 이럴땐 /var/log/message 파일을 열어 에러 메시지를 확인하시기 바랍니다.
 저의 경우 JAVA_HOME을 못 찾아서 계속 뜨지 못하더군요 그래서
 /etc/rc.d/init.d 디렉토리의 tomcatd 파일을 열어
 JAVA_HOME=/usr/local/java
 라고 추가해 줬더니 다음번 부팅시엔 둘다 연동된 상태로 구동 되었습니다.
 지금 상황으론 아파치 DocumentRoot나 각 사용자 계정에서 jsp 파일들은 모두 인식되는데 servlet은
 아직 안되더군요. 혹시 servlet도 성공하신분은 리플 주시면 감사 ^^
Epilog
-- 처음으로 문서를 작성해 봅니다. 저도 아파치와 톰캣을 연동하느라 삼일을 버렸기에, 다른분들은
고생을 덜 하기실 바라며 문서를 남깁니다.(이대로 따라하셨다가 고생을 더하셔도 책임은 못집니다. ㅠ.ㅠ)
삼일동안 각종 버전의 아파치와 톰캣을 깔았다 지웠다를 반복하며, 이사이트 저사이트 정신없이 창 여러개 띄워서
이문서 저문서 보던게 효율이 너무 안 좋아서 하나로 합쳐 보았습니다. 부디 이 문서를 보시고 다들 한번에
연동에 성공하시길 바랍니다.
글의 내용중 잘못 된 부분이 있을 수도 있습니다. 이점 양해 바랍니다.
    2004년 1월 18일   이 지 형

java Framework/jsp 프로그래밍] 패키지로 컴파일된 java 혹은 jar 파일 실행하기


- 패키지 컴파일 및 실행
-- 컴파일
package sample; 로선언된 소스인경우,

javac -d xxx.java

-- 실행
$ java sample.Test

(java 패키지이름.메인클래스)

java -classpath .;$JAVA_HOME/lib/tools.jar;D:/~/WEB-INF/classes; test.Tester


- jar  파일 실행 방법
$ java –jar test.jar

만약 인자값이 있으면
$ java –jar test.jar 인자값리스트

java Framework/jsp 프로그래밍/common.net을 이용한 FTP client 프로그램



소스영역 :::

/**
 * 참조 사이트 목록
 * http://www.okjsp.pe.kr/seq/51685
 * http://benelog.springnote.com/pages/1468338
 * 참조해서 작업 해 본것임.
 * apache 의  common.net api 사용
 * ftp batch 작업을 위한  용도
 * 2009.03.26
 * 인자 : -H:server ip, -P:server port, -UI:user id, -UP:user pw, -PM:passive-mode
 */
package net.nchannel.ftp;
/**
 * @author snipper
 *
 */
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
//import org.apache.commons.net.ftp.FTPListParseEngine;
//import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;

public class FCBatch {
//    protected static final Log logger = LogFactory.getLog(FCBatch.class);
 /**
  *
  */
    public FCBatch() {
  // TODO Auto-generated constructor stub
 }
 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  // 인자는 -H, -P, -ui, -up, -path, -pm 이 존재
  String host = "";
  String port = "";
  String id = "";
  String pw = "";
  String rpath = "";
  String pm = "";
  String fileNm = "";   //"JeusServer_"+getDate(-1)+".log"; //현재 이전 날짜의 파일 가져오기 위한 파일명 구하기
  String lpath = "";    //"d:\\jeuslogs\\JeusServer_"+getDate(-1)+".log"; //현재 이전 날짜의 파일 가져오기 위한 파일명 구하기
  FileOutputStream fos = null;
 
//  System.out.println("입력 인자 수 : " + args.length);
//  System.out.println("파일 명  : " + fileNm);
  // 입력된 인자 값을 각 의미 변수에 할당.
  for(int i=0; i < args.length; i++) {
   if(args[i].indexOf("-H")!=-1)
    host = args[i].substring(2);
   if(args[i].indexOf("-P")!=-1)
    port = args[i].substring(2);
   if(args[i].indexOf("-UI")!=-1)
    id = args[i].substring(3);
   if(args[i].indexOf("-UP")!=-1)
    pw = args[i].substring(3);
   if(args[i].indexOf("-RP")!=-1)
    rpath = args[i].substring(3);
   if(args[i].indexOf("-LP")!=-1)
    lpath = args[i].substring(3);
   if(args[i].indexOf("-FN")!=-1)
    fileNm = args[i].substring(3);
   if(args[i].indexOf("-PM")!=-1)
    pm = args[i].substring(3);
  }
  if(port.equals("")) port = "21";  //접속 포트 번호, 기본 21번 포트 사용
  if(rpath.equals("")) rpath = "/home/tmax/jeus5/logs/ECOWEB/";  //원격 기본 디렉토리 설정, 제우스를 기본으로 했음.
  if(lpath.equals("")) lpath = "c:\\jeuslogs\\";      //로컬 기본 디렉토리 설정, 로컬 디렉토리가 없을 경우.... 현재 폴더로 해도 되나 그냥 위와 같이 함.
  if(fileNm.equals("")) fileNm = "JeusServer_"+getDate(-1)+".log"; //가져올 기본 파일명 설정
  if(pm.equals("")) pm = "Y"; // 패시브모드 on(기본모드)
//  System.out.println("host = " + host);
//  System.out.println("port = " + port);
//  System.out.println("id = " + id);
//  System.out.println("pw = " + pw);
//  System.out.println("remote path = " + rpath);
//  System.out.println("local path = " + lpath);
//  System.out.println("file name = " + fileNm);
//  System.out.println("passive mode y/n  = " + pm);
 
  FTPClient ftp = null;
 
  try {
   ftp = new FTPClient();
   ftp.setControlEncoding("euc-kr");  // ftp 인코딩을 EUC-KR 로 설정.
  
//   if(logger.isDebugEnabled()) {
    System.out.println("FTP Client Test Progrma with Commons NET");
    System.out.println("test by 2009.03.26");
    System.out.println("FCBatch main() start");
//    System.out.println("host = " + host);
//    System.out.println("port = " + port);
//    System.out.println("id = " + id);
//    System.out.println("pw = " + pw);
//    System.out.println("remote path = " + rpath);
//    System.out.println("passive mode y/n  = " + pm);
//   }
//  
  
   if(!host.equals("") && !port.equals("") && !id.equals("") && !pw.equals("")) {
    // ftp 연결
    ftp.connect(host,Integer.parseInt(port));
//    if(logger.isDebugEnabled()) {
     System.out.println("connected to " + host +":"+port);
//    }
//    if(logger.isDebugEnabled()) {
     System.out.println("login by user id : " + id +", password :"+pw);
     System.out.println("ftp.login()");
//    }
    ftp.login(id, pw);
//    if(logger.isDebugEnabled()) {
     System.out.println("login success...");
//    }
   
    // 패시브 모드 설정 하기
    if(pm.endsWith("Y")) {
//     if(logger.isDebugEnabled()){
      System.out.println("passive mode 설정");
      System.out.println("passive mode 입력 값: " +pm);
//     }
     ftp.enterLocalPassiveMode();
//     if(logger.isDebugEnabled()){
      System.out.println("passive mode 설정 완료");
//     }
    }
   
    //change directory
//    if(logger.isDebugEnabled()) {
     System.out.println("change directory : " + rpath );
     System.out.println("ftp.changeWorkingDirectory("+rpath+")");
//    }
    ftp.changeWorkingDirectory(rpath);
//    if(logger.isDebugEnabled()) {
     System.out.println("경로 변경 : " + rpath);
//    }
   
//    if(logger.isDebugEnabled()) {
     System.out.println("파일 전송 타입 설정  : setFileType" );
     System.out.println("ftp.setFileType(FTP.BINARY_FILE_TYPE)");
//    }
    ftp.setFileType(FTP.BINARY_FILE_TYPE);
//    if(logger.isDebugEnabled()) {
     System.out.println("파일 전송 타입 설정 완료 " );
//    }
   
    // ftp  사이트 리스팅.
//    ftpList(ftp, path);
/*    
    try{
//     if(logger.isDebugEnabled()) {
      System.out.println("서버 디렉토리 리스팅  : " );
      System.out.println("ftp.setFileType(FTP.BINARY_FILE_TYPE)");
//     }
     FTPListParseEngine engine = ftp.initiateListParsing("unix",path);
     System.out.println("" + StringUtils.rightPad("Name", 30) + StringUtils.leftPad("Size", 10) + " ");
     System.out.println("" + StringUtils.leftPad("-", 30, "-") + StringUtils.leftPad("-", 10,"-") + "-");
    
     int idx=0;
    
     while(engine.hasNext()) {
      FTPFile[] files = engine.getNext(25);
      idx += files.length;
     
      for(int i=0; i < files.length; i++) {
       FTPFile file= files[i];
       System.out.println(StringUtils.rightPad(" "+file.getName(),30) + StringUtils.leftPad(""+file.getSize(), 10) + " ");
      
      }
     }
    
     System.out.println("-" + StringUtils.leftPad("-", 30, "-") + StringUtils.leftPad("-", 10, "-") + "-");
     System.out.println(" total : " + idx);
     System.out.println("  ");
      
//     if(logger.isDebugEnabled()) {
      System.out.println("서버 디렉토리 리스팅  : " + path + "완료" );
//     }
    } catch (Exception e) {
     System.out.println("ftp 리스팅 실패");
     e.printStackTrace();
     System.exit(-1);
    }
   
*/   
    // 파일 내려 받기 ??
    try {
     fos = new FileOutputStream(lpath+fileNm);
     ftp.retrieveFile(fileNm, fos);
    } catch(IOException e) {
     System.out.println("IO Exception : " + e.getMessage());
    } finally {
     if(fos != null) {
      try {
       fos.close();
      
      } catch (IOException e) {
       System.out.println("IO Exception : " + e.getMessage());
      }
     }
    }
   
    System.out.println(fileNm + "파일 다운로드 완료 !!!");  
   
   } else { // host, port, id, pw 없으면 에러 발생.
    System.out.println("usage : FCBatch -Hhost -P[port] -UIid -UPpw -RP[remote path] -LP[local path] -FN[file name] -PM[passive mode] ");
    System.out.println("options ");
    System.out.println("-H : Host [Name | IP] ");
    System.out.println("-P : 접속할 포트 번호 ,     Default : 21 ");
    System.out.println("-UI : User ID ");
    System.out.println("-UP : User Password");
    System.out.println("-RP : FTP Server Path,    Default : /home/tmax/jeus5/logs/ECOWEB/");
    System.out.println("-LP : Localhost Path,    Default : c:\\jeuslogs\\");
    System.out.println("-FN : Download 할 File Name ,  Default : JeusServer_"+getDate(-1)+".log  ");
    System.out.println("-PM : Passive Mode 사용 여부 [Y/N], Default: Y ");
   
//    throw new Exception("접속에 필요한 필수 정보를 입력하지 않으셨습니다.");
   }
  
  
  } catch (Exception e) {
//   System.out.println("ftp 로그인 실패");
   e.printStackTrace();
  } finally {
   // ftp 연결 해제.
//   System.out.println("ftp 연결해제");
   if(ftp != null && ftp.isConnected()) {
    try {
     ftp.disconnect();
    } catch (IOException e) {
     System.out.println("IOException : " + e.getMessage());
    }
   }
   // 프로그램 종료
   System.exit(-1); // 종료
  }

 }
/*
 public static void ftpList(FTPClient ftp, String path) {
  try{
   if(logger.isDebugEnabled()) {
    System.out.println("서버 디렉토리 리스팅  : " );
    System.out.println("ftp.setFileType(FTP.BINARY_FILE_TYPE)");
   }
   FTPListParseEngine engine = ftp.initiateListParsing("unix",path);
   System.out.println("" + StringUtils.rightPad("Name", 30) + StringUtils.leftPad("Size", 10) + " ");
   System.out.println("" + StringUtils.leftPad("-", 30, "-") + StringUtils.leftPad("-", 10,"-") + "-");
  
   int idx=0;
  
   while(engine.hasNext()) {
    FTPFile[] files = engine.getNext(25);
    idx += files.length;
   
    for(int i=0; i < files.length; i++) {
     FTPFile file= files[i];
     System.out.println(StringUtils.rightPad(" "+file.getName(),30) + StringUtils.leftPad(""+file.getSize(), 10) + " ");
    
    }
   }
  
   System.out.println("-" + StringUtils.leftPad("-", 30, "-") + StringUtils.leftPad("-", 10, "-") + "-");
   System.out.println(" total : " + idx);
   System.out.println();
    
   if(logger.isDebugEnabled()) {
    System.out.println("서버 디렉토리 리스팅  : " + path + "완료" );
   }
  } catch (Exception e) {
   System.out.println("ftp 리스팅 실패");
   e.printStackTrace();
   System.exit(-1);
  }
 
 }
*/

 /**
  *
  * @param day
  * @return
  */
 public static String getDate(int day){
  Calendar temp = Calendar.getInstance();
  StringBuffer sDate = new StringBuffer();
 
  temp.add(Calendar.DAY_OF_MONTH, -1);
 
  int iYY = temp.get(Calendar.YEAR);
  int iMM = temp.get(Calendar.MONTH)+1;
  int iDD = temp.get(Calendar.DAY_OF_MONTH);
 
  sDate.append(iYY);
  if(iMM <10)
   sDate.append("0");
  sDate.append(iMM);
 
  if(iDD < 10)
   sDate.append("0");
  sDate.append(iDD);
 
  return sDate.toString();
 }
}

java Framework/JSP] taglib prefix=c 로 사용시 에러 발생하는 경우



출처 : http://ck1024.tistory.com/14

-<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>" 으로 작성을 했더니 아래의 에러가 발생
→ According to TLD or attribute directive in tag file, attribute value does not accept any expressions

"<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>"으로 수정하니 정상적으로 실행됨


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

Servlet 2.4
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>

java Framework/jsp] 세션 공유시 서블릿 컨텍스트 참조 문제



원문 url : http://blog.daum.net/uttiboy/16864082

세션 공유시 서블릿 컨텍스트 참조 문제


두 웹애플리케이션에서 세션을 공유할때 세션을 통해 서블릿 컨텍스트를 참조할때
어떤 서블릿 컨텍스트를 참조할까?

Root WebApp - xxx.co.kr
WebApp1 - xxx.co.kr/app1

두 애플리케이션은 서로 세션공유가 가능하도록 설정되어 있다
이때 xxx.co.kr로 접근하고 xxx.co.kr/app1으로 접근할때 두 애플리케이션간에
세션은 공유되어 있다.

문제는 WebApp1에서 session.getServletContext()를 호출할때 어떤 서블릿 컨텍스트가 반환될까?
애플리케이션의 접근 순서에 따라 다른데 xxx.co.kr을 접근하고 xxx.co.kr로 접근하게되면
xxx.co.kr에서 세션이 생성되고  Root WebApp의 서블릿 컨텍스트를 참조하게 되어서
WebApp1에서 session.getServletContext()는 xxx.co.kr의 서블릿 컨텍스트를 참조한다.

WebApp1에서 자신의 서블릿 컨텍스트를 참조하기 위해서는 session.getServletContext().getContext("/app1")으로 참조해야 한다.

Tomcat의 경우 context에 crossContext 속성을 true로 설정해야 가능하다고 합니다

java Framework/java]Reading and writing text files


 출처 : http://www.javapractices.com/topic/TopicAction.do?Id=42


Reading and writing text files

When reading and writing text files :
  • it's almost always a good idea to use buffering (default size is 8K)
  • it's often possible to use references to abstract base classes, instead of references to specific concrete classes
  • there is always a need to pay attention to exceptions (in particular, IOException and FileNotFoundException)
The close method :
  • always needs to be called, or else resources will leak
  • will automatically flush the stream, if necessary
  • calling close on a "wrapper" stream will automatically call close on its underlying stream
  • closing a stream a second time has no consequence
Commonly used items :
The FileReader and FileWriter classes are a bit tricky, since they implicitly use the system's default character encoding. If this default is not appropriate (for example, when reading an XML file which specifies its own encoding), the recommended alternatives are, for example :
FileInputStream fis = new FileInputStream("test.txt");
InputStreamReader in = new InputStreamReader(fis, "UTF-8");
FileOutputStream fos = new FileOutputStream("test.txt");
OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");
Scanner scanner = new Scanner(file, "UTF-8");
The following examples use JDK 1.5.
Example 1
Here is a fairly compact example of reading and writing a text file, using an explicit encoding. If you remove all references to encoding from this class, it will still work -- the system's default encoding will simply be used instead.
import java.io.*;
import java.util.Scanner;

/** 
 Read and write a file using an explicit encoding.
 Removing the encoding from this code will simply cause the 
 system's default encoding to be used instead.  
*/
public final class ReadWriteTextFileWithEncoding {

  /** Requires two arguments - the file name, and the encoding to use.  */
  public static void main(String... aArgs) throws IOException {
    String fileName = aArgs[0];
    String encoding = aArgs[1];
    ReadWriteTextFileWithEncoding test = new ReadWriteTextFileWithEncoding(
      fileName, encoding
    );
    test.write();
    test.read();
  }
  
  /** Constructor. */
  ReadWriteTextFileWithEncoding(String aFileName, String aEncoding){
    fEncoding = aEncoding;
    fFileName = aFileName;
  }
  
  /** Write fixed content to the given file. */
  void write() throws IOException  {
    log("Writing to file named " + fFileName + ". Encoding: " + fEncoding);
    Writer out = new OutputStreamWriter(new FileOutputStream(fFileName), fEncoding);
    try {
      out.write(FIXED_TEXT);
    }
    finally {
      out.close();
    }
  }
  
  /** Read the contents of the given file. */
  void read() throws IOException {
    log("Reading from file.");
    StringBuilder text = new StringBuilder();
    String NL = System.getProperty("line.separator");
    Scanner scanner = new Scanner(new File(fFileName), fEncoding);
    try {
      while (scanner.hasNextLine()){
        text.append(scanner.nextLine() + NL);
      }
    }
    finally{
      scanner.close();
    }
    log("Text read in: " + text);
  }
  
  // PRIVATE 
  private final String fFileName;
  private final String fEncoding;
  private final String FIXED_TEXT = "But soft! what code in yonder program breaks?";
  
  private void log(String aMessage){
    System.out.println(aMessage);
  }
}
 


Example 2
This example uses FileReader and FileWriter, which implicitly use the system's default encoding. To make this example compatible with JDK 1.4, just change StringBuilder to StringBuffer:
import java.io.*;

public class ReadWriteTextFile {

  /**
  * Fetch the entire contents of a text file, and return it in a String.
  * This style of implementation does not throw Exceptions to the caller.
  *
  * @param aFile is a file which already exists and can be read.
  */
  static public String getContents(File aFile) {
    //...checks on aFile are elided
    StringBuilder contents = new StringBuilder();
    
    try {
      //use buffering, reading one line at a time
      //FileReader always assumes default encoding is OK!
      BufferedReader input =  new BufferedReader(new FileReader(aFile));
      try {
        String line = null; //not declared within while loop
        /*
        * readLine is a bit quirky :
        * it returns the content of a line MINUS the newline.
        * it returns null only for the END of the stream.
        * it returns an empty String if two newlines appear in a row.
        */
        while (( line = input.readLine()) != null){
          contents.append(line);
          contents.append(System.getProperty("line.separator"));
        }
      }
      finally {
        input.close();
      }
    }
    catch (IOException ex){
      ex.printStackTrace();
    }
    
    return contents.toString();
  }

  /**
  * Change the contents of text file in its entirety, overwriting any
  * existing text.
  *
  * This style of implementation throws all exceptions to the caller.
  *
  * @param aFile is an existing file which can be written to.
  * @throws IllegalArgumentException if param does not comply.
  * @throws FileNotFoundException if the file does not exist.
  * @throws IOException if problem encountered during write.
  */
  static public void setContents(File aFile, String aContents)
                                 throws FileNotFoundException, IOException {
    if (aFile == null) {
      throw new IllegalArgumentException("File should not be null.");
    }
    if (!aFile.exists()) {
      throw new FileNotFoundException ("File does not exist: " + aFile);
    }
    if (!aFile.isFile()) {
      throw new IllegalArgumentException("Should not be a directory: " + aFile);
    }
    if (!aFile.canWrite()) {
      throw new IllegalArgumentException("File cannot be written: " + aFile);
    }

    //use buffering
    Writer output = new BufferedWriter(new FileWriter(aFile));
    try {
      //FileWriter always assumes default encoding is OK!
      output.write( aContents );
    }
    finally {
      output.close();
    }
  }

  /** Simple test harness.   */
  public static void main (String... aArguments) throws IOException {
    File testFile = new File("C:\\Temp\\blah.txt");
    System.out.println("Original file contents: " + getContents(testFile));
    setContents(testFile, "The content of this file has been overwritten...");
    System.out.println("New file contents: " + getContents(testFile));
  }
} 


Example 3
This example demonstrates using

Scanner to read a file containing lines of structured data. Each line is then parsed using a second Scanner and a simple delimiter character, used to separate each line into a name-value pair. The Scanner class is used only for reading, not for writing.
import java.io.*;
import java.util.Scanner;

public final class ReadWithScanner {

  public static void main(String... aArgs) throws FileNotFoundException {
    ReadWithScanner parser = new ReadWithScanner("C:\\Temp\\test.txt");
    parser.processLineByLine();
    log("Done.");
  }
  
  /**
  * @param aFileName full name of an existing, readable file.
  */
  public ReadWithScanner(String aFileName){
    fFile = new File(aFileName);  
  }
  
  /** Template method that calls {@link #processLine(String)}.  */
  public final void processLineByLine() throws FileNotFoundException {
    Scanner scanner = new Scanner(fFile);
    try {
      //first use a Scanner to get each line
      while ( scanner.hasNextLine() ){
        processLine( scanner.nextLine() );
      }
    }
    finally {
      //ensure the underlying stream is always closed
      scanner.close();
    }
  }
  
  /** 
  * Overridable method for processing lines in different ways.
  *  
  * <P>This simple default implementation expects simple name-value pairs, separated by an 
  * '=' sign. Examples of valid input : 
  * <tt>height = 167cm</tt>
  * <tt>mass =  65kg</tt>
  * <tt>disposition =  "grumpy"</tt>
  * <tt>this is the name = this is the value</tt>
  */
  protected void processLine(String aLine){
    //use a second Scanner to parse the content of each line 
    Scanner scanner = new Scanner(aLine);
    scanner.useDelimiter("=");
    if ( scanner.hasNext() ){
      String name = scanner.next();
      String value = scanner.next();
      log("Name is : " + quote(name.trim()) + ", and Value is : " + quote(value.trim()) );
    }
    else {
      log("Empty or invalid line. Unable to process.");
    }
    //(no need for finally here, since String is source)
    scanner.close();
  }
  
  // PRIVATE //
  private final File fFile;
  
  private static void log(Object aObject){
    System.out.println(String.valueOf(aObject));
  }
  
  private String quote(String aText){
    String QUOTE = "'";
    return QUOTE + aText + QUOTE;
  }
} 


Example run of this class :
Name is : 'height', and Value is : '167cm'
Name is : 'mass', and Value is : '65kg'
Name is : 'disposition', and Value is : '"grumpy"'
Name is : 'this is the name', and Value is : 'this is the value'
Done.


java Framework/java]Http 통신


java :: http 통신

출처 : http://blog.naver.com/banhong/104373158

얼마전에 자바 어플리캐이션에서 http통신으로 데이터 값을 가져와야 하는것을 개발해야 해서

동작테스트 삼아 만들었쌈~..... 실제는 이렇게 안만들었지만 서도


/**
 *
 */
package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * @author 이준성
 *
 */
public class HttpRequest {

 private String url;


 public HttpRequest(String url) {
 
  this.url = url;
 
 }

 public String request()  {
 
  String returnVal = "";
 
  HttpURLConnection con = null;
 
  BufferedReader br = null;
 
  try {
  
   URL tempCon = new URL(url);
   con = (HttpURLConnection)tempCon.openConnection();
  
   // 메소드 방식설정
   con.setRequestMethod("POST");
   // 헤더 설정
   con.setRequestProperty("Content-Type" , "application/x-www-form-urlencoded");
  
   con.connect();
  
   InputStreamReader isr = new InputStreamReader(con.getInputStream());
   br = new BufferedReader(isr);
  
   String temp = null;
  
   while((temp = br.readLine()) != null) {
   
    System.out.println(temp);
   
   }
     
  }catch(IOException e) {
  
   e.printStackTrace();
    
  } finally {
  
   if(br != null) {
    try {
     br.close();
    } catch (IOException e) {
     e.printStackTrace();
    }
   }
  
   con.disconnect();
  
  }
 
  return returnVal;
 }



 /**
  * 동작 테스트
  *
  * @param args
  */
 public static void main(String args[]) {
 
  //HttpRequest 생성시에 인자로 요청을 보낼 주소를 적으면 된다.
  //HttpRequest hr = new HttpRequest("");
  //hr.request();
 
 }

}


자바에서 제공하는 HttpURLConnection 이란 녀석때문에 상당이 쉽게 만들수는 있다지만,
상당히 객체지향적이지 못하게 설계된 클래스라고 하네요. 흠~~ 구런가????

서블릿과의 통신 가능한 클라이언트 작성에 대해서
출처 :

HTTP통신을 하는 서버와 클라이언트를 작성하려고 합니다. 서버측은 서블릿으로 작성을 하였습니다. 클라이언트단은 jsp나 html이 아닌 일반 어플리케이션을 이용해야 합니다. URLConnection클래스를 이용하여 서버에 접속하여 정보를 주고 받게끔 작성하였는데 클라이언트에서 정보를 보내는 것은 가능하나 서버로 부터 오는 정보를 다시 받는 방법을 모르겠습니다. 또한, jsp나 html는 form태크를 써서 서버에서 doPost함수에서 response할 수 있는반면 URLConnection으로 서버에 접속을 하게 되면 URL뒤에 정보가 붙어서 가는 Get방식으로 밖에 전송이 안되네요. 어떤 방법으로 클라이언트를 작성하는 것이 더 원활한 서블릿과의 통신방법이 될 수 있을까요? 아래에 소스를 첨부하겠습니다. 꼭 답변 부탁드릴께요.

<HttpClient>
import java.io.*;
import java.net.*;

import sun.net.www.protocol.http.HttpURLConnection;

public class HttpClient {

  public static void main(String[] args) {
    try {
    URL url = new URL("http://127.0.0.1:8080
                    /servlet/HttpTest?p=abc");
    HttpURLConnection huc = (HttpURLConnection)
                                   url.openConnection();
       
    huc.setDoOutput(true);
          OutputStream os = huc.getOutputStream();
    BufferedOutputStream bos = new BufferedOutputStream(os);
    BufferedInputStream bis = new BufferedInputStream
                                    (huc.getInputStream());
           //送信
    bos.write("abc".getBytes());
    bos.flush();
    System.out.println("end");

    //受信
    byte[] r = new byte[3];
    bis.read(r);
    System.out.println("read : "+new String(r));

    } catch (MalformedURLException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}


<HttpServer>
import java.io.*;

import javax.servlet.*;
import javax.servlet.http.*;

public class HttpServer extends HttpServlet {

  public void service(HttpServletRequest request,
                         HttpServletResponse response)
    throws IOException {
       
     response.getOutputStream();
     BufferedInputStream bis = new BufferedInputStream
                               (request.getInputStream());
    byte[] r = new byte[3];
    System.out.println("start");
    int j = bis.read(r, 0, 3);
    System.out.println("read "+j+" : "+new String(r));
    //受信
    bis.read(r);
    System.out.println("read : "+new String(r));
    String str = request.getParameter("p");
    BufferedOutputStream bos = new BufferedOutputStream
                                     (response.getOutputStream());
    //送信
    bos.write(str.getBytes());
    bos.flush();
    System.out.println("write end ");
    }
}
 
   
 
 
 
2003-10-13 13:37:10.0  /  글번호 : 261780 
::carroty:: 도움이 되실란가 모르겠지만...dangguni
 
무슨 이유 때문인지 잘 모르겠지만, 아무튼 HTTP 통신을 하는 CS를 개발
하시는데, 클라이언트가 어플리케이션이어야 하는 이유를 잘 모르겠습니다. 다들 클라이언트를 웹브라우져안으로 이식하기위해 고생하는데 말이져.


클라이언트를 어플케이션으로 만드실것이라면, 애초에 걍 소켓 접속을
통해 프로그램을 만드시는 것이 어떤지요.
클라이언트는 걍 어플리케이션, 서버측도 걍 어플리케이션
이게 더 만들기도 편하고(편한가? *^^*) HTTP보다는 강력할 텐데요.

굳이 80 포트를 경유해야 한다면, 어플리케이션이 애플릿을 경유하여
작성하는 것도 괜찮은 방법이리라 생각됩니다.

클라이언트 프로그램 <-> 웹 브라우져 <-> (애플릿) <-- internet -->

웹 서버 <- 서블릿 -> core 서버 프로그램

머 이런식으로 하시는 것보다는 아래것이 더 낫지 않나요?

클라이언트 프로그램 <-- internet --> core 서버 프로그램

도움이 되시면 좋겠네염.

즐건 하루 되세염.
 
   
 
 
 
2003-10-13 14:32:08.0  /  글번호 : 261785 
서블릿과 애플리케이션과의 통신의 예javamaster
 
/**
  @explain : 서블릿테스트 클라이언트 by javamaster
*/
 
import java.io.*; 
import java.net.*;
import java.util.*;

import javax.servlet.*; 
import javax.servlet.http.*; 

public class HttpConnector{   
  DataInputStream dis;
  OutputStreamWriter writer; // 플래쉬 쓰기만
  String id; // 이 클라이언트가 서버로부터 할당받은 고유아이디  
  String host;
  public static void main(String[] args){ 
    HttpConnector con = new HttpConnector();
    con.initConnection("http://211.110.15.5/javamaster/servlet/Proxy2"); // 특정 URL로 서블릿 생성
  }

  /**
    @explain : 초기 접속 협상을 시도함
    @packet : 000    
  */
  public void initConnection(String _host){      
    host = _host;
    try{      
      URL url = new URL(_host);    
      URLConnection rconnector = url.openConnection();        
      rconnector.setDoOutput(true);
      
      Writer flashwriter = new OutputStreamWriter(rconnector.getOutputStream(), "euc-kr");   
      flashwriter.write("000\n");
      flashwriter.flush();
      flashwriter.close();

      dis = new DataInputStream(rconnector.getInputStream());
      // 이부분에서 무한으로 read() 상태에 있게 된다. 서버와의 통신부분의 핵심
      String line="";
      
      while((line = dis.readLine()) != null){
        System.out.println("서블릿으로 부터 : " + line);      
        if(line.indexOf("000") == 0){ // 초기접속 ok이므로, 서버로 부터 고유아이디를 받았다면 writer를 생성해야 함
          id = line.substring(line.indexOf(" ") + 1, line.length());
          //writeToServer("001 " + id);          
        }else if(line.indexOf("001") == 0){
          System.out.println("history : writer생성 협상 성공,, 이후 서버스 진행하면 됨");  
        }else{
          // 이곳에서 클라이언트 프로토콜을 위임함
          System.out.println("서버로 부터 : " + line);  
        }
        System.out.println("서버로부터 데이터가 오기를 대기함");
      }      
      System.out.println("모든 것 종료");
      
    }catch(Exception e){
      e.printStackTrace();  
    }finally{
    
    }      
  } 
  /**
    @explain : 연결된 writer 객체를 이용해서 서버로 전송
  */
  public void writeToServer(String _packet){
    try{
      URL url = new URL(host);    
      URLConnection wconnector = url.openConnection();        
      wconnector.setDoOutput(true);
      
      // 현재의 writer를 멤버writer로 등록
      OutputStreamWriter writer = new OutputStreamWriter(wconnector.getOutputStream(), "euc-kr");        
      writer.write(_packet + "\n");
      writer.flush();
      writer.close();
      System.out.println("서블릿에 전송 : " + _packet);
      // 응답을 받기위해 임의로
      BufferedReader reader2 = new BufferedReader(new InputStreamReader(wconnector.getInputStream(),"latin1"));      
      reader2.close();
    }catch(Exception e){
      e.printStackTrace();  
    }
  }
}
                    
위의 소스는 일본 KDDI 무선네트워크 프로젝트를 하면서 작성한 것입니다
서버 - 서블릿 - 무선핸드폰 이 실제 구조이고
서버 - 서블릿 - 애플리케이션 의 구조로 실제 서비스전에 데이터 통신에
대한 무선핸드폰 부분을 가상 테스트 하게 됩니다.
혹시 일본쪽 프로젝트신가요?

테스트를 해보시고 궁금하신거나 다른 부분에 대한 문의가 있으시면
제 홈페이지에 방문해 보시기 바랍니다.
요즘 문서 정리중이라 서블릿 부분이 추가 되어서.
그럼

javamaster wild world


제RssReader_Http통신예.zip


아파치 HttpClient 3.x 기준 설명 ..1-1. HttpClient 소개
HttpClient은 HTTP상에서 커뮤니케이션을 하는 자바 기반의 어플리케이션 개발을 쉽게 할수 있도록 제공한다.
우리가 웹 브라우저 또는 그에 준하는 어플리케이션을 개발한다면 HttpClient은 우리에게 클라이언트 코드 개발에 도움을 줄수있다.
이름에서 의미하는것과 같이 HttpClient는 오직 HTTP 클라이언트 코드을 위한 컴포넌트이지 HTTP 요청을 처리하는 서버측 프로세스을 지원하지는 않는다.
1-2. 설치
현재 아파치 HttpClient 는 3.0.1 안정버전을 지원한다.
Jakarta Commons HttpClient 페이지에서 다운로드 받으면 된다.
(다운로드 페이지: http://jakarta.apache.org/commons/httpclient/downloads.html)
(최신버전 다운로드:
  - http://jakarta.apache.org/site/downloads/downloads_commons-httpclient.cgi
  - http://mirror.apache-kr.org/jakarta/commons/httpclient/binary/commons-httpclient-3.0.1.zip
)
commons-httpclient-3.0.1.zip 를 받아서 압축을 풀고,
commons-httpclient-3.0.1.jar 를 CLASSPATH 에 추가하면 된다.
1-3. 추가 설정(Dependencies)
http://jakarta.apache.org/commons/httpclient/dependencies.html
 

Artifact ID  Type  Version  Scope  URL  Comment
commons-codec jar 1.2  http://jakarta.apache.org/commons/codec/
                       http://jakarta.apache.org/site/downloads/downloads_commons-codec.cgi
commons-logging jar 1.0.4  http://jakarta.apache.org/commons/logging/ 
junit jar 3.8.1 test  http://www.junit.org/


[JAVA] httpClient 샘플  ============================
출처 ; http://www.albumbang.com/board/board_view.jsp?board_name=free&no=126


package test;



import java.util.ArrayList;
import java.util.List;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.MultipartPostMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.util.EncodingUtil;

public class HttpClientHelper {
    public HttpClientHelper(String urlStr){
        this.urlStr = urlStr;
        paramList = new ArrayList();
    }

    private String urlStr = "";
    private String content = "";
    private int methodType = 0;
    private int iGetResultCode = 0;
    private int connectionMaxTime = 5000;

    private static final int GETTYPE = 0;
    private static final int POSTTYPE = 1;
    private static final int MULTIPARTTYPE = 2;

    public String getContent() {
        return content;
    }

    public int getIGetResultCode() {
        return iGetResultCode;
    }

    private List paramList = null;

    public void setParam(String key, String value) {
        paramList.add(new NameValuePair(key,value));
    }

    public int getMethodType() {
        return methodType;
    }

    public void setMethodType(int methodType) {
        this.methodType = methodType;
    }

    public int execute() {
        iGetResultCode = 0;
        HttpClient client = null;
        HttpMethod method = null;
        NameValuePair[] paramArray = new NameValuePair[paramList.size()];
        paramList.toArray(paramArray);
        try {
            client = new HttpClient(new MultiThreadedHttpConnectionManager());
            client.setTimeout(getConnectionMaxTime());

            if(methodType == GETTYPE){
                GetMethod getMethod = new GetMethod(urlStr);
                if(paramArray.length > 0)
                    getMethod.setQueryString(EncodingUtil.formUrlEncode(paramArray,"euc-kr"));
                method = getMethod;
            }else if(methodType == POSTTYPE){
                PostMethod postMethod = new PostMethod(urlStr);
                for(int k = 0; k < paramArray.length; k++){
                    postMethod.addParameter(paramArray[k].getName(), new String(paramArray[k].getValue().getBytes(),"ISO-8859-1"));
                }
                method = postMethod;
            }else if(methodType == MULTIPARTTYPE){
                MultipartPostMethod multipartPostMethod = new MultipartPostMethod(urlStr);
                for(int k = 0; k < paramArray.length; k++){
                    multipartPostMethod.addParameter(paramArray[k].getName(), paramArray[k].getValue());
                }
                method = multipartPostMethod;
            }
            // method.setFollowRedirects(true);

            iGetResultCode = client.executeMethod(method);
            if(iGetResultCode == HttpStatus.SC_OK)
            {
                content = method.getResponseBodyAsString();
            }
        } catch (Exception e) {
            iGetResultCode = 0;
        }finally{
            if(method != null) method.releaseConnection();
        }
        return iGetResultCode;
    }

    public int getConnectionMaxTime() {
        return connectionMaxTime;
    }

    public void setConnectionMaxTime(int connectionMaxTime) {
        this.connectionMaxTime = connectionMaxTime;
    }
}



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


package test;



import gshs.eshop.common.httputil.HttpClientHelper;



public class TestSimple {
    private void testPostMethod() {
        System.out.println("testPostMethod() start ###################################");

        String urlStr = "http://kkaok.pe.kr/frameset/door.jsp";
        HttpClientHelper test = new HttpClientHelper(urlStr);
        // 넘겨줄 파라미터 세팅
        test.setParam("act", "/servlet/KBoard?tableName=kjsp");
        // setMethodType을 지정하지 않으면 default = 0, (0:get, 1:post, 2:multipart)
        test.setMethodType(1);
        // connection 연결시간 설정 default = 5000;
        test.setConnectionMaxTime(5000);

        int rtnCode = test.execute(); // 실행하기
        System.out.println(rtnCode); // 결과 값. 200이면 정상
        System.out.println(test.getIGetResultCode()); // rtnCode 값을 결과 값이다.
        System.out.println(test.getContent()); // 해당 페이지의 내용 불러오기
    }

    private void testGetMethod() {
        System.out.println("testGetMethod() start ###################################");
        String urlStr = "http://kkaok.pe.kr/frameset/door.jsp";
        HttpClientHelper test = new HttpClientHelper(urlStr);
        test.setParam("act", "/servlet/KBoard?tableName=kjsp");
        // setMethodType을 지정하지 않으면 default = 0, (0:get, 1:post, 2:multipart)
        test.setMethodType(0);
        // connection 연결시간 설정 default = 5000;
        test.setConnectionMaxTime(5000);

        int rtnCode = test.execute();
        System.out.println(rtnCode); // 결과 값. 200이면 정상
        System.out.println(test.getIGetResultCode()); // rtnCode 값을 결과 값이다.
        System.out.println(test.getContent()); // 해당 페이지의 내용 불러오기
    }

    private void testGetMethodSample() {
        System.out.println("testGetMethodSample() start ###################################");
        String urlStr = "http://kkaok.pe.kr/frameset/door.jsp";
        HttpClientHelper test = new HttpClientHelper(urlStr);
        test.setParam("act", "/servlet/KBoard?tableName=kjsp");
        // setMethodType을 지정하지 않으면 default = 0, (0:get, 1:post, 2:multipart)
        test.setMethodType(0);
        // connection 연결시간 설정 default = 5000;
        test.setConnectionMaxTime(5000);

        int count = 5;
        int rtnCode = 0;
        for (int i = 0; i < count; i++) {
            System.out.println("count : " + (i + 1));
            rtnCode = test.execute();
            if (rtnCode == 200) {
                break;
            }
        }
        if (rtnCode == 200) {
            System.out.println(test.getIGetResultCode());
            System.out.println(test.getContent());
        }
    }

    private void testNoMethodOnlyUrl() {
        System.out.println("testNoMethodOnlyUrl() start ###################################");
        String urlStr = "http://kkaok.pe.kr/frameset/door.jsp?act=/servlet/KBoard?tableName=kjsp";
        HttpClientHelper test = new HttpClientHelper(urlStr);
        int rtnCode = test.execute();
        System.out.println(rtnCode); // 결과 값. 200이면 정상
        System.out.println(test.getIGetResultCode()); // rtnCode 값을 결과 값이다.
        System.out.println(test.getContent()); // 해당 페이지의 내용 불러오기

    }

    public static void main(String[] args) {
        TestSimple test = new TestSimple();
        test.testGetMethod();
        test.testPostMethod();
        test.testNoMethodOnlyUrl();
        test.testGetMethodSample();
    }
}



HttpClient 4.x버전으로 올라오면서 조쿰 바뀐 것 같습니다.
기록용으로 기록합니다-_-
아래 예제는.....티월드사이트의 무료사용량 조회 예제입니다-_-







출처 : http://mudchobo.tomeii.com/tt/479

Java] HttpClient 4.x 버전 예제


import java.net.URI;import java.util.ArrayList;import java.util.List;
import org.apache.http.Header;import org.apache.http.HttpResponse;import org.apache.http.NameValuePair;import org.apache.http.client.HttpClient;import org.apache.http.client.ResponseHandler;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.BasicResponseHandler;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.message.BasicNameValuePair;
publicclassMain{
/**

     * @param args

     */publicstaticvoid main(String[] args)throwsException{HttpClient httpclient =newDefaultHttpClient();

        String id ="t월드 아이디";String pw ="비밀번호";

        List<NameValuePair> qparams =newArrayList<NameValuePair>();

        qparams.add(newBasicNameValuePair("URL","http://www.tworld.co.kr/loginservlet.do?returnURL=http%3A%2F%2Fwww.tworld.co.kr&kind=&popup=&cmd=&reload=&ID="+ id));

        qparams.add(newBasicNameValuePair("ID", id));

        qparams.add(newBasicNameValuePair("PASSWORD", pw));

        qparams.add(newBasicNameValuePair("SERVERIP","203.236.20.129"));

        qparams.add(newBasicNameValuePair("X","0"));

        qparams.add(newBasicNameValuePair("Y","0"));UrlEncodedFormEntity entity =newUrlEncodedFormEntity(qparams,"UTF-8");HttpPost httpPost =newHttpPost("http://nicasams.sktelecom.com:2040/icas/fc/LogOnSV");

        httpPost.setEntity(entity);

        ResponseHandler<String> responseHandler =newBasicResponseHandler();String responseBody ="";HttpResponse response = httpclient.execute(httpPost);Header[] headers  = response.getAllHeaders();

        httpclient =newDefaultHttpClient();HttpGet httpGet =newHttpGet();if(headers.length >1){String url = headers[1].getValue();System.out.println("url = "+ url);

            httpGet.setURI(new URI(url));

            responseBody = httpclient.execute(httpGet, responseHandler);System.out.println(responseBody);}

        httpGet.setURI(new URI("http://www.tworld.co.kr/normal.do?serviceId=S_BILL0070&viewId=V_CENT0261"));

        responseBody = httpclient.execute(httpGet, responseHandler);

        System.out.println("result = "+ responseBody);}}