Struts学习总结 学习

ContextMap 包含值栈包含 root(list结构)和context(map结构)  值栈包含contextMap的引用.  Actioncontext是工具类 可以获取他们

 

Struts2拥有优良的设计和功能,其优势具体如下:  优点

l 项目开源,使用及拓展方便,天生优势。

提供Exception处理机制。

l Result方式的页面导航,通过Result标签很方便的实现重定向和页面跳转。  全局结果视图

l 通过简单、集中的配置来调度业务类,使得配置和修改都非常容易。

l 提供简单、统一的表达式语言来访问所有可供访问的数据。

l 提供标准、强大的验证框架和国际化框架。

l 提供强大的、可以有效减少页面代码的标签。

提供良好的Ajax支持。

l 拥有简单的插件,只需放入相应的JAR包,任何人都可以扩展Struts2框架,比如自定义拦截器、自定义结果类型、自定义标签等,为Struts2定制需要的功能,不需要什么特殊配置,并且可以发布给其他人使用。

l 拥有智能的默认设置,不需要另外进行繁琐的设置。使用默认设置就可以完成大多数项目程序开发所需要的功能。

上面列举的就是Struts2的一系列技术优势,只需对它们简单了解即可,在学习了后面的知识后,会慢慢对这些技术优势有更

好的理解和体会。

 

 

 

请简述下Struts2 的执行流程.

 

首先是,启动tomcat服务器,这时候会加载web.xml,当读到filter标签时,会创建过滤器对象。struts2的核心过滤器(StrutsPrepareAndExecuteFilter)会负责加载类路径下的struts.xml配置文件。接下来,从客户端发送请求过来 先经过前端控制器(核心过滤器StrutsPrepareAndExecuteFilter),前端控制器会根据请求的名称在struts.xml中找到对应的配置,创建我们的动作类对象(每次访问时都会创建新的Action对象),然后执行指定的方法,根据方法的返回值找到Result的配置进行页面的跳转.最后响应浏览器。

 

 

 

 加载struts2的配置文件,他们的加载顺序及作用.

 

 

 

default.properties

 

 

 

struts-default.xml

 

 

 

strtuts-plugin.xml

 

 

 

struts.xml

 

 

 

struts.properties

 

 

 

web.xml

 

 

 

当多个配置文件中,有相同的参数,后加载的配置文件中的值会把前面加载的配置文件的值给覆盖了。

 

 

 

 

 

 实现一下动作类的三种创建方式.

 

第一种:无侵入式创建一个action实现一个跳转(实际开发中基本不用)

 

第二种:实现Action接口的定义方式 (实际开发中用的也不多)

 

第三种:继承ActionSupport (们实际开发中采用的方式)

 

 

 

 

 

1. Struts2与Struts1的联系与区别是什么?为什么要用Struts2?

 

答案:

 

struts1与struts2都是mvc框架的经典实现模式。

 

Struts2不是从Struts1升级而来,而是有WebWork改名而来,Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求

 

区别:(了解几条即可)

 

1.核心控制器改成了过滤器(过滤器比Servlet的级别要高,因为程序运行时是先进入过滤器再进入Servlet)

 

2.struts1要求业务类必须继承Action或dispatchAction,struts2不强制这么做,只需要提供一个pojo

 

3.绑定值到业务类时struts1是通过ActionForm,struts2是通过模型或属性驱动直接绑定到Action属性。

 

4.struts1严重依赖于Servlet(因为太过于依赖于api的HttpServletRequest与HttpServletResponse的两个参数),

 

struts2就则脱离了Servlet的API。

 

5.管理Action时struts1是单例模式,struts2是每个请求产生一个实例

 

6.在表达式的支持上struts2不仅有jstl,还有功能更加强大的ognl表达式

 

7.struts1的类型转换是单向的(页面到ActionForm),struts2是双向的(页面到Action再到页面回显)

 

8.校验,struts1没有针对具体方法的校验,struts2提供了指定某个方法进行效验,还有框架校验。

 

 

 

 

 

 

 

 请求(.action)---->经过StrutsPrepareAndExecuteFilter 核心控制器---->进入到Struts2的拦截器Interceptor(实现代码功能)----->通过action的名称找对应的Action类----->执行Action类的execute方法----->通过execute方法中返回的字符串,在Struts.xml中找对应的结果页面(result)【在action执行之前,执行了defaultStack拦截器栈】

 

 

 

