레이블이 design pattern인 게시물을 표시합니다. 모든 게시물 표시
레이블이 design pattern인 게시물을 표시합니다. 모든 게시물 표시

2013년 10월 13일 일요일

[자바상속컴포지션]Java Inheritance & Composition 상속과 컴포지션

[자바상속컴포지션]Java Inheritance & Composition

상속과 컴포지션은 동전의 양면과 같이 유사하게 서로에게 관련이 있다. 
상속은 마치 양파가 여러 껍질로 이루어진 것과 같이 계층화된 객체
컴포지션은 여러 재료(객체)가 한데 뭉쳐서 만들어진 죽
컴포지션은 개체들간의 'has a' 관계, 상속은 ‘is a’관계
상속과 컴포지션은 상호 배타적이지 않으며 개발자는 이 둘을 같이 사용한다.
다음 예제는 ‘is a’와 ‘has a’의 착각에는 나오게 되는 실수이다.

1. 원은 반지름 값을 갖는 하나의 점이다(a Circle is a Point with a radius.)
   그래서 Circle은 Point를 상속

   
   
class Point {
 private double x, y;
 Point(double x, double y) {
  this.x = x;
  this.y = y;
 }
 double getX() {
  return x;
 }
 double getY() {
  return y;
 }
}
class Circle extends Point {
 private double radius;
 Circle(double x, double y, double radius) {
  super(x, y);
  this.radius = radius;
 }
 double getRadius() {
  return radius;
 }
}
 
2. 원은 한 점과 반지름을 가지고 있다(a circle has a point and a radius)
 
class Point {
 private double x, y;
 Point(double x, double y) {
  this.x = x;
  this.y = y;
 }
 //redundant code 로 인한 유지보수 어려움(코드의 재사용 실패)
 double getX() {
  return x;
 }
 double getY() {
  return y;
 }
}
 
class Circle {
 private Point p;
 private double radius;
 Circle(double x, double y, double radius) {
  p = new Point(x, y);
  this.radius = radius;
 }
 double getX() {
  return p.getX();
 }
 double getY() {
  return p.getY();
 }
 double getRadius() {
  return radius;
 }
}

오라클자바커뮤니티에서 설립한 개발자교육6년차 오엔제이프로그래밍 실무교육센터(오라클SQL,튜닝,힌트,자바프레임워크,안드로이드,아이폰,닷넷 실무개발강의)  

[개강확정강좌]오라클자바커뮤니티에서 운영하는 개발자 전문교육 ,개인80%환급(www.onjprogramming.co.kr)




2013년 8월 9일 금요일

[ORACLEJAVA커뮤니티 .NET교육, JAVA교육]닷넷(C#)으로 만든 주소록 예제

닷넷 주소록은 Visual Studio .Net 에서 작성하시면 되구요 ... 대충 보시면 이해가 되겠지만 ADO.Net을 사용한 예제이며 DB는 오라클을 사용 했습니다.
(주소에 대한 입력/수정/삭제 가능하구요, 검색도 되는 멋진 주소록 입니다.)

Oracle의 Scott에 아래의 주소록 테이블을 만드신 후 실습 바랍니다.
/*
*
* 실습용 Table script
create table AddrBook (
name varchar2(20) not null primary key,
sex varchar2(2) not null constraint ck_sex check (sex in ('M','F')),
addr varchar2(50),
tel varchar2(20) not null
)
*
* */

오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  



--------------------------------------------------------------------
Visual Studio .Net을 실행 하신 후 C#, Window 응용 프로그램을 선택, 프로젝트 이름은 주소록으로 주시기 바랍니다.

AddrBook.cs와 CodeFile1.cs 두개의 파일을 만들어 주시면 됩니다. CodeFile1은 AddrBook.cs에서 DB 처리 부분을 탇게될 라이브러리 형태 입니다. AddrBook.cs 파일을 만들려면 새프로젝트가 시작된 상태에서 우측의 솔루션 탐색기에서 주소록에서 마우스 우측 버튼을 눌러 추가 --> 구성요소 추가 --> 새항목 추가 --> 윈도우 폼을 하시고 CodeFile1.cs의 경우 CodeFile 로 하자구요~

우선 아래의 AddrBook.cs를 다 입력하고 나면 저절로 디자인 화면에 아래처럼 디자인된 화면이 나타날겁니다. 물론 실제 개발하면 대부분의 GUI 프로그램 처럼 먼저 디자인을 하고 나중에 필요한 스크립트를 추가하는 형태가 되겠죠...

-------------------------
1. AddrBook.cs
-------------------------
using System;
using System.Data.OleDb;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace medical
{
///

/// CDJohap에 대한 요약 설명입니다.
///

public class AddrBook : System.Windows.Forms.Form
{
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.ListView listView1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.ColumnHeader Gubun;
private System.Windows.Forms.ColumnHeader JohapCd;
private System.Windows.Forms.ColumnHeader JohapNm;
private System.Windows.Forms.ColumnHeader Bigo;
private System.Windows.Forms.Button btnNew;
private System.Windows.Forms.Button btnInput;
private System.Windows.Forms.Button btnUpdate;
private System.Windows.Forms.Button btnDelete;
private System.Windows.Forms.Button btnSearch;
private System.Windows.Forms.TextBox txtAddr;
private System.Windows.Forms.TextBox txtName;
private System.Windows.Forms.TextBox txtTel;
private System.Windows.Forms.ComboBox comSex;
private System.Windows.Forms.TextBox txtSearchName;
///

/// 필수 디자이너 변수입니다.
///

private System.ComponentModel.Container components = null;

public AddrBook()
{
//
// Windows Form 디자이너 지원에 필요합니다.
//
InitializeComponent();
//
// TODO: InitializeComponent를 호출한 다음 생성자 코드를 추가합니다.
//
}
///

/// 사용 중인 모든 리소스를 정리합니다.
///

protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
///

/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마십시오.
///

private void InitializeComponent()
{
this.Gubun = new System.Windows.Forms.ColumnHeader();
this.JohapCd = new System.Windows.Forms.ColumnHeader();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.btnSearch = new System.Windows.Forms.Button();
this.txtSearchName = new System.Windows.Forms.TextBox();
this.label6 = new System.Windows.Forms.Label();
this.txtAddr = new System.Windows.Forms.TextBox();
this.JohapNm = new System.Windows.Forms.ColumnHeader();
this.listView1 = new System.Windows.Forms.ListView();
this.Bigo = new System.Windows.Forms.ColumnHeader();
this.txtName = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.txtTel = new System.Windows.Forms.TextBox();
this.label4 = new System.Windows.Forms.Label();
this.comSex = new System.Windows.Forms.ComboBox();
this.btnNew = new System.Windows.Forms.Button();
this.btnInput = new System.Windows.Forms.Button();
this.btnUpdate = new System.Windows.Forms.Button();
this.btnDelete = new System.Windows.Forms.Button();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// Gubun
//
this.Gubun.Text = "성별";
this.Gubun.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.Gubun.Width = 100;
//
// JohapCd
//
this.JohapCd.Text = "성명";
this.JohapCd.Width = 80;
//
// groupBox1
//
this.groupBox1.Controls.Add(this.btnSearch);
this.groupBox1.Controls.Add(this.txtSearchName);
this.groupBox1.Location = new System.Drawing.Point(8, 6);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(264, 52);
this.groupBox1.TabIndex = 38;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "사용자 검색창 : 성명";
//
// btnSearch
//
this.btnSearch.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(224)), ((System.Byte)(224)), ((System.Byte)(224)));
this.btnSearch.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnSearch.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnSearch.Font = new System.Drawing.Font("굴림", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.btnSearch.Location = new System.Drawing.Point(176, 16);
this.btnSearch.Name = "btnSearch";
this.btnSearch.Size = new System.Drawing.Size(72, 26);
this.btnSearch.TabIndex = 47;
this.btnSearch.Text = "검색";
this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click);
//
// txtSearchName
//
this.txtSearchName.AutoSize = false;
this.txtSearchName.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.txtSearchName.Font = new System.Drawing.Font("굴림", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.txtSearchName.Location = new System.Drawing.Point(17, 16);
this.txtSearchName.Name = "txtSearchName";
this.txtSearchName.Size = new System.Drawing.Size(160, 26);
this.txtSearchName.TabIndex = 47;
this.txtSearchName.Text = "";
//
// label6
//
this.label6.BackColor = System.Drawing.Color.White;
this.label6.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.label6.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.label6.Location = new System.Drawing.Point(16, 130);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(550, 2);
this.label6.TabIndex = 34;
//
// txtAddr
//
this.txtAddr.AutoSize = false;
this.txtAddr.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.txtAddr.Font = new System.Drawing.Font("굴림", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.txtAddr.Location = new System.Drawing.Point(103, 94);
this.txtAddr.Name = "txtAddr";
this.txtAddr.Size = new System.Drawing.Size(160, 26);
this.txtAddr.TabIndex = 33;
this.txtAddr.Text = "";
//
// JohapNm
//
this.JohapNm.Text = "주소";
this.JohapNm.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.JohapNm.Width = 200;
//
// listView1
//
this.listView1.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(255)), ((System.Byte)(225)));
this.listView1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.JohapCd,
this.Gubun,
this.JohapNm,
this.Bigo});
this.listView1.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.listView1.FullRowSelect = true;
this.listView1.GridLines = true;
this.listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.listView1.Location = new System.Drawing.Point(8, 144);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(568, 368);
this.listView1.TabIndex = 31;
this.listView1.View = System.Windows.Forms.View.Details;
this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged);
//
// Bigo
//
this.Bigo.Text = "전화번호";
this.Bigo.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.Bigo.Width = 175;
//
// txtName
//
this.txtName.AutoSize = false;
this.txtName.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.txtName.Font = new System.Drawing.Font("굴림", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.txtName.Location = new System.Drawing.Point(103, 70);
this.txtName.Name = "txtName";
this.txtName.Size = new System.Drawing.Size(160, 26);
this.txtName.TabIndex = 29;
this.txtName.Text = "";
//
// label3
//
this.label3.BackColor = System.Drawing.SystemColors.Control;
this.label3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.label3.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.label3.Location = new System.Drawing.Point(8, 94);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(96, 26);
this.label3.TabIndex = 28;
this.label3.Text = "주소";
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label2
//
this.label2.BackColor = System.Drawing.SystemColors.Control;
this.label2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.label2.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.label2.Location = new System.Drawing.Point(8, 70);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(96, 26);
this.label2.TabIndex = 27;
this.label2.Text = "성명*";
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// label1
//
this.label1.BackColor = System.Drawing.SystemColors.Control;
this.label1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.label1.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.label1.Location = new System.Drawing.Point(262, 70);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(96, 26);
this.label1.TabIndex = 32;
this.label1.Text = "성별*";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// txtTel
//
this.txtTel.AutoSize = false;
this.txtTel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.txtTel.Font = new System.Drawing.Font("굴림", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.txtTel.Location = new System.Drawing.Point(357, 94);
this.txtTel.Name = "txtTel";
this.txtTel.Size = new System.Drawing.Size(216, 26);
this.txtTel.TabIndex = 39;
this.txtTel.Text = "";
//
// label4
//
this.label4.BackColor = System.Drawing.SystemColors.Control;
this.label4.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.label4.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.label4.Location = new System.Drawing.Point(262, 94);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(96, 26);
this.label4.TabIndex = 40;
this.label4.Text = "전화번호*";
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// comSex
//
this.comSex.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comSex.Font = new System.Drawing.Font("굴림", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.comSex.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.comSex.Location = new System.Drawing.Point(357, 72);
this.comSex.Name = "comSex";
this.comSex.Size = new System.Drawing.Size(216, 23);
this.comSex.TabIndex = 41;
//
// btnNew
//
this.btnNew.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(224)), ((System.Byte)(224)), ((System.Byte)(224)));
this.btnNew.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnNew.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnNew.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.btnNew.Location = new System.Drawing.Point(288, 24);
this.btnNew.Name = "btnNew";
this.btnNew.Size = new System.Drawing.Size(72, 26);
this.btnNew.TabIndex = 43;
this.btnNew.Text = "신규";
this.btnNew.Click += new System.EventHandler(this.btnNew_Click);
//
// btnInput
//
this.btnInput.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(224)), ((System.Byte)(224)), ((System.Byte)(224)));
this.btnInput.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnInput.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnInput.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.btnInput.Location = new System.Drawing.Point(359, 24);
this.btnInput.Name = "btnInput";
this.btnInput.Size = new System.Drawing.Size(72, 26);
this.btnInput.TabIndex = 44;
this.btnInput.Text = "입력";
this.btnInput.Click += new System.EventHandler(this.btnInput_Click);
//
// btnUpdate
//
this.btnUpdate.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(224)), ((System.Byte)(224)), ((System.Byte)(224)));
this.btnUpdate.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnUpdate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnUpdate.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.btnUpdate.Location = new System.Drawing.Point(430, 24);
this.btnUpdate.Name = "btnUpdate";
this.btnUpdate.Size = new System.Drawing.Size(72, 26);
this.btnUpdate.TabIndex = 45;
this.btnUpdate.Text = "수정";
this.btnUpdate.Click += new System.EventHandler(this.btnUpdate_Click);
//
// btnDelete
//
this.btnDelete.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(224)), ((System.Byte)(224)), ((System.Byte)(224)));
this.btnDelete.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnDelete.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btnDelete.Font = new System.Drawing.Font("굴림", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(129)));
this.btnDelete.Location = new System.Drawing.Point(501, 24);
this.btnDelete.Name = "btnDelete";
this.btnDelete.Size = new System.Drawing.Size(72, 26);
this.btnDelete.TabIndex = 46;
this.btnDelete.Text = "삭제";
this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
//
// AddrBook
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(252)), ((System.Byte)(242)), ((System.Byte)(255)));
this.ClientSize = new System.Drawing.Size(584, 516);
this.Controls.Add(this.btnDelete);
this.Controls.Add(this.btnUpdate);
this.Controls.Add(this.btnInput);
this.Controls.Add(this.btnNew);
this.Controls.Add(this.comSex);
this.Controls.Add(this.txtTel);
this.Controls.Add(this.label4);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.label6);
this.Controls.Add(this.txtAddr);
this.Controls.Add(this.listView1);
this.Controls.Add(this.txtName);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Name = "AddrBook";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "주소록";
this.Load += new System.EventHandler(this.CDJohap_Load);
this.groupBox1.ResumeLayout(false);
this.ResumeLayout(false);

}
#endregion
static void Main()
{
Application.Run(new AddrBook());
}
private OleDbConnection LocalConn;
//**************************************************************
//
// ListView에 성명 데이터 전체를 로드하는 함수
//
//
//**************************************************************
private void DataLoad(OleDbDataReader myDataReader)
{
listView1.Items.Clear();
while(myDataReader.Read())
{
ListViewItem myitem1;
string gubun;
if (myDataReader["Sex"].ToString()=="M")
{
gubun = "남자";
}
else
{
gubun = "여자";
}

myitem1 = new ListViewItem(myDataReader["Name"].ToString());
myitem1.SubItems.Add(gubun);
//myitem1.SubItems.Add(myDataReader["Addr"].ToString());
//주소가 null 값을 리턴하면...
if(myDataReader.IsDBNull(2))
{
myitem1.SubItems.Add("");
}
else
{
myitem1.SubItems.Add(myDataReader["Addr"].ToString());
}
//Bigo 가 null 값을 리턴하면...
myitem1.SubItems.Add(myDataReader["Tel"].ToString());

listView1.Items.Add(myitem1);
}
myDataReader.Close();
}

