2018년 6월 30일 토요일

Wildcard SSL 설정

목표

  • letsencrypt wildcard SSL 설정

환경

  • CentOS7
  • Nnginx 1.13.8
  • DigitalOcean Droplet

예상 결과

  • www.{domain}.com 및 {domain}.com 호출시 SSL 접속


Certbot으로 인증서 발급

command

sudo certbot certonly \
--server https://acme-v02.api.letsencrypt.org/directory \
--manual \
--preferred-challenges dns \
-d *.{domain}.com \
-d {domain}.com \

  • wildcard 도메인 뿐 아니라 서브도메인이 없는 경우가 필요하다면 함께 추가

Issuing

Please deploy a DNS TXT record under the name
_acme-challenge.{domain}.com with the following value:

{value}

Before continuing, verify the record is deployed.

  • 위 값을 _acme-challenge 도메인의 DNS TXT 타입으로 등록
  • DNS record가 등록되어야만 다음단계 진행 가능
    • DNS Record 등록 부분 확인

성공시

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/{domain}.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/{domain}.com/privkey.pem
   Your cert will expire on 2018-09-28. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le


DNS Record 등록

  • TXT
    • _acme-challenge.thebudding.com => 위에서 제시한 값
    • 확인방법
      • nslookup -q=TXT {domain}
  • CNAME
    • wildcard 도메인을 redirect 하기 위함
    • *.{domain}.com => {domain}.com
  • NS / A


Nginx 설정

  • server {
        listen       80;
        server_name  ~.;
        return 301 https://$host$request_uri;
    }
    
    server {
        server_name  ~.;
        listen 443;
        
        ssl                  on;
        ssl_certificate      /etc/letsencrypt/live/{domain}/fullchain.pem;
        ssl_certificate_key  /etc/letsencrypt/live/{domain}/privkey.pem;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+ED';
        ssl_prefer_server_ciphers   on;
    
        location / {
         root   html;
         index  index.html index.htm;
      }
    }

참고자료

  • https://www.netmanias.com/ko/post/blog/5365/dns-network-protocol/three-types-of-dns-message-a-ns-and-cname
  • https://levelup.gitconnected.com/how-to-get-certbot-wildcard-certificates-3d25618a81e0
  • https://www.lesstif.com/pages/viewpage.action?pageId=27984443
  • https://certbot.eff.org/lets-encrypt/centosrhel7-nginx
  • https://blog.perfectacle.com/2017/10/05/letsencrypt-with-certbot-feat-aws/




2018년 2월 14일 수요일

Vue js 스터디

목표


  • vue js 로 프로젝트를 할 수 있을 정도 지식 획득
  • 스터디 책: vue.js 이정도는 알아야지 / 김지환.이선협 공저 / 비제이퍼블릭
  • webstorm

기반 프로젝트 생성

  • 참고
    • https://medium.com/codingthesmartway-com-blog/vue-js-2-quickstart-tutorial-2017-246195cfbdd2
    • https://medium.com/witinweb/vue-cli-%EB%A1%9C-vue-js-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-browserify-webpack-22582202cd52
    • https://kr.vuejs.org/v2/guide/installation.html
  • Command
    • npm install -g vue-cli
    • vue init webpack vueapp01
    • cd vueapp01
    • npm install
    • npm run dev
    • npm run build


2018년 1월 27일 토요일

Server Setting

목표

  • 서버 설정방법을 자꾸 잊어버려 기록을 위해 정리 시작
  • 목표를 세분화하고 목적을 해결하는 방식으로 진행
  • 명령형으로 작성하고 내용을 시간순서로 추가하되 되도록 수정하지 않음
    • 결과가 잘못될 수 있으니, 꼭 마지막을 확인 바람

환경

  • DigitalOcean droplet (2 vCPUs, 4GB, 80GB ssd, $20/mo)
  • CentOS 7.4 x64

설정 목표

  1. admin, adminsu 등록
  2. nginx 컴파일
  3. jenkins 설치
  4. gitlab gitpush 등록
  5. /resource path에 static 연동
  6. static build ci 적용
  7. /index.html에 hello world 노출

서버 생성

  • 2 vCPUs, 4GB, 80GB ssd, $20/mo, Singapore
  • CentOS 7.4 x64
  • root 로그인 (pw 메일로 전송받음) 후 비밀번호 변경
  • sudo yum update -y
    • prm, yum 차이
      • http://blackub.tistory.com/15

CentOS7

  • systemd 이해
    • http://linux.systemv.pe.kr/centos-7-systemd-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0/
  • centos6와 차이
    • http://signpen.kr/sp_view.php?cat=D02&fid=155&sk=LHDS

admin, adminsu 계정 등록

  • 목적
    • admin은 일반 사용계정
    • adminsu는 sudo 권한 제공
  • 참고
    • http://kit2013.tistory.com/187
    • http://blog.freezner.com/archives/1094
      • adduser, useradd 차이는 debian 계열 linux만 차이가 있음
  • adduser admin, passwd admin
    • 일반사용자 su 권한 제한
      • http://klero.tistory.com/entry/root-%EA%B3%84%EC%A0%95-su-%EC%A0%9C%ED%95%9C
    • vi /etc/pam.d/su
  • adduser adminsu, passwd adminsu
    • su사용자 sudoer 권한 제공
      • https://slobell.com/blogs/40
    • usermod -aG wheel adminsu 
      • adminsu에 wheel 그룹 추가
    • /etc/sudoers 
      • ## Same thing without a password 
        %wheel ALL=(ALL) NOPASSWD: ALL  // 주석제거

