Freewind @ Thoughtworks scala java javascript dart 工具 编程实践 月结 math python english [comments admin] [feed]

(2012-01-07) Vaadin学习笔记(1)

广告: 云梯:翻墙vpn (省10元) 土行孙:科研用户翻墙http proxy (有优惠)

如同Extjs这样的工具对于做管理后台是非常必要的。管理后台使用人数少,操作多,交互性很强,对控件的功能要求较高。又因为大多是内网操作,所以较大的js库也不是问题。所以像Extjs这样的库,可以很好的满足这样的需求。

我在寻找一个Extjs的替代品,既能产生功能强大且美观的页面效果,又不必手写Javascript。最后找到了Vaadin,其官网是 http://www.vaadin.com

Vaadin内部使用了gwt,但提供了一套现代感比较强、比较华丽的主题,控件也很多。通过其官方演示页面就能看到:http://demo.vaadin.com/sampler

如gwt一样,vaadin也是在后台写java代码,自动生成对应的js代码供浏览器调用。这样的好处是相当明显的:

  1. 我们只需要写Java代码,可以利用编辑器的强大功能以及Java本身的语法特性2. 容易生成可复用的组件,因为我们在写Java,可以封装、继承3. 调试比较容易,可以像调试普通Java代码那样设置断点,单步调试4. 对于同样难度的较复杂的功能,使用Java写比用Javascipt要容易很多,所以可以实现一些较复杂的功能。参看vaadin在线设计器的效果:http://demo.vaadin.com/visualdesigner-nightly5. 可以利用其它语言如scala、xtend等,减化代码

Vaadin还提供了一个Eclipse插件,以可视化的方式来设计界面。

一、基本运行方式

Vaadin程序运行于servlet容器。首先要有一个类继承于com.vaadin.Application,它是程序的入口。例如这个例子:

import com.vaadin.Application;
import com.vaadin.ui.*;

public class TestvaadinApplication extends Application {

@Override     
public void init() {     
    Window mainWindow = new Window("Testvaadin Application");     
    Label label = new Label("Hello Vaadin user");     
    mainWindow.addComponent(label);     
    setMainWindow(mainWindow);     
}

}

它实际上是一个servlet,我们需要在web.xml中定义:

<servlet-name>TestvaadinApplication</servlet-name>     
<servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>     
<init-param>     
    <description>Front</description>     
    <param-name>application</param-name>     
    <param-value>com.example.testvaadin.TestvaadinApplication</param-value>     
</init-param>     


<servlet-name>TestvaadinApplication</servlet-name>     
<url-pattern>/*</url-pattern>     

然后在浏览器中访问 http://localhost:8080/myapp 即可看到这样的内容:

image

二、修改后代码后如何生效

我以debug方式运行tomcat,按说只要没有修改类结构,所做的修改应该能马上热部署。

但奇怪的是,我修改了java代码中一个Label上的文本后,刷新页面,却没有看到任何变化。打开一个新的浏览器访问该页面,却可以看到修改后的内容。这是怎么回事?在vaadin论坛上看到不少人问这个问题,终于弄明白,原来vaadin把很多东西都保存在session中,包括页面上的这些组件的内容等。当修改代码后,虽然后台代码变了,但是保存在session中的内容并没有变,所以只能在新窗口中看到修改变化。

对于这种情况,除了重启tomcat外,还可以:

  1. 在原url后加上?restartApplication,回车即可2. 在原url后加上?debug,可以打开如下的调试窗口,点击其中的"Restart app"按钮即可image

虽然有些不方便,但考虑到vaadin必须以某种方式实现stateful,也只能这样了。好在第二种方法还可以接受,因为那个窗口可以一直存在,不用每次都输入?deubg。

三、如何分开前后台

如果程序中有几个独立的入口,比如前台和后台分开,通过不同的url访问,应该怎么做?

可以在程序中为每个入口定义一个类,继承于Application。因为它就相当于一个servet,我们只需要在web.xml中分别定义对应的映射关系即可。

例如,我们让用户在浏览器中输入/admins时,访问管理后台的页面,怎么做?

再定义一个类(我这里是用xtend写的):

class AdminApplication extends Application {

override init() {     
    val mainWindow = new Window("管理平台");     
    val label = new Label("你好管理员");     
    mainWindow.addComponent(label);     
    setMainWindow(mainWindow);     
}

}

web.xml中也要有相应增加:

<servlet-name>AdminApplication</servlet-name>     
<servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>     
<init-param>     
    <description>Admin Panel</description>     
    <param-name>application</param-name>     
    <param-value>com.example.testvaadin.AdminApplication</param-value>     
</init-param>     
<load-on-startup>1</load-on-startup>     


<servlet-name>AdminApplication</servlet-name>     
<url-pattern>/admins/*</url-pattern>     

重启tomcat后访问:

image

image

注意url的变化。

需要注意的是,一定要保证该路径/VAADIN会被vaadin处理。先看一下firebug的记录:

image

原来vaadin去取那些组件资源时,要访问/VAADIN。所以如果在web.xml中,没有把根目录映射到某个继承于com.vaadin.Application的类时,需要增加类似于下面这样的映射关系:

<servlet-name>AdminApplication</servlet-name>    
<url-pattern>/VAADIN/*</url-pattern>    

四、最简单的页面需要下载多少K资源

image

对于一个最简单的页面,需要下载800多K的资源。其中样式表144.5K,而js文件为686.4K,个头还不小。所以只能用于管理后台。

五、如何与其它框架结合

如前所说,vaadin这样的大个头只适合做管理后台,对于前台,还得要用传统的css方案解决。这样必然需要使用另一种框架与vaadin结合。

如果是springmvc这样的mvc框架比较简单,因为它也是基于servlet,只需要在web.xml中再定义一个入口即可。

如果是play,因为它默认不是基于servlet的,所以只能分开开发,然后将play的程序打包为war,再将两者合并在一起,修改web.xml,丢在tomcat下。这种方式理论上可行,但是还需要实际测试才行。

还有一种方式就是,将前后台完全分开,写成两个独立的应用,放在tomcat中。然后将对首页的访问重定向至某一个应用。

最后的方法是,两个程序完全分开,也不需要都放在tomcat下。在前面用nginx这样的前端通过反向代理,将前后台的请求分别映射到两个应用上。

这些方法最简单的还是第一种。

comments powered by Disqus