//**************************************************************
//
// 주소록 폼이 로딩 될때 전체 데이터를 ListView에 로딩
// 콤보박스 초기화 작업
//
//**************************************************************
private void CDJohap_Load(object sender, System.EventArgs e)
{
try
{
//--------------------------------------------
LocalConn = Common_DB.DBConnection();
//--------------------------------------------
LocalConn.Open();
OleDbDataReader myReader = Common_DB.DataSelect("select * from AddrBook ",LocalConn);
DataLoad(myReader);

//Combo Box 채우기
comSex.Items.Add("남자");
comSex.Items.Add("여자");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "AddrBook Form Loading");
}
finally
{
LocalConn.Close();
}
}
//**************************************************************
//
// ListView에 마우스를 클릭 했을때 윗부분의 TextBox에 자료 로딩
// 2003.10.20
//
//**************************************************************
private void listView1_SelectedIndexChanged(object sender, System.EventArgs e)
{
try
{
txtName.Text = listView1.SelectedItems[0].SubItems[0].Text;
comSex.Text = listView1.SelectedItems[0].SubItems[1].Text;
txtAddr.Text = listView1.SelectedItems[0].SubItems[2].Text;
txtTel.Text = listView1.SelectedItems[0].SubItems[3].Text;
}
catch(Exception)
{
//MessageBox.Show(ex.Message, "listView1_SelectedIndexChanged");
}
}
//**************************************************************
//
// 신규버튼 클릭시... TextBox부분을 Clear(새로운 데이터 입력을 위한)
//
//
//**************************************************************
private void btnNew_Click(object sender, System.EventArgs e)
{
txtName.Text="";
txtAddr.Text="";
comSex.Text="남자";
txtTel.Text="";
}
//**************************************************************
//
// 입력 버튼 클릭시 DB에 Insert 하는 부분
//
//
//**************************************************************
private void btnInput_Click(object sender, System.EventArgs e)
{
if(txtName.Text==""|| txtTel.Text==""||comSex.Text=="")
{
MessageBox.Show("성명, 성별, 전화번호는 필수 입력사항 입니다.");
txtName.Focus();
return;
}

string gubun;
if (comSex.Text=="남자")
{
gubun="M";
}
else
{
gubun="F";
}
LocalConn.Open();
string myExecuteQuery = "Insert Into AddrBook (Name, Sex, Addr, Tel) values(";
myExecuteQuery += "'" + txtName.Text+"'"+",";
myExecuteQuery += "'" + gubun+"'"+",";
myExecuteQuery += "'"+ txtAddr.Text + "'" + ",";
myExecuteQuery += "'"+ txtTel.Text + "'" + ")";

if (Common_DB.DataManupulation(myExecuteQuery, LocalConn))
{
OleDbDataReader myReader = Common_DB.DataSelect("select * from AddrBook",LocalConn);
DataLoad(myReader);
MessageBox.Show("정상적으로 입력 되었습니다...");
}
LocalConn.Close();
}
//**************************************************************
//
// 수정 버튼 클릭시 DB에 Update 하는 부분
//
//
//**************************************************************
private void btnUpdate_Click(object sender, System.EventArgs e)
{
if(txtName.Text==""|| txtTel.Text==""||comSex.Text=="")
{
MessageBox.Show("성명, 성별, 전화번호는 필수 입력사항 입니다.");
txtName.Focus();
return;
}

string gubun;
if (comSex.Text=="남자")
{
gubun="M";
}
else
{
gubun="F";
}
LocalConn.Open();
string myExecuteQuery = "Update AddrBook set Name='" + txtName.Text + "'" + ",";
myExecuteQuery += " Addr = '" + txtAddr.Text + "'" + ",";
myExecuteQuery += " Sex = '" + gubun + "'" + ",";
myExecuteQuery += " Tel = '" + txtTel.Text + "'" ;
myExecuteQuery += " where Name = " + "'" + txtName.Text + "'";

if (Common_DB.DataManupulation(myExecuteQuery, LocalConn))
{
OleDbDataReader myReader = Common_DB.DataSelect("select * from AddrBook",LocalConn);
DataLoad(myReader);
MessageBox.Show(" 정상적으로 수정 되었습니다...");
}
LocalConn.Close();
}
//**************************************************************
//
// 삭제 버튼클릭시 DB의 자료를 Delete
//
//
//**************************************************************
private void btnDelete_Click(object sender, System.EventArgs e)
{
OleDbDataReader myReader=null;
if(txtName.Text==""|| txtTel.Text==""||comSex.Text=="")
{
MessageBox.Show("성명, 성별, 전화번호는 필수 입력사항 입니다.");
txtName.Focus();
return;
}
//------- 삭제 확인
if (MessageBox.Show ("정말 삭제 하시겠습니까?", "삭제확인",
MessageBoxButtons.YesNo, MessageBoxIcon.Question)
!= DialogResult.Yes)
{
return;
}

LocalConn.Open();
string myExecuteQuery = "Delete AddrBook ";
myExecuteQuery += " where Name = " + "'" + txtName.Text + "'";

if (Common_DB.DataManupulation(myExecuteQuery, LocalConn))
{
myReader = Common_DB.DataSelect("select * from AddrBook",LocalConn);
DataLoad(myReader);
MessageBox.Show(" 정상적으로 삭제 되었습니다...");
}
LocalConn.Close();
}
//**************************************************************
//
// 검색 버튼클릭시 DB의 자료를 검색
//
//
//**************************************************************
private void btnSearch_Click(object sender, System.EventArgs e)
{
OleDbDataReader myReader=null;

LocalConn.Open();
myReader = Common_DB.DataSelect("select * from AddrBook where name like '%"+txtSearchName.Text +"%'",LocalConn);
if (myReader != null)
{
DataLoad(myReader);
myReader.Close();
}
LocalConn.Close();
}
}
}


