在Java上以表格forms将数据从数据库输出到用户

我最近开始学习Java。 我需要用Java编写一个Web应用程序,用户可以从下拉列表中的主页html页面上的表单中选择他所需的产品。 产品列表存储在数据库的表中(使用MySQL)。 然后,所选产品应写在“订单历史”表中。 如何将数据库从数据库输出到下拉列表? 如何实现用户选择必要的产品? 我怎么开始? 有没有人得到一个小例子?

Vaadin

以下是使用Java和Vaadin Framework V8.5.2创建Web应用程序的完整工作示例,其中由H2数据库引擎运行的数据库跟踪产品列表(太阳系的10个行星)。 Vaadin中的NativeSelect窗口小部件是从从该数据库中的product_表加载的Product对象List中填充的。 每次用户单击“ Order按钮时,订单将记录为order_表中的一行。

这是数据库中两个表的简单ERD图。

Product表和Order表的实体关系图

用户首先从下拉列表中选择行星产品,然后单击“订购”按钮。

在这个数据输入区域下方,您可以看到一对Grid小部件作为后门窥视数据库。 左边是产品列表,不会改变。 右侧是所有订单的列表,每次用户使用“订单”按钮下订单时,订单都会更新。

请注意,数据库是内存中的,而不是持久的,因为这只是一个小小的演示。 因此,每次启动应用程序时,都会从头开始重建数据库。 order_表每次运行都会清空。

最后,这绝不是生产就绪代码,只是展示可能性的一个例子。 刚刚拍摄截图时我发现了一个与根本不选择产品有关的错误。 这就是生活。

在此处输入图像描述

有关详细信息,请参阅Vaadin手册的以下部分:

  • 按钮 – 按钮小部件概述。
  • NativeSelect – 此下拉列表小部件的快速演示
  • 选择组件 – 讨论NativeSelect等小部件如何在Vaadin中工作
  • 网格 – 如何使用这个function强大的数据网格小部件。

主应用程序类

基本上是样板,使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. * 

* 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 { } }

Servlet上下文侦听器

对Web应用程序启动和退出做出反应。

 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 () { } } 

模型类 – ProductOrder

Vaadin自动检测并使用getter / setter访问器方法在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加载依赖项(库)以及构建/运行Web应用程序。

   4.0.0 com.basilbourque.example prodpop war 1.0-SNAPSHOT prodpop  3   8.5.2 8.5.2 9.4.12.v20180830 UTF-8 10 10  local    vaadin-addons http://maven.vaadin.com/vaadin-addons      com.vaadin vaadin-bom ${vaadin.version} pom import      javax.servlet javax.servlet-api 3.1.0 provided   com.vaadin vaadin-server   com.vaadin vaadin-push   com.vaadin vaadin-client-compiled   com.vaadin vaadin-themes    com.h2database h2 1.4.197      org.apache.maven.plugins maven-war-plugin 3.2.2  false  WEB-INF/classes/VAADIN/widgetsets/WEB-INF/**    com.vaadin vaadin-maven-plugin ${vaadin.plugin.version}    update-theme update-widgetset compile  compile-theme      org.apache.maven.plugins maven-clean-plugin 3.1.0     src/main/webapp/VAADIN/themes  **/styles.css **/styles.scss.cache        org.eclipse.jetty jetty-maven-plugin ${jetty.plugin.version}  2        vaadin-prerelease  false    vaadin-prereleases http://maven.vaadin.com/vaadin-prereleases   vaadin-snapshots https://oss.sonatype.org/content/repositories/vaadin-snapshots/  false   true      vaadin-prereleases http://maven.vaadin.com/vaadin-prereleases   vaadin-snapshots https://oss.sonatype.org/content/repositories/vaadin-snapshots/  false   true       

顺便说一下,在macOS世界中,“下拉列表”被称为“弹出菜单”或“弹出窗口”。