Nginx 컴파일

  • 참고
    • https://www.vultr.com/docs/how-to-compile-nginx-from-source-on-centos-7
  • 준비, 추가패키지, 의존 패키지 설치
    • sudo yum groupinstall -y 'Development Tools'
    • sudo yum install -y vim
    • sudo yum install -y epel-release
    • sudo yum install -y wget
  • nginx 다운 및 압축해제
    • wget http://nginx.org/download/nginx-1.13.8.tar.gz
    • tar -zxvf nginx-1.13.8.tar.gz
  • nginx package 다운
    • pcre
      • wget https://ftp.pcre.org/pub/pcre/pcre-8.41.tar.gz
      • tar xzvf pcre-8.41.tar.gz
    • zlib
      • wget https://www.zlib.net/zlib-1.2.11.tar.gz
      • tar xzvf zlib-1.2.11.tar.gz
    • openssl
      • wget https://www.openssl.org/source/openssl-1.1.0g.tar.gz
      • tar xzvf openssl-1.1.0g.tar.gz
  • nginx configuration
    • ./configure --prefix=/etc/nginx \
                  --sbin-path=/usr/sbin/nginx \
                  --modules-path=/usr/lib64/nginx/modules \
                  --conf-path=/etc/nginx/nginx.conf \
                  --error-log-path=/var/log/nginx/error.log \
                  --pid-path=/var/run/nginx.pid \
                  --lock-path=/var/run/nginx.lock \
                  --user=nginx \
                  --group=nginx \
                  --build=CentOS \
                  --builddir=nginx-1.13.8 \
                  --with-select_module \
                  --with-poll_module \
                  --with-threads \
                  --with-file-aio \
                  --with-http_ssl_module \
                  --with-http_v2_module \
                  --with-http_realip_module \
                  --with-http_addition_module \
                  --with-http_xslt_module=dynamic \
                  --with-http_image_filter_module=dynamic \
                  --with-http_geoip_module=dynamic \
                  --with-http_sub_module \
                  --with-http_dav_module \
                  --with-http_flv_module \
                  --with-http_mp4_module \
                  --with-http_gunzip_module \
                  --with-http_gzip_static_module \
                  --with-http_auth_request_module \
                  --with-http_random_index_module \
                  --with-http_secure_link_module \
                  --with-http_degradation_module \
                  --with-http_slice_module \
                  --with-http_stub_status_module \
                  --http-log-path=/var/log/nginx/access.log \
                  --http-client-body-temp-path=/var/cache/nginx/client_temp \
                  --http-proxy-temp-path=/var/cache/nginx/proxy_temp \
                  --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
                  --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
                  --http-scgi-temp-path=/var/cache/nginx/scgi_temp \
                  --with-mail=dynamic \
                  --with-mail_ssl_module \
                  --with-stream=dynamic \
                  --with-stream_ssl_module \
                  --with-stream_realip_module \
                  --with-stream_geoip_module=dynamic \
                  --with-stream_ssl_preread_module \
                  --with-compat \
                  --with-pcre=../packages/pcre-8.41 \
                  --with-pcre-jit \
                  --with-zlib=../packages/zlib-1.2.11 \
                  --with-openssl=../packages/openssl-1.1.0g \
                  --with-openssl-opt=no-nextprotoneg \
                  --with-debug
    • nginx modules 링크
      • sudo ln -s /usr/lib64/nginx/modules /etc/nginx/modules
    • nginx system 유저 및 그룹 등록
      • sudo useradd --system --home /var/cache/nginx --shell /sbin/nologin --comment "nginx user" --user-group nginx
    • nginx-t
      • 실패시 sudo mkdir -p /var/cache/nginx 생성후 다시 테스트
    • nginx server 시작 및 활성화
      • sudo systemctl start nginx.service
      • sudo systemctl enable nginx.service
      • sudo systemctl is-enabled nginx.service
      • sudo systemctl status nginx.service
    • 초기 파일 삭제
      • sudo rm /etc/nginx/koi-utf /etc/nginx/koi-win /etc/nginx/win-utf
    • nginx syntax highlighting
      • mkdir ~/.vim/
      • sudo cp -r ~/nginx-1.13.8/contrib/vim/* ~/.vim/
      • (cp -R /home/admin/apps/nginx-1.13.8/contrib/vim/* /home/adminsu/.vim/)

Jenkins 설치

  • JDK 설치가 먼저 필요하단걸 깜박함-_-

JDK 설치

  • 참조
    • https://tecadmin.net/install-java-8-on-centos-rhel-and-fedora/#
  • JDK 다운
    • wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.tar.gz"
  • /opt 로 이동 후 압축하제
    • cd /opt
    • tar xzf jdk-8u161-linux-x64.tar.gz
  • alternatives 명령어
    • https://skyoo2003.github.io/post/2017/03/17/what-is-alternatives-command
    • https://donghwi-kim.github.io/jekyll/update/2015/04/17/update-alternatives.html
  • alternatives 명령어로 심볼릭 링크 생성
    • alternatives --install /usr/bin/java java /opt/jdk1.8.0_161/bin/java 2
    • alternatives --config java
    • alternatives --install /usr/bin/jar jar /opt/jdk1.8.0_161/bin/jar 2
    • alternatives --install /usr/bin/javac javac /opt/jdk1.8.0_161/bin/javac 2
    • alternatives --set jar /opt/jdk1.8.0_161/bin/jar
    • alternatives --set javac /opt/jdk1.8.0_161/bin/javac
  • 확인
    • java -version

Tomcat 멀티 인스턴스 설치

  • 멀티 인스턴스를 시도하는 특별한 이유는 없음
    • 그냥, 예전 기억을 되살리기 위해 시도함
  • Jenkins용 서버와 SpringBatch용 서버로 활용할 예정
    • 추후 서비스가 커지는 경우 외부 장비로 이동할 예정 (그럴일이 없을수도 있음)
  • 참고
    • https://cocagolau.blogspot.kr/2014/03/blog-post_4571.html
  • 하려다가, 뭐 귀찮게 할 필요가 있나란 생각이 들어 포기함

Tomcat 설치

  • 톰켓8을 다운받으려 했으나, 9.0.4 버전이 나옴. 잠시 고민했지만, 8버전을 다운받기로 함
  • 참고
    • https://gs.saro.me/#!m=elec&jn=768
  • 다운
    • wget http://apache.tt.co.kr/tomcat/tomcat-8/v8.5.27/bin/apache-tomcat-8.5.27.tar.gz
  • 설정 변경
    • 포트번호 수정, ajp 포트 주석처리
  • 서버 실행 후 서버 접근
    • 방화벽에 막혀 있으므로 해당포트 방화벽 제거 (digitalocean)
    • 그래도 ERR_CONNECTION_REFUSED 발생
  • SeLinux
    • https://ko.wikipedia.org/wiki/%EB%B3%B4%EC%95%88_%EA%B0%95%ED%99%94_%EB%A6%AC%EB%88%85%EC%8A%A4
    • https://lesstif.gitbooks.io/web-service-hardening/content/selinux.html
    • http://navs.tistory.com/entry/SELinux-%EC%99%80-httpd-%ED%8F%AC%ED%8A%B8-%EB%B0%94%EC%9D%B8%EB%94%A9-%ED%95%98%EA%B8%B0
  • 설정된 포트를 SeLinux에 추가
    • semanage port -l | grep http
    • semanage port -a -t http_port_t -p tcp 포트번호
  • .. 서버는 뜨지만, 접근이 안됨. 이유를 모르겠음. 좀더 찾아보겠음 바로 다시 됨. 이놈 세계는 알수 없다.
  • Tomcat context 설정
    • https://ohjongsung.io/2017/06/24/tomcat-8%EC%97%90-root%EB%A1%9C-%EA%B2%8C%EC%8B%9C%ED%95%98%EA%B8%B0

Jenkins 설치

  • 다운로드
    • wget http://mirrors.jenkins.io/war/2.103/jenkins.war
  • 톰켓 배포 후 시작
  • 설정에서 역방향 프록시 설정이 잘못되었다고 나올 때
    • http://www.comsvc.kr/xe/comsvc_tip02/3846
    • sudo getsebool -a
    • sudo setsebool -P httpd_can_network_connect on
    • https://www.lesstif.com/pages/viewpage.action?pageId=22053077
    • '해제' 버튼을 눌러서 끝냄.

Gitlab push event 적용

  • 참고
    • http://yg-park.github.io/2015/03/10/gitlab-jenkins/
    • https://github.com/jenkinsci/gitlab-plugin/issues/375
  • 설치목록
    • Credentials Plugin, GIT plugin, GitLab Plugin, embeddable-build-status
  • 내용
    • jenkins 설정에서 secret key 꼭 설정

Nginx 와 Jenkins 연동


  • 목표
    • jenkins 의 endpoint를 nginx를 사용하도록 수정
  • 참조
    • https://nginx.org/en/docs/
    • https://www.nginx.com/resources/wiki/start/topics/examples/full/
    • https://www.digitalocean.com/community/tutorials/understanding-the-nginx-configuration-file-structure-and-configuration-contexts
    • https://blog.lael.be/demo-generator/nginx/default.conf.php
    • http://nginx.org/en/docs/example.html
    • https://www.digitalocean.com/community/tutorials/understanding-nginx-http-proxying-load-balancing-buffering-and-caching
    • http://nginx.org/en/docs/http/server_names.html
    • http://nginx.org/en/docs/http/request_processing.html
    • http://sarc.io/index.php/nginx/61-nginx-nginx-conf
    • https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms

static build ci 적용

  • 목포
    • jenkins 2.0 파이프라인 기능을 사용하여 배포를 자동화 설정
  • 참고
    • http://kingbbode.tistory.com/42
    • https://jenkins.io/doc/book/pipeline/getting-started/
    • https://jenkins.io/doc/book/pipeline/syntax/

Index.html을 root로 변경

  • 참고
    • https://www.nginx.com/resources/admin-guide/serving-static-content/
  • Nginx conf중 user
    • https://opentutorials.org/module/384/4530
    • 마스터 프로세스는 root로
    • conf의 user는 워커 프로세스의 실행권한

2014년 10월 23일 목요일

jenkins에서 tomcat 실행이 안되는 문제
 - http://lng1982.tistory.com/178
 - https://wiki.jenkins-ci.org/display/JENKINS/ProcessTreeKiller

2014년 4월 23일 수요일

[SQL] prepared statement에서 LIKE 사용방법


0. 환경1

macbook-pro 13” 2012 mid / 10GB
parallels9 ubuntu 12.04 LTS


1. 문제

preparedStatement를 사용시 SQL QUERY에 LIKE 문법 있을 때 처리방법

코드

StringBuffer query = new StringBuffer();
query.append("SELECT * FROM article WHERE name LIKE '%?%'");

// logger
logger.debug("name: " + name);

psmt = conn.prepareStatement(query.toString());
psmt.setString(1, name);  // 이 부분에서 에러 발생
rs = psmt.executeQuery();

에러 메시지

12:00:25.498 [DEBUG] [http-bio-8080-exec-3] [next.wildgoose.dao.ReporterCardDAO] - name: 하
12:00:25.514 [DEBUG] [http-bio-8080-exec-3] [next.wildgoose.dao.ReporterCardDAO] - Parameter index out of range (1 > number of parameters, which is 0).
java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1086) ~[mysql-connector-java-5.1.29.jar:na]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989) ~[mysql-connector-java-5.1.29.jar:na]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:975) ~[mysql-connector-java-5.1.29.jar:na]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:920) ~[mysql-connector-java-5.1.29.jar:na]
    at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3796) ~[mysql-connector-java-5.1.29.jar:na]
    at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3778) ~[mysql-connector-java-5.1.29.jar:na]
    at com.mysql.jdbc.PreparedStatement.setString(PreparedStatement.java:4599) ~[mysql-connector-java-5.1.29.jar:na]
    at next.wildgoose.dao.ReporterCardDAO.findReportersByName(ReporterCardDAO.java:101) ~[ReporterCardDAO.class:na]

2. 해결방법

Mysql

StringBuffer query = new StringBuffer();
query.append("SELECT * FROM article WHERE name LIKE ?");

psmt.setString(1, "%"+name+"%"); 

Oracle

StringBuffer query = new StringBuffer();
query.append("SELECT * FROM article WHERE name LIKE '%' || ? || '%'");

psmt.setString(1, name); 

Note
Oracle의 방법을 Mysql에 적용할 경우,
첫 번째 요청에 대해서는 결과를 응답하지만
name을 바꾼 후 요청은 update시키지 못한다는 문제가 발생했다.
그 이유에 대해서는 아직 찾아보지 못했다.


* 참고자료

stackoverflow - 2857164
stackoverflow - 8247970


Written with Dec7.

2014년 4월 14일 월요일

[javascript] forWD - 4장 변수, 스코프, 메모리


0. 환경

macbook-pro 13” 2012 mid / 10GB


1. 앞장 정리

변수

  1. 자바 스트립트의 변수는 느슨한 타입

    느슨한 타입

    • 한 변수에 어떤 타입이라도 저장할 수 있음
  2. 초기화 하지 않을 경우 undefined

데이터타입

  1. 원시 데이터 타입 (다섯가지의 기본 데이터 타입)
    1. undefined
    2. null
    3. boolean
    4. 숫자
    5. 문자열
  2. 객체 (복잡한 데이터 타입)
    • key - value 쌍의 순서없는 형태

자바 스크립트 데이터 타입은 동적이라서 한 가지 데이터 타입이 여러 특성을 가질 수 있음음

typeof 연산자

자바스크립트의 변수는 느슨한 타입이므로 변수의 타입을 알아야 할 때
typeof는 원시 값에 대해서는 잘 작동하지만 참조 값에서는 쓸모 없음

타입 내용
undefined 정의되지 않은 변수
boolean 불리언
string 문자열
number 숫자
object 함수를 제외한 객체 또는 null
function 함수

instanceof 연산자

// 문법
'result' = 'variable' instanceof 'constructor'

변수가 주어진 참조타입의 인스턴스일 때 true반환

  1. 인스턴스는 프로토타입 체인으로 판단함
  2. 모든 참조 값은 Object의 인스턴스

Note

  1. typeof연산자를 함수에 사용시 function 반환
  2. typeof연산자를 정규표현식에 사용시 function 반환
    • ECMA-262에서 내부에 [call]메소드를 가진 객체는 typeof에서 function를 반환해야한다고 명시했기 때문
      - 사파리5까지, 크롬7까지만 적용, firefox, IE는 object 반환

2. 변수

  1. 원시 데이터 타입
    • 변수에 저장된 실제 값을 조작
  2. 객체 타입
    • 참조 값은 메모리에 저장된 객체
    • 객체의 메모리 공간을 직접 조작할 수 없으므로 참조로 접근

동적 프로퍼티

참조 값의 경우 언제든 프로퍼티와 메소드를 추가/삭제 가능
원시 값의 경우 프로퍼티가 없지만 추가하려도 해도 오류가 발생하지는 않음

// 참조 값
var person = new Object();
person.name = "Nicholas";
console.log("person.name: " + person.name);
console.log("person.age: " + person.age);
person.age = 30;
console.log("person.age: " + person.age);

console.log("------------\n");

// 원시 값
var name = "Dec7";
console.log("name: " + name);
console.log("name.age: " + name.age);
name.age = 30;
console.log("name.age: " + name.age);

/*
* 출력 결과
**************
person.name: Nicholas
person.age: undefined
person.age: 30
------------

name: Dec7
name.age: undefined
name.age: undefined 
**************
*/

