struts2学习笔记

框架,最佳实践,javaEE的层次,MVC,前端控制器

框架:

什么是框架,框架从何而来,为什么使用框架?

框架(framework):

1.是一系列jar,其本质是对JDK功能的拓展(JDK就只能开发JavaSE最原生的东西).

2.框架是一组程序的集合,包含了一系列的最佳实践,作用是解决某一个领域的问题.

小推论:不同类型的框架,旨在解决不同领域的问题.

 

Web开发中的最佳实践:分层开发模式(技术层面的"分而治之")

JavaEE开发根据职责的纵向划分:表现层,业务层,持久层:

表现层(Predentation Layer):(web/MVC)负责处理与界面交互的相关操作 .

      代表框架:Struts/Webwork/Struts2/SpringMVC/EasyJweb

 

业务层(Business Layer):service:负责复杂的业务逻辑计算和判断.

代表框架:Spring.

 

持久层(Persistent Layer):DAO:负责将业务逻辑数据进行持久化存储(

      代表框架:Hibernate,MyBatis(iBatis)).

 

最佳实践(Best Practice):实际上是无数程序员经历过无数次尝试之后,总结出来的处理特定问题的特定方法.

最佳实践三要素:可读性,可维护性,可拓展性.

简单就是美:

消除重复

化繁为简

简单必须可读,简单必须可拓展

    减少依赖,消除耦合

J2ee先后的设计思想:

Model1:模式一.

在早期的时候J2ee的开发模式,是以JSP为中心.

 使用到技术 JSP + JavaBean

--------------------------------------------------

如果仅仅是开发一个简单的应用,完全足也.

存在问题:

    此时JSP不仅仅需要展现页面,还得处理请求.

    JSP本身是不擅长处理请求的.

 

Model2:模式二.

为了解决Model1JSP不擅长处理请求的操作,Model2中引用了Servlet,专门用于处理请求.

  使用到技术:JSP + Servlet +JavaBean

  Model2,Servlet为中心(所有的请求都先发给Servlet).

------------------------------------------------------

责任分类思想(各自做给自最擅长的事情):

 

JSP:       界面展现.

Servlet:    

           1:接受请求参数,封装成对象.

           2:调用业务方法处理请求.

           3:控制界面跳转

JavaBean:  封装功能操作,可以复用.

Model2体现了MVC的思想:

  MVC   :


 

MVC架构型模式,它本身并不引入新的功能,只是用来指导我们改善应用程序的架构,使得应用的模型和视图相分离,从而得到更好的开发和维护效率。

--------------------------------------------------------------------------------

数据模型(Model):负责封装应用的状态,并实现应用的功能。通常又分为数据模型和业务逻辑模型,数据模型用来存放业务数据,比如订单信息、用户信息等;而业务逻辑模型包含应用的业务操作,比如订单的添加或者修改等。(domain,dao,service)

视图展现(View):界面,用来将模型的内容展现给用户,用户可以通过视图来请求模型进行更新。视图从模型获得要展示的数据,然后用自己的方式展现给用户,相当于提供界面来与用户进行人机交互;用户在界面上操作或者填写完成后,会点击提交按钮或是以其它触发事件的方式,来向控制器发出请求(JSP/html/富客户端技术(Flash:Flex/Java FX/Extjs/EasyUI))

控制器(Controller):用来控制应用程序的流程和处理视图所发出的请求。当控制器接收到用户的请求后,会将用户的数据和模型的更新相映射,也就是调用模型来实现用户请求的功能;然后控制器会选择用于响应的视图,把模型更新后的数据展示给用户(Servlet/Filter/Struts2/SpringMVC)

--------------------------------------------------

我们把JavaEE中的表现层的框架称之为MVC框架.

 

MVC框架的功能作用(WEB开发常见功能)

设置编码、接受请求参数、请求数据验证、处理响应、参数类型转换、

把参数封装成对象、文件上传下载、国际化、令牌机制、自定义标签等。

 

前端控制器:

前端控制器(front controller)J2EE中的设计模式:

    主要提供一种可以集中式管理请求的控制器,一个前端控制器可以接受所有的客户请求,完成大部分通用的功能,并将每个请求递交给相应的请求处理对象(Action/Controler),并适当地响应用户。

前端控制器完成大部分通用功能,把把具体的操作交给各个Action去完成。

MVC框架都有前端控制器,使用MVC框架的步骤:jar-->-->-->---->

  1):拷贝框架依赖的jar.

  2):web.xml中配置前端控制器.

 

ThreadLocal:又称为“线程局部变量”,它为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突(好比每一个线程都使用的是一个新的变量)

 

模拟MVC框架:

目的:对不同的请求,完成大部分相同的操作后(Filter),然后分发给相应Action

我们已有的东西:url(用户提供)--Filter--Action