-------------------------
2. CodeFile1.cs
-------------------------
using System;
using System.Data;
using System.Data.OleDb;
using System.Data.SqlTypes;
using System.Windows.Forms;
public class Common_DB
{
//-----------------------------------------------------------------------------
// DataBase Connection
//-----------------------------------------------------------------------------
public static OleDbConnection DBConnection()
{
OleDbConnection Conn;
//아래는 오라클용 접속 문자열, data source 애는 tnsnames.ora 파일에 있는 Alias명을 넣으면 됩니다.
string ConStr = ("Provider=MSDAORA;data source=\\printserver;User ID=scott;Password=tiger");
Conn = new OleDbConnection(ConStr);
return Conn;
}
//-----------------------------------------------------------------------------
// DataSelect
//-----------------------------------------------------------------------------
public static OleDbDataReader DataSelect(string sql, OleDbConnection Conn)
{
try
{
OleDbCommand myCommand = new OleDbCommand(sql, Conn);
return myCommand.ExecuteReader();
}
catch(Exception ex)
{
//Log File에 출력
MessageBox.Show(sql + "\n" + ex.Message, "DataSelect");
return null;
}
finally
{
}
}
//-----------------------------------------------------------------------------
// DataDelete, DataInsert
//-----------------------------------------------------------------------------
public static bool DataManupulation(string sql, OleDbConnection Conn)
{
try
{
OleDbCommand myCommand = new OleDbCommand(sql, Conn);
myCommand.ExecuteNonQuery();
return true;
}
catch(Exception ex)
{
//Log File에 출력
MessageBox.Show(sql + "\n" + ex.Message, "DataManupulation");
return false;
}
finally
{

}
}
/*
*
* 실습용 Table script
create table AddrBook (
name varchar2(20) not null primary key,
sex varchar2(2) not null constraint ck_sex check (sex in ('M','F')),
addr varchar2(50),
tel varchar2(20) not null
)
*
* */
}



[오라클자바커뮤니티, 닷넷교육, ORACLEJAVANEW.KR]닷넷 어셈블리(.NET Assembly)

오늘은 3일차로서 닷넷 어셉블리의 1부를 학습 하도록 합니다. 조금 어렵게 느낄수 있는데 자바를 하신 분들은 자바 프로그램의 배포를 위한 Jar 파일 포맷을 아실 겁니다. 유사하게 생각 하시면 되구요 닷넷 환경의 프로그램이 배포되는 단위라고 정리하시면 됩니다.~
닷넷 어셈블리 (Assembly)란?

오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  


닷넷에 대해 공부 하시다 보면 닷넷 어셈블리라는 말을 가끔식 보게 되실 겁니다. Low Level 언어인 Assembly는 절대 아니니 착오 없으시기를 바랍니다.어셈블리는 하나의 단일한 단위로 존재 하는 .NET 의 실행 가능한 프로그램 또는 실행 프로그램의 일부 입니다 . 결국 C# 프로그램의 실행 및 배포의 단위라고 할 수 있습니다 . C# 응용 프로그램 작성의 결과로 생긴 .exe 파일이 바로 하나의 어셈블리 이며 클래스 라이브러리 작성의 결과인 DLL(Dynamic Link Library) 도 하나의 어셈블리 입니다 . 하나의 단일한 어셈블리 안의 모든 코드는 하나의 단일한 단위로 빌드 , 배포되며 버전 번호가 부여되는데 각 어셈블리는 다른 프로그램들이 사용 할 수 있는 public class, 속성 , 메소드등을 노출하게 됩니다 . private 으로 선언된 것은 모두 어셈블리 안에 은폐 되는 것 입니다 .

다음은 구성요소 흔히 컴포넌트라고 하는것에 대해 잠시 정리하겠습니다.

MS 는 최초 DLL 을 도입하였는데 DLL 은 코드의 일부를 개별적인 파일로 분리 한 이며 프로그램이 같은 언어로 작성 되었을 때 기본적인 수준에서 동작하는 것 입니다 . 프로그램의 입장에서 자신이 사용하고자 하는 DLL 에 대해 많은 것을 알아야 하며 또한 프로그래머들이 서로의 데이터를 교환하는 용도로 DLL 을 사용 할 수 없습니다 .
데이터 교환의 문제를 해결 하기 위해 개발 된 것이 DDE(Dynamic Data exchange) 로 이것은 한 프로그램에서 다른 프로그램으로 데이터를 전송 하기 위한 형식과 메커니즘을 정의하는데 그리 유연하지는 않습니다 . 그 뒤로 OLE(Object Linkig and Embedding) 등장 하면서 Word 와 같은 문서가 다른 프로그램 (Excel) 을 자신안에 포함 할 수 있게 되었는데 비록 구성요소와 비슷한 개념을 지닌 기술이지만 OLE 1.0 을 진정한 범용적 구성요소로 보기는 어렵습니다 .
MS 최초의 진정한 구성요소의 표준은 1990 년대 중반에 나타난 COM(Component Object Model) 이라고 할 수 있습니다 . OLE 2.0 과 기타 여러 기술들은 COM 으로 통합 되었으며 COM 들이 네트웍 너머로 통신 할 수 있게 하는 DCOM, 다계층 환경에서 구성 요소 사이의 호출에 대해 높은 성능을 보장하는 서비스가 추가된 COM+ 가 등장 했습니다 .
COM 은 잘 동작하는 반면 배우기가 어렵고 사용하기도 어렵습니다 . COM 에서는 구성요소의 정보를 Windows Registry 에 등록해야 하는데 이는 구성요소의 설치와 삭제를 어렵게 하는 요인이 되었습니다 . COM 은 원래 C/C++ 를 위해 설계된 것이며 그 이후 VB 에서도 사용토록 개선 되었고 (“ 자동화 ” 라고 하는 것 ) 실제로 잘 동작 하고 있습니다 . 그 대신 C/C++ 로 VB 와 호환이 되는 구성요소를 만드는 것은 어려워 졌습니다 .( 예를 들어 다른 언어에서 정의된 클래스를 상속하는 것은 여전히 불가능 합니다 .)
또한 사용자가 MS 나 기타 회사들의 DLL 혹은 COM 구성 요소의 여러 버전을 설치하다 보면 문제가 발생 하는데 이는 버전이 다르더라도 DLL 파일의 이름은 동일 한데서 기인하는 것이 많습니다 . 그래서 이미 다른 프로그램에서 사용하는 DLL 을 덮어 씌워 버리는 경우가 자주 나타났으며 또한 시스템에 설치 된 DLL 정보를 관리하는 부담 때문에 구성요소의 업그레이드와 유지 보수가 갈수록 어려워 지는 것 입니다 . 결국 .NET 에서 이러한 문제들을 해결 할 수 있는 새로운 표준이 사용되는 것 입니다 .
다음은 닷넷어셈블리의 자기 서술적인 특징에 대해 알아 보겠습니다.
결국 어셈블리는 자바에서의 배포 단위인 Jar와 비숫하게 생각해 볼 수도 있습니다. Jar 파일에 Menifest 파일이 있어 그속에 JAr 파일의 구조에 대해 정의하고 있는데 이것을 자기 서술(Self Description) 이라고 합니다. 닷넷도 어셈블리 안에 자기서술적인 특징을 가지고 있습니다. 결국 기존의 DLL들 처럼 배포한 후 레지스터리에 등록하여 컴퓨터를 껐다 켜야 인식이 되는 것이 아니라 배포되는 닷넷 어셈블리안에 Self-Descriptiion을 하니까 그럴 필요가 없이 복사만 되면 발로 실행이 가능하다는것이 특징 입니다. 어셈블리에 어떤 것이 있는지가 .NET 어셈블리안에 있으므로 그것을 사용하는 프로그램이나 시스템은 레지스트리와 같은 외부 정보를 참조 할 필요가 없습니다 . 닷넷 어셈블리는 자신이 가지고 있는 개체와 메소드 뿐 아니라 매개변수의 데이터 형식까지 제공 합니다 . 또한 개체들의 버전 정보 , 보안정보도 제공하며 실제로 어셈블리의 설치는 기본적으로 대상 시스템에서 어센블리 파일을 복사하는 것으로도 충분 합니다 . 참고로 한가지 명심할 것은 네임스페이스와 어셈블리가 항상 일대일 대응을 이루는 것은 아니라는 것 입니다 . 예를들어 System.Data.dll 은 System.Data 와 System.Xml 네임스페이스의 일부를 구현하며 System.Xml 의 다른 루틴은 System.Xml.xll 에 구현되어 있습니다 .