값 복사

// 원시 값
var num1 = 5
var num2 = num1

num2의 값은 복사되었고, num1의 값과 완전히 분리되어 있음
원시값 복사

// 참조 값
var obj1 = new Object();
var obj2 = obj1;

obj1.name = "Dec7";
console.log("obj2.name: " + obj2.name);

/*
* 출력결과
**************
dog.name: Dec7
**************
*/

참조 값의 경우 다른 변수에 복사할 객체 자체가 아닌 heap에 저장된 객체를 가리키는 포인터를 복사함.
복사 후 두 변수는 동일한 객체를 가리킴.
참조값복사

매개변수

원시값이든 참조값이든 모두 오직 값으로 전달.
매개변수를 값으로 전달하면 지역 변수에 저장됨.
- arguments 객체로 저장
매개변수를 참조형으로 전달하면 메모리상 주소 위치가 지역변수에 저장. 지역변수의 내용을 변경하면 함수 외부에도 반영됨.

// 매개변수가 원시 값일 때
function add(num){
    num += 10;
    return num;
}

var count = 20;
var result = add(count);
console.log("count: " + count);
console.log("result: " + result);

/*
* 출력 결과
**************
count: 20
result: 30 
**************
*/
// 매개변수가 참조 값일 때
function setName (obj) {
    obj.name = "Dec7";
    /*
    * new object
    * obj가 값이 아닌 참조 형태로 전달된다면
    * 출력결과는 Galaxy가 되어야 함
    */
    obj = new Object();
    obj.name = "Galaxy";
    /*
    * 함수 내부에서 위 obj를 덮어쓰면
    * obj는 지역 객체를 가리키는 포인터가 되고
    * 이 지역객체는 함수가 종료되는 즉시 파괴됨.
    */
}

