2009-07-15

웹 브라우저 버전 체크

클라이언트나 서버 프로그래밍에서 사용자 웹 브라우저 정보를 알아야 하는 경우가 있다. 이를 위한 방법이다.


자바 스크립트에서는 아래 함수를 사용한다.

function getBrowser() {
  var agent = navigator.userAgent;
  var result = "unknown";
  if (agent == null) {
  } else if (agent.indexOf("MSIE 6.0") > -1) {
    result = "ie6";
  } else if (agent.indexOf("MSIE 7.0") > -1) {
    result = "ie7";
  } else if (agent.indexOf("MSIE 8.0") > -1) {
    result = "ie8";
  } else if (agent.indexOf("Firefox") > -1) {
    result = "firefox";
  } else if (agent.indexOf("Opera") > -1) {
    result = "opera";
  } else if (agent.indexOf("Chrome") > -1) {
    result = "chrome";
  } else if (agent.indexOf("Safari") > -1) {
    result = "safari";
  }
  return result;
}


자바에서는 아래 메소드를 사용한다.

package com.dimdol.util;

import javax.servlet.http.HttpServletRequest;

public final class WebUtils {

  private WebUtils() {
  }

  public static String getBrowser(HttpServletRequest request) {
    String agent = request.getHeader("User-Agent");
    String result = "unknown";
    if (agent == null) {
    } else if (agent.indexOf("MSIE 6.0") > -1) {
      result = "ie6";
    } else if (agent.indexOf("MSIE 7.0") > -1) {
      result = "ie7";
    } else if (agent.indexOf("MSIE 8.0") > -1) {
      result = "ie8";
    } else if (agent.indexOf("Firefox") > -1) {
      result = "firefox";
    } else if (agent.indexOf("Opera") > -1) {
      result = "opera";
    } else if (agent.indexOf("Chrome") > -1) {
      result = "chrome";
    } else if (agent.indexOf("Safari") > -1) {
      result = "safari";
    }
    return result;
  }

}

Ruby on Rails에서는 아래 함수를 사용한다.

module ApplicationHelper

  def get_browser
    agent = request.env['HTTP_USER_AGENT']
    result = "unknown"
    if agent.nil?
    elsif agent.include?("MSIE 6.0")
      result = "ie6"
    elsif agent.include?("MSIE 7.0")
      result = "ie7"
    elsif agent.include?("MSIE 8.0")
      result = "ie8"
    elsif agent.include?("Firefox")
      result = "firefox"
    elsif agent.include?("Opera")
      result = "opera"
    elsif agent.include?("Chrome")
      result = "chrome"
    elsif agent.include?("Safari")
      result = "safari"
    end
    return result
  end

end


2009-07-02

MS SQL Server 2005 Express

SQL Server 2005 Express


SQL Server 2005 Management Studio Express


SQL Server JDBC Driver



[MSSQL] Microsoft SQL Server 2005 Express Edition 설치 및 사용후기

자바 스크립트 라이브러리

나중에 나온 jQueryPrototype보다는 조금은 우수한 API라는 평가가 있지만

익숙함으로 인해서 아직은 Prototype...

로그

Apache log4jApache Commons Logging을 사용하는 것이 고전적인 방법이기는 하지만

사용하는 라이브러리를 줄이기 위해서 Java Logging API를 사용하는 것을 권장한다.


* 톰켓을 사용하는 경우에는 톰켓 기본 설정 사용
* 동적으로 로깅 관련 설정을 변경할 수 있는가?

웹 디자인

PNG 사용을 검토한다. (IE 6.0에서는 사용할 수 없음)

Getting Creative With Transparency in Web Design

자바 플랫폼

Java SE 5.0 Update 19

Tomcat 6.0.20

Derby 10.5.1.1

2009-02-26

Ruby Gems 업데이트 오류

회사 홈페이지 개편 작업 때문에 노트북(윈도우즈 XP)에 루비를 설치했다.

ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]

그리고 Ruby on Rails 설치를 위해서 Ruby Gems를 최신으로 업데이트했다.

gem update --system


그런데 gem 명령어를 실행하면 정상적으로 동작하지 않았다. 다음 메시지가 출력되었다.

파일 이름, 디렉터리 이름 또는 볼륨 레이블 구문이 틀립니다.


그래서 RUBY_HOME/bin/gem.bat 파일의 마지막 줄을

@"ruby.exe"" "%~dpn0" %*

에서

@"ruby.exe" "%~dpn0" %*

으로 수정하였다.

2009-01-20

아파치 톰켓 6.0 한글 처리

아파치 톰켓 6.0에서 한글 처리 설정을 하는 방법은 다음과 같다. UTF-8을 사용하는 것으로 가정한다.


1. GET

${catalina.base}/conf/server.xml 파일에서 Connector 태그에 URIEncoding 속성을 설정한다.

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>

${catalina.base}는 톰켓을 설치한 디렉토리를 의미한다.


2. POST

서블릿 필터를 이용해서 javax.servlet.ServletRequest 객체의 setCharacterEncoding 메소드를 호출한다.

request.setCharacterEncoding("UTF-8");

* ServletRequest 객체의 getParameter 메소드를 호출하기 전에 setCharacterEncoding 메소드를 호출해야 한다.


3. Content Type


javax.servlet.ServletResponse 객체의 setContentType 메소드로 content-type을 지정한다.

response.setContentType("text/html; charset=UTF-8");

JSP에서 page 선언부로 설정할 수도 있다.

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

JSP 컴파일과 관련된 pageEncoding 속성도 설정한다.


4. HTML

<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>

meta 태그는 title 태그 앞에 있어야 한다.


5. 참고 자료



2008-12-19

display: none과 visibility: hidden

CSS에서 display 속성을 none으로 설정하는 것과 visibility 속성을 hidden으로 설정하는 것은 비슷하지만 명확한 차이가 있다.

다음 HTML이 있다.

<div id="one">One</div>
<div id="two">Two</div>
<div id="three">Three</div>

CSS 설정은 다음과 같다.

div {
  border: 1px solid silver;
  height: 15px;
  margin: 10px 0;
  text-align: center;
  width: 200px;
}

웹 브라우저에 아래와 같이 표시된다.


먼저 두번째 태그(two) display 속성을 none으로 설정하면

#two {
  display: none;
}

웹 브라우저에 아래와 같이 표시된다.


