Blog For Me

Django 스터디 4장. Django의 핵심기능

• tech and post

CH4. Django의 핵심기능

4.1 Admin 사이트 꾸미기

장고의 admin 사이트는 데이터베이스에 들어 있는 데이터를 쉽게 관리 할 수 있도록 데이터의 생성/조회/변경/삭제 등의 기능을 제공한다. ==프로세스의 기동/정지/조회 등의 프로세스 관리기능은 제공하지 않는다!==

4.1.1 데이터 입력 및 수정

레코드 상세보기 화면에서는

기능을 제공하고 있다.(설명은 생략)

4.1.2 필드 순서변경

필드 순서를 변경하고 싶다면 admin.py

class QuestionAdmin(admin.ModelAdmin):
    field = ['pub_date', 'question_text'] #필드 순서변경

admin.site.register(Question, QuestionnAdmin)
admin.site.register(Choice)

위처럼 QuestionAdmin 클래스를 ModelAmdin을 상속받아 정의해, field를 생성하고 admin.site.register()함수의 두 번째 인자로 등록하면 순서변경이 가능하다.

Oracle Synonym과 Grant

• tech and post

Oracle의 Grant와 Synonym에 대해 알아 보자.

AngularJS 공부하기 - Form model binding

• tech and post

Form model binding

이전시간에 AngularJs는 Double Binding을 이용해 model과 view의 동기화한다고 공부했다. 그래서 model이 수정되면 view도 수정되고, view가 수정되면 model이 수정된다고 했다. 그렇다면 view가 수정되었을때 어떻게 model에 결과를 반영할 수있을까? 사용자의 입력을 받을 수 있는 form 태그를 이용해서 model을 수정할 수 있다.

위와 같은 코드가 있다면, model에 어떻게 binding 할까

새롭게 등장하는 ng-model directives를 이용하면 할 수있다.

위처럼 ng-model을 각 요소에 지정하면 지정된 model의 변수로 select, checkbox, radio, textarea 와 같은 다양한 사용자 input들이 model로 binding된다.

<input ng-model="item.isAgree" type="checkbox" />

와 같은 ng-model 처럼 사용할 수있고, checkbox 의 경우 이 item.isAgree라는 property를 true/false로 셋하게 된다.

이번에는 짧게 마무리하고 다음시간에는 ng-submit을 이용해서 controller에 연결된 함수를호출 할 수 있는 방법에 대해 알아 보겠다.

To be continue..

resultMap - Extends attribute 사용

• tech and post

개발 중 발생하지 않은 에러가 발생하여 많은 시간 낭비를 한 케이스가 있어 공유하고자 한다.

ibatis 를 사용하던중(myBatis도 동일할 것이다) resultMapper를 구현하고 select 절의 result를 맵핑해서 사용하는 케이스가 있다.

이 때 resultMap의 attribute중 extends 가 있는데 이것은 기존의 resultMap을 재사용하는 케이스를 나타낸다.

예를 들어

<resultMap id="aaa" resultClass ="AAA">
     <result property="receiptSeq" column="receipt_seq"/>
     <result property="purchaseApplyMId" column="purchase_apply_m_id"/>
     <result property="draftDocNo" column="draft_doc_no"/>
     <result property="bizNpartnerId" column="biz_npartner_id"/>
     <result property="npartnerId" column="npartner_id"/>
     <result property="compId" column="comp_id"/>
     <result property="contractFlag" column="contract_flag"/>
     <result property="chargeEmpNo" column="charge_emp_no"/>
     <result property="contractNm" column="contract_nm"/>
     <result property="contractClassCd" column="contract_class_cd"/>
     <result property="startDay" column="start_day"/>
</resultMap>

와 같은 resultMap 이 존재하고

이것을 기본으로하는 확장 resultMap을 사용하고자 할때 사용하는 attribute이다. 마치 OOP의 상속 개념과 비슷하다고 할 수있다.

<resultMap id="bbb" resultClass ="BBB" extends="aaa">
     <result property="endDay" column="end_day"/>
     <result property="personalInfoOfferFlag" column="personal_info_offer_flag"/>
     <result property="contractKindCd" column="contract_kind_cd"/>
     <result property="slamContractId" column="slam_contract_id"/>
     <result property="slamContractNm" column="slam_contract_nm"/>
     <result property="privateContractFlag" column="private_contract_flag"/>
     <result property="privateContractReason" column="private_contract_reason"/>
     <result property="autoExtensionFlag" column="auto_extension_flag"/>

</resultMap>

라고 작성하면 실제로는 aaa와 bbb를 합친

<resultMap id="aaabbb" resultClass ="BBB" extends="aaa">
<result property="receiptSeq" column="receipt_seq"/>
     <result property="purchaseApplyMId" column="purchase_apply_m_id"/>
     <result property="draftDocNo" column="draft_doc_no"/>
     <result property="bizNpartnerId" column="biz_npartner_id"/>
     <result property="npartnerId" column="npartner_id"/>
     <result property="compId" column="comp_id"/>
     <result property="contractFlag" column="contract_flag"/>
     <result property="chargeEmpNo" column="charge_emp_no"/>
     <result property="contractNm" column="contract_nm"/>
     <result property="contractClassCd" column="contract_class_cd"/>
     <result property="startDay" column="start_day"/>
     <result property="endDay" column="end_day"/>
     <result property="personalInfoOfferFlag" column="personal_info_offer_flag"/>
     <result property="contractKindCd" column="contract_kind_cd"/>
     <result property="slamContractId" column="slam_contract_id"/>
     <result property="slamContractNm" column="slam_contract_nm"/>
     <result property="privateContractFlag" column="private_contract_flag"/>
     <result property="privateContractReason" column="private_contract_reason"/>
     <result property="autoExtensionFlag" column="auto_extension_flag"/> 