다음은 교차 언어 프로그래밍에 대해 정리 하죠

구성요소는 어떠한 .NET 언어에서도 심지어 구성요소를 작성한 언어가 아닌 다른 언어에서도 호출 될 수 있습니다 . 이것 역시 어셈블리가 주는 장점 입니다 . 닷넷은 교차 언어적 프로그래밍을 가능하게 하는 아래와 같은 특징을 가지고 있습니다 .
• Cmmon language Runtime(CLR) : 모든 .NET 어셈블리의 실행을 관리
• Microsoft Intermediate Language(MSIL) : 모든 .NET 언어 컴파일러는 MSIL 을 생산 하며 이는 컴파일러가 생성하는 이진 코드의 표준으로 CLR 은 이 MSIL 코드에 기반하는 것입니다 . MSIL 은 또한 어셈블리의 메타 데이터를 저장 하는 형식을 정의 하는데 이는 어셈블리가 어떤 언어로 만들어 졌든 간에 공통의 형식으로 자신의 메타 데이터를 저장함을 의미 하는 것입니다 .
• Common Language Specification(CLS) : C#, VB, C++ 등 어떠한 닷넷 언어라도 CLS 를 만족 하기만 하면 언어의 경계를 넘어서 구성 요소들을 공유 할 수 있으며 언어의 경계를 넘어서 완전한 상속이 가능 합니다 .
• Common Type System(CTS) : 모든 .NET 언어들이 사용하는 기본 형식들과 자신의 클래스를 정의하는 규칙을 정의 한다 . 예를들면 어떤 언어가 문자열 형식을 비 호환적 방법으로 구현하는 일을 방지한다 . CLS 사양을 따르면 C# 으로 구성 요소를 작성 했을 때 그것을 담은 어셈블리는 VB.NET 같은 언어에서도 사용 될 수 있으며 마찬가지로 C# 은 VB.NET 이나 C++.NET 으로 작성된 구성요소를 사용 할 수 있습니다 . 또한 .NET Framework 에서는 이전에 만들어진 COM 에 대해서도 사용 할 수 있는 방법을 제공 하는데 이는 이전에 작성된 코드를 감싸는 인터페이스 역할을 하는 wrapper assembly 를 통해서 가능 합니다 . VS .NET 은 COM 구성요소에 대한 참조를 추가하면 자동적으로 래퍼 어셈블리를 만듭니다 .
오늘은 3일차로서 다분히 이론적인 내용 이었습니다. 다음 시간은 그림과 함께 닷넷 어셈블리에 대해 조금 더 깊이 살펴 보도록 하겠습니다.
수고하셨습니다.

2013년 8월 8일 목요일

java classpath 클래스패스(ClassPath)란?

-------------
클래스패스
------------- 


오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  



클래스 패스란 말 그대로 클래스를 찾기 의한 경로를 나타내는 말입니다.
여러 디렉토리에 산재한 클래스들의 위치를 지정해서 패키지(Package)에 따라 클래스를 찾게 해 줄 수 있는 경로를 의미 하는 것입니다.

윈도우즈 200인 경우 PC의 바탕 화면에 있는 시스템에서 등록정보, XP인 경우 제어판--> 성능 및 유지 관리 --> 시스템의 등록정보에서 고급 탭의 환경변수에서 환경변수로 지정을 하지 않는다면, 기본적으로 해당 디렉토리(현재 폴더)부터 검색을 하겠지만 작업을 효율적으로 하기 위해서는 클래스패스를 잡아주는 것이 좋습니다. 물론  자바 파일을 컴파일을 할 때마다 –classpath 옵션을 적어주어도 되겠지만 특정한 경로에 필요한 클래스가 모여 있다면 클래스패스를 주는 것이 훨씬 더 효율적 입니다.

클래스패스를 환경변수에서 잡아주게 되면, 그 디렉토리를 기준으로 클래스 파일을 검사하게 되는 것입니다. 예를 들어 C:\class 라고 클래스패스를 잡아주었고 그런다음 C:\java\A.class 라는 파일이 존재하고, C:\java\B.java이 있다고 할때 B.java에서 A라는 클래스를 상속했거나, 객체를 생성하는 코드가 있다(즉 B에서 A를 참조 할때)면 다음과 같이 컴파일할 것 입니다.
C:\java>javac B.java
하지만 이러한 경우에는 에러가 발생 합니다. (클래스패스를 환경 변수에서 잡으면 현재 폴더에서는 클래스를 찾지 않습니다. 물론 환경변수를 지정하지 않은 상태라면 현재 폴더에서 클래스를 찾습니다.) 이유는 C:\classes 아래에서 A.class 을 찾지만 그 곳에는 A.class라는 파일이 없기 때문 입니다.

하지만 클래스패스 환경 변수를 설정 할때 C:\classes;. 로 클래스패스를 잡아주게 되면 ; 앞의 디렉토리를 먼저 검색하고 찾는 파일이 없을경우 .(현재 디렉토리)부터 파일을 검색하게 되는 것이므로 이렇게 클래스패스를 정하게 되면 에러가 없어지게 되는 것 입니다.

클래스패스로 지정한 기준에서 하위 디렉토리가 많아질 경우 파일용량이 커지게 되므로 .jar로 압축하여 놓는 경우도 많이 있습니다.

-----------------------------------------------
Java Launcher의 클래스 찾기(클래스 검색 방식)
-----------------------------------------------
우선 부트스트랩 클래스에서 기본 자바 플랫폼에 있는 API 클래스들을 찾아 메모리에 로딩하며 여기에서 찾지 못할 경우 확장 클래스에서 찾으며 거기에서도 찾지 못한다면 사용자가 정의한 클래스패스에서 클래스를 찾아 메모리에 로딩 합니다.

Bootstrap classes(부트스트랩 클래스) 찾기
- 자바 플랫폼을 구성하는 클래스들이며 rt.jar와 i18n.jar에 포함되어 있는 클래스 입니다.
- jar 압축 파일들은 bootstrap class path에 의해 sun.boot.class.path 시스템 프로퍼티에 저장 됩니다.

extension classes(확장 클래스) 찾기
- 자바 플랫폼을 확장한 클래스들 입니다.
- jre/lib/ext 확장 디렉토리에서 모든 jar 파일들을 자바2 확장 클래스로 가정합니다.

user classes(사용자 클래스) 찾기
- -cp 또는 –classpath 명령행 옵션은 기본 환경 설정과 클래스 패스 환경변수 설정을 재정의 합니다. 즉 명령행에서의 클래스패스를 우선적으로 처리 합니다.
- jar 압축 파일은 다른 환경 설정을 압축 파일 내에 포함 하고 있습니다.

[오라클교육,자바교육,오라클자바커뮤니티]JAVA AWT 배치관리자(Layout Manager)

-----------------------------
배치관리자(Layout Manager)
-----------------------------

오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  