display 속성을 none으로 설정하면 해당 태그가 HTML 문서 상에 존재하지 않는 것과 같이 된다. 즉, 태그가 아래와 같다고 할 수 있다.

<div id="one">One</div>
<div id="three">Three</div>


반면에 두번째 태그(two) visibility 속성을 hidden으로 설정하면

#two {
  visibility: hidden;
}

웹 브라우저에 아래와 같이 표시된다.


visibility 속성을 hidden으로 설정하면 해당 태그 내용은 보이지 않지만 해당 태그가 차지하는 공간은 비워진채로 표시된다.

2008-07-26

[펌] 내 책의 특성에 관한 고찰

진중권씨가 쓴 을 펌합니다.



저자가 매기는 독자의 등급

  • 1등급 : 책을 사놓고 까먹고 또 사는 독자지존
  • 2등급 : 책을 사서 읽고 또 사서 남에게 선물하는 독자제현
  • 3등급 : 책을 사기만 하고 안 읽는 독자분
  • 4등급 : 책을 사서 읽는 독자
  • 5등급 : 책을 사서 읽은 후에 헌책방에 파는 독자녀석
  • 6등급 : 책을 빌려 읽는 독자놈
  • 7등급 : 빌려읽은 주제에 악평 하는 독자색귀

2008-07-07

아파치 더비 - 유용한 SQL

-- 테이블 목록 가져오기

SELECT *
FROM SYS.SYSTABLES
ORDER BY TABLENAME

2008-03-12

아파치 더비에서 자바 함수 만들기

아파치 더비에서 자바 클래스 메소드를 SQL 함수로 사용하는 방법이다.

* 아파치 더비는 자바로 개발된 DBMS이다.


1. 자바 클래스 작성

SQL 함수로 사용하려면 메소드를 public static으로 만들어야 한다. NameUtil 클래스의 toId와 toAlias 메소드처럼...

package com.dimdol.example;

import java.util.HashMap;
import java.util.Map;

public final class NameUtil {

  private static Map ids = new HashMap();

  private static Map alias = new HashMap();

  private AgentUtil() {
    // ids와 alias 초기화
  }

  public static String toId(String key) {
      String result = (String) alias.get(key);
      return result == null ? key : result;
  }

  public static String toAlias(String key) {
    String result = (String) ids.get(key);
    return result == null ? key : result;
  }

}


2. SQL 함수 선언

다음 쿼리로 NameUtil.toId 메소드로 TO_ID 함수를 만든다.

CREATE FUNCTION TO_ID(ALIAS VARCHAR(100)) RETURNS VARCHAR(100) PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA
EXTERNAL NAME 'com.dimdol.example.NameUtil.toId'

다음 쿼리로는 NameUtil.toAlias 메소드로 TO_ALIAS 함수를 만든다.

CREATE FUNCTION TO_ALIAS(ID VARCHAR(100)) RETURNS VARCHAR(100) PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA
EXTERNAL NAME 'com.dimdol.example.NameUtil.toAlias'


3. 사용 방법

이렇게 작성한 SQL 함수를 아래와 같이 사용한다. 일반 SQL 함수와 사용 방법이 다르지 않다.

SELECT TO_ALIAS(ID)
   FROM EMPLOYEE
 WHERE ID = TO_ID('딤돌')



2007-07-11

우분투 서버 7.04 설치

형상관리(CVS)와 빌드 서버를 구축하기 위해서 조립 PC에 우분투 서버 7.04을 설치했다.

기본 설치

우선 설치 CD를 넣은 후에 컴퓨터를 시작한다. 설치 화면에서 Install to the hard disk를 선택한다.

  • Choose language 설정에서 Korean(한국어)을 선택한다.
  • 키보드 레이아웃을 선택한다.
  • 네트워크 설정 - 네트워크 인터페이스로 첫번째로 연결된 네트우크 인터페이스를 선택하면 된다. 그리고 호스트명을 입력한다.
  • 디스크 파티션하기
  • 시간대 설정
  • 사용자 및 열쇠글 설정
  • 베이스 시스템 설치
  • 소프트웨어 선택 - DNS Server 혹은 LAMP Server 등을 추가로 설치할 수 있다.


설치를 마치면 설치 CD가 제거되면서 컴퓨터가 자동으로 재시작된다. 설치 과정에서 지정한 사용자 및 열쇠글로 로그인을 한다.

새로운 소프트웨어를 설치할 때 항상 CD-Rom 먼저 검색한다. 이를 방지하려면 /etc/apt/sources.list 파일에서 맨 앞에 나오는 내용을 주석처리한다.

# no more prompting for CD-ROM please
# deb cdrom:[Ubuntu 6.06 _Dapper Drake_ - Release i386 (20060329.1)]/ dapper main restricted


우분투 서버 업그레이드

다음 명령어를 통해서 우분투 서버를 업그레이드한다.

sudo apt-get update
sudo apt-get upgrade


기본 패키지 설치

몇 가지 중요한 기본 패키지를 설치한다.

sudo apt-get install ssh

sudo apt-get install vim

sudo apt-get install sun-java6-jdk

sudo apt-get install ant


ssh 패키지를 설치한 후에는 putty 등의 터미널 프로그램을 통해서 우분투 서버에 접근할 수 있다.


FTP 설치

FTP를 설치하는 방법은 다음 URL을 참조한다.

아래 명령어를 통해서 FTP 서버를 설치한다.

sudo apt-get install vsftpd

/etc/vsftpd.conf 파일 내용을 아래와 같이 수정한다.

anonymous_enable=NO

local_enable=YES

write_enable=YES

아래 명령어를 통해서 FTP 서버를 실행한다.

sudo /etc/init.d/vsftpd stop

sudo /etc/init.d/vsftpd start


CVS 서버 설치

CVS 서버를 설치하는 방법은 다음 URL을 참조한다.

아래 명령어를 통해서 CVS 서버를 설치한다.

sudo apt-get install cvs

CVS 서버를 시작하고 정지하려면 xinetd 패키지를 설치해야 한다.

sudo apt-get install xinetd

/home/build/repository 디렉토리를 만든 후에 다음 명령어를 수행한다.

cvs -d /home/build/repository init


/etc/xinetd.d/cvspserver 파일을 추가하여 아래 내용을 입력한다.