url(用户提供)--Filter--Action到想要的结果,Filter需要做的是完成大部分相同的操作,其他操作由Action完成.-->Filter需要做的是如果有共同操作则对所有请求的统一初始化操作+识别uri调用Action中相应的方法

由此可知对于Filter来说,Filter需要的是能够识别所有Url,而且知道UrlAction的方法之间的映射关系,在调用方法时知道Action中的所有方法的方法名,方法所在类包,方法的参数

1.如何识别Url?

过滤器配置在web.xml中即可

2.如何映射UrlAction的方法?

a)Filter中用if方法如果url=url1,则调用的方法时method=method1

b)Action对应的xml中将url名和方法名配置在一起如<action uri=”toMethodInvoke”class=”....Clazz” method=”execute”>

3.如何知道Action的方法的方法名,方法所在包和类?

a)在调用方法的时候直接写明方法的所在包类和方法名.

b)在配置文件中配置url和对应的method,同时写明方法的名字,所在类和包.

4.如果Action的方法中没有写跳转,Filter除了负责调用Action中的方法外,还需要处理Action方法的跳转,Filter必须还要知道跳转与方法执行结果的映射关系,跳转的方式,跳转的地址,那么怎样去获取这些信息呢?

在配置文件值直接将方法执行结果与跳转配置在一起,由于方法的执行结果往往是不确定的所以其跳转也是多种的,所以需要配置多个这样的标签<method-result name=方法返回值” type=”跳转方式” url=”跳转的地址”>,由于方法的执行结果是与方法对应的,所以该标签写在方法标签<method/>的子标签位置.

 

这样做的问题:由于xml中很多的关联关系是通过写在一起方式来表达的,所以在Filter中处理这个xml文件时需要时刻注意多个属性(:uri,class,method是否是在同一个标签中),这样Filter需要过分注意xml的结构关系,这样会导致filter的执行比较”,所以可以利用一个封装类ActionConfig封装classmethod来表达package,class,method,results是否是一组的

为了保证在Action中能够得到请求request和响应response的相关信息,所以需要设定一个传递requestresponse的类ActionContext(封装requestresponse,然后提供他们的settergetter方法).


 

Struts2的发展:

Struts2的前世今生:

------------------------------------------------------------------

    1.早期开发模型Servlet+JSP+JavaBean(Model2)显得力不从心:

        流程凌乱、数据传递无序、缺乏辅助功能。

    2.MVC模式的轻量级Web应用框架:Apache Struts1很快风靡全球。

       代码结构划分合理,实用工具框架(如验证框架、国际化框架)等。

    3.时间推移,Struts1的缺点:

       线程不安全、灵活性低、和ServletAPI耦合、页面传值麻烦等。

    4.异军突起,SpringMVCOpenSymphonyWebWork等。

    5.Apache Struts + OpenSymphony WebWork2 = Struts2

-------------------------------------------------------------------

Struts2:基于MVC的轻量级的Web应用框架,

来源于Webwork2,Struts1.x完全不兼容

====================================================

Struts2 是一个非常优秀的MVC框架,基于Model2 设计模型.

由传统Struts1WebWork两个经典框架发展而来:

Struts2框架=Struts2+XWork

Strust2 核心功能:

允许POJOPlain Old Java Objects)对象 作为Action.

Actionexecute 方法不再与Servlet API耦合,更易测试

