如何使用vaadin网格导出到csv/excel? [英] how to export to csv/excel using vaadin grids?

查看:161
本文介绍了如何使用vaadin网格导出到csv/excel?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Vaadin 14+中,我正在创建网格,希望用户能够以一种稳定/便捷的方式将网格的内容导出到csv或(最好是Excel)中.为此,我很惊讶Vaadin似乎没有提供此功能,因此必须使用第三方开发者插件(例如 https://vaadin.com/directory/component/exporter/overview ).但是,这些插件有许多错误(例如,无法将具有日期值的网格正确导出到Excel等).在Vaadin 14中是否有推荐的方法来支持我认为是任何基于Web的网格小部件所要求的功能?

In Vaadin 14+, I'm creating grids and would like the users to have a stable/easy way to export the grid's contents to csv or, preferablly, Excel. To do so, I was surprised that Vaadin does not appear to provide this functionality, and so one has to use 3rd party developer plugins (such as https://vaadin.com/directory/component/exporter/overview). However, these plugins have numerous bugs (eg can't export grids with date values correctly to Excel etc.). Is there a recommended approach in Vaadin 14 to supporting what I would assume is a highly requested feature of any web-based grid widget?

推荐答案

无需插件(在Vaadin中称为附加组件).

No need for plugins (called add-ons in Vaadin).

您需要了解 Grid 小部件用于演示文稿,而不用于数据存储.

You need to understand that a Grid widget is for presentation, not data storage.

每个Grid对象都有关注点分离的设计原则,Grid类仅与显示数据有关,不管理数据访问. DataProvider界面与管理数据访问有关,不显示数据.因此GridDataProvider一起工作.

Each Grid object is backed by a DataProvider, which is responsible for accessing the data store. The data to be displayed in a Grid might come from some objects in memory, or from a data feed, or from the results of a database query, or from some other source. Following the design principle of separation of concerns, the Grid class is concerned only with displaying data, not managing data access. The DataProvider interface is concerned with managing data access, not displaying data. So Grid and DataProvider work together.

对于全部基于内存的有限数量的数据对象,我们可以使用

For a limited number of data objects based all in memory, we can use a ListDataProvider implementation of DataProvider. This list data provider can be built automatically for us when we pass a collection of our data objects.

因此,您不会从Grid对象导出数据.相反,您要侦听DataProvider的更改,然后提供通过该数据提供程序获取的导出数据.

So you do not export data from the Grid object. Instead, you want to listen for changes to the DataProvider, and then offer exporting data obtained through that data provider.

DataProvider中没有内置的导出功能.您可以利用DataProvider实现中可用的数据编写自己的导出功能.您可以在许多基于Java的库之间进行选择,以帮助为导出的数据编写数据文件.在下面显示的代码中,我们使用 Apache Commons CSV 库来编写制表符分隔或逗号分隔的值.

There is no built-in export feature in DataProvider. You can write your own export feature while drawing upon the data made available in the DataProvider implementation. You can choose between many Java-based libraries to assist in writing data files for your exported data. In the code shown below, we use the Apache Commons CSV library for writing tab-delimited or comma-separated values.

这是一个完整的示例应用程序.

Here is a complete example app.

我们有一个简单的Person类,用于保存名称和电话号码.

We have a simple Person class to hold a name and a phone number.

package work.basil.example;

import java.util.Objects;

public class Person
{
    //---------------|  Member vars  |--------------------------------
    private String name, phone;


    //---------------|  Constructors  |--------------------------------

    public Person ( String name , String phone )
    {
        this.name = name;
        this.phone = phone;
    }


    //---------------|  Accessors  |--------------------------------

    public String getName ( ) { return this.name; }

    public void setName ( String name ) { this.name = name; }

    public String getPhone ( ) { return this.phone; }

    public void setPhone ( String phone ) { this.phone = phone; }


    //---------------|  Object  |--------------------------------


    @Override
    public boolean equals ( Object o )
    {
        if ( this == o ) return true;
        if ( o == null || getClass() != o.getClass() ) return false;
        Person person = ( Person ) o;
        return getName().equals( person.getName() );
    }

    @Override
    public int hashCode ( )
    {
        return Objects.hash( getName() );
    }
}

这是一个完整的Vaadin 14.1.18应用程序,可生成4个Person对象作为示例数据集.这些对象被馈送到Grid,为方便起见,该对象会生成ListDataProvider.

This is an entire Vaadin 14.1.18 app that generates 4 Person objects as a sample data set. Those objects are fed to a Grid, which produces a ListDataProvider for our convenience.

我们有一个文本字段,用于编辑网格中所选的Person对象的电话号码.

We have a text field for editing the phone number of the selected Person object represented in the grid.

我们还有一个导出按钮,该按钮使用 Apache Commons CSV 库编写一个 CSV 文件.注意,关键行是我们从ListDataProvider访问数据项的地方.首先,我们将数据提供程序转换为ListDataProvider,然后提取其中存储的所有Person对象的Collection. Java泛型提供类型安全性,并使编译器知道数据提供者包含对象.

And we have an export button which uses the Apache Commons CSV library to write out a CSV file. Notice the key line where we access the data items from the ListDataProvider. First we cast the data provider to ListDataProvider, then we extract a Collection of all the Person objects stored within. Java Generics provides type-safety, and empowers the compiler to know that the data provider contains Person objects.

Collection < Person > persons = ( ( ListDataProvider < Person > ) grid.getDataProvider() ).getItems();

随后是完整的Vaadin 14.1应用代码.

Complete Vaadin 14.1 app code follows.

package work.basil.example;

import com.vaadin.flow.component.AbstractField;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridSingleSelectionModel;
import com.vaadin.flow.component.html.Input;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.provider.ListDataProvider;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.PWA;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

/**
 * The main view contains a button and a click listener.
 */
@Route ( "" )
//@PWA ( name = "Project Base for Vaadin", shortName = "Project Base" )
@CssImport ( "./styles/shared-styles.css" )
@CssImport ( value = "./styles/vaadin-text-field-styles.css", themeFor = "vaadin-text-field" )
public class MainView extends VerticalLayout
{

    Grid < Person > grid;
    TextField phoneField;
    Button phoneSaveButton, exportButton;

    public MainView ( )
    {
        // Widgets
        List < Person > personList = new ArrayList <>( 4 );
        personList.add( new Person( "Alice" , "555.123.1234" ) );
        personList.add( new Person( "Bob" , "555.688.4787" ) );
        personList.add( new Person( "Carol" , "555.632.2664" ) );
        personList.add( new Person( "David" , "555.543.2323" ) );

        // Create a grid bound to the list
        grid = new Grid <>();
        grid.setItems( personList );
        grid.addColumn( Person :: getName ).setHeader( "Name" );
        grid.addColumn( Person :: getPhone ).setHeader( "Phone" );
        GridSingleSelectionModel < Person > singleSelect = ( GridSingleSelectionModel < Person > ) grid.getSelectionModel();
        singleSelect.setDeselectAllowed( false );
        singleSelect.addSingleSelectionListener( singleSelectionEvent -> {
                    Optional < Person > personOptional = singleSelectionEvent.getSelectedItem();
                    if ( personOptional.isPresent() )
                    {
                        this.phoneField.setValue( personOptional.get().getPhone() );
                    }
                }
        );

        phoneField = new TextField( "Phone:" );

        phoneSaveButton = new Button( "Update phone on person " );
        phoneSaveButton.addClickListener(
                ( ClickEvent < Button > clickEvent ) -> {
                    Optional < Person > personOptional = ( ( GridSingleSelectionModel < Person > ) grid.getSelectionModel() ).getSelectedItem();
                    if ( personOptional.isEmpty() )
                    {
                        Notification.show( "First, select a person in list." );
                    } else
                    {
                        Person person = personOptional.get();
                        person.setPhone( phoneField.getValue() );
                        grid.getDataProvider().refreshItem( person );
                    }
                }
        );

        exportButton = new Button( "Export" );
        exportButton.setEnabled( false );
        exportButton.addClickListener(
                ( ClickEvent < Button > clickEvent ) -> {
                    String fileName = "Persons_" + Instant.now().toString() + ".csv";
                    final String fileNamePath = "/Users/basilbourque/" + fileName;
                    try (
                            BufferedWriter writer = Files.newBufferedWriter( Paths.get( fileNamePath ) ) ;
                            CSVPrinter csvPrinter = new CSVPrinter( writer , CSVFormat.RFC4180.withHeader( "Name" , "Phone" ) ) ;
                    )
                    {
                        Collection < Person > persons = ( ( ListDataProvider < Person > ) grid.getDataProvider() ).getItems();
                        for ( Person person : persons )
                        {
                            csvPrinter.printRecord( person.getName() , person.getPhone() );
                        }
                    }
                    catch ( IOException e )
                    {
                        e.printStackTrace();
                    }

                    // Tell user.
                    Notification.show( "Exported to file in your home folder: " + fileName );
                }
        );
        grid.getDataProvider().addDataProviderListener( dataChangeEvent -> {
            exportButton.setEnabled( true );
        } );


        // Arrange
        this.add( grid , phoneField , phoneSaveButton , exportButton );
    }
}

顺便说一句,Apache Commons CSV提供了多种文件格式.通常,最好的方法是RFC 4180中定义的标准格式.但是您提到了Microsoft Excel,该库支持该格式.参见 CSVFormat 类.

By the way, Apache Commons CSV offers several varieties of file formats. Usually, the best would be the standard format defined in RFC 4180. But you mentioned Microsoft Excel, for which the library supports that variant. See the CSVFormat class.

这篇关于如何使用vaadin网格导出到csv/excel?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