service cvspserver
{
    port = 2401
    socket_type = stream
    protocol = tcp
    user = build
    wait = no
    type = UNLISTED
    server = /usr/bin/cvs
    server_args = -f --allow-root /home/build/repository
    disable = no
}

xinetd를 시작한다.

sudo /etc/init.d/xinetd stop

sudo /etc/init.d/xinetd start


CVS 사용자 추가

사용자 열쇠글을 암호화하는데 필요한 apache2-utils 패키지를 설치한다.

sudo apt-get install apache2-utils

사용자를 추가하려면 다음을 입력한다.

htpasswd -n username

패스워드를 입력하면 나오는 내용을 /home/build/repository/CVSROOT/passwd 파일에 입력한다. 이 때 마지막에는 우분투 서버 사용자 아이디도 입력해야 한다.

username:Z5TkEkMFAorLA:build


하드 디스크 추가

추가한 하드 디스크의 SCSI ID를 아래 명령어를 통해서 확인한다.

dmesq | grep SCSI

추가한 하드 디스크에 대해서 파티션 작업을 수행한다.

2007-02-07

애플리케이션 개발의 목표

예전에 참여했던 프로젝트에서 애플리케이션을 어떻게 개발할 것인지에 대한 고객 질문에 답하기 위해서 정리한 내용입니다.


설계의 목적 및 방향

본 애플리케이션은 아래의 사항을 만족시키는 것을 목적으로 설계함.

  • 애플리케이션 인도 이후의 손쉬운 유지 보수 지원
  • 요구 사항 변경이나 새로운 기능 요구에 부합하기 위한 확장성 지원
  • 사용자가 애플리케이션을 사용하여 업무 수행을 하는데 지장이 없는 성능 보장
  • 애플리케이션의 주요 기능이나 데이터를 인증을 받지 않은 사용자가 접근하는 것을 방지하는 보안 기능 지원
  • 용이한 테스트가 가능하도록 설계하여 높은 수준의 품질 보장
  • 전체 애플리케이션에 대한 일관성 유지


설계에서 적용하는 기술 및 기법

위의 목적을 달성하기 위해서 아래의 설계 기술 및 기법을 적용함.

애플리케이션 인도 이후의 손쉬운 유지 보수 지원

  • 중복의 최소화(동일하거나 유사한 기능이 중복되어 설계되는 것을 방지함).
  • 동일하거나 유사한 구조를 갖는 기능을 하나의 컴포넌트로 통합하여 설계(분리하여 설계하면 애플리케이션 관리 비용이 증가하고, 시스템 성능에 부정적인 영향을 미침).
  • 모든 컴포넌트는 추상 상위 컴포넌트 클래스를 상속하도록 설계하여 공통적인 기능을 제공함.

요구 사항 변경이나 새로운 기능 요구에 부합하기 위한 확장성 지원

  • CBD(Component-Based Development)에 충실하여 컴포넌트의 인터페이스와 구현을 분리.
  • 컴포넌트를 사용하는 클라이언트 코드의 변경 없이 컴포넌트의 구현부 변경.
  • 다양한 디자인 패턴(Model-View-Controller, Inversion Of Control, Strategy/Status, Command 패턴 등)을 적용하여 변경이 용이하도록 설계.

사용자가 애플리케이션을 사용하여 업무 수행을 하는데 지장이 없는 성능 보장

  • 안정적인 성능을 보장하기 위해서 POJO(Plain Old Java Object) 방식을 통해서 컴포넌트 설계 및 구현.
  • 분산 기능이 필요한 경우에 한해서 성능에 부정적인 영향을 미치는 EJB를 제한적으로 사용.
  • 웹 UI에서 이미지의 사용을 최소화하고 웹 브라우저로 전송되어야 하는 HTML의 양을 최소화함.
  • 변경이 없거나 변경 빈도가 낮은 데이터(코드, 부대 코드, 메시지 등)를 캐싱하여 불필요한 DB 작업을 최소화함.
  • 자바 스크립트를 이용하여 보안에 문제가 없는 기능을 웹 브라우저에서 수행하여 서버의 부담을 최소화함.
  • DataSource 및 Connection Pooling 기능을 사용하여 안정적인 DB 성능 보장

애플리케이션의 주요 기능이나 데이터를 인증을 받지 않은 사용자가 접근하는 것을 방지하는 보안 기능 지원

  • 권한을 중심으로 보안 기능 설계(Role 디자인 패턴 적용).
  • 사용자 로그인 시 사용자에게 할당된 권한 부여.
  • 모든 URL에 대해서 권한 매핑을 하여 권한을 가지고 있지 않은 사용자가 접근하는 것을 원천적으로 방지함.
  • 메뉴, 버튼, 화면, 화면의 특정 영역에 대해서 권한을 가지고 있지 않은 사용자는 볼 수 없도록 함.(Limited View 디자인 패턴 적용).
  • 주민등록번호 등 주요한 데이터에 대해서 암호화하여 관리하고 불필요하게 노출되는 것을 제거함.

용이한 테스트가 가능하도록 설계하여 높은 수준의 품질 보장

  • WAS(Web Application Server)와 독립적으로 테스트를 수행할 수 있도록 설계(HTTP 및 RMI-IIOP 프로토콜에 독립적으로 컴포넌트 설계).
  • JUnit을 이용하여 자동화된 개발자 테스트 수행.
  • 일일 주기의 자동화된 빌드를 통한 계속적인 단위 형상간 통합을 수행하여 시스템 통합 단계에서의 문제점을 최소화함.
  • 자동화된 소스 코드 Inspection을 수행하여 소스 코드의 품질을 높임.

전체 애플리케이션에 대한 일관성 유지

  • CSS(Cascading Style Sheet)를 이용하여 전체 UI의 구조(색상 및 위치)에 대해서 일관성을 유지함. 또한 변경이 필요한 경우 한번의 수정으로 전체 애플리케이션에 반영되도록 함.
  • 소스 코드 표준 규약을 IDE(JBuilder)를 통해서 자동적으로 부여함으로써 완전한 코딩 표준 준수.
  • 각종 설계 및 구현 표준을 작성하고, 지속적인 Peer Review 및 Code Review를 통한 표준의 준수 여부 체크.




컴포넌트 아키텍처를 구성하기 위해 적용된 패턴 및 기준이 명시되었는가?


