Вывод данных из базы данных пользователю в виде на Java - PullRequest
0 голосов
/ 03 сентября 2018

Я недавно начал изучать Java. Мне нужно написать веб-приложение на Java, где пользователь может выбрать нужный ему продукт из формы на домашней html-странице из выпадающего списка. Список продуктов хранится в таблице в базе данных (с использованием MySQL). Затем выбранный товар должен быть записан в таблицу «История заказов». Как вывести базу данных из базы в выпадающий список? Как реализовать выбор необходимого продукта для пользователя? Как я могу начать? У кого-нибудь есть небольшой пример?

1 Ответ

0 голосов
/ 15 сентября 2018

Vaadin

Вот полный рабочий пример использования Java с Vaadin Framework версии 8.5.2 для создания веб-приложения, в котором база данных, управляемая H2 Database Engine , отслеживает список продуктов ( 10 планет Солнечной системы). Виджет NativeSelect в Vaadin заполняется из List из Product объектов, загруженных из таблицы product_ в этой базе данных. Каждый раз, когда пользователь нажимает кнопку Order, заказ записывается в виде строки в таблице order_.

Вот простая диаграмма ERD для двух таблиц в базе данных.

Entity-relationship diagram of Product table and Order table

Пользователь сначала выбирает продукт планеты из выпадающего списка, затем нажимает кнопку «Заказать».

Под этой областью ввода данных вы видите пару Grid виджетов как задний ход в базу данных. Слева находится список товаров, который не меняется. Справа находится список всех заказов, который обновляется каждый раз, когда пользователь размещает заказ с помощью этой кнопки «Заказ».

Обратите внимание, что база данных находится в памяти, а не является постоянной, поскольку это всего лишь небольшая демонстрация. Поэтому каждый раз, когда вы запускаете приложение, база данных перестраивается с нуля. Таблица order_ начинается пустым при каждом запуске.

Наконец, это ни в коем случае не готовый к работе код, просто пример, демонстрирующий возможности. Только сейчас, когда снимал этот скриншот, я обнаружил ошибку, связанную с отсутствием выбора продукта. C’est la vie.

enter image description here

Подробнее см. В следующих разделах руководства Vaadin :

  • Кнопка - Обзор виджета кнопки.
  • NativeSelect - Быстрая демонстрация этого виджета выпадающего списка
  • Компоненты выбора - Обсуждение работы виджетов, таких как NativeSelect, в Vaadin
  • Сетка - Как использовать этот мощный виджет сетки данных.

Основной класс приложения

В основном шаблон, чтобы заставить Ваадина бежать. Важна пара линий посередине, для ProductPickerLayout.

package com.basilbourque.example;

import javax.servlet.annotation.WebServlet;

import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.*;

/**
 * This UI is the application entry point. A UI may either represent a browser window
 * (or tab) or some part of an HTML page where a Vaadin application is embedded.
 * <p>
 * The UI is initialized using {@link #init(VaadinRequest)}. This method is intended to be
 * overridden to add component to the user interface and initialize non-component functionality.
 */
@Theme ( "mytheme" )
public class MyUI extends UI {

    @Override
    protected void init ( VaadinRequest vaadinRequest ) {
        final Layout layout = new ProductPickerLayout();
        this.setContent( layout );
    }

    @WebServlet ( urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true )
    @VaadinServletConfiguration ( ui = MyUI.class, productionMode = false )
    public static class MyUIServlet extends VaadinServlet {
    }
}

Прослушиватель контекста сервлета

Реагирует на запуск и закрытие веб-приложения.

package com.basilbourque.example;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.time.Instant;

@WebListener
public class MyServletContextListener implements ServletContextListener {
    MyDatabaseService databaseService;

    @Override
    public void contextInitialized ( ServletContextEvent servletContextEvent ) {
        System.out.println( "TRACE - contextInitialized " + Instant.now() );

        // Database.
        MyDatabaseService db = new MyDatabaseService();
        db.establishDatabase();
    }

    @Override
    public void contextDestroyed ( ServletContextEvent servletContextEvent ) {
        // This method intentionally left blank.
    }
}

База данных класса обслуживания

Определяет и предварительно загружает базу данных. Предоставляет вставки и запросы для перемещения данных в базу данных и из нее.

package com.basilbourque.example;

import java.sql.*;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class MyDatabaseService {
    // ---------|  Members  |------------------------------------
    static final private String driverName = "org.h2.Driver";
    static final private String catalogName = "ProdPop";
    static final private String jdbcPath = "jdbc:h2:mem:" + MyDatabaseService.catalogName + ";DB_CLOSE_DELAY=-1";  // "jdbc:h2:mem:autogrid";  // Set delay to keep in-memory database even after last connection closed.
    static final private String productTableName = "product_";
    static final private String orderTableName = "order_";

    public void establishDatabase () {
        // Verify JDBC driver.
        try {
            Class.forName( MyDatabaseService.driverName );
        } catch ( ClassNotFoundException e ) {
            e.printStackTrace();
        }

        // Connect, and create database.
        try ( Connection conn = DriverManager.getConnection( MyDatabaseService.jdbcPath ) ;
        ) {
            String sql = null;

            // Create product_ table.
            // Columns: pkey_  name_
            try ( Statement stmt = conn.createStatement() ; ) {
                sql = "CREATE TABLE " + productTableName + " ( \n" +
                      " pkey_ IDENTITY PRIMARY KEY , \n" +
                      " name_ VARCHAR ( 80 ) NOT NULL \n" +
                      ") ; \n";
                System.out.println( "TRACE - SQL:\n" + sql );
                stmt.execute( sql );
            }
            System.out.println( "TRACE - Created table product_." );

            // Create order_ table.
            // Columns: pkey_  fkey_product_  when_ordered_
            try ( Statement stmt = conn.createStatement() ; ) {
                sql = "CREATE TABLE " + orderTableName + " ( \n" +
                      "  pkey_ IDENTITY PRIMARY KEY  , \n" +
                      "  fkey_product_ LONG NOT NULL , \n" +
                      "  when_ordered_  TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP  \n" +
                      ") ; \n" +
                      "ALTER TABLE " + orderTableName + " ADD FOREIGN KEY ( fkey_product_ ) REFERENCES product_ ( pkey_ ) ; \n "
                ;
                System.out.println( "TRACE - SQL:\n" + sql );
                stmt.execute( sql );
            }

            // List tables
            DatabaseMetaData md = conn.getMetaData();
            try ( ResultSet rs = md.getTables( null , null , null , null ) ) {
                while ( rs.next() ) {
                    System.out.println( rs.getString( 3 ) );
                }
            }

            // List columns of `product_` table.
            try ( ResultSet rs = md.getColumns( null , null , productTableName.toUpperCase( Locale.US ) , null ) ) {
                System.out.println( "Columns of table: " + productTableName );
                while ( rs.next() ) {
                    System.out.println( rs.getString( 4 ) + " | " + rs.getString( 5 ) + " | " + rs.getString( 6 ) ); // COLUMN_NAME, DATA_TYPE , TYPE_NAME.
                }
            }

            // List columns of `order_` table.
            try ( ResultSet rs = md.getColumns( null , null , orderTableName.toUpperCase( Locale.US ) , null ) ) {
                System.out.println( "Columns of table: " + orderTableName );
                while ( rs.next() ) {
                    System.out.println( rs.getString( 4 ) + " | " + rs.getString( 5 ) + " | " + rs.getString( 6 ) ); // COLUMN_NAME, DATA_TYPE , TYPE_NAME.
                }
            }

            // Add rows
            sql = "INSERT INTO product_ ( name_ ) \n" +
                  "VALUES ( ? ) " +
                  "; ";

            List< String > planets = List.of( "Mercury" , "Venus" , "Earth" , "Mars" , "Ceres" , "Jupiter" , "Saturn" , "Uranus" , "Neptune" , "Pluto" );
            try ( PreparedStatement ps = conn.prepareStatement( sql ) ; ) {
                for ( String planet : planets ) {
                    ps.setString( 1 , planet );
                    ps.executeUpdate();
                }
            }

            System.out.println( "TRACE - Dumping tables in their initial state. " + Instant.now() );
            this.dumpTableToConsole( MyDatabaseService.productTableName );
            this.dumpTableToConsole( MyDatabaseService.orderTableName );
        } catch ( SQLException e ) {
            e.printStackTrace();
        }
    }

    public void dumpTableToConsole ( String tableName ) {

        try ( Connection conn = DriverManager.getConnection( MyDatabaseService.jdbcPath ) ;
        ) {
            System.out.println( "TRACE - « " + tableName + " » table dump to console at " + Instant.now() );
            String sql = "SELECT * FROM " + tableName + " ;";
            try ( Statement stmt = conn.createStatement() ;
                  ResultSet rs = stmt.executeQuery( sql ) ; ) {
                ResultSetMetaData meta = rs.getMetaData();
                int colCount = meta.getColumnCount();
                int rowCount = 0;
                while ( rs.next() ) {
                    rowCount++;
                    System.out.print( "Row # " + rowCount + ": " );
                    for ( int col = 1 ; col <= colCount ; col++ ) {
                        System.out.print( meta.getColumnLabel( col ) + "=" );
                        Object o = rs.getObject( col );
                        if ( null != o ) {
                            System.out.print( o.toString() + " " );
                        }
                    }
                    System.out.println( "" ); // Newline.
                }
                System.out.println( "« fin de " + tableName + " »" );
            }
        } catch ( SQLException e ) {
            e.printStackTrace();
        }
    }

    public List< Product > fetchAllProducts () {
        System.out.println( "TRACE MyDatabaseService::fetchAllOrders at " + Instant.now() );

        List< Product > products = new ArrayList<>();

        // Query. Loop ResultSet, instantiating object, and collecting.
        try ( Connection conn = DriverManager.getConnection( MyDatabaseService.jdbcPath ) ;
        ) {
            System.out.println( "TRACE - fetchAllProducts at " + Instant.now() );
            String sql = "SELECT * FROM " + productTableName + " ;";
            try (
            Statement stmt = conn.createStatement() ;
            ResultSet rs = stmt.executeQuery( sql ) ;
            ) {
                int rowCount = 0;
                while ( rs.next() ) {
                    Long pkey = rs.getLong( "pkey_" );
                    String name = rs.getString( "name_" );
                    // Make object from column values.
                    Product p = new Product( pkey , name );
                    products.add( p ); // Collect each `Order` object retrieved from database.
                }
            }
        } catch ( SQLException e ) {
            e.printStackTrace();
        }

        return products;
    }

    public List< Order > fetchAllOrders () {
        System.out.println( "TRACE MyDatabaseService::fetchAllOrders at " + Instant.now() );

        List< Order > orders = new ArrayList<>();

        // Query. Loop ResultSet, instantiating object, and collecting.
        try ( Connection conn = DriverManager.getConnection( MyDatabaseService.jdbcPath ) ;
        ) {
            String sql = "SELECT * FROM " + orderTableName + " \n ORDER BY pkey_ DESC \n ;";
            try (
            Statement stmt = conn.createStatement() ;
            ResultSet rs = stmt.executeQuery( sql ) ;
            ) {
                int rowCount = 0;
                while ( rs.next() ) {
                    Long pkey = rs.getLong( "pkey_" );
                    Long fkey_product = rs.getLong( "fkey_product_" );
                    Instant when_ordered = rs.getObject( "when_ordered_" , Instant.class );
                    // Make object from column values.
                    Order o = new Order( pkey , fkey_product , when_ordered );
                    orders.add( o ); // Collect each `Order` object retrieved from database.
                }
            }
        } catch ( SQLException e ) {
            e.printStackTrace();
        }

        return orders;
    }

    public void insertOrder ( Long fkeyProduct ) {
        System.out.println( "TRACE - MyDatabaseService::insertOrder at " + Instant.now() );
        try ( Connection conn = DriverManager.getConnection( MyDatabaseService.jdbcPath ) ;
        ) {
            String sql = "INSERT INTO " + orderTableName + "( fkey_product_ )\n" + " VALUES ( ? ) ;\n";
            PreparedStatement ps = conn.prepareStatement( sql );
            ps.setLong( 1 , fkeyProduct );
            ps.executeUpdate();
        } catch ( SQLException e ) {
            e.printStackTrace();
        }
    }
}

Макет контента

Отображает наши виджеты: раскрывающийся список продуктов NativeSelect, кнопка заказа и пара Grid сеток данных. Служит видом и контроллером для взаимодействия с нашим пользователем.

package com.basilbourque.example;

import com.vaadin.data.HasValue;
import com.vaadin.data.HasValue.ValueChangeEvent;
import com.vaadin.ui.*;

import java.time.Instant;
import java.util.List;

public class ProductPickerLayout extends VerticalLayout {
    Label prodPopLabel;
    NativeSelect< Product > productSelect;
    Button orderButton;

    Grid< Product > productsGrid;
    Grid< Order > ordersGrid;

    // Constructor
    public ProductPickerLayout () {
        this.widgetsMake();
        this.widgetsArrange();
    }

    private void widgetsMake () {

        // Create the selection component
        this.prodPopLabel = new Label( "Products: " );
        this.productSelect = new NativeSelect<>();
        // Add some items
        List< Product > products = new MyDatabaseService().fetchAllProducts();
        this.productSelect.setItems( products );
        this.productSelect.setItemCaptionGenerator( Product :: getName );
        // Show 5 items and a scrollbar if there are more
//        select.setRows( 3 );

        productSelect.addValueChangeListener( new HasValue.ValueChangeListener< Product >() {
            @Override
            public void valueChange ( ValueChangeEvent< Product > valueChangeEvent ) {
                Product p = valueChangeEvent.getValue();
                orderButton.setEnabled( null != p );
                Notification.show( "Selected: " + p.name );
            }
        } );

        this.orderButton = new Button( "Order" );
        this.orderButton.setEnabled( this.productSelect.getValue() != null );
        this.orderButton.addClickListener( ( Button.ClickEvent e ) -> {
            this.placeOrder();
            this.ordersGrid.setItems( new MyDatabaseService().fetchAllOrders() );
        } );

        MyDatabaseService db = new MyDatabaseService();

        this.productsGrid = new Grid<>( Product.class );
        this.productsGrid.setItems( products );
        this.productsGrid.setCaption( "Products" );

        this.ordersGrid = new Grid<>( Order.class );
        List< Order > orders = db.fetchAllOrders();
        this.ordersGrid.setItems( orders );
        this.ordersGrid.setCaption( "Orders" );
    }

