Многие компании работают с Excel в течение десятилетий. Он мощный, но простой в использовании, однако одна из самых больших проблем с Excel заключается в том, что трудно интегрировать файл Excel с другими системами и службами, особенно с базой данных. Если вы загружаете файл Excel как вложение в систему, и вам необходимо загрузить его и открыть в Excel всякий раз, когда вам нужно отредактировать файл, вы просто используете Excel в автономном режиме. Это не комплексное решение.
В этой статье я покажу вам, как сделать так, чтобы ваш файл Excel работал без проблем в веб-приложении на основе базы данных.
Приложение для доступа к таблице базы данных
Предположим, у вас есть таблица, содержащая торговые записи в базе данных, и вам нужно показать эти торговые записи в виде пользовательского интерфейса, подобного электронной таблице, чтобы пользователи могли редактировать, фильтровать и вычислять данные с помощью формул Excel. Кроме того, ваши пользователи капризны — цвет, формат и стиль пользовательского интерфейса могут время от времени меняться, поэтому его будет легко обновлять в будущем.
Вам также может понравиться:
Превратить ваш файл Excel в веб-приложение
Шаблонный подход
Чтобы выполнить вышеуказанные требования, я хотел бы познакомить вас с подходом на основе шаблонов: использовать файл Excel в качестве шаблона и заполнить данные из базы данных в шаблон.
В архитектурном представлении я делю приложение на 3 части: модель, вид, контроллер .
- Модель : данные из базы данных
- Вид : файл шаблона
- Контроллер : слушатель событий из View и заполнение данных из базы данных
Сопоставляя их с моей реализацией, это:
Keikai Spreadsheet (Просмотреть) — DatabaseComposer
(Контроллер) — MyDataService
(Модель)
Реализация
обзор
Предположим, что есть таблица торговых рекордов:
Подготовьте файл Excel в качестве шаблона:
Сочетая шаблон и данные, полученное в результате веб-приложение будет выглядеть так:
Конечный пользователь может:
- редактировать ячейки и сохранять обратно в базу данных
- перезагрузить данные из базы данных
Построить пользовательский интерфейс
В этом приложении я использую компонент веб-таблиц с открытым исходным кодом Keikai . Keikai основан на инфраструктуре пользовательского интерфейса ZK , поэтому я могу построить пользовательский интерфейс в ZUL, используя также другие компоненты ZK. ZUL — это язык формата XML, где каждый тег представляет компонент, поэтому я могу создать такой интерфейс:
HTML
xxxxxxxxxx
1
<spreadsheet id="ss" width="100%" height="200px"
2
showFormulabar="true" showContextMenu="false" showToolbar="false"
3
showSheetbar="false" maxVisibleRows="11" maxVisibleColumns="4"
4
src="/WEB-INF/books/tradeTemplate.xlsx"></div>
5
<div style="margin: 10px 5px 10px 0px; text-align: right">
6
<button id="save" label="Save to Database" ></button>
7
<button id="load" label="Load from Database" disabled="true"></button>
8
</div>
Строка 4 : вы можете загрузить файл динамически через Java API, Spreadsheet :: setSrc или Importer .
Keikai может загрузить файл Excel и отобразить его содержимое в браузере. После визуализации конечные пользователи могут просматривать и редактировать электронную таблицу в браузере в стиле Excel.
контроллер
Контроллер для Keikai — это класс Java, который расширяет ZK SelectorComposer
и взаимодействует с базой данных посредством MyDataService
.
Джава
xxxxxxxxxx
1
public class DatabaseComposer extends SelectorComposer<Component> {
2
private MyDataService dataService = new MyDataService();
4
5
private Spreadsheet ss;
6
...
7
}
строка 4 : @Wire
в поле члена базовая структура ZK может внедрить Spreadsheet
объект keikai, созданный в соответствии с zul, так что вы можете управлять keikai с помощью его метода.
Применить к странице
Нам нужно связаться DatabaseComposer
со страницей ZUL (database.zul), чтобы контроллер мог прослушивать события и управлять компонентами через API.
Укажите полное имя класса в apply
атрибуте, и Keikai автоматически создаст его экземпляр при посещении страницы. Контроллер может контролировать корневой компонент <hlayout>
и все его дочерние компоненты (эти внутренние теги).
XML
xxxxxxxxxx
1
<hlayout width="100%" vflex="1" apply="io.keikai.tutorial.database.DatabaseComposer">
2
...
3
<spreadsheet ></spreadsheet>
4
<hlayout>
Range API
Для каждой операции ячейка / строка / столбец Range
сначала нужно получить объект. Он может представлять одну или несколько ячеек, строку, столбец, лист или книгу. Так же, как вам нужно выбрать ячейку с помощью мыши, прежде чем предпринимать какие-либо действия для редактирования
Вспомогательный класс Ranges
поддерживает различные методы для создания Range
объекта, такого как:
Джава
xxxxxxxxxx
1
// a book
2
Ranges.range(spreadsheet.getBook());
3
// a sheet
4
Ranges.range(spreadsheet.getSelectedSheet());
5
// a row
6
Ranges.range(spreadsheet.getSelectedSheet(), "A1").toRowRange();
7
// a cell
8
Ranges.range(spreadsheet.getSelectedSheet(), 3, 3);
9
// multiple cells
10
Ranges.range(spreadsheet.getSelectedSheet(), "A1:B4");
11
Ranges.range(spreadsheet.getSelectedSheet(), 0, 0, 3, 1);
Получение a Range
для одной ячейки требует листа, индекса строки и индекса столбца в качестве координаты, а получение нескольких ячеек требует начального и конечного индекса строки / столбца.
С Range
объектом вы можете выполнить действие, подобное setValue()
или getValue()
.
Заполните данные в ячейках
После того, как вы запросите одну или несколько Trade
из базы данных, вы можете заполнить ее в целевые ячейки с помощью Range
установщика:
Джава
xxxxxxxxxx
1
//column index
2
public static int ID = 0;
3
public static int TYPE = 1;
4
public static int SALESPERSON = 2;
5
public static int SALES = 3;
6
...
7
private void load(Trade trade, int row) {
8
Sheet sheet = ss.getSelectedSheet();
9
Ranges.range(sheet, row, ID).setCellValue(trade.getId());
10
Ranges.range(sheet, row, TYPE).setCellValue(trade.getType());
11
Ranges.range(sheet, row, SALESPERSON).setCellValue(trade.getSalesPerson());
12
Ranges.range(sheet, row, SALES).setCellValue(trade.getSale());
13
}
Слушать события
На странице есть 2 кнопки, которые нам нужны, чтобы прослушать событие их нажатия и реализовать логику связанного приложения. Укажите идентификатор 2 кнопок, чтобы вы могли легко слушать их события.
XML
xxxxxxxxxx
1
<button id="save" label="Save to Database" />
2
<button id="load" label="Load from Database" disabled="true"/>
Аннотируйте метод с помощью @Listen, чтобы превратить его в метод прослушивания событий с помощью синтаксиса, подобного селектору CSS, ниже:
Джава
xxxxxxxxxx
1
"onClick = #load") (
Это означает, что вы хотите прослушать onClick
событие, #load
представляющее компонент с идентификатором load
. Для получения дополнительной синтаксиса, пожалуйста, обратитесь к SelectorComposer
Javadoc . Поэтому, когда пользователь нажимает кнопку «Загрузить из базы данных», DatabaseComposer::load()
будет вызвано.
Джава
xxxxxxxxxx
1
//Load from Database
2
"onClick = #load") (
3
public void load(){
4
reload();
5
...
6
}
7
//Save to Database
9
"onClick = #save") (
10
public void save(){
11
dataService.save(modifiedTrades);
12
...
13
}
Затем вы можете реализовать связанную логику приложения в каждом слушателе в соответствии с требованиями.
Сохранить данные в таблицу
Перед сохранением Trade
, вам нужно извлечь пользовательский ввод из ячеек с помощью геттера. Вам все еще нужно Range
, но на этот раз вам позвонят лучше, например:
Джава
xxxxxxxxxx
1
private Trade extract(int row ){
2
Sheet sheet = ss.getSelectedSheet();
3
Trade trade = new Trade(extractInt(Ranges.range(sheet, row, ID)));
4
trade.setType(Ranges.range(sheet, row, TYPE).getCellEditText());
5
trade.setSalesPerson(Ranges.range(sheet, row, SALESPERSON).getCellEditText());
6
trade.setSale(extractInt(Ranges.range(sheet, row, SALES)));
7
return trade;
8
}
9
private int extractInt(Range cell){
11
CellData cellData = cell.getCellData();
12
return cellData.getDoubleValue() == null ? 0 : cellData.getDoubleValue().intValue();
13
}
строка 12 : Осторожно - если ячейка пуста, CellData::getDoubleValue()
возвращает ноль.
Класс персистентности
Чтобы было проще понять, я создал класс MyDataService
для обработки запросов и обновлений (имитируемой) базы данных. Он может запросить коллекцию Trade
объектов для нас, чтобы заполнить в Keikai и сохранить Trade
объекты в базе данных.
В вашем реальном приложении вы можете реализовать свои классы персистентного слоя в соответствии со своими предпочтениями. Здесь нет никаких ограничений, вы можете использовать Hibernate или JDBC или любые другие решения Java, которые вам нравятся.
Это завершает пример приложения.
Почему шаблонный подход?
Прежде чем закончить статью, я бы хотел немного поговорить о том, почему я решил использовать этот шаблонный подход.
Поддержка шаблонов экспертами в области
Если вы строите финансовую систему, очевидно, лучше позволить финансовым экспертам создавать свои таблицы и модели, а не просить разработчика программного обеспечения сделать это. При использовании подхода на основе шаблонов эксперты в области могут сами создавать / поддерживать шаблоны Excel, не пытаясь объяснить разработчикам программного обеспечения все. Кроме того, после изменения файла Excel вы можете просто заменить файл шаблона новым, не обновляя код Java.
Разделите дисплей и данные
В этом примере, поскольку данные не хранятся в файле, легко изменить обе стороны: шаблон и данные . Вы можете применить другой шаблон или импортировать другой набор торговых записей в зависимости от контекста.
Легко интегрируется с другими бэкэнд-системами
Поскольку Keikai управляется классом контроллера Java, его легко интегрировать с любым бэкэндом на основе Java, и нет никаких ограничений для подключения к базе данных.
Исходный код
Надеюсь, вам понравилось читать мою статью. Посетите GitHub, чтобы получить полный исходный код, упомянутый в этой статье.