* 拦截器 在 struts-default.xml定义 【它位于sruts2-core-xxx.jar目录下】

 

 

 

* 执行拦截器 是 defaultStack 中引用拦截器

 

 

 

 获取域对象的两种方式 例如获取request

 

 

1.1 使用ServletActionContext

为了直接访问Servlet APIStruts2框架提供了ServletActionContext类,在实际开发中,这也是我们采用最多的方式。该类包含了几个常用的静态方法,具体如下:

l static HttpServletRequest getRequest():获取Web应用的HttpServletRequest对象。

l static HttpServletResponse getResponse():获取Web应用的HttpServletResponse对象。

l static ServletContext getServletContext():获取Web应用的ServletContext对象。

l static PageContext getPageContext():获取Web应用的PageContext对象。

接下来,讲解如何通过ServletActionContext访问Servlet API。使用方式如下:

/**

 * struts2框架中有三种方式可以获取到ServletAPI对象

 * ServletAPI对象包含了:

 * request,response,HttpSession,ServletContext

 * 第一种方式:

 * 使用的是ServletActionContext对象,它里面提供了一些静态方法,可以让我们获取到ServletAPI

 * 此种方式,使我们实际开发中采用最多的方式

 * 此时我们还要记住一件事:

 * 这四个对象,有一个已经变了,和其他三个不一样,找出来,记住。

 *

 * org.apache.struts2.dispatcher.StrutsRequestWrapper@1577071 它是那个不一样的

org.apache.catalina.connector.ResponseFacade@1973ca4

org.apache.catalina.session.StandardSessionFacade@e4d72

org.apache.catalina.core.ApplicationContextFacade@fe7e93

 *

 */

public class HelloAction extends ActionSupport{

 

private HttpServletRequest request;

private HttpServletResponse response;

private HttpSession session;

private ServletContext application;

/**

 * @return

 */

public String sayHello(){

request = ServletActionContext.getRequest();

response = ServletActionContext.getResponse();

session = request.getSession();

application = ServletActionContext.getServletContext();

 

System.out.println(request);

System.out.println(response);

System.out.println(session);

System.out.println(application);

return SUCCESS;

}

}

1.2 通过实现接口的方式

Struts2还提供了一系列接口,具体如下:

l ServletRequestAware:实现该接口的Action可以直接访问Web应用的HttpServletRequest实例。

l ServletResponseAware:实现该接口的Action可以直接访问Web应用的HttpServletResponse实例。

l SessionAware:实现该接口的Action可以直接访问Web应用的HttpSession实例。

l ServletContextAware:实现该接口的Action可以直接访问Web应用的ServletContext实例。

/**

 * struts2框架中有三种方式可以获取到ServletAPI对象

 * ServletAPI对象包含了:

 * request,response,HttpSession,ServletContext

 * 第三种方式:

 * 采用实现接口的方式,来获取对象

 * 能够使用对象的原因:

 * 是因为在我们的sayHello方法执行之前,已经有一些拦截器执行了。

 *  通过struts-default.xml我们能知道默认的拦截器栈defaultStack,

 *  在我们的动作配置时,默认就会有该拦截器栈中的所有拦截器执行。先正序,再倒序。

 *  

 *  帮我们给对象赋值全靠一个名称为servletConfig的拦截器

 *  

 *  拦截器的重要性:

 *   他可以在不改变我们动作方法的代码基础上,对我们的动作方法进行增强。

 */

public class Hello3Action extends ActionSupport

implements ServletRequestAware,ServletResponseAware,ServletContextAware{

 

private HttpServletRequest request;

private HttpServletResponse response;

private HttpSession session;

private ServletContext application;

/**

 * @return

 */

public String sayHello(){

 

session = request.getSession();

 

System.out.println(request);

System.out.println(response);

System.out.println(session);

System.out.println(application);

return SUCCESS;

}

 

@Override

public void setServletRequest(HttpServletRequest request) {

this.request = request;

}

@Override

public void setServletResponse(HttpServletResponse response) {

this.response = response;

}

@Override

public void setServletContext(ServletContext application) {

this.application = application;

}

 

 

}

 

1. 值栈ValueStack的原理与生命周期?  

 

 

 

答案:

 

 

 

1)ValueStack贯穿整个 Action 的生命周期,保存在request域中,所以ValueStack和request的生命周期一样。当Struts2接受一个请求时,会迅速创建ActionContext工具类,  

 

 

 