    private void widgetsArrange () {
        HorizontalLayout orderBar = new HorizontalLayout();
        orderBar.setSpacing( true );
        orderBar.addComponents( this.prodPopLabel , this.productSelect , this.orderButton );
        orderBar.setComponentAlignment( this.prodPopLabel , Alignment.MIDDLE_CENTER );
        orderBar.setComponentAlignment( this.productSelect , Alignment.MIDDLE_CENTER );
        orderBar.setComponentAlignment( this.orderButton , Alignment.MIDDLE_CENTER );

        HorizontalLayout gridsBar = new HorizontalLayout();
        gridsBar.setSpacing( true );
        gridsBar.addComponents( this.productsGrid , this.ordersGrid );

        this.addComponents( orderBar , gridsBar );
        this.setExpandRatio( gridsBar , 1.0F );
    }

    private void placeOrder () {
        // Get pkey of the currently selected product.

        Product p = this.productSelect.getValue();
        if ( null == p ) {
            throw new IllegalStateException( "The `productSelect` NativeSelect does not have a current value." );
        }
        Long fkeyProduct = p.pkey;

        // Insert row into table.
        new MyDatabaseService().insertOrder( fkeyProduct );

        this.updateOrdersGrid();
    }

    private void updateOrdersGrid () {
    }
}

Модельные классы - Product & Order

Методы доступа метода получения / установки автоматически обнаруживаются и используются Ваадином для отображения данных в виджетах сетки данных Grid. Конечно, вместо этого вы можете выполнить ручную настройку.

Наш Product класс.

package com.basilbourque.example;

public class Product {
    Long pkey;
    String name;

    public Product ( Long pkey , String name ) {
        this.pkey = pkey;
        this.name = name;
    }

    @Override
    public String toString () {
        return "Product{ " +
               "pkey=" + pkey +
               "| name='" + name +
               " }";
    }


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

    public Long getPkey () {
        return pkey;
    }

    public void setPkey ( Long pkey ) {
        this.pkey = pkey;
    }

    public String getName () {
        return name;
    }

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

Наш Order класс.

package com.basilbourque.example;

import java.time.Instant;

public class Order {
    Long pkey;  // Identifier of this order.
    Long fkeyProduct; // Identifier of the product being ordered.
    Instant whenOrdered; // The moment the order was placed.