</resultMap>

와 같은 resultMap 이 완성되는 것이다.

AngularJS 공부하기 - Tab 컨트롤러로 분리하기

• tech and post

지난 시간 공부한 좋지 않은 코드

지난 시간에 AngularJs를 통해 tab을 만드는 것을 공부했다. 이전의 코드가 기억 나는가?

이 코드는 단순한 탭을 구현한다. 그런데 html과 script가 혼합된 이런 코드는 가독성과 유지보수성 측면에서 매우 비 효율적이다. 지금은 코드가 짧지만 만약 복잡한 로직이 들어가게 된다던가 길어지게 되면 가독성이 떨어지게 될 것이다. 이를 해결하기 위해 이번시간에는 이 코드에서 로직을 분리해 새로운 컨트롤러르르 만들어 볼 것이다.

Tab 컨트롤러 분리하기

우선 새로운 컨트롤러를 추가해 보자

app.controller("TabController", function() { });

위처럼 'TabControoler'라는 이름의 기본 컨트 컨트롤러를 생성한다. 이 컨트롤러를 template에 등록하고 현재 template에 들어있는 로직을 controller의 function에 method의 형태로 정의 해야한다.

초기값

우선 ng-init="tab=1" 으로 구현했던 초기 페이지 지정을 컨트롤러로 구현해보겠다.

app.controller("TabController", function() { 
    this.tab = 1;
});

위처럼 this.tab = 1;을 이용해 초기값을 지정할 수있다.

탭 클릭시 탭 번호 지정

<ul>
  <li> <a href ng-click="tab = 1"> First tab </a> </li>
  <li> <a href ng-click="tab = 2"> Second tab </a> </li>
  <li> <a href ng-click="tab = 3"> Third tab </a> </li>

</ul>

위의 코드에서 ng-click="tab = 1" 이 부분은 로직으로 tab = 1을 하나의 함수로 분리해 보자. ng-click="setTab(1)" 이렇게 변경 하고 controller에서 setTab(tabNum) 함수를 정의하면 효과적으로 텝 번호를 지정하는 로직을 관리할 수있다.

app.controller("TabController", function() { 
    this.tab = 1;
    this.setTab = function(tabNum) {
        this.tab = tabNum;
    };
} );

이렇게 구현하면 로직을 성공적으로 분리할 수있다.

탭 클릭 시 보이는 탭 변경

<div ng-show="tab === 1">
  <h4> First tab </h4>
  <p> AAAAAAAAAAAAAAA </p>
</div>
<div ng-show="tab === 2">
  <h4> Second tab </h4>
  <p> BBBBBBBBBBBBBBB </p>
</div>
<div ng-show="tab === 3">
  <h4> Third tab </h4>
  <p> CCCCCCCCCCCCCCC </p>
</div>

위에서 ng-show="tab ===1"도 역시 코드에 비교 로직이 포함되어있다. 이것을 이전 방법처럼 컨트롤러의 method로 분리해 보겠다.

AngularJS 공부하기 - 2way binding

• tech and post

이 내용은 아래의 문서를 번역한 내용임을 밝힙니다.

원본-https://docs.angularjs.org/guide/databinding

1. Data Biniding

Angular app에서 data-binding은 view와 model사이의 데이터 자동 동기화를 말한다. Angular의 data-binding구현 방법은 application의 single-source-truth(단일 데이터 소스) 정책을 따르도록 한다. view는 model의 투사일 뿐이다라는 말이다. 만약 model이 변하면 view역시 변할 수밖에 없다. 그 반대의 경우도 마찬가지 이다.

2. 기존 Template의 Data Binding

대부분의 template system 들은 오로지 한반향의로 data를 bind한다(template과 model을 병합해서 하나의 view를 만들어 내는방식이다). 병합이 이루어지고 난 이후에 model이나 template에 변화가 생기더라도 자동으로 view에 반영하질 못한다. 게다가 사용자가 view를 변화시키더라도 model값은 변하지 않는다. 이것은 개발자가 view와 model, model과 view의 순간적인 동기화를 위한 코드를 작성해야한다는 것을 의미한다.

3. Angular Template의 Data Binding

Angular Template은 위의 경우와 다르게 동작한다. template(HTML, markup, directives)은 브라우저에 의해 compile된다. 이 컴파일 과정에서 live view를 생성한다. view에 어떤 변화가 나타나면 이것 역시 model에 반영된다. 또한 model이 변화면 view에도 전파가 이루어진다(변화한다). model은 이 application의 single-source-of-truth 이다. 프로그래머는 매우 간단하게 model을 프로그래밍 할 수있다. 이것은 view를 단순히 model의 투영체로 생각할수있게 한다.

view가 단순히 model의 투영체이기 때문에, controller는 view와 완전하게 분리될 수있다. 그리고 view를 신경쓸 필요가 없다. 이 것은 controller가 view와 DOM/browser와 관련된 것들과 완전하게 분리됨을 의미하기 때문에 test를 하기에도 매우 용이하다.

AngularJS 공부하기 - Tab

