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

Java 从Vaadin 8应用程序生成HTML页面并在新窗口中打开,java,html,window,vaadin,vaadin8,Java,Html,Window,Vaadin,Vaadin8,在我的Vaadin 8 web应用程序中,我希望用户能够通过单击按钮在另一个窗口中打开报告。内容将由Vaadin应用程序使用普通HTML5生成,而不是使用Vaadin小部件 Vaadin 8手册有一页。它显示了如何使用浏览器WindowOpener对象打开新窗口。但该窗口包含一个VaadinUI子类,而我希望生成自己的HTML内容 传递数据库标识符值等信息的奖励积分。这里是一个完整的示例应用程序,内置于Vaadin 8.5.1中。我们在TextField中将UUID显示为文本,并使用一个按钮打开

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

Vaadin 8手册有一页。它显示了如何使用
浏览器WindowOpener
对象打开新窗口。但该窗口包含一个Vaadin
UI
子类,而我希望生成自己的HTML内容


传递数据库标识符值等信息的奖励积分。

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

如手册中该页所示,您确实需要使用(或)。由于浏览器常见的安全限制,必须在用户单击按钮之前提前配置。因此,与在按钮的单击侦听器中编写代码不同,我们必须更早地配置
BrowserWindowOpener
对象,并与按钮关联

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

Button webPageButton = new Button( "Generate Person report" );
定义要打开的新窗口的目标,它应该使用什么URL作为其web地址。我们想回拨到我们的Vaadin应用程序。因此,请在运行时获取此web应用程序的URL。我们的web应用在Javaservlet术语中的技术术语是“上下文”。因此,我们询问当前上下文的URL(路径)

我们需要将该URL缩小到报告中,详细说明要从数据库加载的单个
Person
对象。因此,我们发明了
person.html
作为URL中请求的资源

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

有了这个对象,我们就可以定义
浏览器WindowOpener

BrowserWindowOpener webPageOpener = new BrowserWindowOpener( resource );
让我们配置它的一些属性,例如要打开的窗口的标题

webPageOpener.setWindowName( "Person ID: " + personUuid.getValue() );  // Set title of the new window to be opened.
我们希望传递“person”行的ID,该行将从数据库中检索,然后显示在生成的网页中

一种将此类信息作为URL中的参数传递的方法。所以我们URL的最后一部分看起来像
person.html?person_id=f0e32ddc-18ed-432c-950b-eda3f3e4a80d
。这个值必须是文本的,所以我们使用代表a的128位的规范的36个字符的十六进制字符串作为数据库标识符。我们为该值提供了一个任意键名,例如
person\u id

String param = "person_id";
webPageOpener.setParameter( param , personUuid.getValue() );
我们可以设置要打开的新窗口的大小。我们将在运行时使其与用户的当前窗口大小相同。我们将使窗口的大小可调整,这样用户可以将其拉伸得更大或更小。我们希望以字符串形式描述窗口功能,例如
width=800、height=600、resizeable
。我们将在运行时插入该宽度和高度

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。在实际工作中,在这里使用日志框架,如和。对于这个演示,我们转储到控制台

System.out.println( "TRACE BrowserWindowOpener URL: " + webPageOpener.getUrl() );
很好,我们现在有了一个按钮,它带有一个开瓶器集,用于请求生成基于HTML的报告。接下来,我们必须生成该报告。要做到这一点,请告诉我们的Vaadin应用程序预期一个带有我们上面指定的
person.html
URL的传入URL。我们通过实现接口来实现这一点。看

在我们的
RequestHandler
中,我们做了四件事:

  • 检索在新窗口中打开的URL的查询字符串中作为参数传递的UUID的十六进制字符串
  • 从该十六进制字符串重构
    UUID
    对象
  • 将该
    UUID
    对象传递给一个例程,该例程生成要在此新窗口中显示的HTML
  • 通过将HTML传递给
    VaadinResponse
    对象,在新窗口中显示该HTML,该对象通过Javaservlet技术传递回用户的web浏览器
  • 我们必须实例化我们的
    RequestHandler
    实现,并向用户会话(一个
    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字符串作为参数传递给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));
        }
    }
    
    StreamResource streamResource = new StreamResource((StreamResource.StreamSource) () -> 
        new ByteArrayInputStream(htmlString.getBytes()), "report.html");
    BrowserWindowOpener opener = new BrowserWindowOpener(streamResource);
    opener.extend(myButtonForLaunchingNewWindow);
    
    编辑:使用之前的方法,我遇到了一个问题,由于HTTP 400错误,弹出页面无法显示。这是由于http头大小太大(是的,我生成了一个很大的html页面)

    我的解决方案是直接为BrowserWindowOpener生成StreamResource:

    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));
        }
    }
    
    StreamResource streamResource = new StreamResource((StreamResource.StreamSource) () -> 
        new ByteArrayInputStream(htmlString.getBytes()), "report.html");
    BrowserWindowOpener opener = new BrowserWindowOpener(streamResource);
    opener.extend(myButtonForLaunchingNewWindow);
    
    StreamResource streamResource = new StreamResource((StreamResource.StreamSource) () -> 
        new ByteArrayInputStream(htmlString.getBytes()), "report.html");
    BrowserWindowOpener opener = new BrowserWindowOpener(streamResource);
    opener.extend(myButtonForLaunchingNewWindow);