var person = new Object();
setName(person);
console.log("person.name: " + person.name);

/*
* 출력 결과
**************
person.name: Dec7
**************
*/

함수 외부의 person이든 함수 내부의 obj든 모두 동일한 메모리 주소를 가리킴.
obj가 가리키는 것은 heap에 존재하는 전역객체이기 때문


3. 실행 컨택스트와 스코프

실행 컨텍스트

  • 이름
    • (변수/함수) 실행 컨텍스트(EC)
    • 짧게 컨텍스트라고 부름
  • 하는 일
    • 다른 데이터에 접근할 수 있는지 규정
    • 어떻게 행동하는지를 규정
  • 특징

    • 각 실행 컨텍스트에는 변수객체(VO)가 연결됨
    • 해당 컨텍스트에 정의된 모든 변수와 함수는 이 객체에 존재
    • 이 객체를 코드에서 직접 접근 불가
    • 이면에서 데이터를 다룰 때 이 객체를 사용
    • 실행 컨텍스트는 그것이 포함된 코드가 모두 실행되면 파괴됨
  • 종류

    1. 전역 컨텍스트

      • 가장 바깥쪽에 존재하는 실행 컨텍스트
      • 웹 브라우저에서 window라고 부름
      • 전역변수와 함수는 window객체의 property, method로 생성
      • 웹 브러우저가 닫칙 때까지 유지됨
    2. 함수 컨텍스트

      • 독자적인 실행 컨텍스트
      • 함수 호출시 생성됨
      • 실행 순서
        1. 실행시
          • 함수의 컨텍스트가 컨텍스트 스택에 쌓임.
        2. 종료시
          • 해당 컨텍스트를 컨텍스트 스택에서 꺼냄.
          • 컨트롤을 이전 컨텍스트로 인전
    3. eval()을 호출할 때 생성되는 세 번재 타입이 있긴함 (p117)

스코프체인

  • 컨텍스트에서 코드를 실행하면 변수객체에 스코프 체인이 형성됨
  • 목적
    • 실행 컨텍스트가 접근할 수 있는 모든 변수, 함수에 순서 정의

스코프체인 실행순서

  • 스코프 체인의 앞쪽
    • 항상 코드가 실행되는 컨텍스트의 변수 객체
    • 컨텍스트가 함수시 활성화 객체를 변수 객체로 사용

      활성화 객체

      • 항상 arguments 변수 하나로 시작
      • arguments객체는 전역 컨텍스트에는 없음
  • 변수객체 다음
    • 해당 컨텍스트를 포함하는 부모 컨텍스트
    • 그 다음은 부모의 부모 컨텍스트
    • 전역 컨텍스트까지 도달
  • 스코프 체인의 마지막
    • 전역 컨텍스트의 변수 객체

식별자를 찾기 위해 스코프 체인 순서를 따라가며 검색
(없는 경우, 에러 발생)

스코프체인 예제

var color = "blue";

function changeColor(){
    var anotherColor = "red";

    function swapColors(){
        var tempColor =anotherColor;
        anotherColor = color;
        color = tempColor;
        // color,anotherColor,tempColor모두 접근가능
    }
    // color,anotherColor접근가능.tempColor는 불가능
    swapColors();
    }
// color만접근가능
changeColor ( ) ;
  • 존재하는 실행 컨텍스트

    1. 전역 컨텍스트

      1. color변수 + changeColor()함수
    2. changeColor()의 지역 컨텍스트

      1. anotherColor변수 + swapColors()함수
      2. 전역 컨텍스트
    3. swapColors()의 지역 컨텍스트

      1. tempColor변수
      2. changeColor()함수의 컨텍스트
      3. 전역 컨텍스트
    4. 그림

      실행컨텍스트

  • 특징

    • 내부 컨텍스트는 스코프 체인을 통해 외부 컨텍스트로 접근 가능
    • 외부 컨텍스트는 내부 컨텍스트를 전혀 알 수 없음
  • swapColors()의 로컬 컨텍스트

    • 변수 객체 3개를 가짐

      1. swapColors()의 변수객체
      2. changeColor()의 변수객체
      3. 전역 변수객체
    • 자신의 변수 객체에서 변수나 함수를 찾음

    • 찾지 못할 경우 스코프 체인을 따라 한 단계씩 올라감
    • 아래로는 내려갈 수 없음
    • 함수 매개변수도 변수로 간주되어 실행 컨텍스트의 변수와 같은 규칙

스코프체인 확장

try-catch문의 catch블록과 with문
- 스코프체인 앞부분에 임시로 변수객체 생성
- 생성된 객체는 코드 실행이 끝나면 사라짐

  • with문

    해당 객체가 스코프체인에 추가

  • catch블록

    에러 객체를 선언하는 변수 객체가 생성

