JAVA에서 XML 파일을 읽는 법

라마·2024년 9월 22일

공부

목록 보기
1/2

궁금증

회사에서 XML 파일에 적혀 있는 쿼리문, 혹은 설정 경로를 읽어와 사용하는 모습을 보게 된다. Java 애플리케이션 내에서 하드 코딩해도 될 것 같은데, 왜 XML 파일을 통해 관리하는걸까?

XML 파일이란?

XML(Extensible Markup Language)은 데이터를 구조화된 형식으로 저장하기 위한 표준 마크업 언어이다.

다양한 플랫폼에서 사용할 수 있으며, 데이터 간 통신에 주로 사용된다. XML 파일은 데이터를 계층적 트리 구조로 표현하며, 기본적으로 루트 요소 아래에 여러 개의 자식 요소가 위치한다.

각 요소는 태그로 감싸져 있으며, 태그 안에는 속성을 추가할 수 있다.

예시

# book : 태그
# id : 속성
# 텍스트 데이터 : 태그 사이에 위치한 데이터
<book id="1">
    <title>Effective Java</title>
    <author>Joshua Bloch</author>
    <publisher>Addison-Wesley</publisher>
    <year>2018</year>
</book>

XML 파일을 사용하는 이유

Java 애플리케이션에서 하드 코딩된 SQL 쿼리나 설정값을 사용하는 대신, XML 파일을 통해 값들을 관리하면 코드의 유연성유지보수성이 크게 향상된다.

재배포의 번거로움

먼저, 하드 코딩된 SQL 쿼리나 설정값은 코드에 직접 삽입되기 때문에, 이를 수정하려면 소스 코드를 수정한 뒤 다시 빌드 및 배포해야 한다. 이는 개발과 운영 환경 모두에서 번거로운 작업이 될 수 있으며, 빠르게 변화하는 요구사항을 반영하기 어렵다. 또한, 코드 내 여러 곳에서 같은 쿼리나 설정이 사용될 경우 이를 일일이 수정하는 과정에서 오류가 발생할 가능성도 높아진다.

반면, XML 파일을 사용하여 쿼리나 설정을 외부에서 관리하면, 서버를 재배포하지 않고도 필요한 부분만 수정하고 적용할 수 있다. 이를 통해 코드의 유연성이 크게 향상된다. XML 파일은 외부 파일로서, 애플리케이션 코드와 독립적으로 관리되므로 설정값이나 쿼리문이 변경되더라도 코드 수정 없이 XML 파일만 업데이트하면 된다. 예를 들어, 데이터베이스 구조나 쿼리 방식이 변경되었을 때, 코드를 다시 수정하고 배포할 필요 없이 XML 파일을 업데이트하는 것만으로 새로운 요구 사항을 처리할 수 있다.

중복의 최소화

또한, XML 파일을 통한 외부 관리 방식은 코드의 유지보수성을 높이는 데 매우 유용하다. 애플리케이션이 커지면 커질수록 코드와 설정값이 섞여 있을 때 관리하기 어려워지며, 수정 시 실수의 여지도 커진다. 그러나 XML 파일에 설정값을 모아두면 중복된 설정을 최소화할 수 있고, 단일 파일에서 설정을 수정하면 전체 시스템에 그 변경 사항을 적용할 수 있다. 이는 유지보수 작업을 더 간편하게 하고, 빠른 수정과 반영을 가능하게 한다.

따라서, XML 파일을 사용한 설정값 관리 방식은 코드의 유연성을 높여 다양한 환경 변화에 신속하게 대응할 수 있으며, 유지보수성을 높여 코드 수정 없이도 설정을 수정하고 관리할 수 있는 장점이 있다.

JDBC를 통해 XML 파일에 저장된 쿼리문을 실행하기

디렉토리 구조

프로젝트 루트/
│
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── JdbcXmlExample.java  // Java 코드
│   │   └── resources/
│   │       └── queries.xml  // XML 파일 위치

의존성 추가

// H2 Database
implementation 'com.h2database:h2:2.2.220'

XML 파일 (queries.xml)

<?xml version="1.0" encoding="UTF-8"?>
<queries>
    <query id="createTable">
        CREATE TABLE IF NOT EXISTS users (
            id INT AUTO_INCREMENT PRIMARY KEY,
            name VARCHAR(255),
            email VARCHAR(255)
        );
    </query>
    <query id="insertUser">
        INSERT INTO users (name, email) VALUES ('John Doe', 'john.doe@example.com');
    </query>
    <query id="selectUsers">
        SELECT * FROM users;
    </query>
</queries>

전체 코드

package org.example;

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.File;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;