Component가 컨테이너에 배열되는 방식을 결정 합니다.
모든 컨테이너는 기본 Layout Manager를 가집니다.
Container는 다른 Component를 포함할 수 있는 최소의 클래스이고 java.awt.container 클래스를 상속해야 합니다.
Container를 상속하지 않은 일반 Component에는 Layout Manager가 등록될 수 없습니다.
Frame, Window, Panel등은 Layout Manager를 설정할 수 있으며 이렇게 설정된 Layout Manager는 화면의 크기가 바뀌거나, Component가 추가 되거나 제거 되었을 경우에 호출 됩니다.(이경우 즉시 다시 배치하지 않으며 Layout을 다시 그릴 필요가 있다는것을 표시한 후 validate함수가 호출되거나 화면이 다시 그려지는 경우에 다시 배치 작업을 수행 합니다. 따라서 Layout Manager를 설치후 즉시 효과를 볼려면 validate를 호출해야 합니다. Invalidate 함수는 특정 Component가 화면에 다시 배치해야 된다고 표시하는 것 입니다.
Layout Manager를 이용하는 경우에 수동으로 Component를 배치하는것이 소용 없습니다. 화면에 표시 될때 Layout Manager가 다시 위치, 크기등을 결정하기 때문 입니다. 수동으로 Layout을 설정하는 경우엔 위치, 크기등을 정해 주어야 하며 그렇지 않은 경우엔 초기 위치, 쿠기등이 정해지지 않으며 보통 화면에 나타나지 않습니다.
Layout Manager를 이용할 경우 크기지정이 유효한 경우는 Window, Frame등과 같은 최상위 Container 입니다.

수동으로 Component 배치하기
주로 소량의 정보를 보이거나 간단한 사용자 입력을 받는 Container에 사용 됩니다.
컨테이너에 설정해야 하는것들…
- 컨테이너의 크기를 고정 시킵니다.(Frame의 경우 setResizable)
- 컨테이너의 Layout Manager를 null로 한다. setLatout을 이용하며 Frame, Panel과 같은 기본 Layout Manager를 가지기 때문에 반드시 이과정을 수행해야 합니다.
- 컨테이너의 크기를 지정 합니다. (자식 컴포넌트의 크기, 위치를 수동으로 주는 경우 상의 컨테이너의 크기도 수동으로 지정해야 합니다. setSize, setBounds 등이용)

[예제]
import java.awt.*;
public class LayoutNull {
public static void main(String[] args) {
Button btn1, btn2, btn3;
Frame myWindow = new Frame("Null Layout");
myWindow.setResizable(false);
myWindow.setLayout(null);
myWindow.setSize(300, 300);
btn1 = new Button("버튼1"); btn1.setBounds(40,50,50,20);
btn2 = new Button("버튼2"); btn2.setBounds(100,50,50,20);
btn3 = new Button("버튼3"); btn3.setBounds(160,50,50,20);
myWindow.add(btn1); myWindow.add(btn2); myWindow.add(btn3);
myWindow.setVisible(true);
}
}

[결과]


인터페이스 java.awt.LayoutManager
컨테이너를 배치하는 클래스의 인터페이스를 정의 합니다.
addLayoutComponent(String, Component) : 지정된 이름을 가진 지정된 컴포넌트를 배치에 추가
layoutContainer(Container) : 지정된 패널에 컨테이너를 배치
minimumLayoutSize(Container) : 지정된 상위 컨테이너에서 컴포넌트를 받은 지정된 패널의 최소 크기를 계산
preferredLayoutSize(Container) : 지정된 상위 컨테이너에서 컴포넌트를 받은 지정된 패널의 환경설정된 크기를 계산
removeLayoutComponent(Component) : 배치에서 지정된 컴포넌트를 제거
LayoutManager2를 구현하는 java.awt의 클래스 - BorderLayout, CardLayout, GridBagLayout, GridLayout, FlowLayout

인터페이스 java.awt.LayoutManager2
LayoutManager2 인터페이스는 LayoutManager 인터페이스를 확장하여 배치에 컴포넌트를 추가하는 방식 및 위치를 지정하는 제약 조건 객체에 따라 배치를 명시적으로 처리 합니다.
addLayoutComponent(Component, Object) : 지정된 제약 조건 객체를 사용하여 지정된 컴포넌트를 배치에 추가 합니다.
getLayoutAlignmentX(Container) : x 축 정렬을 리턴 합니다.
getLayoutAlignmentY(Container) : y 축 정렬을 리턴 합니다.
invalidateLayout(Container) : 배치 관리 프로그램이 버려야 할 정보를 캐시에 넣은 경우 그 사실을 나타내고 배치를 무효화 합니다.
maximumLayoutSize(Container) : 컴포넌트의 최대 크기를 리턴 합니다.
LayoutManager2를 구현하는 java.awt의 클래스 - BorderLayout, CardLayout, GridBagLayout

FlowLayout
컴포넌트를 컨테이너에 연속된 행으로 위치 시킨다. 각 행에 많은 컴포넌트를 채우고 행이 다차면 다음으로 넘어간다. 주로 버튼등을 배열하기 위한 것
컴포넘트의 기본 위치는 행의 한가운데 입니다.
다음과 같은 행의 기본위치를 지정할수 있는 상수가 있습니다.
FlowLayout.LEFT, FlowLayout.RIGHT, FlowLayout.CENTER,
[예제]
import java.awt.*;
class FlowLayoutTest extends Frame {
public FlowLayoutTest() {
setLayout(new FlowLayout());
add(new Button("Button1"));
add(new Button("Button2"));
add(new MyButton("새로운 버튼"));
Panel p = new Panel();
p.add(new Button("Panel Button1"));
p.add(new Button("Panel Button2"));
add(p);
}
public static void main(String[] args) {
Frame f1 = new FlowLayoutTest();
f1.setTitle("Flow Layout Test : default");
f1.setBounds(0, 0, 200, 300);
f1.setVisible(true);
Frame f2 = new FlowLayoutTest();
//((FlowLayout)f2.getLayout()).setAlignment(FlowLayout.LEFT);
FlowLayout flow = new FlowLayout(FlowLayout.LEFT);
flow.setVgap(50);
f2.setLayout(flow);
f2.setTitle("Flow Layout Test : left");
f2.setBounds(200, 0, 200, 300);
f2.setVisible(true);
}
}
class MyButton extends Button {
public MyButton(String text) {
super(text);
}
public Dimension getPreferredSize() {
return new Dimension(super.getPreferredSize().width+30, super.getPreferredSize().height+30);
}
}

GridLayout
각 격자끼리의 width, height는 동일 합니다.
GridLay() : 행이 하나인 GridLayout을 만듭니다.
GridLayout(int row, int col) : 주어진 행과 열의 GridLayout을 만듭니다.
GridLayout(int row, int col, int hgap, int vgap)

[예제]
import java.awt.*;
class GridLayoutTest extends Frame {
public GridLayoutTest(String t, LayoutManager m, int x, int y) {
setTitle("GridLAyout Test " + t);
setLayout(m);
add(new Button("Button1"));
add(new Button("Button2"));
add(new Button("Button3"));
add(new Button("Button4"));
add(new Button("Button5"));
add(new Button("Button6"));
add(new Button("Button7"));
setBounds(x, y, 300, 300);
setVisible(true);
}
public static void main(String[] args) {
new GridLayoutTest("디폴트", new GridLayout(), 0, 0);
new GridLayoutTest("2, 0", new GridLayout(2, 0), 300, 0);
new GridLayoutTest("0, 2", new GridLayout(0, 2), 0, 300);
new GridLayoutTest("3, 3", new GridLayout(3, 3), 300, 300);
}
}

GridBagLayout
Layout Manager중에서 가장 복잡하며, 보통 하나의 GridBagLayout을 사용하여 모든 종류의 폼을 구성할 수 있습니다.
융통성있는 배치 관리 프로그램으로 동일 크기의 컴포넌트를 요구하지 않으면서 컴포넌트를 수직 및 수평으로 정렬 합니다.
각 컴포넌트가 하나 이상의 셀을 차지하는 표시 영역이라 부르는 셀의 사각형 격자를 동적으로 유지 관리 합니다.
GridBagLayout으로 관리하는 각 컴포넌트는 표시 영역에서 컴포넌트 배치 방식을 지정하는 GridBagConstraints의 인스턴와 관련 됩니다
GridBagLayout을 효율적으로 사용하려면 해당 컴포넌트와 관련된 GridBagConstraints 객체를 하나 이상 조정해야 합니다. 그렇게 함으로서 컴포넌트를 원하는 크기와 위치로 배치합니다.
실제 GridBagLayout을 사용하는것 보다 여러 개의 컨테이너와 Layout Manager를 계층적으로 사용하는것이 훨씬 효율적 입니다.
GridBagConstraints
- gridx, gridy : 해당 컴포넌트가 들어가게될 격자의 x번째, y번째 값, 가장 왼쪽 셀의 주소는 gridx=0, gridy=0 입니다.
- gridwidth, gridheight : 해당 열에 존재할수 있는 최대 컴포넌트의 개수, int값 사용, GridBagConstraints.RELATIVE는 컴포넌트들이 이어져서 들어갈수 있게 해주며,GridBagConstraints.REMAINDER는 마지막 자리에 위치해서 더 이상 컴포넌트가 들어갈수 없게 합니다.
- fill : 컴포넌트를 채울때 특정 방향으로 컴포넌트를 늘여 격자를 채울수 있게 합니다. GridBagConstraints.BOTH, GridBagConstraints.HORIZONTAL, GridBagConstraints.VERTICAL등이 있다.
- ipadx, ipady : 컴포넌트가 가지는 내부적 간격, int값 사용 합니다.
- insets : 컴포넌트와 격자와의 외부적인 간격, java.awt.inset 객체가 사용 됩니다.
- anchor : 격자내에서 컴포넌트가 위치하게 되는 격자내의 절대적인 위치, GridBagConstraints.CENTER(기본값), GridBagConstraints.NORTH, GridBagConstraints.NORTHEAST, GridBagConstraints.EAST, GridBagConstraints.SOUTHEAST, GridBagConstraints.SOUTH, GridBagConstraints.SOUTHWEST, GridBagConstraints.NORTHWEST등이 있습니다.
- weightx, weighty : 컴포넌트가 차지할수 있는 가로와 세로의 영역비율, double 값이 사용 됩니다.

[예제]
import java.awt.*;
public class GridBagLayoutTest extends Frame{
public GridBagLayoutTest(String t) {
super(t);
GridBagLayout gbag = new GridBagLayout();
GridBagConstraints con = new GridBagConstraints();
setLayout(gbag);
con.fill=GridBagConstraints.BOTH;
add(new Button("버튼1"), con);
add(new Button("버튼2"), con);
con.gridwidth = GridBagConstraints.REMAINDER;
add(new Button("버튼3"), con);
add(new Button("버튼4"), con);

con.gridwidth = GridBagConstraints.RELATIVE;
add(new Button("버튼5"), con);
con.gridwidth = GridBagConstraints.REMAINDER;
add(new Button("버튼6"), con);
con.gridwidth = 1;
con.gridheight = 2;
add(new Button("버튼7"), con);
con.gridwidth = GridBagConstraints.REMAINDER;
con.gridheight = 1;
add(new Button("버튼8"), con);
add(new Button("버튼9"), con);
}
public static void main(String[] args) {
Frame f = new GridBagLayoutTest("GridBagLayout");
f.setSize(300, 200);
f.setVisible(true);
}
}

CardLayout
여러화면을 겹쳐 두었다가 특정한 화면만 보이도록 할 경우 사용 합니다.
여러 장의 카드가 있으나 보이는 카드는 하나만 있다는 개념에서 나온 이름 입니다
first(), last(), next(), previous() 등의 도구를 사용하여 카드 간에 순차적으로 이동할 수도 있습니다.
CardLayout() : 간격 크기가 제로(0)인 새로운 카드를 작성 합니다.
CardLayout(int, int) : 지정된 수평 간격 및 수직 간격으로 새로운 카드 배치를 작성 합니다.

[예제] //닫기 기능 추가
import java.awt.*;
import java.awt.event.*;
public class CardLayoutTest1 extends Frame {
public static void main(String[] args) {
Frame f = new Frame("CardLayoutTest");

final Panel tabs = new Panel();

tabs.add(new Button("<><"));>
tabs.add(new Button("<"));
tabs.add(new Button("Options"));
tabs.add(new Button("Settings"));
tabs.add(new Button("Preferences"));
tabs.add(new Button(">"));
tabs.add(new Button(">>"));
f.add(tabs, "North");

final CardLayout layout = new CardLayout();
final Panel cards = new Panel(layout);
cards.add(new CardPanel("Options"), "Options");
cards.add(new CardPanel("Settings"), "Settings");
cards.add(new CardPanel("Preferences"), "Preferences");
f.add(cards, "Center");


ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ev) {
String cmd = ev.getActionCommand();
if (cmd.equals("<><")) layout.first(cards);
else if (cmd.equals("<")) layout.previous(cards);>
else if (cmd.equals(">")) layout.next(cards);
else if (cmd.equals(">>")) layout.last(cards);
else layout.show(cards, cmd);
}
};

for(int i=0; i
((Button)tabs.getComponent(i)).addActionListener(al);
}
f.setSize(400, 300);
f.setVisible(true);
f.addWindowListener(new WindowListenerProcessing() );
}
}