    public Order ( Long pkey , Long fkeyProduct , Instant whenOrdered ) {
        this.pkey = pkey;
        this.fkeyProduct = fkeyProduct;
        this.whenOrdered = whenOrdered;
    }

    @Override
    public String toString () {
        return "Order{ " +
               "pkey=" + pkey +
               "| fkeyProduct=" + fkeyProduct +
               "| whenOrdered=" + whenOrdered +
               " }";
    }

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

    public Long getPkey () {
        return pkey;
    }

    public void setPkey ( Long pkey ) {
        this.pkey = pkey;
    }

    public Long getFkeyProduct () {
        return fkeyProduct;
    }

    public void setFkeyProduct ( Long fkeyProduct ) {
        this.fkeyProduct = fkeyProduct;
    }

    public Instant getWhenOrdered () {
        return whenOrdered;
    }

    public void setWhenOrdered ( Instant whenOrdered ) {
        this.whenOrdered = whenOrdered;
    }
}

Maven POM

Файл pom.xml, управляющий Maven для загрузки зависимостей (библиотек) и для создания / запуска веб-приложения.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.basilbourque.example</groupId>
    <artifactId>prodpop</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>prodpop</name>

    <prerequisites>
        <maven>3</maven>
    </prerequisites>

    <properties>
        <vaadin.version>8.5.2</vaadin.version>
        <vaadin.plugin.version>8.5.2</vaadin.plugin.version>
        <jetty.plugin.version>9.4.12.v20180830</jetty.plugin.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>10</maven.compiler.source>
        <maven.compiler.target>10</maven.compiler.target>
        <!-- If there are no local customizations, this can also be "fetch" or "cdn" -->
        <vaadin.widgetset.mode>local</vaadin.widgetset.mode>
    </properties>

    <repositories>
        <repository>
            <id>vaadin-addons</id>
            <url>http://maven.vaadin.com/vaadin-addons</url>
        </repository>
    </repositories>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-bom</artifactId>
                <version>${vaadin.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-server</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-push</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-client-compiled</artifactId>
        </dependency>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-themes</artifactId>
        </dependency>

        <!--Basil-->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.197</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                    <!-- Exclude an unnecessary file generated by the GWT compiler. -->
                    <packagingExcludes>WEB-INF/classes/VAADIN/widgetsets/WEB-INF/**</packagingExcludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-maven-plugin</artifactId>
                <version>${vaadin.plugin.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>update-theme</goal>
                            <goal>update-widgetset</goal>
                            <goal>compile</goal>
                            <!-- Comment out compile-theme goal to use on-the-fly theme compilation -->
                            <goal>compile-theme</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.1.0</version>
                <!-- Clean up also any pre-compiled themes -->
                <configuration>
                    <filesets>
                        <fileset>
                            <directory>src/main/webapp/VAADIN/themes</directory>
                            <includes>
                                <include>**/styles.css</include>
                                <include>**/styles.scss.cache</include>
                            </includes>
                        </fileset>
                    </filesets>
                </configuration>
            </plugin>

            <!-- The Jetty plugin allows us to easily test the development build by
                running jetty:run on the command line. -->
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>${jetty.plugin.version}</version>
                <configuration>
                    <scanIntervalSeconds>2</scanIntervalSeconds>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <!-- Vaadin pre-release repositories -->
            <id>vaadin-prerelease</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>

            <repositories>
                <repository>
                    <id>vaadin-prereleases</id>
                    <url>http://maven.vaadin.com/vaadin-prereleases</url>
                </repository>
                <repository>
                    <id>vaadin-snapshots</id>
                    <url>https://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
                    <releases>
                        <enabled>false</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </repository>
            </repositories>
            <pluginRepositories>
                <pluginRepository>
                    <id>vaadin-prereleases</id>
                    <url>http://maven.vaadin.com/vaadin-prereleases</url>
                </pluginRepository>
                <pluginRepository>
                    <id>vaadin-snapshots</id>
                    <url>https://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
                    <releases>
                        <enabled>false</enabled>
                    </releases>
                    <snapshots>
                        <enabled>true</enabled>
                    </snapshots>
                </pluginRepository>
            </pluginRepositories>
        </profile>
    </profiles>

</project>

Кстати, в мире macOS «выпадающий список» известен как «всплывающее меню» или «всплывающее окно».

...