支持更多视图技术(JSPFreeMarkerVelocity

基于Spring AOP思想的拦截器机制,更易扩展

更强大、更易用输入校验功能

整合Ajax支持

等等

Struts2的组成:

 

struts2目录结构:

apps:该文件夹包含了基于struts2 的示例应用,这些示例应用对于学习者是非常有用的

docs:该文件夹下包含了struts2 相关文档,包括struts2 快速入门、struts2的文档以及API文档等

lib:该文件夹下包含了Struts2框架和核心类库,以及struts2第三方插件类库

src: 该文件夹下包含了Struts2框架的全部源代码

开发Struts2:

开发Struts2必须依赖的jar:

struts2-core-2.3.1.1.jarStruts 2框架的核心类库

xwork-core-2.3.1.1.jarCommand模式框架,WebWorkStruts2都基于xwork

ognl-3.0.3.jar:对象图导航语言(Object Graph Navigation Language),  struts2框架通过其读写对象的属性

freemarker-2.3.18.jarStruts 2UI标签的模板使用FreeMarker编写

commons-logging-1.1.x.jarASF出品的日志包,Struts 2框架使用这个日志包来支持Log4JJDK 1.4+的日志记录。

commons-fileupload-1.2.2.jar: 文件上传组件,2.1.6版本后需要加入此文件

commons-io-2.0.1.jar:传文件依赖的jar

commons-lang-2.5.jar:对java.lang包的增强

步骤:

第一个Struts2程序步骤:

1.准备Struts2依赖的jar文件.

    注意:别拷贝Struts2lib下所有的jar,必须的jar如右.

    Struts2/apps,解压struts2-blank.war,拷贝其WEB-INF/lib中的所有的jar到自己的项目中.

2.web.xml中配置前端控制器.StrutsPrepareAndExecuteFilter-(参阅struts2-blank项目的web.xml文件.)

 

3.定义一个POJO:HelloAction,提供一个execute方法(公共无参数).

 

4.准备Struts2的配置文件:struts.xml.struts2-blank\WEB-INF\classes中拷贝到项目的source folader目录.

 

5:部署项目,访问Action:

 访问格式:http://ip:port/contextPath/namespace/actionName[.action]

          http://localhost:80/oa/hello.action


Struts2的执行流程:

1.简单执行流程:

 

2.完整执行流程:

 

Struts2的执行步骤:

-----------------------------------------------------------

.客户端发送请求;

.该请求经过一系列的过滤器(Filter):其中可选过滤器ActionContextCleanUp,帮助Struts2和其他框架集成。例如:SiteMesh Plugin

.接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper,来决定该请求是否需要调用某个Action

.ActionMapper决定需要调用某个ActionFilterDispatcher把请求的处理交给ActionProxy

.ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类。

.ActionProxy创建一个ActionInvocation的实例。

.ActionInvocation实例调用Action的前后,涉及到相关拦截器(Intercepter)的调用。

.一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果是一个JSP或其他页面(也可以是其他的Action)JSP页面展现可使用Struts2框架中的标签(该过程会涉及ActionMapper).

---------------------------------------------

Strtus2框架中肯定会创建很多对象(Action,Proxy,Intercetor),都是由xwork容器负责创建的.xwork容器中有一个类:ObjectFactory(对象创建).

 

3.Struts2的配置文件和简单配置

struts.xml中引入其他的配置文件:

语法:<include file="struts-part1.xml"/>:

-----------------------------------------------------------------------------

在大部分应用里,随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿。为了避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,我们可以将一个struts.xml配置文件分解成多个配置文件,然后在struts.xml文件中包含其他配置文件。下面的struts.xml通过<include>元素指定多个配置文件:

<struts>

    <include file="struts-part1.xml"/>

    <include file="struts-part2.xml"/>

</struts>

 

Struts2中的6大配置文件:

-----------------------------------------

Struts2框架按照如下顺序加载struts2配置:

1.default.properties:该文件保存在 struts2-core-2.3.7.jar org.apache.struts2包里面:包含了Struts2的默认常量配置(编码,比如action的拓展名等).

2.struts-default.xml:该文件保存在 struts2-core-2.3.7.jar:包含了框架依赖的对象配置和结果类型,拦截器等配置.

3.struts-plugin.xml: 该文件保存在Struts2框架的插件中:struts-Xxx-2.3.7.jar.由插件提供

上述三个文件时框架自带的,我们不能修改,只能使用.

---------------------------------------------------------

4.struts.xml(使用最多的文件):该文件是web应用默认的struts配置文件.重点.配置自定义的Action和其他信息.

5.struts.properties:该文件是Struts的默认配置文件-->可以修改default.properties 的常量配置.

6.web.xml 该文件是Web应用的配置文件

上述三个文件是我们可以修改操作的.

---------------------------------------------------------

如果多个文件配置了同一个struts2 常量,则后一个文件中配置的常量值会覆盖前面文件配置的常量值.

注意:一般的,我们只在struts.xml中做常量配置.

<constant name="struts.action.extension" value="action,opensource,do,,"/>

 

常见的常量配置:

---------------------------------------

指定默认编码集,作用于HttpServletRequestsetCharacterEncoding方法 和freemarker velocity的输出

   <constant name="struts.i18n.encoding" value="UTF-8"/>

   该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。

   如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开

   <constant name="struts.action.extension" value="action,,"/>

   设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭

   <constant name="struts.serve.static.browserCache" value="false"/>

   struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开

   <constant name="struts.configuration.xml.reload" value="true"/>

   开发模式下使用,这样可以打印出更详细的错误信息

   <constant name="struts.devMode" value="true" />:修改struts.xml之后,不要重启Tomcat.

   默认的视图主题

   <constant name="struts.ui.theme" value="simple" />

   是否支持动态方法调用

   <constant name="struts.enable.DynamicMethodInvocation" value="false"/>

 

package元素:struts.xml根元素(strtus)的子元素. java中的package没有一点关系.

    仅仅是为了统一管理多个action元素.

格式为:

<package name="" extends="" namespace="" abstract="true|false">

可以一个模块分出一个<package>元素.

常用的属性:

  name:      表示当前<package>元素的名称,多个<package>元素的name不能相同.oaPkg/crmPkg

  extends:   自定义的<package>元素必须继承于struts-default包或者struts-defalt的子包.

             如此一来,当前<package>元素就可以拥有父package的所有配置.

  namespace: 命名空间,actionname共同决定了一个action的访问路径.

  abstract:  表示当前<package>元素是否是抽象的.

             如果为true,那么当前<package>就不能定义action元素,只能用于被其他<package>所继承.

-----------------------------------------------------------------------

开发中的最佳实践:

多个package共同的配置信息:

<package name="basePkg" extends="struts-default" namespace="/" abstract="true">

     <!--package的拦截器配置--->

</package>

OA:

<package name="oaPkg" extends="basePkg" namespace="/oa">

    <!--packageaction配置--->

</package>

CRM:

<package name="crmPkg" extends="basePkg" namespace="/crm">

    <!--packageaction配置--->

</package>

 

 

action元素:<package>元素的子元素,用于配置Action.

语法:<action name="" class="" method="">

常用的属性:

  name:   action的名称,该名称和当前action所在packagenamespace共同决定了访问路径.

        访问Action的格式:http://ip:port/contextPath/namsspace/actionName[.action]

        注意:action名称没有/,在同一个<package>不能相同.

  class:  Action类的全限定名,表示把哪一个Action类交给Strtus2框架来管理.

          class的默认值:com.opensymphony.xwork2.ActionSupport.

  method: 当前action需要执行哪一个方法,注意:该方法必须在class对应的类中.

          method的默认值:execute.

result元素:<action/>元素的子元素,表示结果视图(action执行完毕跳转到哪里去).

语法格式:<result name="" type=""></result>

result元素的配置:

    name属性: 唯一,表示逻辑视图名称,该名称就是action方法的返回结果.默认值:success.

    type属性: 表示资源的跳转方式(请求转发/URL重定向),阅读struts-default.默认:dispatcher

    文本内容: 表示需要跳转资源的路径(webapp下开始寻找).

result元素的type属性的常用值:

   dispatcher:     请求转发:(Action请求转发到JSP),默认的.

   chain:          请求转发:(Action请求转发到Action).

   redirect:       URL重定向:(Action重定向到JSP).

   redirectAction: URL重定向:(Action重定向到Action).

   stream:         文件下载使用,输入流.

-------------------------------------------------

result元素分类:

  1):局部的结果视图:配置在<action>元素里面,就只能当前Action可以跳转的.

  2):全局的结果视图:配置在<package>元素中的<global-results>元素里面,当前<package>Action都可以跳转进去.

      先从当前Action中去找指定名字的result,找到就跳转,找不到,再找全局的result,找到跳转,找不到,就报404 错误.

 

 

