공적's life

4-6 XML 본문

Programing/Java programing

4-6 XML

melpis 2010. 8. 13. 18:51

XML 어떻게 보면 html과 비슷한 거 같지만 사용하는 용도가 전혀 다른

 

두 가지 입니다. 간단하게 구분하면 XML은 데이터이고 html은 화면에 레이아웃이라고

 

생각하시면 됩니다. 아주 초 간단입니다. 그럼 왜 이것을 사용할까요?

 

데이터라고 했으니까 어디에 읽고 쓰겠죠. 라는 대답이 들리는 군요.

 

네 맞아요. 그렇지요. 여기에 추가적인 목적은 바로 표준화된 데이터입니다.

 

프로그래밍 언어별로 서로 다른 데이터를 사용하니까 그것들인 반드시 일치 할 수 없습니다.

 

예를 들어서 c 에서 int 타입과 java에서 int 타입은 서로 다릅니다. 물론 같은 목적을 사용되지만

 

지원하는 자리수도 다르고요. 이럴 때 사용할 수 있는 것이 바로 XML입니다.

 

이러한 목적으로 사용하게 되었지만 그 활용은 엄청나게 많습니다. 예를 들어서 XML에 저장한

 

데이터를 바탕으로 html로 변환 할 수 있고. 우리가 즐겨 쓰는 워드에서도 XML타입으로 내보내기가 가능합니다.

 

그럼 우리는 어디다가 이것을 써볼까요? 바로 sql문을 XML에 쓰고 그것을 읽어서 데이터베이스에 CRUD를

 

해보겠습니다. 이미 그런 프레임 워크가 있지만 한번 흉내 내보는 것도 재미있을 거 같아서 선택했습니다.

 

이제 실제로 한번 해볼까요?

 

일단 우리는 XML을 읽어서 Map타입으로 저장 할 것 입니다. 필요할 때 마다 XML을 읽어서 작업하는 것보다

 

이것이 조금 더 편하고, 좋은 거 같아서 이렇게 하였습니다. 일단 XML을 해석 해줄 것이 필요합니다.

 

그래서 찾은 것이 바로 SAX파서입니다. 이것은 어떻게 움직이는가? 일단 XML파일에 위치가 필요하고,

 

그 다음에는 클래스를 하나 상속 받아야 합니다. 왜냐하면 제공하는 클래스는 행동은 정의 되어 있지 않고

 

메소드와 파라미터만 정해져 있기 때문 입니다. 우리는 그것을 상속을 받아서 재정의 즉 오버라이드를 해야 합니다.

 

그럼 나머지는 코드를 보면서 설명하도록 하죠. 일단 SAX parser부터 할까요?

 

    SAXParserFactory factory = SAXParserFactory.newInstance();

    factory.setNamespaceAware(true);

    factory.setValidating(true);

    this.saxParser = factory.newSAXParser();

 

객체를 생성할 때 항상 new란 키워드만 쓰는 것이 아닙니다. 이런 식으로 생성하기 어려운 객체를 다른 객체가 대신 만들어

 

줄 때 도 있습니다. 뭐 간단하게 생각해서 반환 값이 객체를 반환하는 거죠.

 

이름에 factory라고 들어 간 것을 보니 아마도 factory패턴이라고 불리는 건가 봐요. 이런 것은 나중에 하죠.

 

그리고 나서

 

SqlXmlHandler sqlXmlHandler = new SqlXmlHandler();

        

    this.saxParser.parse(path, sqlXmlHandler);

 

이런 식으로 handler 조작을 해주기 위해서 객체를 파라미터로 던저 줍니다. 물론 경로도요.

 

자아 그럼 handler를 살펴 볼까요?

public class SqlXmlHandler extends DefaultHandler {

@Override

public void startElement(String uri, String localName, String qName,

            Attributes attributes) throws SAXException {

}

@Override

    public void characters(char[] ch, int start, int length)

            throws SAXException {

}

@Override

    public void endElement(String uri, String localName, String qName)

            throws SAXException {

}

}

이렇게 되어 있습니다. 여기서 중요한 점은 반드시 DefalutHandler를 상속 받아야 하는 점입니다. 저것은 무엇을

 

하는 클래스냐 궁금하시면 직접 열어 보시면 되겠지만, 내용은 없습니다. 빈 메소드 이죠. 왜 그럼 빈 메소드

 

만 두었는가? SAXPaser가 DefalutHandler타입으로 위에 메소드를 사용하기 때문입니다. 그러니까 우리는

 

저 클래스만 상속받아서 사용하면 우리가 만든 메소드를 이용해서 SAXPaser가 동작할 것입니다.

 

그러므로 우리는 저 안에 우리가 원하는 내용을 처리 해야 합니다.

 