네트워크 부하 감소

  • 컴포넌트 구현 방식으로 분산 처리가 필요 없는 경우에는 EJB가 아닌 POJO를 사용한다.
  • EJB를 이용한 컴포넌트 구현 시 Fine grained 한 방식이 아닌 Coarce grained 한 방식으로 설계 및 구현한다.
  • EJB를 이용한 컴포넌트 구현 시 Local Interface를 사용해야 하나 제우스 WAS에서는 동일 프로세스 내에서는 Remote Interface와 Local Interface 간에 성능 차이가 없음으로, 테스트의 용이성 및 Fail Over 지원을 위해서 Remote Interface를 사용하여 구현한다.
  • EJB를 이용한 컴포넌트 구현 시 EJB를 호출하는 클라이언트는 Service Locator 디자인 패턴을 이용하여 EJBHome 객체에 대해서 캐싱을 한다.

재사용

  • Variation이 있는 부분에 대해서 Extension Point를 제공한다.
  • Variation은 Strategy/State 디자인 패턴을 적용하여 구현한다.
  • IoC 디자인 패턴을 활용하여 클라이언트는 컴포넌트 구현부가 아닌 인터페이스에만 의존하게 한다.
  • 특정 기술 및 프로토콜(RMI-IIOP)에 대한 의존을 지양한다.
  • 모든 컴포넌트는 공통 기능을 제공하는 BaseComponent를 상속하여 설계한다.
  • 여러 컴포넌트들이 절차를 공유할 때에는 템플릿 메소드 디자인 패턴을 적용하여 설계한다. 이 경우에는 Inner 클래스 사용을 허용한다.

결합도

  • 기능 구현에 있어서 개별 컴포넌트의 완전성을 추구하여 컴포넌트가 의존성을 최소화한다.
  • 그러나 완전성 추구는 기능(혹은 코드) 중복 방지에 우선하지 않는다.
  • 따라서 중복 방지를 위한 컴포넌트 간의 의존을 허용한다.
  • 컴포넌트 설계 기법 뿐만 아니라 객체지향 설계 개념도 충실하게 반영하기 위해서 컴포넌트 간의 상호 참조를 일정부분 허용한다. 단, 이는 같은 형상 내에서만 허용한다.
  • 형상 간에는 타 형상의 Sys 컴포넌트에 대해서만 참조를 허용한다. 이는 Facade 디자인 패턴을 적용한 것이다.
  • 같은 형상 내에서는 컴포넌트 상호 간의 순환 참조가 꼭 필요한 경우에는 허용하나 최대를 이를 회피해야 한다. 그러나 타 형상 간에는 순환 참조를 절대 허용하지 않는다.

2006-07-07

웹 UI 가이드라인

1. 개요

HTML(Hyper Text Markup Language)과 CSS(Cascading Style Sheet)를 사용한 웹 UI 작성 가이드라인을 설명한다. 이 가이드라인은 HTML 코드의 최소화와 간결성 확보를 통한 웹 어플리케이션 개발 생산성과 유지 보수성 향상을 목표로 한다. 그리고 트래픽의 최소화를 통한 웹 어플리케이션 성능 향상도 목표로 한다.

또한 가능한 대중적으로 사용하는 브라우저(MS IE, 모질라 파이어폭스, 오페라, 사파리 등)에서 정상적으로 동작하는 HTML과 CSS를 작성하는 것을 목표로 한다.

이를 위해서 W3C 표준 기술을 중심으로 웹 UI를 작성하는 것을 권장한다. HTML은 XHTML 1.0을 기준으로 하고, CSS는 대중적으로 많이 사용하는 브라우저를 기준으로 한다. 단, 자세한 버전은 프로젝트와 어플리케이션의 상황에 맞게 조정한다.


2. 웹 표준 가이드

웹 표준과 관련해서 명심해야 하는 사항은 모든 브라우저에서 동일하게 보이도록 UI를 구성하는 것이 목표가 아니라는 점이다. 여기에 과도하게 집중하면 효과보다 큰 비용이 발생할 수 있다. 웹 표준를 통한 웹 UI의 작성의 목표는 모든 브라우저에서 사용자가 사용하는데 큰 불편함을 느끼지 않도록 하는 것이다.


3. HTML 작성 가이드라인

일반적인 HTML 작성 가이드라인은 아래와 같다.


(1) XHTML 사용

일반 HTML 4.0 보다 XML 표준을 준수하는 XHTML 1.0을 사용한다. 따라서 모든 HTML 문서는 아래처럼 시작해야 한다.

<?xml version="1.0" encoding="UTF-8"?> <!-- MS IE를 고려하여 삭제 -->

<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko" lang="ko">
</html>

단, XML 선언부가 있는 경우에 MS IE 6.0은 비표준 방식으로 UI를 표현함으로 이를 삭제하도록 한다.


그리고 XHTML 작성에 있어서 XML의 일반적인 작성 원칙을 준수한다.


DOCTYPE을 선언한다. 문서의 앞 부분에 DOCTYPE을 선언한다.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">


html 태그에 xmlns 속성을 기입한다.

<html xmlns="http://www.w3.org/1999/xhtml"></html>


소문자를 사용한다. XML은 대소문자를 구분하며 XHTML은 태그와 속성의 이름으로 소문자를 사용한다. 그리고 속성의 값도 소문자 사용을 기본으로 한다.

<table border="0">
   
</table>


속성 값은 큰 따옴표(Double Quatation) 안에 넣는다. 큰 따옴표 없이 속성에 대한 값을 지정하지 않는다.

<a href="http://www.doosan.com">Doosan</a>


속성에는 항상 값을 기입한다.

<hr noshade="noshade">


& 속성 값에 대해서 &amp;를 사용한다.

<a href="List.jsp?a=1&amp;b=2">


모든 태그는 닫는다.

<p>모든 태그는 닫는다.</p>

특히 내용이 없는 태그 사용에 주의한다.

<br/>
<input type="text" name="id"/>

이런 태그를 독립형 태그라고 한다.

<area>, <meta/>, <base/>, <col>, <frame>, <link/>, <br/>, <hr/>, <img/>, <input/>, <param/>

다음은 독립형 태그로 혼동하기 쉬운 컨테이너 태그이다.

<script></script>, <object></object>, <div></div>


style과 script 태그의 내용은 모두 주석 처리한다.  style 혹은 script 태그 안에서 XML 태그 요소를 사용하려면 항상 주석 처리한다.

<script><!--

  function doAction() {
    if (a < b) ...
  }

//--></script>


