根据上篇博客的工作原理,来看看一个具体的简单的小例子的分析,使用struts增加学生,如下图:
很简单的一个例子,源码下载:http://download.csdn.net/detail/duancanmeng/4517024,代码一看就懂,重要的是上面的思路要理清楚。
----------------------------------------------------------------------------------------------------华丽的分割线----------------------------------------------------------------------------------------------------------------
1,Action什么时候初始化?
是在用户发出该Action请求时候,而不是在读取配置时初始化。
2,初始化几次?
总共初始化一次,在用户第一次请求时候,不论struts-config.xml中有多少action的type都指向该action类,都只会初始化一次。
3,如果有两个Action的配置中的type都指向同一个action,action只初始化一次,也就是说多个action请求进入了同一个action类,这样容易造成线程安全问题,如何解决?
* 如果这个信息只是用于某一个请求的,这个时候我们就不能用实例变量或者类变量;相反,如果我所有的请求刚好又需要共享某个信息,就可以用实例变量或静态变量来保存
* 存取其他资源(javabean,session等)必须同步,如果这些资源需要保护的话。
* struts与struts2的区别,action安全和不安全是很大的一点
* 来看一个简单例子:统计一个action访问次数,安全性问题的产生和解决图示:
----------------------------------------------------------------------------------------------------华丽的分割线----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------华丽的分割线----------------------------------------------------------------------------------------------------------------
redirect:
False——>容器内跳转.RequestDispatcher:forward
True——>容器外跳转.HttpResponse:sendRedirect .跳转时需要带上绝对路径,例如 path=http://www.baidu.com
----------------------------------------------------------------------------------------------------华丽的分割线----------------------------------------------------------------------------------------------------------------
1、检查Action映射,确定Action中已经配置了对ActionForm的映射
2,、根据name属性,查找formbean的配置信息
3、检查Action的formbean的使用范围,确定在此范围下(request,session),是否已经由此formbean的实例
4、假如当前范围下,已经存在了此formbean的实例,而且对当前请求来说,是同一种类型的话,那么就重用
5、否则,就重新构建一个formbean的实例(调用构造方法),并且保存在一定作用范围
6、formbean的reset方法被调用
7、调用对应的setter方法,对状态属性赋值
8、如果validate的属性设置为true,那么就调用formbean的validate方法
9、如果validate方法没有返回任何错误,控制器将ActionForm作为参数,传给Action实例的execute方法并执行
注意:直接从ActionForm类继承的reset和validate方法并不能实现什么处理功能,所以有必要自己覆盖。
由图也可以看出,验证在赋值之后,execute方法之前执行。
分析上面的流程图中,如何来证明form存了进去?在scope.setAttribute(name,form)处
1、从过程看:实现监听,进行监视
HttpSessionAttributeListener
ServletRequestAttributeListener
上面两个接口分别可以捕捉到scope为request和session不同情况的属性动态
public class AttributeListener implements HttpSessionAttributeListener, ServletRequestAttributeListener { @Override public void attributeAdded(ServletRequestAttributeEvent arg0) { System.out.println("add request attribute"); if(arg0.getValue() instanceof ActionForm){ System.out.println("this is request add mothed"); System.out.println(arg0.getName()+","+arg0.getValue()); } } @Override public void attributeRemoved(ServletRequestAttributeEvent arg0) { System.out.println("Removed request attribute"); if(arg0.getValue() instanceof ActionForm){ System.out.println("this is request Removed mothed"); System.out.println(arg0.getName()+","+arg0.getValue()); } } @Override public void attributeReplaced(ServletRequestAttributeEvent arg0) { System.out.println("Replaced request attribute"); if (arg0.getValue() instanceof ActionForm) { System.out.println("this is request Replaced mothed"); System.out.println(arg0.getName() + "," + arg0.getValue()); } } @Override public void attributeAdded(HttpSessionBindingEvent arg0) { System.out.println("Add session attribute"); if (arg0.getValue() instanceof ActionForm) { System.out.println("this is session Add mothed"); System.out.println(arg0.getName() + "," + arg0.getValue()); } } @Override public void attributeRemoved(HttpSessionBindingEvent arg0) { System.out.println("Removed session attribute"); if (arg0.getValue() instanceof ActionForm) { System.out.println("this is session Removed mothed"); System.out.println(arg0.getName() + "," + arg0.getValue()); } } @Override public void attributeReplaced(HttpSessionBindingEvent arg0) { System.out.println("Replaced session attribute"); if (arg0.getValue() instanceof ActionForm) { System.out.println("this is session Replaced mothed"); System.out.println(arg0.getName() + "," + arg0.getValue()); } } }
我们这里只关心ActionForm
可以看到action的配置文件中:
<action path="/add" type="com.pccw.action.AddStudentAction" name="studentForm"> <forward name="addsuccess" path="/addsuccess.jsp"></forward> <forward name="addfail" path="/addfail.jsp"></forward> </action>
这里的scope没有设置,缺省值为:session,所以我们可以看到当请求过来的时候打印的信息:
这是在session的add方法中监控到的。
2、从结果去看
在execute中直接从request来得到actionForm,然后通过与execute中的参数form进行比较,会发现,这两个东西是同一个东西。
public class AddStudentAction extends Action{ @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { StudentForm studentForm = (StudentForm)form; StudentDao dao = new StudentDaoImpl(); boolean isSave = dao.addStudent(studentForm); String returnKeyValue = "addfail"; if(isSave) returnKeyValue = "addsuccess"; StudentForm studentForm2 = null; String scope = mapping.getScope(); if(scope.equals("request")){ studentForm2 = (StudentForm) request.getAttribute("studentForm"); }else{ studentForm2 = (StudentForm) request.getSession().getAttribute("studentForm"); } System.out.println(studentForm == studentForm2); //一个是参数,一个是从request中获取的 return mapping.findForward(returnKeyValue); } }
打印结果我们可以看到:
打印结果为true,说明是同一个东西,不紧紧是内容相同,而且地址相同。