Action类的三种编写方式:

第一种.使用公共的POJO类作为Action. 提供公共的无参数的Action方法.(不推荐).

缺点:

    没有一种方式约束Action方法必须是公共的无参数的.

    Action方法的返回逻辑视图名可以自定指定. 有时起名不规范. 比如:"ooxx".

解决方案:第二种.

第二种.定义一个类,实现于com.opensymphony.xwork2.Action接口.并覆写execute方法即可.(不推荐)

Action接口中,不仅提供了Action方法的声明,也提供了常用的逻辑视图名称:

public static final String SUCCESS = "success";

public static final String NONE = "none";

public static final String ERROR = "error";

public static final String INPUT = "input";

public static final String LOGIN = "login"; 

缺点:

    不支持国际化,数据校验,消息机制.

解决方案:第三种:

第三种.定义一个类,继承于com.opensymphony.xwork2.ActionSupport.(推荐)

public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {}

---------------------------------------------

真实开发中,我们却往往再提供一个BaseAction.

ActionSupport.

---BaseAction(自定义Action的基类,存储AAction,BAction共同的代码.)

-----AAction

-----BAction

 

 

Action中多个Action方法会造成<action>配置的臃肿.

解决方案:

方案1: DMI:动态方法调用 :官方不推荐.

      格式:  action!方法名

      比如:  emp!edit    emp!list

Struts2新的版本中,默认的关闭了DMI.若我们需要使用DMI,就需要配置常量,启用动态方法调用.

此时:<action/>元素不需要指定method属性值.

<constant name="struts.enable.DynamicMethodInvocation" value="true"/>

注意:

1,开启动态方法调用,配置struts静态常量:DynamicMethodInvocation

2,只需要配置一个action,并使用【action名称!action方法名称】的方式访问;

3,动态方法调用安全性很差,没法控制action中方法的访问权限;官方建议不使用;

 

方案2:使用通配符来访问(*).

使用*来完成通配,*可以表示任意字符;

每一个请求路径上的*都可以匹配具体请求的一段文字,并且可以再整个action配置中,使用{1},{2},{3}来完成替换;