class CardPanel extends Panel {
CardPanel(String name) {
setLayout(new BorderLayout());
add(new Label("CardPanel : " + name, Label.CENTER),"Center");
Panel p = new Panel();
add(p, "South");
Button btn = new Button("Close");
ActionListener a1 = new ActionListener() {
public void actionPerformed(ActionEvent ev) {
String cmd = ev.getActionCommand();
if (cmd.equals("Close")) {
System.exit(0);
}
}
};
btn.addActionListener(a1);
p.add(btn);
}
}
class WindowListenerProcessing extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}



(오라클자바커뮤니티jquery 강좌)jQuery를 통한 키보드 이벤트, keydown, keyup, keypress , ORACLEJAVA CONNUNITY

jQuery를 통한 키보드 이벤트


오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  



keydown : 키 눌러질때,   keypress:글자가입력될때
keyup : 키보드가 떨어질 때

<script type="text/javascript">
$(document).ready(function() {
//keydown 이벤트가발생한순간에는글자가입력되어있지않음
//입력한글자수를표시해야하므로keyup 이벤트사용
$("textarea").keyup(function () {
//남은 글자수 구합니다.
var inputLength = $(this).val().length;
var remain = 50 ? inputLength;
//남은 글자수 display
$("h1").html(remain);
//문서객체 색상 변경
if (remain >= 0) {
$("h1").css("color","Blue");
} else {
$("h1").css("color","red")
}
});
});
</script>
<body><div>
<p>지금 내 생각을</p>
<h1>50</h1>
<textarea cols="40" rows="5"></textarea>
</div>
</body>

[Struts Shopping cart, 오라클자바커뮤니티]스트럿츠 이번에는 상품 상세보기에서 장바구니 담기를 구현해 보도록 하죠^^

이번에는 상품 상세보기에서 장바구니 담기를 구현해 보도록 하죠^^


오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  


 

---------------------------------------------------------------
1. 상품상세보기 에서는 다음과 같이 HTML FORM 태그를 구성합니다.
---------------------------------------------------------------

<html:form action="/CartInsert">



----------------------------------------------------------------
2. CartInsert를 위한 struts-config.xml은 다음과 같습니다.
----------------------------------------------------------------

<!-- Insert ShoppingCart  -->
        <action         
            path="/CartInsert"
            type="goods.action.CartInsertAction"
            name="cartForm"                                     
        />

혹시 몰라 말씀드리는데... 스트럿츠의 <html:form>에는 html이나 jsp에서 from name을 주지않도록 되어 있는데,.,, 이는 struts-config.xml안에서 정의하기 때문이죠... html 소스 보기를 하면 자동으로 form name이 변환되어져 있는 것을 확인 할 수 있습니다.


----------------------------------------------------------------
3. CartInsertAction.java
----------------------------------------------------------------

//============================================================================
/**
  * 시스템명 : goods / 장바구니
  * 작 성 일  : 2005-05-15
  * 작 성 자  : Lee, Jong-Cheol
  * 수 정 자  :
  * 파 일 명  : goods.action.CartInsertAction
  * 버    전  : 1.0
  * 개    요  : 쇼핑카트의 물품 추가 Action
  * 이    력  : 2005-05-15 : 초기 작성
  *     
  */
//============================================================================

package goods.action;

import java.util.ArrayList;

import goods.model.Cart;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

import oraclejava.BaseActionLogin;
import oraclejava.Constants;
import oraclejava.YLog;