function buildUrl() {
    var qs = "?debug=true";

    /*
    * with문이 location객체에 적용되므로
    * location 객체개 scope chain에 추가됨
    */
    with(location) {
        /*
        * href는 location.href를 참조
        * qa는 buildUrl()함수 컨텍스트의 변수객체 참조
        * 
        * with문 내에서 선언한 url은 
        * buildUrl() 함수 컨텍스트로 편입됨
        */
        var url = href + qs;
    }
    /*
    *  with문을 통해 편입되었기 때문에 반환할 수 있음
    */
    return url;
}

var result = buildUrl();
console.log("url: " + result);

/* 
 * 실행결과
*************************
url: file:///Users/Dec7/Desktop/Javascript.html?debug=true
*************************
*/

Note

  • IE8까지는 JS구현에 문제가 있음
    • catch문에서 잡아낸 에러가 catch문의 변수객체가 아닌 실행 컨텍스트의 변수객체로 추가되어 catch블록 외부에서 접근 가능한 버그가 있음
  • IE9부터는 수정됨

블록레벨 스코프

for (var i=0; i < 10; i++){
    // do-something
}
alert(i); // 10
  • JS는 블록단위 스코프가 없음
  • JS는 변수를 선언할 때 현재 실행 컨텍스트에 추가

변수선언

  • var를 사용해 선언하면 자동으로 가장 가까운 컨텍스트에 추가
  • var를 사용하지 않으면 자동으로 전역 컨텍스트에 추가
// 전역 컨텍스트 예제
function one() {
    var one_num = 10;

    function two() {
        var two_num = 20;

        function three () {
            var three_num = 30;

            function four() {
                // var 키워드 미사용, 전역선언
                four_num = 40;
                console.log("in four(), four_num: " + four_num);
            }
            four();
            console.log("in three(), four_num: " + four_num);
        }
        three();
        console.log("in two(), four_num: " + four_num);

    }
    two();
    console.log("in one(), four_num: " + four_num);
}

one();
console.log("in global, four_num: " + four_num);

/*
* 출력결과
*********************
in four(), four_num: 40
in three(), four_num: 40
in two(), four_num: 40
in one(), four_num: 40
in global, four_num: 40 
*********************
*/
// var 키워드를 사용한 경우
function one() {
    var one_num = 10;

    function two() {
        var two_num = 20;

        function three () {
            var three_num = 30;

            function four() {
                // var 키워드 사용
                var four_num = 40;
                console.log("in four(), four_num: " + four_num);
            }
            four();
            console.log("in three(), four_num: " + four_num);
        }
        three();
        console.log("in two(), four_num: " + four_num);

    }
    two();
    console.log("in one(), four_num: " + four_num);
}

one();
console.log("in global, four_num: " + four_num);

/*
* 출력결과
*********************
in four(), four_num: 40
Uncaught ReferenceError: four_num is not defined
// console.log("in three(), four_num: " + four_num);에서 에러발생
*********************
*/

Note
- 변수를 선언하지 않고 사용하면 하면 에러 가능성 높아짐
- 스트릭모드에서 변수를 선언하지 않고 초기화시 에러

식별자검색

  • 컨텍스트 내부에서 식별자를 참조하기 전에 검색이 선행
  • 검색은 스코프체인 앞에서 시작
  • 식별자 이름으로 검색
  • 로컬 컨텍스트에서 검색 후 찾지 못하면
    • 스코프체인을 따라 검색을 계속함
    • 스코프체인 내부의 객체에도 프로토타입 체인이 있으므로 각 객체의 프로토타입 체인을 따라 검색할 수도 있음
  • 같은 식별자가 로컬 컨텍스트에 정의되어 있으며 부모 컨텍스트에 동일한 식별자가 있다고 하더라도 참조 불가
  • 검색에도 비용이 발생
    • 지역변수는 스코프체인 검색이 필요없으므로 전역변수보다 빨리 검색

4. 가비지 콜렉션

  • 더 이상 사용하지 않는 변수를 찾고 메모리를 회수함
  • 이 프로세스는 주기적으로 실행됨
  • [비추] 코드 실행 중 특정 시점에서 메모리 회수하도록 지정할 수도 있음
  • -

변수 사용여부


  • 더 이상 변수가
  • 하지만 명확하지 않은 경우가 많음
    • 사용여부를 확인 후 회수
    • 사용될 가능성이 있는지를 추측
    • 더 이상 사용하지 않는 변수의 기준을 브라우저마다 다름

      지역 변수
      함수를 실행하면 지역 변수가 생성됨
      함수가 종료된다면 그 지역 변수는 더 이상 필요 없음

* 참고자료


Written with Dec7.

2014년 4월 7일 월요일

[mobile-web] viewport


0. 환경

macbook-pro 13” 2012 mid / 10GB


1. veiwport

syntax

<meta name="viewport" content="name=value,name=value">

meta viewport tag는 viewport에 관하여 브라우저에게 지시
특히 width: 20%이 계산되는 것처럼 웹 개발자에게 CSS선언과 관한 layout viewport의 width 설정을 허용함

지시자(directive) 설명

이름-값 쌍으로 구성되며 총 6개의 지시자가 있다

attr name 내용
width layout viewport의 width를 설정
initial-scale 페이지의 초기 zoom과 layout viewport의 width를 설정
minimun-scale 최소 zoom 단계 설정 (user가 얼마나 축소시킬 수 있는지)
maximun-scale 최대 zoom 단계 설정 (user가 얼마나 확대시킬 수 있는지)
height layout viewport의 height를 설정 (작동안함, 게다가 height 설정은 이해안감.)
user-scalable 확대 축소 여부

* Zoom은 처음 보일 화면의 크기를 나타내는 것 같음

device-width 값

width 지시자에 사용되는 특별한 값
이상적인 viewport의 width를 layout viewport의 width로 설정
device-height도 존재하나 작동 안함 (In theory there’s a similar device-height value, but it doesn’t seem to work.)

브라우저

일반적으로 브라우저는 3그룹으로 나누어짐

그룹 브라우저 내용
1 Android Webkit, IE 심각한 버그가 도처에 널려있음, 그 버그가 비슷함
2 Safari landscape mode에서 portrait width 사용시 매우 드럽게 짜증나는 버그 있음 (width=device-width)
3 Chrome, Opera, BlackBerry 대체적으로 기능을 잘 지원하나, 버그에서 자유롭지 못함

2. 3가지 viewport

필요하면 2가지 viewport에 대한 기사를 다시 읽으래요. 이 내용읽을 때 필요하대요

최선의 viewport

디바이스마다 최선의 웹 페이지 크기를 주지만 최선의 viewport에 대한 시각은 디바이스마다 다르다

레티나급이 아닌 오래되거나 싼 디바이스 상에서 최선의 viewport는 화소(pixel)의 물리적 숫자와 동등하지만 필요조건은 아니다. 더 높은 화소를 가진 새로운 디바이스는 과거 이상적인 viewport를 유지해야 한다.

레티나든 아니든 4S까지 iPhone의 최선의 viewport는 320*480 이다. 이 크기는 그러한 iPhone들 상에서 웹 페이지를 위한 최선의 크기이기 때문이다.

