当前位置: 首页 > 知识库问答 >
问题:

如何使用vaadin网格导出到CSV/Excel?

陆高峰
2023-03-14

在Vaadin 14+中,我正在创建网格,并希望用户有一个稳定/简单的方法将网格的内容导出到csv或Excel。要做到这一点,我感到惊讶的是,Vaadin似乎没有提供此功能,因此必须使用第三方开发插件(如https://Vaadin.com/directory/component/exporter/overview)。然而,这些插件有许多bug(例如不能将带有日期值的网格正确地导出到Excel等)。在Vaadin14中是否有一种推荐的方法来支持我认为是任何基于Web的网格小部件高度要求的特性?

共有1个答案

孟和怡
2023-03-14

不需要插件(在Vaadin中称为加载项)。

您需要理解grid小部件是用于表示的,而不是用于数据存储的。

每个Grid对象都由DataProvider提供支持,它负责访问数据存储区。要在网格中显示的数据可能来自内存中的某些对象,或者来自数据提要,或者来自数据库查询的结果,或者来自其他一些源。遵循关注点分离的设计原则,grid类只关心显示数据,而不是管理数据访问。DataProvider接口用于管理数据访问,而不是显示数据。因此gridDataProvider一起工作。

对于有限数量的基于all in memory的数据对象,我们可以使用DataProviderListDataProvider实现。当我们传递数据对象的集合时,可以自动为我们构建这个列表数据提供程序。

因此不从网格对象导出数据。相反,您希望侦听对DataProvider的更改,然后导出通过该数据提供程序获得的数据。

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

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对象作为示例数据集。这些对象被馈送到网格,为方便起见,网格生成ListDataProvider

我们有一个文本字段,用于编辑网格中表示的选定person对象的电话号码。

我们有一个导出按钮,它使用Apache Commons CSV库写出CSV文件。请注意从ListDataProvider访问数据项的关键行。首先,我们将数据提供程序强制转换为ListDataProvider,然后提取存储在其中的所有Person对象的集合。Java泛型提供类型安全,并授权编译器知道数据提供程序包含Person对象。

Collection < Person > persons = ( ( ListDataProvider < Person > ) grid.getDataProvider() ).getItems();
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 );
    }
}
 类似资料:
  • 使用Vaadin的Table类可以向表中添加操作处理程序。例如,在以前的Vaadin版本中,当用户在表格区域内单击鼠标右键时,屏幕上会显示以下2个选项: 行动。处理程序存在于Vaadin 8中,但是不可能添加操作。在Vaadin 8中处理网格,我也没有找到任何其他方法来创建上下文菜单。 在网格中使用操作框架的方法是什么?Grid是否有其他创建上下文菜单的方法?换句话说,上面的例子是如何写的。 现有

  • 我有一个表格数据,我需要在不使用任何外部插件或API的情况下导出到csv。我使用了

  • 我需要从网格(容器)中删除数据,然后我需要刷新行。我该怎么做? 现在我尝试只更改单元格而不删除项目。我的代码是 但是我也有错误…:( Morfic的信息: 我需要更改网格单元格中显示的数据。例如,我有3行,属性ID为firstNumber和secondNumber,第4行表示行的总和。所以,我从数据库中得到了一些数据。我需要包括一些数据手动“从键盘”到网格。。。 想象一下这种情况: firstNu

  • 问题内容: Vaadin 7中的和组件有什么区别? 我应该使用哪个,什么时候使用? 问题答案: Grid是一个功能更强大的新组件,它应该是Table的后继组件(请参阅Table已死,Grid长寿)。因此,应该没有任何必要偏爱表格而不是网格。 这是Vaadin从表格迁移到网格的一系列文章的第一篇:https : //vaadin.com/blog/-/blogs/mission-rip- table

  • 为了测试目的,我正在玩vaadin 14.2.2。然而,我立即使用网格解决了第一个问题。https://vaadin.com/docs/v14/flow/components/tutorial-flow-grid.html中的示例 不在可视化中生成输出。还有几个要使用的GitHub问题中的提示 不能解决这个问题。有人知道怎么解决这个问题吗?

  • 我需要制作瓦丁8网格单元格文本换行。我试着在瓦丁论坛上关注这个链接。https://vaadin.com/forum/thread/16908210/vaadin-8-grid-wrap-long-lines 我的网格仅在每个单元格中包含字符串。 我有一个这样的风格生成器类: 我正在从Vaadin 6转换,所以我仍然使用旧主题() 在我的styles.css文件中,有: 在创建网格的类中,我有: