Формирование объектов PL/SQL для выгрузки отчётов в формате XLS из Formspider с помощью Java

от автора

Часто приходится делать различные выгрузки отчётов в формате XLS из Formspider, используя PL/SQL developer (Oracle 11g2). Так часто, что решил автоматизировать этот процесс на Java.

Язык Java изучаю сам по книгам и видеокурсам уже четвёртый год, поэтому если будут какие-то дополнения или замечания, то можете предложить их здесь через pull request.

Сама выгрузка из PL/SQL делается при помощи пакета as_xlsx.

И так, приступим! Я сделал простенький интерфейс для ввода имён объектов, параметров эксель файла и столбцов:

Интерфейс описан в классе ниже. Для удобства все параметры заполнены по умолчанию. Остаётся добавить информацию для формирования столбцов.

package QueriesCreater;  import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.*; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader;  public class Gui extends JFrame {     static ImageIcon logo = new ImageIcon(Toolkit.getDefaultToolkit().createImage(Gui.class.getResource("/logo.png")));     static JTable table;     static DefaultTableModel model;     static JTable objectTable;     static DefaultTableModel objectModel;     static int guiWindowHeight = 620;     static int guiWindowWidth = 370;     static int guiWindowX = 650;     static int guiWindowY = 190;      public Gui() {         this.setResizable(false);         setIconImage(logo.getImage());         this.setTitle("PL/SQL: excel export");         this.setFont(new Font("Tahoma", Font.PLAIN, 14));         this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);         this.setBounds(guiWindowX, guiWindowY, guiWindowWidth, guiWindowHeight);         this.getContentPane().setBackground(new Color(0xFFF9A1));         this.getContentPane().setLayout(null);          // Object name table         final JScrollPane objectNames = new JScrollPane();         objectNames.setBounds(10, 25, 334, 201);         getContentPane().add(objectNames);          String[] objectColumns = new String[]{"Object", "Value"};         objectModel = new DefaultTableModel(new Object[][] {                 {"Function name", "get_xls_function"},                 {"Procedure name", "get_xls_from_table"},                 {"Record type", "t_type_of_record"},                 {"Table as record", "t_type_of_record_tbl"},                 {"Table or view", "table_or_view"},                 {"Headers background", "FFCC66"},                 {"Headers font size", 13},                 {"Rows font size", 12},                 {"Rows height", 25},                 {"Rows bold", false},                 {"Rows italic", false},                 {"Headers font", "Times New Roman"},                 {"Rows font", "Times New Roman"},                 {"Horizontal alignment", "center"},                 {"Vertical alignment", "center"},                 {"Wrap text", true},         },objectColumns) {             final boolean[] columnEditables = new boolean[]{                     false, true             };             public boolean isCellEditable(int row, int column) {                 return this.columnEditables[column];             }         };         objectTable = new JTable(objectModel);         objectTable.setDefaultRenderer(Object.class, new TableInfoRenderer());         // cell border color         objectTable.setGridColor(new Color(58, 79, 79));         objectTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);         // table background color         objectTable.setFillsViewportHeight(true);         objectTable.setBackground(new Color(250, 252, 255));         // headers settings         JTableHeader objectHeader = objectTable.getTableHeader();         objectHeader.setFont(new Font("Tahoma", Font.BOLD, 13));         //cell alignment         TableInfoRenderer objectRenderer = new TableInfoRenderer();         objectRenderer.setHorizontalAlignment(JLabel.LEADING);         objectTable.getColumnModel().getColumn(0).setCellRenderer(objectRenderer);         objectTable.getColumnModel().getColumn(1).setCellRenderer(objectRenderer);         objectTable.setRowHeight(20);         objectTable.setColumnSelectionAllowed(true);         objectTable.setCellSelectionEnabled(true);         objectTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);         objectTable.setFont(new Font("SansSerif", Font.PLAIN, 13));         objectTable.getColumnModel().getColumn(0).setPreferredWidth(158);         objectTable.getColumnModel().getColumn(1).setPreferredWidth(158);         //colors         objectTable.setSelectionBackground(new Color(254, 204, 204));         objectNames.setViewportView(objectTable);          // удаление содержимого ячейки кнопкой Delete         objectTable.addKeyListener(new KeyAdapter() {             public void keyPressed(KeyEvent e) {                 if (e.getKeyCode()==127){                     objectTable.setValueAt("", objectTable.getSelectedRow(), objectTable.getSelectedColumn());                 }             }         });          // Columns table         final JScrollPane scrollPane = new JScrollPane();         scrollPane.setBounds(10, 255, 336, 283);         this.getContentPane().add(scrollPane);         String[] columns = new String[]{"Header", "Width", "Column", "Type"};         model = new DefaultTableModel(new Object[69][], columns) {             final boolean[] columnEditables = new boolean[]{                     true, true, true, true             };             public boolean isCellEditable(int row, int column) {                 return this.columnEditables[column];             }         };         table = new JTable(model);          // cell border color         table.setGridColor(new Color(58, 79, 79));         table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);         // table background color         table.setFillsViewportHeight(true);         table.setBackground(new Color(250, 252, 255));         // headers settings         JTableHeader header = table.getTableHeader();         header.setFont(new Font("Tahoma", Font.BOLD, 13));         //cell alignment         DefaultTableCellRenderer Renderer = new DefaultTableCellRenderer();         Renderer.setHorizontalAlignment(JLabel.CENTER);         table.getColumnModel().getColumn(0).setCellRenderer(Renderer);         table.getColumnModel().getColumn(1).setCellRenderer(Renderer);         table.getColumnModel().getColumn(2).setCellRenderer(Renderer);         table.getColumnModel().getColumn(3).setCellRenderer(Renderer);         table.setRowHeight(20);         table.setColumnSelectionAllowed(true);         table.setCellSelectionEnabled(true);         table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);         table.setFont(new Font("SansSerif", Font.PLAIN, 13));         table.getColumnModel().getColumn(0).setPreferredWidth(90);         table.getColumnModel().getColumn(1).setPreferredWidth(48);         table.getColumnModel().getColumn(2).setPreferredWidth(90);         table.getColumnModel().getColumn(3).setPreferredWidth(90);         //colors         table.setSelectionBackground(new Color(254, 204, 204));         scrollPane.setViewportView(table);          // удаление содержимого ячейки кнопкой Delete         table.addKeyListener(new KeyAdapter() {             public void keyPressed(KeyEvent e) {                 if (e.getKeyCode()==127){                     table.setValueAt("", table.getSelectedRow(), table.getSelectedColumn());                 }             }         });          // Create objects button         JButton setColumnsBtn = new JButton("Create objects");         setColumnsBtn.setBounds(224, 547, 120, 22);         setColumnsBtn.setBackground(new Color(192, 225, 255));         setColumnsBtn.setFont(new Font("Tahoma", Font.BOLD, 11));         setColumnsBtn.setContentAreaFilled(true);         setColumnsBtn.setBorderPainted(true);         setColumnsBtn.setFocusable(false);         getContentPane().add(setColumnsBtn);         setColumnsBtn.addActionListener((e) -> getValues());          // Clear table         JButton clearTableBtn = new JButton("Clear");         clearTableBtn.setBounds(10, 547, 120, 22);         clearTableBtn.setBackground(new Color(251, 203, 203));         clearTableBtn.setFont(new Font("Tahoma", Font.BOLD, 11));         clearTableBtn.setContentAreaFilled(true);         clearTableBtn.setBorderPainted(true);         clearTableBtn.setFocusable(false);         getContentPane().add(clearTableBtn);          JLabel objectNameLbl = new JLabel("Parameters");         objectNameLbl.setFont(new Font("Tahoma", Font.BOLD, 13));         objectNameLbl.setBounds(10, 5, 334, 18);         getContentPane().add(objectNameLbl);          JLabel columnLbl = new JLabel("Columns");         columnLbl.setFont(new Font("Tahoma", Font.BOLD, 13));         columnLbl.setBounds(10, 235, 334, 18);         getContentPane().add(columnLbl);          clearTableBtn.addActionListener((e) -> {             for (int i = 0; i < table.getRowCount(); i++)                 for(int j = 0; j < table.getColumnCount(); j++) {                     table.setValueAt("", i, j);                 }         });          this.setVisible(true);     }       public static void getValues() {         // определяем количество строк для создания массива (количество столбцов статическое - 4)         int rowCount = 0;         int columnCount = table.getColumnCount();          for (int i = 0; i < columnCount; i++) {             if (table.getValueAt(i, 0) != null) {                 rowCount++;             }         }          // параметры         Object[][] objectParameters = new Object[16][2];         for (int i = 0; i < 16; i++) {             for (int j = 0; j < 2; j++) {                 if (objectTable.getValueAt(i, j) != null) {                     objectParameters [i][j] = objectTable.getValueAt(i, j);                 }             }         }          // столбцы         Object[][] columns = new Object[rowCount][4];         for (int i = 0; i < rowCount; i++) {             for (int j = 0; j < columnCount; j++) {                 if (table.getValueAt(i, j) != null) {                     columns [i][j] = table.getValueAt(i, j);                 }             }         }          // выгрузка запросов в текстовый файл         if (columns.length > 0) {             WriteToFile wr = new WriteToFile();             wr.write(new GetSqlQuery().getQueries(objectParameters, columns));             //System.out.println(sql.getQueries(columns));         }     }      public static class TableInfoRenderer extends DefaultTableCellRenderer {         @Override         public Component getTableCellRendererComponent(JTable table, Object value,                                                        boolean isSelected, boolean hasFocus, int row, int column) {             JLabel c = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, false, row, column);              if(column == 0) {                 if (isSelected) {                     super.setForeground(new Color(99, 9, 9));                 } else {                     super.setForeground(Color.BLACK);                 }                 c.setBackground(new Color(219, 234, 201));                 c.setHorizontalAlignment(LEFT);                 c.setFont(new Font("Tahoma", Font.BOLD,13));             }             else {                 c.setBackground(Color.WHITE);                 c.setHorizontalAlignment(LEFT);                 if (isSelected) {                     super.setBackground(new Color(254, 204, 204));                 }             }             return c;         }     } }

В классе GetSqlQuery производится формирование команд для создания объектов PL/SQL на основе ранее введённых данных.
Record создаётся на выбор в 2 вариантах:
1) на основе %TYPE view или таблицы (не %ROWTYPE т.к. чаще нужны не все поля БД для выгрузки);
2) на основе введённых типов в columns.

