ton*_*nix 4 java user-interface vaadin
当我尝试执行以下操作时,我有一个奇怪的"通信问题"Vaadin错误:
我有两个UI,第一个有一个指向另一个UI的链接,这里是代码:
public class MenuUI extends UI {
@WebServlet(value = "/*", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = MenuUI.class)
public static class Servlet extends VaadinServlet {
}
@Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
layout.setSpacing(true);
setContent(layout);
MenuBar menuBar = new MenuBar();
MenuItem submenu1 = menuBar.addItem("Submenu 1", null);
MenuItem submenu2 = menuBar.addItem("Submenu 2", null);
submenu1.addItem("Option 1", null);
submenu1.addItem("Option 2", null);
submenu2.addItem("Option 3", null);
submenu2.addItem("Option 4", new Command() {
@Override
public void menuSelected(MenuItem selectedItem) {
Notification.show("That was option 4");
}
});
layout.addComponent(menuBar);
Link link = new Link("Go to ShortcutKeys",
new ExternalResource(Page.getCurrent().getLocation().toString() + "Shortcut"));
link.setTargetName("_blank");
layout.addComponent(link);
}
}
Run Code Online (Sandbox Code Playgroud)
这个UI结果如下:

当我点击链接时,会初始化一个新UI,这里是新UI的代码:
public class ShortcutUI extends UI {
@WebServlet(value = "/Shortcut", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = ShortcutUI.class)
public static class Servlet extends VaadinServlet {
}
@Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
layout.setSpacing(true);
setContent(layout);
final TextField tf = new TextField("Your data:");
layout.addComponent(tf);
Button button = new Button("Send data (ENTER)");
button.setClickShortcut(KeyCode.ENTER, ModifierKey.SHIFT);
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
layout.addComponent(new Label(tf.getValue()));
tf.setValue("");
tf.focus();
}
});
layout.addComponent(button);
}
Run Code Online (Sandbox Code Playgroud)
结果如下:

在这里我键入一些文本,然后当我单击"发送数据"按钮时,我得到以下内容:

为什么我会遇到此通信问题?如果UI不是从单击的链接创建的,例如,如果我将ShortcutUI init()内容放在MenuUI中,就像在下面的类中一样:
public class MenuUI extends UI {
@WebServlet(value = "/*", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = MenuUI.class)
public static class Servlet extends VaadinServlet {
}
@Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
layout.setSpacing(true);
setContent(layout);
MenuBar menuBar = new MenuBar();
MenuItem submenu1 = menuBar.addItem("Submenu 1", null);
MenuItem submenu2 = menuBar.addItem("Submenu 2", null);
submenu1.addItem("Option 1", null);
submenu1.addItem("Option 2", null);
submenu2.addItem("Option 3", null);
submenu2.addItem("Option 4", new Command() {
@Override
public void menuSelected(MenuItem selectedItem) {
Notification.show("That was option 4");
}
});
layout.addComponent(menuBar);
Link link = new Link("Go to ShortcutKeys",
new ExternalResource(Page.getCurrent().getLocation().toString() + "Shortcut"));
link.setTargetName("_blank");
layout.addComponent(link);
// Shortcut Keys
final TextField tf = new TextField("Your data:");
layout.addComponent(tf);
Button button = new Button("Send data (ENTER)");
button.setClickShortcut(KeyCode.ENTER, ModifierKey.SHIFT);
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
layout.addComponent(new Label(tf.getValue()));
tf.setValue("");
tf.focus();
}
});
layout.addComponent(button);
}
}
Run Code Online (Sandbox Code Playgroud)
代码会导致这样:

一切正常.根本没有通信问题("一些文本"和"其他一些文本"是在"发送数据"按钮上执行单击时添加的标签).
那么为什么如果我有一个从链接创建的UI,在Button上触发的Click事件会导致Vaadin中的这个"通信问题"?
这是来自?debug Vaadin控制台的完整错误:
Communication error: (SyntaxError) : Unexpected token < - Original JSON-text: html>
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta
http-equiv="X-UA-Compatible" content="IE=11;chrome=1" /> <style type="text/css">html,
body {height:100%;margin:0;}</style> <link rel="shortcut icon"
type="image/vnd.microsoft.icon"
href="./../../VAADIN/themes/chapter_4_menubar_and_shortcutkeys/favicon.ico" /> <link
rel="icon" type="image/vnd.microsoft.icon"
href="./../../VAADIN/themes/chapter_4_menubar_and_shortcutkeys/favicon.ico" /> </head>
<body scroll="auto" class=" v-generated-body"> <div id="Chapter4MenuBarandShortcutKeys-
1103734620" class=" v-app chapter_4_menubar_and_shortcutkeys"> <div class=" v-app-
loading"></div> <noscript> You have to enable javascript in your browser to use an
application built with Vaadin. </noscript> </div> <script type="text/javascript"
src="./../../VAADIN/vaadinBootstrap.js"></script> <script type="text/javascript">//<!
[CDATA[ if (!window.vaadin) alert("Failed to load the bootstrap javascript:
./../../VAADIN/vaadinBootstrap.js"); if (typeof window.__gwtStatsEvent != 'function') {
vaadin.gwtStatsEvents = []; window.__gwtStatsEvent = function(event)
{vaadin.gwtStatsEvents.push(event); return true;}; }
vaadin.initApplication("Chapter4MenuBarandShortcutKeys-1103734620",{ "authErrMsg": {
"caption": "Authentication problem", "message": "Take note of any unsaved data, and
<u>click here<\/u> or press ESC to continue." }, "comErrMsg": { "caption": "Communication
problem", "message": "Take note of any unsaved data, and <u>click here<\/u> or press ESC
to continue." }, "debug": true, "heartbeatInterval": 300, "serviceUrl": "./../..",
"sessExpMsg": { "caption": "Session Expired", "message": "Take note of any unsaved data,
and <u>click here<\/u> or press ESC key to continue." }, "standalone": true, "theme":
"chapter_4_menubar_and_shortcutkeys", "vaadinDir": "./../../VAADIN/", "versionInfo":
{"vaadinVersion": "7.3.7"}, "widgetset": "com.vaadin.DefaultWidgetSet" }); //]]></script>
</body> </html
Run Code Online (Sandbox Code Playgroud)
为什么会这样?
如果有人遇到我面临的同样问题,请注意如何解决此类问题.
问题是负责显示ShortcutUI的VaadinServlet的映射:
简而言之,这个:
@WebServlet(value = "/Shortcut", asyncSupported = true)
Run Code Online (Sandbox Code Playgroud)
应该成为这样的:
@WebServlet(value = "/Shortcut/*", asyncSupported = true)
Run Code Online (Sandbox Code Playgroud)
当在ShortcutUI上发生事件并发送到服务器时,它们会发送一个请求到URL,如下所示:
http://localhost:8080/myapp/Shortcut/UIDL/?v-uiId=0
Run Code Online (Sandbox Code Playgroud)
如果应用程序的上下文根是/myapp,或者像这样:
http://localhost:8080/Shortcut/UIDL/?v-uiId=0
Run Code Online (Sandbox Code Playgroud)
如果应用程序的上下文根是servlet容器的DocumentRoot(例如,在通过mvn命令创建的Maven项目中并mvn jetty:run使用嵌入式Jetty运行).
这就是为什么/Shortcut永远不会匹配/Shortcut/UIDL/?v-uiId=0,因此错误.Shortcut/*相反,将匹配"/*"后的Shortcut匹配/UIDL/?v-uiId=0.
另一个需要注意的重要事项是,您可能想要修改"入口点"UI(即映射到的UI /*)的servlet映射并更改此设置:
@WebServlet(value = "/*", asyncSupported = true)
对此:
@WebServlet(urlPatterns = { "", "/VAADIN/*" }, asyncSupported = true)
绝对不要那样做!这将一直有效,直到Vaadin应用程序发出/HEARTBEAT请求或触发用户界面上的事件并发送到服务器(发出"/ UIDL"请求).Vaadin仍然需要"*",因为它会匹配这样的请求("/ HEARTBEAT","/ UIDL",等等......).
所以IMHO的这个问题的独特解决方案是使用:
@WebServlet(value = "/*", asyncSupported = true)
Run Code Online (Sandbox Code Playgroud)
对于MenuUI,和:
@WebServlet(value = "/Shortcut/*", asyncSupported = true)
Run Code Online (Sandbox Code Playgroud)
对于ShortcutUI,做同样的应用程序的任何"子UI",如果需要多个用户界面.
否则,另一个选择是使用NavigatorAPI - > https://vaadin.com/book/-/page/advanced.navigator.html