Struts2是基于MVC的轻量级的web应用框架。所谓框架:就是能完成一定功能的半成品软件。在没有框架的时候,所有的工作都要乖乖的从零做起;有了框架,它为我们提供了一定的功能,就可以在框架的基础上做起,大大提高开发的效率和质量。
将数据存入值栈中,在jsp页面上使用EL表达式也能获取值栈中的数据,是什么原因呢?当然要从源码看起。
struts2框架的启动是从核心过滤器开始的。struts2的核心过滤器叫做StrutsPrepareAndExecuteFilter,并且肯定已经配置在web.xml文件中,打开web.xml文件,按住Ctrl键点击查看源码。如果没有关联源码,找到源码路径,关联一下。
在核心过滤器中有个doFilter方法
在此有个小经验:在过滤器中一般最重要的就是doFilter方法。在核心过滤器的doFilter方法中,调用request的包装方法wrapRequest,返回request对象。按住Ctrl键,点击该方法。
在该方法中调用Dispather类对request对象的包装方法,返回request对象。按住Ctrl键,点击此方法
在Dispatcher类中的request对象的包装类中首先判断request对象是否已经被该类包装,如果已经被包装,不需要再次包装,直接返回即可,如果没有被包装,执行下面的if-else语句,在if的判断中,判断其是否是文件上传,如果是创建文件上传的包装类对象,在此我们不讨论这种情况。如果不是文件上传,创建request对象的包装类StrutsReuqestWrapper对象,在参数中传入需要包装的request对象。按住Ctrl键,查看该包装类。
因为上面的每个方法都返回request对象,那么如果执行到这里,核心过滤器中的request对象就是StrutsReuqestWrapper类的实例对象。
StrutsReuqestWrapper该类中有个getAttribute方法,就是这个方法判断从Servlet容器中取值还是从值栈中取值
由于getAttribute方法太长,截图不方便,这只是getAttribute方法的一部分,这部分判断如果成立就从Servlet容器中取值。首先是健壮性的判断,传入的参数key不能为空。disableRequestAttributeValueStackLookup是个boolean值,意思是不能从值栈中查询属性值,或者传入的key是以javax.servlet开头的。javax.servlet开头表示使用Servlet容器对request对象的包装类 javax.servlet.ServletRequestWrapper。
这部分判断的是从值栈中取值。先获取ActionContext对象,再调用父类的getAttribute方法,其父类就是Servlet容器对request的包装类javax.servlet.ServletRequestWrapper 。如果可以获得ActionContext对象,并且父类的getAttribute方法取值为空,那么if判断成立,紧接着进行第二个if判断,传入的参数key中不包含"#"。如果包含"#"是从值栈的map结构中取值,可能造成死循环。第二个if如果也成立,调用getValueStack方法,获取值栈对象,再调用值栈对象的findValue方法从值栈中获取对应的值。
到此使用EL表达式可以获取值栈中值的原因分析完了。总结就是获取request的包装类StrutsReuqestWrapper,获得该类的实例对象。类中有getAttribute方法,在该方法中判断是从Servlet容器中取值,还是从值栈中取值。先调用父类javax.servlet.ServletRequestWrapper的getAttribute方法,如果获取不到值,就获取值栈对象,调用值栈对象的findValue方法取值。