介绍Struts2框架
框架实现了部分的功能代码(半成品),使用框架简化了企业的软件开发。提高了开发效率,
学习框架最重要:清楚框架能做什么?哪些事情你要来做?
什么是Struts2框架,它有什么用?
Struts2是Struts的下一代产品,是在Struts1和webwoek的技术的基础上进行了合并的全新Struts2框架
其实
全新的Struts2的提下与Struts1结构差距非常大!
Struts2=Struts1+webwoek;
Struts2是apache的产品
Struts2是一个标准的MVC框架
Javaweb中model2模式就是MVC模式【model2=javabean+jsp+servlet】
Struts2框架是在javaweb开发中使用
使用Struts2框架:简化开发,降低耦合!
类似于Struts2框架的产品:
Struts1 webwoek jsf springMVC
常见的框架整合
SSH strtus2+srpring+hibernate
SSI springMVC+spring+ibatis[MyBatis]
Struts2快速开发
Web的开发流程 index.jsp---àservlet---àhello.jsp
Struts2的流程 index.jsp-àaction---àhello.jsp
1.导jar包
Struts2的目录结构
Apps:官方提供的例子程序
Docs:文档
Lib:Struts2框架所有的应用jar包及插件
Src:源代码
注意:Struts2开发中无须导入全部的jar包
2.创建index.jsp页面 <ahref=”${pagecontext…}/hello”>揍你</a>
创建hello.jsp页面 一句话hello
3.对Struts2框架进行配置
1.web.xml中进行核心控制器的配置---【filter】
【struts-2.3.15.1\apps\struts2-blank\WEB-INF\web.xml中直接复制】
目的:为了让Struts2框架可以运行
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter>
<filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
2.创建一个Struts.xml的配置文件
【struts-2.3.15.1\apps\struts2-blank\WEB-INF\classes\struts.xml 中直接复制】
目的:为了Struts2框架流程可以执行
<package name="default" namespace="/" extends="struts-default"> <action name="hello" class="web.acton.HelloAction" method="add"> <result name="ok">/hello.jsp</result> </action> </package> |
3.创建一个action类
要求:在action类中创建一个带string类型返回值的方法
public String add(){ System.out.println("进入了add方法"); return"ok"; } |
表面执行流程:index.jspàweb.xml-àstruts.xmlàaction类对应的方法->对应返回结果的jsp
Struts2内部的执行流程
1.请求对应的action
2.进入web.xml
3.被Struts2的核心过滤器拦截 进入过滤器
4.在StrutsPrepareAndExecuteFilter核心过滤器的init方法中对应Dispatcher(调度内部的加载资源)对象进行初始化,在Dispatcher类中定义的init方法内描画struts2的配置文件(内部)的加载顺序
init_DefaultProperties(); // [1]
init_TraditionalXmlConfigurations(); // [2]
init_LegacyStrutsProperties(); // [3]
init_CustomConfigurationProviders(); // [5]
init_FilterInitParameters() ; // [6]
init_AliasStandardObjects() ; // [7]
1.default.properties文件
作用:定义了Struts2框架的所有常量【如:编码格式,上传的格式….】
位置:struts2-core-2.3.15.jar/prg/apache/struts2/default.properties
2.struts-default.xml
作用:配置非常多的javaBean组建,提供了Struts2的很多方法【获取参数,转发..】
位置:struts2-core-2.3.15.jar/struts-default.xml
Struts-piugin.xml
作用:加载struts2的插件
Struts.xml
作用就是为了能适应struts2 我们配置的文件
3. 自定义的struts.properties
用户自定义的常量
4.自定义的配置文件
5.web.xml
Web应用的配置文件(配置的常量)
6.bean加载
在开发中,后加载文件中的配置会覆盖前加载文件中配置信息【常量的内容】
Action的配置
1.<package> 作用:用于什么一个包 用于管理action
1.name 他的作用声明一个包名,包名不能重复,也就说它是唯一的
2.namespace 它与action标签中的name属性合并确定一个唯一的acting访问路径
3.extends 表示解除的包名
4.abstrace 它可以取值为true/false true表示这个包可以用于继承
2.<action> 用于声明一个action
1.name它与package标签中的namespace 属性合并确定一个唯一的acting访问路径
2.class 指定action的全类名
3.method 要访问action类中处理请求的方法
3.<result> 用于确定返回结果类型
1.name 他与action中的方法的返回值对比,确定跳转的路径
Action的配置细节
1.关于struts2提供的默认值问题
<packagenamespace=”默认值”>
Namespace的默认值是 “”
<action class=”默认值” method=”默认值”>
Class的默认值 com.opensymphony.xwork2.ActionSupport
Method的默认值 execute
<resultname=”默认值”>
Name的默认值是 success
2.关于action的路径问题:
现在的action的配置是:
<package name="default" namespace="/" extends="struts-default"> <action name="hello" class="web.acton.HelloAction" method="add"> <result name="ok">/index.jsp</result> </action> </package>
当我们输入http://localhost:8080/struts2-day1/stu/a/b/hello也访问到了action 表示非常的神奇
原因:struts2中的action被访问时:首先查找 Namespace=stu/a/b action name=”hello” 没有 Namespace=stu/a action name=”hello” 没有 Namespace=stu/ action name=”hello” 有 如果最后也没有找到 就是404
|
3.默认的action【****】
作用:处理其他页面处理不了的路径
<default-action-refname="st"></default-action-ref> [写在package下]
配置了这个,当访问的路径,其他的action处理不了事,就会执行name指定的名称的action
<default-action-ref name="default"></default-action-ref>
<action name="default" > <result>/hello.jsp</result> </action> |
4.自定义action的默认处理类
在action配置的时候如果class不写,struts2会默认给你一个类,我们又不想使用这个类,自己指定:当不写class时 默认的路径 【写在package下】
<default-class-ref class="web.acton.HelloAction"> </default-class-ref> |
关于常量的配置【在开发中 定义好的变量 不满足我们的需求】
问题:struts自定义的变量存在哪里?可不可以修改default.properties 不能修改
问题:人为的设置变量:可以再哪些位置设置? Struts.xml web.xml
1.struts.xml(应用的最多的)
<constantname="常量名" value="常量值"></constant>
如
<constant name="struts.action.extension" value="lsd,,"></constant> |
2.web.xml(了解)
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>struts.action.extension</param-name> <param-value>yd,,</param-value> </init-param> </filter> |
【后配置的参数 会覆盖前面配置的参数】
常用的常量
struts.action.extension=action,,
指定struts框架的默认拦截的后缀名
struts.i18n.encoding=UTF-8
相当于:reqeust.setCharacterEncoding(“UTF-8”);解决请求体的编码格式
struts.serve.static.browserCache=true
false表示不缓存,true浏览器会缓存静态内容, 产品环境设置true 开发环境false
struts.devMode = false
提供详细的报错页面,修改struts.xml不需要重启服务器。
Struts.xml文件的分离:
为什么需要action的分离?
给一个案例,涉及到管理员/老师/学生/ 每个角色都有对应的业务,如果我们把所有的业务请求的action全部配置在struts.xml文件中,文件会显得非常的臃肿,查找/修改起来 特别的麻烦,
在我么的开发中;会叫struts.xml文件主配置文件,里面会存放配置信息,参数,拦截器,
然后给每一个模块对应一个xml【struts-xxx.xml】,为了使主xml中的哦诶之可以再每个模块的xml中得到使用,我们会让每个模块的xml去继承主xml,
因为系统默认的加载struts.xml并不知道我们每一个模块配置的xml,所有我们必须在主xml中去引用每个模块的xml【include】
Action类的创建方式介绍:【三种方式】
1.创建一个pojo类:
Pojo:简单的Java对象,指是没有实现任何接口,没有继承任何类,没有任何业务
优点:无耦合
缺点:所有的工作都要自己来实现
2.创建一个类,实现Action接口 com.opensymphony.xwork2.Action
优点:耦合相对低 提供了5种视图的结果【5个静态的常量】
缺点:所有的工作都要自己来实现
public static final String SUCCESS = "success";
数据处理成功【成功页】
public static final String NONE = "none";
页面不跳转 跟return null效果一样
public static final String ERROR = "error";
数据处理发送错误【错误页】
public static final String INPUT = "input";
用户的输入数据有误,通常用于表单的数据校验
public static final String LOGIN = "login";
主要权限认证【登录】
3常见一个类;继承ActionSupport com.opensymphony.xwork2.ActionSupport
优点:表单验证,错误信息的设置,读取国际化配置信息,获取参数。…
缺点:高耦合
在开发中 第三种会使用的比较多。
关于action中方法的访问
1.可以通过设置method的值 来确定访问的action中的哪一个方法!
2.使用通配符来访问【推荐】
1在struts.xml文件中
<action name="*" class="web.acton.TeacherAction" method="{1}"> <result>/hello.jsp</result> </action> |
2.jsp页面
<a href="${pageContext.request.contextPath}/teacher/add">add......</a> <a href="${pageContext.request.contextPath}/teacher/update">update.....</a> <a href="${pageContext.request.contextPath}/teacher/delete">delete.....</a> <a href="${pageContext.request.contextPath}/teacher/find">find.....</a> |
3.action类
publicclass TeacherAction extends ActionSupport { public String add(){System.out.println("add"); returnSUCCESS;} public String delete(){ System.out.println("delete"); returnSUCCESS; } public String update(){System.out.println("update"); returnSUCCESS;} public String find(){ System.out.println("find"); returnSUCCESS;}} |
使用通配符的注意事项:
1.必须定义一个统一的命名规范
2.不介意使用过多的通配符,不方便阅读
3.动态的方法的调用【了解】
在struts.xml文件中
<action name="tea" class="web.acton.TeacherAction" > <result>/hello.jsp</result> </action> |
访问路径:http://localhost:8080/struts2-day1/teacher/tea!add
就访问到了teacherAction类中的add方法
用tea!add 就是方法的动态调用
注意:在struts2框架支持动态访问方法的调用,是因为在default.properties配置文件中设置了
<constant name="struts.enable.DynamicMethodInvocation" value="false"> </constant> |
如果设置为false就无法 实现动态访问
在struts2框架中获取servletAPI
对于struts2框架,不介意直接使用servletAPI
在struts2中回去servletAPI有三种方式:
1.通过ActionContext来获取【获取的并不是真正的servletAPI 而是一个Map集合】
1.获取ActionContext对象,
ActionContext是Action的上下文,struts2自定在其中保存了一些在Action执行过程中所需的对象,如:session,application….。struts2会更具每一个执行http请求的线程来创建对应的ActionContext,即一个线程一个唯一的ActionContext对象
代码↓
//获取ActionContext对象 ActionContext context=ActionContext.getContext(); //获取application Map<String, Object> application=context.getApplication(); application.put("aapp", "lsd"); System.out.println(application.get("app")); //获取session Map<String, Object> session=context.getSession(); session.put("ases", "lsx"); System.out.println(session.get("ses")); //获取request Map<String, Object> request=(Map<String, Object>) context.get("request"); request.put("areq", "lsn");
System.out.println(request.get("req")); |
2.注入方式获取
1.要求action类必须实现定义的接口
ServletAContextAware 注入:ServletContext对象
ServletRequestAware 注入:rqeust对象
ServletResponseAware 注入:response对象
SessionAware 注入:session对象
2.声明一个web对象 接口中的方法,将注入web对象 赋值给声明的web对象
//申明web对象 private Map<String, Object> session=null;
publicvoid setSession(Map<String, Object> session) { this.session=session;//将注入的web对象赋值给申明的web对象 } |
扩展:怎么注入进来的
是使用了struts2的一个拦截器完成的 【在struts-default.xml】
<interceptor name="servletConfig" class="org.apache.struts2. interceptor.ServletConfigInterceptor"/>
类中 intercept方法来实现注入功能的! |
3.通过ServletActionContext 获取 【真正的servletAPI】
ServletActionContext 继承ActionContext提供了与ServletAPI相关的对象访问功能! 且在servletActionContext中的方法都是Static 【直接点】
getReqeust();
getResponse();
getPageContext();
Result结果集
<result>标签
1.name
2.type 作用:跳转的方式
其,取值如下↓
在struts-default.xml文件中定义了type的可取值
<result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult"default="true"/>
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
<result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
<result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
<result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
<result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
<result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
<result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult"/>
</result-types>
必会:chain dispatcher redirect redirectAction stream
dispatcher 它代表的是请求转发/包含 也是默认值一般用于从action到页面
chain 它代表的是请求转发/包含 一般用于从action跳到另一个action
redirect 它表示的是重定向 一般用于从action到页面
redirectAction 它表示的是重定向 一般用于从action到另一个action
stream 代表的是服务器断返回的是一个流 一般用于下载
在struts2中获取请求参数
1.属性驱动
1.直接将action当做一个JavaBean,就可以得到请求参数
做法:在action中声明与请求参数名相同的属性名并提供get/set方法
优点:简单
缺点:需要单独定义很多的参数属性
问题:1这种方式,数据怎么封装的?
通过反射来实现的
2.action封装请求参数,会不会存在线程安全问题?
不会:因为每一次请求,都是一个新的action对象【回忆servlet】
2.在action中声明一个javaBean
做法:在action中申明一个javaBean 其属性与请求参数名对应
如:public Student stu; 并提供get/set方法
在页面上使用OGNL表达式来描述属性
如:<input type=”text” name=”stu.username” />
优点:简单,解决了第一种封装属性多的问题
缺点:在页面上使用了ognl表达式,页面不通用了【换了个框架就GG了】
问题:这种方式是怎么来分组的?
是通过struts2中interceptor 进行了数据的封装 【struts-default.xml】
<interceptorname="params" class="*"/>
2.模型驱动【在开发中应用的比较多的】
做法:
1.让action类实现ModelDriven
2.重写getModel方法
3.在action中实例化一个model对象,让getModel方法返回这个对象
implements ModelDriven<Student> //实现的接口
public Student stu=new Student(); //声明的model对象 //重写的方法 public Student getModel() { // TODO Auto-generated method stub returnstu; } |
优点:解决第一种/第二种的缺点
缺点:一次只能封装一个model对象
问题:这种方式数据是怎么来进行封装的?
是通过struts2中interceptor 进行了数据的封装 【struts-default.xml】
<interceptor name="modelDriven" class="*"/>
将请求的参数封装到集合【基于第二种方式的扩展】
1.将数据参数封装到list集合
页面:
<form action="${pageContext.request.contextPath}/student/regList" method="post"> 姓名<input type="text" name="stu[0].username" /><br> 密码<input type="password" name="stu[0].pwd" /><br> 年龄<input type="text" name="stu[0].age" /><br>
姓名<input type="text" name="stu[1].username" /><br> 密码<input type="password" name="stu[1].pwd" /><br> 年龄<input type="text" name="stu[1].age" /><br>
<input type="submit" value="注册"/><br> </form> |
Action类:
public List<Student> stu;//创建集合属性 并提供get/set方法 public String reg(){ for(Student st : stu){ System.out.println(st); } returnNONE;} |
2.将数据参数封装到Map集合
页面
<form action="${pageContext.request.contextPath}/student/regMap" method="post"> 姓名<input type="text" name="stu['one'].username" /><br> 密码<input type="password" name="stu['one'].pwd" /><br> 年龄<input type="text" name="stu['one'].age" /><br>
姓名<input type="text" name="stu['two'].username" /><br> 密码<input type="password" name="stu['two'].pwd" /><br> 年龄<input type="text" name="stu['two'].age" /><br>
<input type="submit" value="注册"/><br> </form> |
Action类
public Map<String,Student> stu; ////创建集合属性 并提供get/set方法
|
Struts2中的提供类型转换
【回忆servlet中获取请求参数 reqeust.getparameter(Stringname) 获取的都是String类型】
问题:谁给我们把数据类型进行了转换!
Struts2内部提供了大量的类型转换器,用来完成数据类型的转化的
Boolean/boolean/char/Character/int/Integer/long/Long/float/Float/double/Double/Date….
数组 可以将多个同名参数 转换到数组中
集合 可以将数据保存到list/Map集合中
例如:如期类型yyyy-MM-dd或yyyy年MM月dd日格式都可以转换成Date类型
但是yyyy/MM/dd就无法转换
【一旦方法无法满足我们现在的需求 我们就像对他进行重写】
Struts2中类型转换器根接口是:
com.opensymphony.xwork2.conversion.TypeConverter
你可以按F4 查看该接口下的所有实现类
Struts2数据校验
在开发中,请求参数是需要进行校验的
客户端校验-----js
服务器校验-----java代码
Struts2中提供的校验---服务器端的校验
分为两种
1.手动校验【自己编写代码】
要求:action类必须继承自ActionSupport,需要重写validate方法
【其实真正验证的方法在 Validateable接口中】
测试发现:action中重写的validate方法执行了,且在请求处理的方法之前执行的
内部:对于struts2提供的校验,通过拦截器实现的【struts-default.xml】
问题:在validate方法中怎么存储错误信息?
this.addFieldError("String name", "String message"); |
问题:在页面上如何获取错误信息【必须要导入struts2的标签】
<%@taglib prefix="s" uri="/struts-tags" %>
展示全部的错误信息<s:fielderror /> 展示对应name值的错误信息<s:fielderror fieldName="对应的name值" /> |
【进入action中不同的方法,发现每一个方法都会走validate】
问题:在同一个action类中肯定有许多的方法(add,delete,update,find,…)
那么有的方法需要进行参数的校验,而有的方法并不需要!
解决办法:创建一个名称叫:validate+请求处理方法名
如:请求处理方法叫add() 那么对应的校验方法就是validateAdd(){//验证}
2.框架校验【配置文件xml】
已经完成了校验的操作(做了很多的校验方法)
而我们使用的时候,只需要将他们调用就可以了【通过配置文件配置】
要求action类继承ActionSupport 无须重写validate方法
问题:配置文件怎么配置?
位置:配置文件要与action类在同一个包下
名称:action类名-validation.xml
约束:xwork-core-2.3.7.jar/xwork-validator-1.0.3.dtd
<!DOCTYPE validatorsPUBLIC
"-//ApacheStruts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
书写:
1.根节点validators
2.子元素 <field name="">
3.field 子元素
<field-validatortype="校验器"></field-validator>
问题:校验器有哪些?
com.opensymphony.xwork2.validator.validators/default.xml
如:<validator name="required" class="*"/>
……….
4.<field-validator >子元素
<param name=”参数名”>值</param>
5.<field-validator>子元素
<message>错误信息</message>
介绍:关于配置校验中的校验器:
required (必填校验器,要求被校验的属性值不能为null 但是可以是"") requiredstring (必填字符串校验器,要求被校验的属性值不能为null,并且长度大于0,默认情况下会对字符串去前后空格) stringlength (字符串长度校验器,要求被校验的属性值必须在指定的范围内,否则校验失败,minLength参数指定最小长度,maxLength参 数指定最大长度,trim参数指定校验field之前是否去除字符串前后的空格) regex (正则表达式校验器,检查被校验的属性值是否匹配一个正则表达式,expression参数指定正则表达式,caseSensitive参数指定进 行正则表达式匹配时,是否区分大小写,默认值为true) int(整数校验器,要求field的整数值必须在指定范围内,min指定最小值,max指定最大值) double(双精度浮点数校验器,要求field的双精度浮点数必须在指定范围内,min指定最小值,max指定最大值) fieldexpression (字段OGNL表达式校验器,要求field满足一个ognl表达式,expression参数指定ognl表达式,该逻辑表达式基于ValueStack 进行求值,返回true时校验通过,否则不通过) email(邮件地址校验器,要求如果被校验的属性值非空,则必须是合法的邮件地址) url(网址校验器,要求如果被校验的属性值非空,则必须是合法的url地址) |
问题:通过配置验证,怎么处理在同一个action中存在多个请求处理方法验证问题。
【同一个action 有的要做验证 有的不要】
解决办法:只需要修改xml的文件名即可
对某个action方法进行校验:action类名+action的name名+validation.xml
struts-2.3.15.1\docs\WW\docs\validation.html官方提供的参考代码
框架验证的方式与方法验证的方式是一样的 都是通过拦截器来做的
拦截器(interceptor)
介绍拦截器:
Struts2拦截器使用的是AOP思想
AOP的底层就是实现动态代理
【高波买包,高波在买包的时候被代购代理了,代购说别忙兄弟,我先帮你看看是不是假货,代购进行了显微镜的观察之后确定是否让你购买】
【发送一个action,被struts2内部代理了,strut2说先别往下执行,我先去看看你这个请求能不能走。Struts2把拦截器拿过来判断你能不能走】
Struts2中在struts.default.xml 文件中声明了所有的拦截器 在<interceptors>节点下
而struts2框架默认使用的是defaultStack这个拦截器栈
<default-interceptor-refname="defaultStack"/>
在这个拦截器栈中使用了18个拦截器也就是说 struts2框架默认情况下只加载18个拦截器 <interceptor-stackname="defaultStack"> 可以查看18个拦截器
Struts2中怎么使用拦截器
确定一个问题:使用拦截器可以做什么?
可以通过烂机器进行控制action的访问,如:验证用户是否登录,权限的操作!
1.创建一个类实现接口 com.opensymphony.xwork2.interceptor.Interceptor
在这个接口中有三个方法init destory intercept[真正做拦截的]
在intercept方法中如果向下继续执行 通过参数ActionInvocation invocation调用它的invoke()放行
2.在struts.xml中进行配置 刚刚自己定义的拦截器
<interceptors> <interceptor name="lsd" class="web.interceptor.Myinter"></interceptor> </interceptors> |
3.在action中指定使用哪些拦截器
<action name="add"> <interceptor-ref name="lsd"></interceptor-ref>//指定拦截器 <result>/index.jsp</result> </action> |
注意:只要显示声明使用拦截器,那么默认的拦截器将不再加载!
默认的拦截器不能使用了:会出现不能接受请求参数,无法类型转换,无法验证……….
如果想使用默认的拦截器我们可以在action中继续编写
<interceptor-refname="defaultStack"></interceptor-ref> 要拦截的action都要写 没灵性
定义拦截器栈进行配置
<interceptors> <!-- 自定义的拦截器 --> <interceptor name="lsd" class="web.interceptor.Myinter"></interceptor> <!-- 自定义的拦截器栈 --> <interceptor-stack name="mystack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="lsd"></interceptor-ref> </interceptor-stack> </interceptors>
<!-- 修改默认加载的拦截器栈 作用于所有的action --> <default-interceptor-ref name="mystack"/> |
案例:权限控制
当用户没有登录的时候我们进行业务操作【增删改查】是不行的必须登录
思路:1.登录成功将用户放入 session
2.每次请求拦截 判断 session中是否存在用户
3.有就放行 没有就滚混去【login.jsp】
开发过程中拦截器定义的三种方式
1.实现interceptor接口
Init(); 初始化拦截器
Destory() 销毁
Intercept(ActionInvocationinvocation) 实现拦截功能
2.继承AbstractInterceptor抽象类
它对Init(); Destory()方法进行了空实现
只需要实现 Intercept(ActionInvocation invocation) 实现拦截功能
3.继承MethodFilterInterceptor类
指定拦截的方法
指定不拦截的方法
关于拦截器与Fliter区别:
1.拦截器是局域java反射机制。而过滤器是基于函数回调。
2.过滤器依赖于servlet容器,拦截器不依赖
3.拦截器只对Action请求起作用,过滤器可以过滤所有
4.拦截器可以访问Action的上下文,过滤器不行
5.在Action的生命周期中 拦截器可以被调用多次,而过滤器只能在容器初始化时调用一次。
局部结果页面与全局结果页面
一般配置在总的struts.xml中
<package name="default" namespace="/" extends="struts-default"> <!—公共的页面-》 <global-results> <result name="cuole">/error.jsp</result> </global-results> </package> |