京山游侠
专注技术,拒绝扯淡
posts - 50, comments - 868, trackbacks - 0, articles - 0
BlogJava
::
首页
::
新随笔
::
联系
::
聚合
::
管理
使用SpringSide 3.1.4.3开发Web项目的全过程(中)
Posted on 2009-07-19 23:15
京山游侠
阅读(15249)
评论(14)
编辑
收藏
所属分类:
SpringSide开发实战
使用SpringSide 3.1.4.3开发Web项目的全过程(上)
第七步、编写Action和JSP。
在SpringSide 3.1.4.3中,使用的是Struts 2及其Convention插件,已经不是前面使用的CodeBehind插件了,关于Convention插件,这里要再说几句,该插件的大部分功能和CodeBehind相同,唯一让人有点迷惑的就是该插件到哪里寻找Action类的问题,它会根据struts.convention.package.locators属性的值来决定,在该项目中,其值为“web”,之需要查阅一下struts.xml文件即可知。这说明,Convention会寻找所有包含“web”这个单词的包,并在该包及其子包中寻找Action类。这也正是Action层的包名为personal.youxia.web的原因。
关于SpringSide 3种的Struts的探讨,大家可以看看我之前写的一篇文章
SpringSide 3 中的 Struts 2
ArticleAction的实现思路如下,修改index.jsp,使其重定向到article.action,该Action默认调用其list方法显示所有文章,并返回article.jsp作为其视图。在该视图上,有添加文章的连接,点击该连接则访问article!input.action,这时会调用ArticleAction的input方法,并返回article-input.jsp作为其视图,在该视图中输入文章的内容,点击保存,调用article!save.action,这时会调用ArticleAction的save方法以保存数据,如果要删除文章,则调用article!delete.action,这时会调用ArticleAction的delete方法。在调用以上方法的过程中,会自动调用prepare系列的方法。
因此,该步骤涉及到三个JSP文件和一个Action类,它们分别是
index.jsp
article.jsp
article-input.jsp
ArticleAction.java
index.jsp的修改很简单,只是让项目一启动后就去访问ArticleAction,而不是默认的UserAction。index.jsp的代码如下:
<%
response.sendRedirect(
"
article.action
"
);
%>
这时,重点进入到ArticleAction中,创建该Action,其代码的框架如下:
package
personal.youxia.web;
import
personal.youxia.entity.entities.Article;
public
class
ArticleAction
extends
CrudActionSupport
<
Article
>
{
@Override
public
String delete()
throws
Exception
{
//
TODO Auto-generated method stub
return
null
;
}
@Override
public
String list()
throws
Exception
{
//
TODO Auto-generated method stub
return
null
;
}
@Override
protected
void
prepareModel()
throws
Exception
{
//
TODO Auto-generated method stub
}
@Override
public
String save()
throws
Exception
{
//
TODO Auto-generated method stub
return
null
;
}
public
Article getModel()
{
//
TODO Auto-generated method stub
return
null
;
}
}
可以看到,该Action从CrudActionSupport类继承,而CrudActionSupport又继承自ActionSupport,并实现了ModelDriven和Preparable接口,这样Struts 2的ModelDriven拦截器和Preparable拦截器就会对我们自己的Action发生作用。CrudActionSupport中的excute方法默认的实现是调用list方法,所以访问article.action就等于访问ArticleAction的list方法,该方法的目的是为了列出所有的文章,所以在该方法中使用了ArticleDao的分页查询,查询结果放在一个page对象中。在Struts 2中,已经没有了ActionForm的概念,可以直接把Action对象传递到视图中,为了能够在视图中访问page对象,只需要把page对象作为ArticleAction的一个属性即可。先在ArticleAction.java中加入几行代码:
@Autowired
private
ArticleManager articleManager;
public
void
setArticleManager(ArticleManager articleManager) {
this
.articleManager
=
articleManager;
}
private
Page
<
Article
>
page
=
new
Page
<
Article
>
(
10
);
public
Page
<
Article
>
getPage() {
return
page;
}
可以看到该代码的作用是为了注入ArticleManager和初始化Page对象,此时list方法的代码就非常简单,如下:
@Override
public
String list()
throws
Exception {
page
=
articleManager.getAll(page);
return
SUCCESS;
}
由于该方法只是简单获取一个页面的Acticle,所以代码很简单,使用articleManager.getAll方法即可。如果要实现复杂的条件查询,就需要创建一个包含PropertyFilter对象的列表,然后使用articleManager.search方法进行查询,为了简化PropertyFilter对象列表的创建,白衣提供了HibernateWebUtils.buildPropertyFilters()静态方法供大家使用。
list方法返回的是SUCCESS,因此返回给用户的视图页面为article.jsp,该页面应该存放在WEB-INF目录的content目录中,这也是Convention插件的一个特性,这样用户就没有办法直接访问到视图页面了。在该页面中,可以通过访问page对象来显示数据,如下:
<%
@ page language
=
"
java
"
contentType
=
"
text/html; charset=UTF-8
"
pageEncoding
=
"
UTF-8
"
%>
<%
@ include file
=
"
/common/taglibs.jsp
"
%>
<!
DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"
>
<
html
>
<
head
>
<
meta
http-equiv
="Content-Type"
content
="text/html; charset=UTF-8"
>
<
title
>
Insert title here
</
title
>
</
head
>
<
body
>
<
table
>
<
tr
><
td
><
a
href
="article!input.action"
>
添加文章
</
a
></
td
></
tr
>
<
s:iterator
value
="page.result"
>
<
tr
>
<
td
>
${subject}
</
td
>
<
td
><
a
href
="article!delete.action?id=${id}"
>
删除
</
a
></
td
>
</
tr
>
<
tr
>
<
td
>
${content}
</
td
>
</
tr
>
</
s:iterator
>
</
table
>
</
body
>
</
html
>
如果数据库中有初始数据的话,该项目运行效果如下图:
到目前为止,还没有涉及到getModel()、prepareModel()、以及prepare系列的方法,但是,一旦需要添加或者删除文章,这一系列的方法就有作用了。在Struts 2中,由于没有了ActionForm的概念,所有的页面传入参数都会被注入到Action中,如果不想在Action中搞太多的getter和setter,最有效的方法就是提供一个Model对象,这时候拦截器会把页面参数注入到Model中,而在目前的项目中,没有比Entity类更适合做Model对象的了。通过观察CrudActionSupport基类,可以发现只有在执行save和input方法之前,才会执行prepareModel方法,该方法可以保证getModel方法返回的对象不是一个空指针,而调用delete方法之前Model对象没有初始化,但是delete方法只需要一个id作为参数,因此,可以在Action中增加一个id属性来满足要求。这时候,有改动的几行代码如下:
private
Long id;
private
Article article;
public
void
setId(Long id) {
this
.id
=
id;
}
@Override
protected
void
prepareModel()
throws
Exception {
if
(id
!=
null
) {
article
=
articleManager.get(id);
}
else
{
article
=
new
Article();
}
}
public
Article getModel() {
return
article;
}
@Override
public
String delete()
throws
Exception {
articleManager.delete(id);
return
RELOAD;
}
这里需要特别关注的是delete方法返回的值,为RELOAD,这是一个在基类中定义好了的字符串。返回该字符串的目的,是为了在delete方法执行完之后,不返回任何视图页面,而是以redirect的方式再次调用article.action,以便显示删除文章后的结果。因此,需要在ArticleAction中使用@Result注解,如下:
@Results( { @Result(name
=
CrudActionSupport.RELOAD, location
=
"
article.action
"
, type
=
"
redirect
"
) })
经过如上修改,这时候再运行应用,就发现能够删除文章了。
再来实现添加文章的功能,从上面的article.jsp中可以看出,添加文章的链接为article!input.action,此时,会运行ArticleAction的input方法,该方法只是简单返回article-input.jsp视图文件作为用户输入文章的接口,article-input.jsp的代码如下:
<%
@ page language
=
"
java
"
contentType
=
"
text/html; charset=UTF-8
"
pageEncoding
=
"
UTF-8
"
%>
<!
DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"
>
<
html
>
<
head
>
<
meta
http-equiv
="Content-Type"
content
="text/html; charset=UTF-8"
>
<
title
>
Insert title here
</
title
>
</
head
>
<
body
>
<
form
id
="inputForm"
action
="article!save.action"
method
="post"
>
<
table
class
="inputView"
>
<
tr
>
<
td
>
主题:
</
td
>
<
td
><
input
type
="text"
name
="subject"
size
="40"
id
="subject"
/></
td
>
</
tr
>
<
tr
>
<
td
>
内容:
</
td
>
<
td
><
textarea
name
="content"
id
="subject"
></
textarea
></
td
>
</
tr
>
<
tr
>
<
td
colspan
="2"
>
<
input
type
="submit"
value
="提交"
/>
<
input
type
="button"
value
="取消"
onclick
="history.back()"
/>
</
td
>
</
tr
>
</
table
>
</
form
>
</
body
>
</
html
>
而ArticleAction中只需要修改如下几行,由于ModelDriven拦截器已经把网页中传入的数据注入到了article对象中,所以save方法中只需要执行简单的保存操作即可:
@Override
public
String input()
throws
Exception {
return
INPUT;
}
@Override
public
String save()
throws
Exception {
articleManager.save(article);
return
RELOAD;
}
至于实现文章的修改功能,那也是通过input方法和save方法实现的,只不过此时网页参数中会包含一个有效的id,而prepare系列的方法会根据该id先从数据库中提取数据,然后显示在article-input.jsp中,用户修改后,再调用save方法保存到数据库中。为减少本博文长度,该功能此处不做示范。
通过上面的步骤可以发现,
使用SpringSide 3中推荐的CRUD一体的模式,可以有效减少Action的数量和JSP文件的数量,每实现一个增删查改功能,只需要一个Action和两个JSP,但是,程序员一定要对其中的数据流向有充足的认识,才能理清它们之间的关系,不至于晕头转向。
到这里大家会发现,ArticleAction谁都可以访问,一点都不安全,所以第八步我会探讨如何让ArticleAction和SpringSecurity一起工作,至于第九步,当然是把项目从单数据库环境更改到多数据库环境了。具体内容,且看下回分解!
评论
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2009-07-20 09:28 by
YangL
中写的有点少了,呵呵
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)[未登录]
回复
更多评论
2009-07-20 17:27 by
Eric
这个中确实是写得太少了点...
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2009-07-20 20:29 by
个性艺术签名
中确实是写得太少了点
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2009-07-21 16:29 by
虎啸龙吟
感觉这块写的不够,比方说:prepare这块。
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2009-07-21 18:06 by
海边沫沫
楼上几位别心急,我还没收工呢。
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2009-07-23 22:57 by
zhj
我在调用article!save.action时候报错
2009-07-23 22:50:16,937 [http-8080-2] ERROR [500.jsp] - The save() is not defined in action class com.opensymphony.xwork2.ActionSupport
java.lang.IllegalArgumentException: The save() is not defined in action class com.opensymphony.xwork2.ActionSupport
at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:453)
at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:279)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:242)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:52)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:468)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:99)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:109)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.basicauth.BasicProcessingFilter.doFilterHttp(BasicProcessingFilter.java:174)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:277)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Unknown Source)
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2009-07-25 12:55 by
海边沫沫
@zhj
不要老在我的博客中发这么长的错误代码呀,影响别人阅读的。一般来说发前几行就足够了。
这里的错误说的是你的ArticleAction中没有定义save方法,你再检查检查。
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)[未登录]
回复
更多评论
2009-08-04 17:17 by
lx
顶了,感谢楼主
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2009-11-04 21:32 by
sina
最近在用springside3做manytoone的时候遇到了很大麻烦,就是在修改many一方对象里的对应one方的外键的时候会报错,与
http://www.javaeye.com/problems/11098这个帖子里的状况类似
,还请海边沫沫帮忙研究一下
其间会报
[com.opensymphony.xwork2.ognl.OgnlValueStack] - Error setting expression 'useType.id' with value '[Ljava.lang.String;@8fff06'
ognl.OgnlException: target is null for setProperty(null, "id", [Ljava.lang.String;@8fff06)
以及
identifier of an instance of pplove.entity.entities.Status was altered from 5 to 2; nested exception is org.hibernate.HibernateException: identifier of an instance of pplove.entity.entities.Status was altered from 5 to 2
的错误
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2009-11-27 10:27 by
skyrocket
aused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'databaseDefinitionSource': FactoryBean threw exception on object creation; nested exception is org.hibernate.hql.ast.QuerySyntaxException: Resource is not mapped [from Resource r left join fetch r.authorityList WHERE r.resourceType=? ORDER BY r.position ASC] 请问博主我在启动Tomcat时候为什么报这个错误啊
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)[未登录]
回复
更多评论
2009-11-27 11:08 by
zhj
经常报找不到action里的某方法。。。,明明有此方法 不知道为啥
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)[未登录]
回复
更多评论
2009-12-24 14:17 by
aaa
啥时候出下
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2011-12-04 15:07 by
plume
session.delete()删除的时候未删除成功,并且后台也没有报错。
#
re: 使用SpringSide 3.1.4.3开发Web项目的全过程(中)
回复
更多评论
2012-04-28 15:17 by
十四
劲啊
新用户注册
刷新评论列表
只有注册用户
登录
后才能发表评论。
网站导航:
博客园
IT新闻
Chat2DB
C++博客
博问
管理
相关文章:
在SpringSide 3 中使用JCaptcha
使用SpringSide 3.1.4.3开发Web项目的全过程(下)
使用SpringSide 3.1.4.3开发Web项目的全过程(中)
使用SpringSide 3.1.4.3开发Web项目的全过程(上)
在SpringSide 3 中使用多个数据库的方法
SpringSide 3 中的多数据源配置的问题
SpringSide 3 中的数据库访问层
使用Fedora 10 进行Java开发,发两张截图让大家尝尝鲜
SpringSide 3 中的 Struts 2
SpringSide 3 中的安全框架
Powered by:
BlogJava
Copyright © 京山游侠
日历
<
2009年7月
>
日
一
二
三
四
五
六
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
7
8
常用链接
我的随笔
我的评论
我的参与
最新评论
留言簿
(72)
给我留言
查看公开留言
查看私人留言
随笔分类
J2EE学习及探索(3)
Linux和Java(4)
NetBeans与J2ME(5)
SpringSide开发实战(24)
SVN与源代码管理(3)
拥抱Eclipse RCP(11)
随笔档案
2014年3月 (1)
2014年2月 (2)
2014年1月 (2)
2013年12月 (1)
2009年8月 (1)
2009年7月 (6)
2009年4月 (3)
2009年3月 (1)
2008年12月 (4)
2008年11月 (1)
2008年3月 (1)
2008年2月 (2)
2008年1月 (1)
2007年12月 (1)
2007年10月 (3)
2007年8月 (3)
2007年7月 (2)
2007年3月 (3)
2007年1月 (2)
2006年12月 (5)
2006年11月 (4)
2006年9月 (1)
收藏夹
我常用的技术资料(7)
我的博客系列
我的 .net 博客
我的 c++ 博客
搜索
积分与排名
积分 - 656133
排名 - 73
最新评论
1. re: SpringSide 3 中的安全框架
通俗易懂,谢谢楼主
--薄荷柠檬草
2. re: 浅论Maven和Git的原理及展示其与Eclipse的集成
就是单纯的表示下 感谢! 入门阶段看了很多介绍 从你这里收货最大!多谢!
--laowang
3. re: 使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军[未登录]
10年过去了。。
--pass86
4. re: SpringSide 3 中的安全框架
楼主的文章果然讲的好清晰,谢谢分享
--匿
5. re: 浅论Maven和Git的原理及展示其与Eclipse的集成
评论内容较长,点击标题查看
--zuidaima
阅读排行榜
1. 使用Eclipse RCP进行桌面程序开发(一):快速起步(69764)
2. SpringSide 3 中的安全框架(65696)
3. 使用Eclipse RCP进行桌面程序开发(二):菜单、工具栏和对话框(36530)
4. 使用Eclipse RCP进行桌面程序开发(三):视图和透视图(33488)
5. SpringSide开发实战(一):使用Eclipse让SpringSide跑起来(31480)
评论排行榜
1. 使用Eclipse RCP进行桌面程序开发(一):快速起步(54)
2. SpringSide开发实战(七):在项目中整合FCKeditor(42)
3. 使用Eclipse RCP进行桌面程序开发(三):视图和透视图(40)
4. SpringSide 3 的进步(33)
5. 使用Eclipse RCP进行桌面程序开发(二):菜单、工具栏和对话框(30)