ValueStack,action。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。请求来的时候,action、ValueStack的生命开始,请求结束,action、ValueStack的生命结束;  

 

 

 

2)action是多例的,和Servlet不一样,Servelt是单例的;  

 

 

 

3)每个action的都有一个对应的值栈,值栈存放的数据类型是该action的实例,以及该action中的实例变量,Action对象默认保存在栈顶;  

 

 

 

4)ValueStack本质上就是一个ArrayList;  

 

 

 

5)关于ContextMap,Struts 会把下面这些映射压入 ContextMap 中:  只能用%{#取出}

 

 

 

parameters  :   该 Map 中包含当前请求的请求参数  

 

 

 

request     :   该 Map 中包含当前 request 对象中的所有属性  session :该 Map 中包含当前 session 对象中的所有属性  

 

 

 

application :该 Map 中包含当前 application 对象中的所有属性  

 

 

 

attr:该 Map 按如下顺序来检索某个属性: request, session, application           

 

 

 

6)使用OGNL访问值栈的内容时,不需要#号,而访问request、session、application、attr时,需要加#号;  

 

 

 

7)注意: Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:<s:property value="name"/>  

 

 

 

8)在struts2配置文件中引用ognl表达式 ,引用值栈的值 ,此时使用的"$",而不是#或者%;  

 

 OGNL表达式和EL表达式的区别

OGNL可以访问静态属性和静态方法  

随机数:<s:property value="@java.lang.Math@random()"/>

 

1.1.1 OGNL表达式创建集合

1.1.1.1 list集合

HTML在浏览器上输出一个单选性别:

<input type="radio" name="gender" value=""/>

<input type="radio" name="gender" value=""/>

<br/>

Struts2的单选按钮标签输出一个单选

<%--s:radio用于在浏览器上显示一个单选按钮

list属性取值是一个OGNL表达式

{}就表示创建了一个List集合 List list = new ArrayList();

{'',''}

list.add("");list.add("");

--%>

<s:radio name="gender" list="{'',''}" label="性别"/>

1.1.1.2 map集合

HTML在浏览器上输出一个单选性别:Map结构

<input type="radio" name="gender" value="male"/>

<input type="radio" name="gender" value="female"/>

<br/>

<%--#{}就表示创建了一个Map

里面的写法

#{'key':'value','key':'value'......}

 --%>

<s:radio name="gender" list="#{'male':'','female':''}" label="性别"/>

 

 

1.1 ActionContext

1.1.1 ActionContext对象概述

它是一个工具类,是struts2框架提供给我们的,可以让我们调用其中的方法,快速的操作ContextMap。用它操作OGNL上下文对象,比直接操作ContextMap要方便很多。

1.1.2 ActionContext对象以及和ContextMap的关系

ActionContext就相当于对ContextMap进行了一次再封装

1.1.3 ActionContext何时创建

由于ActionContext是操作的ContextMapContextMap中封了我们一次请求的所有数据,所以它的创建应该是每次请求访问Action时,即核心控制器(StrutsPrepareAndExecuteFilter)doFilter方法执行时,下图是代码截取:

 

 

 

 

 

1.1.1 ValueStack对象概述

 

ValueStackStruts的一个接口,字面意义为值栈,OgnlValueStack是ValueStack的实现类,客户端发起一个请求struts2架构会创建一个action实例同时创建一个OgnlValueStack值栈实例,OgnlValueStack贯穿整个 Action 的生命周期。

 

它是ContextMap中的一部分,里面的结构是一个List,是我们可以快速访问数据一个容器。它的封装是由struts2框架完成的。

 

通常情况下我们是从页面上获取数据。它实现了栈的特性(先进后出)。

 

1.1.2 ValueStack的内部结构

 

OnglValueStack 中包含了一个CompoundRoot的对象和context上下文对象,该对象继承了ArrayList,并且提供了只能操作集合第一个元素的方法,所以我们说它实现了栈的特性。同时,它里面定义了一个ContextMap的引用,也就是说,我们有值栈对象,也可以通过值栈来获取ContextMap

 

 

1.1.1.1 如何让Action中定义的成员出现在值栈中

 

Action定义一个私有属性,并且提供公有get/set方法,那么该属性就会出现在值栈的Property Name中。显示的名称是根据get/set方法后面的内容决定的,与私有成员变量名称叫什么无关。

 

 