이러한 viewport들 상에서 두 가지 중요한 점이 있다.

  1. layout viewport는 최선의 viewport 값으로 설정할 수 있다. width=device-width 지시자가 그러하다.
  2. 모든 크기 지시자는 최선의 viewport와 관련되어 있다. layout viewport의 width가 뭐든 관련되어 있지 않다. 그래서 maximum-scale=3는 최대 확대가 최선의 viewport의 300%라는 것을 의미한다.

최적의 viewport 크기 찾기

가끔씩 최적의 viewport크기를 읽을 수 있어서 유용하다.
페이지에 아래 태그를 적고 document.documentElement.clientWidth/Height 사용\

<meta name="viewport" content="width=device-width,initial-scale=1">

이 옵션이 아니면 최적의 viewport 크기를 알 수 없다.
또한 screen.width/height도 도움될 것임
그렇지만 오직 BlackBerry만 올바른 정보를 줄 뿐 다른 브라우저는 오락가락한다.

공개 질문: screen.width/height가 최적의 viewport 크기를 줄까?
Pro: 마지막 속성값은 유용한 값일 것이다.
Con: 디바이스 상에서 최적의 viewport 크기는 물리 화소와 동등할 필요는 없다.

호환가능한 최적의 viewport

test 최적의 viewport 크기
iPhone 320 X 480
iPad 768 X 1024
Android Samsung 400 X 640
Android HTC 360 X 640
Chrome 601 X 962
Opera Presto 240 X 320
BlackBerry 342 X 570
IE 320 X 480

슈뢰딩거 상태(맞지도 않고 틀리지도 않음), 값은 디바이스에 의존적, 그리고 모든 값은 분별 가능


test width=device-width
iPhone portrait
iPad portrait
Android Samsung yes
Android HTC yes
Chrome yes
Opera Presto yes
BlackBerry yes
IE yes

width=device-width는 layout viewport의 크기가 최적의 viewport 크기로 하는가?

Safari는 landscape와 portrait 모드에서 둘다 portrait width(320 or 768)가 적용


test initial-scale=1
iPhone yes
iPad yes
Android Samsung yes
Android HTC yes
Chrome yes
Opera Presto yes
BlackBerry yes
IE portrait

initial-scale=1는 layout viewport의 크기가 최적의 viewport 크기로 하는가?

IE10은 landscape와 portrait 모드에서 둘다 portrait width(320)가 적용


test screen.width/height
iPhone portrait
iPad portrait
Android Samsung no
Android HTC no
Chrome width
Opera Presto width
BlackBerry yes
IE no

screen.width/height는 최적의 viewport 크기를 주나?

  • safari는 항상 portrait이 최적의 viewport
  • Chrome과 Oprea는 width는 올바름에도 이용가능한 height를 준다
    • screen height - toolbar
      Android와 IE는 screen상 물리 화소수를 준다

3. layout viewport의 width

페이지를 렌더링 하기 전, 브라우저는 layout viewport가 얼마나 넓은지 알 필요가 있다. width: 20%가 계산되는 것 처럼 CSS 선언을 viewport를 기준으로 한다.

다른 지시 없이도 브라우져는 width를 고른다. 테스트 된 8개 중 6개에서 브라우져는 980px를 BlackBerry와 IE는 1024px 이었다. 이건 슈뢰딩거의 상태다. 브라우져는 단지 결정할 뿐이다.

viewport meta 태그에서 width: 400이거나 다른 숫자 값을 사용할 때 layout viewport의 width는 그 숫자로 설정된다. 우린 이미 알고 있다.

하지만, Android WebKit과 IE의 최소 width는 320px이다. 320px 미만으로 작아지면 최적의 viewport width로 돌아간다.

layout viewport와 최적의 viewport가 동등해질 때가 있다. 그건 width=device-width 이거나 initial-scale=1일 때 발생한다. 하지만 Safari와 IE10에 버그가 있고 initial-scale을 사용해 잡기 때문에 복작하지만 일반적인 규칙이다.

최대 그리고 최소 크기 (Minimum and maximum dimensions)

layout viewport의 최대크기는 10,000픽셀이다. 브라우저가 그 크기만큼 작게 (zoom out)하지는 못하기 때문에 그 숫자를 완전히 믿지는 못한다. 하지만 여전히 공식적으로 받아들인다.

layout viewport의 최소크기는 최적의 viewport의 1/10 정도이고 최대 zoom level이다. (즉, layout viewport는 결코 visual viewport보다 작아질 수 없다)

예외: Android WebKit과 IE는 결코 320px 미만으로 작아지지 않는다.

양립가능한 layout viewport

test Default layout viewport
iPhone 980
iPad 980
Android Samsung 980
Android HTC 980
Chrome 980
Opera Presto 980
BlackBerry 1024
IE 1024

meta viewport 태그 없이 layout viewport의 기본 크기(dimensions)

슈뢰딩거의 상태, 어떤 값이든 그렇게 된다.


test width=10000,minimum-scale=0.01
iPhone 10,000
iPad 10,000
Android Samsung 10,000
Android HTC 10,000
Chrome 10,000
Opera Presto 10,000
BlackBerry 10,000
IE 1024

최대 layout viewport의 width를 찾기 위해

10,000 이상 적용했을 때, 980px 기본으로 돌아온 Android Webkit을 제외하고 모든 브라우져는 10,000에 머무름.


test width=5
iPhone 64/96
iPad 154/205
Android Samsung incorrect
Android HTC incorrect
Chrome 120/192
Opera Presto 48/64
BlackBerry 68/114
IE incorrect

최소 layout viewport width 찾기 위해해…


4. zoom

줌은 교활하다. 이론상으로 간단하다. 줌 요소는 사용자가 zoom in, zoom out 할 수 있는 줌 요소를 결정한다. 문제는 두 가지다

  1. 줌 요소를 직접 읽어낼 수 없다. 대신 visual viewport의 width를 읽어 낼 수 있고 줌 요소와 정반대의 관계를 가진다. 줌 요소가 커질 때,

참고

quirksmode-viewport


* 참고자료


Written with Dec7.

[Servlet/Jsp] headFirst - Ch13 - filter, wrapper


0. 환경

macbook-pro 13” 2012 mid / 10GB
tomcat7
교재: Head First Servlet/Jsp, 한빛미디어, 2012


1. 학습목표

1) filter
2) wrapper


2. filter

필터는 자바 컴포넌트로서 서블릿으로 요청이 넘어가기 전에 요청을 가로채 어떤 처리를 진행

용도

  1. request filter
    • 보안관련 내용 확인
    • 요청헤더와 바디 포멧팅 수정
    • 요청 감시나 기록
  2. response filter
    • 응답 스트림 압축
    • 응답 스트림에 내용 추가 및 수정
    • 완전히 새로운 응답 생성

특징

  1. 필터는 모듈식으로 DD에 설정하고 실행 순서를 설정할 수 있음
  2. 필터가 데이터 형태를 변경하는 경우 그 순서를 지정할 수 있으나 그 의존성을 필터 내부에 삽입할 필요는 없음
  3. filter는 자신의 고유한 API를 가지며 Container는 filter의 API를 앎
  4. Container는 filter의 생명주기를 관리

