代码之家  ›  专栏  ›  技术社区  ›  Basil Bourque

从Vaadin 8应用程序生成一个HTML页面,并在新窗口中打开

  •  4
  • Basil Bourque  · 技术社区  · 6 年前

    在我的Vaadin 8 web应用程序中,我希望用户能够通过单击按钮在另一个窗口中打开报告。内容将由Vaadin应用程序使用纯HTML5生成,而不是使用Vaadin小部件。

    Vaadin 8手册有一页 Handling Browser Windows . 它显示了 BrowserWindowOpener 对象打开新窗口。但那窗户上有一个瓦丁 UI 子类,而我想生成自己的HTML内容。

    传递信息(如数据库标识符值)的额外积分。

    2 回复  |  直到 6 年前
        1
  •  2
  •   Basil Bourque    6 年前

    下面是一个完整的示例应用程序,内置于Vaadin 8.5.1中。我们在 TextField ,按钮打开第二个窗口,显示由我们的Vaadin应用程序生成的HTML网页,而不使用Vaadin小部件或布局。该字段中的id将传递给新窗口,在实际应用程序中,该窗口可用于数据库查找。

    enter image description here

    enter image description here

    如手册的那一页所示,您确实需要使用 BrowserWindowOpener (或 Link ). 必须提前配置, 之前 由于浏览器的常见安全限制,用户单击该按钮。因此,我们必须在前面配置 浏览器开窗器 对象,并与按钮关联。

    定义要由用户单击以生成报告的按钮。

    Button webPageButton = new Button( "Generate Person report" );
    

    定义要打开的新窗口的目标,它应该使用哪个URL作为其web地址。我们想回我们的Vaadin应用程序。所以在运行时获取这个web应用的URL。在Java Servlet术语中,web应用的技术术语是context。所以我们询问当前上下文的URL(路径)。

    String servletPath = VaadinServlet.getCurrent().getServletContext().getContextPath(); // URL for this web app at runtime.
    

    我们需要缩小报告的URL范围,详细说明 Person 要从数据库加载的对象。所以我们发明 person.html 作为我们的URL中请求的资源。

    我们希望在不调用Vaadin小部件的情况下请求动态生成的HTML页面,因此我们使用 ExternalResource 上课。

    Resource resource = new ExternalResource( servletPath + "/person.html" );  // Defining an external resource as a URL that is not really so external -- will call back into this same web app.
    

    带着那个 Resource 我们已经准备好定义 浏览器开窗器 .

    BrowserWindowOpener webPageOpener = new BrowserWindowOpener( resource );
    

    允许配置其某些属性,例如要打开的窗口的标题。

    webPageOpener.setWindowName( "Person ID: " + personUuid.getValue() );  // Set title of the new window to be opened.
    

    我们希望传递要从数据库中检索的person行的ID,然后显示在生成的web页面中。

    一种在 query string 在URL上。所以URL的最后一部分看起来像 person.html?person_id= f0e32ddc-18ed-432c-950b-eda3f3e4a80d . 这个值必须是文本的,所以我们使用标准的36个字符的十六进制字符串来表示 UUID 作为我们的数据库标识符。我们给这个值一个任意的密钥名,比如 person_id .

    String param = "person_id";
    webPageOpener.setParameter( param , personUuid.getValue() );
    

    我们可以设置要打开的新窗口的大小。我们将使其在运行时与用户当前窗口的大小相同。我们将使窗口大小可调,这样用户可以将其拉伸得更大或更小。我们希望以字符串形式描述窗口特性,例如 width=800,height=600,resizable . 我们将在运行时插入该宽度和高度。

    String windowFeaturesString = String.format( "width=%d,height=%d,resizable" , Page.getCurrent().getBrowserWindowWidth() , Page.getCurrent().getBrowserWindowHeight() ) ; // Same size as original window.
    webPageOpener.setFeatures( windowFeaturesString );  // Example: "width=800,height=600,resizable".
    

    我们已经配置好要打开的新窗口。由于用户在事件侦听器中单击按钮时无法调用窗口打开,因此我们必须提前将打开程序与按钮关联起来。

    webPageOpener.extend( webPageButton ); // Associate opener with button.
    

    有趣的是,我们可以预览新窗口调用的URL。在实际工作中,这里使用一个日志框架,比如 SLF4J LogBack . 对于这个演示,我们转储到控制台。

    System.out.println( "TRACE BrowserWindowOpener URL: " + webPageOpener.getUrl() );
    

    很好,我们现在有一个按钮,设置了一个打开器,要求生成一个基于HTML的报告。下一步我们必须生成报告。要做到这一点,告诉我们的Vaadin应用程序期望一个带有 个人.html 我们在上面指定的URL。我们通过实现 RequestHandler 接口。见 the manual .

    在我们的 请求处理器 我们做四件事:

    1. 检索在新窗口中打开的URL的查询字符串中作为参数传递的UUID的十六进制字符串。
    2. 重组a UUID 来自那个十六进制字符串的对象。
    3. 把那个传过去 UUID公司 对象生成要在此新窗口中显示的HTML的例程。
    4. 通过将该HTML传递给 VaadinResponse 对象,该对象通过javaservlet技术传递回用户的web浏览器。

    我们必须实例化 请求处理器 实现,并向用户会话注册实例 VaadinSession 反对。

    VaadinSession.getCurrent().addRequestHandler(
            new RequestHandler() {
                @Override
                public boolean handleRequest ( VaadinSession session ,
                                               VaadinRequest request ,
                                               VaadinResponse response )
                        throws IOException {
                    if ( "/panel.html".equals( request.getPathInfo() ) ) {
                        // Retrieve the hex-string of the UUID from the URL’s query string parameter.
                        String uuidString = request.getParameter( "person_id" );  // In real-work, validate the results here.
                        UUID uuid = UUID.fromString( uuidString ); // Reconstitute a `UUID` object from that hex-string. In real-work, validate the results here.
                        System.out.println( "UUID object reconstituted from string passed as parameter in query string of URL opened in new window: " + uuid );
                        // Build HTML.
                        String html = renderHtml( uuid );
                        // Send out the generated text as HTML, in UTF-8 character encoding.
                        response.setContentType( "text/html; charset=utf-8" );
                        response.getWriter().append( html );
                        return true; // We wrote a response
                    } else
                        return false; // No response was written
                }
            } );
    

    填写该方法以生成HTML。

    // Generate the HTML to report on the details of a `person` from the database, given the UUID of that database row.
    private String renderHtml ( UUID uuid ) {
        String eol = "\n"; // End-of-line character(s) to use in the HTML.
        StringBuilder html = new StringBuilder();
        html.append( "<!DOCTYPE html>" ).append( eol );
        html.append( "<html>" ).append( eol );
        html.append( "<head>" ).append( eol );
        html.append( "<title>Person</title>" ).append( eol );
        html.append( "</head>" ).append( eol );
        html.append( "<body style='color:DarkSlateGray' >" ).append( eol );
        html.append( "<h1>Demo</h1>" ).append( eol );
        html.append( "<p>This is a drill. This is only a drill.</p>" ).append( eol );
        html.append( "<p>If this had been a real application, you would have seen some data.</p>" ).append( eol );
        html.append( "<p>Person ID: " ).append( uuid.toString() ).append( ".</p>" ).append( eol );
        html.append( "<p style='color:DimGray ; font-family: Pragmata Hack Menlo monospaced' >Report generated " ).append( Instant.now() ).append( ".</p>" ).append( eol );
        html.append( "</body>" ).append( eol );
        html.append( "</html>" ).append( eol );
        String s = html.toString();
        return s;
    }
    

    生成的HTML源代码如下所示:

    <!DOCTYPE html>
    <html>
    <head>
    <title>Person</title>
    </head>
    <body style='color:DarkSlateGray' >
    <h1>Demo</h1>
    <p>This is a drill. This is only a drill.</p>
    <p>If this had been a real application, you would have seen some data.</p>
    <p>Person ID: cc5e975b-2632-4c92-a1cb-b25085c60e60.</p>
    <p style='color:DimGray ; font-family: Pragmata , Hack , Menlo , monospace' >Report generated 2018-08-05T02:33:13.028594Z.</p>
    </body>
    </html>
    

    为了您的方便,这里是整个Vaadin 8应用程序的内容 MyUI.java 首先由Vaadin有限公司提供的最简单的Maven原型生成的文件。

    package com.basilbourque.example;
    
    import javax.servlet.annotation.WebServlet;
    
    import com.vaadin.annotations.Theme;
    import com.vaadin.annotations.VaadinServletConfiguration;
    import com.vaadin.server.*;
    import com.vaadin.ui.Button;
    import com.vaadin.ui.Label;
    import com.vaadin.ui.TextField;
    import com.vaadin.ui.UI;
    import com.vaadin.ui.VerticalLayout;
    
    import java.io.IOException;
    import java.time.Instant;
    import java.time.ZonedDateTime;
    import java.util.UUID;
    
    /**
     * 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 VerticalLayout layout = new VerticalLayout();
    
            TextField personUuid = new TextField( "UUID of Person:" );
            personUuid.setWidth( 22 , Unit.EM );
            personUuid.setValue( UUID.randomUUID().toString() );
            personUuid.setReadOnly( true );
    
            Button webPageButton = new Button( "Generate Person report" );
            webPageButton.setWidthUndefined();
            webPageButton.addClickListener( e -> {
                System.out.println( "Button clicked. " + ZonedDateTime.now() );
            } );
    
            // Configure web page opener object. Must be done *before* user clicks on button, not after.
            String servletPath = VaadinServlet.getCurrent().getServletContext().getContextPath(); // URL for this web app at runtime.
            Resource resource = new ExternalResource( servletPath + "/person.html" );  // Defining an external resource as a URL that is not really so external -- will call back into this same web app.
            BrowserWindowOpener webPageOpener = new BrowserWindowOpener( resource );
            webPageOpener.setWindowName( "Person ID: " + personUuid.getValue() );  // Set title of the new window to be opened.
            String param = "person_id";
            webPageOpener.setParameter( param , personUuid.getValue() );
            String windowFeaturesString = String.format( "width=%d,height=%d,resizable" , Page.getCurrent().getBrowserWindowWidth() , Page.getCurrent().getBrowserWindowHeight() ); // Same size as original window.
            webPageOpener.setFeatures( windowFeaturesString );  // Example: "width=800,height=600,resizable".
            webPageOpener.extend( webPageButton ); // Connect opener with button.
            System.out.println( "TRACE BrowserWindowOpener URL: " + webPageOpener.getUrl() );
    
            layout.addComponents( personUuid , webPageButton );
            setContent( layout );
    
            // A request handler for generating some content
            VaadinSession.getCurrent().addRequestHandler(
                    new RequestHandler() {
                        @Override
                        public boolean handleRequest ( VaadinSession session ,
                                                       VaadinRequest request ,
                                                       VaadinResponse response )
                                throws IOException {
                            if ( "/person.html".equals( request.getPathInfo() ) ) {
                                // Retrieve the hex-string of the UUID from the URL’s query string parameter.
                                String uuidString = request.getParameter( "person_id" );  // In real-work, validate the results here.
                                UUID uuid = UUID.fromString( uuidString ); // Reconstitute a `UUID` object from that hex-string. In real-work, validate the results here.
                                System.out.println( "UUID object reconstituted from string passed as parameter in query string of URL opened in new window: " + uuid );
                                // Build HTML.
                                String html = renderHtml( uuid );
                                // Send out the generated text as HTML, in UTF-8 character encoding.
                                response.setContentType( "text/html; charset=utf-8" );
                                response.getWriter().append( html );
                                return true; // We wrote a response
                            } else
                                return false; // No response was written
                        }
                    } );
        }
    
        // Generate the HTML to report on the details of a `person` from the database, given the UUID of that database row.
        private String renderHtml ( UUID uuid ) {
            String eol = "\n"; // End-of-line character(s) to use in the HTML.
            StringBuilder html = new StringBuilder();
            html.append( "<!DOCTYPE html>" ).append( eol );
            html.append( "<html>" ).append( eol );
            html.append( "<head>" ).append( eol );
            html.append( "<title>Person</title>" ).append( eol );
            html.append( "</head>" ).append( eol );
            html.append( "<body style='color:DarkSlateGray' >" ).append( eol );
            html.append( "<h1>Demo</h1>" ).append( eol );
            html.append( "<p>This is a drill. This is only a drill.</p>" ).append( eol );
            html.append( "<p>If this had been a real application, you would have seen some data.</p>" ).append( eol );
            html.append( "<p>Person ID: " ).append( uuid.toString() ).append( ".</p>" ).append( eol );
            html.append( "<p style='color:DimGray ; font-family: Pragmata , Hack , Menlo , monospace' >Report generated " ).append( Instant.now() ).append( ".</p>" ).append( eol );
            html.append( "</body>" ).append( eol );
            html.append( "</html>" ).append( eol );
            String s = html.toString();
            System.out.println( "\n\n" + s + "\n\n" );
            return s;
        }
    
        @WebServlet ( urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true )
        @VaadinServletConfiguration ( ui = MyUI.class, productionMode = false )
        public static class MyUIServlet extends VaadinServlet {
        }
    }
    
        2
  •  0
  •   mhanger    6 年前

    也可以通过将html字符串作为参数传递给BrowserWindowOpener的UI类来完成此操作:

    BrowserWindowOpener opener = new BrowserWindowOpener(MyUI.class);
    opener.extend(myButtonForLaunchingNewWindow);
    opener.setParameter("text",myHtmlStringWhichIJustGenerated);
    
    public static class MyUI extends UI {
        @Override
        protected void init(VaadinRequest request) {
    
            String text = request.getParameter("text");
            // Have some content to print
            setContent(new Label(
                    text,
                    ContentMode.HTML));
        }
    }
    

    编辑:使用我以前的方法时,我遇到了一个问题,由于HTTP 400错误,弹出页面没有显示。这是因为http头太大(是的,我生成了一个大的html页面)。

    我的解决方案是直接为BrowserWindowOpener生成流资源:

    StreamResource streamResource = new StreamResource((StreamResource.StreamSource) () -> 
        new ByteArrayInputStream(htmlString.getBytes()), "report.html");
    BrowserWindowOpener opener = new BrowserWindowOpener(streamResource);
    opener.extend(myButtonForLaunchingNewWindow);