(2) 이미지 사용의 최소화

이미지 사용을 최소화하며 반복적인 이미지를 사용해야 하는 경우에 CSS의 background-image 속성으로 처리한다.

간격 조절을 위한 투명 이미지는 절대로 사용하지 않는다.

이미지의 크기는 이미지 파일의 절대 크기를 그대로 사용한다. 따라서 width와 height를 img 태그에 지정하지 않는다. 그러나 width와 height 속성을 명시적으로 지정하면 웹 브라우저 처리 속도의 향상을 기대할 수 있다.


(3) 구성 요소 간의 간격 조절

HTML 구성 요소 간의 간격 조절에 투명 이미지나 br 태그나 &nbsp;의 사용을 지양하고 CSS로 조정한다.


(4) 태그의 속성 값의 최소화

HTML로는 자료의 내용 및 구조만을 표현하며, UI 표현과 관련한 정보는 CSS로 나타낸다. 따라서 HTML 태그 속성 사용을 최소화한다.


(5) 들여 쓰기 규정

들여 쓰기는 탭이 아닌 스페이스 4자로 한다.


(6) table 태그의 사용

table 태그는 그리드 형 데이터 표현에만 사용한다. table 태그로 레이아웃을 표현하는 것은 지양해야 하며, table 태그 안에 table 태그가 들어가는 형식은 특별한 이유가 아니면 사용하지 않는다.

데이터를 위한 테이블의 경우, row와 column에 대한 헤더(th 태그)를 명기한다.


(7) 리스트 태그를 통한 구조적 데이터 표현

구조적인 데이터는 ul과 li 등의 리스트 태그로 표현한다.


(8) 상대 경로를 사용

모든 URL 경로의 표현은 상대 경로로 한다. 수정을 어렵게 하는 절대 경로를 사용하는 것은 지양한다.


(9) 텍스트를 이미지로 표현하는 것을 지양

텍스트를 이미지 파일로 표현하는 것을 지양한다. 이미지를 사용하면 네트워크 트래픽을 증가시키는 동시에 수정을 어렵게 한다.


(10) Content-based text styles

표현 방식을 지칭하는 b, big, i, small, sub, sup, tt 태그 사용을 지양하고(Physical Styles) 의미 방식을 지칭하는 strong, em 태그의 사용을 지향한다.

  • abbr - abbreviated form of a longer word or phrase
  • acronym - acronym
  • em - 강조해야 하는 내용
  • strong - 매우 강조해야 하는 내용
  • cite - 출처, 인용구
  • code - 프로그래밍 코드의 일부분
  • kbd - 사용자가 입력한 내용
  • samp - 샘플 내용
  • dfn - 정의
  • var - 변수


(11) 사용을 지양해야 하는 태그

center, font, basefont, u, s, strike, marquee 등의 태그 사용을 지양한다.


(12) 사용을 지양해야 하는 속성

태그의 align, style 등의 속성 사용을 지양한다.


(13) img 태그 사용의 지양

이미지를 표현하는데 있어서 img 태그의 사용은 지양하고 CSS의 background-image 속성의 사용을 지향한다.


(14) 개발 시 편집을 위한 태그의 활용

ins, del 등의 태그를 사용하여 개발 시 편집 정보를 기술한다.


4. CSS 작성 가이드라인

일반적인 CSS 작성 가이드라인은 아래와 같다.


(1) 소문자 사용

CSS의 내용은 모두 소문자로 작성한다.


(2) 들여 쓰기 규정

들여 쓰기는 탭이 아닌 스페이스 4자로 한다.


(3) 선택자

선택자는 태그의 이름, 태그의 클래스(class) 속성, 태그의 아이디(id) 속성 순으로 지정한다.
태그의 계층 구조를 사용하면 태그의 이름을 통한 선택자 사용 비율을 늘릴 수 있다.

table tbody tr td {
    background-color: #ffffff;
    font: 1em 굴림, Tahoma, sans-serif;
    height: 2em;
    padding: 0.5em 0.5em 0 1em;
    overflow: hidden;
}

클래스 속성이나 아이디 속성을 사용하는 경우에도 앞에 태그를 지정한다.

div.title-area {
    ...
}

div#header {
    ...
}


(4) 기본 설정의 초기화

html, body, form 태그 등의 기본 설정이 브라우저에 따라서 상이하다. 따라서 이를 CSS를 통해서 동일하게 설정한다.

html, body, form {
    margin: 0;
    padding: 0;
}


(5) 상속을 통한 속성 반복의 최소화

상속을 통하여 동일한 속성 값을 반복하는 것을 지양한다.

div {
    width: 775em;
}

div.title-area {
    color: #0b9af3;
    margin: 0 0 1em 0;
    padding-left: 2em;
}


(6) em을 이용한 크기 설정

해당 요소의 크기를 조정하기 위해 사용하는 여러 단위 중에서 em을 사용하여 크기를 조정한다. 단 border, margin, padding 등과 같은 경우에는 px를 사용할 수 있다.


(7) 색상 속성

색상(color) 속성에 대한 값은 색상 이름이 아닌, 헥사 코드로 표현한다.

bgcolor: #ffffff;

rgb로 표현할 수도 있다.

bgcolor: rgb(255, 255, 255);


(8) background-image 속성을 통해서 이미지 설정

background-image 속성을 통해서 HTML에서의 이미지(img) 태그 사용을 최소화한다.

div.title-area {
    background-image: url(../image/label/Title2.gif);
    background-position: 0 -2px;
    background-repeat: no-repeat;
    margin: 0 0 1em 0;
    padding-left: 2em;
}


(9) 집합 속성의 사용을 지향

CSS의 내용을 간결하게 가기 위해서 집합 속성을 사용한다. 아래는 개별 속성을 사용한 경우이다.

div.title-area {
    margin-top: 5px;
    margin-right: 4px;
    margin-bottom: 3px;
    margin-left: 2px;
}

위의 표현을 아래처럼 집합 속성으로 표현한다.

div.title-area {
    margin: 5px 4px 3px 2px;
}


(10) 웹 브라우저 독립적인 속성의 사용

특정 웹 브라우저에 종속적인 속성의 사용을 지양하며, W3C가 제공하는 아래의 속성 테이블을 중심으로 CSS 파일을 작성한다.

