Vaadin:如何显示 MySQL 数据库中的数据? [英] Vaadin: How do I display data from a MySQL database?

查看:39
本文介绍了Vaadin:如何显示 MySQL 数据库中的数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发 Vaadin Flow(14.1 版)应用程序,但遇到了这个问题,我无法将其直接连接到 MySQL 数据库.

I'm developing a Vaadin Flow (version 14.1) app and I have this issue, I don't get it to connect directly with MySQL database.

我已经建立了与 maven 的 JDBC 连接,我还创建了一个名为 Datasource 的单例类,用于存储我的值和方法.但是现在它只有一个,因为我正在测试这个,这就是我想要做的:

I have set up the JDBC connection with maven, I've also created a singleton class I call Datasource where I store my values and methods. However right now it only has one as I'm testing this, this is what I want to do:

  • 点击应用上的按钮并更新标签

这是按钮点击监听器:

button.addClickListener(click -> {
        label.setText(Datasource.getInstance().getUsername());
    });

这是数据源类方法:

public String getUsername() {
    String username = "QUERY-FAILED";

    try {
        start();
        statement = conn.createStatement();
        ResultSet rs = statement.executeQuery("select * from names");

        rs.next();
        username = rs.getString(1);
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close();
    }

    return username;
}

但是标签不会更新,如果我评论 try 块,它会更新为 QUERY-FAILED,这是我用来测试是否失败的字符串,但如果没有评论标签,则标签保持不变.

But the label doesn't update, if I comment the try block it updates to QUERY-FAILED which is the string I put to test if it failed, but if it isn't commented the label just stays the same.

我还尝试向 Datasource 类添加一个 main 方法并将其作为 Java 应用程序运行,该方法工作正常,它确实返回了一个带有用户名的字符串.所以我猜我被困在与 vaadin 应用程序的连接之间.另外,如果我在启动应用程序时尝试在我的 vaadin 应用程序中获取用户名字符串(而不是使用点击侦听器),我会收到一长串错误,数据源在此处指示空指针异常:

I also tried to add a main method to the Datasource class and run it as a Java application, and the method works fine, it does return a string with the username. So I'm guessing I'm stuck somewhere in between the connection with the vaadin app. Also, If I try to get the username String in my vaadin app when I'm starting the app (and not with a click listener) I got an long stack of errors with the Datasource indicating a nullpointerexception here:

statement = conn.createStatement();

提前致谢!

推荐答案

我无法发现您的代码有任何问题.但我可以提供一个完整的工作示例应用程序供您比较

I cannot spot any problem with your code. But I can provide an entire working example app for you to compare

我的示例应用程序遵循您的问题代码中列出的内容.Vaadin Button 使用用户名表中的 DataSource 对象执行数据库查询.找到的第一行的值显示在网页上的 Vaadin Label 小部件中.

My example app goes along the lines laid out in your Question's code. A Vaadin Button performs a database query using a DataSource object from a table of user names. The value from the first row found is displayed in a Vaadin Label widget on the web page.

此应用程序是在 Vaadin 14.1.5 上构建并运行的,使用的是入门项目的Plain Java Servlet"风格由 Vaadin.com 网站提供.使用捆绑的 Jetty Web 容器在 macOS Mojave 上运行.

This app was built and run with Vaadin 14.1.5 using a "Plain Java Servlet" flavor of a starter project provided by the Vaadin.com site. Running on macOS Mojave with the bundled Jetty web container.

我对他们的 Maven POM 文件的唯一更改是更改为 Java 版本 13,并添加对 H2 数据库引擎 使其成为使用内存数据库的独立示例.

My only changes to their Maven POM file was to change to Java version 13, and to add a dependency for H2 Database Engine to make this a self-contained example using an in-memory database.

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.200</version>
    </dependency>

我使用了 Vaadin 启动的钩子来建立我的 DataSource 对象并初始化数据库.按照手册,嵌套在resources 文件夹,我创建了文件夹 META-INF > services.根据 Java SPI 工具,我在那里创建了一个名为 com.vaadin.flow 的文件.server.VaadinServiceInitListener 包含一行来指定我的类的名称,该类实现以该文件的名称命名的接口:

I used the hook for Vaadin starting, to establish my DataSource object and initialize the database. Following the manual, nested in the resources folder, I created folders META-INF > services. Per the Java SPI facility, there I created a file named com.vaadin.flow.server.VaadinServiceInitListener containing a single line to specify the name of my class that implements the interface named in the name of this file:

work.basil.example.ApplicationServiceInitListener

也就是说,我的ApplicationServiceInitListener 类实现了 Vaadin 接口 VaadinServiceInitListener.当我的 Vaadin Web 应用程序启动时,我的类将被自动实例化并通过该 Java SPI 工具调用它的方法.

That is, my ApplicationServiceInitListener class implement the Vaadin interface VaadinServiceInitListener. My class will be automatically instantiated and its method invoked via that Java SPI facility when my Vaadin web app launches.

我的ApplicationServiceInitListener 类:

package work.basil.example;

import com.vaadin.flow.server.ServiceInitEvent;
import com.vaadin.flow.server.VaadinServiceInitListener;
import org.h2.jdbcx.JdbcDataSource;