<action name="Employee_*" method="{1}" />

<action name="*_*" class="com._520it.struts_*Action" method="{2}" />

 

 

访问ServletAPI:

什么是访问ServletAPI:

---------------------------------------------------------

使用JavaWeb中定义的相关的接口和类,详细如下:

  1):通过请求对象获取请求参数(HttpServletRequest对象).

  2):通过响应对象来处理响应操作(HttpServletResponse对象).

  3):操作Servlet中的三大作用域对象(requerst,session,servletContext).

      1>:HttpServletRequest

     2>:HttpSession

     3>:ServletContext

  4):操作Cookie(Cookie对象).

---------------------------------------------------------

Strtus2中访问ServletApi三种方式:

   方式1:  通过实现感知接口(使用非常少).

   方式2:  通过ServletActionContext类来访问(开发中使用比较多).

   方式3:  通过ActionContext来访问(最规范的方式,开发中使用也比较多,操作作用域).

           如果开发中需要使用到Cookie,此时就可以方式2.

 

方式1:通过实现感知接口.

   需要访问/操作哪一个ServletAPI,就只需要让Action实现对应的感知接口.

   HttpServletRequest                      ServletRequestAware

   HttpServletResponse                     ServletResponseAware

   ServletContext                          ServletContextAware

再实现各自的方法,具体如下:

 

实现感知接口的方式来访问ServletAPI:

  1):确实很简单.

  2):此时ActionServletAPI严重耦合在一起.

    也就是说,使用Strtus2必须依赖Servlet的相关的jar.

   解决方案:参照方式2.

 

 

方式2:通过ServletActionContext工具类.

   ServletActionContext工具类,封装了获取requestresponse的静态方法.

  常用方法:

  static HttpServletRequest getRequest():获取请求对象

  static HttpServletResponse getResponse():获取响应对象

 

通过ServletActionContext工具类.

  1):也很简单也很直观.

  2):也存在ActionServletAPI耦合的问题.

  3):但是在开发中很多人依然使用这种方式.

  如果我想完全让ActionServletAPI解除耦合,方式3.

  方式3:通过ActionContext.

   ActionContext,表示Action的上下文,每一次请求都是一个新的Action对象,可以先简单的理解为:ActionContext就封装了这一次请求所有相关的数据.

 

创建ActionContext对象:

   ActionContext  ctx = ActionContext.getContext();

常用的方法:

  操作request作用域:

    void  put(String key,Object value):把共享数据存放在request. 好比:request.setAttribute(String key,Object value);

    Object get(String key):request中取出共享数据. 好比:Object value = request.getAttribute(String key);

  操作session作用域:

    先获取SessionMap对象:Map<String,Object> getSession();接下来的操作就是操作Map集合.

  操作application作用域:

    先获取applicationMap对象:Map<String,Object> getApplication();接下来的操作就是操作Map集合.

  获取请求参数:

    先获取参数的Map集合,再从Map中取出每一个参数.

   Map<String,Object>  ActionContext.getContext().getParameters();

 


J2EE的最佳实践:按照功能职责,分层开发(表现层/业务层/持久层):

表现层:

     职责:

          1.接受请求数据

          2.把数据封装Model对象

          3.调用业务逻辑方法处理请求

          4.控制界面跳转

-------------------------------------------------

MVC思想:

M:Model.

V:JSP

C:StrutsPrepareAndExecuteFilter(前端控制器(分发请求).)

问题:Action到底充当什么角色?-->贴近控制器的Model,普通的Model(domain)都是贴近数据库的Model

-------------------------------------------------

Action获取请求参数三种方式:

第一种:Action本身作为Model对象,通过setter方法封装请求参数(属性注入)

第二种:创建独立Model对象,页面通过OGNL表达式封装(属性注入)

第三种:Action实现ModelDriven接口,对请求数据进行封装(模型驱动)

 

第一种:Action本身作为Model对象,通过setter方法封装请求参数(属性注入):

    此时Action只需要提供参数同名的属性(setter方法,只需要给Action设置值.)

 

优点:简单,直观.

缺点:如果参数比较多,此时Action就的提供N个setter方法,感觉很繁琐.

------------------------------------

在这里偷偷把参数传递给Action的是拦截器:

在这里,也感受了,Struts2内置的类型转换器.

Struts2中,每一次请求都是一个新的Action对象,在Action中的成员变量是线程安全的.

 

第二种:创建独立Model对象,页面通过OGNL表达式封装(属性注入).

 

此时的方式:

优点:把多个参数信息封装到对象,很容易.

缺点:JSP,表单的参数名称,变得美工看不懂了.

 

第三种:Action实现ModelDriven接口,对请求数据进行封装(模型驱动):

   

该方式:

优点:JSP表单干净,也抽取了Model对象,Action也比较简单.