public class JdbcXmlExample {

    // JDBC URL 및 사용자 정보
    private static final String JDBC_URL = "jdbc:h2:mem:testdb";
    private static final String JDBC_USER = "sa";
    private static final String JDBC_PASSWORD = "";

    public static void main(String[] args) {
        try {
            // XML 파일에서 쿼리 읽기
            Map<String, String> queries = loadQueriesFromXml("src/main/resources/queries.xml");

            // JDBC 연결 설정
            Connection connection = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
            Statement statement = connection.createStatement();

            // 1. 테이블 생성
            statement.execute(queries.get("createTable"));
            System.out.println("Table 'users' created.");

            // 2. 데이터 삽입
            statement.execute(queries.get("insertUser"));
            System.out.println("User 'John Doe' inserted.");

            // 3. 데이터 조회
            ResultSet resultSet = statement.executeQuery(queries.get("selectUsers"));
            while (resultSet.next()) {
                System.out.println("ID: " + resultSet.getInt("id") +
                        ", Name: " + resultSet.getString("name") +
                        ", Email: " + resultSet.getString("email"));
            }

            // 리소스 정리
            resultSet.close();
            statement.close();
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // XML 파일에서 쿼리문을 읽어오는 메서드
    private static Map<String, String> loadQueriesFromXml(String filePath) {
        Map<String, String> queryMap = new HashMap<>();
        try {
            File xmlFile = new File(filePath);
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(xmlFile);
            document.getDocumentElement().normalize();

            NodeList queryList = document.getElementsByTagName("query");

            for (int i = 0; i < queryList.getLength(); i++) {
                Node node = queryList.item(i);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    Element element = (Element) node;
                    String id = element.getAttribute("id");
                    String query = element.getTextContent().trim();
                    queryMap.put(id, query);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return queryMap;
    }
}

전체 코드를 차례대로 살펴보자.

XML 파일에서 쿼리 읽기

// XML 파일에서 쿼리 읽기
Map<String, String> queries = loadQueriesFromXml("src/main/resources/queries.xml");

// XML 파일에서 쿼리문을 읽어오는 메서드
private static Map<String, String> loadQueriesFromXml(String filePath) {
    Map<String, String> queryMap = new HashMap<>();
    try {
        File xmlFile = new File(filePath);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(xmlFile);
        document.getDocumentElement().normalize();

        NodeList queryList = document.getElementsByTagName("query");

        for (int i = 0; i < queryList.getLength(); i++) {
            Node node = queryList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) node;
                String id = element.getAttribute("id");
                String query = element.getTextContent().trim();
                queryMap.put(id, query);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return queryMap;
}

지정된 파일 경로를 기반으로 XML 파일 객체를 생성한다.

File xmlFile = new File(filePath);

그리고 XML 문서를 트리 구조로 파싱하기 위해 DocumentBuilderFactory와 DocumentBuilder 객체를 초기화한다.

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();

XML 파일을 파싱하여 DOM 트리 구조로 변환 후 불필요한 요소들을 제거한다.

Document document = builder.parse(xmlFile);
document.getDocumentElement().normalize();

XML 파일에서 query 태그를 가진 모든 노드를 가져온다.

NodeList queryList = document.getElementsByTagName("query");

query 태그의 id 속성 값들을 가져와 queryMap 에 저장한다.

for (int i = 0; i < queryList.getLength(); i++) {
    Node node = queryList.item(i);
    if (node.getNodeType() == Node.ELEMENT_NODE) {
        Element element = (Element) node;
        String id = element.getAttribute("id");
        String query = element.getTextContent().trim();
        queryMap.put(id, query);
    }
}

쿼리문 실행

그리고 다음과 같은 쿼리문을 실행해보면, H2 DB에서 쿼리문이 잘 실행된 걸 볼 수 있다.

// 1. 테이블 생성
statement.execute(queries.get("createTable"));
System.out.println("Table 'users' created.");

// 2. 데이터 삽입
statement.execute(queries.get("insertUser"));
System.out.println("User 'John Doe' inserted.");

// 3. 데이터 조회
ResultSet resultSet = statement.executeQuery(queries.get("selectUsers"));
while (resultSet.next()) {
    System.out.println("ID: " + resultSet.getInt("id") +
            ", Name: " + resultSet.getString("name") +
            ", Email: " + resultSet.getString("email"));
}

정리

XML 파일을 사용하여 직접 SQL 쿼리문을 읽어와 실행해보았다. 단지 하드 코딩된 쿼리와 설정 대신, XML 파일을 사용함으로써 얻을 수 있는 장점들을 알 수 있었다.

0개의 댓글