'분류 전체보기'에 해당되는 글 2491건
- 2010.02.04 ie8 확인 스크립트
- 2010.01.25 모든 브라우저 버전별 확인 스크립트 2
- 2010.01.25 IE8 확인하는 스크립트 : 익스플러 버전체크
- 2010.01.22 alert 대신 사용하면 좋은 라이브러리
- 2010.01.07 script 문제 1
- 2010.01.05 XMLHttpRequest 객체
- 2010.01.05 Array.prototype 에 max 값 정의 예제
- 2010.01.05 한글도 바이트단위로 처리하기
- 2010.01.04 javascript OS 버전 체크
- 2009.12.28 Spring Security
- 2009.12.28 N사 신입 사원 교육을 위한 Spring 프레임워크 강의
- 2009.12.22 [Java] JAVA - 개발자가 놓치기 쉬운 자바의 개념, 기본원리
- 2009.12.21 classpath내 properties파일로 Properties객체 생성 1
- 2009.12.21 배열을 for 사용하지 않고 출력하기...
- 2009.12.21 Spring - Java/J2EE Application Framework 1
- 2009.12.21 간단한 JavaScriptMethodOverloading
- 2009.12.21 중급 자바 개발자의 난관, 클래스 로딩 문제 분석하기
- 2009.12.21 Spring MVC 초간단 예제 1
- 2009.12.21 framework jpetstore 샘플 분석기
- 2009.12.21 Simplest Spring 3 Application, 초간단 Spring 3 어플
- 2009.12.21 내가 Prototype에서 jQuery로 옮긴 이유
- 2009.12.18 Paging.java 페이지 계산 및 링크 출력 클래스
- 2009.12.09 [Apache - Tomcat] 로드 밸런싱, 세션 클러스터링
- 2009.12.09 apache 에서 제공하는 Common Validator 사용하기
- 2009.12.09 자바 String Util 들
- 2009.12.09 오라클 데이타딕셔너리
- 2009.12.08 Insert BLOG(Picture or Photo) Data Type Into Oracle Database
- 2009.12.08 Create a table in database
- 2009.12.08 Demo ResultSet Oracle
- 2009.12.03 20091203 ajax 모듈화
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
<script type="text/javascript">
// InternetVersion
function getInternetVersion(ver) {
var rv = -1; // Return value assumes failure.
var ua = navigator.userAgent;
var re = null;
if(ver == "MSIE"){
re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
}else{
re = new RegExp(ver+"/([0-9]{1,}[\.0-9]{0,})");
}
if (re.exec(ua) != null){
rv = parseFloat(RegExp.$1);
}
return rv;
}
//브라우저 종류 및 버전확인
function browserCheck(){
var ver = 0; // 브라우저 버전정보
if(navigator.appName.charAt(0) == "N"){
if(navigator.userAgent.indexOf("Chrome") != -1){
ver = getInternetVersion("Chrome");
alert("Chrome"+ver+"입니다.");
}else if(navigator.userAgent.indexOf("Firefox") != -1){
ver = getInternetVersion("Firefox");
alert("Firefox"+ver+"입니다.");
}else if(navigator.userAgent.indexOf("Safari") != -1){
ver = getInternetVersion("Safari");
alert("Safari"+ver+"입니다.");
}
}else if(navigator.appName.charAt(0) == "M"){
ver = getInternetVersion("MSIE");
alert("MSIE"+ver+"입니다.");
}
}
</script>
</head>
<body>
<input type="button" value="브라우저판별" onclick="browserCheck();">
</body>
</html>
pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
<script type="text/javascript">
function getInternetExplorerVersion() {
var rv = -1; // Return value assumes failure.
if (navigator.appName == 'Microsoft Internet Explorer') {
var ua = navigator.userAgent;
alert(ua);
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null)
rv = parseFloat(RegExp.$1);
}
return rv;
}
function checkVersion() {
var msg = "You're not using Windows Internet Explorer.";
var ver = getInternetExplorerVersion();
if (ver > -1) {
if (ver >= 8.0)
msg = "You're using a recent copy of Windows Internet Explorer.";
else
msg = "You should upgrade your copy of Windows Internet Explorer.";
}
alert(msg);
}
function IsIE8Browser() {
var rv = -1;
var ua = navigator.userAgent;
var re = new RegExp("Trident\/([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null) {
rv = parseFloat(RegExp.$1);
}
alert(ua);
alert(re);
alert("re.exec(ua) : "+re.exec(ua));
alert(rv);
return (rv == 4);
}
</script>
</head>
<body>
<input type="button" value="브라우저테스트1" onclick="checkVersion();">
<input type="button" value="브라우저테스트2" onclick="IsIE8Browser();">
</body>
</html>
Output all message types
log.debug( 'this is a debug message' ); log.info( 'this is an info message' ); log.warn( 'this is a warning message' ); log.error( 'this is an error message' );
Click the block to execute the code
Generate test string
log.profile( 'generate test string' ); var testContent = ''; for ( var i = 0; i < 3000; i++ ) { testContent += '-'; } log.profile( 'generate test string' );
Click the block to execute the code
Adding Blackbird to your page
- Download the files and place them on your server or in a local directory on your computer.
- Include blackbird.js in your page.
- Inlcude blackbird.css in your page.
Your HTML source should look similar to the following code:
<html> <head> <script type="text/javascript" src="/PATH/TO/blackbird.js"></script> <link type="text/css" rel="Stylesheet" href="/PATH/TO/blackbird.css" /> ... </head> ...
Browser compatibility
Blackbird is has been smoke-tested on the following browsers:
- Internet Explorer 6+
- Firefox 2+
- Safari 2+
- Opera 9.5
Public API
log.toggle()
- Hide/show Blackbird
log.move()
- Move Blackbird to next fixed positions: top-left, top-right, bottom-left, bottom-right
log.resize()
- Expand/contract Blackbird
log.clear()
- Clear all contents of Blackbird
log.debug( message )
- Add a debug message to Blackbird
message
: the string content of the debug messagelog.info( message )
- Add an info message to Blackbird
message
: the string content of the info messagelog.warn( message )
- Add a warning message to Blackbird
message
: the string content of the warn messagelog.error( message )
- Add an error message to Blackbird
message
: the string content of the warn messagelog.profile( label )
- Start/end a time profiler for Blackbird. If a profiler named
string
does not exist, create a new profiler. Otherwise, stop the profilerstring
and display the time elapsed (in ms). label
: the string identifying a specific profile timer
Keyboard controls
- Hide/show
- F2
- Move
- Shift + F2
- Clear
- Alt + Shift + F2
Interface controls
Pressing the Alt key while clicking any message filter control will only show messages of that type. For example, Alt + click to show only debug messages.
Bookmarklets
Drag the following links to your bookmarks toolbar for quick access to Blackbird commands:
Changing the namespace
The default configuration attaches the public API for Blackbird to the global variable log
. It is possible to have conflicts with existing variable declarations, and it is possible to redefine the global variable log
in other blocks of JavaScript. If you want to define a different variable for Blackbird, such as blackbird
, replace the assignment for NAMESPACE
with any other string.
var NAMESPACE = 'log';
can be replaced with:
var NAMESPACE = 'blackbird';
or:
var NAMESPACE = 'myCustomLog';
The global API will be affected by this change. If you choose to replace log
with myCustomLog
, then log.debug
will become myCustomLog.debug
.
Capture & cancel logging statements
If you're shipping code with logging statements, you might want to capture and cancel commands intended for Blackbird. The following code will do this:
var log = { toggle: function() {}, move: function() {}, resize: function() {}, clear: function() {}, debug: function() {}, info: function() {}, warn: function() {}, error: function() {}, profile: function() {} };
Credits
The code (blackbird.js, blackbird.css) and image assets (blackbird_panel.png, blackbird_icons.png) were created by G. Scott Olson.
The concept for Blackbird was sparked by JavaScript Logging, an article by David F. Miller. The first iteration of this project, named jsLogger, was developed for internal use at Orbitz. In the fall of 2007, jsLogger was rewritten from the ground up, given a facelift, and named project Blackbird.
Contributing to the Blackbird Project
Blackbird is an open source project. If you're intereted in contributing, you can start by checking out the project page on Google Code.
-- 문제
<script type="text/javascript">
function tt(){
var external_links = document.getElementById('external_links');
var links = external_links.getElementsByTagName('a');
for (var i=0;i < links.length;i++) {
var link = links.item(i);
link.onclick = function() {
return confirm('You are going to visit: ' + this.href);
};
}
}
</script>
<div id="external_links">
<a href="http://www.naver.com">link</a>
</div>
<input type="button" name="dddd" onclick="tt();"/>
---
실행조건(1) : 링크를 클릭한다.
실행조건(2) : 버튼을 클릭한 후, 링크를 클릭한다.
결과가 다른 이유는...?
-----------------------------
ex)
window.onload = function() {
tt();
};
출처 : http://dna.daum.net/TR/XMLHttpRequest/
XMLHttpRequest
객체
W3C Working Draft 26 October 2007
- 이 버전:
- http://www.w3.org/TR/2007/WD-XMLHttpRequest-20071026/
- 최신 버전:
- http://www.w3.org/TR/XMLHttpRequest/
- 이전 버전들:
- http://www.w3.org/TR/2007/WD-XMLHttpRequest-20070618/
- http://www.w3.org/TR/2007/WD-XMLHttpRequest-20070227/
- http://www.w3.org/TR/2006/WD-XMLHttpRequest-20060927/
- http://www.w3.org/TR/2006/WD-XMLHttpRequest-20060619/
- http://www.w3.org/TR/2006/WD-XMLHttpRequest-20060405/
- http://www.w3.org/TR/2007/WD-XMLHttpRequest-20070227/
- 작성자:
- Anne van Kesteren (Opera Software ASA) <annevk@opera.com>
- 번역자:
- 이해석 (Infraware) <97079258@infraware.co.kr>
Copyright © 2007 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
요약
The XMLHttpRequest
Object 규격은 서버와 클라이언트간 데이터를 전달하기 위한 스크립트화된 클라이언트 기능을 제공하는 API를 정의한다.
이 문서의 상태
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This is the 26 October 2007 Working Draft of The XMLHttpRequest
Object specification. Please send comments to public-webapi@w3.org (archived) with either [XHR] or [XMLHttpRequest] at the start of the subject line.
This document is produced by the Web API Working Group, part of the Rich Web Clients Activity in the W3C Interaction Domain. Changes made to this document can be found in the W3C public CVS server.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
목차
1. 소개
이 절은 비규범적이다.
XMLHttpRequest
object는 HTTP 클라이언트 인터페이스를 구현한다. 이 인터페이스는 스크립트 엔진을 통해 노출되며 폼 데이터를 보내거나 서버로부터 데이터를 받아오는 기능을 수행한다.
XMLHttpRequest
라는 이름은 웹의 호환성을 위해 지어졌지만 이름의 각 부분은 잠재적으로 오해를 일으킬 수 있다. 첫째, XMLHttpRequest는 XML을 포함한 텍스트 기반의 어떠한 포맷도 지원한다. 둘째, XMLHttpRequest는 HTTP와 HTTPS 프로토콜 모두 사용할 수 있다. (몇몇 구현은 HTTP와 HTTPS 이외의 프로토콜을 지원하기도 하지만 그러한 기능은 본 규격에서는 다루지 않는다.). 마지막으로 XMLHttpRequest의 "request"는 HTTP에 정의된 용어에 비해 광의적으로 사용된다. 즉, HTTP method들을 위한 HTTP request와 response를 수행하기 위한 행위들을 포함한다.
1.1. 사용예
이 절은 비규범적이다.
몇몇 [ECMAScript] 예제들은 본 규격에 열거되었다. 추가로 아래 코드를 참고할 수 있다.
네트워크를 통해 전달된 XML 문서를 가지고 무엇인가를 하는 간단한 코드:
function test(data) {
// taking care of data
}
function handler() {
if(this.readyState == 4 && this.status == 200) {
// so far so good
if(this.responseXML != null && this.responseXML.getElementById('test').firstChild.data)
// success!
test(this.responseXML.getElementById('test').firstChild.data);
else
test(null);
} else if (this.readyState == 4 && this.status != 200) {
// fetched the wrong page or network error...
test(null);
}
}
var client = new XMLHttpRequest();
client.onreadystatechange = handler;
client.open("GET", "test.xml");
client.send();
만약 서버에게 로그 메시지를 전달하고 싶다면:
function log(message) {
var client = new XMLHttpRequest();
client.open("POST", "/log");
client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
client.send(message);
}
만약 서버에 있는 문서의 상태를 확인하고 싶다면:
function fetchStatus(address) {
var client = new XMLHttpRequest();
client.onreadystatechange = function() {
// in case of network errors this might not give reliable results
if(this.readyState == 4)
returnStatus(this.status);
}
client.open("HEAD", address);
client.send();
}
1.2. 준수(Conformance)
다이어그램, 예제, 노트 그리고 비규범적이라고 명시된 절을 제외한 본 문서의 모든 부분은 규범적이다.
이 문서에서 사용된 must, must not, should 와 may 이라는 용어는 RFC 2119 [RFC2119]에 따라 해석된다.
본 규격은 다음과 같은 종류의 산출물을 정의한다.:
- 준수하는 유저 에이전트
-
유저 에이전트는 본 규격에 준수하기 위해 반드시(must) 이 규격에 정의된 대로 동작해야 한다.
만약 유저에이전트가 XML 유저에이전트에 준수하지 않는다면 XML response entity body는 반드시(must) 항상
null
이어야 한다.유저 에이전트는 본 규격에 정의된 알고리즘으로 얻을 수 있는 결과물과 구별 불가능한 결과물을 얻는 알고리즘을 구현할 수 있다. (may)
본 규격에서 사용하는 "준수하는 유저 에이전트(들)"와 "유저 에이전트(들)"는 이 종류의 산출물은 가르킨다.
- 준수하는 XML 유저 에이전트
-
준수하는 유저 에이전트이면서 동시에 namespace well-formed를 보고하는 준수하는 XML처리기인 유저 에이전트를 말한다.[XML] [XMLNS]
1.2.1. 의존성
본 규격은 몇몇 기초 규격에 기반을 두고 있다.
- DOM
-
준수하는 유저에이전트는 반드시(must) DOM Core와 DOM Events에 정의된 기능의 부분 집합을 지원해야한다. [DOM3Events] [DOM3Core]
이 규격이 의존하고 있는 반드시(must) Window Objects 1.0 규격에 정의된 기능의 부분 집합을 지원해야 한다. [Window ]
- HTTP
-
준수하는 유저에이전트는 반드시(must) 특정버전의 HTTP를 지원해야 한다. 꼭(should)
Method
형식에 맞는 HTTP method를 제공해야 하며, 반드시(must) 최소한 아래의 method들을 지원해야 한다.:GET
POST
HEAD
PUT
DELETE
OPTIONS
HTTP에 관한 다른 요구사항은 다음 문서에 정의되어 있다. [RFC2616]
1.2.2. 용어
s1 과 s2 문자열의 case-insensitive match는 두 문자열을 모두 대문자로 만들고 나서 (a-z를 A-Z로 매핑함으로써) 두 문자열이 동일함을 의미한다.
두 개의 URI는 RFC 3987에 정의된 sceheme-based normalization을 수행한 후에 scheme, ihost, port가 모두 동일 할 경우 same-origin 이라고 정의된다. 만약 URI가 두 URI 모두 ihost를 가지고 있지 않을 경우 반드시(must not) same-origin으로 간주되지 말아야 한다. [RFC3987]
1.2.3. 확장
본 규격에 정의된 API의 확장은 강력히 추천되지 않는다. 유저 에이전트들, 워킹 그룹, 그 밖에 관심있는 단체들은 반드시 이러한 확장을 public-webapi@w3.org 와 같은 공개적인 방법으로 논의 해야한다.
2. XMLHttpRequest
객체
XMLHttpRequest
객체는 스크립트에 의해 프로그램적으로 originating server에 접속할 수 있다.
XMLHttpRequest
인터페이스를 구현하는 객체는 반드시(must) EventTarget
인터페이스를 구현해야 한다. [DOM3Events]
Window
인터페이스를 구현하는 객체는 반드시(must) XMLHttpRequest()
생성자를 제공해야한다. [Window]
ECMAScript에서는 다음과 같이 쓰일 수 있다:
var client = new XMLHttpRequest();
XMLHttpRequest()
생성자가 호출될 경우 연관된 Window
객체에 대한 영속적인 포인터가 반드시(must) 새로 생성된 객체에 저장되어야 한다. 이것은 Window
포인터이다. 연관된 Window
객체는 XMLHttpRequest()
생성자가 호출된 것 중 하나이다. 이 포인터는 반드시(must) 해당 윈도우가 속해있는 브라우징 콘텍스트가 파괴된 경우에도 유지되어야 한다. (예를들면 부모 콘텍스트로 부터 제거하는 것과 같이).
브라우징 콘텍스트라는 용어는 Window Object 1.0 규격에 의해 정의된다. [Window]
만약 win
이 Window
객체라면, client
는 아래 예제에서 win
에 대한 포인터를 가질 것이다:
var client = new win.XMLHttpRequest()
interface XMLHttpRequest { // event handler attribute EventListener onreadystatechange; // state const unsigned short UNSENT = 0; const unsigned short OPENED = 1; const unsigned short HEADERS_RECEIVED = 2; const unsigned short LOADING = 3; const unsigned short DONE = 4; readonly attribute unsigned short readyState; // request void open(in DOMString method, in DOMString url); void open(in DOMString method, in DOMString url, in boolean async); void open(in DOMString method, in DOMString url, in boolean async, in DOMString user); void open(in DOMString method, in DOMString url, in boolean async, in DOMString user, in DOMString password); void setRequestHeader(in DOMString header, in DOMString value); void send(); void send(in DOMString data); void send(in Document data); void abort(); // response DOMString getAllResponseHeaders(); DOMString getResponseHeader(in DOMString header); readonly attribute DOMString responseText; readonly attribute Document responseXML; readonly attribute unsigned short status; readonly attribute DOMString statusText; };
XMLHttpRequest
객체는 다섯 가지 상태를 가질 수 있다: UNSENT, OPENED, HEADERS_RECEIVED, LOADING 그리고 DONE. 현재 상태는 readyState
속성에 의해 노출된다. 아래 정의된 방법이 언제 상태 전이가 일어나는지를 정의한다.
생성되었을 때, XMLHttpRequest
객체는 반드시(must) UNSENT 상태여야 한다. 이 상태는 값이 0
인 UNSENT
상수에 의해 표현된다.
OPENED 상태는 open()
메서드가 성공적으로 불렸을 때의 객체의 상태이다. 이 상태에서는 setRequestHeader()
를 이용해 request 헤더를 설정할 수 있으며, send()
를 통해 request를 할 수 있다. 이 상태는 값이 1
인 OPENED
상수에 의해 표현된다.
OPENED 상태는 연관된 send()
플래그를 가지는데, "true" 또는 "false"의 값을 가진다. send()
플래그의 초기값은 "false"이다.
HEADERS_RECEIVED 상태는 모든 response 헤더가 받아진 객체의 상태이다. 이 상태는 값이 2
인 HEADERS_RECEIVED
상수에 의해 표현된다.
LOADING 상태는 response entity body가 받아지고 있는 중의 객체의 상태이다. 이 상태는 값이 3
인 LOADING
상수에 의해 표현된다.
DONE 상태는 데이터의 전송이 끝나거나 전송 중 무한 리다이렉션 같은 오류가 발생한 객체의 상태이다. 이 상태는 값이 4
인 DONE
상수에 의해 표현된다.
DONE는 연관된 error 플래그를 가지며 그 값은 "true" 또는 "false"이다. error 플래그의 초기값은 "false"이다.
response entity body는 현재까지 수신된 entity body의 일부이거나 (LOADING 상태), 완전한 entity body 이다. (DONE 상태). 만약 entity body가 없다면 response entity body 는 "null"이다.
text response entity body는 response entity body를 나타내는 DOMString
이거나 null
이다. Text response entity body는 다음과 같은 알고리즘의 리턴값이다:
-
만약 response entity body가 "null"이면,
null
을 리턴하고 종료한다. -
charset을 "null"로 하자.
-
만약
Content-Type
헤더가 없거나 MIME type이text/xml
,application/xml
이거나+xml
로 끝나는Content-Type
헤더를 가졌다면 (파라메터는 무시한다), character encoding을 판별하기 위해 XML 규격에 설명되어 있는 방법을 사용한다. charset을 판별된 character encoding 값으로 한다. -
만약 MIME type이
text/html
인Content-Type
헤더를 가졌다면, character encoding을 판별하기 위해 HTML 5 규격에 설명되어 있는 방법을 사용한다. charset을 판별된 character encoding 값으로 한다. [HTML5] -
만약
Content-Type
헤더에 지정된 MIME type이 파라메터를 가지고 있고, charset이 "null" 이라면 charset이 그 파라메터의 값으로 한다.XML과 HTML 규격에 정의된 알고리즘은 이미
Content-Type
값을 참고한다. -
만약 charset이 "null"이면, 아래 테이블의 각 행을 첫 줄부터 시작해서 대조하여 처음으로 첫번째 열과 일치하는 행의 두번째 컬럼 값을 charset의 값으로 한다. 만약 일치 하는 행이 없다면 charset 는 "null"로 남는다.
16진수 바이트열 설명 00 00 FE FF UTF-32BE BOM FF FE 00 00 UTF-32LE BOM FE FF UTF-16BE BOM FF FE UTF-16LE BOM EF BB BF UTF-8 BOM -
만약 charset 이 "null"이면 charset를 UTF-8로 한다.
-
Response entity body를 charset를 이용해 디코딩 한 값을 리턴한다. 만약 실패한다면
null
을 리턴한다.
XML response entity body는 response entity body를 나타내는 Document
이거나 null
이다. XML response entity body 는 다음과 같은 알고리즘의 리턴값이다:
-
만약 response entity body가 "null"이면,
null
을 리턴하고 종료한다. -
만약
Content-Type
헤더가 존재하고 MIME type이text/xml
,application/xml
이거나+xml
로 끝나는Content-Type
헤더를 가지지 않았다면 (파라메터는 무시한다),null
을 리턴하고 종료한다. (만약Content-Type
가 전혀 없다면 종료하지 않는다.) -
Response entity body를 XML 규격에 정의된 방법을 따라서 document tree로 파싱한다. parsed document의 값을 그 결과값으로 한다. 만약 지원되지 않는 character encoding이거나 namespace well-formedness 에러 등에 의해 실패한다면
null
을 리턴하고 종료한다. [XML] [XMLNS ]Document tree에 있는 스크립트는 실행되지 않으며, 여기서 참조된 리소스들도 로딩되지 않는다. 또한 연관된 XSLT도 적용되지 않는다.
-
parsed document값을 가지는
Document
인터페이스를 구현한 객체를 리턴한다.
onreadystatechange
of typeEventListener
-
bubbling phase 동안
readystatechange
이벤트가 전달될 경우 이 객체에 등록된 다른 적절한 이벤트 핸들러와 함께 반드시(must) 호출되어야 하는EventListener
를 값을 취하는 속성이다. 초기값은 반드시 (must)null
이다. readyState
of typeunsigned short
, readonly-
이 속성을 읽을 경우 반드시(must) 해당 객체의 현재 상태 값을 리턴해야 한다.
open(method, url, async, user, password)
, method-
호출될 경우 유저 에이전트는 반드시(must) 다음 단계를 따라야 한다. (다른 방식으로 지시되지 않는 한):
-
만약 method인자가 RFC 2616의 5.1.1절에 정의된
Method
형식에 맞지 않은 경우SYNTAX_ERR
예외를 발생하고 종료한다. [RFC2616] -
만약 주어진 method 인자가 보안상의 이유로 지원되지 않을경우 유저 에이전트는 꼭(should)
SECURITY_ERR
예외를 발생하고 종료해야 한다. -
저장된 method값을 method로 한다.
-
만약 method가
GET
,POST
,HEAD
,PUT
,DELETE
또는OPTIONS
와 case-insensitively match하다면 stored method에 이를 a-z를 A-Z로 매핑함으로써 대문자로 변환한 값을 저장한다. -
url에 Fragment identifier가 있다면 이를 제외한 부분을 저장된 url값에 저장한다.
-
만약 저장된 url이 상대적 경로라면,
Window
포인터에 연관된Document
객체의 현재baseURI
속성을 이용해 해결한다. 만약 이것이 실패한다면SYNTAX_ERR
예외를 발생시키고 종료한다. -
만약 저장된 url이 지원되지 않는 scheme을 가졌을 경우,
NOT_SUPPORTED_ERR
예외를 발생시키고 종료한다. -
만약
"user:password"
형식의userinfo
값이 해당 scheme에서 지원되지 않고, 저장된 url값에 이 형식이 존재한다면,SYNTAX_ERR
예외를 발생시키고 종료한다. [RFC3986] -
만약 저장된 url 값이
"user:password"
형식을 가진다면 저장된 user 가 user 부분, 저장된 password 가 password 부분이 되도록한다. -
만약 저장된 url 이
"user"
형식만 가진다면, 저장된 user값이 user 부분이 되도록 한다. -
만약 저장된 url이
Window
포인터에 연관된Document
객체와 same-origin이 아니라면, 유저 에이전트는 꼭(should)SECURITY_ERR
예외를 발생시키고 종료해야 한다. 용어 origin은 HTML 5 규격에 의해 정의된다. [HTML5] -
async 값을 async 인자의 값이 주어졌을 경우에는 그 값으로, 생략되었을 경우에는 true로 한다.
-
만약 user 인자가 주어졌고, 그 형식이 해당 인증 scheme에 적합하지 않은 경우,
SYNTAX_ERR
예외를 발생시키고 종료한다. -
만약 user 인자가 주어졌고
null
이 아니라면 저장된 user 값을 해당 인증 scheme에 지정된 방법으로 인코딩한 값으로 한다. 만약 scheme에서 encoding이 지정되지 않은 경우에는 UTF-8로 인코딩 한 값으로 한다.이 단계는 url 인자에 의해 지정된 user 값보다 우선 순위를 가진다.
-
만약 user 인자가 생략되지 않았고
null
이라면 저장된 user 값을 지운다. -
만약 password 인자가 주어졌고, 그 형식이 해당 인증 scheme에 적합하지 않은 경우,
SYNTAX_ERR
예외를 발생시키고 종료한다. -
만약 password 인자가 주어졌고
null
이 아니라면 저장된 user 값을 해당 인증 scheme에 지정된 방법으로 인코딩한 값으로 한다. 만약 scheme에서 encoding이 지정되지 않은 경우에는 UTF-8로 인코딩 한 값으로 한다. -
만약 password 인자가 생략되지 않았고
null
이라면 저장된 password 값을 지운다. -
send()
알고리즘을 취소하고, response entity body를 "null"로 하고, request header의 목록들을 리셋한다. -
유저 에이전트는 꼭(should) 해당 객체가 수행하는 모든 네트워크 활동을 취소해야 한다.
-
객체의 상태를 OPENED 상태로 세팅하고,
send()
플래그 값을 "false"로 새팅한다. 그리고 동기적으로readystatechange
이벤트를 해당 객체에 보내고, 메서드 호출을 리턴한다.
본 규격의 향후 버전 또는 확장은 cross-site request에 대한 방법을 정의할 가능성이 높다.
-
setRequestHeader(header, value)
, method-
각각의 request는 연관된 값을 지닌 request header 목록을 가진다. 이 메서드는 그 값을 조작하거나 새로운 request header를 지정하는데 사용할 수 있다.
호출 될 경우, 유저 에이전트는 반드시(must) 다음 단계를 따라야한다. (다른 방법으로 지시되지 않았을 경우):
-
만약 객체의 상태가 OPENED 가 아닐 경우
INVALID_STATE_ERR
예외를 발생하고 종료한다. -
만약
send()
플래그가 "true"라면,INVALID_STATE_ERR
예외를 발생하고 종료한다. -
만약 header 인자가 RFC 2616의 4.2절에 정의된
field-name
형식과 맞지 않거나null
일 경우SYNTAX_ERR
예외를 발생하고 종료한다. [RFC2616] -
만약 value 인자가
null
이라면 종료한다. (예외를 발생시키지 않는다.) -
만약 value 인자가 RFC 2616의 4.2절에 정의된
field-value
형식에 맞지 않는다면SYNTAX_ERR
예외를 발생시키고 종료한다. [RFC2616] -
만약 header 인자가 아래의 값 중 하나와 case-insensitively match한다면 꼭(should) 보안상의 이유로 종료되어야 한다:
Accept-Charset
Accept-Encoding
Connection
Content-Length
Content-Transfer-Encoding
Date
Expect
Host
Keep-Alive
Referer
TE
Trailer
Transfer-Encoding
Upgrade
Via
-
역시 보안상의 이유로 만약 header 인자의 첫 여섯글자가
Proxy-
와 case-insensitively match 한다면 종료해야 한다. -
만약 header 인자가 request header 목록에 없다면 연관된 value를 목록에 추가하고 종료한다.
-
만약 header 인자가 request header 목록에 있다면, 복수의 header를 사용하거나 값을 합치거나 그 두 개의 조합을 사용한다. (RFC 2616 4.2절) [RFC2616]
유저 에이전트가 캐싱, 인증, 프록시, 쿠키와 관련해서 header를 어떻게 다루는지 보려면
send()
메서드를 참조하다.// 다음의 스크립트는: var client = new XMLHttpRequest(); client.open('GET', 'demo.cgi'); client.setRequestHeader('X-Test', 'one'); client.setRequestHeader('X-Test', 'two'); client.send(); // ...아래와 같은 request header를 보내게 된다: ... X-Test: one, two ...
-
send(data)
, method-
send()
메서드는 요청을 시작하며, 이의 선택적 인자는 entity body를 제공한다. 저작자들은send()
를null
이 아닌 data 인자와 함께 호출하기 전에setRequestHeader()
로Content-Type
header를 지정 했는지 확인 하도록 강력히 권장된다.호출될 경우 유저 에이전트는 반드시(must) 다음의 단계를 따라야 한다. (다른 방식으로 지정되지 않았을 경우). 이 알고라즘은
open()
또는abort()
메서드가 호출됨으로써 취소될 수 있다.send()
알고리즘이 중단될 경우에 유저 에이전트는 반드시(must) 현재 진행 중인 단계를 끝내고 종료해야 한다.아래 알고리즘은 async가
false
일 경우, 스크립트를 통해 중단될 수 없다. 오직 async가true
이고 해당 메서드가 리턴한 이후에만 중단될 수 있다.-
만약 객체의 상태가 OPENED 가 아니라면
INVALID_STATE_ERR
예외를 발생 시키고 종료한다. -
만약
send()
플래그가 "true"라면INVALID_STATE_ERR
예외를 발생시키고 종료한다. -
만약 async가
true
라면send()
플래그를 "true"로 한다. -
만약 data 인자가 생략되지 않았고,
null
이 아니라면 이 값을 RFC 2616의 7.2절에 정의된 대로 entity body 값으로 사용하되 다음의 규칙을 따른다. [RFC2616]- data가
DOMString
이다. -
전송을 위해 data를 UTF-8로 인코딩한다.
- data가
Document
이다. -
data를 namespace well-formed한 XML document로 직렬화(serialize)하고
data.xmlEncoding
에서 주어진 값으로 인코딩한다. 만약 주어지지 않았을 경우 UTF-8로 인코딩한다. 만약Document
가 직렬화(serialize) 되지 못해서 실패한다면, data가null
인 것 처럼 동작한다.만약
Content-Type
헤더가 request header 목록에 존재하지 않는다면, request header 목록에application/xml
를 값으로Content-Type
헤더를 추가한다.Document
에 대한 이후의 변경은 전송되는 값에 영향을 미치지 않는다. - data가
DOMString
도 아니고,Document
도 아니다. -
data의 호스트 언어에서 지정된 문자열화(stringification) 방법을 사용하고, data가
DOMString
인 것처럼 동작한다. 만약 실패할 경우 data가null
인 것처럼 동작한다.
만약 data 인자가 생략되었거나,
null
이라면 이 요청에서 entity body가 사용되지 않는다. - data가
-
이 단계 직후에 stored url에 stored method의 HTTP method, stored user의 user (만약 있다면), stored password의 password (만약 있다면), entity body와 request header 목록을 이용해 요청을 한다.
-
동기적으로
readystatechange
이벤트를 객체에 보낸다.객체의 상태는 변경되지 않는다. 이 이벤트는 역사적인 이유로 보내지는 것이다.
-
만약 async 가
true
라면send()
메서드 호출을 리턴한다. (하지만 이 알고리즘을 종료하지는 않는다.) -
리소스가 다운로드 되는 동안 아래의 규칙이 적용된다.
- 만약 response가 HTTP redirect라면
-
만약 redirect가 보안상의 문제 점이 없고, (예를 들면 same-origin이라면) 무한 루프에 빠질 위험이 없다면 그 scheme은 투명하게(transparently) 지원되며, redirect를 따라간 후 이 단계 맨 처음으로 돌아한다.
HTTP는 유저에이턴트가 redirect 하는 동안 request method와 entity body를 유지하도록 요구한다. 또한 이러한 자동 redirection이 사용자에게 알려지도록 요구한다.
그렇지 않다면 다음의 단계를 따른다:
-
response entity body를 "null"로 세팅하고 error flag를 "true"로 하고 request header 목록을 리셋한다.
-
동기적으로 객체의 상태를 DONE으로 전환한다.
-
만약 async 가
false
라면NETWORK_ERR
예외를 발생시키고 전체 알고리즘을 종료한다. -
동기적으로
readystatechange
이벤트를 객체에 보낸다. -
전체 알고리즘을 종료한다.
향후 버전의
XMLHttpRequest
객체는 여기에서도error
이벤트를 보내게 될 가능성이 높다. -
- 만약 사용자가 다운로드를 취소한다면
-
다음 단계를 수행한다:
-
response entity body를 "null"로 세팅하고 error flag를 "true"로 하고 request header 목록을 리셋한다.
-
동기적으로 객체의 상태를 DONE으로 전환한다.
-
만약 async 가
false
라면ABORT_ERR
예외를 발생시키고 전체 알고리즘을 종료한다. -
동기적으로
readystatechange
이벤트를 객체에 보낸다. -
전체 알고리즘을 종료한다.
향후 버전의
XMLHttpRequest
객체는 여기에서도abort
이벤트를 보내게 될 가능성이 높다. -
- 네트워크 에러가 발생한 경우라면
-
DNS 에러 또는 다른 종류의 네트워크 에러의 경우 다음의 단계를 수행한다. 여기에는 HTTP status code 410과 같은 어떤 종류의 에러를 나타내는 HTTP response를 포함하지 않는다.
-
response entity body를 "null"로 세팅하고 error flag를 "true"로 하고 request header 목록을 리셋한다.
-
동기적으로 객체의 상태를 DONE으로 전환한다.
-
만약 async 가
false
라면NETWORK_ERR
예외를 발생시키고 전체 알고리즘을 종료한다. -
동기적으로
readystatechange
이벤트를 객체에 보낸다. -
전체 알고리즘을 종료한다.
향후 버전의
XMLHttpRequest
객체는 여기에서도error
이벤트를 보내게 될 가능성이 높다. -
- 만약 모든 HTTP 헤더들을 수신했다면
-
message body(있다면)를 수신하기 전에 만약 모든 HTTP header들을 수신했다면 다음 단계를 따른다:
-
동기적으로 객체의 상태를 HEADERS_RECEIVED으로 전환한다.
-
동기적으로
readystatechange
이벤트를 객체에 보낸다.
-
- 만약 response entity body의 첫 바이트 (또는 더 많은 바이트)를 수신했다면
- 만약 response entity body가 없다면
-
만약 response entity body의 첫 바이트 (또는 더 많은 바이트)를 수신했거나 response entity body가 없다면 다음의 단계를 따른다:
-
동기적으로 객체의 상태를 LOADING으로 전환한다.
-
동기적으로
readystatechange
이벤트를 객체에 보낸다.
-
마지막으로, 리소스의 다운로드가 완료되면 다음 단계로 이동한다.
-
해당 요청이 로딩을 성공적으로 끝내면, 동기적으로 상태를 DONE로 전환하고, 동기적으로
readystatechange
이벤트를 객체에 보낸다. 만약 async가false
라면 이 메서드를 리턴한다.
만약 유저 에이전트가 사용자가 프록시를 설정할 수 있도록 허용한다면 꼭(should) 적절히 요청을 수정해야 한다; 즉, origin server 대신 proxy host에 접속하고,
Request-Line
을 수정하며Proxy-Authorization
헤더를 지정된 대로 보내야 한다.만약 유저 에이전트가 HTTP 인증을 지원한다면 꼭(should) 이 객체로부터 발생한 request에 대해 보호된 영역으로 간주해야 한다. 즉, accessed URI를 포함하고
Authorization
헤더를 보내며401 Unauthorized
요청을 적절히 처리해야한다. 만약 인증이 실패할 경우, 유저 에이전트는 꼭(should) 사용자에게 자격(credentials)에 대해 물어야 한다. [RFC2617]만약 유저 에이전트가 HTTP State Management를 지원한다면 꼭(should) 적절히 쿠키를 저장하고, 제거하고, 보내야 한다. (
Set-Cookie
와Set-Cookie2
response 헤더에 의해 받아지고,Cookie
헤더에 의해 보내진다.) [RFC2965]만약 유저 에이전트가 HTTP cache를 구현한다면 꼭(should)
Cache-Control
request 헤러들 준수해야 한다. (예,Cache-Control: no-cache
는 cache를 사용하지 않는다.) 유저 에이전트는 사용자에 의해 명시적으로 요청된 경우가 아니라면Cache-Control
이나Pragma
헤더를 자동으로 보내서는 안된다(must not). (예, (강제로-)페이지를 Reloading할 경우). 유저 에이전트의 조건 요청에 따른304 Not Modified
response는 반드시(must) 적절한 콘텐트로200 OK
response처럼 보여져야 한다. 유저 에이전트는304 Not Modified
가 반드시(must) 전달되어야 할때 반드시(must)If-None-Match
,If-Modified-Since
와 같은 request header를 설정함으로써 자동 캐시 검증 방법보다 높은 우선 순위의 검증 방법을 제공할 수 있어야한다. [RFC2616]만약 유저 에이전트가 서버 기반 content-nogotiation을 구현한다면 꼭(should)
Accept-Language
,Accept-Encoding
와Accept-Charset
헤더를 적절히 세팅해야한다; 자동으로Accept
헤더를 세팅해서는 안된다(must not). 이러한 request에 대한 response에는 자동으로 디코딩된 content-encoding 들이 반드시must있어야 한다. [RFC2616] -
abort()
, method-
호출될 경우 유저 에이전트는 반드시(must) 다음의 단계를 수행해야한다. (다른 방법으로 지시되지 않을 경우):
-
send()
알고리즘을 취소하고, response entity body를 "null"로 세팅하고, error flag를 "true"로 한 뒤 등록된 모든 request header들을 제거한다. -
유저 에이전트는 꼭(should) 해당 객체가 수행하는 모든 네트워크 활동을 취소해야 한다.
-
만약 상태가 UNSENT 또는 OPENED 이고
send()
플래그 가 "false"이거나, 상태가 DONE 히면 다음 단계로 간다.그렇지 않을 경우 상태를 DONE으로 바꾸고,
send()
플래그를 "false"로 한 뒤, 동기적으로 객체에게readystatechange
이벤트를 보낸다. -
객체 상태를 UNSENT로 바꾼다. (
readystatechange
이벤트를 발생시키지는 않는다.)향후 버전의
XMLHttpRequest
객체는 여기에서도abort
이벤트를 발생시킬 가능성이 높다.
-
getAllResponseHeaders()
, method-
호출될 경우 유저 에이전트는 반드시(must) 다음의 단계를 수행해야한다:
-
만약 error flag 가 "true" 라면,
null
을 리턴하고 종료한다. -
모든 HTTP 헤더를 리턴한다. 이는 단일 문자열로 이루어지며 각각의 헤더 라인은 상태 라인을 제외하고는 U+000D CR U+000A LF 짝으로 분리된다.
// 아래의 스크립트는: var client = new XMLHttpRequest(); client.open("GET", "test.txt", true); client.send(); client.onreadystatechange = function() { if(this.readyState == 3) { print(this.getAllResponseHeaders()); } } // ...다음과 유사한 텍스트를 출력해야 한다: Date: Sun, 24 Oct 2004 04:58:38 GMT Server: Apache/1.3.31 (Unix) Keep-Alive: timeout=15, max=99 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/plain; charset=utf-8
getResponseHeader(header)
, method-
호출될 경우 유저 에이전트는 반드시(must) 다음의 단계를 수행해야한다:
-
만약 header 인자가
field-name
형식에 맞지 않는 다면 빈 문자열을 리턴하고 종료한다. -
만약 error 플래그 가 "true"라면
null
을 리턴하고 종료한다. -
만약 header 인자가 마지막으로 보낸 request의 헤더들 중 여러 개와 case-insensitively match 한다면, 이 헤더들의 값을 U+002C COMMA와 그 뒤에 U+0020 SPACE로 구별되는 한 개의 문자열로 합쳐서 리턴하고 종료한다.
-
만약 header 인자가 마지막으로 보낸 request의 헤더들 중 한 개와 case-insensitively match 한다면, 이 헤더의 값 리턴하고 종료한다.
-
null
을 리턴한다.
// 아래의 스크립트는: var client = new XMLHttpRequest(); client.open("GET", "test.txt", true); client.send(); client.onreadystatechange = function() { if(this.readyState == 3) { print(client.getResponseHeader("Content-Type")); } } // ...다음과 같은 문자열을 출력해야 한다: Content-Type: text/plain; charset=utf-8
responseText
of typeDOMString
, readonly-
얻을때, 유저 에이전트는 반드시(must) 다음과 같은 단계를 수행해야 한다:
-
만약 상태가 LOADING 또는 DONE이 아니라면
INVALID_STATE_ERR
예외를 발생시키고 종료한다. -
text response entity body를 리턴한다.
-
responseXML
of typeDocument
, readonly-
얻을때, 유저 에이전트는 반드시(must) 다음과 같은 단계를 수행해야 한다:
-
만약 상태가 DONE이 아니라면
INVALID_STATE_ERR
예외를 발생시키고 종료한다. -
XML response entity body를 리턴한다.
-
status
of typeunsigned short
, readonly-
얻을때, 존재한다면 이는 반드시(must) 서버에서 보내진 HTTP status code를 리턴해야 한다. (보통 성공적인 요청에 대해서는
200
이다). 존재하지 않는 다면 유저 에이전트는 반드시(must)INVALID_STATE_ERR
예외를 발생시켜야 한다. statusText
of typeDOMString
, readonly-
얻을때, 존재한다면 이는 반드시(must) 서버에서 보내진 HTTP status text를 리턴해야 한다. (status code 바로 뒤에 있다). 존재하지 않는다면 유저 에이전트는 반드시(must)
INVALID_STATE_ERR
예외를 발생시켜야 한다.
2.1. XMLHttpRequest
객체의 이벤트
이 절은 XMLHttpRequest
인터페이스를 구현한 객체가 보내는 다양한 이벤트에 대해 설명한다. 이 버전의 규격에서는 한 개의 이벤트만 정의되어 있다.
readystatechange
- 유저 에이전트가
readystatechange
이벤트를 발생시킬 경우에는 (위에서 지시된바와 같이) bubble 하지 말아야 하며(must not), cancelable 하지 않아야 하고(must not), 반드시(must)Event
인터페이스를 구현해야한다. 이의namespaceURI
속성은 반드시(must)null
이어야 한다. [DOM3Events]
2.2. XMLHttpRequest
객체의 예외
이 규격에서 정의된 몇몇 알고리즘은 예외를 발생시킬 수 있다. 이 예외들은 모두 DOM Level 3 Core에서 정의된 ExceptionCode
의 일부이며 DOMException
객체를 사용한다. 여기에 더해 본 규격에서는 ExceptionCode
에 아래와 같은 새로운 상수들을 정의한다. [DOM3Core]
const unsigned short SECURITY_ERR = 18; const unsigned short NETWORK_ERR = 101; const unsigned short ABORT_ERR = 102;
SECURITY_ERR
예외는 유저 에이전트의 보안 정책에 위배되거나 보안상의 위험이 있는 방식으로 동작을 수행하거나 데이터에 접근할 경우 발생한다.
SECURITY_ERR
예외는 궁극적으로 DOM Level 3 Core 규격의 향후 버전에 동일한 정의와 상수값으로 포함되어야 한다. 그 때까지 구현자에 대한 가이드로서 여기에 정의된다. (이것은 다른 예외들과 다른 상수값을 가지는 이유이기도 하다.)
NETWORK_ERR
예외는 동기적인 요청에서 네트워크 에러가 생겼을때 발생한다.
ABORT_ERR
예외는 동기적인 요청에서 사용자가 요청을 취소했을 때 발생한다.
본 규격에 정의되지 않은 것들
이 절은 비규범적이다.
본 규격은 향후 버전의 규격에서 고려되고 있는 다음과 같은 기능들을 포함하지 않는다:
load
이벤트와onload
속성;error
이벤트와onerror
속성;progress
이벤트와onprogress
속성;abort
이벤트와onabort
속성;- 타이머가 제안되었으며,
ontimeout
속성이 고려 중; - redirect를 막는 속성;
text/html
문서에 대한responseXML
;- Cross-site
XMLHttpRequest
; - 바이트 스트립을 다루기위한
responseBody
; - MIME 타입을 수정하기 위한
overrideMimeType
; getRequestHeader()
와removeRequestHeader()
.
참조
- [DOM3Core]
- Document Object Model (DOM) Level 3 Core Specification, A. Le Hors, P. Le Hégaret, L. Wood, G. Nicol, J. Robie, M. Champion, S. Byrne, editors. W3C, April 2004.
- [DOM3Events]
- Document Object Model (DOM) Level 3 Events Specification (work in progress), Björn Höhrmann, editor. W3C, April 2006.
- [ECMAScript]
- ECMAScript Language Specification, Third Edition. ECMA, December 1999.
- [HTML5]
- HTML 5 (work in progress), Ian Hickson, editor. WHATWG, 2007.
- [RFC2119]
- Key words for use in RFCs to Indicate Requirement Levels, S. Bradner. IETF, March 1997.
- [RFC2616]
- Hypertext Transfer Protocol -- HTTP/1.1, R. Fielding, J. Gettys, J. Mogul, H. Frystyk, L. Masinter, P. Leach, T. Berners-Lee, editors. IETF, June 1999.
- [RFC2617]
- HTTP Authentication: Basic and Digest Access Authentication, P. Hallam-Baker, J. Hostetler, S. Lawrence, P. Leach, A. Luotonen, L. Stewart, editors. IETF, June 1999.
- [RFC2965]
- HTTP State Management Mechanism, D. Kristol, L. Montulli, editors. IETF, October 2000.
- [RFC3986]
- Uniform Resource Identifier (URI): Generic Syntax, T. Berners-Lee, R. Fielding, L. Masinter, editors. IETF, January 2005.
- [RFC3987]
- Internationalized Resource Identifiers (IRIs), M. Duerst, M. Suignard, editors. IETF, January 2005.
- [Window]
- Window Object 1.0 (work in progress), I. Davis, M. Stachowiak, editors. W3C, April 2006.
- [XML]
- Extensible Markup Language (XML) 1.0 (Fourth Edition), T. Bray, J. Paoli, C. Sperberg-McQueen, E. Maler, F. Yergeau, editors. W3C, September 2006.
- [XMLNS]
- Namespaces in XML (Second Edition), T. Bray, D. Hollander, A. Layman, R. Tobin, editors. W3C, August 2006.
감사의 말
이 절은 비규범적이다.
The editor would like to thank to the following people who have contributed to this specification (ordered by first name):
- Ahmed Kamel
- Alex Hopmann
- Alex Vincent
- Alexey Proskuryakov
- Asbjørn Ulsberg
- Boris Zbarsky
- Björn Höhrmann
- Cameron McCormack
- Christophe Jolif
- Charles McCathieNevile
- Dan Winship
- David Håsäther
- Dean Jackson
- Denis Sureau
- Doug Schepers
- Douglas Livingstone
- Elliotte Harold
- Eric Lawrence
- Gideon Cohn
- Gorm Haug Eriksen
- Hallvord R. M. Steen
- Håkon Wium Lie
- Ian Davis
- Ian Hickson
- Ivan Herman
- Jeff Walden
- Jens Lindström
- Jim Deegan
- Jim Ley
- Joe Farro
- Jonas Sicking
- Julian Reschke
- Karl Dubost
- Maciej Stachowiak
- Magnus Kristiansen
- Marc Hadley
- Marcos Caceres
- Mark Baker
- Mark Nottingham
- Mohamed Zergaoui
- Pawel Glowacki
- Robin Berjon
- Ruud Steltenpool
- Simon Pieters
- Stewart Brodie
- Sunava Dutta
- Zhenbin Xu
Special thanks to the Microsoft employees who first implemented the XMLHttpRequest
interface, which was first widely deployed by the Windows Internet Explorer browser.
Special thanks also to the WHATWG for drafting an initial version of this specification in their Web Applications 1.0 document (now renamed to HTML 5). [HTML5]
Thanks also to all those who have helped to improve this specification by sending suggestions and corrections. (Please, keep bugging us with your issues!)
function array_max( )
{
var i, max = this[0];
for (i = 1; i < this.length; i++)
{
if (max < this[i])
max = this[i];
}
return max;
}
Array.prototype.max = array_max;
var x = new Array(1, 2, 3, 4, 5, 6);
var y = x.max( );
function tt(){
alert("y : "+y);
}
</script>
<input type="button" onclick="tt();">
출처 : http://jsguide.net/ver2/examples/index.php?mode=view&category=5&qstr=&uid=197&page=1
자바스크립트에서는 2바이트 문자를 한글자로 처리하기 때문에 바이트 단위로 잘라야 하거나 검사할때 문제가 많습니다.
그래서 바이트 단위로 길이를 검사하고 자르는 메소드를 추가해봤습니다.
서핑중에 sms 보내는 폼이 나오면... 혹시나하고 소스를 열어보곤 하는데.. ㅇ_ㅇ(힉..)
80바이트가 넘는지 검사하는걸 상당히 복잡하게 코딩해논게 보이더군요..
코드 나갑니다
<script>
/**
* string String::cut(int len)
* 글자를 앞에서부터 원하는 바이트만큼 잘라 리턴합니다.
* 한글의 경우 2바이트로 계산하며, 글자 중간에서 잘리지 않습니다.
*/
String.prototype.cut = function(len) {
var str = this;
var l = 0;
for (var i=0; i<str.length; i++) {
l += (str.charCodeAt(i) > 128) ? 2 : 1;
if (l > len) return str.substring(0,i) + "...";
}
return str;
}
/**
* bool String::bytes(void)
* 해당스트링의 바이트단위 길이를 리턴합니다. (기존의 length 속성은 2바이트 문자를 한글자로 간주합니다)
*/
String.prototype.bytes = function() {
var str = this;
var l = 0;
for (var i=0; i<str.length; i++) l += (str.charCodeAt(i) > 128) ? 2 : 1;
return l;
}
aaa = "동a해b물c과 백두산이";
alert(aaa.cut(15));
// 또는
bbb = "너무긴내용너무긴내용너무긴내용";
alert("length: " + bbb.length + "\nbytes(): " + bbb.bytes());
//응용
if (bbb.bytes() > 20) {
alert("내용이 너무 깁니다");
} else {
// 처리
}
/* 여기서부터는 실행되지는 않습니다 ---
// 다시응용 (sms폼에서 80바이트 넘는지 처리할경우)
var sms = document.forms['폼이름'].elements['입력창'];
if (sms.value.bytes() > 80) {
alert('80바이트까지만 전송할 수 있습니다');
sms.value = sms.value.cut(80);
}
여기까지 실행되지 않습니다 */
</script>
<script type="text/javascript">
<!--
function ttt(){
var request_os = window.navigator.appVersion;
var os_array = request_os.split(";");
//alert("os_array : "+os_array[2]);
//alert("request_os : "+request_os);
//alert(document.cookie);
switch(os_array[2])
{
case " Windows NT 6.1" :
os_version = "Windows7";
break;
case " Windows NT 6.0" :
os_version = "WindowsVista";
break;
case " Windows NT 5.1" :
os_version = "WindowsXP";
break;
case " Windows NT 5.0" :
os_version = "Windows2000";
break;
case " Windows NT 4.0" :
os_version = "WindowsNT";
break;
case " Windows 98" :
os_version = "Windows98";
break;
case " Windows 95" :
os_version = "Windows95";
break;
}
alert("os_version : "+os_version);
}
-->
</script>
<input type="button" onclick="ttt();">
개발 환경 세팅
사전 준비물 및 버전
- JDK 5.0
- Eclipse 3.2.1
- MySQL 5.0.x
- Tomcat 5.5.20
개발 환경 세팅을 위해 필요한 파일들
- Eclipse 플러그인
- Maven IDE
- Spring IDE
- Eclipse Workspaces 압축 파일
예제 소스
강의 문서
•Architecture
•Spring Introduction
•Spring IoC 이해 및 활용
•Spring AOP 이해 및 활용
•Spring Abstract API
•Spring Transaction
•Spring Test
Spring 2.0
- Aspect Weaver 사용 : Run As.. >> Arguments >> VM Arguments에 -javaagent:lib/aspectjweaver.jar 를 추가해주어야 한다.
- 모든 spring 프로젝트에 적용 : Window || Preferences || Java || Installed JREs || 사용하는 JDK의 VM Aguments에 -javaagent:lib/aspectjweaver.jar을 추가한다.
- 이 경우 모든 프로젝트의 lib 디렉토리 하위에 aspectjweaver.jar가 존재해야한다.
출처 : http://www.javajigi.net/pages/viewpage.action?pageId=7777
출처 :
http://www.aboutjsp.com/spring/board/viewArticle.do?cpage=1&pgroup=1&boardId=JSPTip&keyfield=contentTitle&keyword=&boardSeq=62
JAVA를 배우는 사람, 또는 프로그래밍에 종사하시는 개발자 분들이 다시한번 봐도 괜찮을거 같은
목차
-
- 1 객체지향의 구멍 static
- 2 Java는 Pointer언어이다? (Java에는 Pointer밖에 없다?)
- 3 상속과 interface의 문제점
- 4 package와 access 제어에 관한 이해
- 5 기타 Java 기능
- 6 이래도 Java가 간단한가?
- 7 Java 기능 적용 몇가지
- 8 Java 5.0 Tiger 에 대하여
-
- 8.1 Working with java.util.Arrays
- 8.2 Using java.util.Queue interface
- 8.3 java.lang.StringBuilder 사용하기
- 8.4 Using Type-Safe Lists
- 8.5 Writing Generic Types
- 8.6 새로운 static final enum
- 8.7 Using java.util.EnumMap
- 8.8 Using java.util.EnumSet
- 8.9 Convert Primitives to Wrapper Types
- 8.10 Method Overload resolution in AutoBoxing
- 8.11 가변적인 argument 개수 ...
- 8.12 The Three Standard Annotation
- 8.13 Creating Custom Annotation Types
- 8.2 Using java.util.Queue interface
- 8.1 Working with java.util.Arrays
- 9 The for/in Statement
-
- 9.1 for/in 의 자주 사용되는 형태
- 10 Static Import
-
- 10.1 static member/method import
- 11 References
1.1 Java는 객체지향 언어이다? #
- 오해1. "객체지향에서는 객체끼리 서로 메세지를 주고 받으며 동작한다." 라는 말을 듣고 다음과 같이 생각할 수 있다. "객체지향에서는 객체가 각각 독립하여 움직인다는 것인가, 그러면 각 객체에 독립된 thread가 할당되어 있단 말인가?" 그렇지 않다. "메세지를 보낸다"라는 것은 단순히 각 객체의 함수 호출에 불과하다.
- 오해2. "객체지향에서는 method가 class에 부속되어 있다"는 말을 듣고 다음과 같이 생각할 수 있다. "그러면 instance별로 method의 실행코드가 복제되고 있는 것이 아닌가?" 물론 이것도 오해다. method의 실행코드는 종래의 함수와 동일한 어딘가 다른곳(JVM의 class area)에 존재하며 그 첫번째 파라미터로 객체의 포인터 this가 건네질 뿐이다.
- 오해3. "그렇다면 각 instance가 method의 실행코드를 통째로 갖고 있지 않는 것은 확실하지만, method의 실행 코드의 포인터는 각 instance별로 보관하고 있는것이 아닌가?" 이것은 약가 애매한 오해이긴 하다. JVM 스펙에서는 class영역에 실행코드를 갖고 있으며, method 호출시 별도의 stack frame이 생성되어 실행되고 실행 완료시 복귀 주소를 전달한다.
1.2 전역변수 #
- (참고) final 초기화에서의 주의점. 예를 들어 다음과 같은 코드를 보았을때 우려되는 점은 무엇인가?
public final static Color WHITE = new Color(255, 255, 255);
- static field는 final의 경우와 달리 정말 "하나여도 되는지" 여부를 잘 생각해야 한다.
- static method는 주저하지 말고 쓰되 다음 두가지의 경우 매우 활용적이다.
- 다른 많은 클래스에서 사용하는 Utility Method 군을 만드는 경우. (주로 Utility Class의 method)
- 클래스 안에서만 사용하는 "하청 메소드(private method)". 이유를 예를 들어 설명하면, 아래와 같은 조금은 과장된 클래스가 있다고 하자.
public class T .. private int a; private int b; private int c; private int calc(){ c = a + b; return c * c; } ....other method or getter/setter...
private static int calc(int a, int b){ int c = a + b; return c * c; }
2.1 Java는 primitive형을 제외하곤 모두 Pointer이다 #
2.2 null은 객체인가? #
- null object의 instance method 호출
- null object의 field(member variables)에 대한 액세스 또는 그 값의 변경
- null의 길이를 배열처럼 취득할 경우
- null의 slot을 배열처럼 액세스 또는 수정
- null을 Throwable처럼 throw 할 경우
2.3 String에 대하여 #
String str = "111222"; String a = "111"; String b = "222"; String c = "111"; String d = b; String t = str.substring(0,3); //111
- str == (a + b) ==> 이것은 두개의 참조와 하나의 참조를 비교했으므로 당연히 false이다.
- a == b ==> 이것은 당연히 false
- d == b ==> 이것은 동일한 reference이므로 true
- a == t ==> a 와 t 는 둘다 값이 "111"이다. 하지만 이것은 서로 다른 참조를 가져 false이다. 그렇다면 다음 5번도 false일까?
- a == c ==> 이것은 true이다. 아.. 4번과 혼란스럽다. 이것이 참인 이유는? ==> 이것의 해답은 JSR 3.10.5에 다음과 같이 나와 있기 때문이다.
2.4 객체지향의 캡슐화 파괴 주의 #
//(참고)Member에는 두개의 field(Identity Class 형의 ID와 Family Class 형의 family)가 있다. /** shallow copy */ Member shallowCopy(){ Member newer = new Member(); newer.id = this.id; newer.family = this.family; return newer; } /** deep copy */ Member deepCopy(){ Member newer = new Member(); newer.id = new Idetity(this.id.getId(), this.id.getName()); newer.family = new Family(this.family.getFamilyName(), this.family.getFamilyInfo()); return newer; }
- 모든 field(member variable)를 생성자(constructor)를 이용하여 초기화 한다.
- 모든 field는 private으로 선언하고, getter method는 만들되 setter는 기술하지 않는다.
2.5.1 배열은 object 인가? #
2.5.2 배열의 length는 왜 field(member variable)인가? #
2.5.3 final과 배열에 대하여... #
2.5.4 "Java에서의 다차원 배열은 존재하지 않는다." #
2.6.1 "Java에서 parameter(argument) 전달은 무조건 'call by value' 이다" #
2.6.2 "C와 같은 언어는 static linking이지만, Java는 dynamic linking이다." #
2.7.1 "Garbage Collection은 만능이 아니다." #
2.8.1 "결국 Java에는 pointer가 있는 것인가, 없는 것인가?" #
// 이부분에 대해 Object를 이해하시면 족히 이런 문제는 사라질것으로 봅니다.
// 클래스에 대한 인스턴스(object)들은 reference로 밖에 가질(참조될)수 없기 때문입니다.
// 컴파일러 입장이 아닌 언어 자체의 사상을 가지고 쉽게 이해시키는 것이 좋을것 같습니다.
3.1.1 상속에 있어서의 생성자(constructor) #
3.1.2 "down cast는 본질적으로 매우 위험하다" #
3.1.3 "추상클래스에 final이 있으면 compile error이다" #
3.2.1 "interface는 interface일뿐 다중 상속의 대용품이 아니다." #
3.3 상속 제대로 사용하기 #
- 상속에서는 슈퍼클래스가 허용하고 있는 조작을 서브클래스에서 모두 허용해야 하지만, composition과 delegation에서는 조작을 제한할 수 있다.
- 클래스는 결코 변경할 수 없지만, composition하고 있는 객체는 자유롭게 변경할 수 있다. 예를 들면 학생 클래스가 영원이 학생이 아니라 나중에 취직을 하여 직장인 클래스가 될수 있다.
- Shape(부모)의 공통된 내용을 구현한 구현 클래스(ShapeImpl)를 만든다.
- Polyline과 Circle 클래스에서 ShapeImpl을 composition하고 부모와 공통되지 않는 method를 각각 위임 받는다.
- ShapeImpl 클래스의 method를 추출한 ShapeIF interface를 작성하고 Polyline과 Circle에서는 implements 한다.
4.1.1 "package는 '계층구조' 인가?" #
4.1.2 "compiler 가 인식하는 class검색 순서(소스코드내 클래스가 발견될 경우 그 클래스의 위치를 찾는 순서)" #
- 그 class자신
- 단일형식으로 임포트된 class
- 동일한 패키지에 존재하는 다른 class
- 온디멘드 형식(..* 형태) 임포트 선언된 class
4.2.1 "interfacde member의 access 제어" #
4.2.2 그렇다면 interface를 다른 package에 대하여 숨기고 싶으면 어떻게 하는가? #
5.1.1 "Multi Thread에서는 흐름은 복수이지만 data는 공유될 수 있다." #
5.1.2 "Thread는 객체와 직교하는 개념이다." #
- Multi Thread에서는 Thread라는 처리 흐름이 2개 이상 존재할 수 있다.
- 어떤 Thread에서 움직이기 시작한 method가 다른 method를 호출 했을때 호출된 측의 method는 호출한 측의 method와 동일한 Thread에서 동작한다.
- Thread의 경계와 객체의 경계는 전혀 관계가 없다. 즉, Thread와 객체는 직교하고 있다.
5.1.3 "Synchronized 의 이해" #
synchronized void method1(){ ... } void method2(){ synchronized(this){ ... } }
5.1.4 "Thread 사용법의 정석은?" #
- Runnable을 implements하고 Thread의 참조를 보유(composition) 하는 방법. 이경우는 단지 Runnable만 implement함으로서 해결되는 경우가 대부분이긴 하지만, 그 class 내에서 해당 class의 Thread를 조작하게 된다면 composition한 Thread 객체에 delegation하면 된기 때문이다.
- Thread class를 상속하는 방법. JDK의 소스를 보면 Thread class에는 Runnable을 implements 하고 있다. 그리고 run method는 native method이다. 따라서 Thread를 상속한 모든 클래스는 사실 Runnable을 implements하고 있는 것이다. run method는 abstract가 아니므로 구현되어 있고 우리는 이를 오버라이드하여 사용하고 있다. 이 방식을 사용하면 Thread의 method를 안팍으로 자유롭게 호출할 수 이지만, 이미 다른 class를 상속하고 있다면 이 방식을 사용할 수는 없다.
5.2.1 "finally 절은 반드시 어떠한 경우에도 실행되는가?" #
try{ ... System.exit(1); }catch(...){ }finally{ ... //이 부분은 실행되지 않는다. }
5.2.2.1 Error #
5.2.2.2 RuntimeException #
5.2.2.3 그밖의 Exception #
5.2.3 "OutOfMemoryError는 어떻게 처리해야 하는가?" #
5.3 Object Serialize #
5.3.1 "Serialize를 위해서는 marker interface인 java.io.Serializable interface를 implements해야한다." #
5.3.2 "super class는 Serializable이 아닌데 sub class만 Serializable인 경우의 문제점" #
5.3.3 "transient field의 복원(?)관련" #
private void writeObject(java.io.ObjectOutputStream out) throws IOException; private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
5.3.4 "Stack Overflow에 주의하라!" #
private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { s.defaultWrtieObject(); //이 코드는 무조건 들어가게 되는데 이곳 소스의 System.arraycopy()에서 overflow발생한다. s.writeInt(size); //이부분이 실제 추가되어 Stack Overflow를 예방한다. for(Entry e = ...) s.writeObject(e.element); } ... } //readObject()도 이와 같은 개념으로 변경되어 있다.
5.4.1 "중첩클래스의 개념" #
5.4.2 "내부클래스는 부모의 참조를 몰래 보유하고 있다." #
class Test{ class InnerClass { int i; ... } public static void main(String[] args){ InnerClass icls = new InnerClass(); ... } }
5.4.3 "local inner class에 대하여" #
public class OuterClass { public int get(){ int i = 9; int id = 99; int id2 = 99; final int id3 = 100000; class LocalInnerClass { int id = 100; LocalInnerClass(){ System.out.println("LocalInnerClass"); } int getId(){ return id3 + id; } } LocalInnerClass lic = new LocalInnerClass(); return id + lic.getId(); } public static void main(String[] args){ OuterClass outer = new OuterClass(); System.out.println("id = " + outer.get()); //결과 값은 "100000(id3) + 100(LocalInnerClass.id) + 99(OuterClass.get())" 인 100199가 나온다. } }
5.4.4 "anonymous class(무명클래스)에 대하여" #
class AnonymousTest { private interface Printable { void print(); } static void doPrint(Printable p){ p.print(); } public static void main(String[] args){ doPrint( new Printable(){ public void print(){ System.out.println("this is new Printable print()"); } }); } }
6.1.1 "overload란 이름이 가고 인수가 다른 method에 compiler가 다른 이름을 붙이는 기능" #
//IFS.java interface IFS { public String getName(); } //Impl1.java class Impl1 implements IFS { public String getName(){ return "Impl1"; } } //Impl2.java class Impl2 implements IFS { public String getName(){ return "Impl2"; } } //main이 있는 OverloadTest.java public class OverloadTest { static void pr(int i){ System.out.println("pr_int : " + i); } static void pr(String s){ System.out.println("pr_string : " + s); } static void pr(IFS ifs){ System.out.println("pr_string : " + ifs.getName()); } static void pr_run(Impl1 i1){ System.out.println("pr_run : " + i1.getName()); } static void pr_run(Impl2 i2){ System.out.println("pr_run : " + i2.getName()); } public static void main(String[] args){ OverloadTest test = new OverloadTest(); test.pr(10); test.pr("Jeid"); IFS ifs1 = new Impl1(); test.pr(ifs1); IFS ifs2 = new Impl2(); test.pr(ifs2); //pr_run(ifs1); //pr_run(ifs2); } }
OverloadTest.java:36: cannot resolve symbol symbol : method pr_run (IFS) location: class OverloadTest pr_run(ifs1); ^ OverloadTest.java:37: cannot resolve symbol symbol : method pr_run (IFS) location: class OverloadTest pr_run(ifs2); ^ 2 errors
6.1.2 "그렇다면 overload에서 실제로 혼동되는 부분은 무엇인가?" #
class OverloadTest2 { static int base(double a, double b){ ... } //method A static int count(int a, int b){ ... } //method B static int count(double a, double b){ ... } //method C static int sum(int a, double b){ ... } //method D static int sum(double a, int b){ ... } //method E }
- base(3,4) 를 호출했을때 수행되는 method는? => 당연히 method A (3과 4는 정수라도 double이 되므로 정상적으로 수행됨)
- count(3,4) 를 호출했을때 수행되는 method는? => B와 C중 갈등이 생긴다. 이럴경우 JVM은 가장 한정적(more specific)한 method를 찾는다. 여기서 3과 4는 정수형에 가까우므로 method B 가 호출된다.
- count(3, 4.0) 을 호출했을때 수행되는 method는? => 이것은 4.0 이 double이므로 method C 가 더 한정적이므로 method C 가 호출된다.
- sum(3,4.0) 을 호출했을때 수행되는 method는? => 이것은 당연히 type이 일치하는 method D.
- sum(3,4) 를 호출했을때 수행되는 method는?? => 이런 코드가 소스내에 있으면 다음과 같은 compile 오류를 표출한다.
OverloadTest.java:48: reference to sum is ambiguous, both method sum(int,double) in OverloadTest and method sum(double,int) in OverloadTest match System.out.println("sum(3,4) = " + sum(3,4)); ^ 1 error
6.1.3 (참고) 또다른 혼동, overload한 method를 override 하면? #
6.2.1 "Java class의 member 4 종류" #
- instance field
- instance method
- static field
- static method
6.2.2 "override시 method 이름에 대한 함정" #
6.2.3 "또다른 나의(?) 실수 - 말도 안되는 오타" #
public class Member { private int memberNo; public int getMemberNo(){ return this.memberNo; } public void setMemberNo(int menberNo){ this.memberNo = memberNo; } ...... }
6.2.4 "static member를 instance를 경유하여 참조해서는 안 된다." #
ClassA a = new ClassA(); int i = a.AA; //instance를 경유하여 접근 int j = ClassA.AA; //올바르게 접근
6.2.5 "super keyword는 부모의 this" #
6.4.1 "생성자에 void 를 붙인다면?" #
public class ConstructorTest{ void ConstructorTest(){ System.out.println("Constuctor"); } ..... }
6.4.2 "if / switch 의 함정" #
.... if( a < 5 ) b = 3; c = 10; //이부분은 나중에 추가된 라인이다. if( isStudent ) if( isFemale ) sayHello("Hi~~"); else sayHello("Hello Professor~");
7.1.1 "interface 분리의 필요성" #
7.2 Java에서의 열거형 #
public static final int LEFT = 0; public static final int CENTER = 1; public static final int RIGHT = 2; ... label.setAlignment(Label.CENTER); ...
//LabelAlignment.java public class LabelAlignment { private LabelAlignment() {} //이는 생성자를 private으로 하여 다른데서는 만들지 못하도록 하기위함이다. public static final LabelAlignment LEFT = new LabelAlignment(): public static final LabelAlignment CENTER = new LabelAlignment(): public static final LabelAlignment RIGHT = new LabelAlignment(): } //변형된 Label.java 의 일부.. public synchronized void setAlignment(LabelAlignment alignment){ if( alignment == LabelAlignment.LEFT ){ ...//왼쪽으로 맞추기.. }else if( ... ... } } ...
//LabelAlignment.java public class LabelAlignment { private int flag; private LabelAlignment(int flag){ this.flag = flag; } public static final LabelAlignment LEFT = new LabelAlignment(0): public static final LabelAlignment CENTER = new LabelAlignment(1): public static final LabelAlignment RIGHT = new LabelAlignment(2): public boolean equals(Object obj){ return ((LabelAlignment)obj).flag == this.flag; } } //변형된 Label.java 의 일부.. public synchronized void setAlignment(LabelAlignment alignment){ if( LabelAlignment.LEFT.equals(alignment) ){ ...//왼쪽으로 맞추기.. }else if( ... ... } } ...
7.3 Debug write #
#ifdef DEBUG fprintf(stderr, "error...%d\n", error); #endif /* DEBUG */
if( Debug.isDebug ){ System.out.println("error..." + error); }
// 1. GetCallerSecurityManager.java public final class GetCallerSecurityManager extends SecurityManager { public Class[] getStackTrace(){ return this.getClassContext(); } } // 2. GetCallerClass.java public final class GetCallerClass { private static GetCallerSecurityManager mgr; static{ mgr = new GetCallerSecurityManager(); System.setSecurityManager(mgr); } public static void writeCaller(String str){ Class[] stk = mgr.getStackTrace(); int size = stk.length; for(int i = 0; i < size; i++){ System.out.println("stk[" + i + "] = " + stk[i]); } String className = stk[2].getName(); System.out.println("className is " + className + " : " + str); } } // 3. GetCallerClassMain1 : 호출하는 클래스 예제 1 public class GetCallerClassMain1 { public static void main(String[] args){ GetCallerClass.writeCaller(", real is 1."); } } // 4. GetCallerClassMain1 : 호출하는 클래스 예제 2 public class GetCallerClassMain2 { public static void main(String[] args){ GetCallerClass.writeCaller(", real is 2."); } }
className is GetCallerClassMain1 : , real is 1. className is GetCallerClassMain2 : , real is 2.
8.1 Working with java.util.Arrays #
package com.jeid.tiger; import java.util.Arrays; import java.util.Comparator; import java.util.List; public class ArraysTester { private int[] arr; private String[] strs; public ArraysTester(int size) { arr = new int[size]; strs = new String[size]; for (int i = 0; i < size; i++) { if (i < 10) { arr[i] = 100 + i; } else if (i < 20) { arr[i] = 1000 - i; } else { arr[i] = i; } strs[i] = "str" + arr[i]; } } public int[] getArr() { return this.arr; } public String[] getStrs() { return this.strs; } public static void main(String[] args) { int size = 50; ArraysTester tester = new ArraysTester(size); int[] testerArr = tester.getArr(); int[] cloneArr = tester.getArr().clone(); String[] testerStrs = tester.getStrs(); String[] cloneStrs = tester.getStrs().clone(); // clone test if (Arrays.equals(cloneArr, testerArr)) { System.out.println("clonse int array is same."); } else { System.out.println("clonse int array is NOT same."); } if (Arrays.equals(cloneStrs, testerStrs)) { System.out.println("clonse String array is same."); } else { System.out.println("clonse String array is NOT same."); } // 2부터 10까지 값 셋팅 Arrays.fill(cloneArr, 2, 10, new Double(Math.PI).intValue()); testerArr[10] = 98; testerStrs[10] = "corea"; testerStrs[11] = null; List<String> listTest = Arrays.asList(testerStrs); System.out.println("listTest[10] = " + listTest.get(10)); System.out.println("------- unsorted arr -------"); System.out.println("Arrays.toString(int[]) = " + Arrays.toString(testerArr)); System.out.println("Arrays.toString(String[]) = " + Arrays.toString(testerStrs)); Arrays.sort(testerArr); // Arrays.sort(testerStrs); //NullPointerException in sort method..(null이 없더라도 길이에 대한 크기 체크는 못함) Arrays.sort(testerStrs, new Comparator<String>() { public int compare(String s1, String s2) { if (s1 == null && s2 == null) { return 0; } else if (s1 == null && s2 != null) { return -1; } else if (s1 != null && s2 == null) { return 1; } else if (s1.length() < s2.length()) { return -1; } else if (s1.length() > s2.length()) { return 1; } else if (s1.length() == s2.length()) { return 0; } else { return s1.compareTo(s2); } } }); System.out.println("------- sorted arr -------"); System.out.println("Arrays.toString(int[]) = " + Arrays.toString(testerArr)); System.out.println("Arrays.toString(String[]) = " + Arrays.toString(testerStrs)); System.out.println("------------------------------------------------"); String[][] mstrs1 = { { "A", "B" }, { "C", "D" } }; String[][] mstrs2 = { { "a", "b" }, { "c", "d" } }; String[][] mstrs3 = { { "A", "B" }, { "C", "D" } }; System.out.println("Arrays.deepToString(mstrs1) = " + Arrays.deepToString(mstrs1)); System.out.println("Arrays.deepToString(mstrs2) = " + Arrays.deepToString(mstrs2)); System.out.println("Arrays.deepToString(mstrs3) = " + Arrays.deepToString(mstrs3)); if( Arrays.deepEquals(mstrs1, mstrs2)) { System.out.println("mstrs1 is same the mstrs2."); }else { System.out.println("mstrs1 is NOT same the mstrs2."); } if( Arrays.deepEquals(mstrs1, mstrs3)) { System.out.println("mstrs1 is same the mstrs3."); }else { System.out.println("mstrs1 is NOT same the mstrs3."); } System.out.println("mstrs1's hashCode = " + Arrays.deepHashCode(mstrs1)); System.out.println("mstrs2's hashCode = " + Arrays.deepHashCode(mstrs2)); System.out.println("mstrs3's hashCode = " + Arrays.deepHashCode(mstrs3)); } }
8.2 Using java.util.Queue interface #
package com.jeid.tiger; import java.util.LinkedList; import java.util.PriorityQueue; import java.util.Queue; public class QueueTester { public static void main(String[] args) { System.out.println("---------- testFIFO ----------"); testFIFO(); System.out.println("---------- testOrdering ----------"); testOrdering(); } private static void testFIFO() { Queue<String> q = new LinkedList<String>(); q.add("First"); q.add("Second"); q.add("Third"); String str; while ((str = q.poll()) != null) { System.out.println(str); } } private static void testOrdering() { int size = 10; Queue<Integer> qi = new PriorityQueue<Integer>(size); Queue<String> qs = new PriorityQueue<String>(size); for (int i = 0; i < size; i++) { qi.offer(10 - i); qs.offer("str" + (10 - i)); } for (int i = 0; i < size; i++) { System.out.println("qi[" + i + "] = " + qi.poll() + ", qs[" + i + "] = " + qs.poll()); } } }
8.3 java.lang.StringBuilder 사용하기 #
package com.jeid.tiger; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class StringBuilderTester { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("str1"); list.add("str2"); list.add("str3"); String ret = appendItems(list); System.out.println("ret = " + ret); } private static String appendItems(List<String> list) { StringBuilder sb = new StringBuilder(); for (Iterator<String> iter = list.iterator(); iter.hasNext();) { sb.append(iter.next()).append(" "); } return sb.toString(); } }
8.4 Using Type-Safe Lists #
package com.jeid.tiger; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class ListTester { public static void main(String[] args) { List<String> list = new LinkedList<String>(); list.add("str1"); list.add("str2"); list.add(new Integer(123)); // <-- String이 아니므로 compile error!! //Iterator에 String type을 명시하므로 정삭작동됨. for (Iterator<String> iter = list.iterator(); iter.hasNext();) { String str = iter.next(); System.out.println("srt = " + str); } //Iterator에 String type을 명시하지 않았으므로 아래 A 부분에서 compile 오류 발생!! for (Iterator iter = list.iterator(); iter.hasNext();) { String str = iter.next(); //A System.out.println("srt = " + str); } //byte, short, int, long, double, float 동시 사용 List<Number> lstNum = new LinkedList<Number>(); lstNum.add(1); lstNum.add(1.2); for (Iterator<Number> iter = lstNum.iterator(); iter.hasNext();) { Number num = iter.next(); System.out.println("num = " + num); } } }
8.5 Writing Generic Types #
class AnyTypeList<T> { //class AnyTypeList<T extends Number> { // <-- 이는 Number를 상속한 type은 허용하겠다는 의미. private List<T> list; //private static List<T> list; // <-- 이는 정적이므로 compile error 발생!!! public AnyTypeList(){ list = new LinkedList<T>(); } public boolean isEmpty(){ return list == null || list.size() == 0; } public void add(T t){ list.add(t); } public T grap(){ if (!isEmpty() ) { return list.get(0); } else { return null; } } }
8.6 새로운 static final enum #
package com.jeid.tiger; import com.jeid.BaseObject; import com.jeid.MyLevel; public class EnumTester extends BaseObject { private static long start = System.currentTimeMillis(); public static void main(String[] args) { try { test(); enum1(); } catch (Exception e) { e.printStackTrace(); } printEllapseTime(); } private static void test() throws Exception { byte[] b = new byte[0]; System.out.println(b.length); } private static void enum1() { //enum TestEnum { A, B }; //enum cannot be local!!! for(MyVO.TestEnum te: MyVO.TestEnum.values()){ System.out.println("Allow TestEnum value : " + te); } System.out.println("---------------------------------------"); MyVO vo = new MyVO(); vo.setName("enum1"); vo.setLevel(MyLevel.A); System.out.println(vo); System.out.println("isA = " + vo.isA() + ", isGradeA = " + vo.isLevelA()+ ", isValueOfA = " + vo.isValueOfA()); System.out.println("getLevelInKorean = " + vo.getLevelInKorean()); } private static void printEllapseTime() { System.out.println("==> ellapseTime is " + (System.currentTimeMillis() - start) + " ms."); } } package com.jeid.tiger; import com.jeid.BaseObject; import com.jeid.MyLevel; public class MyVO extends BaseObject { enum TestEnum { A, B }; // this is same public static final private int id; private String name; private MyLevel grade; // private List<T> list; public MyLevel getLevel() { return grade; } public void setLevel(MyLevel grade) { this.grade = grade; } public boolean isA() { return "A".equals(this.grade); } public boolean isValueOfA() { return MyLevel.valueOf("A").equals(grade); } public boolean isLevelA() { return MyLevel.A.equals(this.grade); } //A,B,C..대신 0,1,2... 도 동일함. public String getLevelInKorean() { switch(this.grade){ case A: return "수"; case B: return "우"; case C: return "미"; case D: return "양"; case E: return "가"; default: return "없음"; } } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
8.7 Using java.util.EnumMap #
package com.jeid.tiger; import java.util.EnumMap; public class EnumMapTester { private enum MyEnum { A, B, C }; // this is same the static final.. public static void main(String[] args) { MyEnum[] enums = MyEnum.values(); System.out.println("MyEnum is " + enums[0] + ", " + enums[1] + ", " + enums[2]); EnumMap<MyEnum, String> em = new EnumMap<MyEnum, String>(MyEnum.class); em.put(MyEnum.A, "수"); em.put(MyEnum.B, "우"); em.put(MyEnum.C, "미"); em.put(MyEnum.B, "가"); //key 중복은 HashMap과 동일하게 overwrite임. for (MyEnum myEnum : MyEnum.values()) { System.out.println(myEnum + " => " + em.get(myEnum)); } } }
8.8 Using java.util.EnumSet #
package com.jeid.tiger; import java.util.EnumSet; public class EnumSetTester { private enum MyEnum { A, B, C, a, b, c }; // this is same the static final.. public static void main(String[] args) { MyEnum[] enums = MyEnum.values(); System.out.println("MyEnum is " + enums[0] + ", " + enums[1] + ", " + enums[2]); EnumSet<MyEnum> es1 = EnumSet.of(MyEnum.A, MyEnum.B, MyEnum.C); EnumSet<MyEnum> es2 = EnumSet.of(MyEnum.a, MyEnum.b, MyEnum.c); EnumSet<MyEnum> es3 = EnumSet.range(MyEnum.a, MyEnum.c); if (es2.equals(es3)) { System.out.println("e2 is same e3."); } for (MyEnum myEnum : MyEnum.values()) { System.out.println(myEnum + " contains => " + es1.contains(myEnum)); } } }
8.9 Convert Primitives to Wrapper Types #
package com.jeid.tiger; public class AutoBoxingTester { public static void main(String[] args) { int i = 0; Integer ii = i; // boxing. JDK 1.4에서는 incompatible type error가 발생 했었으나 Tiger에서는 괜찮다. int j = ii; // unboxing for (ii = 0; ii < 5; ii++) { // Integer인데도 ++ 연산자 지원. } i = 129; ii = 129; if (ii == i) { System.out.println("i is same ii."); } // -128 ~ 127 사이의 수는 unboxing이 되어 == 연산이 허용되지만, // 그 범위 외의 경우 Integer로 boxing된 상태므로 equals를 이용해야함. // 이는 버그가 발생했을 경우 찾기 쉽지 않은 단점도 내포하고 있다.!! checkIntegerSame(127, 127); // same checkIntegerSame(128, 128); // Not same checkIntegerEquals(128, 128); // equals checkIntegerSame(-128, -128); // same checkIntegerSame(-129, -129); // Not same checkIntegerEquals(-129, -129); // equals System.out.println("--------------------------------------------"); Boolean arriving = false; Boolean late = true; String ret = arriving ? (late ? "도착했지만 늦었네요." : "제시간에 잘 도착했군요.") : (late ? "도착도 못하고 늦었군요." : "도착은 못했지만 늦진 않았군요."); System.out.println(ret); StringBuilder sb = new StringBuilder(); sb.append("appended String"); String str = "just String"; boolean mutable = true; CharSequence chSeq = mutable ? sb : str; System.out.println(chSeq); } private static void checkIntegerSame(Integer ii, Integer jj) { if (ii == jj) { System.out.println("ii = " + ii + ", jj = " + jj + " ==> jj is same ii."); } else { System.out.println("ii = " + ii + ", jj = " + jj + " ==> jj is NOT same ii!!"); } } private static void checkIntegerEquals(Integer ii, Integer jj) { if (ii.equals(jj)) { System.out.println("ii = " + ii + ", jj = " + jj + " ==> jj is equals ii."); } else { System.out.println("ii = " + ii + ", jj = " + jj + " ==> jj is NOT equals ii!!"); } } }
8.10 Method Overload resolution in AutoBoxing #
package com.jeid.tiger; public class OverloadTester { public static void main(String[] args) { double d = 10; Integer ii = new Integer(10); doSomething(10); doSomething(1000); doSomething(ii); doSomething(d); } private static void doSomething(Integer ii) { System.out.println("This is doSomething(Integer)"); } private static void doSomething(double d) { System.out.println("This is doSomething(double)"); } }
8.11 가변적인 argument 개수 ... #
package com.jeid.tiger; public class VarArgsTester { public static void main(String[] args) { setNumbers(1, 2); setNumbers(1, 2, 3, 4); setNumbers(1); // setNumbers(); //해당 되는 method가 없어 compile error!! System.out.println("=============================================="); setNumbers2(1, 2, 3, 4); setNumbers2(1); setNumbers2(); } // this is same setNumbers(int first, int[] others) private static void setNumbers(int first, int... others) { System.out.println("-----------setNumbers()----------- : " + first); for (int i : others) { System.out.println("i = " + i); } } // this is same setNumbers(int[] others) private static void setNumbers2(int... others) { System.out.println("-----------setNumbers2()----------- : " + (others != null && others.length > 0 ? others[0] : "null")); for (int i : others) { System.out.println("i = " + i); } } }
8.12 The Three Standard Annotation #
//정상적인 사용 @Override public int hashCode(){ return toString().hashCode(); } //스펠링이 틀려 compile error!! @Override public int hasCode(){ //misspelled => method does not override a method from its superclass error!! return toString().hashCode(); }
package com.jeid.tiger; public class AnnotationDeprecateTester { public static void main(String[] args){ DeprecatedClass dep = new DeprecatedTester(); dep.doSomething(10); //deprecated } } class DeprecatedClass { @Deprecated public void doSomething(int ii){ //deprecated System.out.println("This is DeprecatedClass's doSomething(int)"); } public void doSomethingElse(int ii){ System.out.println("This is DeprecatedClass's doSomethingElse(int)"); } } class DeprecatedTester extends DeprecatedClass { @Override public void doSomething(int ii){ System.out.println("This is DeprecatedTester's doSomething(int)"); } }
package com.jeid.tiger; import java.util.ArrayList; import java.util.List; public class AnnotationSuppressWarningsTester { @SuppressWarnings({"unchecked", "fallthrough"} ) private static void test1(){ List list = new ArrayList(); list.add("aaaaaa"); } @SuppressWarnings("unchecked") private static void test2(){ List list = new ArrayList(); list.add("aaaaaa"); } //warning이 없는 소스. private static void test3(){ List<String> list = new ArrayList<String>(); list.add("aaaaaa"); } }
8.13 Creating Custom Annotation Types #
package com.jeid.tiger; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented @Target( { ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String columnName(); String methodName() default ""; } //사용하는 쪽.. public class AnnotationTester { @MyAnnotation(columnName = "test", methodName = "setTest") private String test; @MyAnnotation(columnName = "grpid") public String grpid; .... } //위의 test 멤버의 경우 다음과 같이 접근 가능하다. Field testField = cls.getDeclaredField("test"); if (testField.isAnnotationPresent(MyAnnotation.class)) { Annotatioin anno = testField.getAnnotation(MyAnnotation.class); System.out.println(anno.columnName() + ", method = " + anno.methodName()); }
9.1 for/in 의 자주 사용되는 형태 #
//1. 가장 단순한 형태인 배열(array) String[] strs = { "aaa", "bbb", "ccc" }; for (String str : strs) { System.out.println(str); } //2. List by using Iterator List<Number> lstNum = new LinkedList<Number>(); lstNum.add(1); lstNum.add(1.2); for (Iterator<Number> iter = lstNum.iterator(); iter.hasNext();) { Number num = iter.next(); System.out.println("num = " + num); } //3. List를 바로 사용 List<String> lst = new LinkedList<String>(); lst.add("aaaaa"); lst.add("bbbbb"); lst.add("ccccc"); lst.add("ddddd"); for (String str : lst) { System.out.println("str = " + str); } // 4. List of List List[] lists = { lst, lst }; for (List<String> l : lists) { for (String str : l) { System.out.println("str = " + str); } }
10.1 static member/method import #
//예를 들어 System.out.println() 이라는 것을 사용하기 위해서는 다음의 import 문이 필요하다. import java.lang.System; //물론 java.lang 이기에 import 문이 필요없지만 예를 들자면 그렇다는 것이다.&^^ //허나, Tiger에서는 다음과 같이 사용할수 있다. import static java.lang.System.out; ... out.println(...); // method를 import 한다면.. import static java.lang.System.out.println; ... println(...);
11 References #
- http://java.sun.com/j2se/1.4.2/docs/index.html
- http://java.sun.com/j2se/1.5.0/docs/index.html
- SUN의 JLS
- http://java.sun.com/docs/books/jls/html/index.html
- Java 핵심원리 - 마에바시 가즈야 저 - 영진닷컴
- Java 1.5 Tiger - Brett McLaughlin 저 - O'Reilly
from: http://www.twelo.com/96
Properties configProps = new Properties();
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(propertyFilePath);
configProps.load(inputStream);
------------------------------------------------
// 메일보낼사람 정보 가져오기
// db.properties 가져오기 (* db.properties file은 DBCheckThread.class와 같은곳에 존재...)
Properties properties = new Properties();
InputStream inputstream = getClass().getResourceAsStream("/senduser.properties");
properties.load(inputstream);
String sendUser = properties.getProperty("mailuser");
String toUser = "hanho9@nate.com";
Spring - Java/J2EE Application Framework
Reference Documentation
Version 1.2.2
(Work in progress)
Table of Contents
- 서문
- 1. 소개
- 2. 배경 지식
- 3. Beans, BeanFactory 그리고 ApplicationContext
-
- 3.1. 소개
- 3.2. BeanFactory 와 BeanDefinitions - 기초
-
- 3.2.1. BeanFactory
- 3.2.2. BeanDefinition
- 3.2.3. bean 클래스
- 3.2.2. BeanDefinition
-
- 3.2.3.1. 생성자를 통한 Bean 생성
- 3.2.3.2. 정적 factory메소드를 통한 Bean 생성
- 3.2.3.3. 인스턴스 factory메소드를 통한 Bean 생성
- 3.2.3.2. 정적 factory메소드를 통한 Bean 생성
- 3.2.3.1. 생성자를 통한 Bean 생성
- 3.2.4. bean 구분자 (id 와 name)
- 3.2.5. 싱글톤이나 비-싱글톤(non-singleton)
- 3.2.1. BeanFactory
- 3.3. 프라퍼티, 협력자(collaborators), autowiring 과 의존성 체크
-
- 3.3.1. bean프라퍼티와 협력자(collaborators) 셋팅하기
- 3.3.2. 생성자의 인자 분석
-
- 3.3.2.1. 생성자의 인자 타입 대응(match)
- 3.3.2.2. 생성자의 인자 인덱스
- 3.3.2.1. 생성자의 인자 타입 대응(match)
- 3.3.3. bean프라퍼티와 상세화된 생성자의 인자
-
- 3.3.3.1. value와 ref 간략화한(shortcut) 폼
- 3.3.4. 메소드 삽입
-
- 3.3.4.1. 룩업(Lookup) 메소드 삽입
- 3.3.4.2. 임의의 메소드 교체
- 3.3.4.1. 룩업(Lookup) 메소드 삽입
- 3.3.5. depends-on 사용하기
- 3.3.6. Autowiring 협력자
- 3.3.7. 의존성을 위한 체크
- 3.3.6. Autowiring 협력자
- 3.3.1. bean프라퍼티와 협력자(collaborators) 셋팅하기
- 3.4. bean의 성질을 커스터마이징하기.
-
- 3.4.1. Lifecycle 인터페이스
-
- 3.4.1.1. InitializingBean / init-method
- 3.4.1.2. DisposableBean / destroy-method
- 3.4.1.1. InitializingBean / init-method
- 3.4.2. 당신이 누구인지 알고 있다.(Knowing who you are)
-
- 3.4.2.1. BeanFactoryAware
- 3.4.2.2. BeanNameAware
- 3.4.2.1. BeanFactoryAware
- 3.4.3. FactoryBean
- 3.5. 추상 그리고 자식 bean정의
- 3.6. BeanFactory와 상호작동하기
- 3.7. BeanPostprocessors로 bean 커스터마이징하기
- 3.8. BeanFactoryPostprocessors를 가진 bean factory커스터마이징하기
-
- 3.8.1. PropertyPlaceholderConfigurer
- 3.8.2. PropertyOverrideConfigurer
- 3.8.1. PropertyPlaceholderConfigurer
- 3.9. 추가적인 사용자지정 PropertyEditors 등록하기
- 3.10. 존재하는 bean을 위한 별칭을 추가하기 위한 별칭 요소 사용하기.
- 3.11. ApplicationContext에 대한 소개
- 3.12. ApplicationContext에 추가된 기능
- 3.10. 존재하는 bean을 위한 별칭을 추가하기 위한 별칭 요소 사용하기.
-
- 3.12.1. MessageSource 사용하기
- 3.12.2. events 전파하기
- 3.12.3. Spring내에서 자원(resources) 사용하기
- 3.12.2. events 전파하기
- 3.12.1. MessageSource 사용하기
- 3.13. ApplicationContext내에서 사용자정의 행위
-
- 3.13.1. ApplicationContextAware 표시자(marker) 인터페이스
- 3.13.2. BeanPostProcessor
- 3.13.3. BeanFactoryPostProcessor
- 3.13.4. PropertyPlaceholderConfigurer
- 3.13.2. BeanPostProcessor
- 3.13.1. ApplicationContextAware 표시자(marker) 인터페이스
- 3.14. 추가적인 사용자정의 PropertyEditors 등록하기
- 3.15. 프라퍼티 표현에서 bean프라퍼티 또는 생성자의 인자를 셋팅하기.
- 3.16. 필드값으로부터 bean프라퍼티 또는 생성자의 인자를 셋팅하기.
- 3.17. 다른 메소드를 호출하고 선택적으로 반환값을 사용한다.
- 3.18. 하나의 파일로부터 다른것으로 bean정의를 끌어오기
- 3.19. 웹 애플리케이션으로부터 ApplicationContext생성하기.
- 3.20. Glue 코드와 좋지않은 싱글톤
- 3.15. 프라퍼티 표현에서 bean프라퍼티 또는 생성자의 인자를 셋팅하기.
- 3.1. 소개
- 4. PropertyEditors, data binding, validation and the BeanWrapper
- 5. Spring AOP: Spring을 이용한 Aspect 지향적인 프로그래밍
-
- 5.1. 개념
-
- 5.1.1. AOP 개념
- 5.1.2. Spring AOP의 기능과 대상
- 5.1.3. Spring 내 AOP 프록시
- 5.1.2. Spring AOP의 기능과 대상
- 5.1.1. AOP 개념
- 5.2. Spring내 Pointcuts
-
- 5.2.1. 개념
- 5.2.2. pointcuts에서의 작업(operation)
- 5.2.3. 편리한 pointcut 구현물
- 5.2.2. pointcuts에서의 작업(operation)
-
- 5.2.3.1. 정적 pointcuts
- 5.2.3.2. 동적 pointcuts
- 5.2.3.1. 정적 pointcuts
- 5.2.4. Pointcut 수퍼클래스(superclasses)
- 5.2.5. 사용자지정 pointcuts
- 5.2.1. 개념
- 5.3. Spring 내 Advice타입들
-
- 5.3.1. Advice 생명주기
- 5.3.2. Spring내 Advice 타입들
-
- 5.3.2.1. Interception around advice
- 5.3.2.2. 전(Before) advice
- 5.3.2.3. Throws advice
- 5.3.2.4. advice를 반환한 후(after returning advice)
- 5.3.2.5. Introduction advice
- 5.3.2.2. 전(Before) advice
- 5.3.2.1. Interception around advice
- 5.3.1. Advice 생명주기
- 5.4. Spring내 Advisors
- 5.5. AOP프록시를 생성하기 위한 ProxyFactoryBean사용하기
-
- 5.5.1. 기본
- 5.5.2. 자바빈 프라퍼티
- 5.5.3. 프록시 인터페이스
- 5.5.4. 프록시 클래스
- 5.5.5. 'global' advisor 사용하기
- 5.5.2. 자바빈 프라퍼티
- 5.5.1. 기본
- 5.6. 편리한 프록시 생성
-
- 5.6.1. TransactionProxyFactoryBean
- 5.6.2. EJB 프록시
- 5.6.1. TransactionProxyFactoryBean
- 5.7. 간결한 프록시 정의
- 5.8. ProxyFactory로 프로그램적으로 AOP프록시를 생성하기.
- 5.9. advised 객체 조작하기.
- 5.10. "autoproxy" 기능 사용하기
- 5.8. ProxyFactory로 프로그램적으로 AOP프록시를 생성하기.
-
- 5.10.1. autoproxy bean정의
-
- 5.10.1.1. BeanNameAutoProxyCreator
- 5.10.1.2. DefaultAdvisorAutoProxyCreator
- 5.10.1.3. AbstractAdvisorAutoProxyCreator
- 5.10.1.2. DefaultAdvisorAutoProxyCreator
- 5.10.1.1. BeanNameAutoProxyCreator
- 5.10.2. 메터데이타-지향 자동 프록시 사용하기.
- 5.11. TargetSources 사용하기
-
- 5.11.1. 핫 스왑가능한 대상 소스
- 5.11.2. 풀링 대상 소스
- 5.11.3. 프로토 타입 대상 소스
- 5.11.4. ThreadLocal 대상 소스
- 5.11.2. 풀링 대상 소스
- 5.11.1. 핫 스왑가능한 대상 소스
- 5.12. 새로운 Advice 타입을 정의하기
- 5.13. 추가적으로 읽을거리와 자원들
- 5.14. 로드맵
- 5.13. 추가적으로 읽을거리와 자원들
- 6. AspectJ 통합
-
- 6.1. 개요
- 6.2. Spring IoC를 사용하여 AspectJ 설정하기.
-
- 6.2.1. "싱글톤" aspects
- 6.2.2. 싱글톤 형식이 아닌 aspect
- 6.2.3. Gotchas
- 6.3. 목표 Spring advice를 위한 AspectJ 포인트컷(pointcut) 사용하기
- 6.4. AspectJ를 위한 Spring aspect
- 6.1. 개요
- 7. 트랜잭션 관리
-
- 7.1. Spring 트랜잭션 추상화
- 7.2. 트랜잭션 전략
- 7.3. 프로그래밍적인 트랜잭션 관리
- 7.2. 트랜잭션 전략
-
- 7.3.1. TransactionTemplate 사용하기
- 7.3.2. PlatformTransactionManager 사용하기
- 7.3.1. TransactionTemplate 사용하기
- 7.4. 선언적 트랜잭션 관리
- 7.5. 프로그래밍적/선언적 트랜잭션 관리 중 선택하기
- 7.6. 트랜잭션 관리를 위한 어플리케이션 서버가 필요한가?
- 7.7. 공통적인 문제
- 7.6. 트랜잭션 관리를 위한 어플리케이션 서버가 필요한가?
- 7.1. Spring 트랜잭션 추상화
- 8. 소스 레벨 메타데이타 지원
-
- 8.1. 소스-레벨 메타데이타
- 8.2. Spring의 메타데이타 지원
- 8.3. Jakarta Commons Attributes과 통합
- 8.4. 메타데이타와 Spring AOP 자동 프록시
- 8.2. Spring의 메타데이타 지원
-
- 8.4.1. 기초
- 8.4.2. 선언적인 트랜잭션 관리
- 8.4.3. 풀링(Pooling)
- 8.4.4. 사용자정의 메타데이타
- 8.4.2. 선언적인 트랜잭션 관리
- 8.4.1. 기초
- 8.5. MVC 웹티어 설정을 최소화하기 위한 속성 사용하기
- 8.6. 메타데이타 속성의 다른 사용
- 8.7. 추가적인 메타데이타 API를 위한 지원 추가하기
- 8.6. 메타데이타 속성의 다른 사용
- 8.1. 소스-레벨 메타데이타
- 9. DAO support
-
- 9.1. 소개
- 9.2. 일관된 예외 구조
- 9.3. DAO지원을 위한 일관된 추상클래스
- 9.2. 일관된 예외 구조
- 9.1. 소개
- 10. JDBC를 사용한 데이터 접근
-
- 10.1. 소개
- 10.2. 기본적인 JDBC처리와 에러 처리를 위한 JDBC Core클래스 사용하기
-
- 10.2.1. JdbcTemplate
- 10.2.2. DataSource
- 10.2.3. SQLExceptionTranslator
- 10.2.4. Statements 실행하기
- 10.2.5. 쿼리문 실행하기
- 10.2.6. 데이터베이스 수정하기
- 10.2.2. DataSource
- 10.2.1. JdbcTemplate
- 10.3. 데이터베이스에 연결하는 방법을 제어하기
-
- 10.3.1. DataSourceUtils
- 10.3.2. SmartDataSource
- 10.3.3. AbstractDataSource
- 10.3.4. SingleConnectionDataSource
- 10.3.5. DriverManagerDataSource
- 10.3.6. DataSourceTransactionManager
- 10.3.2. SmartDataSource
- 10.3.1. DataSourceUtils
- 10.4. 자바 객체처럼 JDBC작업을 모델링 하기.
-
- 10.4.1. SqlQuery
- 10.4.2. MappingSqlQuery
- 10.4.3. SqlUpdate
- 10.4.4. StoredProcedure
- 10.4.5. SqlFunction
- 10.4.2. MappingSqlQuery
- 10.4.1. SqlQuery
- 10.1. 소개
- 11. 객체-관계 연결자(O/R Mappers)를 이용한 데이터 접근
-
- 11.1. 소개
- 11.2. Hibernate
-
- 11.2.1. 자원 관리
- 11.2.2. 애플리케이션 컨텍스트내에서 자원 정의
- 11.2.3. Inversion of Control: Template and Callback
- 11.2.4. 탬플릿 대신에 AOP인터셉터 적용하기.
- 11.2.5. 프로그램의 트랜잭션 구분(Demarcation)
- 11.2.6. 선언적인 트랜잭션 구분
- 11.2.7. 트랜잭션 관리 전략
- 11.2.8. 컨테이너 자원 대 로컬 자원
- 11.2.9. 샘플들
- 11.2.2. 애플리케이션 컨텍스트내에서 자원 정의
- 11.2.1. 자원 관리
- 11.3. JDO
- 11.4. iBATIS
-
- 11.4.1. 1.3.x and 2.0 사이의 개요와 차이점
- 11.4.2. iBATIS 1.3.x
-
- 11.4.2.1. SqlMap을 셋업하기
- 11.4.2.2. SqlMapDaoSupport 사용하기
- 11.4.2.3. 트랜잭션 관리
- 11.4.2.2. SqlMapDaoSupport 사용하기
- 11.4.2.1. SqlMap을 셋업하기
- 11.4.3. iBATIS 2
-
- 11.4.3.1. SqlMap 셋업하기
- 11.4.3.2. SqlMapClientDaoSupport 사용하기
- 11.4.3.1. SqlMap 셋업하기
- 11.4.1. 1.3.x and 2.0 사이의 개요와 차이점
- 11.1. 소개
- 12. 웹 MVC framework
-
- 12.1. 웹 MVC framework 소개
-
- 12.1.1. 다른 MVC구현물의 플러그인 가능성
- 12.1.2. Spring MVC의 특징
- 12.1.1. 다른 MVC구현물의 플러그인 가능성
- 12.2. DispatcherServlet
- 12.3. 컨트롤러
-
- 12.3.1. AbstractController 와 WebContentGenerator
- 12.3.2. 간단한 다른 컨트롤러
- 12.3.3. MultiActionController
- 12.3.4. CommandControllers
- 12.3.2. 간단한 다른 컨트롤러
- 12.3.1. AbstractController 와 WebContentGenerator
- 12.4. Handler mappings
-
- 12.4.1. BeanNameUrlHandlerMapping
- 12.4.2. SimpleUrlHandlerMapping
- 12.4.3. HandlerInterceptors 추가하기
- 12.4.2. SimpleUrlHandlerMapping
- 12.4.1. BeanNameUrlHandlerMapping
- 12.5. view와 view결정하기
-
- 12.5.1. ViewResolvers
- 12.5.2. ViewResolvers 묶기(Chaining)
- 12.5.1. ViewResolvers
- 12.6. 로케일 사용하기.
-
- 12.6.1. AcceptHeaderLocaleResolver
- 12.6.2. CookieLocaleResolver
- 12.6.3. SessionLocaleResolver
- 12.6.4. LocaleChangeInterceptor
- 12.6.2. CookieLocaleResolver
- 12.6.1. AcceptHeaderLocaleResolver
- 12.7. 테마(themes) 사용하기
- 12.8. Spring의 multipart (파일업로드) 지원
-
- 12.8.1. 소개
- 12.8.2. MultipartResolver 사용하기
- 12.8.3. 폼에서 파일업로드를 다루기.
- 12.8.2. MultipartResolver 사용하기
- 12.8.1. 소개
- 12.9. 예외 다루기
- 13. 통합 뷰 기술들
-
- 13.1. 소개
- 13.2. JSP & JSTL
-
- 13.2.1. 뷰 해결자(View resolvers)
- 13.2.2. 'Plain-old' JSPs 대(versus) JSTL
- 13.2.3. 추가적인 태그들을 쉽게 쓸수 있는 개발
- 13.2.2. 'Plain-old' JSPs 대(versus) JSTL
- 13.2.1. 뷰 해결자(View resolvers)
- 13.3. Tiles
-
- 13.3.1. 의존물들(Dependencies)
- 13.3.2. Tiles를 통합하는 방법
-
- 13.3.2.1. InternalResourceViewResolver
- 13.3.2.2. ResourceBundleViewResolver
- 13.3.2.1. InternalResourceViewResolver
- 13.3.1. 의존물들(Dependencies)
- 13.4. Velocity & FreeMarker
-
- 13.4.1. 의존물들(Dependencies)
- 13.4.2. 컨텍스트 구성(Context configuration)
- 13.4.3. 생성 템플릿들(Creating templates)
- 13.4.4. 진보한 구성(Advanced configuration)
- 13.4.2. 컨텍스트 구성(Context configuration)
-
- 13.4.4.1. velocity.properties
- 13.4.4.2. FreeMarker
- 13.4.4.1. velocity.properties
- 13.4.5. 바인드(Bind) 지원과 폼(form) 핸들링
-
- 13.4.5.1. 바인드(bind) 매크로
- 13.4.5.2. 간단한 바인딩
- 13.4.5.3. 폼 input 생성 매크로
- 13.4.5.4. HTML회피를 오버라이드하고 XHTML호환 태그를 만든다.
- 13.4.5.2. 간단한 바인딩
- 13.4.5.1. 바인드(bind) 매크로
- 13.4.1. 의존물들(Dependencies)
- 13.5. XSLT
-
- 13.5.1. 나의 첫번째 단어
-
- 13.5.1.1. Bean 정의
- 13.5.1.2. 표준적인 MVC 컨트롤러 코드
- 13.5.1.3. 모델 데이터를 XML로 변환하기
- 13.5.1.4. view프라퍼티 정의하기
- 13.5.1.5. 문서 변형
- 13.5.1.2. 표준적인 MVC 컨트롤러 코드
- 13.5.1.1. Bean 정의
- 13.5.2. 요약
- 13.6. 문서 views (PDF/Excel)
-
- 13.6.1. 소개
- 13.6.2. 설정 그리고 셋업
-
- 13.6.2.1. 문서 view정의
- 13.6.2.2. 컨트롤러 코드
- 13.6.2.3. Excel view를 위한 하위클래스 만들기
- 13.6.2.4. PDF view를 위한 하위클래스 만들기
- 13.6.2.2. 컨트롤러 코드
- 13.6.2.1. 문서 view정의
- 13.6.1. 소개
- 13.7. JasperReports
-
- 13.7.1. 의존성
- 13.7.2. 설정
-
- 13.7.2.1. ViewResolver 설정하기
- 13.7.2.2. View 설정하기
- 13.7.2.3. 리포트 파일에 대해
- 13.7.2.4. JasperReportsMultiFormatView 사용하기
- 13.7.2.2. View 설정하기
- 13.7.2.1. ViewResolver 설정하기
- 13.7.3. ModelAndView 활성화하기
- 13.7.4. 하위-리포트로 작동하기
-
- 13.7.4.1. 하위-리포트 파일 설정하기
- 13.7.4.2. 하위-리포트 데이터소스 설정하기
- 13.7.4.1. 하위-리포트 파일 설정하기
- 13.7.5. 전파자(Exporter) 파라미터 설정하기
- 13.7.1. 의존성
- 13.1. 소개
- 14. 다른 웹 프레임워크들과의 통합
-
- 14.1. 소개
- 14.2. JavaServer Faces
-
- 14.2.1. DelegatingVariableResolver
- 14.2.2. FacesContextUtils
- 14.2.1. DelegatingVariableResolver
- 14.3. Struts
-
- 14.3.1. ContextLoaderPlugin
-
- 14.3.1.1. DelegatingRequestProcessor
- 14.3.1.2. DelegatingActionProxy
- 14.3.1.1. DelegatingRequestProcessor
- 14.3.2. ActionSupport 클래스들
- 14.4. Tapestry
-
- 14.4.1. 아키텍쳐
- 14.4.2. 구현체
-
- 14.4.2.1. 샘플 어플리케이션 컨텍스트
- 14.4.2.2. Tapestry pages에서 빈들을 얻어오기
- 14.4.2.3. 어플리케이션 컨텍스트를 Tapestry에 드러내기
- 14.4.2.4. Component 정의 파일들
- 14.4.2.5. abstract accessors 추가하기
- 14.4.2.2. Tapestry pages에서 빈들을 얻어오기
- 14.4.2.1. 샘플 어플리케이션 컨텍스트
- 14.4.3. 개요
- 14.4.1. 아키텍쳐
- 14.5. WebWork
- 14.1. 소개
- 15. JMS
-
- 15.1. 소개
- 15.2. 도메인 단일화(unification)
- 15.3. JmsTemplate
- 15.2. 도메인 단일화(unification)
-
- 15.3.1. ConnectionFactory
- 15.3.2. 트랜잭션 관리
- 15.3.3. 목적지(destination) 관리
- 15.3.2. 트랜잭션 관리
- 15.3.1. ConnectionFactory
- 15.4. JmsTemplate 사용하기
-
- 15.4.1. 메시지 보내기
- 15.4.2. 동기적으로 받기(Receiving)
- 15.4.3. 메시지 변환기(converter) 사용하기
- 15.4.4. SessionCallback 과 ProducerCallback
- 15.4.2. 동기적으로 받기(Receiving)
- 15.4.1. 메시지 보내기
- 15.1. 소개
- 16. EJB에 접근하고 구현하기
-
- 16.1. EJB에 접근하기
-
- 16.1.1. 개념
- 16.1.2. local SLSBs에 접근하기
- 16.1.3. remote SLSB에 접근하기
- 16.1.2. local SLSBs에 접근하기
- 16.1.1. 개념
- 16.2. Spring의 편리한 EJB구현물 클래스를 사용하기.
- 17. Spring을 사용한 원격(Remoting)및 웹서비스
-
- 17.1. 소개
- 17.2. RMI를 사용한 서비스 드러내기
-
- 17.2.1. RmiServiceExporter를 사용하여 서비스 내보내기
- 17.2.2. 클라이언트에서 서비스 링크하기
- 17.2.1. RmiServiceExporter를 사용하여 서비스 내보내기
- 17.3. HTTP를 통해 서비스를 원격으로 호출하기 위한 Hessian 이나 Burlap을 사용하기.
-
- 17.3.1. Hessian을 위해 DispatcherServlet을 묶기.
- 17.3.2. HessianServiceExporter를 사용하여 bean을 드러내기
- 17.3.3. 클라이언트의 서비스로 링크하기
- 17.3.4. Burlap 사용하기
- 17.3.5. Hessian 이나 Burlap을 통해 드러나는 서비스를 위한 HTTP 기본 인증 적용하기
- 17.3.2. HessianServiceExporter를 사용하여 bean을 드러내기
- 17.3.1. Hessian을 위해 DispatcherServlet을 묶기.
- 17.4. HTTP호출자를 사용하여 서비스를 드러내기
-
- 17.4.1. 서비스 객체를 드러내기
- 17.4.2. 클라이언트에서 서비스 링크하기
- 17.4.1. 서비스 객체를 드러내기
- 17.5. 웹 서비스
-
- 17.5.1. JAX-RPC를 사용하여 서비스를 드러내기
- 17.5.2. 웹 서비스에 접근하기
- 17.5.3. Register Bean 맵핑
- 17.5.4. 자체적인 핸들러 등록하기
- 17.5.5. XFire를 사용하여 웹 서비스를 드러내기
- 17.5.2. 웹 서비스에 접근하기
- 17.5.1. JAX-RPC를 사용하여 서비스를 드러내기
- 17.6. 자동-탐지(Auto-detection)는 원격 인터페이스를 위해 구현되지 않는다.
- 17.7. 기술을 선택할때 고려사항.
- 17.1. 소개
- 18. Spring 메일 추상 계층을 사용한 이메일 보내기
-
- 18.1. 소개
- 18.2. Spring 메일 추상화 구조
- 18.3. Spring 메일 추상화 사용하기
- 18.2. Spring 메일 추상화 구조
-
- 18.3.1. 플러그인할 수 있는 MailSender 구현클래스들
- 18.4. JavaMail MimeMessageHelper 사용하기
-
- 18.4.1. 간단한 MimeMessage 를 생성하고 보내기
- 18.4.2. 첨부파일들과 inline 리소스들을 보내기
- 18.4.1. 간단한 MimeMessage 를 생성하고 보내기
- 18.1. 소개
- 19. Quartz 혹은 Timer 를 사용한 스케쥴링
-
- 19.1. 소개
- 19.2. OpenSymphony Quartz 스케쥴러 사용하기
-
- 19.2.1. JobDetailBean 사용하기
- 19.2.2. MethodInvokingJobDetailFactoryBean 사용하기
- 19.2.3. triggers 와 SchedulerFactoryBean을 사용하여 jobs를 묶기
- 19.2.2. MethodInvokingJobDetailFactoryBean 사용하기
- 19.2.1. JobDetailBean 사용하기
- 19.3. JDK Timer support 사용하기
-
- 19.3.1. 임의의 timers 생성하기
- 19.3.2. MethodInvokingTimerTaskFactoryBean 사용하기
- 19.3.3. 감싸기 : TimerFactoryBean을 사용하여 tasks를 세팅하기
- 19.3.2. MethodInvokingTimerTaskFactoryBean 사용하기
- 19.3.1. 임의의 timers 생성하기
- 19.1. 소개
- 20. JMX 지원
-
- 20.1. 소개
- 20.2. 당신의 bean을 JMX로 내보내기(Exporting)
-
- 20.2.1. MBeanServer 생성하기
- 20.2.2. 늦게 초기화되는(Lazy-Initialized) MBeans
- 20.2.3. MBean의 자동 등록
- 20.2.2. 늦게 초기화되는(Lazy-Initialized) MBeans
- 20.2.1. MBeanServer 생성하기
- 20.3. 당신 bean의 관리 인터페이스를 제어하기
-
- 20.3.1. MBeanInfoAssembler 인터페이스
- 20.3.2. 소스레벨 메타데이타(metadata) 사용하기
- 20.3.3. JDK 5.0 Annotations 사용하기
- 20.3.4. 소스레벨 메타데이타 타입들
- 20.3.5. AutodetectCapableMBeanInfoAssembler 인터페이스
- 20.3.6. 자바 인터페이스를 사용하여 관리 인터페이스 정의하기
- 20.3.7. MethodNameBasedMBeanInfoAssembler 사용하기
- 20.3.2. 소스레벨 메타데이타(metadata) 사용하기
- 20.3.1. MBeanInfoAssembler 인터페이스
- 20.4. 당신의 bean을 위한 ObjectName 제어하기
-
- 20.4.1. Properties로 부터 ObjectName 읽기
- 20.4.2. MetadataNamingStrategy 사용하기
- 20.4.1. Properties로 부터 ObjectName 읽기
- 20.5. JSR-160 연결자(Connectors)로 당신의 bean을 내보내기
-
- 20.5.1. 서버측 연결자(Connectors)
- 20.5.2. 클라이언트측 연결자
- 20.5.3. Burlap/Hessian/SOAP 곳곳의 JMX
- 20.5.2. 클라이언트측 연결자
- 20.5.1. 서버측 연결자(Connectors)
- 20.6. 프록시를 통해서 MBean에 접속하기
- 20.1. 소개
- 21. Testing
-
- 21.1. 단위 테스팅
- 21.2. 통합 테스팅
-
- 21.2.1. 컨텍스트 관리와 캐슁
- 21.2.2. 테스트 클래스 인스턴스들의 의존성 주입
- 21.2.3. 트랜잭션 관리
- 21.2.4. 편리한 변수들
- 21.2.5. 예시
- 21.2.6. 통합 테스트 실행하기
- 21.2.2. 테스트 클래스 인스턴스들의 의존성 주입
- 21.2.1. 컨텍스트 관리와 캐슁
- 21.1. 단위 테스팅
- A. spring-beans.dtd
function addMethod(object, name, fn){
var old = object[name];
object[name] = function(){
if (fn.length == arguments.length)
return fn.apply(this, arguments);
else
if (typeof old == 'function')
return old.apply(this, arguments);
};
}
// Now setup the methods
function Users(){
addMethod(this, "find", function(){
// Find all users...
});
addMethod(this, "find", function(name){
// Find a user by name
});
addMethod(this, "find", function(first, last){
// Find a user by first and last name
});
}
// Now use the methods
var users = new Users();
users.find(); // Finds all
users.find("John"); // Finds users by name
users.find("John", "Resig"); // Finds users by first and last name
users.find("John", "E", "Resig"); // Does nothing
출처 : http://openframework.or.kr/Wiki.jsp?page=JavaScriptMethodOverloading
중급 자바 개발자의 난관, 클래스 로딩 문제 분석하기 |
![]() |


|
초급을 넘어 중급 단계로 들어서는 자바 개발자에게 몇 가지 난관 중 하나가 클래스 로딩 문제입니다.
적당한 jar 파일을 찾아 적당한 디렉터리에 넣어주면 해결되는 단순한 문제부터, 커스텀 클래스 로더가 필요한 경우까지 다양한 원인과 해결책이 있겠지만, 원리를 이해하지 않고 검색 엔진의 힘에 의지해 문제를 해결하다 보면 더 큰 문제를 만들게 됩니다.
이 연재에서는 클래스 로딩의 작동 원리에서 시작해, 개발하는 과정에서 발생할 수 있는 다양한 클래스 로딩 관련 문제에 대한 원인과 해결책을 4회에 걸쳐 설명하고 있습니다.
또한 직접 확인해 볼 수 있는 풍부한 예제와 실습을 통해, 이 연재에서 설명하지 않은 다른 형태의 클래스 로딩 문제를 만나더라도 신속하게 원인을 규명하고 해결책을 찾을 수 있는 응용 능력을 습득할 수 있을 것입니다.
- 1회: 클래스 로딩과 디버깅 툴 소개(한글)
- 2회: 기본적인 클래스 로딩 예외(Exception)(한글)
- 3회: 특이한 클래스 로딩 문제 해결(한글)
- 4회: 교착 상태와 제약 조건(한글)
첫 번째 연재에서는 클래스 로더 위임 모델과 각각의 클래스 로더를 제어하기 위한 JVM의 명령어 옵션을 알아봅니다. 그리고 클래스 로딩 과정을 단계별로 설명합니다. 마지막으로 IBM의 JDK에 내장된 도구들을 사용해 이러한 과정들을 직접 확인하는 방법을 설명합니다.
흔히 볼 수 있는 ClassNotFoundException, NoClassDefFoundError 같은 예외부터 ClassCircularityError, ExceptionInInitializerError 같은 평생 한 번 보기도 힘든 예외까지 클래스 로딩과 관련된 거의 모든 예외와 에러(error) 들에 대해 자세히 알아봅니다.
클래스패스 끝에 붙은 '/' 문자 때문에 발생하는 사소한 문제부터, 클래스 로더 위임 모델과 클래스 가시성 때문에 발생하는 문제, 커스텀 클래스 로더를 만들 때 부주의로 발생하는 문제, 그리고 클래스로 로더가 가비지 컬렉션되면서 발생하는 문제까지, 클래스 로딩시 일어날 수 있는 더 복잡한 문제들에 대해 자세히 설명합니다.
마지막으로 클래스 로더 교착 상태, 클래스 로더 제약 조건 위반 같은 쉽게 발생하지 않지만 일단 발생하면 해결하기 어려운 문제들에 대해 자세히 설명합니다.
출처 : http://www.javajigi.net/display/OSS/Spring+MVC
Table of Contents
Spring Introduction
Spring에 대한 전반적인 내용은 아래를 참조하기 바란다.
http://wiki.javajigi.net/pages/viewpage.action?pageId=280
http://martinfowler.com/articles/injection.html
Spring MVC
![]() |
Spring's web MVC framework is designed around a DispatcherServlet that dispatches requests to handlers, with configurable handler mappings, view resolution, locale and theme resolution as well as support for upload files. A flexible MVC web application framework, built on core Spring functionality. |
Spring의 웹 MVC framework는 설정가능한 핸들러 맵핑들, view분석, 로케일과 파일 업로드를 위한 지원같은 테마분석과 함께 핸들러에 요청을 할당하는 DispatcherServlet을 기반으로 디자인되었다.
디폴트 핸들러는 ModelAndView handleRequest(request,response)메소드를 제공하는 매우 간단한 컨트롤러 인터페이스이다.
이것은 이미 애플리케이션 컨트롤러를 위해 사용될수 있지만 AbstractController, AbstractCommandController그리고 SimpleFormController같은 것들을 포함한 구현 구조를 포함한것을 더 선호할것이다.
애플리케이션 컨트롤러들은 전형적으로 이것들의 하위 클래스가 된다. 당신이 선호하는 빈 클래스를 선택하도록 하라.
만약에 당신이 form을 가지지 않는다면 당신은 FormController가 필요없다. 이것이 Struts와 가장 큰 차이점이다.
유연한 MVC 웹 어플리케이션 프레임웍은 Core Spring과 상호작용하여 만들어진다.
이 프레임웍은 전략적인 인터페이스를 거쳐 높은수준으로 만들어진다. 그리고, JSP, Velocity, Tiles, iText, POI처럼 다양한 view 기술을 수용한다.
Spring middle tier는 Struts, WebWork, Tapestry와 같은 다른 웹 MVC 프레임워크를 기반으로 한 웹티어와 결합할수 있다.
Spring프레임웍에서 Model-View-Controller를 지원하는 기능이다.
강좌가 올라와있네요...
Spring MVC에서 클라이언트 요청의 처리 과정을 먼저 살펴보시면 이해가 되실거 같습니다.
http://wiki.javajigi.net/pages/viewpage.action?pageId=1133
참 고 : http://www.springframework.org/docs/reference/
번역본 : http://openframework.or.kr/framework_reference/spring/ver1.2.2/html/
설정 방법
Spring MVC를 사용하기 위해서는
- web-app/WEB-INF/lib 아래로 spring.jar 또는 spring-webmvc.jar파일을 복사한다.
- web-app/WEB-INF/web.xml에 DispatcherServlet를 설정한다.
- <web.xml>
<servlet> <servlet-name>action</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping>
.do, .html 로 끝나는 모든 요청은 DispatcherServlet에서 담당한다.
- DispattcherServlet이 초기화 할 때 디폴트로 사용하는 빈 설정파일의 이름은 "서블릿 이름-servlet.xml"이 된다.
- web-app/WEB-INF/web.xml에서 설정한 <servlet-name>인 action-servlet.xml 파일을 생성한다.
즉 spring.jar 와 web.xml에 DispatcherServlet 을 사용한다는 선언 그리고 서블릿 이름-servlet.xml 을 작성하면 사용할 수 있다.
다양한 예제들
Spring MVC를 사용한 초간단 예제
링크된 강좌를 살펴보고 대략적인 것을 파악한다면 Spring MVC 사용하기 위해서 개발자들이 만들어야 하는 것은 Controller 라는 것을 알게 될 것이다. 물론 화면에 보여주는 jsp(여기선 jsp 를 연결) 파일, 빈 설정 파일을 만드는 것은 당연한 것이다.
Controller를 생성하고 빈 설정파일에 맵핑 하는 방법 등의 관계를 보여주기 위한 데이터를 가져와서 List 형태로 보여주는 예제이다
- Controller
package com.tmax.spring.web; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import com.tmax.spring.service.iface.BbsServiceIface; public class BbsController implements Controller { private BbsServiceIface bbsService; public void setBbsService(BbsServiceIface newBbsService){ this.bbsService = newBbsService; } public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception { List list = bbsService.findBbsList(); return new ModelAndView("bbs/list","bbsList", list); } }
위에서 보면 직접적으로 Controller 인터페이스를 구현해서 ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; 를 구현한다. Spring MVC에서 제공하는 다양한 Controller 들은 모두 Controller 인터페이스를 구현하기 때문에 가장 기본적인 구조라고 생각할 수 있다.
Service 객체는 setter Injection을 통해 생성된 것이다. 이것은 이미 앞에서 다 이해했을 것이다.
handleRequest(... ) 안에서 실제 메소드를 호출한 뒤 ModelAndView 객체를 통해 리턴을 하였다.
링크된 Spring MVC의 요청에 대한 생명주기를 보게 되면 비지니스 계층에서 전달된 모델 데이타와 클라이언트에게 보여줄 뷰화면에 대한 정보를 ModelAndView 클래스에 담아서 반환을 하게 되어 있다. 즉 전달 데이타 모델, 화면이름, 화면에서 사용될 객체 이름 등을 담아서 ModelAndView객체를 생성, 리턴한다.
ModelAndView 객체의 View정보가 논리적인 view이름(String) 인 경우 빈 설정 파일에 정의되어 있는 ViewResolver클래스를 이용하여 클라이언트에세 출력할 화면이름을 만들어 낼 수 있다. ModelAndView의 첫번째 인자인 "bbs/list"가 view 이름이기 때문에 설정파일의 ViewResolver를 만나서 리턴되는 화면의 전체이름이 완성되는 것이다.
- action-servlet.xml
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <bean name="/bbs/listBbs.do" class="com.tmax.spring.web.BbsController"> <property name="bbsService"> <ref bean="bbsService" /> </property> </bean> <!-- View Resolver for JSPs --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/jsp/"/> <property name="suffix" value=".jsp"/> </bean>
설정파일을 보면 ViewResolver로 InternalResourceViewResolver클래스를 사용한다.
그리고 JSTLView를 사용해서 jsp 로 화면을 출력할 것이라는 것을 알 수 있다. 위에 설정된 것과 ModelAndView객체에 넘긴 view이름을 조합해 보면 /jsp/bbs/list.jsp 가 되는 것이다. (prefix+view 이름+suffix )
설정파일을 보면 BeanNameUrlHandlerMapping 클래스를 사용해서 Controller와 URL을 맵핑해주는 것을 알 수 있다.
만일 빈 설정파일에 HandlerMapping이 설정되어 있지 않으면 default 로 BeanNameURLHandlerMapping을 설정한다.
맵핑 방법에는 BeanNameURLHandlerMapping, SimpleUrlHandlerMapping,CommonsPathMapHandlerMapping 등이 있다.
- BeanNameURLHandlerMapping
빈 이름과 URL을 mapping 하는 방법이다.<bean name="/bbs/listBbs.do" class="com.tmax.spring.web.BbsController"> <property name="bbsService"> <ref bean="bbsService" /> </property> </bean>
즉 요청이 ..../bbs/listBbs.do가 오면 BbsController 클래스를 호출하겠다는 의미이다. name에는 <bean name="/bbs/listBbs.do /bbs/listBbs2.do".. /> 로 여러 개를 기술할 수 있다.
- SimpleUrlHandlerMapping
매핑에 대한 정보를 각각의 Controller에서 설정하는 것이 아니라 하나의 저장소에서 관리하는 것이다.
Controller를 개발하는 개발자들은 빈을 정의하기만 하고 이 Controller가 어떻게 맵핑되어서 사용하는지에 대해서는 몰라도 된다.
위의 설정파일을 SimpleUrlHandlerMapping으로 바꾸어 보면<bean id="bbsController" class="com.tmax.spring.web.BbsController"> <property name="bbsService"> <ref bean="bbsService" /> </property> </bean> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key ="/bbs/listBbs.do">bbsController</prop> </props> </property> </bean>
실제 Controller에 대한 정의는 일반 빈을 정의 할 때와 다르지 않게 된다. 맵핑에 대한 정보는 별도의 빈(urlMapping)에서 관리되고 있다. 만일 더욱 많은 Controller가 생성되고 맵핑을 해 줘야 할 때 모든 매핑 정보는 한곳에서 관리를 할 수 있게 되는 것이다. Controller 마다 맵핑정보까지 나열할 필요가 없게 된다.
urlMapping 빈에서 Controller와 URL을 맵핑할 때 <props/>를 사용해서 기술할 수 있다. 또 다른 방법은 <props/>를 사용하지 않고 별도의 Properties 파일에서 관리 할 수도 있다.
- CommonsPathMapHandlerMapping
Spring MVC를 사용하여 다중요청 처리하기
개발자들이 Controller 만 만들면 되지만 개발하면서 페이지, 기능이 추가 될 때마다 새로운 Contoller를 만드는 것은 굉장히 짜증이 나는 작업이다. 게다가 점점 관리해야 하는 파일의 수가 많아져서 빈 설정파일도 점점 복잡해질 것이다.이 같은 상황을 해결하기 위하여 Spring MVC는 MultiActionController를 제공한다. MultiActionController은 하나의 Controller를 구현함으로써 다수의 요청을 처리하는 것이 가능하다.
아래 예는 회원가입,수정을 통해 MultiActionController 구현을 보여준다.
Controller 객체인 MemberController.java
package net.javajigi.member.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.javajigi.member.model.Member; import net.javajigi.member.service.MemberService; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.multiaction.MultiActionController; public class MemberController extends MultiActionController{ private MemberService memberService = null; public void setMemberService(MemberService memberService){ this.memberService = memberService; } public ModelAndView add(HttpServletRequest request, HttpServletResponse reponse) throws Exception{ Member command = new Member(); bind(request,command); memberService.addMember(command); return new ModelAndView("main"); } public ModelAndView update(HttpServletRequest request, HttpServletResponse reponse) throws Exception{ Member command = new Member(); bind(request,command); memberService.updateMember(command); return new ModelAndView("list"); } }
위의 예제는 add(가입), update(수정)을 구현하기 위해 MultiActionController를 상속받은 Controller 이다.
각각의 메소드에 로직이나 서비스 호출 부분들의 소스를 구현하다.
add 메소드를 보면 화면에서 입력받은 내용을 bind()를 사용해 domain 객체에 넘기고 있다.(이 내용은 나중에..)
그 뒤 서비스의 addMember()를 호출한다.
처리 후 리턴될 페이지를 설정한다.(add->main.jsp, update->list.jsp)
Controller를 작성 후 webapps/WEB-INF/action-servlet.xml 파일에 빈을 매핑한다.
action-servlet.xml
<bean id="memberService" class="net.javajigi.member.service.MemberService"/> <bean name="/member/addMember.do /member/updateMember.do" class="net.javajigi.member.web.MemberController"> <property name="methodNameResolver"> <ref local="memberControllerMethodNameResolver"/> </property> <property name="memberService"> <ref local="memberService"/> </property> </bean> <bean id="memberControllerMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver"> <property name="mappings"> <props> <prop key="/member/addMember.do">add</prop> <prop key="/member/updateMember.do">update</prop> </props> </property> </bean>
MemberController는 두 개의 URL(/member/addMember.do,/member/updateMember.do)에 맵핑이 되었다.각각의 URL이 호출될 때 MemberController 안의 어떤 메소드가 호출될 지는 "memberControllerMethodNameResolver"빈에서 PropertiesMethodNameResolver를 통해 매핑이 된다. 결국 /member/addMember.do 가 호출되면 MemberController의 add 메소드가 /member/updateMember.do가 호출되면 update 메소드가 호출된다.
결국 위의 예는 빈 설정파일에서 URL을 다르게 함으로써 메소드에 접근할 수 있도록 설정한 것이다. (PropertiesMethodNameResolver 클래스를 통해서)
<bean name="/member/member.do" class="net.javajigi.member.web.MemberController"> <property name="methodNameResolver"> <ref local="methodNameResolver"/> </property> </bean> <bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName"> <value>method</value> </property> <property name="defaultMethodName"> <value>add</value> </property> </bean>
위의 예를 보면 MemberController는 하나의 URL에 맵핑이 되었다. 그럼 어떻게 MemberController의 다른 메소드를 호출할 수 있을까? 그것은 "methodNameResolver" 빈의 "ParameterMethodNameResolver" 를 이용해서 호출이 가능하다.
URL을 통해 전달되는 인자중에 "paramName"인 method라는 이름을 가지는 인자의 값에 해당하는 메소드를 호출해 주는 것이다.
즉 /member/member.do?method=add 를 하게 되면 MemberController의 add()를 호출하는 것이다. /member/member.do?method=update를 하면 update()를 호출하게 될 것이다. 만일 아무 값도 없다면 default 으로 add()를 호출하게 된다. 호출하는 URL은 같지만 뒤 인자의 인자값을 변경해 줌으로써 다른 메소드를 호출할 수 있다.
ParameterMethodNameResolver를 이용하면 MultiActionController를 상속받은 Controller 에 메소드가 추가되더라도 설정파일에 추가적인 설정이 필요 없을 것이다. 하지만 호출할 때 추가된 메소드 이름을 알아야 한다.
데이터 바인딩(Data Binding)
웹 애플리케이션 개발에서 입력, 수정과 관련된 기능을 구현하기 위해서 입력하는 값에 대한 유효성 체크와 입력 값을 도메인 모델로 바인딩 하는 기능이 필요하다.그 동안 개발자들은 유효성 체크를 위해서 화면단에는 많은 자바스크립트를 데이타 바인딩을 위해서는 HttpServletRequest에 담긴 인자를 꺼내서 다시 도메인 모델로 set하는 코드들이 난무했을 것이다.
Spring MVC 에서는 입력화면(또는 수정화면)에서 전달되는 입력 데이터를 비즈니스 계층에 전달하기 위하여 HttpServletRequest에 담긴 인자와 도메인 모델의 속성을 자동적으로 연결하는 데이터 바이팅을 지원하고 있다.
위에 나온 bind()가 그 역할을 하는 것이다.
bind(request,command);
Bind request parameters onto the given command bean
@param request request from which parameters will be bound
@param command command object, that must be a JavaBean
@throws Exception in case of invalid state or arguments
대신 클라이언트가 입력한 데이터를 도메인 모델과 데이터 바인딩 하기 위해서는 입력 화면에서 사용한 속성이름과 도메인 모델의 속성이름이 같아야 한다.
- 회원가입 입력폼인 memberEntry.jsp
<%-- 작성자 : 난다 일자 : 2006.02.13 설명: 회원가입 --%> <%@page contentType="text/html; charset=euc-kr"%> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>사용자 관리 - 회원 가입</title> <link rel="stylesheet" type="text/css" href="../css/style.css" media="screen"> </head> <body> <div id="member"> <form name="thisform" method="post" action="${pageContext.request.contextPath}/member/addMember.do"> <table summary="회원가입"> <caption>회원 정보 </caption> <tr> <th id="id">* 아이디</th> <td headers="id"> <input type="text" id="id" name="id" /> </td> </tr> <tr> <th id="password">* 비밀번호</th> <td headers="password"> <input type="text" id="password" name="password" /> </td> </tr> <tr> <th id="passwordRepeat">* 비밀번호</th> <td headers="passwordRepeat"> <input type="text" id="passwordRepeat" name="passwordRepeat" /> </td> </tr> <tr> <th id="password_hint">* 비밀번호 힌트 </th> <td headers="passwordHint"> <input type="text" id="passwordHint" name="passwordHint" /> </td> </tr> <tr> <th id="passwordAnswer">* 비밀번호 답 </th> <td headers="passwordAnswer"> <input type="text" id="passwordAnswer" name="passwordAnswer" /> </td> </tr> <tr> <th id="email">* e-mail</th> <td headers="email"> <input type="text" id="email" name="email" /> </td> </tr> </table> <center> <input type="submit" value="확인" tabindex="4" /> </center> </form> </div> </body> </html>
- 도메인 모델 Member.java
package net.javajigi.member.model; import org.apache.commons.lang.builder.ToStringBuilder; public class Member { private String userId = null; private String password = null; private String passwordRepeat = null; private String passwordHint = null; private String passwordAnswer = null; private String email = null; 변수들에 대한 getter,setter 메소드... . . . public String toString() { return ToStringBuilder.reflectionToString(this); } }
memberEntry.jsp의 입력필드의 이름은 id,password,passwordRepeat,passwordHint,passwordAnswer,email로 정의 되어 있다.
그리고 바인딩되는 도메인 모델 Member도 id,password,passwordRepeat,passwordHint,passwordAnswer,email 가 정의되어 있다.
즉 같은 속성이름에 대해서는 가져올 수 있지만 만일 다르다면 가져오지 못하게 된다.
위의 예제에서 사용한 MultiActionController는 입력데이터에 대한 유효성 체크 기능을 지원하지 않는다. 만일 유효성 체크도 원한다면 MultiActionContorller를 상속받아서는 사용할 수 없다.
유효성 체크와 바인딩 기능까지 모든 기능을 사용하길 원한다면 AbstractCommandControllder 클래스를 상속받아야 한다.
AbstractCommandControllder를 상속받은 Controller
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.validation.BindException; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractCommandController; import com.tmax.spring.domain.Member; import com.tmax.spring.service.app.MemberService; public class MemberAbstractCommandController extends AbstractCommandController{ private static transient Log log = LogFactory.getLog(MemberAbstractCommandController.class); private MemberService memberService = null; public void setMemberService(MemberService memberService){ this.memberService = memberService; } public MemberAbstractCommandController(){ setCommandClass(Member.class); } protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { Member member = (Member)command; //memberService.addBbs(command); log.error("가져오는지..."+member.toString()); return new ModelAndView("../index"); } }
AbstractCommandController를 상속받아 구현 하려면 바인딩하는 클래스를 디폴트 생성자 안에 setCommandClass()를 통해서 설정해야 한다. 위의 예를 보면
public MemberAbstractCommandController()
Unknown macro: { setCommandClass(Member.class); }
그러면 들어오는 입력 값들과 설정한 클래스와의 바인딩이 이전에 보았던 bind() 라는 메소드 없이 Casting 만으로 이루어 진다.
하지만 AbstractCommandController는 요청에 대해 각각의 Controller를 만들어야 한다.결국 데이터 바인딩 및 데이터에 대한 유효성 체크 기능을 지원하고 있지만 AbstractCommandController를 상속받은 Controller로는 다수의 요청을 처리 할 수 없는 것이다.즉 Controller 를 이용하면 요청에 따라 추가되고 빈 설정 정보또한 수정해 주어야 한다.
결국 큰 주제로 했던 다수의 요청을 한 Controller에서 처리하는 방법은 아니지만 좀 더 손쉽게 유효성체크와 데이터 바인딩을 할 수 있다는 점에서는 유용하다. 간단한 CRUD 같은 작업은 MultiController를 구현해 한 Controller에서 사용할 수도 있고( 물론 유효성체크는 스크립트나 다른 방법을 통해) 복잡하고 많은 입력 필드를 가지고 있는 화면이라면 AbstractCommandController를 사용해 좀 더 손쉽게 처리 할 수 있을 것이다.
이것은 각각의 프로젝트, 요구사항등에 맞추어 결정하면 될 것이다.
action-servlet.xml 추가사항
<bean name="/member/addMemberWithAbstract.do" class="com.tmax.spring.web.MemberAbstractCommandController"> <property name="memberService"> <ref bean="memberService" /> </property> </bean>
- 실제로직을 담당하는 비지니스 객체인 MemberService.java 파일을 생성한다.
package net.javajigi.member.service; import net.javajigi.member.model.Member; public class MemberService { public void addMember(Member member){ //로직처리 } public void updateMember(Member member){ //로직처리 } }
하나의 Controller만으로 입력,수정처리하기
<ation-servlet.xml>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/login.do">loginFormController</prop> </props> </property> </bean> <bean id="loginFormController" class="spring.LoginFormController"> <property name="formView"><value>/login</value></property> <property name="successView"><value>/main</value></property> </bean> <bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass"> <value>org.springframework.web.servlet.view.JstlView</value> </property> <property name="cache"> <value>false</value> </property> <property name="prefix"> <value>/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> </beans>
Controller를 URL과 매핑해주어야 한다.
login.do에 대한 요청을 loginFormController가 담당하며, 이 Controller는 로그인을 위한 로직처리를 포함하고, 사용자가 직접 작성해야한다.
입력화면은 /login 이며, 로직을 무사히 처리한후에는 /main으로 이동한다.
JSTL pages , jsp Page를 사용하기위해 JstlView를 선언하였다.
- web-app/login.jsp 로그인 페이지를 생성한다.
<login.jsp>
<%@page contentType="text/html; charset=euc-kr"%> <%@ page language="java" import="java.util.*" %> <html> <head> <title>My JSP 'login.jsp' starting page</title> </head> <body> <form name="myForm" method="post" action="/spring/login.do"> <table> <tr> <td> ID : <input type="text" name="userId" value="1"> </td> </tr> <tr> <td> PASSWORD : <input type="password" name="password" value="2"> </td> </tr> <tr> <td> <input type="submit" name="login" value="로그인"/> </td> </tr> </table> </form> </body> </html>
- web-app/main.jsp 로그인성공후 이동할 메인 페이지를 생성한다.
<main.jsp>
<%@page contentType="text/html; charset=euc-kr"%> <%@ page language="java" import="java.util.*" %> <html> <head> <title>My JSP 'main.jsp' starting page</title> </head> <body> Login Success~!! </body> </html>
- web-app/WEB-INF/net.javajigi.user.web.LoginFormController.java 파일을 생성한다.
package net.javajigi.user.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import net.javajigi.user.model.Authenticate; import org.springframework.validation.BindException; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.SimpleFormController; public class LoginFormController extends SimpleFormController { public LoginFormController() { // bean 객체 setCommandName("authenticate"); setCommandClass(Authenticate.class); } public ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { if (request.getParameter("login") != null) { Authenticate auth = (Authenticate) command; try { //로직처리 //boolean bResult = UserLoginProc.login(auth); //View 객체 리턴 return new ModelAndView(getSuccessView()); } catch (Exception e) { request.setAttribute("errorMessage", e.getMessage()); return new ModelAndView(getFormView()); } } else { HttpSession session = request.getSession(); if (session.getAttribute("loginUser") != null) { return new ModelAndView("decorators/logout"); } else { return new ModelAndView("decorators/login"); } } } }
SimpleFormController 을 상속받은 LoginFormController.java 파일을 생성한다.
- web-app/WEB-INF/net.javajigi.user.model.Authenticate.java 파일을 생성한다.
package net.javajigi.user.model; public class Authenticate { private String userId = null; private String password = null; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } }
LoginFormController.java에서 호출되는 bean객체를 생성한다.
참고문헌
출처 : http://www.javajigi.net/pages/viewpage.action?pageId=6962
출처 : http://dogfeet.tistory.com/159
Ioc.java
01.
import
java.util.Calendar;
02.
import
org.springframework.beans.factory.BeanFactory;
03.
import
org.springframework.beans.factory.xml.XmlBeanFactory;
04.
import
org.springframework.core.io.ClassPathResource;
05.
06.
public
class
Ioc {
07.
08.
private
Calendar myCalendar;
09.
10.
public
void
setMyCalendar(Calendar cal) {
11.
myCalendar = cal;
12.
}
13.
14.
@Override
15.
public
String toString() {
16.
return
"Ioc Class with "
+ myCalendar;
17.
}
18.
19.
public
static
void
main(String[] args) {
20.
System.out.println(
"Spring Study!"
);
21.
BeanFactory bf =
new
XmlBeanFactory(
new
ClassPathResource(
"beans.xml"
));
22.
System.out.println(bf.getBean(
"ioc"
));
23.
System.out.println(bf.getBean(
"date"
));
24.
}
25.
}
beans.xml
01.
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
02.
<
beans
xmlns
=
"http://www.springframework.org/schema/beans"
03.
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
04.
xsi:schemaLocation="
07.
08.
09.
<
bean
id
=
"calendar"
class
=
"java.util.GregorianCalendar"
/>
10.
11.
<
bean
id
=
"date"
class
=
"java.util.Date"
/>
12.
13.
<
bean
id
=
"ioc"
class
=
"Ioc"
>
14.
<
property
name
=
"myCalendar"
ref
=
"calendar"
/>
15.
</
bean
>
16.
17.
</
beans
>
library files
- commons-logging.jar
- org.springframework.beans-3.0.0.RC1.jar
- org.springframework.core-3.0.0.RC1.jar
execution
1.
$ javac Ioc.java -
cp
org.springframework.beans-3.0.0.RC1.jar:org.springframework.core-3.0.0.RC1.jar
2.
$ java -
cp
.:org.springframework.core-3.0.0.RC1.jar:org.springframework.beans-3.0.0.RC1.jar:commons-logging.jar Ioc
3.
Spring Study!
4.
Nov 10, 2009 5:49:14 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
5.
INFO: Loading XML bean definitions from class path resource [beans.xml]
6.
Ioc Class with java.util.GregorianCalendar[
time
=1257842954691,areFieldsSet=
true
,areAllFieldsSet=
true
,lenient=
true
,zone=sun.util.calendar.ZoneInfo[
id
=
"Asia/Seoul"
,offset=32400000,dstSavings=0,useDaylight=
false
,transitions=14,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2009,MONTH=10,WEEK_OF_YEAR=46,WEEK_OF_MONTH=2,DAY_OF_MONTH=10,DAY_OF_YEAR=314,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=49,SECOND=14,MILLISECOND=691,ZONE_OFFSET=32400000,DST_OFFSET=0]
7.
Tue Nov 10 17:49:14 KST 2009
오역된 부분이 있을 지도 모르겠습니다.-_-;; 교과서 영어가 아니라-_-;; 나름대로 의역을 하긴 했는데 어렵네요.
----여기부터는 번역입니다.
jQuery는 겸손한(unobtrusive) 자바스크립트를 위한 자바스크립트 라이브러리다. jQuery는 태생적으로 Behavior driven development 방법론을 지향하고 CSS 셀렉터를 사용하여 HTML 문서를 훓는 방법(traversing)을 방법에 기반한다. 반면에 Prototype은 태생적으로 Class driven development를 지향하고 쉽게 자바스크립트 개발할 수 있도록 해준다. Prototype 라이브러리는 Ruby on Rails에서 아주 잘 지원되고 많은 헬퍼 함수들을 가지고 있다.
세달 전에 마음을 jQuery로 굳히기까지 나는 항상 Prototype 라이브러리를 사용해왔다. jQuery은 나를 매우 고무시겼다. 여기에 그 이유가 있다.
1. BDD(Behavior driven development)
jQuery를 사용하면 CSS로 HTML 엘리먼트의 스타일을 정의하는 것 처럼 HTML 엘리먼트의 행동들을 분리하여 정의할 수 있다. 클릭했을 때 경고창을 띄우는 예제를 보자.
1.
$(element).click(
function
(){
2.
alert(
"warning"
);
3.
});
1. href를 "javascript:void(0);"로 변경하고
2. 클릭시 로그를 남기고
3. onhover시(mouse over시) 배경색을 변경한다.
1.
$(
"div.speciallinks"
).attr(
"href"
,
"javascript:void(0)"
)
2.
.click(
function
() {console.log(
"div.speciallinks clicked"
);})
3.
.hover(
function
(){$(
this
).addClass(
"hovered"
);},
4.
function
(){$(
this
).removeClass(
"hovered"
);});
2. MVC + J
MVC 프레임웍은 웹 개발 환경을 Model-View-Controller로 나누었다. MVC 프레임워크에서 뷰는 HTML, CSS, Javascript의 부분으로 나누어지고 GUI 개발은 이 세부분이 하나로 결합하여 완성된다. 게다가 Ruby on Rails에서의 Prototype 라이브러리는 HTML과 JavaScript도 함께 합쳐버린다(meshup). 뷰를 개발하면서 JavaScript를 분리하는 BDD 방법론을 따르려 한다면 jQuery가 매우 적절하다. 나는 Ajax에서 MVC + J가 매우 강력하다는 것을 깨닭았다.
나는 JQuery를 사용하여 나의 HTML 파일을 매우 깨끗하게 만들었고 모든 JavaScript 코드를 .js에 넣음으로써 HTML 엘리먼트의 행위를 모두 .js 파일에 정의하였다.
3. 액션 체인(Chaining of actions)
액션 체인은 DRY 원칙을 따를 뿐만 아니라 JavaScript 코드의 가독성을 증가시킨다. 만약 엘리먼트에 오퍼레이션들을 삽입하려면 다음과 같이 할 수 있다.
1.
$(
"div.message"
).show()
2.
.append(
"<P>Action has been executed successfully"
)
3.
.addClass(
"flash"
);
4.
// 각 함수는 라인으로 구분하여 사용한다.
5.
</P>
이 것은 jQuery의 모든 메소드가 query 객체를 반환하기 때문에 가능하다. 그리고 뒤따르는 메소드들이 선택된 HTML 엘리먼트에 체인 형식으로 적용된다.
4. CSS 셀렉터 문제(CSS Selector rocks)
CSS 셀럭터 HTML DOM을 사용하기에 매우 강력한 도구이다. jQuery는 HTML 문서의 엘리먼트를 식별하기 위해 CSS 셀러터를 이용하고 이를 위해 HTML 태그의 id 속성을 관리해야 하는 지루한 작업을 회피하게 해준다. 대부분의 id 속성은 CSS 셀렉터를 올바르게 사용하여 회피할 수 있다. Prototype의 $$ 함수는 CSS 셀렉터를 지원하지만 CSS 셀렉터의 능력을 모두 이끌어내지 못한다. 나는 Prototype에서 id 속성을 사용하는 것이 최선이라는 것을 알게 됐다.
5. 엘리먼트의 존재 유무를 검사할 필요가 없다.
프로토타입으로 액션으로 적용하기 전에 항상 엘리먼트가 존재하는지 확인해야 했다. 예를 들어 나는 사용자가 로그인 했을 때만 사용자가 명시한 내용을 보여주고 싶었다. 사용자가 로그인 했다면 렌더링된 페이지에 div{id='user-box'}같은 엘리먼트가 있다는 것을 검사해야 했다. 프로토타입에서는 그렇게 해야 했다.
1.
if
($(
'user-box'
)!=
null
) {
2.
// jQuery에서는 이 if 블럭이 필요없다.
3.
$(
"user-box"
).style.backgroundColor =
"red"
;
4.
}
6. Aids development process
jQuery를 사용하면 HTML 코드가 간결해지고 거의 건드릴 필요가 없다. 나의 웹 디자이너는 쉽게 html과 stylesheet를 수정할 수 있고 Prototype 라이브러리를 몰라도 된다.
예제들:
여기에는 jQuery와 프로토타입의 차이점을 강조하는 몇 가지 예제가 있다(물론, 이 코드가 최상의 코드는 아니다).
Example1:
이 Tab 예제는 tabs 클래스에 속하는 3 개의 tab이 있고 id는 각각 tabs1, tabs2, tabs3이다(ids=>["tabs1","tabs2","tabs3"]). 사용자가 "show first tab" 링크를 클릭했을 때 #tab1만 보여진다.
jQuery의 경우
1.
$(
"div.tabs"
).hide();
2.
$(
"div#tabs1"
).show();
Prototype의 경우
1.
$$(
"div.tabs"
).invoke(
"hide"
);
// 이거
2.
$$(
"div.tabs"
).each(
function
(x){
3.
Element.hide(x);
4.
});
5.
// 그리고 다음과 같은 코드로 마무리한다.
6.
$(
"tabs1"
).show();
Example2:
엘리먼트의 CSS를 수정하는 예제
jQuery의 경우
1.
$(
"#user-box"
).css(
"background-color"
,
"red"
)
Prototype의 경우
1.
var
a = $(
"user-box"
);
2.
a.style.cssText +=
"background-color:red;"
;
Remy Sharp의 발표자료에서 다른 예제들도 볼 수 있다. http://ajaxian.com/archives/prototype-and-jquery-a-code-comparison.
Prototype이 좋은 이유
1. Ajax 요청에서 div의 내용이 부분적으로 변경돼야 할때 JavaScript 행위는 activated/reactivated돼야 한다. jQuery에서는 이를 위한 많은 코드를 만들지 않아도 된다. 하지만 나는 Ajax로 로드된 이 부분을 항상 마음속으로만 새겨야 한다. Prototype에서는 로드된 HTML 엘리먼트들에 관련된 JavaScript 코드가 포함된다.
2. Ruby on Rails의 Prototype 헬퍼들은 정말 대단하고 JavaScript와 Ajax를 만들때 많은 부분에서 매우 편리하다.
3. Prototype은 자바스크립에서도 Ruby같은 문법을 사용할 수 있게 해준다. 개발을 쉽고 빠르게 할 수 있도록 배열, 객체 등의 기능을 변경해준다.
4. jQuery에서는 JavaScrpt 파일이 모두 다운로드되고 DOM 생성된 후에만 엘리먼트의 행위를 사용할 수 있다. 연결이 느릴 때는 기다려야만 하기 때문에 매우 고통스럽다.
결론:
jQuery와 Prototype은 둘 다 매우 굉장하다. 나는 더 적은 코드로 더 많은 일을 하면서 직관적이고 겸손하게 유지해야 한다는 jQuery의 철학이 큰 차이를 만든다고 생각한다. 그러나 나는 Prototype이 매우 그립다. jquery-rails가 통합되길 기다리고 있다. 결국 이 고지는 점령될 것이다. 나는 사람들이 이 변화를 감지하고 있다는 소식을 들을 때마다 기쁘다.
ps> 이 두 라이브러리를 함께 사용하려면 여기를 보라.
출처 : http://dogfeet.tistory.com/29
package com.jisan.common.util.page;
public class Paging {
private int totalCount;
private int currentPage;
private int listLimit;
private int pageLimit;
private int totalPage;
private int startPage;
private int endPage;
private int startNum;
private int endNum;
private String btnStart="";
private String btnEnd="";
private String btnListPrev="";
private String btnListNext="";
private String btnPageList="";
private String btnListTenPrev= "";
private String btnListTenNext= "";
public Paging(int totalCount, int currentPage, String queryOption) {
this.totalCount = totalCount;
this.currentPage = currentPage;
this.listLimit = 15;
this.pageLimit = 5;
}
public Paging(int totalCount, int currentPage, String queryOption, int listLimit, int pageLimit) {
this.totalCount = totalCount;
this.currentPage = currentPage;
this.listLimit = listLimit;
this.pageLimit = pageLimit;
}
public PagingBean pagingProcess() throws Exception {
PagingBean pb = new PagingBean();
totalPage = (totalCount - 1) / listLimit + 1;
startPage = ( (currentPage - 1) / pageLimit) * pageLimit + 1;
endPage = startPage + pageLimit - 1;
if (totalPage < endPage) {
endPage = totalPage;
}
if (totalCount == 0) {
totalPage = 0;
}
startNum = (currentPage - 1) * listLimit;
endNum = listLimit;
//제일 처음 페이지로.
if (currentPage > 1) {
btnStart = "<a href=\"javascript:go_Page('1')\"><img src=\"/spi/images/board/pag_rr.jpg\" border=\"0\" class=\"m_lr2\" /></a> ";
} else{
btnStart = "<a href=\"#\"><img src=\"/spi/images/board/pag_rr.jpg\" border=\"0\" class=\"m_lr2\" /></a> ";
}
//바로 이전 페이지 목록으로. (예: 이전 10 페이지로)
if (currentPage > pageLimit) {
int prevListPage = startPage - 1;
btnListPrev = "<a href=\"javascript:go_Page('"+prevListPage+"')\"><img src=\"/spi/images/board/pag_r.jpg\" border=\"0\" class=\"m_lr5\" /></a> ";
} else{
btnListPrev = " ";
}
//페이지 목록
btnPageList = "";
for (int i = startPage; i <= endPage; i++) {
if (currentPage == i) {
btnPageList += "<b><a href=\"#\" align=\"center\" valign=\"middle\" class=\"text_05\">" + i + "</a></b>";
} else {
btnPageList += "<a href=\"javascript:go_Page('"+i+"')\" align=\"center\" valign=\"middle\" class=\"text_05\"> " + i + "</a>";
}
if (i < endPage) {
btnPageList += "<img src=\"/spi/images/board/icon_pagingdot.jpg\" class=m_lr2>";
}
}
//바로 다음 페이지 목록으로. (예: 다음 10 페이지로)
int nextListPage = endPage + 1;
if (nextListPage <= totalPage) {
btnListNext = " <a href=\"javascript:go_Page('"+nextListPage+"')\"><img src=\"/spi/images/board/pag_f.jpg\" border=\"0\" class=\"m_lr5\" /></a> ";
} else {
btnListNext = " ";
}
//제일 마지막 페이지로.
if (currentPage < totalPage) {
btnEnd = " <a href=\"javascript:go_Page('"+totalPage+"')\"><img src=\"/spi/images/board/pag_ff.jpg\" border=\"0\" class=\"m_lr2\" /></a>";
} else {
btnEnd = " <a href=\"#\"><img src=\"/spi/images/board/pag_ff.jpg\" border=\"0\" class=\"m_lr2\" /></a>";
}
StringBuffer pageInfo = new StringBuffer();
pb.setPageInfo(pageInfo.toString());
StringBuffer pageHtml= new StringBuffer();
pageHtml.append("<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">");
pageHtml.append(" <tr>");
pageHtml.append(" <td align=\"center\">" );
pageHtml.append( btnStart);
pageHtml.append( btnListPrev);
pageHtml.append( btnPageList);
pageHtml.append( btnListNext);
pageHtml.append( btnEnd);
pageHtml.append(" </td>");
pageHtml.append(" </tr>");
pageHtml.append("</table>");
pb.setPageHtml(pageHtml.toString());
//페이징 처리 내용을 넘기기 위해 PagingBean에 처리한 값들을 담는다.
pb.setTotalCount(totalCount);
pb.setCurrentPage(currentPage);
pb.setTotalPage(totalPage);
pb.setStartPage(startPage);
pb.setEndPage(endPage);
pb.setStartNum(startNum);
pb.setEndNum(endNum);
pb.setBtnStart(btnStart);
pb.setBtnEnd(btnEnd);
pb.setBtnListPrev(btnListPrev);
pb.setBtnListNext(btnListNext);
pb.setBtnPageList(btnPageList);
return pb;
}
public PagingBean pagingProcess2() throws Exception {
PagingBean pb = new PagingBean();
totalPage = (totalCount - 1) / listLimit + 1;
startPage = ( (currentPage - 1) / pageLimit) * pageLimit + 1;
endPage = startPage + pageLimit - 1;
if (totalPage < endPage) {
endPage = totalPage;
}
if (totalCount == 0) {
totalPage = 0;
}
startNum = (currentPage - 1) * listLimit;
endNum = listLimit;
//제일 처음 페이지로.
if (currentPage > 1) {
btnStart = "<a href=\"javascript:go_Page('1')\"><img src=\"/spi/images/board/button_start_be.gif\" border=\"0\" class=\"m_lr2\" /></a> ";
} else{
//btnStart = "<a href=\"#\"><img src=\"/spi/images/board_img/button_start.gif\" border=\"0\" align=\"middle\" /></a> ";
}
//이전 10 페이지
int pretenpage = (currentPage/pageLimit-1)*10+1;
if (pretenpage > 0) {
btnListTenPrev += "<a href=\"javascript:go_Page('"+pretenpage+"')\"><img src=\"/spi/images/board/pag_rr.jpg\" border=\"0\" class=\"m_lr2\" /></a> ";
} else{
//btnStart = "<a href=\"#\"><img src=\"/spi/images/board_img/button_start.gif\" border=\"0\" align=\"middle\" /></a> ";
}
//바로 이전 페이지 목록으로.
//if (currentPage > pageLimit) {
if (totalPage > 1) {
int prevListPage = currentPage - 1;
if(prevListPage < 1){
//btnListPrev = "<a href=\"#\"><img src=\"/spi/images/board_img/button_pre.gif\" border=\"0\" align=\"middle\" /></a> ";
}else{
btnListPrev = "<a href=\"javascript:go_Page('"+prevListPage+"')\"><img src=\"/spi/images/board/pag_r.jpg\" border=\"0\" class=\"m_lr5\" /></a> ";
}
} else{
btnListPrev = " ";
}
//페이지 목록
btnPageList = "";
for (int i = startPage; i <= endPage; i++) {
if (currentPage == i) {
btnPageList += "<a href=\"#\" align=\"center\" valign=\"middle\" ><b>" + i + "</b></a>";
} else {
btnPageList += "<a href=\"javascript:go_Page('"+i+"')\" align=\"center\" valign=\"middle\">" + i + "</a>";
}
if (i < endPage) {
btnPageList += " <img src=\"/spi/images/board/icon_pagingdot.jpg\" class=\"m_lr2\">";
}
if(endPage==1){
}else{
btnPageList += " ";
}
}
//바로 다음 페이지 목록으로. (예: 다음 10 페이지로)
int nextListPage = currentPage + 1;
if (nextListPage <= totalPage) {
btnListNext = "<a href=\"javascript:go_Page('"+nextListPage+"')\"><img src=\"/spi/images/board/pag_f.jpg\" border=\"0\" class=\"m_lr5\" /></a> ";
} else {
//btnListNext = " ";
}
//다음 10 페이지
int nexttenpage = (1+currentPage/pageLimit)*10+1;
if (totalPage > nexttenpage) {
btnListTenNext += "<a href=\"javascript:go_Page('"+nexttenpage+"')\"><img src=\"/spi/images/board/pag_ff.jpg\" border=\"0\" class=\"m_lr2\" /></a> ";
} else{
//btnStart = "<a href=\"#\"><img src=\"/spi/images/board_img/button_start.gif\" border=\"0\" align=\"middle\" /></a> ";
}
//제일 마지막 페이지로.
if (currentPage < totalPage) {
btnEnd = "<a href=\"javascript:go_Page('"+totalPage+"')\"><img src=\"/spi/images/board/button_end_last.gif\" border=\"0\" class=\"m_lr2\" /></a>";
} else {
//btnEnd = " <a href=\"#\"><img src=\"/spi/images/board_img/button_end.gif\" border=\"0\" align=\"middle\" /></a>";
}
StringBuffer pageInfo = new StringBuffer();
pb.setPageInfo(pageInfo.toString());
StringBuffer pageHtml= new StringBuffer();
pageHtml.append("<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">");
pageHtml.append(" <tr>");
pageHtml.append(" <td align=\"center\" >" );
pageHtml.append( btnStart);
pageHtml.append( btnListTenPrev);
pageHtml.append( btnListPrev);
pageHtml.append( btnPageList);
pageHtml.append( btnListNext);
pageHtml.append( btnListTenNext);
pageHtml.append( btnEnd);
pageHtml.append(" </td>");
pageHtml.append(" </tr>");
pageHtml.append("</table>");
pb.setPageHtml(pageHtml.toString());
//페이징 처리 내용을 넘기기 위해 PagingBean에 처리한 값들을 담는다.
pb.setTotalCount(totalCount);
pb.setCurrentPage(currentPage);
pb.setTotalPage(totalPage);
pb.setStartPage(startPage);
pb.setEndPage(endPage);
pb.setStartNum(startNum);
pb.setEndNum(endNum);
pb.setBtnStart(btnStart);
pb.setBtnEnd(btnEnd);
pb.setBtnListPrev(btnListPrev);
pb.setBtnListNext(btnListNext);
pb.setBtnPageList(btnPageList);
return pb;
}
}
보통 톰캣으로 서비스 구축할 때 안정적으로 서비스하려면 한 서버에 톰캣을 4개 정도 구동시켜야 한다고 하던데 ㅎㅎ
http://www.ibm.com/developerworks/kr/li ··· 61017%2F
웹 개발자에게 있어 톰캣은 JSP를 배우거나 간단한 테스트를 하는 정도의 웹 컨테이너로 생각하는 경우가 많다. 하지만 근래 들어 기업 및 대형 포탈에서 상용 서비스를 위한 웹 컨테이너로서 톰캣을 선택해, 성공적으로 적용한 사례들이 늘고 있다. 톰캣에서 안정적인 웹 서비스를 제공하기 위해서 지원하는 기능은 5가지가 있다. 아파치 웹서버와 연동, 로드밸런싱, 세션 클러스터링, 데이터베이스 처리, 모니터링 및 관리 등이 그것이다.
이 문서에서는 로드밸런싱과 세션 클러스터링 위주로 설명을 할 것이며, 다음에 기회가 된다면 다른 부분에 대해서도 자세히 알아보도록 하겠다.
아파치 웹 서버와 톰캣의 연동
일반적으로 정적인 페이지를 서비스할 때는 웹서버가 훨씬 더 좋은 성능을 발휘한다. 또한 이렇게 역할 분담을 함으로 톰캣에 가중되는 부하를 줄여주는 효과도 얻을 수 있다. 아파치웹서버와 톰캣을 연동하는 것을 일반적으로 ‘커넥터(Connector)'라고 부르며, 여기에는 WARP 커넥터, JK 커넥터 그리고 JK2 커넥터가 있다. 이중에서 WARP와 JK2는 공식 커넥터에서 제외되었고 현재 남아 있는 것은 JK 커넥터뿐이다. 그럼 먼저 JK 커넥터를 이용해서 아파치 웹서버와 톰캣을 연동해 보도록 하겠다.
아파치 웹사이트에서 바이너리 혹은 소스 코드를 다운로드 받도록 하자. 유닉스 혹은 리눅스는 mod_jk.so이며 윈도우용은 mod_jk.dll이다. 이 파일을 아파치 웹서버의 modules 디렉토리에 저장한다(주의, 아파치 웹서버를 컴파일해서 사용하는 경우는 컴파일시에 DSO 기능이 가능하도록 설정해줘야 한다). 저장을 한 후에 아파치 웹서버에 해당 모듈을 인식시켜야 하며 아파치 웹서버의 httpd.conf 파일에 다음 내용을 추가하도록 하자.
리스트 1. httpd.conf
... LoadModule jk_module modules/mod_jk.so # 모듈 추가 JkWorkersFile "conf/workers.properties" # JK 설정 파일 위치 및 이름 JkLogFile "logs/mod_jk.log" # JK에 대한 로그 파일 위치 JkLogLevel info # 로그 레벨 지정 JkLogStampFormat "[%a %b %d %H:%M:%S %Y]" # 로그 시간 포맷 지정 JkRequestLogFormat "%w %V %T" # 로그 내용 포맷 JkMount /* loadbalancer # URL 링크 -> 모든 요청을 톰캣으로 지정 JkMount /servlet/* loadbalancer # URL 링크 -> servlet 요청을 톰캣으로 지정 ...
위와 같은 설정을 하게 되면 아파치 웹서버로 들어온 모든 요청을 톰캣으로 재전송 하게 된다. 만일 JSP와 서블릿만 톰캣에서 서비스를 하고 나머지는 아파치 웹서버에서 서비스 하고자 한다면 다음과 같이 수정하면 된다.
JkMount /*.jsp loadbalancer # URL 링크 -> *.jsp 요청을 톰캣으로 지정 JkMount /servlet/* loadbalancer # URL 링크 -> servlet 요청을 톰캣으로 지정
httpd.conf에는 위의 내용이 전부이다. 그럼 이제 workers.properties 파일을 작성해 보도록 하겠다. 이 파일이 실제 로드밸런싱을 위한 설정이 되겠다.
라운드 로빈 방식의 로드밸런싱 설정
톰캣에서 제공하는 로드밸런싱은 정확히 톰캣 자체에서 제공하는 것이 아니라 아파치 웹서버와 연동되는 커넥터에 의해서 제공된다(로드밸런싱은 JK, JK2 커넥터에서만 제공된다). 현재는 라운드 로빈(Round Robin) 방식만이 제공되며 로드밸런싱에 대한 설정은 workers.properties 파일에서 정의하게 된다.
리스트 2. workers.properties
worker.list=tomcat1, tomcat2, loadbalancer worker.tomcat1.type=ajp13 worker.tomcat1.host=localhost worker.tomcat1.port=11009 worker.tomcat1.lbfactor=100 worker.tomcat2.type=ajp13 worker.tomcat2.host=localhost worker.tomcat2.port=12009 worker.tomcat2.lbfactor=200 worker.loadbalancer.type=lb worker.loadbalancer.balanced_workers=tomcat1,tomcat2
worker라는 개념은 톰캣의 프로세스로 보면 된다. 즉 worker를 설정하는 구성 요소는 JK 커넥터를 연결하는 방식(JK는 ajp13을 이용한다), 톰캣이 실행되어 있는 IP 혹은 도메인, ajp13 서비스 포트, 그리고 작업 할당량이다. 여기서 주의 깊게 볼 것이 작업 할당량인데 로드밸런싱 시에 lbfactor라는 작업량의 비율을 보고 라운드 로빈 방식의 서비스를 제공하게 된다. 여기서는 tomcat1과 tomcat2를 1대 2의 비율로 작업량을 할당한 것이다.
그럼 이제 남은 작업은 2개의 톰캣 프로세스를 실행시키는 것이다. 톰캣 프로세스를 여러 개 띄우는 방법은 2가지가 있다.
- 톰캣을 2개 설치해서 기동시킨다. 이때 포트 충돌을 피하기 위해 서버 포트, AJP13과 HTTP 1.1 커넥터 포트 2개를 충돌되지 않게 재정의 한다.
- 하나의 톰캣에 2개의 서비스를 정의하고 톰캣을 기동시킨다. 이때 AJP13과 HTTP1.1 커텍터 포트 2개를 충돌되지 않게 재정의 한다.
먼저 2개의 바이너리를 설치했다고 가정하면 각각의 톰캣은 다음과 같은 형태의 server.xml 파일로 적용해 준다.
리스트 3. server.xml
리스트 4. server.xml
리스트 3은 tomcat1의 환경 설정이고 리스트 4는 tomcat2의 환경 설정이다. 두 환경 설정의 차이는 3개의 포트번호와 태그의 jvmRoute 속성이다. 태그의 포트는 톰캣을 종료 시키는 작업을 할 때 사용하는 것이며 태그의 포트들은 아파치를 통하지 않고 직접 톰캣에 접속할 경우와 아파치와 연계하여 JK 커넥터와 연동할 때 사용하는 포트이다. 마지막으로 태그는 JK 커넥 터에서 로드밸런싱을 수행할 때 해당 값을 구분자로 활용하게 되는데 이 값을 반드시 다른 톰캣 프로세스와 다른 이름으로 지정해야 한다. 지금까지의 환경 설정은 하나의 아파치 웹서버와 두 개의 톰캣 간의 연계를 위한 것이며 톰캣은 동일한 하드웨어 장비에 설치되어 있다는 가정하에 적용한 것이다. 만일 각각의 톰캣이 서로 다른 하드웨어에 존재한다면 jvmRoute명만 다르게 하고 포트명은 동일해도 상관이 없다. 하지만 만일 하나의 장비에 4개의 톰캣 프로세스를 실행시키고 로드밸런싱을 하려고 한다면 어떻게 될까? 톰캣을 4번 설치하고 각각의 환경 설정 파일을 수정해 주어야 할까? 만일 필요한 환경 설정 내용이 변경된다면(예를 들어 JNDI Resource 정보) 모두 운영자가 환경 설정 파일을 수정해 주어야 할까? 다행히도 톰캣에서는 하나의 바이너리에 여러 개의 프로세스가 뜨도록 할 수 있다. 톰캣의 server.xml 태그는 다음과 같은 구조를 가지고 있다.
--> --> --> -->
여기서 Server 태그는 유일해야 하며 Server 태그 밑에는 여러 개의 태그가 올 수 있다. 여기서 말하는 태그가 바로 하나의 톰캣 프로세스가 된다. 만일 2개의 태그를 정의했다면 2개의 프로세스가 구동되는 것이다. 리스트 5는 이렇게 구현한 환경 설정 파일이다.
리스트 5. server.xml
리스트 5는 하나의 톰캣 바이너리를 통해 2개의 프로세스를 실행시키는 것이다. 이렇게 하면 환경 설정의 편리성을 가져올 수 있지만 특정 서비스만 실행하거나 종료 시키는 것은 아직 지원되지 않는다. 즉 모든 서비스가 동시에 실행되거나 혹은 동시에 종료되는 것을 의미한다. 이런 점을 잘 판단해서 두 가지 형태의 환경 설정 중 하나를 선택하면 되겠다.
지금까지는 로드밸런싱에 대해 알아보았다. 위의 환경설정을 가지고 테스트를 하다 보면 한가지 문제가 발생한다. 예를 들어 어떤 사용자가 tomcat1을 이용해서 쇼핑몰 서비스를 받고 있다가 tomcat1이 비정상 종료를 하게 되었다. 이때 사용자가 웹 페이지를 요청하게 되면 아파치 웹서버는 tomcat1이 종료된 것을 인지하고 그 이후부터 서비스를 tomcat2로 요청하게 된다. 하지만 tomcat1에 저장되어 있던 쇼핑바구니 정보 즉 세션 정보는 사라진 상태다. 즉, 서비스는 유지되지만 사용자는 다시 이유도 모르게 처음부터 쇼핑 항목들을 등록해야 하는 문제를 가지게 된다. 이제부터는 이런 문제를 해결할 수 있는 톰캣 프로세스 간의 세션 정보 공유에 대해서 알아보겠다.
세션 클러스터링 설정
클러스터링은 톰캣 5.x 버전부터 지원이 되고 있지만 아직은 초기 단계이고 세션 클러스터링만이 제공되고 있는 수준이다. 기능이 많이 부족하긴 하지만 로드밸런싱과 더불어 사용할 경우에는 좀 더 안정적인 서비스를 제공할 수 있다. 작업을 해주어야 할 것은 다음과 같다.
- server.xml에 태그 정의
- 웹 어플리케이션의 web.xml에 태그 추가
리스트 6. server.xml
... ...
리스트 6은 tomcat1의 server.xml에 적용한 태그이다. 이 내용은 태그 사이에 위치하게 된다. 태그 사이에는 , , 라는 3개의 태그가 위치하는데 은 멤버 그룹을 정의하는 것으로 해당 값이 동일한 모든 톰캣 프로세스는 클러스터로 묶이게 된다. 는 클러스터 그룹에서 보내오는 메시지와 세션 정보 등을 받아오는 것이며 는 자신의 세션 정보 및 메시지를 전송하는 것이다. 위의 내용을 tomcat2의 server.xml에 Receiver 태그의 tcpListenPort 값을 4002로 변경해서 적용하도록 하자.
웹 어플리케이션 작성을 통한 테스트
먼저 테스트를 위해서 간단한 웹 어플리케이션을 작성하도록 하겠다. 여기서 웹 어플리케이션 이름은 lbtest라고 하겠다.
리스트 7. index.jsp
<%@ page contentType="text/html; charset=euc-kr" %>
세션 JSP 테스트
<% Integer ival = (Integer)session.getAttribute("sessiontest.counter"); if(ival==null) { ival = new Integer(1); } else { ival = new Integer(ival.intValue() + 1); } session.setAttribute("sessiontest.counter", ival); %> 당신은 이곳을 <%= ival %> 번 방문 했습니다.여기를 클릭하세요. 여기
request 객체와 관련된 세션 데이터
요청된 세션 ID : <%= request.getRequestedSessionId() %>쿠키로 부터 요청된 세션 ID 인가? : <%= request.isRequestedSessionIdFromCookie() %>
URL로부터 요청된 세션 ID 인가? : <%= request.isRequestedSessionIdFromURL() %>
유효한 세션 ID 인가? : <%= request.isRequestedSessionIdValid() %>
작성된 웹 애플리케이션을 tomcat1과 tomcat2에 배포한다. 이때 가장 중요한 것이 web.xml에 반드시 이라는 항목을 넣어 야 한다. 그럼 이제 테스트를 해보도록 하자. 먼저 아파치 웹서버, tomcat1, tomcat2를 차례로 실행시켜 보자. 그리고 http://ipaddress/lbtest/index.jsp 접속하여 세션 객체를 생성해보자. 결과 화면은 그림 1과 같다. 여기서 요청된 세션ID를 보면 뒤에 어떤 톰캣에 접속한 상태인지를 알 수 있다. 이 화면상에서는 tomcat2에 접속한 세션이다. 그럼 tomcat2를 강제로 종료시켜 보도록 하자. 종료 후 화면에 보이는 “여기”를 계속 눌러 보자. 분명히 tomcat2가 종료되었음에도 불구하고 세션 값이 유지되고 있음을 알 수 있다. 이젠 반대로 tomcat2를 다시 실행시킨 후에 tomcat1을 종료시켜 보도록 하자. 역시 마찬가지로 세션 정보가 유지되는 것을 확인할 수 있을 것 이다.
그림 1. 테스트 결과 화면
이상으로 톰캣을 이용한 로드밸런싱과 세션 클러스터링에 대해서 알아보았다. 일반적으로 로드밸런싱과 클러스터링은 성능 향상이라는 측면과 안정성 확보에 그 목적을 가지고 있다. 물론 고가의 상용 웹 어플리케이션 서버에 비하면 많이 부족하고 하드웨어를 이용한 로드밸런싱과 클러스터링에 비하면 안정성이 떨어질 수도 있지만 저렴한 비용으로 최대의 안정성과 성능을 얻고자 한다면 한번쯤 시도해 볼만한 좋은 기능이라고 할 수 있다. 아무쪼록 리눅스, 아파치, 톰캣 그리고 오픈소스를 통해 즐거운 웹 어플리케이션 개발 환경을 느껴보기 바란다.
참고 자료
The Apache Tomcat Connector: http://tomcat.apache.org/connectors-doc/
Clustering/Session Replication HOW-TO: http://tomcat.apache.org/tomcat-5.5-doc/cluster-howto.html
출처 : http://tellus.tistory.com/63?srchid=BR1http%3A%2F%2Ftellus.tistory.com%2F63
데이터 Validator 체크를 위해서 공통클래스를 만들곤 하는데 이미 만들어진걸
씀으로서 수고를 덜 수 있다. 그게 apache 에서 제공하는 common-validator jar 이다.
이것을 잘 활용한다면 많은 수고를 덜수 있다. 무식하게 만든다고 장땡이는 아니다.
있는걸 활용해서 시간을 업무에 집중할수 있는것도 중요하다.
http://commons.apache.org/validator/index.html
현재 1.3.1 까지 나와있는 상태이다. 그대로 활용해도 되지만
이 jar 내부에 제공하는 클래스들을 상속받아 좀더 구체적인 로직을 구현해서 사용하는것도
확장성 면에서 고려해볼만하다. 1.3. 에선 xml 검증 엔진도 추가되어있다.
routines 패키지 내에 보면 구체적으로 Validator 체크를 할수 있도록 클래스가 제공된다.
클래스 이름만 봐도 어떤 종류의 데이터를 체크할수 있을지 감이 올것이다.
그리고 제일 위 3개는 Abstract 라는 이름이 붙어있다. 이것은 추상클래스를 나타내며
3개를 제외한 클래스들에서 상속받아 구체적으로 구현한것이다. 그러므로 3개를 제외한
클래스들을 쓰면된다.
common-validator API 를 보면 http://commons.apache.org/validator/api-1.3.1/
설명에도 나와있지만 어떤 특정데이타를 다룰때 그 데이타에 해당하는 validator 를
체크할수 있도록 클래스가 분류 되어있는 것을 볼수있다.
데이타에 대한 validator 가 아닌 일반적인 체크는 아래 클래스들을 사용하면되는데
보통 Genericvalidator 를 많이 사용한다.
함수예제를 몇가지 추려보면 다음과 같다.
public static boolean isBlankOrNull(String value) : blank or null 체크
public static boolean isByte(String value) : Byte 로 변환가능한지 여부
public static boolean isShort(String value) : Short 변환가능한지 여부
public static boolean isInRange(byte value, byte min, byte max)
범위지정한 곳에 속하는지에 대한 여부 등등이 있다.
위 함수들을 사용해서 구현한 예제이다.
private static final int ID_CHECK_ID = 2;
public void validateId(String id){
if (!GenericValidator.minLength(id, ID_CHECK_ID)){
throw new IllegalArgumentException("ID 의 길이가 너무 작습니다");
}
}
출처 : http://mainia.tistory.com/336?srchid=BR1http%3A%2F%2Fmainia.tistory.com%2F336
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
/**
* 공통 String Util
* org.apache.commons.lang.StringUtils 상속후 필요 메소드 추가
* 자세한 기타 자세한 스펙은 org.apache.commons.lang.StringUtils 참조
* (url : http://jakarta.apache.org/commons/lang/api-release/org/apache/commons/lang/StringUtils.html)
*/
public class StringUtil extends StringUtils {
public static String nullToZero(String value){
;
if(value == null || value.equals("")){
value = "0";
}
return value;
}
/**
* 문자열 좌측의 공백을 제거하는 메소드
* @param str 대상 문자열
* @return trimed string with white space removed from the front.
*/
public static String ltrim(String str){
int len = str.length();
int idx = 0;
while ((idx < len) && (str.charAt(idx) <= ' '))
{
idx++;
}
return str.substring(idx, len);
}
/**
* 문자열 우측의 공백을 제거하는 메소드
* @param str 대상 문자열
* @return trimed string with white space removed from the end.
*/
public static String rtrim(String str){
int len = str.length();
while ((0 < len) && (str.charAt(len-1) <= ' '))
{
len--;
}
return str.substring(0, len);
}
/**
* String을
* @param str
* @return
*/
public static String changeMoney(String str) {
DecimalFormat df = new DecimalFormat("###,###");
return df.format(parseInt(str));
}
/**
* 파라미터로 넘어오는 String을 , 를 제거해준다.
*
* @param s java.lang.String
* @return java.lang.String
*/
public static String removeComma(String str) {
String rtnValue = str;
if ( isNull(str) ) {
return "";
}
rtnValue = replace(rtnValue, ",", "");
return rtnValue;
}
/**
* 숫자 0이 넘어오면 ""로 대치
* @param int 대상 숫자
* @return java.lang.String
*/
public static String isOneNull(int num){
if (num == 0) return "";
else return Integer.toString(num);
}
/**
* str이 null 이거나 "", " " 일경우 return true
* @param str
* @return
*/
public static boolean isNull(String str) {
return (str == null || (str.trim().length()) == 0 );
}
public static boolean isNull(Object obj) {
String str = null;
if( obj instanceof String ) {
str = (String)obj;
} else {
return true;
}
return isNull(str);
}
/**
* null이 아닐때.
* @param str
* @return
*/
public static boolean isNotNull(String str) {
/**
* isNull이 true이면 false
* false이면 true
*/
if( isNull(str) ){
return false;
} else {
return true;
}
}
/***
* 널체크
* @param obj
* @return
*/
public static boolean isNotNull(Object obj) {
String str = null;
if( obj instanceof String ) {
str = (String)obj;
} else {
return false;
}
return isNotNull(str);
}
/**
* 파라미터가 null 이거나 공백이 있을경우
* "" 로 return
* @param value
* @return
*/
public static String replaceNull(String value) {
return replaceNull(value, "");
}
/**
* Object를 받아서 String 형이 아니거나 NULL이면 ""를 return
* String 형이면 형 변환해서 넘겨준다.
* @param value
* @return
*/
public static String replaceNull(Object value) {
Object rtnValue = value;
if( rtnValue == null || !"java.lang.String".equals(rtnValue.getClass().getName())) {
rtnValue = "";
}
return replaceNull((String)rtnValue, "");
}
/**
* 파라미터로 넘어온 값이 null 이거나 공백이 포함된 문자라면
* defaultValue를 return
* 아니면 값을 trim해서 넘겨준다.
* @param value
* @param repStr
* @return
*/
public static String replaceNull(String value, String defaultValue) {
if (isNull(value)) {
return defaultValue;
}
return value.trim();
}
/**
* Object를 받아서 String 형이 아니거나 NULL이면 defaultValue를 return
* String 형이면 형 변환해서 넘겨준다.
* @param value
* @param repStr
* @return
*/
public static String replaceNull(Object value, String defaultValue) {
String valueStr = replaceNull(value);
if ( isNull(valueStr) ) {
return defaultValue;
}
return valueStr.trim();
}
/**
* Method ksc2asc.
* 8859-1를 euc-kr로 인코딩하는 함수
* @param str - String
* @return String
*/
public static String ksc2asc(String str) {
String result = "";
if (isNull(str)) {
result = "";
} else {
try {
result = new String( str.getBytes("euc-kr"), "8859_1" );
} catch( Exception e ) {
result = "";
}
}
return result;
}
/**
* Method asc2ksc.
* euc-kr을 8859-1로 인코딩하는 함수
* @param str - String
* @return String
*/
public static String asc2ksc(String str) {
String result = "";
if (isNull(str)) {
result = "";
} else {
try {
result = new String( str.getBytes("8859_1"), "euc-kr" );
} catch( Exception e ) {
result = "";
}
}
return result;
}
/**************************************************************************************/
/* parse method start */
/**
* String을 int형으로
* @param value
* @return
*/
public static int parseInt(String value) {
return parseInt(value, 0);
}
/**
* Object를 int형으로
* defaultValue는 0이다.
* @param value
* @return
*/
public static int parseInt(Object value) {
String valueStr = replaceNull(value);
return parseInt(valueStr, 0);
}
/**
* Object를 int형으로
* Object가 null이면 defaultValue return
* @param value
* @param defaultValue
* @return
*/
public static int parseInt(Object value, int defaultValue) {
String valueStr = replaceNull(value);
return parseInt(valueStr, defaultValue);
}
/**
* String을 int형으로
* String이 숫자 형식이 아니면 defaultValue return
* @param value
* @param defaultValue
* @return
*/
public static int parseInt(String value, int defaultValue) {
int returnValue = 0;
if( isNull(value) ) {
returnValue = defaultValue;
} else if( !isNumeric(value) ) {
returnValue = defaultValue;
} else {
returnValue = Integer.parseInt(value);
}
return returnValue;
}
/**
* String을 long형으로
* defaultValue는 0이다.
* @param value
* @return
*/
public static long parseLong(String value) {
return parseLong(value, 0);
}
/**
* String을 long형으로
* 잘못된 데이타 일시 return은 defaultValue
* @param value
* @return
*/
public static long parseLong(String value, long defaultValue) {
long returnValue = 0;
if( isNull(value) ) {
returnValue = defaultValue;
} else if( !isNumeric(value) ) {
returnValue = defaultValue;
} else {
returnValue = Long.parseLong(value);
}
return returnValue;
}
/**
* Exception을 String으로 뽑아준다.
* @param ex
* @return
*/
public static String stackTraceToString(Throwable e) {
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
return "------\r\n" + sw.toString() + "------\r\n";
}catch(Exception e2) {
return StringUtil.stackTraceToString2(e);
}
}
/**
* Exception을 String으로 뽑아준다.
* @param ex
* @return
*/
public static String stackTraceToString2(Throwable e) {
ByteArrayOutputStream b = new ByteArrayOutputStream();
PrintStream p = new PrintStream(b);
e.printStackTrace(p);
p.close();
String stackTrace = b.toString();
try {
b.close();
} catch (IOException ex) {
ex.printStackTrace();
}
// return convertHtmlBr(stackTrace);
return stackTrace;
}
/**
* Html 코드에서 <br> 태크 제거
* @param comment
* @return
*/
public static String convertHtmlBr(String comment) {
String rtnValue = "";
if( isNull(comment) ) {
return "";
}
rtnValue = replace(comment, "\r\n", "<br>");
return rtnValue;
}
/**
* String 배열을 List로 변환한다.
* @param values
* @return
*/
public static List changeList(String [] values) {
List list = new ArrayList();
if( values == null ) {
return list;
}
for(int i=0,n=values.length; i<n; i++) {
list.add(values[i]);
}
return list;
}
public static String[] toTokenArray(String str, String sep){
String[] temp = null;
try{
StringTokenizer st = new StringTokenizer(str, sep);
temp = new String[st.countTokens()];
int index = 0;
while(st.hasMoreTokens()){
temp[index++] = st.nextToken();
}
}catch(Exception e){
e.printStackTrace();
}
return temp;
}
public static String strip(String str, String str1){
if(str == null || "".equals(str.trim())) return "";
String temp = str;
int pos = -1;
while((pos = temp.indexOf(str1, pos)) != -1) {
String left = temp.substring(0, pos);
String right = temp.substring(pos + 1, temp.length());
temp = left + "" + right;
pos += 1;
}
return temp;
}
/**
* Method ksc2asc.
* euc-kr을 euc-kr로 인코딩하는 함수
* @param str - String
* @return String
*/
public static String ksc2utf8(String str) {
String result = "";
if (isNull(str)) {
result = "";
} else {
try {
result = new String( str.getBytes("euc-kr"), "utf-8" );
} catch( Exception e ) {
result = "";
}
}
return result;
}
/**
* string에 있는 ', ", \r\n 를 HTML 코드로 변환한다.
* @param str
* @return
*/
public static String changeQuotation(String str) {
String rtnValue = str;
rtnValue = replaceNull(rtnValue);
rtnValue = replace(replace(replace(rtnValue, "'", "'"), "\"", """), "\r\n", "<br>");
return rtnValue;
}
public static String changeQuotation(Object obj) {
if( isStringInteger(obj) ) {
return changeQuotation(String.valueOf(obj));
}
return "";
}
/**
* 해당 Object가 String or Integer 이면 true
* 아니면 false
* @param obj
* @return
*/
public static boolean isStringInteger(Object obj) {
boolean flag = false;
if( obj instanceof String || obj instanceof Integer ) {
flag = true;
}
return flag;
}
/**
* 백분율을 구한다.
* %는 빼고 값만 리턴
* @param value
* @param total
* @return
*/
public static String percentValue(int value, int total) {
double val = Double.parseDouble(String.valueOf(value)) / Double.parseDouble(String.valueOf(total)) * 100;
DecimalFormat df = new DecimalFormat("##0.0");
return df.format(val);
}
/**
* XSS(Cross Site Scripting) 취약점 해결을 위한 처리
*
* @param sourceString String 원본문자열
* @return String 변환문자열
*/
public static String replaceXSS(String sourceString){
String rtnValue = null;
if(sourceString!=null){
rtnValue = sourceString;
if(rtnValue.indexOf("<x-") == -1){
rtnValue = rtnValue.replaceAll("< *(j|J)(a|A)(v|V)(a|A)(s|S)(c|C)(r|R)(i|I)(p|P)(t|T)", "<x-javascript");
rtnValue = rtnValue.replaceAll("< *(v|V)(b|B)(s|S)(c|C)(r|R)(i|I)(p|P)(t|T)", "<x-vbscript");
rtnValue = rtnValue.replaceAll("< *(s|S)(c|C)(r|R)(i|I)(p|P)(t|T)", "<x-script");
rtnValue = rtnValue.replaceAll("< *(i|I)(f|F)(r|R)(a|A)(m|M)(e|E)", "<x-iframe");
rtnValue = rtnValue.replaceAll("< *(f|F)(r|R)(a|A)(m|M)(e|E)", "<x-frame");
rtnValue = rtnValue.replaceAll("(e|E)(x|X)(p|P)(r|R)(e|E)(s|S)(s|S)(i|I)(o|O)(n|N)", "x-expression");
rtnValue = rtnValue.replaceAll("(a|A)(l|L)(e|E)(r|R)(t|T)", "x-alert");
rtnValue = rtnValue.replaceAll(".(o|O)(p|P)(e|E)(n|N)", ".x-open");
rtnValue = rtnValue.replaceAll("< *(m|M)(a|A)(r|R)(q|Q)(u|U)(e|E)(e|E)", "<x-marquee");
rtnValue = rtnValue.replaceAll("&#", "&#");
}
}
return rtnValue;
}
/**
* 특정문자를 HTML TAG형식으로 변경하는 메소드.
*
* <xmp>
* & --> &
* < --> <
* > --> >
* " --> "
* ' --> '
*-----------------------------------------------------------------
* <option type=radio name=r value="xxxxxxxx"> yyyyyyy
* <input type=hidden name=h value="xxxxxxxx">
* <input type=text name=t value="xxxxxxxx">
* <textarea name=msg rows=20 cols=53>xxxxxxx</textarea>
*-
* 위와 같은 HTML 소스를 생성할 때, xxxxxxx 부분의 문자열 중에서
* 아래에 있는 몇가지 특별한 문자들을 변환하여야 합니다.
* 만약 JSP 라면 미리 변환하여 HTML 전체 TAG를 만들거나, 혹은 아래처럼 사용하세요.
*-
* <option type=radio name=r value="<%= StringUtil.translate(s) %>"> yyyyyyy
* <input type=hidden name=n value="<%= StringUtil.translate(s) %>">
* <input type=text name=n value="<%= StringUtil.translate(s) %>">
* <textarea name=body rows=20 cols=53><%= StringUtil.translate(s) %></textarea>
*-
* 또 필요하다면 yyyyyyy 부분도 translate(s)를 할 필요가 있을 겁니다.
* 필요할 때 마다 사용하세요.
*-
* </xmp>
*
* @return the translated string.
* @param str java.lang.String
*/
public static String translate(String str){
if ( str == null ) return null;
StringBuffer buf = new StringBuffer();
char[] c = str.toCharArray();
int len = c.length;
for ( int i=0; i < len; i++){
if ( c[i] == '&' ) buf.append("&");
else if ( c[i] == '<' ) buf.append("<");
else if ( c[i] == '>' ) buf.append(">");
else if ( c[i] == '"' ) buf.append("""); // (char)34
else if ( c[i] == '\'') buf.append("'"); // (char)39
else buf.append(c[i]);
}
return buf.toString();
}
/**
* String 앞 또는 뒤를 특정문자로 지정한 길이만큼 채워주는 함수 <BR>
* (예) pad("1234","0", 6, 1) --> "123400" <BR>
*
* @param src Source string
* @param pad pad string
* @param totLen total length
* @param mode 앞/뒤 구분 (-1:front, 1:back)
* @return String
*/
public static String pad(String src, String pad, int totLen, int mode){
String paddedString = "";
if(src == null) return "";
int srcLen = src.length();
if((totLen<1)||(srcLen>=totLen)) return src;
for(int i=0; i< (totLen-srcLen); i++){
paddedString += pad;
}
if(mode == -1)
paddedString += src; // front padding
else
paddedString = src + paddedString; //back padding
return paddedString;
}
/**
* 주어진 길이(iLength)만큼 주어진 문자(cPadder)를 strSource의 왼쪽에 붙혀서 보내준다.
* ex) lpad("abc", 5, '^') ==> "^^abc"
* lpad("abcdefghi", 5, '^') ==> "abcde"
* lpad(null, 5, '^') ==> "^^^^^"
*
* @param strSource
* @param iLength
* @param cPadder
*/
public static String lpad(String strSource, int iLength, char cPadder){
StringBuffer sbBuffer = null;
if (!isEmpty(strSource)){
int iByteSize = getByteSize(strSource);
if (iByteSize > iLength){
return strSource.substring(0, iLength);
}else if (iByteSize == iLength){
return strSource;
}else{
int iPadLength = iLength - iByteSize;
sbBuffer = new StringBuffer();
for (int j = 0; j < iPadLength; j++){
sbBuffer.append(cPadder);
}
sbBuffer.append(strSource);
return sbBuffer.toString();
}
}
//int iPadLength = iLength;
sbBuffer = new StringBuffer();
for (int j = 0; j < iLength; j++){
sbBuffer.append(cPadder);
}
return sbBuffer.toString();
}
/**
* 주어진 길이(iLength)만큼 주어진 문자(cPadder)를 strSource의 오른쪽에 붙혀서 보내준다.
* ex) lpad("abc", 5, '^') ==> "abc^^"
* lpad("abcdefghi", 5, '^') ==> "abcde"
* lpad(null, 5, '^') ==> "^^^^^"
*
* @param strSource
* @param iLength
* @param cPadder
*/
public static String rpad(String strSource, int iLength, char cPadder){
StringBuffer sbBuffer = null;
if (!isEmpty(strSource)){
int iByteSize = getByteSize(strSource);
if (iByteSize > iLength){
return strSource.substring(0, iLength);
}else if (iByteSize == iLength){
return strSource;
}else{
int iPadLength = iLength - iByteSize;
sbBuffer = new StringBuffer(strSource);
for (int j = 0; j < iPadLength; j++){
sbBuffer.append(cPadder);
}
return sbBuffer.toString();
}
}
sbBuffer = new StringBuffer();
for (int j = 0; j < iLength; j++){
sbBuffer.append(cPadder);
}
return sbBuffer.toString();
}
/**
* byte size를 가져온다.
*
* @param str String target
* @return int bytelength
*/
public static int getByteSize(String str){
if (str == null || str.length() == 0)
return 0;
byte[] byteArray = null;
try{
byteArray = str.getBytes("UTF-8");
}catch (UnsupportedEncodingException ex){}
if (byteArray == null) return 0;
return byteArray.length;
}
/**
* 긴 문자열 자르기
* @param srcString 대상문자열
* @param nLength 길이
* @param isNoTag 테그 제거 여부
* @param isAddDot "..."을추가 여부
* @return
*/
public static String strCut(String srcString, int nLength, boolean isNoTag, boolean isAddDot){ // 문자열 자르기
String rtnVal = srcString;
int oF = 0, oL = 0, rF = 0, rL = 0;
int nLengthPrev = 0;
// 태그 제거
if(isNoTag) {
Pattern p = Pattern.compile("<(/?)([^<>]*)?>", Pattern.CASE_INSENSITIVE); // 태그제거 패턴
rtnVal = p.matcher(rtnVal).replaceAll("");
}
rtnVal = rtnVal.replaceAll("&", "&");
rtnVal = rtnVal.replaceAll("(!/|\r|\n| )", ""); // 공백제거
try {
byte[] bytes = rtnVal.getBytes("UTF-8"); // 바이트로 보관
// x부터 y길이만큼 잘라낸다. 한글안깨지게.
int j = 0;
if(nLengthPrev > 0) while(j < bytes.length) {
if((bytes[j] & 0x80) != 0) {
oF+=2; rF+=3; if(oF+2 > nLengthPrev) {break;} j+=3;
} else {if(oF+1 > nLengthPrev) {break;} ++oF; ++rF; ++j;}
}
j = rF;
while(j < bytes.length) {
if((bytes[j] & 0x80) != 0) {
if(oL+2 > nLength) {break;} oL+=2; rL+=3; j+=3;
} else {if(oL+1 > nLength) {break;} ++oL; ++rL; ++j;}
}
rtnVal = new String(bytes, rF, rL, "UTF-8"); // charset 옵션
if(isAddDot && rF+rL+3 <= bytes.length) {rtnVal+="...";} // ...을 붙일지말지 옵션
} catch(UnsupportedEncodingException e){
e.printStackTrace();
return srcString;
}
return rtnVal;
}
/**
* total과 success 로 % 구하고 소수점 1자리까지 계산
* @param int success
* @param int total
* @return String %
*/
public static String calculatePercent(int success,int total){
String result = "0";
if(total == 0){
}else{
Double tempSuccess = new Double(success+".0");
Double tempTotal = new Double(total+".0");
Double tempPercent = new Double(100+".0");
double cal = tempSuccess.doubleValue()*tempPercent.doubleValue()/tempTotal.doubleValue();
result = new java.text.DecimalFormat("#.#").format(cal);
}
return result;
}
}
출처 : http://shonm.tistory.com/177?srchid=BR1http%3A%2F%2Fshonm.tistory.com%2F177
All_all_tables : user가 access할수있는 모든 Table
All_catalog : user가 access할수있는 모든 Table, Views, synonyms, sequence
All_clusters : user가 access할수있는 모든 clusters
All_col_comments : user가 access할수있는 모든 Table,Views에 대한 칼럼comments
All_col_privs : user에게 또는 Public에게 허용된 모든 칼럼에 대한 권한.
All_col_privs_made : user가 부여한 칼럼에 대한 권한.
All_col_privs_recd : user에게 또는 Public에게 허용된 모든 칼럼에 대한 권한.
All_coll_types : user가 access 할수 있는 모든 collection type
All_cons_columns : 제약조건에 관련된 칼럼, access할수 있는 대한 정보
All_constraints : access할수 있는 테이블에 대한 제약조건.
All_db_links : user가 access 할수 있는 데이터베이스 link
All_def_audit_opts : 오브젝트가 생성될때 적용될수있는 default오브젝트감사내용.
All_dependencies : user가 access할수있는 오브젝트간의 dependencies(참조,link)
All_directories : user가 access할 수 있는 모든 directories (owner 는 항상 sys)
All_errors : user가 access할수있는 모든 objects(view,procedure,package, function,
packagebody) 에 대한 에러.
All_ind_columns : user가 access할수있는 테이블에 대한 인덱스의 칼럼.
All_ind_partitions : user가 access할수있는 인덱스partition, partition에 대한
storage매개변수, Analyze명령에 의해 결정된 partition통계.
All_indexes : user가 access할수있는 테이블의 인덱스.
이 view의 통계를 수집하기위해, Analyze명령을 사용한다.
병렬partition인텍스탐색을 지원한다.
All_labels : system labels 에 대한 Oracle server view.
All_libraries : user가 access할 수 있는 모든 libraries.
All_lobs : user가 access할 수 있는 모든테이블에 포함된 LOBs.
All_method_params : user가 access할 수 있는 method와 그method의 parameter.
All_method_results :
All_nested_tables : user가 access할수있는테이블내의 Nested Table
All_object_tables : user가 access할수있는테이블의모든정보.
All_objects : user가 access할수있는objects(index partition,table partition,package,
package body, trigger)
All_part_col_statistics : user가 access할 수 있는 테이블partition에 대한 칼럼통계와
막대그래프화된 정보.
All_part_histograms : user가 access할수있는 테이블partition의 histograms에 대한
histogram정보.
All_part_indexes : user가 access할수있는 모든partition된 index의 partition정보.
All_part_key_columns :user가 access할수있는 partition된 objects의 partition key
칼럼에 대한정보
All_part_tables : user가 access할수있는partition된 Table에 대한 partition정보.
All_refresh : user가 access할수있는모든 refresh groups.
All_refresh_children : user가 access할 수 있는 refresh groups 안의 모든objects
All_refs : user가 access할 수 있는 칼럼중 REF칼럼과, REF속성.
All_registered_snapshots : 모든 등록된 snapshots.
All_sequences : user가 access할수있는 sequences.
All_snapshot_logs : 모든 snapshot logs.
All_snapshot_refresh_times : 모든 snapshot refresh times.
All_snapshots : user가 acces할수있는 모든 snapshots.
All_source : user가 access할수있는 모든 stored objects의 text source.
All_synonyms : user가 access할수있는 모든 synonyms.
All_tab_col_statistics : 'User_tab_columns' view안의 정보에대한 칼럼통계와 그래프정보
All_tab_columns : user가 access할수있는모든 table, views, clusters에 대한 칼럼.
이view를 활용하기위해서는 Analyze명령어를 사용한다.
All_tab_comments : user가 access할 수 있는 모든 table, views에 대한 comments.
All_tab_histograms : user가 access할수있는table, views에 대한 histograms.
All_tab_partitions : user가 access할수 있는 각각의 테이블partition에 대한
partition정보, storage parameter, Analyze명령에 의한
통계정보등을 서술한다.
All_tab_privs : user혹은 PUBLIC가 부여받은 오브젝트권한.
All_tab_privs_made : user가 부여한 user권한과 오브젝트권한.
All_tab_privs_recd : user 또는 PUBLIC이 부여받은 오브젝트권한.
All_tables : user가 access할 수 있는 모든 테이블.
Analyze명령으로 이 view의 통계를 얻을 수 있다.
All_triggers : user소유의 trigger, user소유테이블의 trigger, 또는 user가
CREATE ANY TRIGGER 권한을 갖고있다면, 모든 트리거에 대한 정보.
All_trigger_cols : user소유의 trigger, user소유테이블의 trigger, 또는 user가
CREATE ANY TRIGGER 권한을 갖고있다면, 모든 트리거에 대한 칼럼정보.
All_type_attrs : user가 access할 수 있는 type의 attributes.
All_type_methods : user가 access할수있는type의 methods.
All_types : user가 access할 수 있는 type.
All_updatable_columns : join view에서 update가능한 칼럼에 대한 정보.
All_users : 데이터베이스의 모든 user에 대한 정보.
All_views : user가 access할수있는view의 텍스트.
Audit_actions : 감사추적type코드 정보.
catalog : Oracle 5.0 version과의 호환정보를 포함한다.
이view의 사용은 추천할만하지 못하다.
cat : user_catalog 에 대한 synonym.
chained_rows : ANALYZE LIST CHAINED ROWS 명령에 대한 default table.
clu : user_clusters 테이블의 synonym.
code_pieces : dba_object_size 와 user_object_size view를 create 시에 사용됨.
code_size : dba_object_size 와 user_object_size view를 create 시에 사용됨.
col : Oracle 5.0version 호환정보를 포함하고 있다.
cols : user_tab_columns view 의 synonym.
column_privileges : user가 부여한권한,부여받은권한, owner인권한,
또는 PUBLIC에게 부여받은 권한에 대한 칼럼정보.
Dba_2pc_neighbors : 진행중인 트랜잭션에 대한 연결 및 종료에 대한 정보.
Dba_2pc_pending : recovery를 기다리는 분산된트랜잭션에 대한 정보.
Dba_all_tables : 데이터베이스내의 모든테이블(object table, relational table).
Dba_audit_exists : "AUDIT NOT EXISTS" and "AUDIT EXISTS"에 의해 생성된
감사추적요소.
Dba_audit_object : 시스템내의 모든 object에 대한 감사추적기록.
Dba_audit_session : 세션연결과 종료에 관련된 모든 감사 추적기록.
Dba_audit_statement : GRANT, REVOKE, AUDIT, NOAUDIT, ALTER SYSTEM
관련된 감사추적기록.
Dba_audit_trail : 모든 감사추적요소.
Dba_blockers : 누군가가 스스로 걸지않은 lock이 해제되기를 기다리는 session정보.
Dba_catalog : 모든 데이터베이스 table, views, synonyms 과 sequence에 대한 정보.
Dba_clu_columns : cluster칼럼과 table칼럼의 mapping정보.
Dba_clusters : 데이터베이스내에 있는 모든 cluster.
Dba_col_comments : 데이터베이스내의 모든 table, views의 칼럼에대한 comments.
Dba_col_privs : 데이터베이스내의 칼럼에 대한 모든권한.
Dba_coll_types : 데이터베이스내의 모든 collection type, VARRAYs, nested tables,
object tables 등에 대한 정보.
Dba_constraints : 모든테이블에 대한 constraint(primary, check, unique,
referential integrity, with check option on a view,
with read only on a view) 정보.
Dba_cons_columns : constraint 정의안에 있는 access가능한 칼럼에 대한 정보.
Dba_data_files : 데이터베이스파일에 관한 정보.
Dba_db_links : 데이터베이스내의 모든 Link.
Dba_Ddl_locks : 데이터베이스내의 모든 DDL lock과 DDL lock이 현저하게
요구되는 사항에 관한정보.
Dba_dependencies : object 에 대한 Dependence.(REF, HARD)
Dba_directories : 데이터베이스내의 모든 directory objects.
Dba_Dml_locks : 데이터베이스내에 구성된모든 DML lock과 DML lock이
현저하게 요구되는사항에 관한정보.
Dba_errors : 데이터베이스내의 저장된 object에 대해 가장최근에 발생된 error.
Dba_exp_files : export파일에 대한 정보.
Dba_exp_objects : 점진적으로 export 되고있는 object에 대한 정보.
Dba_exp_version : 가장최근에 export된 session에 대한 version 정보.
Dba_extents : 데이터베이스내의 모든 세그먼트를 이루는 extents에 대한 정보.
Dba_free_space : 모든 테이블스페이스내의 free extents의 정보.
Dba_free_space_coalesced : 테이블스페이스내의 합쳐진 공간에 대한 통계정보.
Dba_indexes : 데이터베이스내의 모든 index. 통계정보를 얻기위해 Analyze를 사용.
Dba_ind_columns : 모든테이블과 클러스터에서 인덱스를 구성하는 칼럼에 대한정보.
Dba_ind_partitions : 각각의 index파티션에 대해서, 파티션정보, 파티션에대한
storage 매개변수, Analyze에 결정된 파티션통계자료.
Dba_jobs : 데이터베이스에 있는 모든 Jobs.
Dba_jobs_running : 데이터베이스내에 현재 실행중인 모든 Jobs.
Dba_libraries : 데이터베이스내의 모든 libraries.
Dba_lobs : 모든 테이블에 포함된 LOBs.
Dba_locks : 데이터베이스내에 생성된 모든 lock, latch과 lock,latch가
현저하게 요구되는 사항에 대한 정보.
Dba_method_params : 데이터베이스내에 type에 대한 method 매개변수.
Dba_method_results : 데이터베이스내에 type에 대한 method results.
Dba_nested_tables : 모든테이블내에 포함된 nested table에 대한 정보.
Dba_object_size : PL/SQL object에 대한 size, bytes.
Dba_object_tables : 데이터베이스내에 모든 object tables.
Dba_objects : 데이터베이스내에 모든 objects.(index partition, table partition,
package,package_body,trigger)
Dba_obj_audit_opts : 모든 table, view에 대한 감사 option.
Dba_part_col_statistics : 모든 table 파티션에 대한 칼럼통계와 그래프정보.
Dba_part_histograms : 모든 table 파티션의 histogram에 대한 데이터(endpoint).
Dba_part_indexes : 모든 partition index에 대한 정보.
Dba_part_key_columns : 모든 partition된 object에 대한 분할키칼럼정보.
Dba_part_tables : 모든 partition된 table에 대한 정보.
Dba_priv_audit_opts : 시스템과 user에 의해 감사를 받고있는 시스템 privileges.
Dba_profiles : 모든 profiles과 해당 profile의 limit을 나타냄.
Dba_queue_schedules : 메시지를 전달하는 schedule.
Dba_queue_tables : 데이터베이스내에 생성된 모든 queue테이블의
queue type의 name과 type.
Dba_Queus : 데이터베이스내의 모든 queue에 대한 동작특성.
Dba_rchild : refresh group 안의 모든 children object.
Dba_refresh : 모든 refresh group 에 대한 정보.
Dba_refresh_children : refresh group 안의 모든 object에 대한 정보.
Dba_refs : 데이터베이스내의 모든 테이블의 REF칼럼과, REF 속성을 가진 칼럼.
Dba_refistered_snapshot_groups : 모든 snapshot 사본 그룹.
Dba_registered_snapshots : 지역테이블의 원격snapshot 에 대한 정보.
Dba_rgroup : 모든 refresh group.
Dba_roles : 모든 데이터베이스내에 존재하는 roles.
Dba_role_privs : user와 role에 부여된 role에 대한 정보.
Dba_rollback_segs : rollback segments 에 대한 정보.
Dba_segments : 모든 데이터베이스 segment에 대한 할당된 storage에 대한 정보.
Dba_sequences : 모든 데이터베이스내의 sequences 에 대한 정보.
Dba_snapshot_logs : 모든 데이터베이스내의 snapshot_logs.
Dba_snapshot_refresh_times : snapshot refresh 한 시간.
Dba_snapshots : 모든 데이터베이스내의 snapshots.
Dba_source : 모든 데이터베이스내의 저장object 의 source를포함.
Dba_stmt_audit_opts : system, user에 의한 현재의 감사option에 대한 정보.
Dba_synonyms : 데이터베이스내의 모든 synonyms
Dba_sys_privs : user에게 부여된 system privilege와 role.
Dba_tab_col_statistics : Dba_tab_columns view에 있는정보에 대한 칼럼통계와
그래프정보
Dba_tab_columns : 모든 table, view, cluster에 대한 칼럼정보. Analyze명령어사용.
Dba_tab_comments : 데이터베이스내의 모든 table, view에 대한 주석.
Dba_tab_histograms : 모든 table의 칼럼에 대한 histogram.
Dba_tab_partitions : 각각의 table partition에 대해서, partition level의 partition정보와,
partition의 storage매개변수 ,Analyze 에의해 결정된 여러 partition통계정보.
Dba_tab_privs : 모든 데이터베이스내의 object에 부여된 권한.
Dba_tables : 모든 데이터베이스내의 관계형테이블에 관한정보.Analyze로
통계정보를 얻을수 있다.
Dba_tablespaces : 모든 테이블스페이스에 관한정보.
Dba_triggers : 모든 데이터베이스내의 trigger 정보.
Dba_trigger_cols : 모든 trigger에서 사용된 칼럼정보.
Dba_ts_quotas : 모든 user에게 할당된 tablespace.
Dba_type_attrs : 데이터베이스내의 type에 대한 속성.
Dba_type_methods : 데이터베이스내의 모든 type에 대한 methods.
Dba_types : 데이터베이스내의 모든 추상적데이터type.
Dba_updatable_columns : join view에서 데이터베이스관리자가
update할수있는칼럼정보.
Dba_users : 데이터베이스내의 모든 user정보.
Dba_views : 모든 데이터베이스내의 view의 text.
Dbms_alert!_info : 등록된 alert!정보.
Dbms_lock_allocated : 사용자에게 할당된 lock정보.
Deptree : utldtree.sql 에의해 생성되며, object의 dependency tree정보를 포함함.
'Sys' user인 경우. 이 object에 관련된 공유커서를 나타내고,
다른 user인 경우공유커서이외의 object를 나타낸다.
다른 user는 공유커서정보를 얻기위해, Sys.deptree를 access할수있다.
Dictionary : data dictionary table, view에 대한 정보.
Dict_columns : data dictionary table, view에 대한 칼럼.
Error_size : Dba_obejct_size 와 user_obejct_size view를 create 할때 사용된다.
Exceptions : 무결성제약조건에 위배되는 정보를 포함. utlexcpt.sql 로 생성.
File_lock : 병렬서버view. 초기화파라미터 GC_FILE_TO_LOCKS 에 명시된,
데이터파일에 PCM lock의 mapping정보.
File_ping : 병렬서버view.각데이타파일에 할당된 block의 수.
GC_FILES_TO_LOCKS 최적값을 구하기 위해 현존하는 데이터파일의
access방법을 결정하는데 이 정보를사용할 수 있다.
FILEXT$ : DBA_DATA_FILES 와 동일. (DBA_DATA_FILES의 사용을 추천)
GLOBAL_NAME : 현제 데이터베이스의 유일한 이름.
HS_ALL_CAPS : 모든 비 Oracle Data store (FDS) 와 관련된 특성에 관한정보.
HS_ALL_DD : 모든 비 Oracle Data store(FDS)에 대한 Data dictionary.
HS_ALL_INITS : 비 Oracle Data store(FDS)에 대한 초기화 매개변수.
HS_BASE_CAPS : 비 Oracle Data store(FDS)에 대한 기본특성에 관한정보.
HS_BASE_DD : 비 Oracle Data store(FDS)에 대한 Data dictionary.
HS_CLASS_CAPS : 비 Oracle Data store(FDS)에 포함된 class-specific 특성정보.
HS_CLASS_DD : 비 Oracle Data store(FDS) class_specific data dictionary.
HS_CLASS_INIT : 비 Oracle Data store(FDS) class-specific 초기화 매개변수.
HS_EXTERNAL_OBJECT_PRIVILEGES : user에게 부여된 object권한.
HS_EXTERNAL_OBJECTS : oracle server에서 access가능한 external obejct.
HS_EXTERNAL_USER_PRIVILEGES : 어느 특정object에 국한되지않은 모든
부여된권한
HS_FDS_CLASS : 비 oracle (FDS) class 에 관한 정보.
HS_FDS_INST : 비 oracle (FDS) instance에 관한정보.
HS_INST_CAPS : instance-specific 특성정보.
HS_INST_DD : 비 oracle (FDS) instance-specific data dictionary 변경정보.
HS_INST_INIT : 비 oracle (FDS) instance-specific 초기화 매개변수정보.
IDEPTREE : UTLDTREE.sql 로 생성하고, 관련tree를 나타냄.
Deptree의 자동정렬버젼.
INDEX_HISTOGRAM : Analyze index...validate structure 명령에 대한정보.
INDEX_STATS : 마지막 Analyze index..validate structure 명령에 대한정보.
NLS_DATABASE_PARAMETERS : 데이터베이스의 NLS 매개변수.
NLS_INSTANCE_PARAMETERS : instance의 NLS 매개변수.
NLS_SESSION_PARAMETERS : user session의 NLS 매개변수.
OBJ : user_objects 의 synonym.
PARSED_PIECES : Dba_object_size, User_object_size view를 생성시에 필요.
PARSED_SIZE : Dba_obejct_size, User_object_size view를 생성시에 필요.
Plan_table : explain plan의 결과에 대한 table. utlxplan.sql로 생성.
Product_component_version : Oracle 제품군의 버전과 상태설명.
Pstubtbl : Pstub utility에 의해 생성된 stub에 관한정보.
Publicsyn : public synonym 에 관한 정보.
Public_dependency : object와 관련된 dependencies.(parent object)
Resource_cost : 각각의 resource에 대한 cost.
Resource_map : 각각의 resource에 대한 정보.(resource name, resource number)
Role_role_privs : 다른 role에 부여된 role정보.(user가 access가능한 role에 한해)
Role_sys_privs : 다른 role에 부여된 system role정보(user가 access가능한role에 한해)
Role_tab_privs : 다른 role에 부여된 table privileges정보.
(user가 access가능한role에 한해)
SEQ : user_sequences 의 synonym.
Session_privs : 현재 user에게 사용가능한 권한.
Session_roles : 현재 user에게 사용가능한 roles.
Source_size : Dba_object_size, User_object_size view를 생성시 필요.
Stmt_audit_option_map : 감사 option type code정보.
Syn : user_synonyms 에 대한 synonym.
Synonyms : Oracle ver 5.와 호환성을 포함. not recommend
Syscatalog : Oracle ver 5.와 호환성을 포함. not recommend
Sysfiles : Oracle ver 5.와 호환성을 포함. not recommend
Syssegobj : Oracle ver 5.와 호환성을 포함. not recommend
System_privilege_map : system privilege code에 대한 정보.
Sys_objects : object ID와 object type 그리고 segment data block주소를 매핑하는정보.
Tab : Oracle ver 5.와 호환성을 포함. not recommend
Table_privileges : user가 부여한, 부여받은, 소유한, 그리고 PUBLIC으로
부여된 object 권한정보. Oracle ver 6.과 호환성을 포함. not recommend.
Table_privilege_map : access 가능한 권한code/권한명칭 정보.
Tabs : User_tables 의 synonym.
Tabquotas : Oracle ver 5.와 호환성을 포함. not recommend
Trusted_servers : 분산환경에서 서버가 신뢰할만한지를 나타냄.
Tp_pitr_check : catpitr.sql 에 의해 생성. 테이블스페이스의 point-in-time복구를
방해할지도 모르는 dependencies혹은 restriction에 관한 정보제공.
Ts_pitr_objects_to_be_dropped : 테이블스페이스의 point-in-time복구수행의 결과
손실된 object에 대한 정보. (point-in-time recovery의 경우만 해당).
User_all_tables : user가 사용가능한 테이블(object table, relational table)정보.
User_arguments : user가 access가능한 object의 매개변수정보.
User_Audit_object : cataudit.sql로 생성. object에 관련된 감사추적기록.
User_Audit_session : cataudit.sql로 생성. user의 연결/종료에 관련된 감사추적기록.
User_Audit_statement : cataudit.sql로 생성. user에 의해 실행된 GRANT,REVOKE,
AUDIT, NOAUDIT, ALTER SYSTEM 명령에 대한 감사추적기록.
User_Audit_trail : user와 관련된 전반적인 사항의 감사추적기록.
User_catalog : user 소유의 table, views, synonyms, sequences 의 이름과 type.
User_clusters : user소유의 cluster.
User_clu_columns : user table 의 칼럼과 cluster칼럼과의 매핑테이블.
User_col_comments : user 의 table, view의 칼럼에 대한 주석.
User_col_privs : user 가 소유한, 부여한, 부여받은 칼럼에 대한 권한.
User_col_privs_made : user 소유 object의 칼럼에 대한 권한.
User_col_privs_recd : user가 부여받은 칼럼에 대한 권한.
User_coll_types : user가 명명한 collection type정보.
User_constraints : user소유 테이블의 제약조건정의.
User_cons_columns : user소유 제약조건에 정의된 칼럼에 대한정보.
User_db_links : user소유 데이터베이스링크에 대한정보.
User_dependencies : user소유 object에 대한 dependencies.
User_errors : user소유 저장 object에 대한 현재의 에러.
User_extents : user소유 object에 속하는 세그먼트의 extent 정보.
User_free_space : user가 access가능한 테이블스페이스내의 free extent 정보.
User_indexes : user 소유의 indexes. Analyze명령을 사용해야함. 병렬서버를 지원.
User_ind_columns : user소유 index 또는 user소유 table 의 칼럼정보.
User_ind_partitions : user소유의 index partition각각에 대한설명과, partition정보,
partition의 storage 매개변수, Analyze명령으로 결정된 여러partition통계
User_jobs : user소유의 모든 job.(export/import!, execution)
User_libraries : user소유의 모든 libraries .
User_lobs : user소유의 table에포함된 LOBs정보.
internal LOBs( BLOBs, NCLOBs) 만해당, external LOBs(i.e, BFILES)은 아님.
User_method_params : user type의 method 매개변수.
User_method_results : user type의 method 의 results.
User_nested_tables : user소유 테이블에 포함된 nested tables.
User_object_tables : user가 사용가능한 object table.
User_objects : user소유의 object.(index partition, table partition, package,
packagebody, trigger)
User_object_size : user소유의 PL/SQL object.
User_obj_audit_opts : cataudit.sql로 생성. user소유의 table,view에 대한 감사option
User_part_col_statistics : user소유의 tablepartition정보에 대한 칼럼통계와 그래프정보.
User_part_histograms : user가 access할수있는 table partition의 histogram에 대한
그래프데이터(end-pointer).
User_part_key_columns : user소유의 partition object의 partition key칼럼에 대한정보.
User_part_indexes : 모든 user소유의 partition index의 partition정보.
User_part_tables : user소유의 partition table에 대한 object 레벨의 partition정보.
User_password_limits : user에게 적용된 password profile parameter.
User_queue_tables : user소유 스키마에 생성된 queue table내부의 queues정보.
User_Queues : user스키마의 모든 queue에 대한 동작 특성을 나타냄.
User_refresh : 모든 refresh group.
User_refresh_children : user가 소유한 refresh group 내부의 object에 관한정보.
User_refs : user소유테이블의 object type칼럼중 REF칼럼, REF속성.
User_resource_limits : 현재 user의 resource 한계.
User_role_privs : user에게 부여된 roles.
User_segments : user오브젝트에 포함된 데이터베이스 segments의 storage할당정보.
User_sequences : user 소유의 sequences.
User_snapshots : user 가 볼수있는 snapshots.
User_snapshot_logs : user 소유의 모든 snapshot logs.
User_source : user소유 저장 objects 의 모든 text source.
User_snapshot_refresh_times : snapshot refresh time.
User_synonyms : user소유의 synonym.
User_sys_privs : user에게 부여된 system 권한.
User_tab_col_statistics : user_tab_columns view에 대한 칼럼통계와
그래프정보를 나타냄.
User_tab_columns : user소유의 table, view, cluster의 칼럼정보.(Analyze명령사용)
User_tab_comments : user소유의 table, view에 대한 주석.
User_tab_histograms : user소유 table의 칼럼에 대한 histogram.
User_tab_partitions : user소유 table partition에 대한, partition 레벨의 분할정보와,
partition의 storage매개변수, Analyze에 의해 집계된 여러통계정보.
User_tab_privs : user가 소유한, 부여한, 부여받은 object에 대한 권한 정보.
User_tab_privs_made : user가 소유한 object에 관한 모든 권한.
User_tab_privs_recd : user가 부여받은 object 권한정보.
User_tables : user소유의 relational table에 대한 정보. (Analyze명령사용)
User_tablespaces : user가 access 가능한 tablespaces에 대한 설명.
User_triggers : user가 소유한 triggers 정보.
User_trigger_cols : user가 소유한 또는 user테이블에 있는 trigger안의 column 정보.
User_ts_quotas : user에게 할당된 tablespace quotas 정보.
User_types : 테이블안의 user소유의 type.
User_type_attrs : user type의 속성을 나타냄.
User_type_methods : user type의 methods를 나타냄.
User_updatable_columns : join view에서 사용자에게 update가 허용된 칼럼정보.
User_users : 현재 user에 관한 정보.
User_views : user 소유의 view에 대한 text.
FILEXT$ : 데이터파일의 AUTOEXTEND를 ON으로 변경했을 때 처음 생성.
V$ACCESS : 현재 데이터베이스내의 lock이걸린 object와 그 object를
access 하려는 session id.
V$ACTIVE_INSTANCES : 현재 데이터베이스내의 Mount된
모든 인스턴스에대하여 인스턴스 이름과, 번호를 매치.
V$AQ : 데이터베이스내의 모든 Queue에 대한 통계.
V$ARCHIVE : Archive에 필요한 redo log file에 대한 정보.
각각의 행은 하나의 thread에 대한 정보이다. V$LOG도 동일한정보.
V$ARCHIVE_DEST : 현재의 instance에서, 모든 archive log destination,
현재값, mode, status.
V$ARCHIVED_LOG : archive log 이름을 포함하는 controlfile에 대한 archive log 정보,
archive log 기록은 online중 redo log가 성공적으로 저장되었거나,
clear(log가 clear되면, name칼럼은 null이 된다)된후 insert된다.
V$BACKUP : 모든 online 데이터파일의 backup 상태를 나타낸다.
V$BACKUP_CORRUPTION : 데이터파일의 backup 중 에러정보를 나타낸다.
에러들은 control 파일과 achived log backup 에 포함되지 않는다.
V$BACK_DATAFILE : control 파일에서 datafile과 controlfile 의 backup정보를 보여줌.
V$BACK_DEVICE : 지원되는 backup 디바이스정보.
V$BACK_PIECE : controlfile에서 backup piece에 대한 정보를 포함.
각각의 backup set 은 하나 또는 그이상의 backup piece로 구성된다.
V$BACKUP_REDOLOG : controlfile에서 backup set의 저장된 log에 대한 정보.
Online redo logs는 곧바로 backup 되지 않는다: 먼저 disk에 저장된후 backup
된다. 저장된 log backup set 은 하나 또는 그이상의 logs들로 구성된다.
V$BACKUP_SET : controlfile에서 backupset 정보를 보여줌.
backup set 행은 backup set이 성공적으로 완료되었을 때 insert된다.
V$BGPROCESS : 백그라운드 프로세스 정보.
V$BH : 병렬서버 view이다.
SGA내의 모든 버퍼에 대한 ping의 상태와 수를 나타낸다.
V$BUFFER_POOL : 인스턴스내에서 사용가능한 모든 버퍼풀에 대한정보.
V$CACHE : 병렬서버 view이다.
특정데이타베이스object에 관련된 현재의 인스턴스의
SGA내부의 각각의 block에 대한 block header에 대한 정보.
V$CACHE_LOCK : 병렬서버view. platform-specific lock manager 식별자를 제외하면,
V$CACHE와 유사하다.
V$CIRCUIT : 가상 circuit에 관한 정보이며, 가상circuit란 dispatcher와 server를
통한 데이터베이스와의 user 연결을 말한다.
V$CLASS_PING : 각각blockclass마다 ping된 블록의 수를나타낸다.
다른class블록의 충돌을 비교하기위해 사용.
V$COMPATIBILITY : 이전버전으로 downgrade를 방지하기위해
데이터베이스인스턴스에 의해 사용된특성들을 설명.
다른 인스턴스가 갖고있는 특성에 영향을 미치지 않으며,
데이터베이스가 완전히 정지한이후에도 존재하지 않는 일시적인
비호환성들을 포함할수도 있다.
V$COMPATSEG : 이전버전으로 되돌아가는 것을 막기위한 데이터베이스에서
사용되는 영구적인 특성들.
V$CONTROLFILE : 컨트롤파일의 이름과 상태.
V$CONTROLFILE_RECORD_SECTION : 컨트롤파일의 record에 대한 정보.
V$COPY_CORRUPTION : 컨트롤파일로부터 데이터파일의 복사불량에 대한 정보.
V$CURRENT_BUCKET : 캐쉬내의 버퍼의 수가 감소할때 발생할 수 있는
캐쉬손실의 경우수를 예상하는데 유용.
V$DATABASE : control file 로부터 데이터베이스정보를 포함.
V$DATAFILE : 컨트롤파일로부터데이타파일에대한 정보를 포함.
V$DATAFILE_COPY :컨트롤파일로부터 데이터파일의 복사에 대한 정보를포함.
V$DATAFILE_HEADER : 데이터파일헤더에 대한 정보.
V$DBFILE : 데이터베이스를 구성하는 모든 데이터파일.
대신에 V$DATAFILE 추천한다.
V$DBLINK : 세션에 의해 open된 데이터베이스링크에 대한 설명.
이 데이터베이스링크들은 닫히기전에 commit되거나 rollback되어야만 한다.
V$DB_OBJECT_CACHE : library cache에 cach된 데이터베이스오브젝트를 나타냄.
V$DB_PIPES : 데이터베이스내에 현재 운영중인 pipe에 대한 설명.
V$DELETED_OBJECT : 삭제된 archived 로그, 데이터파일 copy,
컨트롤파일에서 백업piece 에 대한 정보. 이뷰의 목적은 복구목록의
재동조작업을 최적화하는 것이다. archived 로그나, 데이터파일 copy,
백업piece 등이 삭제될때는 해당하는 행이삭제되었음이 표시된다.
V$DISPATCHER : dispatcher 프로세스에 관한 정보.
V$DISPATCHER_RATE : dispatcher 프로세서에 관련된 확률통계.
V$DLM_CONVERT_LOCAL : lock 변환작업에 대한 경과시간.
V$DLM_CONVERT_REMOTE : 원격 lock변환작업에 대한 경과시간.
V$DLM_LATCH : DLM 잠금에 대한 통계.
각각의 잠금에 대한 통계보다는, 각 타입에 대한 총계를 포함.
개념적으로 IMM_GETS/TTL_GETS 값은 1에 가깝게 된다.
V$DLM_LOCKS : 병렬서버 view이다. 블록화되었거나, 다른 것을
블록화하고있는 lock manager에 알려진 모든 lock에 대한 정보.
V$DML_MISC : 잡다한 DLM 통계에 대한 정보.
V$ENABLEDPRIVS:사용가능한 권한에 대한정보, 이들권한은
SYS.SYSTEM_PRIVILEGES_MAP테이블에 존재해야만 한다.
V$ENQUEUE_LOCK : 큐에 대기상태인 오브젝트에의해 소유된 모든 lock이
view의 칼럼은 V$LOCK의 칼럼과 동일하다.
자세한 것은 V$LOCK을 참고.
V$EVENT_NAME : wait event 에 대한 정보.
V$EXECUTION : 병렬 질의 실행에 대한 정보.
V$EXECUTION_LOCATION : 병렬 질의 실행 트리의 위치에 대한 자세한 정보.
V$FALSE_PING : 병렬서버view. ping에 실패지도 모르는 버퍼에 대한 정보.
즉, 10회이상ping된 다른 버퍼와
동일한 lock으로 잠겨있는 버퍼를 말한다.
ping이 실패로 판명된 버퍼는 lock충돌을 감소시키기위해
1-44페이지의 "GC_FILES_TO_LOCK"에 다시 매핑된다.
V$FILE_PING : 데이터파일마다 ping된 블록수를 보여줌. 이정보는 현존하는
데이터파일에 대한 access패턴을 결정하는데 and,
데이터파일블록을 PCM lock에 새로 매핑하는것을 결정하는데 사용된다.
V$FILESTAT : 파일 read/write 통계.
V$FIXED_TABLE : 데이터베이스내의 모든 동적실행테이블, views, 유도테이블.
실제테이블을 참조하는 약간의 V$테이블은 리스트에 없다.
V$FIXED_VIEW_DEFINITION : (V$로 시작하는)고정view에 대한 설명.
유의해서 사용해야한다.
V$GLOBAL_TRANSACTION : 현재 활동중인 트랜잭션에 대한 설명.
V$INDEXED_FIXED_COLUMN : index된 동적실행테이블(X$ table)의 칼럼에
대한 설명. X$ table은 경고없이 변경할수있다.
이view는 보다 효과적으로 고정뷰(V$view)에 대한
V$INSTANCE : 현재의 인스턴스의 상태를 나타냄.
V$INSTANCE의 버전은 V$INSTANCE의 초기버전과 호환성이 없다.
V$LATCH : 하위 잠금에 대한 통계와 상위 잠금에 대한 요약통계.
즉, 상위잠금에 대한 통계는 그 하위잠금에 대한 각각의 통계를 포함한다.
V$LATCHHOLDER : 현재잠금에 대한 정보.
V$LATCHNAME : V$LATCH 에 있는 잠금에 대한 디코드된 잠금이름에 대한
정보. V$LATCHNAME의 행들은 V$LATCH의 행들과 1:1로 대응된다.
V$LATCH_CHILDREN : 하위잠금에 대한 통계를 포함.
V$LATCH의 칼럼에 child# 칼럼이추가되었다. LATCH#칼럼이 서로
동일하다면, 하위잠금이 동일한 상위잠금을 갖는 것이다.
V$LATCH_MISSES : 잠금을 획득하는데 실패한 시도에 대한 통계.
V$LATCH_PARENT : 상위잠금에 대한 통계.
V$LATCH_PARENT 칼럼은 V$LATCH칼럼과 동일하다.
V$LIBRARYCACHE : library cache의 실행과 활동통계.
V$LICENSE : license 한계에 대한 정보.
V$LOADCSTAT : 직접적재하는동안 컴파일된 SQL*loader 통계정보.
이테이블에대한 어떤 Select 문도 "no rows returned" 결과가 나오는데,
왜냐면, 동일한 시간에 데이터를 적재하면서, 쿼리를 날릴수 없기 때문이다.
V$LOCK : 현재 Oracle 서버에 의해 확립된 잠금에 대한 정보나 lock또는
latch에 대한 두드러진요청
V$LOCK_ACTIVITY : 병렬서버view이다. V$LOCK_ACTIVITY는 현재의
인스턴스의 DLM잠금동작을 나타낸다.
각각의 행은 잠금동작의 타입과 일치된다.
V$LOCK_ELEMENT : 병렬서버view이다. 버퍼캐쉬에 의해사용된 각각의
PCM잠금에 대해 v$LOCK_ELEMENT 에 한행이다.
잠금요소에 대응되는 PCM잠금의 이름은 'BL',indx,class등이다.
V$LOCKED_OBJECT : 시스템안의 모든 트랜잭션에 걸린 잠금을 나타낸다.
V$LOCKED_WITH_COLLISIONS : 병렬서버view이다.
여러버퍼를 보호하는 lock을 찾는데 사용되며, 그 버퍼들은 최소한
10회이상 각각 강제로 쓰여지거나, 강제로 읽혀진 버퍼들이다.
V$LOG : 컨트롤파일로부터 log 파일정보를 포함한다.
V$LOGFILE : redo log 파일정보. redo log 그룹과 멤버 파일명.
V$LOGHIST : 컨트롤파일로부터 log history정보를 포함. 지속적인 호환성을
포함하고 있다. 대신에 V$LOG_HISTORY의 사용을 권장한다.
V$LOG_HISTORY : 컨트롤파일로부터 log history 정보를 포함한다.
V$MLS_PARAMETERS : Oracle Server의 확정된 초기화파라미터를 나타냄.
V$MTS : multi-threaded server의 성능향상을위한 정보를 포함.
V$MYSTAT : 현재 세션에 대한 통계값포함.
V$NLS_PARAMETERS : 현재의 NLS 매개변수의 값들을 포함.
V$NLS_VALID_VALUES : 유효한 NLS 매개변수값.
V$OBJECT_DEPENDENCY : 현재 공유풀에 적재되어있는 package, procedure,
cursor등에 관련되어있는 object를 결정하는데 사용된다.
예를들면, V$SESSION, V$SQL등과 조인하면, 현재 어떤 user가
실행중인 SQL문에서 어떤 테이블이 사용되었는지를 알아낼수가 있다.
V$OFFLINE_RANGE : 컨트롤파일로부터 offline된 datafile을 보여준다.
DATAFILE행에 저장되어있는 각각의 데이터파일의 최종offline 간격을
보여줌. offline 간격은 테이블스페이스가 처음 offline normal,
또는 Read Only로 변경되고난이후 다시 online 또는 read-write로
변경된다음에 확정된다.
데이터파일이 스스로 Offline로 변경되거나 테이블스페이스가
OFFLINE IMMEDIATE로 변경되면, offline간격은 확정되지 않는다.
V$OPEN_CURSOR : 각각 user 세션이 열렸있거나, 정지되어있는 cursor를 보여준다.
V$OPTION : Oracle Server와 같이 설치된 선택사항들.
V$PARAMETER : 초기화 파라미터에 대한 설명이다.
V$PING : 병렬서버view이다.
최소한 1번이상 ping된 블록만을 보여준다는 것을 제외하고 V$CACHE view와
동일하다.특정 데이터베이스 object와 관련된 현재의 인스턴스내의 SGA에
있는 각각의 블록에대한 block header정보를 포함하고 있다.
V$PQ_SESSTAT : 병렬쿼리에 대한 session 통계를 포함.
V$PQ_SLAVE : 인스턴스내에 실행중인 parallel 쿼리서버에 대한 통계.
V$PQ_SYSSTAT : 병렬쿼리에 대한 시스템통계.
V$PQ_TQSTAT : 병렬쿼리 동작의 통계를 포함. 통계는 질의가 완료된후에
컴파일되며 세션이 살아있는동안 계속 남아있는다.
V$PROCESS : 현재 작업중인 프로세스에 대한 정보.
LATCHWAIT 칼럼은 프로세스잠금이 무엇을 기다려야하는가를 나타내며,
LATCHSPIN 칼럼은 프로세스잠금이 동작되는 것을 나타낸다.
멀티프로세서의 경우 Oracle 프로세스는 잠금을 기다리기전에 실시한다.
V$PWFILE_USERS : password 파일로부터 유도해낸
SYSDBA, SYSOPER 권한을 부여받은 user.
V$QUEUE : 멀티쓰레드 메시지큐에 대한 정보.
V$RECENT_BUCKET : 대용량 캐쉬실행을 평가하기에 유용한 정보.
V$RECOVER_FILE : media 복구에필요한 파일의 상태를 나타냄.
V$RECOVERY_FILE_STATUS : 각각의 RECOVER명령에 대한 각 데이터파일에
대한 정보를 한행씩 포함.
Oracle프로세스가 복구를 수행하는데 유용한 정보임.
recover manager는 서버프로세스에 직접 복구를수행하도록 했을 때,
recovery manager가 이 view에서 관련된정보를 참고할 수 있다.
다른user들에게는 유용하지 않다.
V$RECOVERY_LOG : 완벽한 media복구에 필요한 archived logs에 관한 정보.
이정보는 log history view인 V$LOG_HISTORY에서 유도된 것이다.
V$RECOVERY_PROGRESS : 데이터베이스복구작업이 중간에 멈추지않도록하는데
사용되며, 복구작업을 완료하는데 요구되는 시간을 측정하는데 사용된다.
V$RECOVERY_STATUS : 현재의 복구진행상태를 나타낸다. 단지 복구를 수행하는
Process 에대한 정보만이유용하다. 복구관리자가 서버프로세스에게 복구를
수행하라고 지시할때에, 복구관리자는 이view에서
관련정보를 참조할 수 있다. 다른 user에게는 불필요하다.
V$REQDIST : MTS dispatcher의 응답시간에 대한 그래프통계를 나타내며,
time range는 버킷 number의 지수함수로 증가한다.
V$RESOURCE : 자원(resource)의 이름과 주소정보를 포함.
V$RESOURCE_LIMIT : System 자원의 부분적인 사용에 대한 정보. 자원의
소비를 모니터링함으로서 낭비를 방지하는데 사용된다.
V$ROLLNAME : 모든 online중인 rollback segments의 이름.
데이터베이스가 open시에만 조회가능.
V$ROLLSTAT : 롤백세그먼트통계정보.
V$ROWCACHE : 자료사전활동에 대한 통계.
각각의 행은 하나의 자료사전cache 통계를 포함.
V$SESSION : 현재 open된 세션에 대한 정보.
V$SESSION_CONNECT_INFO : 현재의 세션에 대한 network 연결에 대한 정보.
V$SESSION_CURSOR_CACHE : 현재의 세션에 대한 cursor 사용에 대한 정보.
SESSION_CACHED_CURSORS 초기화파라미터에 대한 효율을 측정하지는
않는다.
V$SESSION_EVENT : 세션의 event 대기에 관한정보.
V$SESSION_LONGOPS : 장시간실행되는 작업에 대한 상태. SOFAR,
TOTALWORK칼럼은 진행상태를 제공한다. 예를들어
다음요소(hach cluster creations, backup, recovery) 에 대한
작동상태를 모니터링할 수 있다.
V$SESSION_OBJECT_CACHE : 로칼서버의 현재사용중인
user세션의 object, cache통계정보.
V$SESSION_WAIT : 활동중인 세션이 대기하고있는 자원또는 이벤트이다.
V$SESSTAT : user세션 통계이다. 통계number(statistic#)에 해당하는
통계name을 찾으려면, V$STATNAME를 참고하면 된다.
V$SESS_IO : 각각의 user세션에 대한 I/O 통계이다.
V$SGA : System Global Area 에대한 간략한 정보.(name, size)
V$SGASTAT : System Global Area에 대한 자세한 정보.(name, bytes, pool)
V$SHARED_POOL_RESERVED : Shared Pool내에 예약풀과 공간을
바꾸고자할 때 도움이 되는통계.
V$SHARED_SERVER : Shared Server processes 에 대한 정보를 포함.
V$SORT_SEGMENT : 주어진 인스턴스내의 각 sort세그먼트에 대한 정보.
테이블스페이스가 Temporary 타입일때만 update된다.
V$SORT_USAGE : sort 사용에 대해 기술한다.
V$SQL : Group by절이없는 공유sql영역에대한 통계이며 입력된
원래 sql문장의 각 child의 row를 포함.
V$SQL_BIND_DATA : 데이터가 이 서버에서 추출가능하다면 이 view를
조회하는 세션에 소유된 각 커서안에 있는 각각의 원격bind변수에 대한
클라이언트에 의해 보내진 데이터.
V$SQL_BIND_METADATA : 이view를 조회하는 세션에 소유된 각커서안에 있는
각각의 원격bind변수에 대해 클라이언트에의해 제공되는 bind metadata.
V$SQL_CURSOR : 이 view를 조회하는 세션과 관련된 각 cursor에 대한 디버깅정보.
V$SQL_SHARED_MEMORY : 메모리 스냅샷에 공유된 커서에 대한 정보.
공유풀에 저장된 각SQL문은 관련된 하나또는 그이상의 하위object를
가지고 있다.
V$SQLAREA : 공유SQL영역에 대한 통계를 가지고있으며, Sql 문자열마다
한행을 포함한다. 메모리내에 존재하는, parse된, 실행을 대기하고있는
SQL문장에 대한 통계를 제공한다.
V$SQLTEXT : SGA내부의 공유SQL 커서에 속해있는 SQL문장을 포함.
V$SQLTEXT_WITH_NEWLINES : 가독성이 증가되고, 공백을 포함한 SQL문장안에
newline과 tabs을 대체하지 않는다는 것을 제외하고는 V$SQLTEXT view와
동일하다.
V$STATNAME : V$SESSTAT와 V$SYSSTAT테이블에서 나타난 statistics에 대한 이름.
V$SUBCACHE : 현재 라이브러리 캐쉬메모리에 적재된 하위 캐쉬에 대한 정보.
모든 라이브러리캐쉬에 대해 언급하고있으며, 각 라이브러리 캐쉬object마다
각 적재된 하위 캐쉬에 대해 한행을 나타낸다.
V$SYSSTAT : 시스템 통계이다. 각 statistic number(statistic#)와 관련된 statistic의
이름을 찾기위해서는, "V$STATNAME"를 보시오.
V$SYSTEM_CURSOR_CACHE : 시스템 전반적인정보라는 것을 제외하고,
V$SESSION_CURSOR_CACHE와 유사한 정보를 나타낸다.
V$SYSTEM_EVENT : 이벤트에 대한 총 wait정보. TIME_WAITED,
AVERAGE_WAIT칼럼은 급속메커니즘을 지원하지 않는 플랫폼에서
0값을 포함할 것이다. 이런 플랫폼에서 DB를 운영중이고,
이칼럼이 wait time을 줄여주기를 원한다면, 파라미터파일의
TIMED_STATISTICS를 TRUE로 세팅하면된다.
단지 이렇게 하면, 시스템 성능에 약간의 마이너스효과를 가져올 것이다.
V$SYSTEM_PARAMETER : System parameter에 대한 정보.
V$TABLESPACE : 컨트롤파일로부터 테이블스페이스 정보를 나타내준다.
V$THREAD : 컨트롤파일로부터 thread 정보를 가져온다.
V$TIMER : 1/100 초로 나타낸 경과시간. 시간은 epoch가 시작된이후부터
측정되며, epoch는 OS의 특성이며, 값이 4bytes(약 497일)를 넘을때마다
0근처의 값이 된다.
V$TRANSACTION : 시스템내의 활동중인 트랜잭션.
V$TRANSACTION_ENQUEUE : 트랜잭션 오브젝트에 의해 소유된 lock를 나타냄.
V$TYPE_SIZE : 데이터블록용량을 측정하는데 사용되는 여러
데이터베이스컴포넌트들의 SiZe.
V$VERSION : Oracle Server의 core 라이브러리 컴포넌트의 Version수이다.
각 컴포넌트에 한 row가 있다.
V$WAITSTAT : 블록점유에 대한 통계. 통계가 사용가능한 시간에만 갱신된다.
Defining the Table: Oracle and MySql
create table MyPictures (
id INT PRIMARY KEY,
name VARCHAR(0),
photo BLOB
);
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import oracle.jdbc.OracleResultSet;
public class Main {
public static void main(String[] args) throws Exception {
Connection conn = getOracleConnection();
int rows = 0;
FileInputStream fin = null;
OutputStream out = null;
ResultSet rs = null;
Statement stmt = null;
oracle.sql.BLOB photo = null;
conn.setAutoCommit(false);
stmt = conn.createStatement();
String id = "001";
String binaryFileName = "fileName.dat";
rows = stmt.executeUpdate("insert into my_pictures(id, photo ) values ('" + id
+ "', empty_blob() )");
System.out.println(rows + " rows inserted");
rs = stmt.executeQuery("select photo from my_pictures where id = '" + id
+ "' for update nowait");
rs.next();
photo = ((OracleResultSet) rs).getBLOB(1);
fin = new FileInputStream(new File(binaryFileName));
out = photo.getBinaryOutputStream();
// Get the optimal buffer size from the BLOB
byte[] buffer = new byte[photo.getBufferSize()];
int length = 0;
while ((length = fin.read(buffer)) != -1) {
out.write(buffer, 0, length);
}
conn.commit();
out.close();
fin.close();
rs.close();
stmt.close();
conn.close();
}
private static Connection getHSQLConnection() throws Exception {
Class.forName("org.hsqldb.jdbcDriver");
System.out.println("Driver Loaded.");
String url = "jdbc:hsqldb:data/tutorial";
return DriverManager.getConnection(url, "sa", "");
}
public static Connection getMySqlConnection() throws Exception {
String driver = "org.gjt.mm.mysql.Driver";
String url = "jdbc:mysql://localhost/demo2s";
String username = "oost";
String password = "oost";
Class.forName(driver);
Connection conn = DriverManager.getConnection(url, username, password);
return conn;
}
public static Connection getOracleConnection() throws Exception {
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@localhost:1521:databaseName";
String username = "userName";
String password = "password";
Class.forName(driver); // load Oracle driver
Connection conn = DriverManager.getConnection(url, username, password);
return conn;
}
}
import java.sql.DriverManager;
import java.sql.Statement;
public class Main {
public static void main(String[] args) throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:@localhost:1521:javaDemo";
String username = "username";
String password = "welcome";
String sql = "CREATE TABLE books (id NUMBER(11), title VARCHAR2(64))";
Connection connection = DriverManager.getConnection(url, username, password);
Statement statement = connection.createStatement();
statement.execute(sql);
connection.close();
}
}
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DemoResultSetOracle {
public static Connection getConnection() throws Exception {
String driver = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@localhost:1521:databaseName";
String username = "username";
String password = "password";
Class.forName(driver); // load Oracle driver
Connection conn = DriverManager.getConnection(url, username, password);
return conn;
}
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = getConnection();
System.out.println("conn=" + conn);
// prepare query
String query = "select id, name, age from employees";
// create a statement
stmt = conn.createStatement();
// execute query and return result as a ResultSet
rs = stmt.executeQuery(query);
// extract data from the ResultSet
while (rs.next()) {
String id = rs.getString(1);
String name = rs.getString(2);
int age = rs.getInt(3);
System.out.println("id=" + id);
System.out.println("name=" + name);
System.out.println("age=" + age);
System.out.println("---------------");
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
} finally {
// release database resources
try {
rs.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}