缺点:一个Action只能把请求的参数封装到一种类型的对象中去.

--------------------------------------------------

开发中的选择:

  1):如果参数少,或者没有Model对象,选择第一种方式.

  2):第二种方式使用最多.

  3):在编写统一的CRUD的时候,方式3有优势.

-------------------------------------------------------

有时候,我们会综合应用,举个例子.

  修改密码案例:

        用户名 :____________________

       原始密码:____________________

        :____________________

       确认密码:____________________

   因为在:User对象中,只有一个密码,没有新密码,确认密码的属性.

   此时,方式1+方式2,或者方式1+方式3来完成.

 

把请求数据封装到集合中:

    1):把多组请求数据封装到List集合.(常用)

    2):把多组请求数据封装到Map集合.

 

 

 


拦截器:Interceptor,使用动态代理机制来实现,Spring中的AOP是同一种思想.

------------------------------

拦截器:Struts2拦截器是在访问某个ActionAction的某个方法之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP的一种实现.

AOP:面向切面编程.其实现原理:动态代理模式--->留给Spring

WebWork中文文档解释:拦截器是动态拦截Action而调用的对象。它提供了一种机制可以使开发者可以定义在一个Action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也提供了一种可以提取Action中可重用的代码的方式。

拦截器栈(Interceptor Stack:Struts2拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。

-------------------------------------------------------------------------

拦截器的"":

---------------------------------------------------

DRY原则:Dont't Repeat Yourself.

拦截器在设计和程序结构上的优点:

  拦截器能把很多功能从Action中独立出来,分散到不同的拦截器里面,减少了Action的代码。如此,拦截器和Action本身的功能都更单一了。当通用的功能代码被封装在拦截器里面(代码模块化),就可以对不同的Action,根据功能需要,来配置相应功能的拦截器了。提高了拦截器所实现的功能的重用性,也变相实现了装配式和可插拔式的体系结构,使得整个系统结构变得更灵活。

1.简化Action的实现

2.功能更单一

3.通用代码模块化

4.提高重用性

 

 

 

Struts2中内置的拦截器:

struts-core-2.3.x.jar--->struts-default.xml

------------------------------------------

常见的拦截器:

1params拦截器

这个拦截器偷偷的把请求参数设置到相应的Action的属性去的,并自动进行类型转换。

2.modelDriven拦截器

如果Action实现ModelDriven接口,它将getModel()取得的模型对象存入OgnlValueStack中。

3.execption拦截器

顾名思义,在抛出异常的时候,这个拦截器起作用。最好把它放在第一位,让它能捕获所有的异常。

4.validation拦截器

调用验证框架读取 *-validation.xml文件,并且应用在这些文件中声明的校验。

5.token拦截器

核对当前Action请求(request)的有效标识,防止重复提交Action请求。

6.fileUpload拦截器

用来处理文件上传

7.workflow拦截器

调用Actionvalidate方法,一旦有错误返回,重新定位到INPUT结果视图

8.servletConfig

   通过感知接口,获取感应对象.

内置拦截器:

 

感知接口对应的拦截器

 

 

自定义拦截器(LoginInterceptor),控制必须登陆之后才能访问MainAction,如果没有登陆强制访问MainAction,则应该自动跳转到login.jsp页面:

--------------------------------------------------------------------

操作步骤:

   第一步:定义拦截器类.

      方式1:直接实现于com.opensymphony.xwork2.interceptor.Interceptor接口(太弱了).

      方式2:直接继承于com.opensymphony.xwork2.interceptor.AbstractInterceptor(用的多).

      方式3:直接继承于com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.

           excludeMethods:可以设置该拦截器排除对哪些方法的拦截操作.

           includeMethods:可以设置该拦截器必须等哪些方法做拦截操作.

   第二步:strtus.xml中注册该自定义拦截器.

 

 

  第三步:引用自定义拦截器(action元素或者package元素真正的来引用拦截器,生效).

     待会截完整的图.

 

第一个版本:

 

上述代码和配置针对于上述案例没有问题,但是:

   仅仅是在mainaction元素中,引用了LoginInterceptor拦截器,那如果多个<action>元素都要做登陆判断,此时每一个<action>元素都得配置:<interceptor-ref name="loginInterceptor"/>.

解决方案:loginInterceptor作用域于整个<package>.

<!-- 引用该package的默认拦截器 -->

 

<default-interceptor-ref name="loginInterceptor" />.

此时发现:编写了package的默认拦截器之后,再也不能接受到请求参数了.

原因是:当我们自己设置默认拦截器之后,会覆盖了<package>的默认拦截器引用也就会失去默认拦截器在的很多拦截器功能..

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

解决方案:同时引用两个拦截器.

 

版本二:

 

 

Struts中给页面传递数据的方式:

   1):通过ServletAPI来传递. request.setAttribute(String key,Object value).

          太依赖Servlet API,很不方便.

   2):Strtus2中有新的给页面传递数据的方式,OGNL-->升级版的EL:(依赖Strtus2标签)

