2 minute read

1. 프로젝트 생성

ojdbc로 쿼리를 조회 하기 위해 ojdbc.jar라이브러리가 필요해서 프로젝트는 간단하게 maven 프로젝트로 생성했다.
maven 프로젝트를 생성하면 dependency를 정의할수있는 pom.xml파일이 자동으로 만들어지는데 그곳에 아래와같이 ojdbc 의존성을 추가해준다.

<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>21.5.0.0</version>
</dependency>

저렇게 추가 한 후 프로젝트를 빌드하면 라이브러리 폴더에 ojdbc8.jar 라이브러리가 내려받아진걸 확인할 수 있다.

2. main함수에서 connection 생성 후 쿼리 실행


public class ExportToExcel {
// connection 정보 세팅
    private static final String JDBC_URL  = {DB 주소};
    private static final String USER      = {USER};
    private static final String PASSWORD  = {패스워드};
    private static final String OUT_FILE  = {다운받을 파일 root 경로};

    public static void main(String[] args) {
      String query = "select * from table"; // 쿼리 샘플
      Connection conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD); // connection pool 생성
      Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      ResultSet rs = stmt.executeQuery(query) // rs에 쿼리 조회 결과가 담기게 됨

3. Resultset에 담은 데이터를 CSV파일로 내려받으면된다.

원래는 POI를 사용해서 엑셀로 내려받으려고 했읐는데 받을 데이터의 컬럼중에 CLOB타입이 있었고
엑셀은 컬럼에 글자수제한(32,767자)이 있어 글자수 제한이 없는 CSV로 내려받기로 바꾸었다 ㅠㅠ
CSV 다운로드 부분 적용한 전체 코드

       try-with-resources 방식으로 이방식을 사용하면 try블록을 벗어나는 순간 자동으로 자원이 close 된다.
        try (Connection conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
             Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
             ResultSet rs = stmt.executeQuery(query)) {
​
            rs.last();
            int totalRows = rs.getRow();
            rs.beforeFirst();
​
           
            String fileName = OUT_FILE  +docType+ "_"+ deptKeyword + ".csv";
            Path outPath = Paths.get(fileName);
            Files.createDirectories(outPath.getParent());
​
          // CSV로 내려받는 부분
            try (BufferedWriter bw = Files.newBufferedWriter(outPath, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
                 PrintWriter pw = new PrintWriter(bw)) {
​
                pw.write('\uFEFF'); // UTF-8 BOM
                ResultSetMetaData meta = rs.getMetaData();
                int colCnt = meta.getColumnCount();
​
                for (int c = 1; c <= colCnt; c++) {
                    if (c > 1) pw.print(',');
                    pw.print(escape(meta.getColumnLabel(c)));
                }
                pw.print("\r\n");
                int rowCount = 0;
                while (rs.next()) {
                    for (int c = 1; c <= colCnt; c++) {
                        if (c > 1) pw.print(',');
                        Object val = rs.getObject(c);
                        String text = "";
                        // CLOB처리
                        if (val instanceof Clob) {
                            text = readClobTrim((Clob) val);
                        } else if (val != null) {
                            text = val.toString();
                        }
                       
                        pw.print(escape(text));
                    }
                    pw.print("\r\n");
                    
                }
            }
        } catch (Exception e) {
            SwingUtilities.invokeLater(() -> logArea.append("\n오류 발생: " + e.getMessage() + "\n"));
            e.printStackTrace();
        }
    }
​

4. 사용자 입력 창 만들기

나는 쿼리에 like문에 들어갈 조건을 사용자에게 입력 받고 싶어서
GUI를 사용해서 간단하게 조회조건을 입력 받았다.

   JFrame frame = new JFrame("계약 자료 CSV 추출기");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
​
        JPanel panel = new JPanel();
        panel.setBorder(new EmptyBorder(15, 15, 15, 15));
        panel.setLayout(new BorderLayout(10, 10));
​
        JPanel topPanel = new JPanel(new FlowLayout());
​
        // 입력 form 1
        topPanel.add(new JLabel("자료유형:"));
        String[] types = {"유형1", "유형2"};
        JComboBox<String> typeCombo = new JComboBox<>(types);
        topPanel.add(typeCombo);
​
        //입력 form2
        JLabel label = new JLabel("선택:");
        topPanel.add(label);
        String[] departments = {"사과", "바나나", "포도", "파인애플"};
        JComboBox<String> deptCombo = new JComboBox<>(departments);
        topPanel.add(deptCombo);
​
        JButton exportBtn = new JButton("CSV 내보내기");
        topPanel.add(exportBtn);
​
        JTextArea logArea = new JTextArea(15, 60);
        logArea.setEditable(false);
        JScrollPane scrollPane = new JScrollPane(logArea);
​
        JProgressBar progressBar = new JProgressBar();
        progressBar.setStringPainted(true);
​
        panel.add(topPanel, BorderLayout.NORTH);
        panel.add(scrollPane, BorderLayout.CENTER);
        panel.add(progressBar, BorderLayout.SOUTH);
​
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
​
        exportBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String deptKeyword = (String) deptCombo.getSelectedItem();
                String docType     = (String) typeCombo.getSelectedItem();
                exportBtn.setEnabled(false);
                progressBar.setIndeterminate(true);
                logArea.setText("");
                new Thread(() -> {
                    exportCsv(deptKeyword,docType, logArea, progressBar);
                    SwingUtilities.invokeLater(() -> {
                        exportBtn.setEnabled(true);
                        progressBar.setIndeterminate(false);
                        logArea.append("\nCSV 저장 완료\n");
                    });
                }).start();
            }
        });


이렇게 작성하면 간단한 입력폼이 작성 되고 버튼 입력 이벤트에 스레드처리를 적용하여 쿼리를 조회하고
csv로 내보내는 작업을 스레드에서 진행하도록 할수있다.


위의 프로젝트를를 package 명령 실행해서 만들어진 jar파일을
.bat파일에서 실행할수 있도록 만들면 바탕화면에서 손쉽게 파일을 실행 할 수 있다.

@echo off
set JAR_NAME=your-app.jar

REM Java 실행
java -jar %JAR_NAME%

pause


다음에는 poi를 사용해서 excel로도 다운받는 방법도 올려봐야겠다
csv로 내려받으면 스타일을 적용하기가 힘들어서 아무래도 결과물이 이쁘게 나오지 않는다…