• tech and post

오늘 공부할 내용은 TAB에 대해서 공부 해 보도록 하겠다.

TAB?

메뉴가 여러개 존재하고 각 메뉴에 따라 다른 내용이 출력되길 원할 때 우리는 흔히 TAB 이라고 불리는 컴포넌트(?)를 사용한다.

AngularJS 에서 기본Tab 구현

AngularJS에서는 expression을 이용해서 Tab을 편하게 개발할 수 있다.

위와 같은 방법으로 구현을 하면

ng-click="tab = 1"

이 부분에서 tab이라는 변수에 1을 할당해주는 것이 되고, {tab}} 이 표현식에 tab에 들어있는 숫자가 화면에 랜더링 된다.

이런것이 가능한 이유는 AngularJs는 2-way Data Biding을 하기 때문이다. 이 부분은 다음에 자세히 알아보도록 하겠다.

AngularJS 공부하기 - 다양한 Directives & Filter

• tech and post

지난시간에는 컨트롤러의 데이터를 HTML 문서에서 보여줄 수있는 Expression에 대해 공부했습니다. 또한 ng-show, ng-hide, ng-repeat와 같은 directive에 대해 공부했습니다. 오늘은 더욱 다양한 directive와 filter에 대해 고부해 보도록 하겠습니다.

Directives

지금까지 배운 Directives 는

  1. ng-app (HTML페이지에 angular App을 인식시킴)
  2. ng-controller (HTML페이지에 컨트롤러를 인식시킴)
  3. ng-show (해당 요소를 보일지를 결정)
  4. ng-hide (해당 요소를 안보일지르 결정)
  5. ng-repeat (Array의 각각의 item을 순회)

이상 5가지 입니다.

새롭게 추가된 directive는 ng-src 입니다.

위처럼 만약 object에 이미지 주소가 들어있을때 쓰이는 directive가 바로 ng-src 입니다.

AngularJS 공부하기(3)

• tech and post

지난 시간에는 AngularJs의 주요 개념 4가지에 대해 살펴보았고, HTML문서에서 어떻게 Angular를 불러오는지에 대해 공부 하였다.

이번시간에는 Controller에 대해 공부하도록 하겠다.

Controller란?

컨트롤러란 App이 실제로 행동하는 행동을 Function으로 구현한 것을 말한다.

(function(){
    var app = angular.module('myapp', [ ]);
    app.controller('SomeController', function() { 
        ~~~~~~~~~~~~~~ 
    });
})();

위와 같은 코드가 실행되면, app이라는 angularJs의 module에 'SomeController' 라는이름의 컨트롤러가 삽입되게 되고, 그 행동은 function()으로 구현된다.

AngularJS 공부하기(2)

• tech and post

