• Struts2技术详解


    1, 当Action设置了某个属性后,Struts将这些属性封装一个叫做Struts.valueStack的属性里。获取valueStack对象: ValueStack vs = (ValueStack) request.getAttribute("struts.valueStack");
       调用ValueStack 的vs.findValue("books")方法(books为Action中的属性);

    2, struts2的Action类是一个普通的POJO类(通常包含一个无参的execute方法)从而很 好的重用代码。

    4,struts2通常直接使用Action来封装HTTP请求参数,所以Action中要定义与请求参数对应的属性,并且为该属性提供相应的 getter和setter方法。

    5,即使Action需要处理的请求name和pass两个HTTP请求参数,Action类也可以不包含name和pass属性,因为系统是通过对应的 getter和setter方法来处理请求参数。而不是通过属性来处理请求参数的。所以Action类是否包含name和pass属性不重要, 重要的是需要setter和getter方法。

    6,Action类的属性,不仅可以封装请求参数,还可以用于封装处理结果,通过Struts2标签来输出对应的属性值。如 <s:Property value="tip">。

    7,ActionContext类。Struts2的Action并未直接与任何Servlet api耦合,从而更加方便测试该Action(可以通过脱离web容器测试Action)。但是对于Web应用的控制器来说,不访问Servlet api 几乎是不能的。例如跟踪HTTP session状态等。访问的Servlet Api 就 是HttpServeltRequest、HttpSession、ServletContext,这三个类分别jsp内置对象中的request、session、application。Web应用中提供了一个ActionContext类,Struts2的Action可以通过该类来访问Servlet api。
    该类的ActionContext提供getContext方法得到ActionContext实例,
      该类的方法:
       ①Object get(Object key),该方法类似于HttpServletRequest的getAttribute(String name)方法;
       ②Map getApplication(),返回Map对象,该对象模拟了应用的ServletContext的实例
       ③static ActionContext getContext(),静态方法,获得系统提供的ActionContext实例。
       ④Map getParameters()获取所有的请求参数,类似于调用HttpServletRequest对象的getParammeterMap方法。
       ⑤Map getSession()该Map对象模拟了HttpSession实例。
       ⑥void setApplication(Map application)直接传入一个Map实例,将该Map实例的key-value对转换成application的属性名、属性值。类似的还有setSession(Map session)
       ⑦put(Object key, Object value)直接为HttpServletRequest设置属性。相当于request.setAttribute(key,value).可通过EL表达式输出。

    8,ServletActionContext类(是ActionContext类的子类)。 虽然Struts2提供了ActionContext来访问Servlet Api,但是这种访问毕竟不能直接获得Servlet Api实例,为了Action中 直接访问Servlet api,Struts2提供了如下的接口:ServletContextAware、ServletRequestAware、ServletResponseAware 。如果Action实现这些接口,能分别直接访问用户请求的ServletContext、HttpServletRequest、HttpServletResponse实例。
      并且,为了直接访问Servlet api。Struts2提供了一个ServletAction类。通过ServletActionContext类可以更加方便的地直接访问Servlet api。这类的主要方法(全是static):
       ①getActionContext(HttpServletRequest req)得到当前的ActionContext实例。
       ②getActionMapping()得到ActionMapping实例(得到 action mapping为context)。
       ③getRequest()得到HttpServletRequest实例(Gets the HTTP servlet request object)。
       ④getResponse()得到HttpServletResponse实例(Gets the HTTP servlet response object.)
       ⑤getServletContext()得到ServletAction实例(Gets the servlet context.)
       ⑥getValueStack(HttpServletRequest req)得到ValueStack实例。
       ⑦setRequest(HttpServletRequest request)(Sets the HTTP servlet request object)相应的有setResponse(HttpServletResponse response)、setServletContext(ServletContext servletContext)。

    9,虽然可以在Action类获取HttpServletResponse,但如果希望通过HttpServletResponse来生成服务器响应是不可能的,因为Action只是控制器(它并不直接对浏览器生成任何相应)。即如果在Action中写如下代码:response.getWriter().println("hello world");
    是没有意义的。

    10,对于使用Struts2框架的应用而言,尽量不要让超级链接链接到某个视图资源,
    因为这种方式增加了额外的风险,推荐将所有请求都发给Struts2框架,让该框架来处理用户的请求,
    即使是简单的超级链接。

    11,逻辑视图名是指:Action返回的字符串;物理视图是指:页面的实际名称。
    Struts2通过配置逻辑视图名和物理视图之间的映射关系,一旦系统收到Action返回的某个逻辑视图,系统就会把相应的物理视图呈现给用户。

    12,默认值:如果配置<result../>元素时没有指定location参数,系统将会把<result..>...<result../>中间的字符串当成实际视图资源。如果没有配置parse参数,则默认值为true(该参数指定实际视图名是否可以使用OGNL表达式);如果没有指定name属性则默认值为Struts2的默认处理结果类型(dispacher).

    13,归纳起来,Struts2内建支持结果类型如下(14):
       ①chain结果类型:Action链式处理结果类型。
       ②chart结果类型:用于整合JFreeChart的结果类型。
       ③dispatch结果类型:用于jsp整合的结果类型。
       ④freemarker结果类型:FreeaMarker整合的结果类型。
       ⑤httpheader结果类型:用于控制Http行为的结果类型。   
       ⑥jasper结果类型:用于JasperReports整合的结果类型。
       ⑦jsf结果类型:用于整合JSF整合的结果类型。
       ⑧redirect结果类型:用于直接跳转到其他的URI的结果类型。
       ⑨redirectAction结果类型:用于直接跳转到其他的Action的结果类型。
       ⑩stream结果类型:用于向浏览器返回一个InputStream(一般用于文件下载)。
       ⑾tiles结果类型:用于与Tiles整合的结果类型。
       ⑿velocity结果类型:用于与Velocity整合的结果类型。
       ⒀xslt结果类型:用于与XML/XSLT整合的结果类型。
       ⒁plainText结果类型:用于显示某个页面的原始代码的结果类型。

    14,【redirect】结果类型。
       这种结果类型与dispatch结果类型相对,dispatch结果类型是将请求Forward(转发)
    到指定的jsp资源。而redirect结果类型,则意味着将请求Redirect(重定向)
    到指定的视图资源。
       dispatch结果类型与redirect结果类型的差别就是转发和重定向的差别:
    重定向会丢失所有的请求参数和请求属性---当然也会丢失Action的处理结果。
       使用redirect结果类型的效果是:系统将调用HttpServletResponse的sendRedirect(String)方法来重定向指定的视图资源,这种重定向的效果就是重新产生一个请求。所以所有的请求参数、请求属性、Action实例和Action中封装的属性全部丢失。

    15,【redirectAction】结果类型.
       使用redirectAction结果类型时,系统将重新生成一个新的请求,
    只是该请求的URI不是一个具体的试图资源,而是一个Action。因此前一个Action处理结果
    ,请求参数,请求参数都会丢失。

    16,除了可以通过通配符来配置Action(result),还可以使用OGNL表达式,这种
    用法允许让请求参数来决定结果。如:
    <action name="save" class="......." method="save">
    <result name="input">/..jsp</result>
    <result type="redirect" >edit.action?skillName=${currentSkill.name}</result>
    </action>
    对于上面的表达式语法,要求对应的Action实例里应该包含currentSkill属性,且currentSkill属性必须包含name属性--否则,${currentSkill.name}表达式为null。

    17,模型驱动:
    对于Struts1的ActionForm对象而言。它的唯一作用就是封装请求参数,当Struts1拦截到用户的请求后,Struts1负责将请求参数封装成ActionForm对象。
    如果Struts2的开发者怀念这种开发方式,则可以使用Struts2提供的模型驱动模式,
    这种模式也通过专门的JavaBean来封装请求参数。
        相比于Struts1的Action类,Struts2的Action承担了太多的责任,既用于封装来回请求的参数,也保护了控制逻辑---这种模式实在不太清晰。出于清晰的考虑,应该采用单独的Model实例来封装请求参数和处理结果,这就是所谓的模型驱动。
       作用:Struts2的模型对象可以封装更多的信息,它不仅可以封装用户的请求参数,而且还可以封装Action的处理结果。用单独的JavaBean实例来贯穿MVC流程。
       使用模型驱动时,Action必须实现ModelDriven接口,且必须实现getModel方法,
    该方法用于把Action和与之相对应的Model实例关联起来。
        简单的说,模型驱动使用单独的VO(值对象)来封装请求参数和处理结果。

    18,【属性驱动】:
    使用属性(Property)作为贯穿MVC流程的信息携带者,当然属性无法独立存在,他必须依附于一个对象,这个对象就是Action实例,
        简单的说,属性驱动使用Action实例来封装请求参数和处理结果。

    19,Struts2的【处理异常机制】:
       在execute方法中手动捕捉异常,当捕捉到特定的异常时,返回特定的视图--但是
    这种方式很是繁琐,需要在execute中书写大量的catch块,最大的缺点
    还在于异常与代码耦合,一旦需要改变异常处理方式,必须修改代码!
       Struts2提供了一种声明式的异常处理方式。
    在输出错误信息的jsp页面,有两种输出方式:
       ①通过struts2标签输出异常对象的message属性。<s:property value="exception.message"/>。
       ②通过struts2标签输出堆栈信息。<s:property value="exceptionStack"/>。
    注意:全局异常映射的result属性通常不要使用局部结果,局部异常映射的result属性可以使用全局结果,也可以不使用。

    20,对于WEB应用而言,所有的请求参数都是字符串类型的。

    21,【类型转换器】:
    struts2的类型转换器实际上是基于OGNL实现的,在OGNL项目中有一个TypeConverter接口,因其实现的方法过于麻烦,所以OGNL项目还提供了一个该接口的实现类:DefaultTypeConverter,通过继承该类来实现自己的转换器。
      实现自定义的类型转换需要重写DefaultTypeConverter类的convertValue方法。

    22,上面的类型转换器都是基于OGNL的DefaultTypeConverter类实现的,基于
    该类实现类型转换器的时候时,将字符串转化成符合类型要通过convertValue方法实现
    因此我们必须先通过toType参数来判断转换的方向,然后分别实现不同的转换逻辑。
      为了简化类型转换的实现,struts2提供了一个StrutsTypeConverter抽象类(基于struts2的类转换器)
    这个抽象类是DefaultTypeConverter类的子类.

    23,对于以上的类型转换,我们一直只处理字符串数组的第一个元素---我们都假设请求参数是单个值。实际上,必须考虑请求参数是字符数组的情形, 假设用户信息的请求参数,名称都是user。那么这两个请求参数必须通过getParameterValues方法来获取参数。此时user请求参数必须是数组类型,或者List类型(实际上,List和数组是完全相通的)。

    24,因为struts2内建的OGNL表达式的支持,那么可以用另一种方式将请求参数转换成复合类型,如(JSP页面中):
    <input type=text name="user.name"/>,<input type=text name="user.pass"/>这样就不需要转换器了。
      通过这种方式也可以把字符串转换成复合类型。但需要注意以下几点:
        ①因为struts2是需要直接创建一个复合类(User类)的实例,因此系统必须为该复合类构建一个无参的构造方法。
        ②如果希望使用user.name请求参数的形式为Action实例的user属性和pass属性赋值,则必须为user属性对应的复合类型提供setName方法,因为struts2是通过该方法类为属性赋值的。当然Action类还应该包含setUser方法。

    25,表单元素enctype属性指定的是表单数据的编码方式。属性有如下3个值:
        ①application/x-www-form-urlencoded:这是默认的编码方式。它只处理表单中的value属性值,采用这种编码方式会将表单域的值处理成URL编码方式。
        ②multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定的文件内容也封装到请求参数里。
        ③text/plain:这种编码方式当表单的action的属性为mailto:URL的形式时比较方便,这种方式主要适用于直接通过表单发送邮件的方式。

    26,通过Action在jsp页面输出提示信息,我们可以
       ①在Action中添加一个属性(通过setXx方法设置属性值),然后通过struts2的标签(<s:properties value="xx"/>)在jsp页面输出。
       ②通过ActionContext类来处理,如:ActionContext.getContext.put(key,value);然后通过EL表达式进行输出。

    27,在Form表单中action属性的值要得到【上下文路径】:
       ①<%=request.getContextPath()%>
       ②还可以通过EL表达式得到 :${pageContext.request.contextPath}

    28,得到【ValueStack】的对象有哪几种方法:
       ①ServletActionContext类中的方法:static getValueStack(HttpServletRequest req)【Gets the current value stack for this request】;
       ②ActionContext类中的方法:getValueStack()【Gets the OGNL value stack.】;
       ③ValueStack vs = (ValueStack) request.getAttribute("struts.valueStack");
    (request.getAttribute()返回一Object类型)

    29,【拦截器】。在默认的情况下,如果我们为某个Action定义了拦截器,则这个拦截器会拦截Action的所有方法。可能在有些情况下,我们无需拦截器所有的方法,只需要拦截某些方法,此时就需要struts2拦截器的方法过滤特性。

    30,struts2的【校验】,可以继承ActionSupport类重写validate方法,利用ActionSupport的addFieldError方法把错误信息通过key保存起来,在jsp页面通过struts2标签的fielderror属性输出错误信息。注意:struts2的校验在配置action的时候需要提供输入页面(就是<result name="input">)。这是对action中的所有方法进行校验。
        如果要对action中指定的方法进行校验,把validate方法名改为:validateXxx,其中Xxx是需要校验的指定方法名。

    31,输入校验的流程:
       ①类型转换器把请求参数进行类型转换,并把转换后的值赋给action中的属性。
       ②如果在执行类型转换的过程中出现异常,系统会将异常信息保存到ActionContext中,conversionError拦截器将异常信息 添加到fieldErrors中。不管类型转换是否失败都会转入第三步。
       ③系统通过反射技术调用action中的validateXxx方法。
       ④再调用validate方法。
       ⑤如果fieldErrors中存在错误信息,系统自动将请求转发至input视图。如果没有错误信息将执行action中的方法。
    注意:如果validate方法里没有问题,却返回input页面,可能是类型转换有问题。所以返回input视图有两种原因(类型转换有问题或校验出错).

    32,基于xml配置方式对action内所有的方法进行校验,xml文件的命名规则是:ActionClassName-validation.xml
       如果只需要对action内指定的方法进行校验,则xml文件的命名规则为:ActionClassName-ActionName-validation.xml。其 中ActionName(action的逻辑名称)。它的配置一般用通配符(有助于实验)。
       ①基于xml配置方式的校验,如果ActionClassName-validation.xml、ActionClassName-ActionName-validation.xml同时存在则把两个文件汇总,在进行校验。如果两个xml文件的校验规则起了冲突则执行后面的xml文件。
       ②如果action继承了另一个action则先找到父action校验文件,在找到子action校验文件,再把4(每个action都有指定方法名或非指定方法名)个文件汇总。

    33,【国际化】。国际化按范围分为:全局、action、package的范围的资源文件。Properties文件命名的规则为:xxx_language_country.properties(xxx为用户定义的名字,第二部分为语言类别。)
      Ⅰ定义好了国际化文件后,需要在struts.xml文件配置<constants name="struts.custom.i18n.resources" value="国际化文件的名称(xxx)">[这是定义全局的国际化资源文件],可以在jsp页面显示国际化信息<s:text name="key"/>。
      Ⅱ也可以通过action类继承ActionSupport类,再调用个getText方法的资源文件的key(getText("key")).然后可以通过EL表达式在jsp页面输出。
      Ⅲ也可以通过struts2的表单标签的key属性。如<s:textfield key="key"/>或<s:textarea key="key"/>
    输出带有占位符的国际化信息:
    ①<s:text name="key"><s:param>....</s:param>..</s:text>
    ②通过ActionSupport类的getText(String key,String[] str)或者getText(String key,List list)

    34,包范围的国际化资源文件,
    在大型的应用程序中,整个应用有大量的内容需要国际化,如果我们把国际化的内容放置在全局资源属性文件中,显然会导致资源文件变得过于庞大、臃肿,不便于维护,这个时候我们需要针对不同的模块,使用包范围来组织国际化文件。
       在java的包下创建名为:package_language_country.properties的资源文件,package为固定写法,language_country是对应的语言类别。处于该包及子包都可以访问该资源文件。当在包范围找不到对应的资源文件,然后会在全局范围内查找。

    35,Action范围的资源文件。在Action所在的路径创建名为:ActionClassName_language_country.properties
    如果同时存在全局、package、Action范围的国际化资源文件,系统搜索的顺序是:Action-->package-->全局范围。

    36,以上三种配置有的是基于配置的国际化资源文件。我们也可以通过无配置的方式进行直接访问某个资源文件。
    通过struts2标签,如:
        <s:i18n name="xxx">
           <s:text name="key">
        </s:i18n> 其中xxx是全局范围文件的名称的前缀。
    如果直接想访问包范围的国际化资源文件
        <s:i18n name="com.johnny.action.package">
           <s:text name="key">
        </s:i18n> 其中package是固定写法。



    37,OGNL表达式(Object Graphic Navigation Language对象图导航语言),当struts2接受一个请求时,会迅速创建ActionContext、ValueStack、action,然后把action存放在ValueStack,所以OGNL表达式可以迅速访问action实例的属性。
        OGNL表达式一般要配合Struts2标签使用。
        在struts2中,EL表达式只能访问OgnlValueStack的root里的属性。即action的属性(因为action的属性放在OgnlValueStack的root属性里)。利用OGNL表达式创建List/Map对象,<s:set var="" value="" scope=""/>scope指定变量的被放置的范围,可以为application、session、request、page和action。如果没有设置属性,则默认为OGNLContext(OGNL上下文)中,如果在OGNLContext访问时不用#,如果scope为request....中,则需要用#。value:赋给变量的值,如果没有该属性,则将ValueStack的栈顶的值赋给变量。

    38,防止表单重复提交,首先要有struts的token标签。再使用系统的拦截器。

  • 相关阅读:
    深入解析Hibernate核心接口
    Hibernate基本原理
    深入hibernate的三种状态
    Hibernate commit() 和flush() 的区别
    Hibernate中的merge使用详情解说
    Record is locked by another user
    Vue路由router-link的使用
    Vue-router的基本使用
    Vue把父组件的方法传递给子组件调用(评论列表例子)
    Vue中子组件调用父组件的方法
  • 原文地址:https://www.cnblogs.com/Coda/p/4247739.html
Copyright © 2020-2023  润新知