Cascading Style Sheets, level 2 CSS2 Specification, Appendix F. Property index (http://www.w3.org/TR/REC-CSS2/propidx.html)


(11) CSS 파일 수의 최소화

CSS 파일의 수를 최소화한다. 유사한 형태의 업무 화면은 하나의 CSS 파일로 조정한다. 각 업무 화면에 특징적인 요소를 별개의 CSS 파일로 지정하기 보다는 HTML의 style 태그를 이용해서 설정하는 것을 권장한다.

단 메인 화면, 사이트 맵 등 업무 화면과는 독립적인 화면에 대해서는 별도의 CSS 파일을 가져간다.


(12) 특기 사항

CSS와 관련한 특기 사항은 아래와 같다.

  • select 태그 CSS 적용 - border 속성을 지정할 수 없음


5. 참고 자료



2006-05-21

NTLM 인증

윈도우 인트라넷 환경에서 NTLM(Windows NT LAN Manager) 프로토콜로 SSO(Single Sign On)를 구현하는 경우가 있다.

자바(JSP)에서 NTLM 프로토콜을 이용해서 윈도우 도메인 이름과 사용자 계정을 획득하는 방법이다.

<%@ page contentType="text/html; charset=UTF-8" %>

<%
String auth = request.getHeader("Authorization");
if (auth == null) {
    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    response.setHeader("WWW-Authenticate", "NTLM");
    response.flushBuffer();
    return;
    // 이 응답을 받은 IE 웹 브라우저는 다시 요청을 보낸다.
}

if (auth.startsWith("NTLM ")) {
    byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
    int off = 0, length, offset;
    if (msg[8] == 1) {
        byte z = 0;
        byte[] msg1 = { (byte) 'N', (byte) 'T', (byte) 'L',
                        (byte) 'M', (byte) 'S', (byte) 'S', (byte) 'P', z,
                        (byte) 2, z, z, z, z, z, z, z, (byte) 40, z, z, z,
                        (byte) 1, (byte) 130, z, z, z, (byte) 2, (byte) 2,
                        (byte) 2, z, z, z, z, // this line is 'nonce'
                        z, z, z, z, z, z, z, z };
        response.setContentLength(0);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        String value = "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1);

        // 웹로직에서는 Header 값에 CRLF 문자를 포함하면 예외가 발생함.
        response.setHeader("WWW-Authenticate", value.replaceAll("\n", ""));
        response.flushBuffer();
        return;
        // 이 응답을 받은 IE 웹 브라우저는 다시 요청을 보낸다.
    } else if (msg[8] == 3) {
        // 최종적으로 윈도우 도메인 이름과 사용자 계정을 도출할 수 있는 요청이다.
        String remoteHost = null;
        String domain = null;
        String username = null;

        off = 30;
        length = msg[off + 17] * 256 + msg[off + 16];
        offset = msg[off + 19] * 256 + msg[off + 18];
        remoteHost = new String(msg, offset, length);

        length = msg[off + 1] * 256 + msg[off];
        offset = msg[off + 3] * 256 + msg[off + 2];
        domain = new String(msg, offset, length);

        length = msg[off + 9] * 256 + msg[off + 8];
        offset = msg[off + 11] * 256 + msg[off + 10];
        username = new String(msg, offset, length);

        // 사용자 계정에 포함된 특수 문자 제거
        username = username.replaceAll("\\W", "");
        return;
    }
}
%>


물론 이 경우에는 MS IE 웹 브라우저만을 사용해야 한다.


참고 자료



2006-05-05

Active Directory 연동

LDAP(Lightweight Directory Access Protocal)과 JNDI(Java Naming and Directory Interface) API를 이용해서 MS Active Directory와 연동(사용자 정보 검색)하는 방법이다.


Active Directory 서버 연결 시작

ActiveDirectoryDao 클래스의 생성자에서 Active Directory 서버와 연결한다.

ActiveDirectoryDao.java

private DirContext ldapContext;

private String host = "127.0.0.1";

private String port = "389";

private String username = "username";

private String password = "password";

public ActiveDirectoryDao() {
    try {
        Hashtable ldapEnv = new Hashtable(5);
        ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.ldap.LdapCtxFactory");
        ldapEnv.put(Context.PROVIDER_URL, "ldap://" + host + ":" + port);
        ldapEnv.put(Context.SECURITY_PRINCIPAL, username);
        ldapEnv.put(Context.SECURITY_CREDENTIALS, password);
        ldapContext = new InitialDirContext(ldapEnv);
    } catch (NamingException e) {
        throw new SystemException(e);
    }
}


Active Directory 서버 연결 종료

ActiveDirectoryDao 클래스의 close 메소드로 Active Directory 서버와의 연결을 종료한다.

ActiveDirectoryDao.java

public void close() {
   if (ldapContext != null) {
       try {
           ldapContext.close();
       } catch (NamingException e) {
           throw new SystemException(e);
       }
   }
}


사용자 존재 여부 확인

ActiveDirectoryDao 클래스의 hasUser 메소드로 Active Directory 서버에 특정 사용자 정보가 존재하는지 확인한다.

ActiveDirectoryDao.java

private String baseDn = "...";

public boolean hasUser(String name) {
    try {
        NamingEnumeration all = ldapContext.search(baseDn, "name=" + name,
                getSearchControl());
        return all.hasMoreElements();
    } catch (NamingException e) {
        throw new SystemException(e);
    }
}


하위 노드에서도 사용자 정보를 검색하도록 SearchControls를 설정한다. 사용자 아이디가 유일해야 한다.

ActiveDirectoryDao.java

protected SearchControls getSearchControl() {
    SearchControls result = new SearchControls();
    result.setCountLimit(1);
    result.setSearchScope(SearchControls.SUBTREE_SCOPE);
    return result;
}


사용자 정보 확인

ActiveDirectoryDao 클래스의 getUser 메소드로 Active Directory 서버에 있는 특정 사용자 정보를 java.util.Map 객체로 반환한다. 사용자가 존재하지 않으면 java.util.Collections.EMPTY_MAP 객체를 반환한다.


ActiveDirectoryDao.java

public Map getUser(String name) {
    try {
        NamingEnumeration all = ldapContext.search(baseDn, "name=" + name,
                getSearchControl());
        while (all.hasMoreElements()) {
            SearchResult each = (SearchResult) all.nextElement();
            Map result = new HashMap();
            NamingEnumeration attributes = each.getAttributes().getAll();
            while (attributes.hasMoreElements()) {
                Attribute attribute = (Attribute) attributes.nextElement();
                result.put(attribute.getID(), attribute.get());
            }
            return result;
        }
        return Collections.EMPTY_MAP;
    } catch (NamingException e) {
        throw new SystemException(e);
    }
}


사용 예제

아래처럼 ActiveDirectoryDao 클래스를 사용한다.

Client.java

ActiveDirectoryDao dao = null;

try {
    dao = new ActiveDirectoryDao();
    Map userInfo = null;
    if (dao.hasUser("username")) {
        userInfo = dao.getUser("username");
    }
} finally {
    if (dao != null) {
        dao.close();
    }
}

Active Directory 서버와의 연결을 유지하려면 close 메소드를 호출하지 않는다.


참고 자료



* ActiveDirectoryDao 전체 소스 코드

package com.dimdol.example;

import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

/**
 * JNDI/LDAP을 이용해서 MS Active Directory와 연동하는 클래스.
 *
 * @version 1.0
 */
public class ActiveDirectoryDao {

    /**
     * 기본 루트.
     */
    private DirContext ldapContext;

    /**
     * Active Directory 서버의 호스트.
     */
    private String host = "active.dimdol.com";

    /**
     * Active Directory 서버의 포트.
     */
    private String port = "389";

    /**
     * 사용자.
     */
    private String username = "";

    /**
     * 패스워드.
     */
    private String password = "";

    /**
     * 기본 Distinguished Name,
     */
    private String baseDn = "OU=조직이름,DC=corp,DC=dimdol,DC=com";

    /**
     * 기본 생성자. Active Directory 서버와 연결한다.
     */   
    public ActiveDirectoryDao(String username, String password) {
        try {
            Hashtable ldapEnv = new Hashtable(5);
            ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY,
                    "com.sun.jndi.ldap.LdapCtxFactory");
            ldapEnv.put(Context.PROVIDER_URL, "ldap://" + host + ":" + port);
            ldapEnv.put(Context.SECURITY_PRINCIPAL, username + "@corp.dimdol.com");
            ldapEnv.put(Context.SECURITY_CREDENTIALS, password);
            ldapContext = new InitialDirContext(ldapEnv);
        } catch (NamingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Active Directory 서버와의 연결을 종료한다.
     */
    public void close() {
        if (ldapContext != null) {
            try {
                ldapContext.close();
            } catch (NamingException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 사용자가 존재하는지 확인한다.
     *
     * @param name
     *            사용자 아이디
     * @return 사용자가 존재하면 true를, 존재하지 않으면 false를 반환한다.
     */
    public boolean hasUser(String name) {
        try {
            NamingEnumeration all = ldapContext.search(baseDn, "name=" + name,
                    getSearchControl());
            return all.hasMoreElements();
        } catch (NamingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 사용자 정보를 java.util.Map 객체에 담아서 반환한다. 사용자가 존재하지 않으면
     * java.util.Collections.EMPTY_MAP 객체를 반환한다.
     *
     * @param name
     *            사용자 아이디
     * @return 사용자 정보를 담고 있는 java.util.Map 객체
     */
    public Map getUser(String name) {
        try {
            NamingEnumeration all = ldapContext.search(baseDn, "name=" + name,
                    getSearchControl());
            while (all.hasMoreElements()) {
                SearchResult each = (SearchResult) all.nextElement();
                Map result = new HashMap();
                NamingEnumeration attributes = each.getAttributes().getAll();
                while (attributes.hasMoreElements()) {
                    Attribute attribute = (Attribute) attributes.nextElement();
                    result.put(attribute.getID(), attribute.get());
                }
                return result;
            }
            return Collections.EMPTY_MAP;
        } catch (NamingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 하위 노드에서도 검색하도록 설정한 SearchControls를 반환한다.
     *
     * @return 하위 노드에서도 검색하도록 설정한 SearchControls
     */
    protected SearchControls getSearchControl() {
        SearchControls result = new SearchControls();
        result.setCountLimit(1);
        result.setSearchScope(SearchControls.SUBTREE_SCOPE);
        return result;
    }

    public static void main(String[] args) throws Exception {
        ActiveDirectoryDao dao = new ActiveDirectoryDao("","");
        System.out.println(dao.hasUser("dimdol"));
        System.out.println(dao.getUser("dimdol").get("description"));
        dao.close();
    }

}


2006-04-21

CVSNT 설치와 관리

1. 개요

형상관리 도구인 CVSNT를 설치하고 사용하는 방법을 설명한다. 여기서 설명하는 CVSNT의 버전은 2.5.04.3510이고, 여기에서 다운로드한다.

사용자 관리 등의 클라이언트 용도로 CVSNT를 설치한다면 <2. 설치>와 <5. 사용자 관리>만을 참고한다. 그리고 CVSNT를 설치하면 자동으로 윈도우 서비스에 등록되기 때문에 클라이언트 목적으로 설치하였다면 서비스를 중지시키고 상태를 자동에서 수동으로 수정한다.

2. 설치

(1) 설치와 관련한 주의 사항

안정성 등의 이유로 CVSNT를 NTFS 파일 시스템에 설치하는 것을 권장하지만 FAT 파일 시스템에 설치해도 된다.

설치하기 전에 기존에 설치한 CVSNT와 CVS 프로그램을 삭제하는 것을 권장한다. 삭제하기 곤란한 경우에는 최소한 PATH가 겹치는 일은 방지해야 한다. 예를 들어 WinCVS의 cvs.exe나 Cygwin의 cvs.exe 등의 프로그램은 CVSNT 일부 기능의 수행을 방해할 수 있다.

윈도우 2003에 CVSNT를 설치하는 경우 WMI 서비스와 연관되어 문제가 발생하는 경우가 있다. 이 경우 WMI 서비스를 중단하고 CVSNT를 설치한 뒤, WMI 서비스를 재시작한다. 이는 CVSNT 설치시에만 해당하며 이 두 서비스를 동시에 운영하는 것에는 문제가 되지 않는다.


(2)  CVSNT 설치 과정

다운로드한 cvsnt-server-2.5.04.3510.msi 파일을 클릭하여 설치를 시작한다. Next 버튼을 클릭한다.

Setup 화면


라이센스에 동의한 후에 Next 버튼을 클릭한다.

End-User License Agreement 화면


Typical을 선택한 후 Next 버튼을 클릭한다.

Choose Setup Type 화면


Install 버튼을 클릭하면 프로그램 복사를 시작한다.

Ready to Install 화면


아래는 복사가 진행 중인 화면이다.

Installing CVSNT 화면


설치가 완료되면 Finish 버튼을 클릭한다.

설치 완료 화면


설치를 마친 후에는 운도우를 다시 시작해야 한다. CVSNT는 윈도우 서비스에 자동으로 등록되어 윈도우가 시작될 때 함께 시작한다. CVSNT를 서버가 아닌 클라이언트로만 사용한다면 서비스를 중지시키고 시작 유형을 자동에서 수동으로 수정한다.

재시작 확인 화면



3. CVSNT 서버의 시작과 종료

윈도우 시작 메뉴의 <CVSNT | CVSNT Control Panel> 메뉴를 통해서 CVSNT 서버를 제어한다. Control Panel의 About 탭 하단의 Services 영역을 통해서 CVSNT 서버를 시작하고 종료한다.

그림 8. About 탭 화면



4. 환경 설정

(1) Repository 관리

Control Panel의 Repository Configuration 탭을 이용해서 Repository를 추가하고 삭제한다. Repository를 추가하려면 하단의 Add 버튼을 클릭한다.

Repository configuration 탭 화면


 
Add 버튼을 클릭하면 나오는 화면의 Location 필드에 오른쪽 버튼을 이용해서 C:/project-temp/repository를 입력한다. Name 필드에는 자동으로 /project-temp/repository가 입력된다. 이 이름이 곧 Repository 경로이다.
 

Server Settings 화면


경로는 상황에 맞게 수정한다.

OK 버튼을 클릭하면 아래처럼 해당 디렉토리를 CVS Repository 디렉토리로 초기화할지에 대해서 물어본다. 예 버튼을 클릭한다.
 

Repository 디렉토리 초기화 화면


권한과 신뢰성 문제 등을 이유로 Repository 디렉토리로 네트워크 드라이브를 선택해서는 안된다.
새로운 Repository를 추가하였다면 Control Panel의 About 탭 하단의 Services 영역을 통해서 CVSNT 서버를 다시 시작한다.

경험적으로 설치 이후나 Repository 추가 이후에 윈도우 혹은 CVSNT를 재시작하지 않아도 정상적으로 동작하는 경우도 있고 그렇지 않은 경우도 있다. 따라서 가급적 재시작하도록 한다.


(2) CVS와의 호환성 유지

CVSNT 기본 설정은 표준 CVS와의 호환에 문제가 있다. 이 문제를 해결하기 위해서 아래처럼 설정한다.
 

Compatibility Options 탭 화면


Control Panel의 Compatibility Options 탭의 Non-CVSNT Clients 영역에서 Respond as cvs 1.11.2 to version request와 Emulate ‘-n checkout’ bug 옵션을 체크한다.


5. 사용자 관리

CVSNT 서버 접근에 사용하는 프로토콜에 따라서 사용자, 그룹, 권한을 다양하게 설정할 수 있다. 다양한 클라이언트와의 호환성과 편리한 설정 등을 이유로 가장 많이 사용하는 프로토콜은 pserver이다. 이 글에서는 pserver 프로토콜에 대한 설정만을 설명한다. 보안상의 이슈가 있다면 ssh(ext) 프로토콜을 사용한다.

pserver 프로토콜을 이용하면 CVSNT가 설치된 윈도우 사용자 계정으로 CVSNT 서버에 접근할 수 있다. 그러나 모든 사용자를 윈도우 사용자 계정으로 등록할 필요는 없다. CVSNT 서버를 관리하기 위한 대표 윈도우 사용자 계정 하나를 두고 이 계정을 이용하여 다른 사용자를 추가할 수 있는데 이렇게 추가한 사용자를 alias라고 한다. 사용자 alias 정보는 Repository 디렉토리 밑의 CVSROOT/passwd 파일에 저장된다.

이 때 사용하는 윈도우 사용자 계정은 관리자(Administrators) 권한을 지녀야 한다.


(1) 사용자 추가

사용자를 추가하기 위해서는 우선 윈도우 사용자 계정으로 CVSNT 서버에 로그인해야 한다. 여기서는 윈도우 사용자 계정 이름을 Administrator로 가정한다. localhost는 CVSNT 서버가 설치된 컴퓨터의 호스트 이름 혹은 IP 주소로 수정한다.

set cvsroot=:pserver:Administrator@localhost:/project-temp/repository
cvs login

Administrator 계정에 대한 패스워드를 입력하면 로그인에 성공한다. 사용자(alias)는 아래처럼 추가한다.

cvs passwd -a -r Administrator 정대만

위의 예처럼 한글 이름으로도 사용자(alias) 계정을 만들 수 있기 때문에 프로젝트에 참여하는 개발자들의 이름으로 사용자(alias)를 추가하는 것을 권장한다. 단, 일부 CVS 클라이언트에서는 사용자 계정이 한글인 경우에 올바르게 동작하지 않는다.

기본적으로 패스워드는 1111로 설정하고, 개별 사용자가 직접 패스워드를 수정하게 한다.

작업이 완료되었으면 아래처럼 로그아웃한다.

cvs logout


(2) 패스워드 수정

수정할 사용자(alias)로 CVSNT 서버에 로그인한다. localhost는 CVSNT 서버가 설치된 컴퓨터의 호스트 이름 혹은 IP 주소로 수정한다.

set cvsroot=:pserver:정대만@localhost:/project-temp/repository
cvs login

정대만 계정에 대한 패스워드를 입력하면 로그인에 성공한다. 패스워드는 아래처럼 수정한다.

cvs passwd

수정할 새로운 패스워드를 입력한다.


(3) 사용자 삭제

사용자를 삭제하기 위해서는 우선 윈도우 사용자 계정으로 CVSNT 서버에 로그인해야 한다. 여기서는 윈도우 사용자 계정 이름을 Administrator로 가정한다. localhost는 CVSNT 서버가 설치된 컴퓨터의 호스트 이름 혹은 IP 주소로 수정한다.

set cvsroot=:pserver:Administrator@localhost:/project-temp/repository
cvs login

Administrator 계정에 대한 패스워드를 입력하면 로그인에 성공한다. 사용자(alias)는 아래처럼 삭제한다.

cvs passwd -X -R 정대만

X와 R은 대문자이다.