---------------------------------------------------------------------------------------------

1.什么是OGNL

   OGNLObject Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。

  Struts2框架使用OGNL作为默认的表达式语言。

  EL(表达式语言),OGNL就是EL的升级版.

  作用:Action和视图(JSP)之间数据交互的桥梁.

  讲解OGNL之前,先得学习ValueStack.

--------------------------------------------------------------

2.什么是ValueStack(值栈)

        值栈是对应每一个请求对象的轻量级的内存数据中心。

    每一次请求的时候,都会创建一个新的ValueStack对象,ValueStack对象封装了这一次请求相关的数据信息.

1).ValueStack实际是一个接口,Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack,这个类是Struts2利用OGNL的基础。

2).ValueStack贯穿整个Action的生命周期(一次请求到响应):每个Action类的实例都拥有一个ValueStack对象。 ValueStack相当于数据的中转站,在其中保存该次请求和当前Action对象和其他相关对象信息。

3).Struts2框架把ValueStack对象保存在名为“struts.valueStack”的request属性中。

   新的请求:

            ValueStack vs = new  ValueStack..;

            request.setAttribute("struts.valueStack",vs);

3.如何获取ValueStack对象.

     方式1(最传统的方式):

           ValueStack vs = (ValueStatck)ServletActionContext.getRequest().getAttribute("struts.valueStack");

           ValueStack vs = (ValueStatck)ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

     方式2(最简单的方式):

           ValueStack vs3 = ActionContext.getContext().getValueStack();

4.ValueStack内部结构

  ValueStack对象中有两个很重要的属性,这两个属性就是ValueStack的主要内部结构:

------------------------------------

  root:    类型: CompoundRoot extends ArrayList  : 栈的数据结构(后进先出)

  context: 类型: Map:                            : 上下文

  root:主要存储Action对象相关的数据信息.

  context:主要存储映射关系数据.(key-value).

context存在root对象的引用(只要拿到context对象就可以获取到root对象):

context中还存在requestsessionapplicationattrparameters对象的引用。

获取到context,就可以获取ValueStack中所有的数据.

root中获取数据:    直接使用属性名获取.   ---><s:property value="属性名"/>

context中获取数据: #key                  ---><s:property value="#key"/>

#:表示ActionContext.getContext():其实就是我们的上下文.

 

 

 

5:Action如何往ValueStack中存储数据,JSP如何从ValueStack中取出数据.

1).把数据放入root:(,ArrayList.每次都要压在栈顶)

     方式1:ValueStack对象.getRoot().add(0, Obejct val);//把数据压入栈顶

     方式2:ValueStack对象.getRoot().push(Object val):等价于valueStack对象.getRoot().add(0, Obejct val);

     方式3:ValueStack对象.set(String propertyName,Object value);

     方式4.Action中提供一个可访问的属性(getter方法).

     一般的,把单个对象可放入root,就在栈顶.

------------------------------------------------------------------

2).把数据放入context:

    方式1:ValueStack对象.getContext().put(String key,Object value); 太长了.

    方式2:ActionContext对象.put(String key,Object value);

     一般的:把集合中的数据放入context.

-------------------------------------------------------------------

如何从JSP中取出ValueStack中的数据:

此时必须使用Struts的标签.--->先引入Struts2标签

<%@ taglib uri="/struts-tags" prefix="s"%>

Struts2的调试标签:<s:debug/> :主要用来观察数据在哪一个空间(root,context).

访问方式:<s:property value="OGNL表达式"/>

1).获取root中数据:

   :放入root中的数据,没有属性名:<s:property value="[0].top"/>

   :放入root中的数据有属性名:   <s:property value="属性名"/>

2).context中数据:

   <s:property value="#key"/>

------------------------------------------------------------------

EL可以访问ValueStack中的数据:

   不建议这么做:

   为什么可以呢: Struts2重新包装而来请求对象.${msg}---><%=pageContext.findAttribute("msg")  %>

   StrutsRequestWrapper:先从ValueStack中取出数据,再放入request.


第一个Struts2的标签:

第一步:JSP,引入Struts2的标签库:

<%@ taglib uri="/struts-tags" prefix="s"%>

------------------------------------------------------

<s:debug/>:调试标签,用来观察ValueStack的内部结构,和数据存储为位置.

 


输入校验:

.客户端校验:  过滤正常用户的误操作,通过JS代码完成(可以绕开).

.服务端校验:  整个应用阻止非法数据的最后防线(必须),使用Java代码.

------------------------------------------------------------------

Struts2校验方式:

1.代码方式校验:开发中常用(在代码中编写校验规则)