Пытался сделать красиво, но не обошлось без множества append.. опять же — можно лучше — покажите как надо через pull request на gitHub

package QueriesCreater;  public class GetSqlQuery {      //формирование функции     String getQueries(Object [][] pParameters, Object [][] pColumns) {         Object functionName = pParameters[0][1];         Object procedureName = pParameters[1][1];         Object recordName = pParameters[2][1];         Object typeTableName = pParameters[3][1];         Object tableOrViewName = pParameters[4][1];         Object headersBackground = pParameters[5][1];         Object headersFontSize = pParameters[6][1];         Object rowsFontSize = pParameters[7][1];         Object rowHeight = pParameters[8][1];         Object rowsBold = pParameters[9][1];         Object rowsItalic = pParameters[10][1];         Object xlsFont = pParameters[11][1];         Object rowsFont = pParameters[12][1];         Object horizontalAlignment = pParameters[13][1];         Object verticalAlignment = pParameters[14][1];         Object wrapText = pParameters[15][1];          StringBuilder xlsHeaders = new StringBuilder("-- Package specification\n");         // создаём запись (1 вариант)         xlsHeaders.append("-- version 1\n");         xlsHeaders.append("type ").append(recordName).append(" is record (\n");         for (Object[] column : pColumns) {             xlsHeaders.append("\t").append(column[2]).append(" ").append(tableOrViewName).append(".").append(column[2]).append("%TYPE,\n");         }         // удаляем крайнюю запятую         xlsHeaders.deleteCharAt(xlsHeaders.length() - 2);         xlsHeaders.append(");\n\n");          // создаём запись (2 вариант)         xlsHeaders.append("-- version 2\n");         xlsHeaders.append("type ").append(recordName).append(" is record (\n");         for (Object[] column : pColumns) {             xlsHeaders.append("\t").append(column[2]).append(" ").append(column[3]).append(",\n");         }         // удаляем крайнюю запятую         xlsHeaders.deleteCharAt(xlsHeaders.length() - 2);         xlsHeaders.append(");\n\n");          //создаём тип таблицы на основе записи         xlsHeaders.append("type ").append(typeTableName).append(" is table of ").append(recordName).append(";\n\n");          // создаём функцию на основе типа таблицы         xlsHeaders.append("function ").append(functionName).append("(p_type in ").append(typeTableName).append(") return blob;\n\n");          // тело пакета         xlsHeaders.append("-- Package body\n");         // создание функции         xlsHeaders.append("-- function\n");         xlsHeaders.append("function ").append(functionName).append("(p_type in ").append(typeTableName).append(") return blob is\n")                 .append("  row_num number := 0;\n")                 .append("  v_file  blob;\n")                 .append("begin\n")                 .append("  as_xlsx.clear_workbook;\n")                 .append("  as_xlsx.new_sheet('tab1');\n")                 .append("  row_num := row_num + 1;\n")                 .append("  as_xlsx.set_row(row_num, p_fontId => as_xlsx.get_font('")                 .append(xlsFont)                 .append("', p_fontsize => ")                 .append(headersFontSize)                 .append(", p_bold => true),\n")                 .append("  p_fillId => as_xlsx.get_fill('solid', '")                 .append(headersBackground)                 .append("'), p_borderId => as_xlsx.get_border);\n")                 .append("\t-- headers\n")                 .append("\tas_xlsx.set_row_height(1, ")                 .append(rowHeight)                 .append(");\n");          // headers         for (int i = 0; i < pColumns.length; i++) {             int x = i + 1;             xlsHeaders.append("\tas_xlsx.set_column_width(")                     .append(x).append(", ").append(pColumns[i][1]).append("); ")                     .append("as_xlsx.cell(").append(x).append(", 1, '").append(pColumns[i][0]).append("', ")                     .append("p_alignment => as_xlsx.get_alignment (")                     .append("p_horizontal => '").append(horizontalAlignment).append("', ")                     .append("p_vertical => '").append(verticalAlignment).append("', ")                     .append("p_wraptext => ").append(wrapText)                     .append("));\n");         }         xlsHeaders.append("  \nFOR i IN 1..p_type.count\n" + "    loop\n"                 + "    row_num := row_num + 1;\n"                 + "    as_xlsx.set_row(row_num, p_fontId => as_xlsx.get_font('")                 .append(xlsFont)                 .append("', p_fontsize => ").append(rowsFontSize)                 .append("), p_borderId => as_xlsx.get_border);\n")                 .append("    as_xlsx.set_row_height(row_num, ")                 .append(rowHeight)                 .append(");\n    --\n");          // rows         for (int i = 0; i < pColumns.length; i++) {             int x = i + 1;             xlsHeaders.append("    as_xlsx.cell(")                     .append(x).append(", i + 1, coalesce(p_type(i).").append(pColumns[i][2]).append(", '-'), ")                     .append("p_alignment => as_xlsx.get_alignment(\n")                     .append("p_horizontal => '").append(horizontalAlignment).append("', ")                     .append("p_vertical => '").append(verticalAlignment).append("', ")                     .append("p_wraptext => ").append(wrapText)                     .append("), p_fontId => as_xlsx.get_font('")                     .append(rowsFont)                     .append("', p_fontsize => ")                     .append(rowsFontSize)                     .append(", p_bold => ")                     .append(rowsBold)                     .append(", p_italic => ")                     .append(rowsItalic)                     .append("));\n");         }         xlsHeaders.append("    end loop;\n"                 + "  v_file := as_xlsx.finish;\n"                 + "  RETURN v_file;\n"                 + "  exception\n"                 + "   when others then\n"                 + "    sb_util.write_log('package.")                 .append(functionName)                 .append(" ошибка: ' ||sqlerrm||chr(13)||dbms_utility.format_error_backtrace, 'info'); \n")                 .append("END;\n\n");          // Формирование процедуры для скачивания файла         xlsHeaders.append("-- procedure\n");         xlsHeaders.append("procedure ").append(procedureName).append(" is\n")                 .append("  l_file BLOB;\n")                 .append("  l_type ").append(typeTableName).append(";\n")                 .append("begin\n")                 .append("  select ");         for (Object[] column : pColumns) {             xlsHeaders.append(column[2]).append(", ");         }         xlsHeaders.deleteCharAt(xlsHeaders.length() - 2).append("\n");         xlsHeaders.append("    bulk collect into l_type\n    from ")                 .append(tableOrViewName).append("\n");         xlsHeaders.append("   where column_name between sysdate and sysdate + 1;\n" + "\n" + "  l_file := ")                 .append(functionName).append("(l_type);\n").append("\n")                 .append("  if lengthb(l_file) > 0 then\n")                 .append("    api_datasource.setColumnValue('BLOB_DUAL_ds.blob', l_file);\n")                 .append("    api_datasource.download('BLOB_DUAL_ds.blob', file_name||'.xlsx');\n")                 .append("  end if;\n\n")                 .append("exception\n" + "  when others then\n" + "    sb_util.write_log('package.")                 .append(procedureName)                 .append(" ошибка: ' || sqlerrm ||chr(13)||dbms_utility.format_error_backtrace, 'info');\n")                 .append("end;");          return xlsHeaders.toString();     } }

Класс WriteToFile выгружает запросы в формате txt в указанное вами место (по умолчанию — на Рабочий стол):

package QueriesCreater;  import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets;  public class WriteToFile {     void write(String pSql) {         //Save file to         FileNameExtensionFilter filter = new FileNameExtensionFilter("*.txt", "*.txt", "*.TXT", "*.*");         JFileChooser save_to = new JFileChooser();         save_to.setFileFilter(filter);         save_to.setCurrentDirectory(new File                 (System.getProperty("user.home") + System.getProperty("file.separator") + "Desktop"));         int ret = save_to.showDialog(null, "Save");         if (ret == JFileChooser.APPROVE_OPTION) {             try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(save_to.getSelectedFile() + ".txt"), StandardCharsets.UTF_8)) {                 writer.write(pSql);                 writer.flush();             } catch (IOException e) {                 e.printStackTrace();             }         }     } }

Завершает парад классов — данный код:

package QueriesCreater;  public class Main {     public static void main(String[] args) {         new Gui();     } }

В итоге после ввода нужных нам столбцов

и нажатия кнопки «Create objects» — получаем следующие запросы:

-- Package specification -- version 1 type t_type_of_record is record ( 	DB_ID table_or_view.DB_ID%TYPE, 	DB_NAME table_or_view.DB_NAME%TYPE, 	DB_DATE table_or_view.DB_DATE%TYPE );  -- version 2 type t_type_of_record is record ( 	DB_ID NUMBER, 	DB_NAME VARCHAR2(69), 	DB_DATE DATE );  type t_type_of_record_tbl is table of t_type_of_record;  function get_xls_function(p_type in t_type_of_record_tbl) return blob;  -- Package body -- function function get_xls_function(p_type in t_type_of_record_tbl) return blob is   row_num number := 0;   v_file  blob; begin   as_xlsx.clear_workbook;   as_xlsx.new_sheet('tab1');   row_num := row_num + 1;   as_xlsx.set_row(row_num, p_fontId => as_xlsx.get_font('Times New Roman', p_fontsize => 13, p_bold => true),   p_fillId => as_xlsx.get_fill('solid', 'FFCC66'), p_borderId => as_xlsx.get_border); 	-- headers 	as_xlsx.set_row_height(1, 25); 	as_xlsx.set_column_width(1, 20); as_xlsx.cell(1, 1, 'id', p_alignment => as_xlsx.get_alignment (p_horizontal => 'center', p_vertical => 'center', p_wraptext => true)); 	as_xlsx.set_column_width(2, 50); as_xlsx.cell(2, 1, 'name', p_alignment => as_xlsx.get_alignment (p_horizontal => 'center', p_vertical => 'center', p_wraptext => true)); 	as_xlsx.set_column_width(3, 40); as_xlsx.cell(3, 1, 'date', p_alignment => as_xlsx.get_alignment (p_horizontal => 'center', p_vertical => 'center', p_wraptext => true));    FOR i IN 1..p_type.count     loop     row_num := row_num + 1;     as_xlsx.set_row(row_num, p_fontId => as_xlsx.get_font('Times New Roman', p_fontsize => 12), p_borderId => as_xlsx.get_border);     as_xlsx.set_row_height(row_num, 25);     --     as_xlsx.cell(1, i + 1, coalesce(p_type(i).DB_ID, '-'), p_alignment => as_xlsx.get_alignment( p_horizontal => 'center', p_vertical => 'center', p_wraptext => true), p_fontId => as_xlsx.get_font('Times New Roman', p_fontsize => 12, p_bold => false, p_italic => false));     as_xlsx.cell(2, i + 1, coalesce(p_type(i).DB_NAME, '-'), p_alignment => as_xlsx.get_alignment( p_horizontal => 'center', p_vertical => 'center', p_wraptext => true), p_fontId => as_xlsx.get_font('Times New Roman', p_fontsize => 12, p_bold => false, p_italic => false));     as_xlsx.cell(3, i + 1, coalesce(p_type(i).DB_DATE, '-'), p_alignment => as_xlsx.get_alignment( p_horizontal => 'center', p_vertical => 'center', p_wraptext => true), p_fontId => as_xlsx.get_font('Times New Roman', p_fontsize => 12, p_bold => false, p_italic => false));     end loop;   v_file := as_xlsx.finish;   RETURN v_file;   exception    when others then     sb_util.write_log('package.get_xls_function ошибка: ' ||sqlerrm||chr(13)||dbms_utility.format_error_backtrace, 'info');  END;  -- procedure procedure get_xls_from_table is   l_file BLOB;   l_type t_type_of_record_tbl; begin   select DB_ID, DB_NAME, DB_DATE      bulk collect into l_type     from table_or_view    where column_name between sysdate and sysdate + 1;    l_file := get_xls_function(l_type);    if lengthb(l_file) > 0 then     api_datasource.setColumnValue('BLOB_DUAL_ds.blob', l_file);     api_datasource.download('BLOB_DUAL_ds.blob', file_name||'.xlsx');   end if;  exception   when others then     sb_util.write_log('package.get_xls_from_table ошибка: ' || sqlerrm ||chr(13)||dbms_utility.format_error_backtrace, 'info'); end;

Итоговый эксель-файл выглядит так:

Мне такая утилита пару лет назад очень бы помогла. Надеюсь Я кому-то помогу этим постом.

Спасибо за внимание!

ссылка на оригинал статьи https://habr.com/ru/post/567966/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *