原文地址:http://www.360doc.com/content/12/0521/15/1332348_212538068.shtml
一rap简单介绍
1 基本概念
RAP可以让开发人员使用JAVA API和按照Eclipse 插件的开发模式构建基于AJAX的Web 2.0应用程序, RAP的工作原理是采用交叉编译的方式将Java 代码生成html、JavaScript和CSS文件,底层基于Qooxdoo AJAX框架,这样,我们就不必接触JavaScript、CSS和处理Http的细节了,可以让我们更关心程序的功能实现。
2 与rcp的关系
RAP和RCP 一样,运行在Equinox框架上,Equinox是OSGI R4规范的实现,是一个非常优秀和成熟的OSGi框架,Eclipse 是通过这个框架实现灵活的扩展性和插件的热部署。RAP也支持Eclipse的大部分扩展点,其实RAP和RCP在架构上非常的类似,下图分别为RCP和RAP的架构图
可以看出,这之间的整体架构差别不大,RCP是基于SWT的,RAP是基于RWT的,RWT是实现了SWT功能的一个子集。其实这之间的使用方式都差不多。比如RWT也能和SWT一样使用MVC的方式来创建表格。
简单的说就是让RCP的程序在浏览器中展示,那什么是RCP呢?RCP就是由eclipse 插件开发转向桌面应用开发,让你开发出来和eclipse一样的程序一样构造的程序出来,复用eclipse的视图、编辑器、状态栏等等,摆脱失败的awt和swing,让程序拥有专业级效果,程序实现又很简单很优雅,试想一下哪天eclipse整体的界面都可以跑在web上面?对,rap就可以实现,而且eclipse 官方也计划E4版本上让eclispe在web上面跑?虽然现在的进度有很大的延迟,但是我们可以看到rap的版本还是在有条不紊的发布,让eclipse跑在浏览器上面也不会太远了吧。
3 最新版本下载
1、下载eclipse rcp/rap版本 Eclipse for RCP and RAP Developers
http://www.eclipse.org/downloads/packages/eclipse-rcp-and-rap-developers/indigosr1
安装方式1
在eclipse中打开Help?Welcom?Overview选项,选择Rich Ajax Platform? Install Target Platform,如下图
点击ok即可完成安装。
3.2 安装方式2
选择Help?Install New Software,选择如下图所示的网址,选择rap选项,如下图所示;点击Next然后Finish即可完成安装。
如果下拉选项中没有下图所示的网址,可以点击右侧的Add按钮进行添加。
4 相关文档
http://help.eclipse.org/indigo/index.jsp?topic=/org.eclipse.rap.help/help/html/intro.html
1、 Eclipse rap项目目前的进度
目前rap 的最新版本是 rap 1.5M4,最稳定版本是 rap 1.4.1,我们项目目前使用的版本是rap 1.4.1,Rap目前已经支持的部分是 swt,JFace,rap目前暂时不支持的部分是 dwaw2d、gef关于对dwaw2d、gef的支持目前正在开发中,原计划在eclipse E4版本中支持,目前改版本已经延迟了,而且暂时不支持dwaw2d、gef,至于什么时候完成,就不得而知了.
关于版本和支持情况大家可以去这个页面上看一下
http://www.eclipse.org/rap/downloads/
2、目前rap上存在的问题
1、运行速度
速度上面不同浏览器支持情况不同,使用chrome浏览器速度最快,firefox其次,IE浏览器(所有IE核心的都一样)最慢,而且不支持IE6(IE6上面跑界面上显示有些小问题),其他浏览器没有试过.大家有时间可以验证下,目前官方上发布支持的浏览器有
Firefox 2+ 、IE 7+ 、Safari 3+ 、Chrome 3+ 、Opera 9+
2、系统的bug
现在稳定版本的bug不少,开发中遇到的问题也不少,例如 treeViewer 会出现遮挡,系统自带的提示框第一次弹出的时候只能展示一半,等等,当然这些bug都可以通过其他的方式给避免掉.
郑重提示:想在自己项目中使用rap朋友们一定要慎重考虑
是否有精力和人力来处理一下”小”问题
虽然rap 是rcp的web版本,但是因为 一个是图形界面,一个是web界面,它们之间还是存在一些差异,现在把我们项目中碰见的差异罗列一下,大家以后碰见了就不至于浪费时间找原因了.^_^
1、 Label和Button按钮的显示的差异
当Label 和 Button显示的文字过长显示不开的时候,rcp、rap的处理方式就不一样了,rap显示不开会自己截取掉后面的文字,rcp会在文字的中间加上省略号.
还有关于Label 和Button 设置图片,文字过长的时候rap的图片不会显示,可以使用CLabel来替换Label
建议统一处理方式:不使用他们自带的文字截取方式,统一计算文件的长度,在文字最后面加上… 来使二者统一
2、 TreeViewer的差异
目前最新的rap 版本 TreeViewer偶尔有遮挡的问题,这个问题暂时不能有效的避免,
3、 属性视图 -tree无法设置行高的问题
关于设置 treeViewer的高度,rcp支持设置行的高度,rap不支持,这个暂时没有解决方法
4、 对GEF、draw2d的支持
目前rap暂时不支持GEF draw2d,不过目前已经在开发中。
5、 paint监听,rap没有
rap组建很多都没有paint 重绘方法,导致很多界面不能进行重绘。比如treeVIewer上面添加cellEditor进行界面上直接编辑,因为不支持,paint 导致 cellEditor和当前的行的位置不匹配。在后续文章中会对此问题的解决方法进行专门的讲解
6、 扩展点的差异控制台扩展点
Rap界面目前对扩展点的支持也不是很完善,控制台扩展点和帮助视图扩展点都不是很完善,不过大家可以自己实现.不是很复杂
7、 帮助系统的差异
Rcp /rap的帮助系统完全不同,rap的帮助系统只是加载一个jsp页面
8、上传下载的差异
一个是web 一个是图形界面,后续会写如何在rap实现上传和下载
9、视图拖动
用过eclipse的朋友都知道,eclipse之间的视图是可以任意拖动的,目前Rap不支持,视图间的拖动,这个算是比较遗憾吧
完成后:
最后点finish。
重新打开RAP程序,可以看到汉化结果。
1、 在工程的根目录下面建立一个plugin.properties
资源文件;
在此资源文件中写入需要国际化的内容(键/值对),举例如下:
2、
在 MANIFEST.MF文件中增加代码行:Bundle-Localization: plugin;说明:添加代码行中的plugin这个名称是plugin.properties 这个文件的名称。也可以是其它的名称但要与文件名保持一致。
3、 plugin.xml配置文件对资源文件进行引用时, 在引用的key前面加一个%即可;
plugin.xml引用资源文件举例如下:
- <extension point="org.eclipse.ui.views">
- <view
- id="org.eclipse.rap.helloworld.helloWorldView"
- class="org.eclipse.rap.helloworld.HelloWorldView"
- name="%helloWorldView_name">
- </view>
- </extension>
类文件中中文内容的国际化
1、 建立一个messages_zh_CN.properties资源文件;
说明:此资源文件中的内容为需要国际化的键/值对;
2、 建立一个Messages.java类文件,文件内容如下:
- import org.eclipse.osgi.util.NLS;
- public class Messages extends NLS
- {
- private static final String BUNDLE_NAME = "telecomui.nls.messages";
- public static String PriceDomainDao_AddTextToBrower;
- static {
- NLS.initializeMessages(BUNDLE_NAME, Messages.class);
- }
- private Messages(){
- }
- }
3、 在需要进行国际化的类文件上点击右键,出现下图的操作:
4、 点击蓝色菜单选项后,弹出下面的窗体,如图:
5、 在上图中列出的需要国际化的字段中,对需要进行国际化的字段前勾选加号,不需要进行国际化的字段前勾选差号;
注意:
对于需要进行国际化的字段项,如图
中字段Test_0是生成到资源文件中的默认key值,建议进行重命名下,建议命名规则是最好以当前类名做前缀;如上字段可命名为:Test_printStr;
6、 单击窗体中的【Configure…】按钮,弹出窗体,如图:
7、 对上图中的各选项进行设置后,点击【ok】按钮—>【next】—>【finish】
先下载以来的打包插件
war products
输入下面的地址,选择相应的插件
新建一个 war product Configutation向导
下面的war product Configutation 配置面板
选择插件
将除了 自己项目 在外的所有插件都删除,然后点 Add Required Plug-ins 将需要的插件添加进来,吧所有的关于 Jetty 和Juit 的插件全部删除掉,这样在验证的时候就不会出现什么错误。避免把没必要的插件加进来。
在 Overview 中点 Validate 按钮验证是否存在问题:
点击导出war
发布成功
1、 Rap样式原理
Rap的界面样式目前是以css来配置的,程序启动后加载相应的css配置文件再对组件进行样式设置,界面上的所有组件Label button composit等的样式最开始都是通过css来确定显示样式的.因此只需要选择不同的css文件就可以控制css样式了
2、 Rap如何选择样式
Plugin.xml – 扩展 – 新建 org.eclipse.rap.ui.branding 扩展点 – 在这个扩展点上新建branding .在 branding上就可以选择样式了,对应的选项是themdID ,点击浏览就可以选择目前已经存在的样式
目前rap自带的样式大约有2个 , Classis 样式和 Default ,
建议大家使用Classis 样式,因为默认的default样式本身在界面显示上面会有不少的问题.
3、 修改rap自带的样式
如果你觉得目前rap界面上的样式不太符合你的要求,那么你就可以新建自己的rap样式 方法如下:
新建扩展点:org.eclipse.rap.ui.themes
在扩展点上新建 theme
点击 theme 会有一个属性 file,这个是用来选择对应的样式css文件的.
关于rap每个组建对应的样式名称,大家可以通过如下方式进行查看
找到 org.eclipse.rap.rwt.theme.classes 插件(直接通过插件列表-导出源代码到目前工程)
在对应的 theme目录下面就可以看到 classic.css文件了
4、 Rap样式的发布
Rap最好按照默认的方式以插件的形式进行发布,这样就可以松耦合了.
1 、解决 rap 字符集乱码的问题
字符集问题,解决办法: 在plugin.xml - build.properties 中添加
javacDefaultEncoding.. = UTF-8 即可解决字符集乱码
2、解决web前台输入乱码问题
使用传统的 字符集过滤器
写一个过滤器类
- <span style="font-size: small;">public class CharacterEncodingFilter implements Filter
- {
- private String edcoding;
- private FilterConfig filterConfig;
- private boolean ignore;
- public CharacterEncodingFilter()
- {
- this.edcoding = null;
- this.filterConfig = null;
- this.ignore = true; }
- public void destroy() {
- this.edcoding = null;
- this.filterConfig = null;
- }
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
- {
- if ((this.ignore) || (request.getCharacterEncoding() == null)) {
- String encoding = setCharacterEncoding(request);
- if (encoding != null)
- request.setCharacterEncoding(encoding)
- }
- filterChain.doFilter(request, response);
- }
- public void init(FilterConfig filterConfig) throws ServletException {
- this.filterConfig = filterConfig;
- this.edcoding = filterConfig.getInitParameter("encoding");
- String value = filterConfig.getInitParameter("ignore");
- if (value == null)
- this.ignore = true;
- else if (value.equalsIgnoreCase("true")) {
- this.ignore = true;
- }
- else
- this.ignore = false;
- }
- public String setCharacterEncoding(ServletRequest request)
- {
- return this.edcoding;
- }
- }
- </span>
然后达成 jar 包方式到 war /WEB_INF/lib 目录下面
在 web.xml 添加
rap 导出 war 包时,编码问题处理,加入了字符过滤器的处理方式
1. 在导出 WAR 后,修改 war 包里面的 web.xml 文件,添加过滤器,
内容如下
- <span style="font-size: small;"><span> <filter>
- <filter-name>CharacterEncodingFilter</filter-name>
- <filter-class>com.encoding.CharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>CharacterEncodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </span>
- </span>
2. 增加 jar 包
把过滤器要用的 jar 包【 encoding.jar 】添加到导出的 WAR 包的 lib 下面,这样 WAR 包加载后,能够找寻到过滤器用到的类。
上面 2 部分可以保证完美的解决中文问题
一 上传
上传即将文件上传到服务器上,在客户端需要写相应的脚本,服务器端需要注册相应的 handle 接受客户端的请求。
原理:
Rap 的上传和下载是通过普通的 web 的方式进行上传和下载的 , 但是和传统的 wen 还不相同
1、 rap 本身就单线程在跑 , 和上传下载的线程不能进行混淆
所以采用的方式如下:
上传:通过传统的方式上传到指定目录 ,rap 不能直接操作上传的文件流 , 如果想获得上传的数据必须要先上传到指定文件 , 然后让 rap 去加载指定文件即可
下载: 先通过 rap 程序生成需要下载的文件到指定目录 , 然后通过 rap 加载成文件流的形式发送给客户端
1 在服务器端注册相应的 handler
// 注册上传处理事件
IServiceManager manager = RWT.getServiceManager ();
IServiceHandler uploadHandler = new UploadServiceHandler();
manager.registerServiceHandler( "uploadServiceHandler" , uploadHandler); //$NON-NLS-1$
2 在客户端的脚本调用
目前的做法是创建上传的 dialog, 在 dialog 里面添加 browser 控件,然后 browser 里书写上传的 javaScript 脚本,脚本请求的 url 格式可以通过以下类似的代码创建:
private String createUploadUrl(String uploadFileName) {
StringBuffer url = new StringBuffer();
url.append(RWT.getRequest ().getContextPath());
url.append(RWT.getRequest ().getServletPath());
url.append( "?" ); //$NON-NLS-1$
url.append(IServiceHandler . REQUEST_PARAM );
url.append( "=uploadServiceHandler" ); //$NON-NLS-1$
url.append( "&fileName=" ); //$NON-NLS-1$
url.append(uploadFileName);
return url.toString();
}
3 服务器端 handler 的写法
public class UploadServiceHandler implements IServiceHandler {
public void service() throws IOException, ServletException {
HttpServletRequest request = RWT.getRequest ();
request.setCharacterEncoding( "UTF-8" );
String fileName = request.getParameter( "fileName" );
FileOutputStream o = null ;
BufferedReader bufferReader = null ;
InputStream in = null ;
try {
in = request.getInputStream();
File f = null ;
try {
f = new File(FileUtil.getTempFilePathAndName (RWT.getRequest ()
.getSession().getAttribute( "userName" ).toString(),
fileName));
} catch (Exception e) {
throw new IOException(e);
}
o = new FileOutputStream(f);
bufferReader = new BufferedReader( new InputStreamReader(in));
String line = null ;
boolean beginWrite = false ;
boolean endWrite = false ;
while ((line = bufferReader.readLine()) != null ) {
if (line.indexOf(PriceDomainBean. class .getName()) != -1) {
if (!beginWrite) {
beginWrite = true ;
} else {
endWrite = true ;
}
}
if (beginWrite) {
o.write((line + "\r\n" ).getBytes());
}
if (endWrite) {
break ;
}
}
} catch (IOException e) {
throw e;
} finally {
if ( null != o) {
o.close();
}
in.close();
if ( null != bufferReader) {
bufferReader.close();
}
}
HttpServletResponse response = RWT.getResponse ();
response.setContentType( "text/html;charset=UTF-8" );
response.getWriter().write(
"<br><br><br><DIV align=center><h2> 上传成功 !</h2>" );
}
}
二 下载
下载和上传采用的方式基本相同,只不过是将服务器文件读取到本地,和上传是一个相反的过程。
1 在服务器端注册相应的 handler
// 注册下载处理事件
IServiceManager manager = RWT.getServiceManager ();
IServiceHandler downloadHandler = new DownloadServiceHandler();
manager.registerServiceHandler( "downloadServiceHandler" , downloadHandler);
2 在客户端节本的调用
在 bowser 控件中书写 js 请求脚本,脚本请求的 url 如下
private String createDownloadUrl(String fileName) {
StringBuffer url = new StringBuffer();
url.append (RWT.getRequest ().getContextPath());
url.append (RWT.getRequest ().getServletPath());
url.append ( "?" );
url.append (IServiceHandler. REQUEST_PARAM );
url.append ( "=downloadServiceHandler" );
url.append ( "&fileName='+encodeURI('" );
url.append (fileName);
url.append ( "')" );
return url.toString();
}
3 服务器端 handler 的写法
public class DownloadServiceHandler implements IServiceHandler {
public void service() throws IOException, ServletException {
String fileName = URLDecoder.decode (
RWT.getRequest ().getParameter( "fileName" ), "UTF-8" );
String filePathAndName = null ;
try {
filePathAndName = FileUtil
.getTempFilePathAndName (RWT.getRequest ().getSession()
.getAttribute( "userName" ).toString(), fileName);
} catch (Exception e) {
throw new IOException(e);
}
File file = new File(filePathAndName);
if (!file.exists()) {
return ;
}
HttpServletResponse response = RWT.getResponse ();
response.setHeader( "pragma" , "no-cache" );
response.setHeader( "cache-control" , "no-cache" );
response.setDateHeader( "Expires" , 0);
response.setCharacterEncoding( "UTF-8" );
response.setContentType( "text/html;charset=UTF-8" );
response.setHeader( "Content-Disposition" , "attachment;filename="
+ new String(fileName.getBytes( "gb2312" ), "ISO8859-1" ));
try {
BufferedInputStream in = new BufferedInputStream(
new FileInputStream(filePathAndName));
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
byte [] temp = new byte [1024];
int size = 0;
while ((size = in.read(temp)) != -1) {
out.write(temp, 0, size);
}
in.close();
byte [] content = out.toByteArray();
response.setContentLength(content. length );
response.getOutputStream().write(content);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
} finally {
try {
FileUtil.deleteTempFile (RWT.getRequest ().getSession()
.getAttribute( "userName" ).toString(), fileName);
} catch (Exception e) {
throw new IOException(e);
}
}
}
}
平常进行 rap 程序开发一般都是在 win 下面完成 , 然后在 tomcat 下面测试 , 但是程序最终发布一般都是在linux aix 上面 , 这个时候就有能会出现一下问题,下面 2 个问题是我们把在开发中真是出现的问题,与大家一起分享下 ;
1、 图片路径
这个是最常用的方法,就是在 rap 中加载图片进行显示,刚开始我们使用的是如下代码
- public static String getRoot() {
- String path = null ;
- try {
- path = FileLocator.toFileURL (Platform.getBundle (Activator. PLUGIN_ID ).getEntry( "" )).getPath();
- path = path.substring(path.indexOf( "/" ) + 1, path.length());
- }
- catch (Exception e) {
- log .error( "getRoot method :" , e);
- }
- return path;
- }
来获得系统的跟路径 . 但是当程序在移植到 linux 和 aix 上面的时候发现图片路径全部失效 . 可以使用如下方式进行寻址来获得图片。
- /**
- * 获取图片
- * @param fileName
- * 图片的名称
- * @return 先从缓存对象中查找,若有直接返回,若没有,则将图片加载到缓存中,在从缓存中将图片传给调用着
- */
- public static Image getImage(String fileName) {
- Bundle bundle = Platform.getBundle ( "TelecomUI" );
- URL url = bundle.getEntry( "icons" );
- try {
- url = Platform.asLocalURL (url) ;
- }
- catch (Exception e) {
- }
- Image image = registry .get(fileName);
- if ( null != image) {
- return image;
- }
- else {
- URL fullPathString = bundle.getEntry( "icons/" + fileName);
- ImageDescriptor des = ImageDescriptor.createFromURL (fullPathString);
- registry .put(fileName, des);
- return ImageDescriptor.createFromURL (fullPathString).createImage();
- }
- }
2、 获得屏幕的分辨率
因为需要把一些弹出的组件居中显示 , 这个时候就需要获得系统的分辨率
刚开始我们使用的方法如下;
- screenH = Toolkit.getDefaultToolkit().getScreenSize ().height;
- screenW = Toolkit.getDefaultToolkit().getScreenSize ().width;
上面这段代码在 window 下面是没有问题的 , 可是到了 linux 和 aix 下面就报错了 , 找不到
sun.awt.X11.XToolkit 类
可以采用如下方式来获得屏幕的分辨率
3、 其他如果有发现不兼容会陆续补充