Filter Interface

javax.servlet.Filter

public interface Filter {
    // init() 메소드는 반드시 구현
    // Container가 Filter를 인스턴스화 할 때 실행
    // Filter 호출 전 뭔가 설정할 것이 있는 경우 (일반적으로 FilterConfig 객체를 내부 field에 저장)
    public void init( FilterConfig ) throws ServletException;

    // 실제 filter를 구현
    public void doFilter ( ServletRequest, ServletResponse, FilterChain ) throws IOException, ServletException;

    // Conteriner가 Filter의 인스턴스를 제거할 때 호출 ( 삭제 전 수행할 코드 )
    public void destroy();
}

FilterChain Interface

  1. DD를 통해 filter의 순서를 지정할 수 있고 FilterChain이 다음에 실행할 filter를 판단함으로써 순차적 진행을 가능하게 함
  2. Filter.doFilter()와 다름
  3. FilterChain.doFilter()는
    • 다음에 호출할 filter가 무엇인지 파악하여 doFilter()를 실행
    • 체인의 마지막 filter인 경우 Servler의 service() 메소드 호출

javax.servlet.FilterChain

public interface FilterChain {
    public void doFilter ( ServletRequest, ServletResponse ) throws IOException, ServletException;
}

개념적인 스택 모델

  1. 요청이 들어오면 Filter A의 doFilter() 메소드 호출
    • doFilter() 메소드에서 FilterChain 인스턴스의 doFilter() 메소드를 만날 때까지 수행
  2. Conatiner는 Filter B의 doFilter() 메소드를 Stack의 제일 위에 쌓음
    • doFilter() 메소드에서 FilterChain 인스턴스의 doFilter() 메소드를 만날 때까지 수행
  3. Container는 Servlet A의 service() 메소드를 Stack의 제일 위에 쌓음
  4. Conatiner는 service() 메소드의 실행 완료시 Stack에서 제거
  5. Container는 Filter B의 doFilter() 메소드로 돌아옴
    • doFilter() 메소드에서 FilterChain 인스턴스의 doFilter() 이후의 로직을 수행
    • 이후 로직에서 response관련 작업
  6. Container는 Filter B의 doFilter() 실행 완료시 Stack에서 제거
  7. Container는 Filter A의 doFilter() 메소드로 돌아옴
    • doFilter() 메소드에서 FilterChain 인스턴스의 doFilter() 이후의 로직을 수행
    • 이후 로직에서 response관련 작업
  8. Container는 Filter A의 doFilter() 실행 완료시 Stack에서 제거
  9. Container는 응답 완료함

requset filter / response filter

// Filter를 구현한 Class 중..
// .
public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) {
    // 요청을 처리
    chain.doFilter ( request, response );
    // 응답을 처리
}
// .

3. request filter

실행 순서 지정

  1. url-pattern으로 일치하는 필터가 체인에 순서대로 들어감
    • 일치하는 모든 필터를 모두 체인에 넣고 실행
  2. 이후 servlet-name으로 일치하는 필터를 찾아 그 정의된 순서대로 체인에 등록
<web-app ...>
    <servlet> ... </servlet>

    <!-- filter-name, filter-class는 반드시 필요한 항목 -->
    <!-- init-param은 옵션 -->
    <filter>
        <filter-name>BeerRequest</filter-name>
        <filter-class>com.example.web.BeerRequestFilter</filter-class>
        <init-param>
            <param-name>LogFileName</param-name>
            <param-value>UserLog.txt</param-value>
        </init-param>
    </filter>

    <!-- filter-mapping 선언규칙 -->
    <!-- filter-name은 반드시 필요하며, filter 선언을 찾기 위해 필요 -->
    <!-- url-pattern, servlet-name 중 하나는 반드시 필요 -->
    <filter-mapping>
        <filter-name>BeerRequest</filter-name>
        <!-- url-pattern은 어떤 웹 어플리케이션 리소들에 필터를 적용할지 정의 -->
        <url-patterm>*.do</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>BeerRequest</filter-name>
        <!-- 필터를 적용할 웹 어플리케이션 하나를 정의 -->
        <servlet-name>AdviceServlet</servlet-name>
    </filter-mapping>
</web-app>

RequestDispatcher 요청시

forward, include, request dispatch, error를 통해 웹 리소스를 요청하는 경우에도 필터 적용 가능

<filter-mapping>
    <filter-name>MonitorFilter</filter-name>
    <url-pattern>*.do</url-pattern>
    <!-- dispatcher 항목을 0 .. 4까지 포함 가능 -->
    <!-- request는 client가 요청할 때 적용한다는 의미 -->
    <!-- dispatcher 항목이 없는 경우 request가 DEFAULT -->
    <dispatcher>request</dispatcher>
        그리고 / 또는
    <!-- include는 client가 포함될 때 적용 -->
    <dispatcher>include</dispatcher>
        그리고 / 또는
    <!-- forward는 client가 요청을 다른 곳으로 넘길 때 적용 -->
    <dispatcher>forward</dispatcher>
        그리고 / 또는
    <!-- error는 error 핸들러는 호출했을 때 적용 -->
    <dispatcher>error</dispatcher>
</filter-mapping>

4. response filter

심각한 문제점

  1. filter는 Servlet으로 request, response객체를 전달
    • Servlet에게 다시 response 객체를 전달받기를 기다림
  2. Servlet은 자신이 받은 인자가 filtering 되었다는 사실을 모름
    • 출력에 대한 제어는 Container가 가져감
    • Container는 결과를 Client에게 전달
  3. filter는 response 객체를 전달받기 위해 계속 기다림

해결책

4가지의 wrapper class를 사용하여 Response 객체를 새롭게 정의한 후 Servlet에게 전달
Servlet에서 새 Response 객체에 기록시 Client로 전달되기 전에 제어 가능


5. Wrapper

랩퍼 클래스는 현재 구현하려는 타입의 객체를 내부에 가짐
모든 메소드 호출을 위임할 동일한 타입의 클래스 객체에 대한 참조를 내부에서 가짐


Written with Dec7.

2014년 4월 6일 일요일

[Servlet/Jsp] headFirst - Ch5 - listener, attribute


0. 환경

macbook-pro 13” 2012 mid / 10GB
tomcat7
교재: Head First Servlet/Jsp, 한빛미디어, 2012


1. 학습목표

1) ServletContext 초기화 파라미터
2) 서블릿 속성 생존범위
3) 웹 컨테이너 요청 처리 모델
4) 웹 컨테이너 생명주기 이벤트 모델
5) ResquestDispacher 매커니즘


2. 서블릿 초기화 파라미터

  • 서블릿도 초기화 파라미터가 존재
  • Container가 서블릿을 초기화할 때 단 한번만 초기화 파라미터를 읽음
  • 이름/값 쌍이 ServletConfig안에 기록시 서블릿이 다시 배포되지 않는 한 DD를 수정해도 바뀌지 않음