그럼 동작을 살펴 볼까요?

<xml>

    <insert>aaa </insert>

</xml>

 

이런 구조에 XML이 있습니다 그럼 SAXPaser는 이런 식으로 동작합니다.

 

1. startElement -> characters -> startElement->characters-> endElement-> characters -> endElement

    <xml>     공백        <insert>    aaa     </insert>     공백        </xml>

이런 식으로 움직입니다.

 

공백을 무시 하지 않습니다. 그러니까 공백까지 모조리 읽습니다.

 

이제 메소드에 용도를 알겠죠? 나머지 용도는 api를 검색 해보시면 빠르실 겁니다.

 

그러니 값을 읽을 때는 공백제거 즉 trim()을 써 주시는 게 좋습니다.

 

이제 우리가 원하는 모든 준비가 끝났습니다. XML에 sql문을 작성하시고

 

읽기만 하시면 됩니다. 물론 시작할 때 한번만 읽어서 Map타입으로 저장해두시면

 

언제든지 활용 가능합니다.

 

그런 다음에 지겨운 문자열 파싱을 통해서 우리가 원하는 데이터를 넣어주고 완성된

 

sql문을 jdbc로 실행만 하면 끝입니다. 나머지는 코드를 보시면 이해가 될듯합니다.

 

난해 보여도 그냥 문자 가지고 이것 저것 하는 것입니다. 그럼 문자열 처리 한가지 예제만 보도록 하죠.

 

<insert id="insertBoard">

        insert into TB_BOARD(SEQ, TITLE, CONTENT, REGIST_DATE, HIT )

        values (SEQ_TB_BOARD.NEXTVAL, @title , @content, sysdate, 0)

</insert>

 

이것이 XML에 써 있는 sql문입니다. 바꿔줘야 할 데이터는 @를 붙였습니다.

public void insert(String id, String[] data){

 

Map에 있는 sql을 가지고 옵니다.

 

String sql=this.sqlMap.get(id);

        

values를 기준으로 문자를 나누어 줍니다.

        String[] separatedSqls=sql.split("values");

 

결과값: 0=[insert into TB_BOARD(SEQ, TITLE, CONTENT, REGIST_DATE, HIT )]

1=[(SEQ_TB_BOARD.NEXTVAL, @title , @content, sysdate, 0)]

        

values를 기준으로 나누어진 문자열 두 번째(1)를 , 기준으로 다시 나눕니다.

        String[] valuesSparate=separatedSqls[1].split(",");

        

        StringBuffer buffer = new StringBuffer();

values를 기준으로 나누어진 문자열 첫 번째와 values를 다시 StringBuffer에 저장합니다.

        buffer.append(separatedSqls[0]);

        buffer.append("values");

사용자가 입력한 문자를 처리하기 위한 변수 입니다.

        int dataIndex=0;

콤마로 잘려진 문자를 @에 들어 있다면 사용자가 입력한 문자로 대치 합니다.

        for(int indexI=0;indexI<valuesSparate.length;indexI++){

            int checkInputValue=valuesSparate[indexI].indexOf("@");

@이 있다면 사용자가 입력한 문자로 대치합니다. 문자 이기 때문에 '를 붙여 줍니다.

if(checkInputValue == 1){

                buffer.append("'"+data[dataIndex++]+"'");

            }else{

@없다면 그대로 저장합니다.

                buffer.append(valuesSparate[indexI]);

            }

끝에는 콤마가 들어 가지 않기 때문에 끝을 제외한 나머지 문자에는 콤마를 붙여줍니다

            if(indexI !=valuesSparate.length-1){

                buffer.append(",");

            }

        }

        sql = new String(buffer);

Jdbc를 사용하여 sql을 실행 시킵니다.

        try {

            this.connection = getConnection();

            this.preparedStatement = this.connection.prepareStatement(sql);

            this.preparedStatement.executeUpdate();

        } catch (SQLException e) {

            e.printStackTrace();

        }finally{

자원을 해제합니다.

            close();

        }

        

    }

