根据上篇博客的工作原理,来看看一个具体的简单的小例子的分析,使用struts增加学生,如下图:
很简单的一个例子,源码下载:http://download.csdn.net/detail/duancanmeng/4517024,代码一看就懂,重要的是上面的思路要理清楚。
ActionForm据官方文档介绍应该归类到控制器
----------------------------------------------------------------------------------------------------华丽的分割线----------------------------------------------------------------------------------------------------------------
关于Action要注意的问题:
1,Action什么时候初始化?
是在用户发出该Action请求时候,而不是在读取配置时初始化。
2,初始化几次?
总共初始化一次,在用户第一次请求时候,不论struts-config.xml中有多少action的type都指向该action类,都只会初始化一次。
3,如果有两个Action的配置中的type都指向同一个action,action只初始化一次,也就是说多个action请求进入了同一个action类,这样容易造成线程安全问题,如何解决?
* 如果这个信息只是用于某一个请求的,这个时候我们就不能用实例变量或者类变量;相反,如果我所有的请求刚好又需要共享某个信息,就可以用实例变量或静态变量来保存
* 存取其他资源(javabean,session等)必须同步,如果这些资源需要保护的话。
* struts与struts2的区别,action安全和不安全是很大的一点
* 来看一个简单例子:统计一个action访问次数,安全性问题的产生和解决图示:
----------------------------------------------------------------------------------------------------华丽的分割线----------------------------------------------------------------------------------------------------------------
ActionMapping——>对struts-config中<action-mapping>的封装
----------------------------------------------------------------------------------------------------华丽的分割线----------------------------------------------------------------------------------------------------------------
ActionForward(导航器)
redirect:
False——>容器内跳转.RequestDispatcher:forward
True——>容器外跳转.HttpResponse:sendRedirect .跳转时需要带上绝对路径,例如 path=http://www.baidu.com
----------------------------------------------------------------------------------------------------华丽的分割线----------------------------------------------------------------------------------------------------------------
ActionForm的工作原理:处理ActionForm的一般步骤
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,说明是同一个东西,不紧紧是内容相同,而且地址相同。