|
|||||||||
| PREV NEXT | FRAMES NO FRAMES | ||||||||
database 처리에 있어 JDBC와 SQL문을 직접 이용할 때 발생하는 구현에 치중한 코딩, 반복적인 작업(컬럼명 맞추기, type validation, 문자열 처리등)그리고 그로 인해 발생하는 여러가지 에러처리, 디버깅작업, 유지보수 작업 등 여러가지 오버헤드가 있습니다. 그래서 이런 오버헤드를 피하기 위해 SQL문 대신 추상화된 Class를 이용하여 관념적인 프로그래밍 방법으로 DB 처리를 대신하기 위한 Framework API 입니다.
| Packages | |
| org.metaworks | |
| org.metaworks.inputter | |
| org.metaworks.query | |
| org.metaworks.ui | |
| org.metaworks.validator | |
| org.metaworks.viewer | |
| org.metaworks.web | |
| org.metaworks.wizard | |
서비스
이 Framework은 다음의 서비스를 지원합니다.프로그래머 가이드한 마디로 SQL문장으로 처리하던 모든 것을 JAVA 자료구조와 문법구조에 에뮬레이션한다고 생각하면 쉽게 이해하실 수 있습니다. 다음 표는 그러한 맵핑 구조를 보여줍니다.
- Hashtable 기반의 Row단위로 Record 검색, 저장, 수정, 삭제
- 새 레코드 저장과 기존 데이터 수정을 위한 입력/수정 폼 생성(Swing Dialog / panel)
- 일관화된 입력방법/검증방법 제공 (Inputter / Validator)
- Database 의 meta data 를 직접 불러와 Data처리에 바로 활용
- Query Form 의 제공
※ Metaworks Class and Database Mapping
class 명 Database Mapping 주요 메서드 Database Mapping Table Table load, find select Record Record (tuple) save, update, delete insert, update, delete Field Data get, put select <fieldname>, update set <field> FieldDescriptor Field Declaration get, put desc <table> FieldAttribute Field 속성 (size, default...) Inputter 입력방법 Validator Check Constraint isValid check (...)
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@165.186.52.29:1526:iman5", "infodba", "ckddnjs5");
// table을 생성한다. db의 'create'문을 연상
Table px_part_newparts = new Table(
"px_part_newparts", // table명
// column title type iskey
new FieldDescriptor[]{
new FieldDescriptor("SEQNO", "순번", Types.INTEGER, true),
new FieldDescriptor("DESCRIPTION", "설명"),
new FieldDescriptor("DEVELOPMENTDATE", "개발일정", Types.DATE),
new FieldDescriptor("DIVISION", "사업부")
},
con // 이 table이 사용할 db connection
);
검색
// 위에서 정의한 table에서 seqno=10000인 레코드를 검색
Record [] rec = px_part_newparts.find("SEQNO=10000");
// 하나라도 찾았으면 그 값을 화면에 뿌림
if(rec.length> 0){
System.out.println("DESCRIPTION = " + rec[0].get("DESCRIPTION"));
System.out.println("SEQNO = "+rec[0].get("SEQNO"));
}
수정
rec[0].put("DESCRIPTION", "바꾼내용");
rec[0].update();
삭제
rec[0].delete();새 레코드 생성해서 insert(save)하기
Record newRec = new Record(px_part_newparts);
newRec.put("SEQNO", "5555");
newRec.put("DESCRIPTION", "새 레코드의 description");
newRec.put("DIVISION", "CNZ");
newRec.save();
주어진 Table의 한 Row를 입력받을 수 있는 Form Panel (Swing JPanel)을 생성한다.
Example 1) 폼 생성
public static void main(String args[]) throws Exception{
Class.forName("oracle.jdbc.driver.OracleDriver");
// ~/orawin95/network/admin/tnsnames.ora file 참조.
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@165.186.52.29:1526:iman5", "infodba", "ckddnjs5");
// table을 생성한다. db의 'create'문을 연상
Table px_part_newparts = new Table(
"px_part_newparts", // table명
// column title type iskey
new FieldDescriptor[]{
new FieldDescriptor("SEQNO", "순번", Types.INTEGER, true),
new FieldDescriptor("description", "설명"),
new FieldDescriptor("developmentdate", "개발일정", Types.DATE),
new FieldDescriptor("DIVISION", "사업부")
},
con
);
Record [] rec = px_part_newparts.find("seqno=10000");
if(rec.length> 0){
System.out.println("description = " + rec[0].get("description"));
System.out.println("seqno = "+rec[0].get("seqno"));
}
final InputForm newForm = new InputForm(px_part_newparts, "10000");
JFrame frame = new JFrame("test");
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add("Center", newForm); // ◀◀◀◀◀◀
JButton saveBtn = new JButton("저장");
frame.getContentPane().add("South", saveBtn); // ◀◀◀◀◀◀
saveBtn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
try{
newForm.getRecord().save();
}catch(Exception ex){}
}
});
frame.pack();
frame.setVisible(true);
}
Example 2) 다이얼 로그를 만들어 입력 폼 띄우기
InputForm testForm2 = new InputForm(
new Table("test2",
new FieldDescriptor[]{
new FieldDescriptor("column1"),
new FieldDescriptor("column2"),
new FieldDescriptor("column3")
}
)
){
public void onSaveOK(Record rec, JDialog dialog){
com.ugsolutions.util.MessageBox.post("'"+ rec.get("column1") +"' 레코드가 저장되었습니다.", "저장완료", 1);
}
public void onSaveFailed(Exception e, JDialog dialog){
com.ugsolutions.util.MessageBox.post("저장 실패 했습니다.\n 에러=" + e.getMessage(), "실패", 1);
}
};
testForm2.postInputDialog(frame);
Swing 입력 UI Component들을 일관적인 방법으로 처리하기 위한 Interface로 재활용성과 추상화가 쉬워 UI개발 및 확장이 유연하고 용이합니다.
기본으로 제공되는 Inputter들(com.cwpdm.util.db.inputter.*)
| Inputter class명 | 설명 | default type(세팅하지 않아도 자동으로 선택되는 Type |
|---|---|---|
| TextInput | JTextField 입력창 | Types.VARCHAR |
| NumberInput | 숫자만 입력되고 right 배치인 JTextField | Types.INTEGER |
| DateInput | 달력 DateButton | Types.DATE |
| SelectInput | JComboBox로 되고 옵션중에 하나만 선택 | 없슴 |
| RadioInput | RadioButton로 되고 옵션중에 하나만 선택 | 없슴 |
| ReferenceInput | 선택 PopupButton으로 되고 db에서 옵션을 읽어와 하나만 선택 | 없슴 |
사용예제
FieldDescriptor의 6번째 parameter에 인자로 넣으면 된다.
new FieldDescriptor("COMMON", "공용여부", 12, false,
new FieldAttribute[]{
new FieldAttribute("default", new String("개조")),
},
new SelectInput(new String[]{"", "신작", "개조", "수량추가"}) //◀◀◀◀◀
),
new FieldDescriptor("TARGETPRICE", "목표단가", 2, false,
null,
new NumberInput() //◀◀◀◀◀
),
...
위와 같이 table을 정의한 후에 InputForm class를 이용해 Form panel을 만듭니다.
InputForm inputForm = new InputForm(table); someFrame.add(inputForm); someFrame.setVisible(true); ...나만의 Inputter 만들기
public class AbstractComponentInputter{
// InputForm이 값을 얻어낼 때 사용할 로직
abstract public Object getValue();
// InputForm이 값을 세팅해서 보여줄 때(수정 폼/초기치 세팅시) 사용할 로직
abstract public void setValue(Object obj);
// InputForm이 새로 컴포넌트를 얻어야 할 때 사용할 로직
abstract public Component getNewComponent();
}
아래의 예제는 DateInput의 소스코드입니다. (inputter.*를 보시면 다양한 예제를 볼 수 있습니다)
package com.cwpdm.util.db.inputter;
import java.awt.Component;
import javax.swing.*;
import com.ugsolutions.util.*;
import java.util.Date;
import java.text.*;
public class DateInput extends AbstractComponentInputter{
public DateInput(){
super();
}
/////////// implemetations //////////////
// InputForm이 값을 얻어낼 때 사용할 로직
public Object getValue(){
Date srcDate = ((DateButton)getComponent()).getDate();
if(srcDate==null) return null;
Date rtnDate = new Date(srcDate.getTime()){
public String toString(){
SimpleDateFormat displayFormatter = new SimpleDateFormat("yyyy-MM-dd");
String making = displayFormatter.format(this);
return making;
}
};
return rtnDate;
}
// InputForm이 값을 세팅해서 보여줄 때(수정 폼/초기치 세팅시) 사용할 로직
public void setValue(Object obj){
if(obj instanceof Date && obj!=null)
((DateButton)getComponent()).setDate((Date)obj);
}
// InputForm이 새로 컴포넌트를 얻어야 할 때 사용할 로직
public Component getNewComponent(){
DateButton dateButton = new DateButton();
dateButton.setDisplayFormat("yyyy-MM-dd");
return dateButton;
}
}
약간의 변형으로 강력한 적응성을 보여주는 Inputter!
...
new FieldDescriptor("LEVELNO", "LEVEL", 12, false, null,
// level no는 '.'과 숫자만 받음
new TextInput(){
public Component getNewComponent(){
CodeField codeField = new CodeField(10);
codeField.setAllowAlphabet(false);
codeField.setAllowSpace(false);
codeField.setAllowingCharset(".");
return codeField;
}
}
)
...
입력받은 필드값을 검사(invalidate; validation)하기 위한 일관적인 interface를 제공한다. 특히, Validator를 여러개 세팅한 조합에 의한 validation은 거의 모든 validation rule을 커버할 수 있으며 InputForm에 의해 자동으로 에러 메시징이 처리된다.
기본으로 제공되는 Validator들(com.cwpdm.util.db.validator.*)
| Validator class명 | 설명 | default type(세팅하지 않아도 자동으로 선택되는 Type |
|---|---|---|
| NotNullValid | 내용이 있는지(null인지) 체크 (db의 "not null" 제약) | 업슴 |
| NumberValid | 숫자가 입력되었는지 체크 | Types.INTEGER |
사용법
Field Descriptor 의 7번째 인자로 입력한다.
내 Validator 만들기
AbstractValidator 의 Flow Diagram
1. isValid(data)를 call해서 data가 맞는지 확인한다.
2. 틀리면 throw new Exception(getErrorMessage())한다.
3. InputForm은 (validator를 사용한 class) Exception이 나게 된다.
구현예제
public static void main(String args[]){
new InputForm(
new Table(
"validator test",
new FieldDescriptor[]{
new FieldDescriptor("userid", "사용자 ID", 0, true, null, null,
new Validator[]{
// 길이 체크
new AbstractValidator(){
public boolean isValid(Object data){
return ((String)data).length() > 10;
}
public String getErrorMessage(){
return "10자 이하여야 합니다";
}
},
// 빈칸 체크
new AbstractValidator(){
public boolean isValid(Object data){
return ((String)data).indexOf(" ") == -1;
}
public String getErrorMessage(){
return "빈칸이 허용되지 않습니다.";
}
}
}
)
}
)
).postInputDialog(null);
}
FieldAttribute는 다음과 같은 용도로 사용됩니다.
Example)
public static void main(String args[]) throws Exception{
// table을 생성한다. db의 'create'문을 연상
Table px_part_newparts = new Table(
"px_part_newparts", // table명
// column title type iskey
new FieldDescriptor[]{
new FieldDescriptor("NAME", "이름", Types.VARCHAR, true,
new FieldAttribute[]{
new FieldAttribute("default", new String('pongsor')), //◀◀◀◀◀
new FieldAttribute("size", new Integer(10)) //◀◀◀◀◀
},
),
new FieldDescriptor("DATE", "입력일", Types.DATE, false,
new FieldAttribute[]{
new FieldAttribute("source", new String('sysdate')), //◀◀◀◀◀
}
)
}
);
}
Attibute Keys| key 값 | 설명 | 사용예 |
|---|---|---|
| default | InputForm 생성시 초기값 | new FieldAttribute("default", "남자")) |
| size | 입력받는 컴포넌트의 최대 입력값 사이즈 | new FieldAttribute("size", new Integer(10)) |
| hidden | 숨겨진 필드로 InputForm생성시 나타나지 않음. 주로 값을 처리해서 넣을 때 사용. 세팅한 값은 디폴트로 사용됨 | new FieldAttribute("hidden", "test") |
| mandatory | 필수 입력 필드임. 입력 컴포넌트에 붉은 세모가 생김 | new FieldAttribute("mandatory", new Boolean(true)) |
| source | SQL처리시 세팅한 String을 그대로 SQL로서 사용한다. 주로 DB server 날짜(sysdate), 시퀀스등의 표현을 바로 쓰면 유용하다. | new FieldAttribute("source", "sysdate") |
| dontcare | 모든 처리에 대상이 되지 않는다 | new FieldAttribute("dontcare", new Boolean(true)) |
※ 모든 값은 Object 형으로 입력되어야 하기 때문에 primitive type을 사용해서는 안된다. 예를 들어 수치를 입력할 때는 'new Integer(값)'으로 입력해야 한다.
new Table(...){
public void save(Record rec) throws Exception{
try{
rec.update();
}catch(Exception e){
super.save(rec);
}
}
}
...
private class ConfigTable extends Table{
ConfigTable(){
super(
"Table 세팅",
new FieldDescriptor[]{
new FieldDescriptor("connStr"),
new FieldDescriptor("uid"),
new FieldDescriptor("pwd")
}
);
}
public void save(Record rec) throws Exception{
setConnection(""+get("connStr"), ""+get("uid"), ""+get("pwd"));
}
public void update(Record rec) throws Exception{
save(rec);
}
}
....
new InputForm(new ConfigTable()){
public void onSaveOK(Record newConfig){
MessageBox.post("설정이 완료되었습니다", "설정완료", 1);
}
}.postInputDialog(null, "확인", "수정");
...
|
|||||||||
| PREV NEXT | FRAMES NO FRAMES | ||||||||