什么是MVC
M-Model 模型
模型的职责是负责业务逻辑。包括两部分:业务数据和业务处理逻辑
比如实体类、DAO、Service都属于模型层。
V-View视图
视图的职责是负责显示界面和用户交互
属于视图的类不包含业务逻辑和控制逻辑的JSP(如果在JSP页面中有<%%>就不能算是视图,或者JSP中有转发和重定向的控制也是不可以的)。
C-Controller控制器
控制器是模型层M和视图层V之间的桥梁,用于控制流程。
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
<package name="helloworld" extends="struts-default"
namespace="/"> package的名称不可以重复,主要用于继承,extends可以写成extends="struts-default,json-default,"
OGNL表达式
基本类型属性(包括String )
例如id ,name
数组和List
例如array[0], list[0]
Map
例如:map[‘key‘], map.key
基本运算
调用方法
调用静态方法
创建List ,Map
创建List:{1,2,3,4,5}
创建Map: #{‘key1‘:‘value1‘,‘key2‘:‘value2‘}
关联属性
empList[1].name
投影
过滤
Ognl.getValue("id",foo);//基本类型属性
Ognl.getValue("array[0]",foo);//数组,List属性
Ognl.getValue("list[1]",foo);
Ognl.getValue("map.one",foo);//Map属性
Ognl.getValue("map[two]",foo);
Ognl.getValue("id+100",foo);//基本运算
Ognl.getValue("\‘What is \‘+name",foo);
Ognl.getValue("id>500",foo);
Ognl.getValue("name.toUpperCase( )",foo)//调用方法
Ognl.getValue("list.size( )",foo);
Ognl.getValue("map[‘three‘].lastIndexOf(name)", foo);
Ognl.getValue("@[email protected](atty)", foo);//调用静态方法
Ognl,getValue("{1,2,3,4,5}",null);//创建List
Ognl.getValue("#{1:‘value1‘,2:‘value2‘ , 3:‘value3‘}",null);//创建Map对象
标准OGNL结构
root对象:Ognl操作的对象
context对象:就是一个Map,用于存放一个和整个系统都相关的公共数据
当有了Ognl引擎,我们就可以访问各种各样的root对象(比如Emp对象,Dept对象)在访问中有一些数据是每一次访问都需要用到的,这些数据就可以保存在context对象中。
XWork对Ognl的扩展
OGNL引擎
CompoundRoot对象:在XWork中,root对象被改为类似“栈”一样的存储空间,在该对象空间内可以存放多个root对象。
当取数据时符合“栈”的规则,如果OGNL表达式是“name”,在CompoundRoot从栈顶开始依次看是否有name属性。
ValueStack基本结构
Struts2将XWork对Ognl的扩展这一套机制封装起来,这个对象叫ValueStack。
Struts2在请求到来时,首先会创建一个ValueStack;
然后,把当前的Action对象放入栈顶(CompoundRoot);
Struts2会把ValueStack存放在request中,属性为“struts.valueStack”,
所以标签库可以访问到ValueStack
Struts2的许多标签就是通过访问ValueStack获取数据的:
<s;property value="ognl表达式"/>
<s:property/>取出ValueStack的栈顶
依次将集合中的对象至于栈顶
<s:iterator value="ognl...list">
<s:property value="name"/>
</s:iterator>
Struts2如何支持EL
Struts2通过StrutsRequestWrapper,重写了getAttribute方法。
<%@page pageEncoding = "utf-8"%>
<%taglib uri="/struts-tags" prefix="s"%>
<!--struts2通过标签库访问valueStack
<s:property value="ognl表达式"/>通过OGNL表达式访问ValueStack
把得到的数据显示出来
value属性:用户所提供德尔OGNL表达式
如果省略values属性,取出来的是CompoundRoot的栈顶
-->
<s:property value="name"/>
可调用方法
<s;property arry[1].toUpperCase()"/>
name属性存放于DebugAction中,DebugAction位于ValueStack中,ValueStack存放在request中,我们是不能直接找到name的,为何可以在页面使用EL表达式
因为Struts2支持EL表达式,它通过StrutsRequestWapper重写了getAttribute方法
Action基本原理
每次请求都会创建一个新的Action的实例
因为每次都对应一个单独的Action,所以不需要考虑线程安全问题。
Action对象将置于ValueStack的栈顶
Action的业务方法(默认为execute)根据输入算输出
在Action中如何访问Session&Application
1 使用ActionContext访问Session
ActionContext ctx = ActionContext.getContext( );//获取session的方法
Map<String,Object> session = ctx.getSession( );
session.put(‘user‘, user);
Map application = ctx.getApplication( );
session ,application将存放在ValueStack的Context中
<s:property value="#session.xxx"/>
<s:property value="#session[user].username"/>
<s:property value="#application.xxx"/>
不推荐使用ActionContext访问Session的方式,因为这种方式的侵入性较强。ActionContext是Struts2的API ,如果使用其他框架代替目前的Struts2框架,而我们实际项目中的Action的数量非常庞大,每个类都修改会很费劲
2 通过实现SessionAware接口访问session(更好)
新建BaseAction implements SessionAware
protected Map<String,Object> session;//为了让子类也能使用,所以访问控制为protected,还需提供setSession方法
所有需要session的XXXAction extends BaseAction
接口
org.apache.struts2.interceptor.ServletRequestAware
org.apache.struts2.interceptor.ServletResponseAware
org.apache.struts2.interceptor.SessionAware
org.apache.struts2.util.ServletContextAware
request 对应 ServletRequestAware
response对应 ServletResponseAware
session 对应 sessAware
application 对应 ServletContextAware
使用通配符配置Action
<action name="*_*_*" class="com.{1}Action" method="{2}">
<result name="success" >/WEB-INF/jsp/{3}.jsp</result>
</action>
给Action注入参数
<param name="pageSize">10</param>
在result的配置中使用OGNL表达式
<result name="success" type="dispatcher">
/WEB-INF/jsp/user.jsp?userId=${user.userId}
</result>
结果类型
<package name="core" extends="struts-defalut" namespace="/">
chain
dispatcher
freemarker
httpheader
redirect
redirectAction
stream
velocity
xslt
plainText
<package name="json" extends="json-defalut" namespace="/json">
需要导入json相关的jar包,json-defalut在struts-defalut的基础上增加了json结果类型
json
如果不写type默认为dispatcher
Struts2核心标签库
UI标签
form
textfield
password
submit
textarea
checkbox
radio
select
通用属性,需要主题为xhtml
label
labelposition
required
tooltip
tooltipIconPath
cssClass
cssStyle
name
value
<s:form></form>
theme
namespace
action
method
<s:textfield> <s:password>
maxLength
size
readonly
<s:textarea>
cols
rows
<s:checkbox>
<s:checkbox name="product" fieldValue="1"/>
<s:checkbox name="product" fieldValue="2"/>
<s:checkbox name="product" fieldValue="3"/>
动态获得
<s:iterator value="products">
<s:checkbox name="product" fieldValue="%{id}"/>
</s:iterator>
<s:radio>
<input type="radio" name="abc" value="1"/>One
<input type="radio" name="abc" value="2"/>Two
<input type="radio" name="abc" value="2"/>Three
<s:radio list="productOptions" label="Radio" name="abc"
listValue="label" listKey="value"/>
属性含义
name
label
list 需要迭代的集合 OGNL
listValue 作用于每一个选项的提示 OGNL
listKey 作用于每一个要提交的值OGNL
<s:select>
<select name="abc">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three></option>
</select>
Struts2标记
<s:select list="productOptions" label="Select" name="abc"
listValue="label" listKey="value"/>
属性含义
listValue 对应每一个Option的文本
listKey 对应每一个Option提交的值
headerValue 提示头的文字
headerKey 提示头对应的提交值
<s:action name="" executeResult="true false"/>
name 表示Action的名称
executeResult 值为true、false,true表示在页面显示action,false表示不显示。
<s:debug/>
<s:iterator value="userList" status="st"></s:iterator>
<s:debug/>
st对应的类是InteratorStatus
//count index first last even odd
count属性 从1开始计数
index属性 下标,从0开始计数
first属性,是否为第一个元素
modulus(n) count除以n后取余
<s:date name="date" format="yyyy年MM月dd日 E"/>
2015年02月03日 星期二
<s:url action="XXAction" var="urladdress"/>
用于产生一个地址,可以连接到某个action
var 自定义的变量名,将产生的地址放入ValueStack中。
<a href="${urladdress}">click me</a>
<s:url action="" var="" includeParams="get/none/all"/>
includeParams属性 值可取get/none/all
值get 仅get请求本页面的参数,加于本url之后
值none 表示没有此功能(默认)
值all 表示自动将请求页面的参数,加于本url之后
有时,我们希望valueStack中的某些数据能存放于4个范围内(pageContext、request、session、application),更加方便操作
<s:set var="" value = "" scope=""/>
从valueStack中取出数据,放入4个范围中
scope 指定4个范围之一(pageContext、request、session、application)
value Ognl表达式
<s:url action="XXAction" var="urladdress"/>
<a href="${urladdress}">click me</a>
<s:set var="url" value="#urladdress" scope="pageContext"/>
<a href="${url}">Click me</a>
<s:if test="userList.size()>5">
</s:if>
在页面可以直接使用Action中的含有get方法的字段。
拦截器
struts-default.xml
在<interceptors>标签中定义了许多拦截器
比如
<interceptor name="fileUpload">
封装了文件上传的功能,对应的类为
class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor-stack name="basicStack">
......
</interceptor-stack>
拦截器栈,在拦截器栈 中包含着若干拦截器的引用
如果“拦截器” 比作文件,那么“拦截器“相当于文件夹。
"拦截器栈"中,还可以有"拦截器栈",那么可以说"拦截器栈"也可以当做"拦截器"来用,相当于我们认为"文件夹"也是"文件"的一种。
总结一下
1)在package中定义拦截器
<interceptor name="" class="类完全限定名">
2)在package中定义拦截器栈
<interceptor-stack name="">
<interceptor-ref name="">
</interceptor-stack>
3)package中定义默认拦截器
<default-interceptor-ref name=""/>
4)action定义拦截器
<action name="" class="">
<!-- 表示访问该action前先调用这个拦截器-->
<interceptor-ref name="">
<param name=""></param>
</interceptor>
</action>
文件上传的拦截器配置
<interceptor-ref name="fileUpload">
<param name="maximumSize">102400</param>
</interceptor-ref>
<interceptor-ref name="basicStack"/> 这里用defalutStack吧?
上传文件如果大于102400字节,将报500错误
File file1
String file1FileName//固定格式
String file1ContentType
Struts2控制流程
请求到来
创建ValueStack(Action放栈顶),进行初始化
调用拦截器Interceptor,在拦截器中是可以访问ValueStack的
调用Action,执行execute( )方法
调用Result,Result负责把数据显示该用户
最后到页面,通过标签取出数据
自定义拦截器
public class SomeInterceptor implements Intercepor{
public void destroy(){ }
public void init( ){ }
public String intercept(ActionInvocation actionInvocation) throws Exception{
//获取ValueStack对象
ValueStack stack = actionInvocation.getStack( );
//获取和设置ValueStack中的值
stack.findValue("ognl表达式");
stack.setValue(arg0,arg1)
//调用Action 的2种方法,在调用拦截器的过程中,我们通过手动添加代码来调用Action
//第1种
String result = actionInvocation.invoke( );
//第2种
String result = actionInvocation.invokeActionOnly( );
return "two";
}
}
ActionInvocation类封装了Action调用过程中所需要的一切API,
actionInvocation.invoke( )和actionInvocation.invokeActionOnly( )的区别是什么?
如果拦截器SomeInterceptor中调用了actionInvocation.invoke( )方法,将调用Result对象,既然有了Reslut对象,execute 方法已经执行了返回结果
那么在SomeInterceptor中,返回值是什么都可以
String result = actionInvocation.invoke( );
return "abc";
所以,如果在拦截器中调用了actionInvocation.invoke( ),返回结果 return null即可。
如果拦截器SomeInterceptor中调用了actionInvocation.invokeActionOnly( )方法,将不会调用Result对象,这样一来,拦截器SomeInterceptor的intercept( ) 方法的返回值是必须写的。
String result = actionInvocation.invokeActionOnly( );
return "fail";
所以,要想让拦截器决定返回值是什么(返回到哪个页面),则调用actionInvocation.invokeActionOnly( )方法。
自定义拦截器步骤
1)实现Interceptor接口,实现intercept方法
2)获取ValueStack
ValueStack stack = actionInvocation.getStack( );
获取Servlet API
HttpServletRequest request = ServletActionContext.getRequest( );
HttpServletResponse response = ServletActionContext.getResponse( );
ServletContext application = ServletActionContext.getServletContext( );
调用Action
Action连Result一起调用
actionInvocation.invoke();
此后,intercept方法的返回值无意义
只调用Action,没有调用Result
actionInvocation.invokeActionOnly( );
此后,由intercept( )方法的返回值来决定执行哪个Result
设置参数