여기서 큰 문제라면 첫 번째 (SEQ_TB_BOARD.NEXTVAL 이것이 아니라 사용자가 입력한 데이터로 바꿔줘야 한다면

 

문제가 생길 것입니다. ( )처리를 하지 않았습니다.

 

두 번째 문자만 처리 할 수 있습니다.

 

과연 제가 왜 안 했을 까요? 어려워서? 우리에 목적이 아니기 때문입니다. 우리는 XML을 다루는 것이 목적이지

 

이것을 완성시키는데 목적이 아니기 때문입니다.

 

SAXparser만 있는 것이 아니라 Dom이라는 Parser도 있습니다. 기회가 되면 다루어 보도록 하죠.

 

그럼 나머지는 코드를 보시면 될 것 입니다. 다음은 데이터베이스에 대해서 다루어 보도록 하죠^^;

package com.tistory.melpis.board;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;

public class BoardExecution {


	public static void main(String[] args) throws IOException, ParseException {

		// 문서 등록 폼 Register Document Form
		// 문서 등록 Register Document
		// 문서 상세 보기 view Document
		// 문서 목록 보기 view Document List
		// 문서 삭제 Delete Document
		// 문서 수정 폼 Edit Document Form
		// 문서 수정 Edit Document

		// 1. 사용법 출력
		System.out.println("문서 등록 폼: ex) RF");
		System.out.println("문서 등록: ex) RD:제목:내용 ");
		System.out.println("문서 상세 보기: ex) VD:문서번호 ");
		System.out.println("문서 목록 보기: ex) VL ");
		System.out.println("문서 삭제: ex) DD:문서번호 ");
		System.out.println("문서 수정폼: ex) EF:문서번호 ");
		System.out.println("문서 수정: ex) ED:문서번호:제목:내용 ");

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		BoardManager boardManager = new BoardManager();
		
		while (true) {
			// 2. 사용자 입력
			String userInputData = br.readLine();

			// 3. 데이터 추출
			// 3.1 데이터 구분하기
			String outputData[] = userInputData.split("\\:");

			// 3.2 사용자의 의도 알아 내기
			String userAction = outputData[0].toUpperCase();

			
			
			if (userAction.equals("RF")) {
				boardManager.registDoumentForm();
			} else if (userAction.equals("RD")) {
				boardManager.registDocument(outputData);
			} else if (userAction.equals("VD")) {
				boardManager.viewDocument(outputData);
			} else if (userAction.equals("VL")) {
				boardManager.viewDocumentList();
			} else if (userAction.equals("DD")) {
				boardManager.deleteDocument(outputData );
			} else if (userAction.equals("EF")) {
				boardManager.editDocumentForm(outputData);
			} else if (userAction.equals("ED")) {
				boardManager.editDocument(outputData);
			} else {
				System.out.println("잘못 입력하셨습니다");
			}
			

		}

	}
}

package com.tistory.melpis.board;

import java.text.ParseException;
import java.util.List;
import java.util.Map;

public class BoardManager {
	private final String XML_PATH="src/com/tistory/melpis/board/sql/sql.xml";
	
	private final String DRIVER_NAME="oracle.jdbc.driver.OracleDriver";
	private final String DB_URI="jdbc:oracle:thin:@localhost:1521:XE";
	private final String DB_USER_NAME="user00";
	private final String DB_USER_PASSWORD="user00";
	
	private JdbcXmlexecuter jdbcXmlexecuter = null;
	
	
	public BoardManager(){
		this.jdbcXmlexecuter = new JdbcXmlexecuter(XML_PATH,DRIVER_NAME,DB_URI,DB_USER_NAME,DB_USER_PASSWORD);
	}
	
	// 문서 등록 폼
	public void registDoumentForm() {

		// 1. 등록 폼출력
		System.out.println("제목: ");
		System.out.println("내용: ");

	}
	// 문서 등록
	public void registDocument(String[] outputData) {
		// 1.1 제목 추출
		String userInputTitle = outputData[1];
		// 1.2 내용 추출
		String userInputContent = outputData[2];
		// 2. 유효성 검사
		if (userInputTitle.length() < 1 && userInputTitle.length() > 600) {
			return;
		}
		if (userInputContent.length() < 1 && userInputContent.length() > 2000) {
			return;
		}
		//3. 등록
		String[] data= {userInputTitle,userInputContent};
		
		this.jdbcXmlexecuter.insert("insertBoard", data);
		
		// 4. 결과 출력
		System.out.println("등록 완료");

	}
	
	// 문서 상세 보기 
	public void viewDocument(String[] outputData){
		//1. 사용자가 입력한 문서 번호 가져오기
		String userInputSeq = outputData[1];
		//1.1 변환
		int parameterSeq = Integer.parseInt(userInputSeq);
		//2. 유효성 검사
		if(parameterSeq <=0){
			return;
		}
		//3.1 조회수 증가
		this.jdbcXmlexecuter.update("updateHit",new Object[]{parameterSeq});
		Map data = null;
		//3.2 조회
		data = (Map) this.jdbcXmlexecuter.select("selectBoard", parameterSeq);
		
		//4. 결과 출력
		System.out.println("글번호 : " +data.get("SEQ"));
		System.out.println("제목  : "  +data.get("TITLE"));
		System.out.println("등록일 : " +data.get("REGIST_DATE"));
		System.out.println("조회수 : " +data.get("HIT"));
		System.out.println("내용 : "  +data.get("CONTENT"));
	
		
	}
	

	public void viewDocumentList(){
		// 1. 조회 
		List> dataList = this.jdbcXmlexecuter.selectList("selectBoardList");
		// 2. 결과 출력
		for(Map data:dataList){
			System.out.println("글번호 : " +data.get("SEQ"));
			System.out.println("제목  : "  +data.get("TITLE"));
			System.out.println("등록일 : " +data.get("REGIST_DATE"));
			System.out.println("조회수 : " +data.get("HIT")+"\n");
		}

	}

	public void deleteDocument(String[] outputData) {
		//1. 사용자가 입력한 문서 번호 가져오기
		String userInputSeq = outputData[1];
		//1.1 변환
		int parameterSeq = Integer.parseInt(userInputSeq);
		//2. 유효성 검사
		if(parameterSeq<=0){
			return ;
		}
		//3. 삭제
		this.jdbcXmlexecuter.delete("deleteBoard",parameterSeq);
		
		//4. 결과 출력
		System.out.println("삭제 되었습니다");

	}

	public void editDocumentForm(String[] outputData) throws ParseException {
		//1. 사용자가 입력한 문서 번호 가져오기
		String userInputSeq = outputData[1];
		//1.1 변환
		int parameterSeq = Integer.parseInt(userInputSeq);
		//2. 유효성 검사
		if(parameterSeq<=0){
			return;
		}
		//3. 조회
		Mapdata =this.jdbcXmlexecuter.select("selectBoard", parameterSeq);
	
		//4. 결과 출력
		System.out.println("글번호 : " +data.get("SEQ"));
		System.out.println("제목  : "  +data.get("TITLE"));
		System.out.println("등록일 : " +data.get("REGIST_DATE"));
		System.out.println("조회수 : " +data.get("HIT"));
		System.out.println("내용 : "  +data.get("CONTENT"));
		
	}

	public void editDocument(String[] outputData) {
		//1.1 번호 추출
		String userInputSeq = outputData[1];
		//1.2 제목 추출  
		String userInputTitle = outputData[2];
		//1.3 내용 추출
		String userInputContent = outputData[3];
		//1.4 변환
		int parameterSeq = Integer.parseInt(userInputSeq);
		//2. 유효성검사
		if(parameterSeq<=0){
			return ;
		}
		if (userInputTitle.length() < 1 && userInputTitle.length() > 600) {
			return;
		}
		if (userInputContent.length() < 1 && userInputContent.length() > 2000) {
			return;
		}
		//3. 수정
		Object[] data={userInputTitle, userInputContent,parameterSeq};
	
		this.jdbcXmlexecuter.update("updateBoard", data);
		//4. 결과 출력
		System.out.println("수정완료 하였습니다");

	}
	
}


	
		insert into TB_BOARD(SEQ, TITLE, CONTENT, REGIST_DATE, HIT )
		values (SEQ_TB_BOARD.NEXTVAL, @title , @content, sysdate, 0)
	
	
	
		delete from TB_BOARD
		where SEQ = @seq
	


	
		update TB_BOARD 
		set
			TITLE = @title,
			CONTENT = @content,
			REGIST_DATE=sysdate
		where SEQ = @seq
	
	
	
		update TB_BOARD 
			set
			HIT = HIT+1
		where SEQ = @seq 
	
	
	
	

package com.tistory.melpis.board;

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

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class SqlXmlHandler extends DefaultHandler {
	private Map sqlMap = null;
	
	private String currentId = null;
	private int currentIdEqual=0;
	
	public SqlXmlHandler() {
		this.sqlMap=new HashMap();
	}
	
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		if (attributes.getLength()!=0) {
			this.currentId=attributes.getValue(0);
		}
	}
	
	
	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		String value = new String(ch,start,length).trim();
		
		if(!value.equals("")&&this.currentId!=null){	
			currentIdEqual++;
			if(currentIdEqual== 1){
			this.sqlMap.put(this.currentId,value);
			}else{
				String temp=this.sqlMap.get(this.currentId);
				String progressValue=temp+" "+value;
				this.sqlMap.put(this.currentId, progressValue);
			}
		}
	}
	
	
	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		this.currentId = null;
		currentIdEqual=0;
	}

	public Map getSqlMap() {
		return sqlMap;
	}
		
}


이것만 이상하게 보여서 파일 첨부할게요 ㅠㅠ

'Programing > Java programing' 카테고리의 다른 글

immutable을 사용하는 이유  (0) 2019.06.20
4-7 I.O File JDBC XML 회고  (0) 2010.08.15
4-5 JDBC-2  (0) 2010.08.10
4-4 JDBC -1  (0) 2010.08.10
4-3 DataBase network  (0) 2010.08.07