EL表达式原来的搜素顺序:

 

page Scope——>request Scope——>sessionScope——>application Scope

 

EL表达式改变后的搜索顺序:

 

page Scope>request Scope>valueStack>contextMap>sessionScope>application Scope

 

 

在不修改源码的基础上,已有的方法进行动态增强。

 

struts2中,拦截器它就是对我们的动作方法进行增强。(其实就是把重复性的代码提取出来,然后放到拦截器中,统一管理,统一调用)

 

 

1.1 自定义拦截器

在程序开发过程中,如果需要开发自己的拦截器类,就需要直接或间接的实现com.opensymphony.xwork2.interceptor.Interceptor接口。其定义的代码如下:

public interface Interceptor extends Serializable {

void init();

void destroy();

    String intercept(ActionInvocation invocation) throws Exception;

}

该接口提供了三个方法,其具体介绍如下。

l void init():该方法在拦截器被创建后会立即被调用, 它在拦截器的生命周期内只被调用一次. 可以在该方法中对相关资源进行必要的初始化。

l void destroy():该方法与init方法相对应,在拦截器实例被销毁之前,将调用该方法来释放和拦截器相关的资源。它在拦截器的生命周期内,也只被调用一次。

l String intercept(ActionInvocation invocation) throws Exception该方法是拦截器的核心方法,用来添加真正执行拦截工作的代码,实现具体的拦截操作。它返回一个字符串作为逻辑视图,系统根据返回的字符串跳转到对应的视图资源。每拦截一个动作请求, 该方法就会被调用一次。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过该参数的invoke()方法,将控制权转给下一个拦截器或者转给Actionexecute()方法

如果需要自定义拦截器,只需要实现Interceptor接口的三个方法即可。然而在实际开发过程中,除了实现Interceptor接口可以自定义拦截器外,更常用的一种方式是继承抽象拦截器类AbstractIntercepter。该类实现了Interceptor接口,并且提供了init()方法和destroy()方法的空实现。使用时,可以直接继承该抽象类,而不用实现那些不必要的方法。拦截器类AbstractInterceptor中定义的方法如下所示:

public abstract class AbstractInterceptor implements Interceptor {

    public void init() {}

    public void destroy() {}

    public abstract String intercept(ActionInvocation invocation)

throws Exception;

}

从上述代码中可以看出,AbstractInterceptor类已经实现了Interceptor接口的所有方法,一般情况下,只需继承AbstractInterceptor类,实现interceptor()方法就可以创建自定义拦截器。

只有当自定义的拦截器需要打开系统资源时,才需要覆盖AbstractInterceptor类的init()方法和destroy()方法。与实现Interceptor接口相比,继承AbstractInterceptor类的方法更为简单。

当然还有更简单的,AbstractInterceptor还有一个子类,MethodFilterInterceptor,该类中提供了两个属性,可以告知拦截器对哪些方法进行拦截或者对哪些方法排除。

 

 

1.1.1 自定义步骤

 

通过在拦截器类视图上我们可以得知,我们定义拦截器可以有三种办法:

 

第一种:定义一个类,实现Interceptor接口

 

第二种:定义一个类,继承AbstractInterceptor

 

第三种:定义一个类,继承MethodFilterInterceptor

 