이내용은 codeschool(http://codeschool.com) 내용에 따라 공부하면서 정리한 글입니다. (전문가가 아니기 때문에 깊이있는 지식이아닙니다. 또한 잘못된 정보가 있을 수 있으니 잘못된 정보는 댓글로 알려주시면 수정해 나가도록 하겠습니다.)

이전 시간에 AngularJS의 기본개념과 사용이유 등 간단한 정보에 대해 공부했다면 이제는 실제로 웹페이지에 어떻게 적용되는지 알아보도록 하겠다.

angularjs에서 중요한 개념이 4가지가 존재한다.

  1. Directives

  2. Modules

  3. Controllers

  4. Expressions

AngularJs Study(1)

• tech and post

code school(https://www.codeschool.com/paths/javascript#angular-js)로 AngularJS를 공부한 내용을 정리해 본다.

IBATIS에 LIST 파라미터 넘기고 구현하기

• tech and post

ibatis SQL mapper를 작성하는 중 LIST를 파라미터로 넘겨야하는 상황이되었다.

조사한 내용을 기족해 본다.

GIT 잘못된 머지방법

• tech and post

GIT을 이용한 개발 중 Merge의 실수로 큰 어려움을 겪었다.

이 글을 보는 개발자라면 이러한 머지 방법은 지양하는 것이 좋을것이다.

사건은이러하다.

develope의 branch에 A 개발자는 자신의 개발중인 코드를 merge했다.

B는 develope에서 브랜치를 새로 만들고, 자신의 코드를 개발하여 커밋하였다.

그리고 이 커밋을 master에 merge하게된다. 그런데 이때 B는 A의 코드가 master에 머지되는 것을원치 않아 의도적으로 A의 코드를 삭제하고 merge를 했다. (이후 A가 코드를 merge하면 아무 문제가 없을것이라 착각하고..)

하지만 A가 자신의 코드를 master에 merge하려고 할때, merge할 커밋에 A의 코드가 정상적으로 나오지않는다. 그 이유는 이미 B의 이전 merge시점에서 A의 코드를 지워버렸기 때문에이다. A가 merge하려는 코드가 B가 merge한 시점의 이전의 버전이라면 A가 지워버린 것이 그대로 반영된다. 결과적으로 A의 코드가 정상적으로 master에 merge할 수 없게 된다.

이것을 해결하는 방법은 여러가지가 있을 수 있다. 내가 시도했던 방법은 아래 두가지있다.

1.revert 기능의 이용 - 잘못된 커밋을 revert시키고 다시 commit하기

2.merge시점 이전의 브랜치에서 새로운 branch 를 생성하고 이후 시점의 commit을 cherrypick으로 merge 한다.

2번방법을 이용해 이번 문제를 해결했다. 단순한 merge가 가능한(새로운 브랜치를 생성하기 이전에 생성된 브랜치) branch는 merge를 하면되지만, 그렇지않은(새로운브랜치를 생성하기 이후에 master에서 생성된 branch의 경우는 나의 잘못된 커밋을 포함하고있다) 브랜치는 변경이력들만 따로 cherrypick이 필요하다.

위의 방법을 통해 식은땀나는 상황을 해결 할 수있었다.

결론 : merge시점에 자신이 프로그래밍하지 않은 코드에 대해서는 unstaging하면 큰일이 발생한다.

ORACLE의 MERGE SQL

• tech and post

오라클 기반의 서비스를 운영하는 중 큐브리드나 MySql에서 보지 못한 문법을 발견하게되었다. 그래서 한번 찾아보고 사용법에 대해 정리해 보았다.

ibatis $preferredOrder$, #value# 의 차이

• tech and post

ibatis로 개발을 하는중에 controller에서 넘어오는 값이 '$'로 감쌓지는 경우와 '#'로 감쌓지는 경우를 보게되어, 두개의 차이점을 찾아 보게 되었다.

$preferredOrder$는 이곳에 들어오는 문자열 그대로 query문이 만들어진다.

예를 들어

SELECT * FROM table1 WHERE col1 = '$whereClaus$';

이라는 쿼리를 mapper에 작성했다고 가정하자. 그리고 whereCond라는 변수(맵객체의 키가 whereCond인 경우 포함)에 "kim" 이라는 문자열이 들어있다면, 위의 쿼리는

SELECT * FROM table1 WHERE col1 = 'kim'

이라는 쿼리가 완성되어 실행될 것이다.

SQL에서 CONNECT BY 와 START WITH의 활용

• tech and post

SQL문중 특이한 SQL 문이 존재한다.

CONNECT BY와 SATRT WITH 문이 그것이다. 이 구문은 ORACLE DB에 존재하던 구문으로 CUBRID에서도 지원하고 있다.

이 구문을 사용하는 때는 하나의 디비에 계층형으로 이루어진 DB를 다루는데 유용한다.

예를 들어

| id | name | upper_id | | 1 | 자동차 | 0| | 2 | 바퀴 | 1| | 3 | 고무 | 2|

와 같은 형태의 DB 가 존재한다고 할 때, 고무의 상위 항목은 바퀴이고 바퀴의 방위 카테고리는 자동차이다

자동차가 바퀴를 포함하고 바퀴는 고무를 포함하는 관계를 하나의 DB로 표현하면 이러한 식으로 표현이 가능하다. (이러한 구조를 순환관계 테이블이라고도 부른다.)

위 순환관계 테이블에서고무를 조회할때 고무가 포함되는 상위 카테고리를 알고 싶을때, CONNECT BY와 START WITH를 사용하면 효과적으로 조회할 수있다.

SELECT name 
  FROM mydb
START WITH upperId = 0
CONNECT BY PRIOR id = upper_id

라는 구문을 사용하면 계층화된 db를 접근이 가능하다.

START WITH 구문은 계층화된 구조의 루트노드를 지정하기 위해 사용된다. CONNECT BY PRIOR절은 부모와 자식노드간의 관계를 설정하기 위해 사용되었다. 특히 PRIOR 은 upper_id가 아닌 id앞에 붙어야한다. 부모노드의 id와 현재 노드의 upper_id간의 관계설정을 위해 부모 노드의 id에 PRIOR 을 지정해야한다.

또한 특정 조건의 열에대해서 필터링을 위해서는 FROM과 START WITH사이에 WHERE 절을 삽입 할 수있다.

SELECT name
  FROM mydb
 WHERE id = '1'
START WITH upperId = '0'
CONNECT BY PRIOR id = upper_id

위와 같은 절이 가능하다. 절의 실행 순서는 START WITH -> CONNECT BY PRIOR -> WHERE 임을 유의해야한다.

또한 connect by는 잘못된 구조의 DB에서 잘못사용하는 경우 무한루프가 발생할 수있다. 이때 connect by prior은 에러를 발생시키지만 connect by nocycle prior 을 사용하면 에러가 나지않고 처리할 수있다.

javascript에서 문자열 replaceAll하기

• tech and post

자바에서 문자열 함수 중 replaceAll() 함수가 존재한다. 이것은 문자열 내의 하나의 문자를 모두 찾아서 원하는 문자로 바꿔주는 기능을 한다. 자바스크립트에서도 당연히 존재할 줄 알았던 이 기능이 없다는 사실에 당황했다.

하지만 이와 동일한 기능을 수행하게 할수있다!

어떻게?

HTML INPUT 태그의 콤마가 포함된 STRING의 SPRING에서의 파라미터 바인딩

• tech and post

프로그래밍 중 이상한 현상을 경험했다. Spring 프레임웍으로 서비스중인 웹어플리케이션의 input 태그의 value에 "123,444,555" 처럼 숫자와 컴마로 구성된 값을 컨트롤러로 전송했다. 이 값을 바인딩 하는 VO의 변수 타입이 String[] foo이었고, 이때 내가 의도한 것은 foo[0]="123,444,555" 가 assign되길 기대했다. 그런데 바인딩 결과는 foo[0] = "123", foo[1] = "444", foo[2] = "555" 로 하나의 배열로 변수에 할당되었다. 그 이유가 궁금해 조사해 보았다.

이유는 스프링에서 기본으로 제공하는 바인더가 이런 기능을 포함하고 있기 때문이다. 참고

위의 링크에 따르면 Spring의 기본 property editor가 ','를 포함한 스트링에 대해 배열로 처리하게 되어있다.

리퀘스트가 들어오면 3가지 과정으로 동작한다.
1. 파라미터 타입의 오브젝트 생성
2. 웹파라미터 바인딩
3. validation

세개의 과정을 거치는중 binding하는 과정이 있다. 이 때 프로젝에서 별도의 binder를 지정해주지않았기 때문에 Spring의 기본 property eiditor를 사용했고, 원하지 않은 방법으로 바인딩이 이루어졌던 것이다. 이를 해결하기 위해 별도의 binder를 지정해 주므로서 해결이 가능하다. 바인딩하는 방법에는 두가지가 있다. xml을 통해 resolver를 지정해 주거나, initBinder 함수와 annotation 을 사용하는 방법이다. 내가 처리했던 방법은 컨트롤러를 수정하기 보다 front에서 넘어 오는값에서 ','를 제거하는 방법을 택했다(이유는 db에 저장될때 다시 ,가 제거되어야 하기때문에 두번의 과정을 거치는 것보다 효율적이라 생각했기 때문이다)

이 관련된 것을 조사하는중 url파라미터와 modelAttriubte 가 처리되는 handler의 차이가 있다는 것을 알게 되었고 이다음에 이부분에 집중 분석해 봐야할 필요성을 느꼈다.

tomcat6 에서 tomcat7 migration 하기

• tech and post

현재 사용하고 잇는 tomcat 6.0.x 버전을 더 높은 버전의 tomcat으로 migration 하기 위해 필요한 내용이다. 이 글은 http://tomcat.apache.org/migration-7.html 사이트의 내용을 정리한 것임을 밝힌다.

http://tomcat.apache.org/migration.html 페이지에 내용을 통해 다른 버전의 migration을 확인할 수 있다.

6.0.x에서 7.0.x 로 migration하기

Java 6

Servlet 3.0 API

정규식(Regular expressions)

배포(Deployemnt)

관리 어플리케이션(Manager Application)

호스트 관리 어플리케이션(Host Manager Application)

권한(role)들은 단일 admin권한에서 아래처럼 두개의 권한으로 분리된 호스트 관리 어플리케이션을 사용해야햔다. 사용자는 기능적으로 필요한 역할을 할당해야한다. * amdin-gui - HTML GUI와 상태페이지 접근을 허용한다. * admin-script - text 인터페이스와 상태페이지 접근은 허용한다. HTML 인터페이스는 CSRF에 대해 보안이 되어있지만 text 인터페이스는 그렇지 않다. CSRF 보안을 위해 아래를 따라라. * admin-gui 권한을 가진 사용자는 admin-script 권한을 가져서는 안된다. * admin-script권한을 가진 사용자가 브라우저를 통해 접근하는 경우세션이 종료되고난후 반드시 브라우저를 종료해야한다.

세션 관리 설정

세션관리에 많은 변화가 있었다. 이것은 세션을 생성되고 제거할때 또는 세션의 아이디생성하는 성능을 향상하기 위해 이루어졌다. 세션 아이디 생성의 변화는 java.secure.ScureRandom을 사용하면서 변화했다. 설정의 변화는 이렇다. * Manager의 randomClass 속성은 secureRandomClass로 바뀌었고, 제공되는 클래스는 반드시 java.secure.SecureRandom을 확장해야한다. * secureRandomAlgorithm과 secureRandomProvider의 두개의 새로운 property들은 ScureRandom의 구현선택을 활성화하기 위해 추가되었다. * algorithm 속성은 제거되었다. * entropy 속성은 제거되었다.

java.secure.SecureRandom과 관련된 이슈중 하나는 이것의 초기화시 entropy 소스에 있는 임의(random)의 데이터를 요구하는 것이다. 어떤 entorpy 소스 구현에서는 임이의 데이타를 모으는데 어느정도 시간이 걸릴 수있다. 만약 세션아이디 생성의 초기화가 100ms 이상의 시간을 사용한다면 아래의 진단 메시지가 로그에 나타날 것이다. ex: DATE org.apache.catalina.util.SessionIdGenerator createSecureRandom INFO: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [406] milliseconds.

JRE를 통해 entropy 소스를 바꾸는 것이 가능하다. (ex : -Djava.security.egd=file:/dev/./urandom)

세션쿠기 설정(Session cokie configuration)

Servlet 3.0 스펙에서 SessionCookieConfig가 추가되면서 코드의 복잡도를 낮추기위해 많은 수의 쿠키설정 옵션이 제거되었다. * Connector.emptySessionPath: 이 옵션은 제거되었다. 글로벌 context.xml(CATALINA_BASE/conf/context.xml)의 sessionCokiePath="/"설정을 동일한 기능이 가능하다. * org.apache.catalina.SESSION_COOKIE_NAME 시스템프로퍼티: 이 옵션도 제거되었다. 글로벌 contex.xml 파일의 sessionCookieName 설정을 통해 동일한 기능이 가능하다. * org.apache.catalina.SESSION_PARAMETER_NAME 시스템프로퍼티: 이 옵션도 제거되었다. 글로벌 contex.xml 파일의 sessionCookieName 설정을 통해 동일한 기능이 가능하다. * Context.disableURLRewriting: 이 옵션도 제거되었다. 웹어플리케이션이나 CATALINA_BASE/conf/web.xml 파일의 session-config/tracking-mode 요소를 설정함으로써 동일한 기능이 가능한다.

Tomcat7에서 세션과 SSO 쿠키는 기본값으로 HttpOnly플래그가 셋팅되어 보내진다. 이것은 자바스크립트로가 접근하는것을 막기위해 브라우저에게 지시하는 것이다. 이는 더 안전한 방법이지만, 자바스크립트가 쿠키의 값에 접근하는 것을 방지한다. 이 기능은 Context 요소의 useHttpOnly 속성을 통해 조절된다.(이미 Tomcat6.0의 마지막 버전에서도 구현이 되어있지만 기본적으로 false로 설정되어있다. 이를 사용하기위해서는 CATALINA_BASE/conf/context.xml 파일의 useHttpOnly="true"를 설정함으로써 사용가능하다)

쿠기(Cookies)

톰캣은 기본적으로 스펙을 준수하지않은 이름만 쿠키인 것들은 더이상 수용하지 않다. 그러나 새로운 시스템 프로퍼티가 추가되었다. org.apache.tomcat.util.http.ServerCooki.ALLOW_NAME_ONLY 는 이러한 쿠키를 수용할 수있게 한다.

요청 속성(Request attributes)

커스텀 request속성 javax.servlet.request.ssl_session(새로운 표준 request 속성을 위해 제거되었다. servlet 스펙문서의 javax.servlet.request.ssl_session_id에서 확인가능하다) 은 SSL 세션아이디에 접근하기 위해 제공된다. 커스텀 request속성은 tomcat8에서 제거될 것이다.

Comet

코맷 클래스가 org.apache.catalina package 에서 the org.apache.catalina.comet package 으로 옮겨졌다. 코맷을 사용하는 코드는 새로운 패키지 이름을 반영하여 재 컴파일 해야한다.

XML 검증(validation)

XML 검증 설정이 간편해 졌다. xmlValidation과 xmlNamespaceAware 속성이 Host요소에서 제거됐다. 이 속성들은 tldValidation과 tldNamespaceAware와 같이 Context 요소마다 설정된다. 기본설정(fales) 은 바뀌지 않았다. 그러나 Servlet의 스펙에 의하면, 만약 org.apache.catalina.STRICT_SERVLET_COMPLIANCE 스스템 프로퍼티가 true로 설정 되어있다면 XML 검증과 namespace 인지가 초기값으로 활성화될 것이다.

시스템 프로퍼티

org.apache.catalina.STRICT_SERVLET_COMPLIANCE 시스템 프로퍼티가 수정되었다. 각각의 변화는 해당하는 시스템 프로퍼티에 의해 조절된다. 기본적인 행위는 변화지 않았다. 이제 org.apache.catalina.STRICT_SERVLET_COMPLIANCE 시스템프로퍼티는 spec 준수 기본값이 다른 시스템 프로퍼티에서 사용되는지 아닌지를 주절한다. 만약 org.apache.catalina.STRICT_\SERVLET_COMPLIANCE이 true라면 개별적인 시스템 프로퍼티보다 언제나 우선시 된다. org.apache.coyote.MAX_TRAILER_SIZE는 제거됐다. 그리고 Connector의 maxTrailerSize가 이를 대체한다.

conf/web.xml 파일의 처리

Servlet 3.0 spec은 어플리케이션의 web.xml 파일이 어떻게 web fragments와 annotations를 조합하는지 정의한다. 서버전반의 기본값을 정의 하는 conf/web.xml파일의 처리는 이런 rule 구현의 결과로 변했다. 주목할만한 변화는 글로벌 conf/web.xml에 정의된 필터가 이제는 web application의 web.xml을 따른다는 점이다.

Welcom 파일 처리

welcome파일의 처리는 Servlet 3.0 spec의 설명을 따르도록 변했다. 만약 welcome 파일들의 리스트에 servlet에 의해 처리되는 파일(예를 들어 *.jsp)이 추가되어있을 경우 변화된 행위를 관측할 수 있다. Context 의 resourceOnlyServlets 을 보길바란다.

Annotation 스캐닝

Annotation 스캐닝은 웹어플리케이션의 startup 시간에 영향을 미친다. 또한 클래스의 스캔에 필요한 메모리 양도 늘어난다. Servlet 2.4와 그 이전버전을 스캔을 사용하는 어플리케이션은 이점을 유의해야한다. 이 이슈를 다루는 여러방법이 있다. 추천하는 방법은 이러한 어플리케이션들은 annotation스캐닝을 요구하지않는다고 마크하는 것이다. WEB-INF/web.xml 파일에서 아래의 절차로 가능하다. * web-app 요소에 웹어플리케이션이 사용하는 spec의 버전이 3.0이 되도록 바꿔라. 이것은 기본 conf/web.xml파일에서 version. xsi:schemaLocation, xmlns, xmlns:xsi 속성을 복사할 수 있다. * metadata-compete="true" 속성을 web-app 요소에 추가하라. * 속성을 추가하라. metadata-complete 속성은 Servlet 2.5 스펙부터 지원하기 시작했다. absolute-ordering은 Servlet 3.0을 요구한다.

두 번째 방법은 JarScanner 컴포넌트가 특정 JAR파일(이름에따라)을 무시하도록 설정하는것이다. 이것은 보통 conf/catalina.properties파일에서 설정한다. System properties챕터의 jarsToSkip을 확인하라. Tomcat 7.0.30을 시작으로 Servlet 3.0에서 JARs 스캐닝(annotation과 웹어플리케이션 fragment)과 TLD 스캐닝(tag 라이브러리들)에서 분리시켜서 스킵하는 설정하는것이 가능하다. 톰캣의 이후 버전은 더욱 나은 방법을 제공할 것이다.

TLD 처리

TLD처리에서 많은 향상이 있었다. 게다가 일관성을 향상하고 중복을 제거하기 위해 내부적인 리펙토링을 했고, 많은 기능적인 향상이 있었다. * 이제는 태그 파일의 EL 처리가 태그파일에 선언된 JSP 버전과 일괄성이 있게 되었다. * JSP 스펙의 JSP 7.3.1의 요구사항이 이제는 강요된다. 그리고 TLD파일들은 WEB-INF/lib 나 WEB-INF/classes 위치에 존재하는것이 허용되지 않는다.

내부 API들(Internal APIs)

Tomcat 7 내부 API들이 대부분이 Tomcat 6과 호환하지만 세부적인 수준에서 많은 변화가 있었다. 때문에 바이너리(binary)호환은 하지 않느다. Tomcat의 내부 API를 사용하는 커스텀 컴포넌트의 개발자는 관련된 API의 JavaDoc을 확인하길 바란다.

특히 주의할 점은 * 모든 컴포넌트들이 확장하고 있는 Lifecycle interface의 표준구현 * 제네릭의 사용 * Host conntext의 유일한 식별자로서의 Context path를 사용하기보다 Context의 이름의 직접 사용의 경우

JSP 컴파일러

성능 최적화의 하나를 컨트롤하는 JspServlet의 초기화 파라미터의 이름이 genStrAsCharArray에서 genStringAsCharArray로 바뀌었고 Apache Ant의 Jasper Task의 관련된 속성의 이름과 일관된다.

7.0.x 로 업그레이드 하기(Upgrading 7.0.x)

Tomcat 7.0.x의 주목할만한 변화

Tomcat개발자는 완벽하게 이전 버전화 호환하게 패치를 릴리즈 하려고 한다. 때때로, 버그를 고치기위해 이전 버전과의 호환성을 지키지 못하는 경구가 있다. 대부분의 경우 이런 변화는 간과된다. 이 섹션은 이전버전과 완벽히 호환되지 않고 업그레이드 할때 충돌이 있을수 있는 변화를 나열한다. * 7.0.51 이후에는 웹어플리케이션 클래스 로더가 시스템 클래스 로더보다 클래스를 로딩하는데 높은 우선권을 가진다.

Tomcat 7.0.x 설정 파일의 차이점들

Apache Tomcat 의 인스턴스를 7의 한버전에서 7의 다른 버전으로 업그레이드할때(특별히 분리된 $CATALINA_HOME 과 $CATALINA_BASE를 를 사용하는 경우), 새로운 설정들이나 적용되는 기본값이 달라지는 설정파일을 확인해야한다. 이것을 보조하기 여기의 맨 아래 폼을 참고하길 바란다.

tomcat과 apache 연동하면서 겪은 애로 사항

• tech and post

Tomcat과 Apache 웹서버를 직접 설치하면서 겪은 어려움과 해결법을 나열해 보겠다. Linux CentoOS 6.6, jdk 1.8, Tomcat 8.0, Apache HTTP 웹서버 2.4.9 버전을 이용했다.

  1. jdk 버전 바꾸기 /etc/alternatives라는 명령어를 이용해 여러버전의 JDK가 설치되어있는 환경의 Default JDK 변경할 수 있다. 처음 할당받은 서버에 이미 JDK 1.6이 설치가 되어있는 상황이었는데, JDK 1.8을 사용해야하는 상황이었기 때문에 어떻게 변경할 수있을지 고민이 많았다. alternatives라는 명령을 이용해 해결할 수 있었다.

    • alternatives --install /usr/bin/java java /user/wh/jdk1.6.0_35/bin/java 100 ## JDK를 변경가능한 리스트에 추가한다.
    • alternatives --config java ## 이 옵션을 이용하면 멋진UI(?)를 통해 변경이 가능하다. 이뿐만 아니라, 명령어를 직접 입력하는 방법이 있는것같으나(사실 이렇게 해결했는데 어떻게 했는지 검색해도 도통 찾을수가 없다.) 이방법이 훨씬 편리하고 간단하다.
  2. apache build 시 에러1 apache 빌드시 ./configure --prefix=/usr/local/apache2 --enable-all
    --enable-so --with-included-apr --with-mpm=prefork 이런 명령으로 configure을 하게 된다. 이때 이전 단계에서 apr과 apr-util의 위치를 잘못 지정해 주는 바람에 빌드가 되지 않아 많은 삽질을 햇다.

  3. apache build 시 에러2 빌드를 준비하는 과정에서 yum install make gcc gcc-c++ autoconf automake libtool pkgconfig findutils 이런 명령어를 인테넷에서 그래도 썼는데 저중 어디선가 제대로 설치가 되지 않아서 무엇인가 찾을 수 없다는 메세지를 보았다. 하나하나 꼼꼼히 다시 설치해서 해결했다. 그리고 jk_mod를 컴파일하는 과정에서 apxs의 경로를 설정해주는데 이것은 /usr/local/bin 폴더에 pcre라는 파일이 존재하느데, 이곳으로 경로를 지정해줘야 성공적으로 빌드가 된다.

  4. tomcat과 apache의 권한 문제... 이것은 아주 특수한 케이스일 수 있다(우리 사내에서만 해당) su(root를 위임한)계정과 그렇지 않은 계정을 이용해 apache와 tomcat을 설치하게 되는데.. 두개를 모두 su계정으로 설치했더니 tomcat이 동작하지않는 문제가 생겼다. 이것은 어떤 이유인지 정확히 모르겠으나(알아보겟다!!!) tomcat을 su계정이 아닌 계정으로 설치했더니 해결되었다.

  5. connector설정 문제.. tomcat과 apache를 연동하기 위해 connector를 설치했는데 apache의 http.conf파일로 jk_mod 무듈을 로드하고 virtual host를 지어해야하는 설정이 필요하다. 아직 http.conf파일의 구조와 기능(특히 virtualhost)에 대해 지식이 부족하여 많은 공부가 필요하다. 일단은 인터넷에 있는 가이드를 참고하여 진행했다.

was와 웹서버의 차이 – 톰캣과 아파치를 구별하지 못하는 사람을 위해

• tech and post

평소 tomcat과 apache를 잘 구분하지 못하여 공부한 내용을 정리해 본다.

아파치 톰캣을 이용해서 웹서버를 띄우고 개발을 진행해왔다. 그런데 실제 일을 하면서 서버를 실핼할때 단순히 tomcat만 쓰는게 아니라 apache라는 프로그램을 별도로 실행하는 것에 혼란이 왔다. 그리고 평소에 apache tomcat은 그렇다면 두개의 프로그램을 합쳐놓은 것인가를 고민하게 되어 정리해 보았다.

apache 란?

apach란 것은 소프트웨어 단체 이름이다. 그리고 우리가 흔히 부르는 아파치서버라는 것은 이제단에서 후원하는 오픈소프 프로젝트 커뮤니티에서 만든 http웹서버를 지칭하는 말이다. (아파치 프로젝트는 웹서버 외에도 여러가지 프로젝트를 진행하고 있다고 한다. 이건 추후에 조사해볼것이다.) http 웹서버는 http 요청을 처리할 수 있는 웹서버이고, 아파치 http서버는 http요청을 처리하는 웹서버인 것이다. 클라이언트가 GET, POST, DELETE 등등의 메소드를 이용해 요청을 하면 이 프로그램이 어떤 결과를 돌려주는 기능을 한다. 아파치는 웹서버 이다!

tomcat 이란?

tomcat은 흔히 WAS(Web Application Server)라고 말한다. WAS는 웹서버와 웹 컨테이너의 결합으로 다양한 기능을 컨테이너에 구현하여 다양한 역할을 수행할 수 있는 서버를 말한다. 클라이언트의 요청이 있을 때 내부의 프로그램을 통해 결과를 만들어내고 이것을 다시 클라이언트에 전달해주는 역할을 하는 것이 바로 웹 컨테이너 이다. 앞에서 본 아파치 웹 서버와 차이는 이 컨테이너 기능이 가능하냐의 차이가 가장 크다고 생각한다. was구조 이미지출처 : http://gap85.tistory.com/45

WAS역시 웹 서버로써 역할을 수행할 수 있기 때문에 둘을 잘 구별하지 못하면 필자 같은 혼란이 생길 수 있다.

둘의 차이는?

그렇다면 WAS만 쓰면 되지 어째서 웹서버를 따로 쓰느냐는 의문이 생길 수 있다. 그 이유는 목적이 다르기 때문이다. 웹 서버는 정적인 데이터를 처리하는 서버이다. 이미지나 단순 html파일과 같은 리소스를 제공하는 서버는 웹 서버를 통하면 WAS를 이용하는 것보다 빠르고 안정적이다(왜? 다른 글 소스로 써볼까?) WAS는 동적인 데이터를 처리하는 서버이다. DB와 연결되어 데이터를 주고 받거나 프로그램으로 데이터 조작이 필요한 경우에는 WAS를 활용 해야 한다.

기타(리눅스에서 설치 및 연동하기)

두 서버의 목적의 차이 때문에 두 개의 서버를 연동해서 사용하면 더욱 효과적인 서비스를 제공할 수 있다. 사용자 요청은 http 웹 서버를 통해 받고 내부 프로그램은 was를 통해 처리하는 식으로 한다면 정적인 데이터와 동적인 데이터를 효과적으로 처리가 가능할 것이다.

연동에 관련된 부분은 정리가 이곳을 보고 참조해보길 바란다. tomcat 과 apache 연동하기

Welcome to Jekyll!

• jekyll and update

You’ll find this post in your _posts directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run jekyll serve, which launches a web server and auto-regenerates your site when a file is updated.

To add new posts, simply add a file in the _posts directory that follows the convention YYYY-MM-DD-name-of-post.ext and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works.

Jekyll also offers powerful support for code snippets:

def print_hi(name)
  puts "Hi, #{name}"
end
print_hi('Tom')
#=> prints 'Hi, Tom' to STDOUT.

Check out the Jekyll docs for more info on how to get the most out of Jekyll. File all bugs/feature requests at Jekyll’s GitHub repo. If you have questions, you can ask them on Jekyll’s dedicated Help repository.