- 浏览: 14307 次
- 性别:
- 来自: 北京
最新评论
Struts2中的零配置与CoC(Convention over Configration)
关键字: struts2 coc
摘要:介绍Struts2中的零配置(Zero Configuration),以及如何用COC来更好地简化Struts2的配置。在第一章,我使用Maven来创建一个起点项目;第二章,以该项目为例,讲解如何使用Struts2的零配置;第三章,论述第二章中的实现方式的缺陷,然后讲解如何使用COC来改进这些缺陷,并进一步简化Struts2的配置。附件是这篇文章用到的示例代码。
一、从零开始
这里,我将建立一个新的示例项目,作为讲解的起点。我使用JDK 6、Maven 2、Eclipse 3.3来建立这个示例,如果读者对Maven2不熟也没关系,这只是个示例。
首先,运行下边的命令:
mvn archetype:create -DgroupId=demo.struts -DartifactId=demo-struts-coc -DarchetypeArtifactId=maven-archetype-webapp
这会建立如下的目录结构:
|- POM.xml
|- src
|- main
|- resources
|- webapp
|- index.jsp
|- WEB-INF
|- web.xml
然后我们在src/main目录下新建一个名为java的目录,用来放置java代码。在src下建立test目录,并在test目录下建立java目录,用来放置测试代码。另外,我这个示例不想使用JSP,所以我将src/main/webapp目录下的index.jsp改为index.html。
现在,需要配置该项目要用到哪些lib。在POM.xml中加入struts2-core:
xml 代码
1. <dependency>
2. <groupId>org.apache.struts</groupId>
3. <artifactId>struts2-core</artifactId>
4. <version>2.0.9</version>
5. </dependency>
另外,我想在Eclipse里使用jetty来启动项目并进行测试,所以在POM.xml中再加入jetty、jetty-util、servlet-api等的依赖,详情见附件。
我希望使用Eclipse来作为这个项目的IDE,所以,我在命令行状态下,进入这个项目所在的目录,运行:
mvn eclipse:eclipse
然后使用Eclipse导入这个项目。如果你是第一次用Eclipse导入用Maven生成的项目,那你需要在Eclipse里配置一个名叫 M2_REPO的Variable,指向你的Maven 2的repository目录。缺省情况下,它应该位于${user.home}/.m2/repository。
OK!现在我们已经可以在Eclipse中进行工作了。
修改src/main/webapp/WEB-INF/web.xml,加入struts2的FilterDispatcher并设置filter- mapping。在这个示例中我将url-pattern设为"/app/*",也就是说,url的匹配是基于路径来做的。这只是我的个人喜好而已,你也可以将它设成"*"。
既然是在讲struts2的零配置,当然是可以不要任何配置文件的。但是为了更好地进行“配置”,我还是建立了struts.xml文件(在 src/main/resources目录下)。我不喜欢url最后都有个action后缀,现在,我在struts.xml中配置 struts.action.extension,将这个后缀去掉:
xml 代码
1. <struts>
2. <constant name="struts.action.extension" value="" />
3. </struts>
然后我在src/test/java下建立demo/RunJetty.java文件,main方法如下:
java 代码
1. public static void main(String[] args) throws Exception {
2. Server server = new Server(8080); //也可以改成其它端口
3. File rootDir = new File(RunJetty.class.getResource("/").getPath()).getParentFile().getParentFile();
4. String webAppPath = new File(rootDir, "src/main/webapp").getPath();
5. new WebAppContext(server, webAppPath, "/");
6. server.start();
7. }
现在,在Eclipse里运行或调试这个RunJetty.java,用浏览器打开http://localhost:8080/看看吧。如果不出问题,应该可以访问到webapp目录下的index.html了。有了Jetty,你还在用MyEclipse或其它插件么?
二、零配置
首先要澄清一点,这里说的零配置并不是一点配置都没有,只是说配置很少而已。
Struts2(我只用过Struts 2.0.6和2.0.9,不清楚其它版本是否支持零配置)引入了零配置的新特性,元数据可以通过规则和注解来表达:A "Zero Configuration" Struts application or plugin uses no additional XML or properties files. Metadata is expressed through convention and annotation.
目前,这个新特性还在测试阶段,但经过一段时间的使用,我觉得这个特性已经可用。下面我讲一下如何使用它。
1. Actions的定位
以前需要在xml配置文件中配置Action的name和class,如果使用零配置,所带来的一个问题就是如何定位这些Action。我们需要在 web.xml中找到struts2的filter的配置,增加一个名为actionPackages的init-param,它的值是一个以逗号分隔的 Java包名列表,比如:demo.actions1,demo.actions2。struts2将会扫描这些包(包括这些包下边的子包),在这些包下,所有实现了Action接口的或者是类名以“Action”结尾的类都会被检查到,并被当做Action。
以前,我们写Action必须要实现Action接口或者继承ActionSupport。但是,上面提到的类名以"Action"结尾的类并不需要这样做,它可以是一个POJO,Struts2支持POJO Action!
下面是actionPackages的配置示例:
xml 代码
1. <filter>
2. <filter-name>struts2</filter-name>
3. <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
4. <init-param>
5. <param-name>actionPackages</param-name>
6. <param-value>demo.actions1,demo.actions2</param-value>
7. </init-param>
8. </filter>
2. 示例
现在我们建立demo.actions1.app.person和demo.actions2.app.group两个包,在 demo.actions1.app.person包下建立ListPeopleAction.java,在 demo.actions2.app.group下建立ListGroupAction.java。作为示例,这两个类只是包含一个execute方法,返回"success"或"error",其它什么都不做:
java 代码
1. public String execute() {
2. return "success";
3. }
在Filter的配置中,我指定actionPackages为demo.actions1,demo.actions2,当系统启动时,Struts2 就会在这两个包下扫描到demo.actions1.app.person.ListPeopleAction和 demo.actions2.app.group.ListGroupAction。
3. Action and Package name
Struts2扫描到Action后,从actionPackages指定的包开始,子包名会成为这个Action的namespace,而Action 的name则由这个Action的类名决定。将类名首字母小写,如果类名以Action结尾,则去掉"Action"后缀,形成的名字就是这个 Action的名字。在如上所述的示例中,actionPackages指定为demo.actions1,demo.actions2,那么你可以这样访问demo.actions1.app.person.ListPeopleAction:
http://localhost:8080/app/person/listPeople
4. Results
Struts2是通过"Result"和"Results"两个类级别的annotations来指定Results的。
作为示例,我们在webapp目录下建两个html文件:success.html和error.html,随便写点什么内容都可以。现在假设我们访问 /app/person/listPeople时,或Action返回success就转到success.html页面,若是error就转到 error.html页面,这只需要在ListPeopleAction类上加上一段注解就可以了:
java 代码
1. @Results({
2. @Result(name="success", type=NullResult.class, value = "/success.html", params = {}),
3. @Result(name="error", type=NullResult.class, value = "/error.html", params = {})
4. })
5. public class ListPeopleAction {
6. public String execute() {
7. return "success";
8. }
9. }
同上,我们给ListGroupAction也加上注解。
现在,我们已经完成了一个零配置的示例。我们并没有在xml文件里配置ListPeopleAction和ListGroupAction,但它们已经可以工作了!
用Eclipse运行RunJetty,然后用浏览器访问http://localhost:8080/app/person/listPeople和 http://localhost:8080/app/group/listGroup看看,是不是正是success.html(或 error.html)的内容?
5. Namespaces
如上所述,namespace由包名所形成,但我们可以使用"Namespace"注解来自己指定namespace。
6. Parent Package
这个配置用得较少。Struts2提供一个"ParentPackage"注解来标识Action应该是属于哪个package。
三、使用COC
如上所述,Struts2用注解来实现零配置。然而,这不是我喜欢的方式。在我看来,这不过是将配置从XML格式换成了注解方式,并不是真的零配置。而且,这种方式也未必比XML形式的配置更好。另外,对元数据的修改必然会导致项目的重新编译和部署。还有,现在的Struts2版本似乎对Result注解中的params的处理有些问题。
其实,Struts2的actionPackages配置已经使用了COC,那为什么不能为Results也实现COC,从而去除这些每个Action都要写的注解?
在严谨的项目中,package、action的名称和页面的路径、名称一定存在着某种关系。比如,页面的路径可能和package是对应的,页面的名称可能和action的名称是对应的,或是根据某种法则运算得到。我们知道webwork2和struts2有个配置叫global-results。我们为什么不能根据这些对应规则写个Result,将它配到global-results中,从而真正免去result的配置?
事实上,我推荐Struts2的使用者只用Struts2输出XML或JSON,放弃UI,页面这层还是使用标准的HTML、CSS和一些JS组件来展现。许多人反映Struts2慢,确实,Struts2是慢,很慢!慢在哪儿?很大一部分因素是UI这层引起的,特别是使用了过多的Struts2的 tag,并使用了ajax theme。但是,如果我们放弃了Struts2的笨拙的UI,Result只输出XML或JSON,UI则使用标准的HTML+CSS,使用JS组件(DOJO、Adobe Spry Framework、YUI-Ext等)来操作Struts2的输出数据,情况将会如何?我们会得到一个高性能、高可配的、UI和应用服务器的职责分割更为明确、合理的、更易于静态化部署的开发组合。
这似乎是阉割了Struts2,但是这样阉割过的Struts2摆脱了性能低下的包袱,更轻、更现代化。
有些扯远了,言归正传,不管是让Struts2输出XML或JSON,还是输出页面,我们都有办法根据项目的规则写一个Result,将它配到global-results中,从而大大减少Result的配置。
假设我们让Struts2只输出JSON,有个jsonplugin可以做这件事。使用JsonResult时,不再需要知道页面的位置、名称等信息,它仅仅是数据输出,那么我们就可以将这个Result配成全局的,大部分Action将不再需要Result的配置。
作为示例,我假设我的例子中输出的两个html页面(success.html和error.html)是JSON,我们看看怎么免去我例子中的两个Action的Result注解。
首先,我们删去ListPeopleAction和ListGroupAction两个Action的注解,并修改struts.xml文件,加入:
xml 代码
1. <package name="demo-default" extends="struts-default">
2. <global-results>
3. <result name="success">/success.html</result>
4. </global-results>
5. </package>
请记住这只是一个示例,为了方便,我没在项目中加入jsonplugin来作真实的演示,我只是假设这个success是json输出,读者可以自行使用jsonplugin来作实验。
现在,离成功不远了,但是项目仍然不能正常运行。我们的Action返回success,但并不会匹配到global-results中配置。为什么呢?因为,我们这里是把global-results配置到"demo-default"这个package下的,而Struts2根据 actionPackages找到的Action不会匹配到这个package上。解决办法也很简单,还记得上面讲到的Parent Package吧?给Action加个注解,指定ParentPackage为"demo-default"。但这样可不是我喜欢的,其实有更好的办法,我们在struts.xml中加个constant就好了:
xml 代码
1. <constant name="struts.configuration.classpath.defaultParentPackage" value="demo-default" />
现在,大功告成!运行RunJetty来测试下吧!你可以访问/app/person/listPeople,可以访问/app/group /listGroup,而所有的配置仅仅是web.xml和struts.xml中的几行,我们的Java代码中也没有加注解。如果再加上几百个 Action呢?配置仍然就这几行。
可是,某些Action确实需要配置怎么办?对这些Action,你可以加注解,也可以针对这些Action来写些XML配置。一个项目中,大部分Action的配置是可以遵从一定规则的,可以使用规则来简化配置,只有少部分需要配置,这就是COC。
注:附件demo-struts-annotations.zip是使用注解实现零配置的示例代码,附件demo-struts-coc.zip是使用global-results后的示例代码。
另外,我以前写过一篇文章《改写Restful2ActionMapper让Struts2支持REST风格的URL映射》,这里所说的零配置并不适用于支持REST。也就是说,你要用REST风格的URL映射,你就必须配置。不过还好,使用REST风格后,配置并不复杂。
另外我见到不少人使用Spring来配置和管理Action,其实完全没有必要!设置struts.objectFactory 等于spring就可以了,如果在Action中有setService1,这个service1在Spring中有配置的话,它会自动注入的。 Javaeye论坛中早有相关的讨论。
参考:
http://struts.apache.org/2.x/docs/zero-configuration.html
http://struts.apache.org/2.x/docs/zero-configuration-scanning.html
* demo-struts-annotations.zip (8.4 KB)
* 描述: demo-struts-annotations.zip是使用注解实现零配置的示例代码。
* 下载次数: 281
* demo-struts-coc.zip (8.3 KB)
* 描述: demo-struts-coc.zip是使用global-results后的示例代码。
* 下载次数: 300
* 22:21
* 浏览 (3902)
* 论坛浏览 (7608)
* 评论 (17)
* 分类: Java
* 收藏
* 相关推荐
评论
allenny 2007-12-18 回复
UI确实很慢,但是我又不得不用S2的标签,请问楼主有什么办法能够改善S2的UI的性能。哪怕只是20%的改善也行啊。
seno 2007-12-09 回复
interceptor在哪里配置?
flashing 2007-10-31 回复
会用struts2,差别不是仅仅的一个1和2的问题,而是模型的问题。
williamy 2007-10-28 回复
如果struts 1也能零配置,各位大大,會用struts1還是struts2呢?
kyo100900 2007-10-28 回复
downpour 写道
楼主的CoC完全采用XML或者Json方式输出,可能多数人还接受不了,可能多数开发者还停留在JSP或者Freemarker的阶段。当然,对此个人有个人的喜欢,我觉得比较好的方式是任何一种方式仅仅提供一种Option,可以在各种Option中任意切换。
事实上,楼主的文章还欠缺了很大的一块,Struts2其实已经相当CoC了。Struts2所提供的CoC,主要包含2个主要的阶段:
1. 根据URL命名映射到相应的Action类进行执行。
这种方式楼主已经进行了介绍,其实就是利用namespace+url映射到package+Action类。
2. 根据URL命名,自动寻找Result
这一点楼主没有说。事实上Struts2提供了一个插件,叫做Codebehind Plugin。它可以自动根据URL去寻找对应目录下的jsp,ftl模板或者vm模板。具体的URL地址在:http://struts.apache.org/2.x/docs/codebehind-plugin.html。详细内容一看就明白了,无须过多解释。
将上述2点结合起来在项目中使用,可以极大程度上简化配置,要是在加上annotation,至少可以减少90%以上的配置。不过要真正做到0配置,我想还是有些难度的。如果真要追求URL漂亮或者URL的Rest化,就不得不改写ActionMapper了。
downpour能把Codebehind讲明白点吗?
avi2 2007-10-16 回复
downpour 写道
楼主的CoC完全采用XML或者Json方式输出,可能多数人还接受不了,可能多数开发者还停留在JSP或者Freemarker的阶段。当然,对此个人有个人的喜欢,我觉得比较好的方式是任何一种方式仅仅提供一种Option,可以在各种Option中任意切换。
事实上,楼主的文章还欠缺了很大的一块,Struts2其实已经相当CoC了。Struts2所提供的CoC,主要包含2个主要的阶段:
1. 根据URL命名映射到相应的Action类进行执行。
这种方式楼主已经进行了介绍,其实就是利用namespace+url映射到package+Action类。
2. 根据URL命名,自动寻找Result
这一点楼主没有说。事实上Struts2提供了一个插件,叫做Codebehind Plugin。它可以自动根据URL去寻找对应目录下的jsp,ftl模板或者vm模板。具体的URL地址在:http://struts.apache.org/2.x/docs/codebehind-plugin.html。详细内容一看就明白了,无须过多解释。
将上述2点结合起来在项目中使用,可以极大程度上简化配置,要是在加上annotation,至少可以减少90%以上的配置。不过要真正做到0配置,我想还是有些难度的。如果真要追求URL漂亮或者URL的Rest化,就不得不改写ActionMapper了。
貌似你的路子比楼主正很多啊
colin4k 2007-10-11 回复
结合楼主的思路,再加上struts2自己的通配符,我是这样做的,struts.xml这样配置
Java代码 复制代码
1. <action name="*/*" method="{2}" class="workbench.web.actions.{1}Action">
2. <result name="custom">/view/{1}/${target}.jsp</result>
3. </action>
<action name="*/*" method="{2}" class="workbench.web.actions.{1}Action">
<result name="custom">/view/{1}/${target}.jsp</result>
</action>
然后写一个BaseAction:
Java代码 复制代码
1. public abstract class BaseAction {
2. protected final String CUSTOM = "custom";
3. private String target;
4. protected final Log logger = LogFactory.getLog(getClass());
5. public String getTarget() {
6. return target;
7. }
8. public void setTarget(String target) {
9. this.target = target;
10. }
11.
12. protected String render(String _target){
13. setTarget(_target);
14. return CUSTOM;
15. }
16. }
public abstract class BaseAction {
protected final String CUSTOM = "custom";
private String target;
protected final Log logger = LogFactory.getLog(getClass());
public String getTarget() {
return target;
}
public void setTarget(String target) {
this.target = target;
}
protected String render(String _target){
setTarget(_target);
return CUSTOM;
}
}
然后继承BaseAction
Java代码 复制代码
1. public class UserAction extends BaseAction{
2. private User user;
3. private UserService userService;
4. public void setUserService(UserService userService) {
5. this.userService = userService;
6. }
7.
8. public User getUser() {
9. return user;
10. }
11. public void setUser(User user) {
12. this.user = user;
13. }
14. public String test(){
15. user = userService.get(1l);
16. return render("test");
17. }
18. }
public class UserAction extends BaseAction{
private User user;
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String test(){
user = userService.get(1l);
return render("test");
}
}
这样在action里面,可以通过return render(target)来间接实现零配置转发到指定的jsp页面
URL:http://localhost:8080/workbench/User/test
downpour 2007-10-10 回复
楼主的CoC完全采用XML或者Json方式输出,可能多数人还接受不了,可能多数开发者还停留在JSP或者Freemarker的阶段。当然,对此个人有个人的喜欢,我觉得比较好的方式是任何一种方式仅仅提供一种Option,可以在各种Option中任意切换。
事实上,楼主的文章还欠缺了很大的一块,Struts2其实已经相当CoC了。Struts2所提供的CoC,主要包含2个主要的阶段:
1. 根据URL命名映射到相应的Action类进行执行。
这种方式楼主已经进行了介绍,其实就是利用namespace+url映射到package+Action类。
2. 根据URL命名,自动寻找Result
这一点楼主没有说。事实上Struts2提供了一个插件,叫做Codebehind Plugin。它可以自动根据URL去寻找对应目录下的jsp,ftl模板或者vm模板。具体的URL地址在:http://struts.apache.org/2.x/docs/codebehind-plugin.html。详细内容一看就明白了,无须过多解释。
将上述2点结合起来在项目中使用,可以极大程度上简化配置,要是在加上annotation,至少可以减少90%以上的配置。不过要真正做到0配置,我想还是有些难度的。如果真要追求URL漂亮或者URL的Rest化,就不得不改写ActionMapper了。
dunjh 2007-10-10 回复
无需修改,自动的,其他部分照着楼主的说明做,只是Action class里面不是一个execute方法,而是各个你自己的action method。你可以自己试一下,我试过没有问题,Struts2.0.9
不过个人最后还是决定在需要使用Spring管理action的情况下放弃用这种零配置了,因为如果照我上面的帖子里说的,把class的全名作为bean name的话,applicationContext.xml看起来实在是不伦不类,而且没办法在写test的时候做到autowire自动注入。看了一下Struts2的code, 在这个文件里:
org\apache\struts2\config\ClasspathConfigurationProvider.processActionClass(Class cls, String[] pkgs)
有这么一段:
Java代码 复制代码
1. ActionConfig actionConfig = new ActionConfig();
2. actionConfig.setClassName(cls.getName());
3. actionConfig.setPackageName(actionPackage);
ActionConfig actionConfig = new ActionConfig();
actionConfig.setClassName(cls.getName());
actionConfig.setPackageName(actionPackage);
如果这里setClassName里面改成设定cls.getSimpleName()的话(可能首字母要转成小写),应该就可以更好的适应Spring的情形了,但仔细想想也很难实现,因为这样要求必须在Spring里配置action (否则用Simplename,如果Spring plugin不能load action,则Struts2也无法load到action),实在违背了零配置的初衷。而且没有其他配置的情况下,也很难决定究竟什么时候用 simpleName,什么时候用全名。因此,这确实是个两难的问题,也难怪Struts2采用这样的实现了。
话说回来,反正如果要写Spring的配置文件的话,也不在乎在Struts的配置文件里多写一行了,唉……
kusoft 2007-10-10 回复
to dunjh兄:能不能指点一下,如何修改源代码.才能实现
1)*/*/People!list.action
(2)*/*/People!save.action
(3)*/*/People!edit.action
williamy 2007-10-10 回复
我改写的struts是1.2.4的,这些小菜功能,早就加了,请问它有什么用?搞来搞去,我突然发现,还是一个MVC而已
dunjh 2007-10-10 回复
从webwork时代开始,楼上的需求就是可以做到的。
分别调用的URL是:
(1)*/*/People!list.action
(2)*/*/People!save.action
(3)*/*/People!edit.action
虽然用叹号不太好看,但的确是可以用的。如果要用楼上的方式的话,恐怕要自己去hack Struts2的Code了。
不过还是有一个问题,对于原文中的这一段:
“另外我见到不少人使用Spring来配置和管理Action,其实完全没有必要!设置struts.objectFactory 等于spring就可以了,如果在Action中有setService1,这个service1在Spring中有配置的话,它会自动注入的。 Javaeye论坛中早有相关的讨论。”
似乎如果用Struts2来读入Action而不是用Spring读入的话,property的确是可以自动注入进去,不过假如Action实现了Spring的InitializingBean方法的话,其afterPropertiesSet()是不会被自动调用的。也许是我的配置有问题,可如果不是在web.xml里配置自动读入action的话就完全没有问题。在Struts2的mailing list和Jira里都没搜到这方面的问题,更新到Struts2.0.9也没能解决。正在努力看code想办法中……
这个问题已经解决。的确是我的配置有问题。因为如果让Struts2自动扫描Action的Class文件的话,它自然会把class的全名作为 Action的ClassName,而在load action的时候,Spring的plugin会用全名来搜索bean配置,而我在applicationContext.xml的配置还是旧的,bean name用的并不是全名,自然会找不到bean。于是,Spring plugin就只好用Struts2的方式来load action,action不是由Spring管理的,自然没办法用spring方式来初始化。
如果需要使用Spring对action进行控制,比如像这样的InitializingBean,或者用Acegi来控制action的方法访问的话,还是必须要在spring的applicationContext里面进行配置的。如果不配置的话,action并不是有Spring管理的,虽然action里的property还是可以被注入,不过这个应该是通过intercepter实现的吧,还没有仔细研究过。
个人认为这样的零配置如果是用Json的话还是很有用的,对大规模系统来说,配置应该还是越少越好的吧。非常感谢楼主的文章,教会了我不少东西。
kusoft 2007-10-09 回复
使用annotation,能不能一个Action里的多个方法.配置成对应多个URL.
例如:
Java代码 复制代码
1. public class PeopleAction{
2.
3. public String list(){
4. return "success";
5. }
6. public String save(){
7. return "success";
8. }
9. public String edit(){
10. return "success";
11. }
12. }
public class PeopleAction{
public String list(){
return "success";
}
public String save(){
return "success";
}
public String edit(){
return "success";
}
}
分别调用的URL是;
(1)*/*/listPeople.action
(2)*/*/savePeople.action
(3)*/*/editPeople.action
这样的话,写起的action不会太多.
andlu 2007-08-16 回复
pn2006 写道
多个Action返回sussess但返回页面可能并不一样,这样配置根本解决不了问题!
楼上就没读懂这篇文章,也许我那太简单的示例让大家误会了,我道歉。
如果你坚持要action返回页面,那必然会因为页面的位置不同而需要配置。文中已经提了,你可以使用注解,更好的方法是定个规则,写个Global Result(除非你项目中页面和Action之间的对应毫无规则)。即使你不想自己写Result,Struts2也是可以配置页面的缺省位置及后缀等信息的,只是我文中没有讲。不管怎么做,都不需要以前那么多配置。没能力自己写Result又需要让Struts2返回页面,而且坚持不用注解的,那么没必要读这篇文章。
Struts2只是提供了一些配置方面的机制,怎么用还是看我们自己,你可以用得很简单很灵活,也可以用得很复杂很繁琐,Struts2本身并没象新框架一样使用COC大幅减少配置,但不代表它没这能力。如果坚持用以前webwork2的传统办法来想问题,这篇文章根本就没意义。
为什么传统思想会根深蒂固?为什么传统教科书上说了什么就奉为金科玉律?自己写个Result很难么?放弃XML配置很难么?放弃Struts2的UI,换成XML/JSON很难么?这些工作真的没有想象中那么难。即使再实现个精简后的Struts2,也没有想象中那么难。
当然,对于已经进行开发的Struts2项目,再改架构是有难度。我仅仅是介绍了Struts2的一些机制,并给出一些改进思路,是否理解我真正的意图,以及怎么用它,还看大家自己。
另外,我并不是推崇Struts2,事实上我并不喜欢它!我希望大家能明白我真正的意图:只要有思想,不管什么框架你总能发现可以改进的地方,否则只能人云亦云,就等着这些框架自己进行改进吧。
pn2006 2007-08-16 回复
多个Action返回sussess但返回页面可能并不一样,这样配置根本解决不了问题!
andlu 2007-08-16 回复
jianfeng008cn 写道
ui我可以不用tag啊 没道理连direct这些功能都去掉吧 局限性太大了 你这个返回json和xml的东西不用说大家也知道怎么做到0配置,真正需要的地方却没讲,关注ing
我并没去掉direct等功能。COC的真正意义在于让规则做大部分事,特殊需要的再用配置。你想redirect,你想chain,都可以。至于说大家都知道怎么做到json和xml的0配置,事实上并非如此,如果有比我的demo-struts-coc示例代码更简洁的办法,可以贴出来看看,让大家共同提高。
另外,这篇文章仅仅是在讲述struts2的零配置和一些改进,你觉得有哪些真正需要的地方没讲呢?
jianfeng008cn 2007-08-16 回复
ui我可以不用tag啊 没道理连direct这些功能都去掉吧 局限性太大了 你这个返回json和xml的东西不用说大家也知道怎么做到0配置,真正需要的地方却没讲,关注ing
关键字: struts2 coc
摘要:介绍Struts2中的零配置(Zero Configuration),以及如何用COC来更好地简化Struts2的配置。在第一章,我使用Maven来创建一个起点项目;第二章,以该项目为例,讲解如何使用Struts2的零配置;第三章,论述第二章中的实现方式的缺陷,然后讲解如何使用COC来改进这些缺陷,并进一步简化Struts2的配置。附件是这篇文章用到的示例代码。
一、从零开始
这里,我将建立一个新的示例项目,作为讲解的起点。我使用JDK 6、Maven 2、Eclipse 3.3来建立这个示例,如果读者对Maven2不熟也没关系,这只是个示例。
首先,运行下边的命令:
mvn archetype:create -DgroupId=demo.struts -DartifactId=demo-struts-coc -DarchetypeArtifactId=maven-archetype-webapp
这会建立如下的目录结构:
|- POM.xml
|- src
|- main
|- resources
|- webapp
|- index.jsp
|- WEB-INF
|- web.xml
然后我们在src/main目录下新建一个名为java的目录,用来放置java代码。在src下建立test目录,并在test目录下建立java目录,用来放置测试代码。另外,我这个示例不想使用JSP,所以我将src/main/webapp目录下的index.jsp改为index.html。
现在,需要配置该项目要用到哪些lib。在POM.xml中加入struts2-core:
xml 代码
1. <dependency>
2. <groupId>org.apache.struts</groupId>
3. <artifactId>struts2-core</artifactId>
4. <version>2.0.9</version>
5. </dependency>
另外,我想在Eclipse里使用jetty来启动项目并进行测试,所以在POM.xml中再加入jetty、jetty-util、servlet-api等的依赖,详情见附件。
我希望使用Eclipse来作为这个项目的IDE,所以,我在命令行状态下,进入这个项目所在的目录,运行:
mvn eclipse:eclipse
然后使用Eclipse导入这个项目。如果你是第一次用Eclipse导入用Maven生成的项目,那你需要在Eclipse里配置一个名叫 M2_REPO的Variable,指向你的Maven 2的repository目录。缺省情况下,它应该位于${user.home}/.m2/repository。
OK!现在我们已经可以在Eclipse中进行工作了。
修改src/main/webapp/WEB-INF/web.xml,加入struts2的FilterDispatcher并设置filter- mapping。在这个示例中我将url-pattern设为"/app/*",也就是说,url的匹配是基于路径来做的。这只是我的个人喜好而已,你也可以将它设成"*"。
既然是在讲struts2的零配置,当然是可以不要任何配置文件的。但是为了更好地进行“配置”,我还是建立了struts.xml文件(在 src/main/resources目录下)。我不喜欢url最后都有个action后缀,现在,我在struts.xml中配置 struts.action.extension,将这个后缀去掉:
xml 代码
1. <struts>
2. <constant name="struts.action.extension" value="" />
3. </struts>
然后我在src/test/java下建立demo/RunJetty.java文件,main方法如下:
java 代码
1. public static void main(String[] args) throws Exception {
2. Server server = new Server(8080); //也可以改成其它端口
3. File rootDir = new File(RunJetty.class.getResource("/").getPath()).getParentFile().getParentFile();
4. String webAppPath = new File(rootDir, "src/main/webapp").getPath();
5. new WebAppContext(server, webAppPath, "/");
6. server.start();
7. }
现在,在Eclipse里运行或调试这个RunJetty.java,用浏览器打开http://localhost:8080/看看吧。如果不出问题,应该可以访问到webapp目录下的index.html了。有了Jetty,你还在用MyEclipse或其它插件么?
二、零配置
首先要澄清一点,这里说的零配置并不是一点配置都没有,只是说配置很少而已。
Struts2(我只用过Struts 2.0.6和2.0.9,不清楚其它版本是否支持零配置)引入了零配置的新特性,元数据可以通过规则和注解来表达:A "Zero Configuration" Struts application or plugin uses no additional XML or properties files. Metadata is expressed through convention and annotation.
目前,这个新特性还在测试阶段,但经过一段时间的使用,我觉得这个特性已经可用。下面我讲一下如何使用它。
1. Actions的定位
以前需要在xml配置文件中配置Action的name和class,如果使用零配置,所带来的一个问题就是如何定位这些Action。我们需要在 web.xml中找到struts2的filter的配置,增加一个名为actionPackages的init-param,它的值是一个以逗号分隔的 Java包名列表,比如:demo.actions1,demo.actions2。struts2将会扫描这些包(包括这些包下边的子包),在这些包下,所有实现了Action接口的或者是类名以“Action”结尾的类都会被检查到,并被当做Action。
以前,我们写Action必须要实现Action接口或者继承ActionSupport。但是,上面提到的类名以"Action"结尾的类并不需要这样做,它可以是一个POJO,Struts2支持POJO Action!
下面是actionPackages的配置示例:
xml 代码
1. <filter>
2. <filter-name>struts2</filter-name>
3. <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
4. <init-param>
5. <param-name>actionPackages</param-name>
6. <param-value>demo.actions1,demo.actions2</param-value>
7. </init-param>
8. </filter>
2. 示例
现在我们建立demo.actions1.app.person和demo.actions2.app.group两个包,在 demo.actions1.app.person包下建立ListPeopleAction.java,在 demo.actions2.app.group下建立ListGroupAction.java。作为示例,这两个类只是包含一个execute方法,返回"success"或"error",其它什么都不做:
java 代码
1. public String execute() {
2. return "success";
3. }
在Filter的配置中,我指定actionPackages为demo.actions1,demo.actions2,当系统启动时,Struts2 就会在这两个包下扫描到demo.actions1.app.person.ListPeopleAction和 demo.actions2.app.group.ListGroupAction。
3. Action and Package name
Struts2扫描到Action后,从actionPackages指定的包开始,子包名会成为这个Action的namespace,而Action 的name则由这个Action的类名决定。将类名首字母小写,如果类名以Action结尾,则去掉"Action"后缀,形成的名字就是这个 Action的名字。在如上所述的示例中,actionPackages指定为demo.actions1,demo.actions2,那么你可以这样访问demo.actions1.app.person.ListPeopleAction:
http://localhost:8080/app/person/listPeople
4. Results
Struts2是通过"Result"和"Results"两个类级别的annotations来指定Results的。
作为示例,我们在webapp目录下建两个html文件:success.html和error.html,随便写点什么内容都可以。现在假设我们访问 /app/person/listPeople时,或Action返回success就转到success.html页面,若是error就转到 error.html页面,这只需要在ListPeopleAction类上加上一段注解就可以了:
java 代码
1. @Results({
2. @Result(name="success", type=NullResult.class, value = "/success.html", params = {}),
3. @Result(name="error", type=NullResult.class, value = "/error.html", params = {})
4. })
5. public class ListPeopleAction {
6. public String execute() {
7. return "success";
8. }
9. }
同上,我们给ListGroupAction也加上注解。
现在,我们已经完成了一个零配置的示例。我们并没有在xml文件里配置ListPeopleAction和ListGroupAction,但它们已经可以工作了!
用Eclipse运行RunJetty,然后用浏览器访问http://localhost:8080/app/person/listPeople和 http://localhost:8080/app/group/listGroup看看,是不是正是success.html(或 error.html)的内容?
5. Namespaces
如上所述,namespace由包名所形成,但我们可以使用"Namespace"注解来自己指定namespace。
6. Parent Package
这个配置用得较少。Struts2提供一个"ParentPackage"注解来标识Action应该是属于哪个package。
三、使用COC
如上所述,Struts2用注解来实现零配置。然而,这不是我喜欢的方式。在我看来,这不过是将配置从XML格式换成了注解方式,并不是真的零配置。而且,这种方式也未必比XML形式的配置更好。另外,对元数据的修改必然会导致项目的重新编译和部署。还有,现在的Struts2版本似乎对Result注解中的params的处理有些问题。
其实,Struts2的actionPackages配置已经使用了COC,那为什么不能为Results也实现COC,从而去除这些每个Action都要写的注解?
在严谨的项目中,package、action的名称和页面的路径、名称一定存在着某种关系。比如,页面的路径可能和package是对应的,页面的名称可能和action的名称是对应的,或是根据某种法则运算得到。我们知道webwork2和struts2有个配置叫global-results。我们为什么不能根据这些对应规则写个Result,将它配到global-results中,从而真正免去result的配置?
事实上,我推荐Struts2的使用者只用Struts2输出XML或JSON,放弃UI,页面这层还是使用标准的HTML、CSS和一些JS组件来展现。许多人反映Struts2慢,确实,Struts2是慢,很慢!慢在哪儿?很大一部分因素是UI这层引起的,特别是使用了过多的Struts2的 tag,并使用了ajax theme。但是,如果我们放弃了Struts2的笨拙的UI,Result只输出XML或JSON,UI则使用标准的HTML+CSS,使用JS组件(DOJO、Adobe Spry Framework、YUI-Ext等)来操作Struts2的输出数据,情况将会如何?我们会得到一个高性能、高可配的、UI和应用服务器的职责分割更为明确、合理的、更易于静态化部署的开发组合。
这似乎是阉割了Struts2,但是这样阉割过的Struts2摆脱了性能低下的包袱,更轻、更现代化。
有些扯远了,言归正传,不管是让Struts2输出XML或JSON,还是输出页面,我们都有办法根据项目的规则写一个Result,将它配到global-results中,从而大大减少Result的配置。
假设我们让Struts2只输出JSON,有个jsonplugin可以做这件事。使用JsonResult时,不再需要知道页面的位置、名称等信息,它仅仅是数据输出,那么我们就可以将这个Result配成全局的,大部分Action将不再需要Result的配置。
作为示例,我假设我的例子中输出的两个html页面(success.html和error.html)是JSON,我们看看怎么免去我例子中的两个Action的Result注解。
首先,我们删去ListPeopleAction和ListGroupAction两个Action的注解,并修改struts.xml文件,加入:
xml 代码
1. <package name="demo-default" extends="struts-default">
2. <global-results>
3. <result name="success">/success.html</result>
4. </global-results>
5. </package>
请记住这只是一个示例,为了方便,我没在项目中加入jsonplugin来作真实的演示,我只是假设这个success是json输出,读者可以自行使用jsonplugin来作实验。
现在,离成功不远了,但是项目仍然不能正常运行。我们的Action返回success,但并不会匹配到global-results中配置。为什么呢?因为,我们这里是把global-results配置到"demo-default"这个package下的,而Struts2根据 actionPackages找到的Action不会匹配到这个package上。解决办法也很简单,还记得上面讲到的Parent Package吧?给Action加个注解,指定ParentPackage为"demo-default"。但这样可不是我喜欢的,其实有更好的办法,我们在struts.xml中加个constant就好了:
xml 代码
1. <constant name="struts.configuration.classpath.defaultParentPackage" value="demo-default" />
现在,大功告成!运行RunJetty来测试下吧!你可以访问/app/person/listPeople,可以访问/app/group /listGroup,而所有的配置仅仅是web.xml和struts.xml中的几行,我们的Java代码中也没有加注解。如果再加上几百个 Action呢?配置仍然就这几行。
可是,某些Action确实需要配置怎么办?对这些Action,你可以加注解,也可以针对这些Action来写些XML配置。一个项目中,大部分Action的配置是可以遵从一定规则的,可以使用规则来简化配置,只有少部分需要配置,这就是COC。
注:附件demo-struts-annotations.zip是使用注解实现零配置的示例代码,附件demo-struts-coc.zip是使用global-results后的示例代码。
另外,我以前写过一篇文章《改写Restful2ActionMapper让Struts2支持REST风格的URL映射》,这里所说的零配置并不适用于支持REST。也就是说,你要用REST风格的URL映射,你就必须配置。不过还好,使用REST风格后,配置并不复杂。
另外我见到不少人使用Spring来配置和管理Action,其实完全没有必要!设置struts.objectFactory 等于spring就可以了,如果在Action中有setService1,这个service1在Spring中有配置的话,它会自动注入的。 Javaeye论坛中早有相关的讨论。
参考:
http://struts.apache.org/2.x/docs/zero-configuration.html
http://struts.apache.org/2.x/docs/zero-configuration-scanning.html
* demo-struts-annotations.zip (8.4 KB)
* 描述: demo-struts-annotations.zip是使用注解实现零配置的示例代码。
* 下载次数: 281
* demo-struts-coc.zip (8.3 KB)
* 描述: demo-struts-coc.zip是使用global-results后的示例代码。
* 下载次数: 300
* 22:21
* 浏览 (3902)
* 论坛浏览 (7608)
* 评论 (17)
* 分类: Java
* 收藏
* 相关推荐
评论
allenny 2007-12-18 回复
UI确实很慢,但是我又不得不用S2的标签,请问楼主有什么办法能够改善S2的UI的性能。哪怕只是20%的改善也行啊。
seno 2007-12-09 回复
interceptor在哪里配置?
flashing 2007-10-31 回复
会用struts2,差别不是仅仅的一个1和2的问题,而是模型的问题。
williamy 2007-10-28 回复
如果struts 1也能零配置,各位大大,會用struts1還是struts2呢?
kyo100900 2007-10-28 回复
downpour 写道
楼主的CoC完全采用XML或者Json方式输出,可能多数人还接受不了,可能多数开发者还停留在JSP或者Freemarker的阶段。当然,对此个人有个人的喜欢,我觉得比较好的方式是任何一种方式仅仅提供一种Option,可以在各种Option中任意切换。
事实上,楼主的文章还欠缺了很大的一块,Struts2其实已经相当CoC了。Struts2所提供的CoC,主要包含2个主要的阶段:
1. 根据URL命名映射到相应的Action类进行执行。
这种方式楼主已经进行了介绍,其实就是利用namespace+url映射到package+Action类。
2. 根据URL命名,自动寻找Result
这一点楼主没有说。事实上Struts2提供了一个插件,叫做Codebehind Plugin。它可以自动根据URL去寻找对应目录下的jsp,ftl模板或者vm模板。具体的URL地址在:http://struts.apache.org/2.x/docs/codebehind-plugin.html。详细内容一看就明白了,无须过多解释。
将上述2点结合起来在项目中使用,可以极大程度上简化配置,要是在加上annotation,至少可以减少90%以上的配置。不过要真正做到0配置,我想还是有些难度的。如果真要追求URL漂亮或者URL的Rest化,就不得不改写ActionMapper了。
downpour能把Codebehind讲明白点吗?
avi2 2007-10-16 回复
downpour 写道
楼主的CoC完全采用XML或者Json方式输出,可能多数人还接受不了,可能多数开发者还停留在JSP或者Freemarker的阶段。当然,对此个人有个人的喜欢,我觉得比较好的方式是任何一种方式仅仅提供一种Option,可以在各种Option中任意切换。
事实上,楼主的文章还欠缺了很大的一块,Struts2其实已经相当CoC了。Struts2所提供的CoC,主要包含2个主要的阶段:
1. 根据URL命名映射到相应的Action类进行执行。
这种方式楼主已经进行了介绍,其实就是利用namespace+url映射到package+Action类。
2. 根据URL命名,自动寻找Result
这一点楼主没有说。事实上Struts2提供了一个插件,叫做Codebehind Plugin。它可以自动根据URL去寻找对应目录下的jsp,ftl模板或者vm模板。具体的URL地址在:http://struts.apache.org/2.x/docs/codebehind-plugin.html。详细内容一看就明白了,无须过多解释。
将上述2点结合起来在项目中使用,可以极大程度上简化配置,要是在加上annotation,至少可以减少90%以上的配置。不过要真正做到0配置,我想还是有些难度的。如果真要追求URL漂亮或者URL的Rest化,就不得不改写ActionMapper了。
貌似你的路子比楼主正很多啊
colin4k 2007-10-11 回复
结合楼主的思路,再加上struts2自己的通配符,我是这样做的,struts.xml这样配置
Java代码 复制代码
1. <action name="*/*" method="{2}" class="workbench.web.actions.{1}Action">
2. <result name="custom">/view/{1}/${target}.jsp</result>
3. </action>
<action name="*/*" method="{2}" class="workbench.web.actions.{1}Action">
<result name="custom">/view/{1}/${target}.jsp</result>
</action>
然后写一个BaseAction:
Java代码 复制代码
1. public abstract class BaseAction {
2. protected final String CUSTOM = "custom";
3. private String target;
4. protected final Log logger = LogFactory.getLog(getClass());
5. public String getTarget() {
6. return target;
7. }
8. public void setTarget(String target) {
9. this.target = target;
10. }
11.
12. protected String render(String _target){
13. setTarget(_target);
14. return CUSTOM;
15. }
16. }
public abstract class BaseAction {
protected final String CUSTOM = "custom";
private String target;
protected final Log logger = LogFactory.getLog(getClass());
public String getTarget() {
return target;
}
public void setTarget(String target) {
this.target = target;
}
protected String render(String _target){
setTarget(_target);
return CUSTOM;
}
}
然后继承BaseAction
Java代码 复制代码
1. public class UserAction extends BaseAction{
2. private User user;
3. private UserService userService;
4. public void setUserService(UserService userService) {
5. this.userService = userService;
6. }
7.
8. public User getUser() {
9. return user;
10. }
11. public void setUser(User user) {
12. this.user = user;
13. }
14. public String test(){
15. user = userService.get(1l);
16. return render("test");
17. }
18. }
public class UserAction extends BaseAction{
private User user;
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String test(){
user = userService.get(1l);
return render("test");
}
}
这样在action里面,可以通过return render(target)来间接实现零配置转发到指定的jsp页面
URL:http://localhost:8080/workbench/User/test
downpour 2007-10-10 回复
楼主的CoC完全采用XML或者Json方式输出,可能多数人还接受不了,可能多数开发者还停留在JSP或者Freemarker的阶段。当然,对此个人有个人的喜欢,我觉得比较好的方式是任何一种方式仅仅提供一种Option,可以在各种Option中任意切换。
事实上,楼主的文章还欠缺了很大的一块,Struts2其实已经相当CoC了。Struts2所提供的CoC,主要包含2个主要的阶段:
1. 根据URL命名映射到相应的Action类进行执行。
这种方式楼主已经进行了介绍,其实就是利用namespace+url映射到package+Action类。
2. 根据URL命名,自动寻找Result
这一点楼主没有说。事实上Struts2提供了一个插件,叫做Codebehind Plugin。它可以自动根据URL去寻找对应目录下的jsp,ftl模板或者vm模板。具体的URL地址在:http://struts.apache.org/2.x/docs/codebehind-plugin.html。详细内容一看就明白了,无须过多解释。
将上述2点结合起来在项目中使用,可以极大程度上简化配置,要是在加上annotation,至少可以减少90%以上的配置。不过要真正做到0配置,我想还是有些难度的。如果真要追求URL漂亮或者URL的Rest化,就不得不改写ActionMapper了。
dunjh 2007-10-10 回复
无需修改,自动的,其他部分照着楼主的说明做,只是Action class里面不是一个execute方法,而是各个你自己的action method。你可以自己试一下,我试过没有问题,Struts2.0.9
不过个人最后还是决定在需要使用Spring管理action的情况下放弃用这种零配置了,因为如果照我上面的帖子里说的,把class的全名作为bean name的话,applicationContext.xml看起来实在是不伦不类,而且没办法在写test的时候做到autowire自动注入。看了一下Struts2的code, 在这个文件里:
org\apache\struts2\config\ClasspathConfigurationProvider.processActionClass(Class cls, String[] pkgs)
有这么一段:
Java代码 复制代码
1. ActionConfig actionConfig = new ActionConfig();
2. actionConfig.setClassName(cls.getName());
3. actionConfig.setPackageName(actionPackage);
ActionConfig actionConfig = new ActionConfig();
actionConfig.setClassName(cls.getName());
actionConfig.setPackageName(actionPackage);
如果这里setClassName里面改成设定cls.getSimpleName()的话(可能首字母要转成小写),应该就可以更好的适应Spring的情形了,但仔细想想也很难实现,因为这样要求必须在Spring里配置action (否则用Simplename,如果Spring plugin不能load action,则Struts2也无法load到action),实在违背了零配置的初衷。而且没有其他配置的情况下,也很难决定究竟什么时候用 simpleName,什么时候用全名。因此,这确实是个两难的问题,也难怪Struts2采用这样的实现了。
话说回来,反正如果要写Spring的配置文件的话,也不在乎在Struts的配置文件里多写一行了,唉……
kusoft 2007-10-10 回复
to dunjh兄:能不能指点一下,如何修改源代码.才能实现
1)*/*/People!list.action
(2)*/*/People!save.action
(3)*/*/People!edit.action
williamy 2007-10-10 回复
我改写的struts是1.2.4的,这些小菜功能,早就加了,请问它有什么用?搞来搞去,我突然发现,还是一个MVC而已
dunjh 2007-10-10 回复
从webwork时代开始,楼上的需求就是可以做到的。
分别调用的URL是:
(1)*/*/People!list.action
(2)*/*/People!save.action
(3)*/*/People!edit.action
虽然用叹号不太好看,但的确是可以用的。如果要用楼上的方式的话,恐怕要自己去hack Struts2的Code了。
不过还是有一个问题,对于原文中的这一段:
“另外我见到不少人使用Spring来配置和管理Action,其实完全没有必要!设置struts.objectFactory 等于spring就可以了,如果在Action中有setService1,这个service1在Spring中有配置的话,它会自动注入的。 Javaeye论坛中早有相关的讨论。”
似乎如果用Struts2来读入Action而不是用Spring读入的话,property的确是可以自动注入进去,不过假如Action实现了Spring的InitializingBean方法的话,其afterPropertiesSet()是不会被自动调用的。也许是我的配置有问题,可如果不是在web.xml里配置自动读入action的话就完全没有问题。在Struts2的mailing list和Jira里都没搜到这方面的问题,更新到Struts2.0.9也没能解决。正在努力看code想办法中……
这个问题已经解决。的确是我的配置有问题。因为如果让Struts2自动扫描Action的Class文件的话,它自然会把class的全名作为 Action的ClassName,而在load action的时候,Spring的plugin会用全名来搜索bean配置,而我在applicationContext.xml的配置还是旧的,bean name用的并不是全名,自然会找不到bean。于是,Spring plugin就只好用Struts2的方式来load action,action不是由Spring管理的,自然没办法用spring方式来初始化。
如果需要使用Spring对action进行控制,比如像这样的InitializingBean,或者用Acegi来控制action的方法访问的话,还是必须要在spring的applicationContext里面进行配置的。如果不配置的话,action并不是有Spring管理的,虽然action里的property还是可以被注入,不过这个应该是通过intercepter实现的吧,还没有仔细研究过。
个人认为这样的零配置如果是用Json的话还是很有用的,对大规模系统来说,配置应该还是越少越好的吧。非常感谢楼主的文章,教会了我不少东西。
kusoft 2007-10-09 回复
使用annotation,能不能一个Action里的多个方法.配置成对应多个URL.
例如:
Java代码 复制代码
1. public class PeopleAction{
2.
3. public String list(){
4. return "success";
5. }
6. public String save(){
7. return "success";
8. }
9. public String edit(){
10. return "success";
11. }
12. }
public class PeopleAction{
public String list(){
return "success";
}
public String save(){
return "success";
}
public String edit(){
return "success";
}
}
分别调用的URL是;
(1)*/*/listPeople.action
(2)*/*/savePeople.action
(3)*/*/editPeople.action
这样的话,写起的action不会太多.
andlu 2007-08-16 回复
pn2006 写道
多个Action返回sussess但返回页面可能并不一样,这样配置根本解决不了问题!
楼上就没读懂这篇文章,也许我那太简单的示例让大家误会了,我道歉。
如果你坚持要action返回页面,那必然会因为页面的位置不同而需要配置。文中已经提了,你可以使用注解,更好的方法是定个规则,写个Global Result(除非你项目中页面和Action之间的对应毫无规则)。即使你不想自己写Result,Struts2也是可以配置页面的缺省位置及后缀等信息的,只是我文中没有讲。不管怎么做,都不需要以前那么多配置。没能力自己写Result又需要让Struts2返回页面,而且坚持不用注解的,那么没必要读这篇文章。
Struts2只是提供了一些配置方面的机制,怎么用还是看我们自己,你可以用得很简单很灵活,也可以用得很复杂很繁琐,Struts2本身并没象新框架一样使用COC大幅减少配置,但不代表它没这能力。如果坚持用以前webwork2的传统办法来想问题,这篇文章根本就没意义。
为什么传统思想会根深蒂固?为什么传统教科书上说了什么就奉为金科玉律?自己写个Result很难么?放弃XML配置很难么?放弃Struts2的UI,换成XML/JSON很难么?这些工作真的没有想象中那么难。即使再实现个精简后的Struts2,也没有想象中那么难。
当然,对于已经进行开发的Struts2项目,再改架构是有难度。我仅仅是介绍了Struts2的一些机制,并给出一些改进思路,是否理解我真正的意图,以及怎么用它,还看大家自己。
另外,我并不是推崇Struts2,事实上我并不喜欢它!我希望大家能明白我真正的意图:只要有思想,不管什么框架你总能发现可以改进的地方,否则只能人云亦云,就等着这些框架自己进行改进吧。
pn2006 2007-08-16 回复
多个Action返回sussess但返回页面可能并不一样,这样配置根本解决不了问题!
andlu 2007-08-16 回复
jianfeng008cn 写道
ui我可以不用tag啊 没道理连direct这些功能都去掉吧 局限性太大了 你这个返回json和xml的东西不用说大家也知道怎么做到0配置,真正需要的地方却没讲,关注ing
我并没去掉direct等功能。COC的真正意义在于让规则做大部分事,特殊需要的再用配置。你想redirect,你想chain,都可以。至于说大家都知道怎么做到json和xml的0配置,事实上并非如此,如果有比我的demo-struts-coc示例代码更简洁的办法,可以贴出来看看,让大家共同提高。
另外,这篇文章仅仅是在讲述struts2的零配置和一些改进,你觉得有哪些真正需要的地方没讲呢?
jianfeng008cn 2007-08-16 回复
ui我可以不用tag啊 没道理连direct这些功能都去掉吧 局限性太大了 你这个返回json和xml的东西不用说大家也知道怎么做到0配置,真正需要的地方却没讲,关注ing
相关推荐
默认的struts2-config-browser-plugin包中的ftl文件include标签路径用的相对路径,会找到包内的include文件,将包内ftl里include的路径改成的/开头的全路径。
struts2-config-browser-plugin-2.1.8.1.jar
而"struts2-config-browser-plugin-2.3.20.zip"是一个Struts2框架的插件包,主要用于增强Struts2应用的配置管理能力。这个插件的主要功能是提供一个可视化的配置浏览器,帮助开发者更方便地浏览和管理Struts2应用的...
struts2-config-browser-plugin-2.2.3.jar
struts-config.xml struts标准配置文件 struts-config
### Struts框架中struts-config.xml文件配置详解 #### 一、引言 在Java Web开发领域,Struts是一个非常重要的MVC(Model-View-Controller)框架,它极大地简化了Web应用程序的开发过程。而在Struts框架中,`struts...
### Struts struts-config.xml配置详解 #### 一、引言 在Java Web开发领域,Struts框架一直是构建MVC架构应用的重要工具之一。而`struts-config.xml`配置文件则是Struts应用的核心配置文件,它负责管理Struts应用中...
Struts1.3是Apache软件基金会的一个开源框架,主要用于构建基于Java EE的Web应用程序。...同时,持续学习和实践Struts1.x的相关知识,对于理解和掌握其他MVC框架,如Spring MVC或Struts2,也会有极大的帮助。
Struts-config详解 Struts-config.xml 是Struts框架的核心配置文件,它描述了所有的Struts组件。在这个文件中,我们可以配置主要的组件及次要的组件。下面是struts-config.xml文件的主要元素: 一、struts-config....
在 Struts 应用程序中,`struts-config.xml` 文件是核心配置文件,它定义了应用的行为、控制器(Actions)、数据源(Form Beans)以及视图(JSP 页面)之间的关系。本文将深入探讨 `struts-config.xml` 的主要元素和...
`struts-config.xml`是Struts框架的核心配置文件,它定义了应用的各个组件及其交互方式。下面将详细介绍这个配置文件的主要元素和子元素。 ### 主要元素 1. **`<data-sources>`**: 这个元素用于配置数据源,通常...
struts2-config-browser-plugin-2.3.24.jar, struts2-core-2.3.24.jar, struts2-jasperreports-plugin-2.3.24.jar, struts2-jfreechart-plugin-2.3.24.jar, struts2-pell-multipart-plugin-2.3.24.jar, struts2-...
struts2-config-browser-plugin-2.1.6.jar
2.5.10.1.jar,struts2-config-browser-plugin-2.5.10.1.jar,struts2-convention-plugin-2.5.10.1.jar,struts2-dwr-plugin-2.5.10.1.jar,struts2-embeddedjsp-plugin-2.5.10.1.jar,struts2-gxp-plugin-2.5.10.1....
struts2-core-2.0.1.jar, struts2-core-2.0.11.1.jar, struts2-core-2.0.11.2.jar, struts2-core-2.0.11.jar, struts2-core-2.0.12.jar, struts2-core-2.0.14.jar, struts2-core-2.0.5.jar, struts2-core-2.0.6.jar,...
本文将详细介绍Struts2中的两个插件——Zero Config(零配置)与CodeBehind,以及它们如何共同工作以减少配置文件的复杂度。 #### 二、Zero Config插件介绍 Zero Config插件的主要目的是减少甚至消除`struts.xml`...
struts-config配置文件详解
### Struts2核心知识点解析 #### 一、Struts2框架概述 - **定义与特点**:Struts2是一款基于MVC(Model-View-Controller)设计模式的Java Web应用程序框架,它继承了Struts1的优点,同时在设计上更加灵活、易用,...