/**
 * @author 이종철
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class CartInsertAction extends BaseActionLogin{
    public ActionForward cartInsert(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
                    throws Exception {                         
       
                DynaActionForm dForm = (DynaActionForm)form;
       
                String gCode        = dForm.get("gcode").toString();
                String gName        = dForm.get("gname").toString();
                String gName2      = dForm.get("gname2").toString();
                String price        = dForm.get("price").toString();
                String cnt          = dForm.get("cnt").toString();
                String juklip_ratio = dForm.get("juklip_ratio").toString();
                String unit        = dForm.get("unit").toString();
                String image_path3  = dForm.get("image_path3").toString();
                String is_taekbae_discount  = dForm.get("is_taekbae_discount").toString();
                String is_direct    = dForm.get("is_direct").toString();
             
                Cart cart = getCart(request);
                                                                                                                     
                cart.addItem(gCode, gName, gName2, price, cnt, juklip_ratio, unit, image_path3, is_taekbae_discount);
               
                ArrayList cartList = (ArrayList)cart.getCartItems();
               
                HttpSession session = request.getSession();
                   
                session.setAttribute(Constants.CART_LIST, cartList);
               
                //장바구니 보기
                if (is_direct.equals("N")) {                                     
                    return mapping.findForward(Constants.CARTOK);
                }
                //바로 주문하기
                else {
                    return mapping.findForward(Constants.ORDERPAGE); 
                }                                                         
            }
}


Cart.java, CartItem.java는 이전 강좌를 참고 하세요~

[ORACLEJAVANEW.KR]Struts DispacthAction 클래스

Struts DispacthAction 클래스 DispacthAction 클래스


오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  


액션의 경우 하나의 클래스에 관련된 action이 정의 되어 있는 것이 좋은 방법인데  DispacthAction 클래스는 관련된 action은 하나의 클래스에 관리하는 방법을 제공 합니다.

DispacthAction 클래스는 추상 클래스 이므로 사용하기 위해서는 액션 클래스에서 오버라이드 해야 하며 DispacthAction 클래스에서는 어느 action이 불리어져야 하는지를 관리 하기 위해 hidden request parameter를 관리 합니다.

DispacthAction 을 상속 받은 하위 클래스로 넘어오는 hidden parameter는 스트럿츠 설정 파일에 있는 <action> 요소의 parameter 라는 속성의 값이 넘어 오게 됩니다.

결국 DispacthAction 클래스를 상속 받은 하위 클래스는 execute() 메소드와 signature가 같은 많은 메소드(각각의 Action이 수행 해야 하는 메소드)를 정의해야 합니다.


=================================================================

1. Action 처리를 위한 DispatchAction클래스의 하위 클래스를 작성

public class UserRegistrationMultiAction extends DispatchAction {
...
}

2. 관계된 action을 구현 합니다.

public ActionForward processPage1( ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
...
}

public ActionForward processPage2(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
...
}


3. Action Mapping을 작성 합니다. 이때 paramter라는 속성에 “action” 이라고 줍니다. 이 action이라는 파라미터와 그 값(이건 JSP에서 넘어 옵니다)이 위에서 구현한 DispatchAction 클래스를 상속한 UserRegistrationMultiAction 클래스에 넘어 가게 됩니다.
즉 paramter인 action의 값이 수행 하고자 하는 action이 되는 것 입니다.

<action path="/userRegistrationMultiPage1"
type="strutsTutorial.UserRegistrationMultiAction"
name="userRegistrationForm"
attribute="user"
parameter="action"
input="/userRegistrationPage1.jsp">
...
</action>

<action path="/userRegistrationMultiPage2"
type="strutsTutorial.UserRegistrationMultiAction"
name="userRegistrationForm"
attribute="user"
parameter="action"
input="/userRegistrationPage2.jsp">
...
</action>

4. 이젠 JSP에서 action이라는 히든 텍스트를 만들어 Action이 일어 날 때 Action을 처리하는  클래스(UserRegistrationMultiAction ) 로 넘기게 됩니다.

userRegistrationPage1.jsp 에 포함된 히든 태그

<html:hidden property="action" value="processPage1"/>

userRegistrationPage2.jsp 에 포함된 히든 태그

<html:hidden property="action" value="processPage2"/> 

[오라클자바커뮤니티강좌,자바교육]Struts에서의 예외처리-2

Struts에서의 예외처리(2)



오라클자바커뮤니티에서 설립한 오엔제이프로그래밍 실무교육센터
(오라클SQL, 튜닝, 힌트,자바프레임워크, 안드로이드, 아이폰, 닷넷 실무전문 강의)  




스트럿츠가 제공 하는 예외 처리

스트럿츠 1.1. 이후에는 작지만 효율적인 예외처리 프레임워크를 추가 했습니다. 또한 org.apache.struts.util.AppException 클래스는 ActionError를 포함하며 java.lang.Exception을 확장한 클래스 입니다.

아래와 같이 스트럿츠에서 사용하면 되는데

throw new AppException(“error.password.invalid”);

생성자의 “error.password.invalid”는 리소스 번들의 key 이며 프레임웍에서는 자동적으로 예외의 ActionError 객체를 생성하고 적절한 scope에 저장 합니다. 물론 애플리케이션에서 AppException에 대해 확장이 가능 합니다.

----------------------------------------------------
선언적 예외 처리와 프로그램적 예외처리
----------------------------------------------------

선언적 예외처리는 struts-config.xml등에 예외에 대해서 정의 하는 것 입니다. 이에 반해 프로그램적 예외 처리는 선언적 예외 처리와 정반대되는 개념으로 애플리케이션에서 정의한 내부 코드를 통해 예외를 처리하는 전통적인 방법 입니다.

아래는 login Action에서 발생하는 세가지 예외를 정의한 것 입니다.

<action-mappings>
                <action
                        path="/login"
                        type="com.oreilly.struts.storefront.security.LoginAction"
                        name="loginForm"
                        scope="request"
                        input="/login.jsp">
               
                <!--The following exceptions can be thrown during the login action -->
                <exception
                        key="security.error.changepassword"
                        path="/changePassword.jsp"
        type="com.oreilly.struts.framework.exceptions.ExpiredPasswordException"/>

                <exception
                        key=" security.error.loginfailed"
                type="com.oreilly.struts.framework.exceptions.InvalidLoginException"
                        path="/login.jsp"/>

                <exception
                        key="security.error.accountlocked"
        type="com.oreilly.struts.framework.exceptions.AccountLockedException"
                        path="/accountLocked.jsp"/>
        </action>
</action-mappings>


위에서 exception 요소는 정의한 예외가 발생 할 경우 포워드할 경로를 액션 매핑이나 전역 예외에 정의 합니다. Login Action이 실행하는 동안 ExpiredPasswordException이 발생 한다면 컨트롤러의 제어를 changePassword.jsp로 포워드 됩니다.

예외를 Action 클래스에 프로그램 코드를 통해 코딩을 하지 않았다면 RequestProcessor는 정의한 예외 타입을 설정한 exception 요소가 있는지 확인 하며 만약 exception 요소가 있다면 컨트롤러는 exception 요소의 path 속성에 지정된 자원으로 포워드 합니다.

아래는 RequestProcessor 클래스의 processException() 메소드 입니다. 메소드의 시작 시점에 findException() 메소드가 ExceptionConfig 객체를 반환 하는데 ExceptionConfig 객체는 설정 파일에 기술된 exception 요소가 메모리에 있는 것으로 생각하면 됩니다.

만약 findException() 메소드가 발생한 예외와 대응하는 exception 요소를 찾지 못하면 스트럿츠 프레임워크에서의 예외 처리 없이 클라이언트에 반환 됩니다. 발생한 예외가 IOException이나 IOException 클래스의 서브 클래스가 아니면 ServletException 인스턴스로 감싸서 다시 던집니다.

만약 특정한 예외를 정의한 Action Mapping이 있다면 findException() 메소드를 통해 ExceptionConfig 객체를 반환 합니다.

getHandler() 메소드는 ExceptionConfig 객체를 추출하고 추출한 핸들러를 예외를 처리하는데 사용 합니다.

--------------------------------------------------------
protected ActionForward processException(HttpServletRequest        request,
                                        HttpServletResponse response,
                                        Exception exception,
                                        ActionForm form,
                                        ActionMapping mapping)
                                        throws IOException, ServletException {
        // Is there a defined handler for this exception?
        ExceptionConfig config =mapping.findException(exception.getClass( ));

        if (config == null){
                if (log.isDebugEnabled( )){
                        log.debug(getInternal().getMessage("unhandledException",exception.getClass( )));
                }

        if (exception instanceof IOException){
                throw (IOException) exception;
        }
        else if (exception instanceof ServletException){
                throw (ServletException) exception;
        }
        else{
                throw new ServletException(exception);
        }


        // Use the configured exception handling
        try {
                Class handlerClass = Class.forName(config.getHandler( ));
                ExceptionHandler handler =(ExceptionHandler)handlerClass.newInstance( );
                return (handler.execute(exception, config, mapping,        form,request, response));
        }
        catch (Exception e){
                throw new ServletException(e);
        }
}


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

스트럿츠 프레임워크에서는 예외 처리에 관한 환경 설정이 되어 있지 않은 경우 사용 가능한 기본 예외 처리 클래스를 포함 하고 있는데. org.apache.struts.action.ExceptionHandler가 기본 핸들러 입니다.

기본 핸들러의 execute() 메소드는 ActionError를 생성하고 적절한 scope에 저장한 다음 exception 요소의 path 속성에 할당 되어 있는 ActionForward 객체를 반환 합니다. 결국 Actionforward의 경로로 제어를 넘기게 됩니다.

예외가 발생 했을 때 다른 처리를 원한다면 exception 요소는 핸들러 클래스에 대한 오버라이드를 허용 합니다. 즉 struts-config.xml 파일에 exception 요소 안에서 handler 속성에 org.apache.struts.action.ExceptionHandler 클래스를 상속하는 클래스를 명시 함으로서 가능 합니다. Handler 클래스의 execute() 메소드를 오버라이드 함으로서 각각의 애플리케이션들은 기본 예외에서 확장된 예외 처리를 할 수 있습니다.



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

import java.util.List;
import java.util.ArrayList;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* 이 클래스는 애플리케이션 예외의 공통 슈퍼 클래스 입니다.
* 이 클래스와 이 클래스의 서브 클래스는 chained exception 기능을 제공
* chained exception 기능은 원래 문제를 이 클래스나 이 클래스의 서브 클래스로
* 감싸서 다시 실행 할 수 있습니다.
* 이 클래스는 exception을 List로 관리 함으로서 다중 예외 처리가 가능 합니다.
*/
public class BaseException extends Exception{
        protected Throwable rootCause = null;
       
        //예외를 여러 개 관리하고 나중에 ActionError를 만들 때도 반영
        private List exceptions = new ArrayList( );

        private String messageKey = null;
        private Object[] messageArgs = null;

        public BaseException( ){
                super( );
        }
       
        //생성자
        public BaseException( Throwable rootCause ) {
                this.rootCause = rootCause;
        }

        public List getExceptions( ) {
                return exceptions;
        }

        public void addException( BaseException ex ){
                exceptions.add( ex );
        }

        public void setMessageKey( String key ){
                this.messageKey = key;
        }

        public String getMessageKey( ){
                return messageKey;
        }
       
        //어떤 메시지는 아규먼트가 여러 개 일 수 있습니다.
        // 예를들면 나이는 0 ~ 99 사이의 수가 들어와야 합니다.
        public void setMessageArgs( Object[] args ){
                this.messageArgs = args;
        }

        public Object[] getMessageArgs( ){
                return messageArgs;
        }

        public void setRootCause(Throwable anException) {
                rootCause = anException;
        }

        public Throwable getRootCause( ) {
                return rootCause;
        }

        public void printStackTrace( ) {
                printStackTrace(System.err);
        }

        public void printStackTrace(PrintStream outStream) {
                printStackTrace(new PrintWriter(outStream));
        }

        public void printStackTrace(PrintWriter writer) {
                super.printStackTrace(writer);
                if ( getRootCause( ) != null ) {
                        getRootCause( ).printStackTrace(writer);
                }
                writer.flush( );
        }
}



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

아래에서 messageKey는 ActionError 클래스의 생성자에 전달되고 스트럿츠 프레임웍에서는 키와 리소스 번들의 메시지를 대응 시킵니다. 또한 클래스는 생성된 예외들을 추가 할 수 있는 객체 배열을 포함합니다.

객체 배열에 있는 예외 객체들은 MessageFormat을 기반으로 파라미터에 따라 리소스 번들의 메시지를 교환 할 수 있습니다. 번들 안에 있는 메시지는 다음과 같습니다.

global.error.invalid.price=The price must be between {0} and {1}.

아래는 기본 예외 핸들러 클래스를 확장 하고 ActionError 생성자 내부의 인자를 동적으로 생성하는 기능을 제공 합니다.

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

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ExceptionHandler;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionError;
import org.apache.struts.util.AppException;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.config.ExceptionConfig;
import com.oreilly.struts.framework.exceptions.BaseException;

