SpringSide 3 中的 Struts 2其中struts.codebehind.pathPrefix设置为“/WEB-INF/jsp/”,package的namespace
SpringSide 3 中的 Struts 2
其中struts.codebehind.pathPrefix设置为“/WEB-INF/jsp/”,package的namespace没有设置,所以,如果我们的Action为UserAction,则返回success时,就会返回到/WEB-INF/jsp/user.jsp,如果返回input,则返回到/WEB-INF/jsp/user-input.jsp。这里江南白衣玩了一个狡猾,他把所有的jsp页面放到WEB-INF目录中,别人就没有办法直接访问了,这样就可以简化Acegi的配置工作。
2、关于拦截器栈
在上面讲Struts 2的特点时,我已经说了Struts 2中拦截器的重要作用,在上面的截图中,package的配置没有做别的什么事,主要就是配置了拦截器栈。那么拦截器栈是怎么使用的呢?它是在Action类中通过@ParentPackage指定的,如下面的代码:
下面,我来具体说一下拦截器有什么作用。
?例子一、我们知道Struts 2中的Action是和Servlet API解耦的,那么如果我们要在Action中访问Servlet API怎么办呢?一种办法就是使用ServletActionContext,如下图:
另外一种办法,就是让我们的Action实现ServletRequestAware接口,如下代码:
public?class?MyAction?implements?ServletRequestAware?{
???private?HttpServletRequest?request;
???public?void?setServletRequest(HttpServletRequest?request)?{
????????this.request?=?request;
???}
???public?String?execute()?throws?Exception?{
????????//?do?the?work?using?the?request
????????return?Action.SUCCESS;
???}
}这时候,
ServletConfigInterceptor 拦截器就会把request对象注入到我们的Action中。
例子二、
ParametersInterceptor 拦截器会自动解析web表单或URL参数,并把它们注入到Action中。但是很多时候,我们不愿意我们的Action具有太多的属性,因为一大堆的get、set方法看起来太乱糟糟,我们希望有一个专门的Model对象来存储这些值,而且刚好我们为Hibernate设计的Entity类用来做Model正合适。这时,我们可以让我们的Action实现
ModelDriven接口,让getModel()方法返回我们的entity对象即可。这正是SpringSide 3采取的方法,如下图的代码片断:
这时候,
ModelDrivenInterceptor拦截器就会帮助我们把解析的URL参数或表单数据注入到entity的属性中,而不是Action中。
例子三、
Preparable 接口联合
PrepareInterceptor拦截器一起工作,可以让action在执行execute() 方法前, 执行一个prepare()方法,这也正是SpringSide 3的工作方式。
3、关于Action
有了上面对CodeBehind的理解和对拦截器栈的理解后,再来理解SpringSide 3中的Action就再简单不过了,SpringSide 3中Action的继承树如下:
其中ActionSupport类是Struts 2提供的,另外两个类是白衣自己扩展的。其中SimpleActionSupport主要是提供了一些绕过jsp页面直接输出字符串的方法,不值一谈。而CRUDActionSupport就比较复杂,如下:public?abstract?class?CRUDActionSupport<T>?extends?SimpleActionSupport?implements?ModelDriven<T>,?Preparable?{
????/**
?????*?进行CUD操作后,以redirect方式重新打开action默认页的result名.
?????*/
????public?static?final?String?RELOAD?=?"reload";
????/**
?????*?Action函数,默认action函数,默认指向list函数.
?????*/
????@Override
????public?String?execute()?throws?Exception?{
????????return?list();
????}
????/**
?????*?Action函数,显示Entity列表.
?????*?return?SUCCESS.
?????*/
????public?abstract?String?list()?throws?Exception;
????/**
?????*?Action函数,新增或修改Entity.?
?????*?return?RELOAD.
?????*/
????public?abstract?String?save()?throws?Exception;
????/**
?????*?Action函数,删除Entity.
?????*?return?RELOAD.
?????*/
????public?abstract?String?delete()?throws?Exception;
????/**
?????*?在save()前执行二次绑定.
?????*/
????public?void?prepareSave()?throws?Exception?{
????????prepareModel();
????}
????/**
?????*?在input()前执行二次绑定.
?????*/
????public?void?prepareInput()?throws?Exception?{
????????prepareModel();
????}
????/**
?????*?屏蔽公共的二次绑定.
?????*/
????public?void?prepare()?throws?Exception?{
????}
????/**
?????*?等同于prepare()的内部函数.?
?????*/
????protected?abstract?void?prepareModel()?throws?Exception;
}
第一,它做了把CRUD操作放到了同一个Action中的操作,这样可以少写几个Action。这个工作难度不大,我觉得白衣此举,主要是为了规范CRUD函数的命名。在Struts 2中,如果我们要访问的不是默认的excute方法,可以使用如/user!save.action的格式,这样访问的就是UserAction的save方法。
第二,它实现了ModelDriven接口和Preparable接口,关于这两个接口,我在前面讲拦截器的时候已经提到过了,所以很容易理解。我们可以把我们为Hibernate设计的entity类作为Model,也可以把初始化这些entity的工作放到prepareSave()和prepareInput()方法中,这两个方法将会在save()和input()方法执行前自动执行。
第三,它定义了一个静态变量RELOAD,定义这个变量的目的是为了定义一个result的需要。CodeBehind中,大部分的result可以自己猜测,对于不能猜测的,需要使用@Results指定,如下代码:
?
?好了,对SpringSide 3中Struts 2的分析就写到这里了。总之,使用SpringSide 3时,对于Action这一块非常简单,如果不设及到CRUD操作,就继承SimpleActionSupport,如果涉及到CRUD操作,就继承CRUDActionSupport,并在getModel()\save()\prepareSave\input()\prepareInput()等框框中填入适当的代码即可。