Struts2中的零配置与CoC(Convention over Configration)
摘要:介绍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
这会建立如下的目录结构:<demo-struts-coc>
?|- 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:
</demo-struts-coc>目前,这个新特性还在测试阶段,但经过一段时间的使用,我觉得这个特性已经可用。下面我讲一下如何使用它。
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的配置示例:
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不会太多.
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的配置文件里多写一行了,唉……<action name="*/*" method="{2}" name="code">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
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");}}