public class SpecialExceptionHandler extends ExceptionHandler
{
        protected ActionForward execute(Exception ex,
                        ExceptionConfig config,
                        ActionMapping mapping,
                        ActionForm formInstance,
                        HttpServletRequest request,
                        HttpServletResponse response)
                                        throws ServletException {
                ActionForward forward = null;
                ActionError error = null;
                String property = null;

                /* input 속성이나 exception 요소에서 포워드할 path를 가져옴 */
                String path = null;
                if (config.getPath( ) != null) {
                        path = config.getPath( );
                }
                else{
                        path = mapping.getInput( );
                }

                // Construct the forward object
                forward = new ActionForward(path);

                /* Figure out what type of exception has been thrown.The Struts
                * AppException is not being used in this example.
                */
                if( ex instanceof BaseException) {
                        // ********* 특화된 처리 부분
                        BaseException baseException = (BaseException)ex;
                        String messageKey = baseException.getMessageKey( );
                        Object[] exArgs = baseException.getMessageArgs( );
                        if ( exArgs != null && exArgs.length > 0 ){
                        // If there were args provided, use them in the       
ActionError
                                error = new ActionError( messageKey, exArgs );
                        }
                        else{
                                // Create an ActionError without any arguments
                                error = new ActionError( messageKey );
                        }
                }
                else{
                        error = new ActionError(config.getKey( ));
                        property = error.getKey( );
                }

                // Store the ActionError into the proper scope
                // The storeException method is defined in the parent        class
                storeException(request, property, error, forward,
                config.getScope( ));
                return forward;
        }
}


스트럿츠의 예외 처리에 대해 정리해보면 Action에서 execute() 메소드를 실행 시 예외처리를 위해 try-catch로 쌉니다. 예외가 발생 했다면 RequestProcessor 클래스의 findException이 호출되어 ExceptioConfig 객체를 반환 합니다. 다음으로 getHandler() 메소드가 호출 되어 핸들러를 얻습니다. 다음으로 기본 핸들러만 정의되어 있다고 보면 핸들러 클래스의 execute() 메소드가 호출되고 여기에서 ActionError를 생성 후 적절한 scope에 저장 후 path 속성에 정의된 리소스로 제어를 넘깁니다.

 


-------------------------------
프로그램에서 오류 처리하기
-------------------------------

Action 클래스에서 예외가 발생 했을 때 만약 발생한 예외가 애플리케이션 예외 인 경우 로그를 남기고 ActionError를 생성하여 해당 스코프에 저장한 후 ActionForward를 통해 제어를 넘기는 식으로 처리 합니다.

예외의 효과적인 관리를 위해 최상위 래퍼 클래스(BaseException)를 하나 만들고 애플리케이션 예외를 모두 그 안에 두는 것 입니다. 이렇게 하면 catch 문에서 BaseException만 받아내면 될 것 입니다. (BaseException이 아니면 시스템 예외라고 가정 할 수 있으며 이렇게 처리 해야 합니다.)

시스템 예외 처리 방법은 예외를 로그로 남기고 시스템 에러 페이지를 만들어 그곳으로 포워드 시키면 됩니다.

아래는 Action안에서의 처리 입니다.

try{
        // Peform some work that may cause an application or system        exception
}
catch( BaseException ex ){
        // Log the exception
        // Create and store the action error
        ActionErrors errors = new ActionErrors( );
        ActionError newError = new ActionError( ex.getErrorCode(),ex.getArgs( ) );
        errors.add( ActionErrors.GLOBAL_ERROR, newError );
        saveErrors( request, errors );

        // Return an ActionForward for the Failure resource
        return mapping.findForward( "Failure" )
}
catch( Throwable ex ){
        // Log the exception
        // Create and store the action error
        ActionError newError = new        ActionError( "error.systemfailure" );
        ActionErrors errors = new ActionErrors( );
        errors.add( ActionErrors.GLOBAL_ERROR, newError );
        saveErrors( request, errors );
        // Return an ActionForward for the system error resource
        return mapping.findForward( IConstants.SYSTEM_FAILURE_PAGE );
}

Action마다 이렇게 한다는 것은 중복되는 코드가 발생 할 수 있는데 앞에서 설명 드린 선언적 접근 방법을 이용한다면 해결 할 수 있지만 Action의 최상위인 BaseAction을 하나 만들어 이를 해결 할 수 있습니다.

모든 action에 공통적으로 들어가야 할 기능이 있다면 (로그인 체크,접속/비 접속 체크,쇼핑 카트 등) 그것을 구현해 놓고(추상 클래스로), 다른 action들이 struts의 action을 상속받지 않고, 이 공통 action을 상속받게 합니다. 이것은 필수요소가 아니라 선택사항입니다. 공통사항이 없다면 하지 않아도 상관 없습니다.

아래에 최상위 Action에 관련된 예문이 있으니 참고 바랍니다.
 
//execute( ) method of the BaseAction(Action의 최상위 클래스로서 추상클래스 입니다.)
//아래의 경우 예외 발생시 execute 메소드의 catch에 의해 잡힙니다.
public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response) throws Exception {
ActionForward forwardPage = null;
        try{
                UserContainer userContainer = getUserContainer( request );
                // 이부분에 필요하다면 모든 액션들이 공통으로 확인해야 되는 사항이
                //있다면 처리 합니다.(로그인 여부, 장바구니 확인 등)

        // 별도로 선언된 executeAction을 실행 시킵니다.
        // executeAction은 서브 액션의 입맛에 맞게 적절히 구현해서 사용 합니다.
        //예를들면 게시판 기능이라면 게시물을 읽는 기능, 쓰는 기능, 삭제 기능, 수정 기능 등이  될 수 있습니다.
                forwardPage = executeAction(mapping, form, request,        response, userContainer);
        }
        //아래의 catch문이 모든 Action에 있어야 하는 겁니다.
        catch (BaseException ex){
                // Log the application exception using your logging        framework
                // Call the generic exception handler routine
                forwardPage = processExceptions( request, mapping,        ex );
        }catch (Throwable ex){
                // Log the system exception using your logging framework
                // Make the exception available to the system error page
                request.setAttribute( Action.EXCEPTION_KEY, ex );

                // Treat all other exceptions as system errors
                forwardPage =mapping.findForward( IConstants.SYSTEM_FAILURE_KEY );
        }
        return forwardPage;
}

//추상메소드로 선언하고 이 최상위 액션을 상속 받는 하위 액션들의 입맛에 맞게 구현토록 합니다.
abstract public ActionForward executeAction( ActionMapping mapping,
                                                                                        ActionForm form,
                                                                                        HttpServletRequest request,
                                                                                        HttpServletResponse response,
                                                                                        UserContainer userContainer )
throws BaseException;


다음은 execute() 메소드에서 예외가 발생 되었을 때 이것을 처리하기 위한 BaseAction의processException() 메소드를 보도록 합니다.

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

Action안에 정의 되어 있습니다. 이 메소드는 여러 개일지 모르는 예외를 찾아 예외의 수 만큼 processBaseException 이라는 메소드를 다시 불러 그곳에서 ActionError등에 저장 하는 기능 등을 수행하도록 합니다.

protected ActionForward processExceptions( HttpServletRequest request,
                                        ActionMapping mapping,
                                        BaseException ex )
{
        ActionErrors errors = new ActionErrors( );
        ActionForward forward = null;

        // 사용자의 지역 설정을 가지고 옵니다.
        Locale locale = getUserContainer( request ).getLocale( );
        if (locale == null){
                        // 지역이 설정되지 않았다면 기본 지역을 사용
                        environment locale = Locale.getDefault( );
        }

        processBaseException(errors, (FieldException) ex, locale);

        // 입력된 리소스와 failure 포워드를 반환 합니다.
        String inputStr = mapping.getInput( );
        String failureForward = mapping.findForward(IConstants.FAILURE_KEY);

        if ( inputStr != null) {
                forward = new ActionForward( inputStr );
        }
        else if (failureForward != null){
                forward = failureForward;
        }

        // 예외가 하위 예외를 포함하고 있는지 확인
        List exceptions = ex.getExceptions( );

        if (exceptions != null && !exceptions.isEmpty( ) ){
                int size = exceptions.size( );
                Iterator iter = exceptions.iterator( );

                while( iter.hasNext( ) ){
                        // 모든 하위예외들은 BaseException이어야 합니다.
                        BaseException subException =(BaseException)iter.next( );
                        processBaseException(errors, subException, locale);
                }
        }

        // Tell the Struts framework to save the errors into the request
        saveErrors( request, errors );

        // Return the ActionForward
        return forward;
}


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

processException 메소드의 수행 과정은 다음과 같습니다.

1.        사용자의 지역 확인
2.        Top레벨 예외의 processBaseException() 메소드를 수행
3.        다른 서브 예외가 있다면 각각의 예외를 수행
4.        생성한 모든 ActionError를 저장
5.        제어를 input 속성에 있는 리소스나 액션에 설정된 “Failure” Actionforward에 넘김


아래는 BaseAction의 processBaseException 메소드 입니다.


protected void processBaseException( ActionErrors errors,
                                                                        BaseException ex,
                                                                        Locale locale)
{

        // 추가될 ActionError의 레퍼런스 저장
        ActionError newActionError = null;

        // 에러 코드는 리소스 번들의 키값
        String errorCode = ex.getMessageKey( );

        /*MessageFormat 객체가 사용하는 추가적인 인자가 있다면
        * args에 예외를 추가
        */
        Object[] args = ex.getMessageArgs( );

       
        // ACtionError 클래스의 인스턴스 생성자
        if ( args != null && args.length > 0 ){
                // Use the arguments that were provided in the exception
                newActionError = new ActionError( errorCode, args );
        }
        else{
                newActionError = new ActionError( errorCode );
        }

        errors.add( ActionErrors.GLOBAL_ERROR, newActionError );