public class ApplicationServiceInitListener implements VaadinServiceInitListener
{
    @Override
    public void serviceInit ( ServiceInitEvent serviceInitEvent )
    {
        System.out.println( "DEBUG Running `serviceInit` of " + this.getClass().getCanonicalName() );

        // Database work.
        prepareDataSource();
        App.INSTANCE.provideDatabase().initializeDatabase();
    }

    private void prepareDataSource ( )
    {
        JdbcDataSource ds = new JdbcDataSource();
        ds.setURL( "jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1" );
        ds.setUser( "scott" );
        ds.setPassword( "tiger" );
        App.INSTANCE.rememberDataSource( ds );
    }
}

那个类调用我的 App 类,它充当一种 服务定位器.通过 单身javase/tutorial/java/javaOO/enum.html" rel="nofollow noreferrer">enum.

That class calls my App class which acts as a sort of service locator. Designed as a singleton via enum.

package work.basil.example;

import javax.sql.DataSource;
import java.util.Objects;

public enum App
{
    INSTANCE;

    // -------|  DataSource  |---------------------------------
    private DataSource dataSource;

    public DataSource provideDataSource ( )
    {
        return this.dataSource;
    }

    public void rememberDataSource ( DataSource dataSource )
    {
        this.dataSource = Objects.requireNonNull( dataSource );
    }


    // -------|  Database  |---------------------------------
    private Database database;

    public Database provideDatabase ( )
    {
        return new Database();
    }
}

那个类调用我的Database 类.在实际工作中,Database 将是一个接口,具有用于测试和部署的各种具体实现.出于演示目的,我在这里忽略了这一点.

That class calls my Database class. In real work, Database would be an interface with various concrete implementations for testing versus deployment. I ignored that here for demonstration purposes.

package work.basil.example;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Database
{
    public String getFirstUserName ( )
    {
        String userName = "QUERY-FAILED";

        String newline = "\n";
        StringBuilder sql = new StringBuilder();
        sql.append( "SELECT name_ from  user_ ; " ).append( newline );
        System.out.println( "sql = " + sql );
        try (
                Connection conn = App.INSTANCE.provideDataSource().getConnection() ;
                Statement statement = conn.createStatement() ;
                ResultSet resultSet = statement.executeQuery( sql.toString() ) ;
        )
        {
            while ( resultSet.next() )
            {
                userName = resultSet.getString( "name_" );
                break; // Go no further. We need only the first row found.
            }
        }
        catch ( SQLException e )
        {
            e.printStackTrace();
        }

        return userName;
    }

    public void initializeDatabase ( )
    {
        System.out.println( "DEBUG Running `initializeDatabase` of " + this.getClass().getCanonicalName() );
        String newline = "\n";

        // Create table.
        StringBuilder sql = new StringBuilder();
        sql.append( "CREATE TABLE user_ ( " ).append( newline );
        sql.append( "pkey_ IDENTITY NOT NULL PRIMARY KEY , " ).append( newline );  // `identity` = auto-incrementing long integer.
        sql.append( "name_ VARCHAR NOT NULL " ).append( newline );
        sql.append( ") " ).append( newline );
        sql.append( ";" ).append( newline );
        System.out.println( "sql = " + sql );
        try (
                Connection conn = App.INSTANCE.provideDataSource().getConnection() ;
                Statement statement = conn.createStatement() ;
        )
        {
            statement.executeUpdate( sql.toString() );
        }
        catch ( SQLException e )
        {
            e.printStackTrace();
        }
        System.out.println("DEBUG Finished `CREATE TABLE` statement.");

        // Populate table.
        sql = new StringBuilder();
        sql.append( "INSERT INTO user_ ( name_ ) " ).append( newline );
        sql.append( "VALUES " ).append( newline );
        sql.append( "( 'Alice' ) , " ).append( newline );
        sql.append( "( 'Bob' ) , " ).append( newline );
        sql.append( "( 'Carol' ) " ).append( newline );
        sql.append( ";" ).append( newline );
        System.out.println( "sql = " + sql );
        try (
                Connection conn = App.INSTANCE.provideDataSource().getConnection() ;
                Statement statement = conn.createStatement() ;
        )
        {
            int rowsAffected = statement.executeUpdate( sql.toString() );
            System.out.println( "DEBUG Inserted rows into name_ table: " + rowsAffected );
        }
        catch ( SQLException e )
        {
            e.printStackTrace();
        }
        System.out.println("DEBUG Finished `INSERT` statement.");
    }
}

最后是 MainView 类.我禁用了 @PWA 注释,因为我们没有将该功能用于渐进式网络应用程序.

And lastly, the MainView class. I disable the @PWA annotation as we are not using that feature for progressive web apps.

package work.basil.example;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;

/**
 * The main view contains a button and a click listener.
 */
@Route ( "" )
//@PWA ( name = "Project Base for Vaadin", shortName = "Project Base" )
public class MainView extends VerticalLayout
{
    private Label label;
    private Button button;

    public MainView ( )
    {
        // Widgets
        this.label = new Label( "User: ?" );
        this.button = new Button(
                "Get user" ,
                event -> {
                    Notification.show( "Getting user." );
                    String userName = App.INSTANCE.provideDatabase().getFirstUserName();
                    this.label.setText( "User: " + userName );
                }
        );
        add( button );

        // Arrange
        this.add( label , button );
    }
}

这篇关于Vaadin:如何显示 MySQL 数据库中的数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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