2.配置校验:

  2.1.基于XML配置校验(推荐使用)

  2.2.基于Annotation配置校验。

 

Action

    *  要继承ActionSupport(才能拥有输入校验功能)

    *  重写Validateable接口中的validate()方法 ,在该方法中完成验证

           * 步骤如下:

                 * validate()方法在其他的业务方法之前执行

                 * 验证出错转向的页面

                         struts.xml配置<result name="input">/validate/login.jsp</result>   

                         其中input转向是在action中已经定义好的.

                         public static final String INPUT = "input";                  

                 *   什么时候表示验证出错(转向input所指向的页面)

                         *  super.addFieldError("字段名称", "错误信息");

                         *  当集合不为空时,转向错误页面.

                         *  若校验失败,不会再执行Action中的业务方法.

 

 问题1:为什么校验失败,默认跳转到input结果视图.

   观察:DefaultWorkflowInterceptor的源代码,发现如上图.

 

问题2.为什么在执行input方法之前,没有执行validate方法.

  validationworkflow拦截中,设置了不被校验的默认方法.

  在配置validationworkflow拦截器的时候,会忽略掉input方法.


 

问题3:Action中某些方法不需要校验,却也执行了validate方法,如何避免问题.

   可以为不需要校验的方法上,使用@SkipValidation(跳过验证).

 

问题4.开发中在一个Action,校验的方法是少数,大多数方法都不需要校验.

      难道大多数方法都要使用@SkipValidation标签吗?

   为了避免该问题,我们就应该对指定的方法做校验操作,Action类中提供:

    public void validateXxx(){}:Xxx表示被校验的方法.

    比如:Action中新增和更新的方法叫做:saveOrUpdate.

    此时需要对saveOrUpdate方法做校验,那么校验方法:validateSaveOrUpdate.

 

问题5:workflow的拦截器可以看出,校验失败会跳到默认的结果视图("input").

 

      问题:是否可以修改默认的结果视图?----?校验失败跳到"edit"视图

      @InputConfig(resultName="edit")

      必须贴在被校验的方法之上,而不是贴在validate.

问题6:错误信息提示丑陋..

 

Struts2的国际化:

 

 

 

准备国际化资源文件:基本名词:app

中文:app_zh_CN.properties

英文:app_en_US.properties


---------------------------------

告诉Struts2框架:国际化资源文件叫什么名字.

<constant name="struts.custom.i18n.resources" value="app"/>

---------------------------------

准备国际化的login.jsp

JSP,获取指定的国际化信息:(先引入Struts2的标签库)

<s:text name="资源文件中的key"/>

-----------------------------------

若要让Action支持国际化,那么Action必须继承ActionSupport或者ActionSupport的子类.

Action中获取资源信息:

通过ActionSupport类中的:

String getText(String name,String[] args);

参数: name:表示资源文件中的key

      args:资源文件中指定key占位符的真实值.

返回:拼接好的一个国际化信息.

 

 

 

文件上传:

Strtus2的文件上传操作:

文件上传准备:

注意:

     1:表单必须使用POST方式提交;

     2:使用二进制编码.multipart/form-data

     3:<input type="file" name=""/>

 

要注意处理文件上传的表单的Action中必须要有文件控件的name为前缀的settergetter,比如此Action对应的处理文件是headImg,所以必须要有setHeadImgFileName,setHeadImgContent Type,才能对文件的文件名和文件的类型做接收.(约定优于配置)


Strtus2对上传组件的支持:

default.properties

------------------------

struts.multipart.parser=jakarta  : 设置在Struts2中使用哪一种上传组件

struts.multipart.saveDir=        : 设置临时文件的保存路径(不要设置),默认就在Tomcat.

struts.multipart.maxSize=2097152 : 设置一次请求的最大值,单位字节. 默认是2M

---------------------------------------------------------------------------

Strtus2中支持文件上传时因为拦截器的原因:

  <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>

 

此处要注意拦截器的覆盖问题:

在一个包中引用多个<interceptor-ref>,前面配置的<interceptor-ref>中包含的拦截器会覆盖后面配置的<interceptor-ref>中包含的同名的拦截器(前面覆盖后面)


若文件过大,则提示:

 

解决方案:把提示信息作出国际化.支持中文.

提示信息都在struts-messages.properties 文件里预定义.  (org.apache.struts2包下)


 struts.xml中引用资源文件:

 <constant name="struts.custom.i18n.resources" value="uploadMessage"/>

 

 

文件下载:

 

 

使用Strtus2标签的好处:

表单自动回显数据.

对页面进行布局和排版.

支持AJAX应用.

---------------------------

Struts2标签:

        通用标签

            控制标签/数据标签

        UI标签

引用标签库:

<%@ taglib uri="/struts-tags"  prefix="s"%>

 

 









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值