看完两个类之后,我们有了结论。即:选择第三种方式,比第二种多了一个功能,就是告知拦截器哪些方法我们需要拦截,哪些方法我们不需要拦截。(注意:不要想着很傻的问题,在需要拦截和不需要拦截的属性中提供同一个方法

 

1.1.1 配置拦截器

<!-- 一个公共包 -->

<package name="myDefault" extends="struts-default" abstract="true">

<!-- 声明拦截器 -->

<interceptors>

<interceptor name="checkLogin" 

class="com.itheima.web.interceptors.CheckLoginInterceptor"/>

<!-- 定义一个拦截器栈 -->

<interceptor-stack name="myDefaultStack">

<interceptor-ref name="checkLogin">

<!-- 由于我们使用了继承MethodFilterInterceptor

此时我们可以告知拦截器,排除掉登录方法 -->

<param name="excludeMethods">login</param>

</interceptor-ref>

<interceptor-ref name="defaultStack"></interceptor-ref>

</interceptor-stack>

</interceptors>

 

<!-- 修改默认拦截器栈,设置我们自定义的拦截器栈

这样的话我们写的所有动作都有了检查登录功能。并且排除了登录方法-->

<default-interceptor-ref name="myDefaultStack"/>

 

<!-- 全局结果视图 -->

<global-results>

<result name="login">/login.jsp</result>

</global-results>

</package>

 

 

 

 

 

 

 

1.1.1 @InterceptorRef

出现的位置:

它可以出现在动作类上或者Action注解中。

作用:

用于配置要引用的拦截器或者拦截器栈

属性:

value用于指定拦截器或者拦截器栈

示例:

出现在动作方法上:

/**

 * 查询所有客户

 * @return

 */

@Action(value="findAllCustomer",results={

@Result(name="findAllCustomer",location="/jsp/customer/list.jsp")

},interceptorRefs={

@InterceptorRef("myDefaultStack")

})

public String findAllCustomer(){

customers = customerService.findAllCustomer();

return "findAllCustomer";

}

 

出现在动作类上:

@InterceptorRef("myDefaultStack")

public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {

private Customer customer = new Customer();

 

@Override

public Customer getModel() {

return customer;

}

}

 

 

 

OgnlValueStack贯穿整个 Action 的生命周期。

它是ContextMap中的一部分,里面的结构是一个List,是我们可以快速访问数据一个容器。它的封装是由struts2框架完成的。

通常情况下我们是从页面上获取数据。

 

  1. 请阐述一下ValueStack的内部结构

在 OnglValueStack 中包含了一个CompoundRoot的对象,该对象继承了ArrayList,并且提供了只能操作集合第一个元素的方法,所以我们说它实现了栈的特性。同时,它里面定义了一个ContextMap的引用,也就是说,我们有值栈对象,也可以通过值栈来获取ContextMap。

 

 

 

1. 继承AbstractInterceptor继承MethodFilterInterceptor的区别

 

答:MethodFilterInterceptor多了一个功能,就是告知拦截器哪些方法我们需要拦截,哪些方法我们不需要拦截。推荐使用。

 

 

 

1. 【简答题】拦截器和过滤器的区别

答:

拦截器:

拦截器是struts2框架自己的,只有使用了struts2框架的工程才能用。

拦截器它是只有进入struts2核心内部之后,才会起作用,如果访问的是jsp, html,css,image或者js是不会进行拦截的。

过滤器:

过滤器是servlet规范中的一部分,任何java web工程都可以使用。

过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。

 

1、①拦截器是基于java的反射机制的,而过滤器是基于函数回调

 

2、②过滤器依赖与servlet容器,而拦截器不依赖与servlet容器

 

3、③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用

 

4、④拦截器可以访问action上下文、值栈里的对象,而过滤器不能

 

5、⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

 

拦  拦截器 :是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。

 

 

 

配置拦截器 并不拦截login方法

 

<package name="myDefault" extends="struts-default">
<!-- 声明拦截器 -->
<interceptors>
<interceptor name="checkLogin"
class="cn.itcast.action.CheckUserInterceptor"/>
<!-- 定义一个拦截器栈 -->
<interceptor-stack name="myDefaultStack">
<interceptor-ref name="checkLogin">
<!-- 由于我们使用了继承MethodFilterInterceptor, 此时我们可以告知拦截器,排除掉登录方法 -->
<param name="excludeMethods">login</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>

 

<!-- 修改默认拦截器栈,设置我们自定义的拦截器栈, 这样的话我们写的所有动作都有了检查登录功能。并且排除了登录方法 -->
<default-interceptor-ref name="myDefaultStack" />

 

 

 

 

1. 举例Struts2中通过拦截器实现了哪些功能?

答案:

参数绑定、参数校验、类型转换等

 

 

1. struts2有哪些优点?

答案:

1)在软件设计上Struts2的应用可以不依赖于Servlet API和struts API。 Struts2的这种设计属于无侵入式设计;  

2)拦截器,实现如参数拦截注入等功能;  

3)类型转换器,可以把特殊的请求参数转换成需要的类型;  

4)多种表现层技术,如:JSP、freeMarker、Velocity等;  

5)Struts2的输入校验可以对指定某个方法进行校验;  

6)提供了全局范围、包范围和Action范围的国际化资源文件管理实现

 支持全局结果视图

支持Ognl  

 

posted @ 2018-06-13 17:40  阿善9  阅读(276)  评论(0编辑  收藏  举报