실행 흐름

  1. Container는 DD를 읽음
  2. Container는 새로운 ServletConfig 인스턴스 생성 (서블릿당 하나씩)
    • 서블릿 생성자에서는 이 메소드를 호출할 수 없음
  3. Container는 init-param에 있는 값들을 이름-값 쌍으로 읽음
  4. Conatiner는 ServletConfig 객체에 이름-값으로 된 초기화 파라미터 설정
  5. Container는 XXXServlet.class 인스턴스 생성
  6. Container는 ServletConfig의 참조를 인자로 Servlet의 init() 메소드 호출

ServletConfig

초기화 파라미터에 접근할 수 있는 능력

javax.servlet.ServletConfig

public abstract interface ServletConfig {

    // context정보 (Servlet 설정정보)를 담고 있는 ServletContext를 반환
    public abstract ServletContext getServletContext();
    public abstract String getInitParameter(String);
    public abstract Enumeration getInitParameterNames();
    public abstract String getServletName();
}

DD (Web.xml)

<servlet>
    <servlet-name>Tests</servlet-name>
    <servlet-class>TestInitParams</servlet-class>

    <!-- DD의 <servlet>항목 안에 <init-param>으로 작성 -->
    <init-param>
        <param-name>adminEmail</param-name>
        <param-value>dec7@abc.com</param-value>
    </init-param>
</servlet>

Servlet 코드

// ServletConfig getServletConfig ();
// 모든 servlet은 상속받은 getServletConfig() 메소드를 가짐
out.println(getServletConfig().getInitParameter("adminEmail"));

3. 컨텍스트 초기화 파라미터

모든 웹 어플리케이션에서 이용할 수 있음 (JSP, Servlet)
ServletContext와 ServletConfig는 다른 객체로 다른 이름공간을 이용

실행흐름

  1. Container는 DD를 읽음
  2. 항목을 읽고 각각의 이름-값 쌍을 만듦
  3. Container는 ServletContext 객체를 생성
  4. Container는 생성한 컨텍스트 초기화 파라미터 이름-값에 대한 참조를 init() 인자로 전달
  5. Web Application에 있는 모든 Servlet과 JSP는 ServletContext에 접근 가능

ServletContext

javax.servlet.ServletContext

public abstract interface jServletContext {
  public static final String TEMPDIR = "javax.servlet.context.tempdir";
  public static final String ORDERED_LIBS = "javax.servlet.context.orderedLibs";

  public abstract String getContextPath();
  public abstract jServletContext getContext(String);
  public abstract int getMajorVersion();
  public abstract int getMinorVersion();
  public abstract int getEffectiveMajorVersion();
  public abstract int getEffectiveMinorVersion();
  public abstract String getMimeType(String);
  public abstract Set getResourcePaths(String);
  public abstract URL getResource(String) throws MalformedURLException;
  public abstract InputStream getResourceAsStream(String);
  public abstract RequestDispatcher getRequestDispatcher(String);
  public abstract RequestDispatcher getNamedDispatcher(String);
  public abstract jServlet getServlet(String) throws jServletException;
  public abstract Enumeration getServlets();
  public abstract Enumeration getServletNames();
  public abstract void log(String);
  public abstract void log(Exception, String);
  public abstract void log(String, Throwable);
  public abstract String getRealPath(String);
  public abstract String getServerInfo();
  public abstract String getInitParameter(String);
  public abstract Enumeration getInitParameterNames();
  public abstract boolean setInitParameter(String, String);
  public abstract Object getAttribute(String);
  public abstract Enumeration getAttributeNames();
  public abstract void setAttribute(String, Object);
  public abstract void removeAttribute(String);
  public abstract String getServletContextName();
  public abstract jServletRegistration.Dynamic addServlet(String, String);
  public abstract jServletRegistration.Dynamic addServlet(String, jServlet);
  public abstract jServletRegistration.Dynamic addServlet(String, Class);
  public abstract jServlet createServlet(Class) throws jServletException;
  public abstract jServletRegistration getServletRegistration(String);
  public abstract Map getServletRegistrations();
  public abstract FilterRegistration.Dynamic addFilter(String, String);
  public abstract FilterRegistration.Dynamic addFilter(String, Filter);
  public abstract FilterRegistration.Dynamic addFilter(String, Class);
  public abstract Filter createFilter(Class) throws jServletException;
  public abstract FilterRegistration getFilterRegistration(String);
  public abstract Map getFilterRegistrations();
  public abstract SessionCookieConfig getSessionCookieConfig();
  public abstract void setSessionTrackingModes(Set);
  public abstract Set getDefaultSessionTrackingModes();
  public abstract Set getEffectiveSessionTrackingModes();
  public abstract void addListener(String);
  public abstract void addListener(EventListener);
  public abstract void addListener(Class);
  public abstract EventListener createListener(Class) throws jServletException;
  public abstract descriptor.JspConfigDescriptor getJspConfigDescriptor();
  public abstract ClassLoader getClassLoader();
  public abstract void declareRoles(String...);
  public abstract String getVirtualServerName();
}

DD (Web.xml)

<servlet>
    <servlet-name>Tests</servlet-name>
    <servlet-class>TestInitParams</servlet-class>
</servlet>

<!-- 전체 어플리케이션을 위한 항목 / <web-app> 항목에 포함 -->
<context-param>
    <param-name>adminEmail</param-name>
    <param-value>dec7@abc.com</param-value>
</context-param>

Servlet Code

out.println ( getServletContext().getInitParameter("adminEmail") );

4. Listener

컨텍스트 초기화가 이루어질 때 파라미터를 읽은 뒤 특정 코드를 실행시키고 싶을 때

실행흐름

  1. Container는 DD를 읽음
    • context-param, listen
  2. Container는 Application에 공유할 ServletContext 객체 생성
  3. Container는 컨텍스트 초기화 파라미터의 이름-값 String쌍을 만듦
  4. Container는 String쌍을 ServletContext객체에 설정
  5. Container는 ServletContextListener를 상속받아 만든 Class를 인스턴스화 시킴
  6. Container는 contextInitialized()메소드를 호출하고 인자로 ServletContextEvent를 전달
    • ServletContextEvent 객체를 이용하여 ServletContext에 접근
    • ServletContext로 컨텍스트 초기화 파라미터 값을 읽음
  7. Listener가 ServletContextEvent에게 ServletContext에 대한 참조를 요청
  8. Listener가 ServletContext에게 초기화 파라미터의 값을 요청
  9. Listener는 초기화 파라미터를 이용해 객체를 생성
  10. Listener는 ServletContext.setAttribute(“newObj”, obj)를 이용하여 생성된 객체를 설정
  11. Container는 새로운 Servlet을 생성
    1. 초기화 파라미터로 ServletConfig 생성
    2. ServletContext에 대한 참조를 설정
    3. Servlet init() 메소드 호출
  12. Servlet은 요청을 받고 ServletContext에게

Written with Dec7.