一、开发环境的搭建步骤:
1.导入jar包
2.在web.xml文件中配置filter过滤器
3.在类路径下加入struts.xml文件,导入模板文件(.dtd)
二、action和Action类
1.action:代表一个struts的请求
2.Action:能够处理struts请求的类
(1)必须有一个无参构造器
(2)每次Http都会请求创建一个新的Action实例,是线程安全的。
(3)具有与javaBean一样的属性和封装方法,封装方法名对应于jsp页面的输入,属性名对应jsp页面的输出内容,它的数据类型的转换时自动的。
(4)一个Action类可以有多个action方法,返回多个result对应的名字的字符串
三、Action类访问WEB资源
1.什么是WEB资源?
HttpServletRequest,HttpSession,ServletContext等原生的API。
2.为什么访问WEB资源
B/S的应用的Controller中必然需要访问WEB资源:向域中读写属性,读写Cookie,获取realPath等。。。
3.如何访问
(1)和Servlet API解耦的方式:只能访问有限的Servlet API对象,且只能访问其有限的方法(读取请求参数,读写域对象的属性,使session失效...)
①使用ActionContext,创建ActionContext对象
(ActionContext actionContext=ActionContext.getContext();)
--->获取ApplicationMap集合
Map<String,Object> applicationMap=actionContext.getApplication();
--->获取SessionMap集合
Map<String,Object> sessionMap=actionContext.getSession();
--->获取RequestMap集合
Map<String,Object> requestMap=(Map<String, Object>) actionContext.get("request");
--->获取Parameters集合
Map<String,Object> parameters=actionContext.getParameters();
注:parameters的返回值为String数组的类型,并且没有提供写入数据的功能,即使写入也读不出来。
②实现XxxAware接口
创建类实现XxxAware接口,创建私有属性变量,通过这些私有属性变量接收对应集合:
@Override
public void setParameters(Map<String, String[]> parametersMap) {
this.parametersMap=parametersMap;
}
@Override
public void setRequest(Map<String, Object> requestMap) {
this.requestMap=requestMap;
}
@Override
public void setSession(Map<String, Object> sessionMap) {
this.sessionMap=sessionMap;
}
@Override
public void setApplication(Map<String, Object> applicationMap) {
this.applicationMap=applicationMap;
}
private Map<String,Object> applicationMap;
private Map<String,Object> sessionMap;
private Map<String,Object> requestMap;
private Map<String,String[]> parametersMap;
--》ActionContext和实现XxxAware接口的方法比较:
当我们需要在一个类中创建多个action对应方法时,采用第二种会使得代码简洁,不用多次调用ActionContext去创建相应的对象。
--》session对应的Map实际上是SessionMap类型的!强转后若调用invalidate()方法可使其失效。。。
代码:
if(sessionMap instanceof SessionMap)
{
SessionMap sm=(SessionMap) sessionMap;
sm.invalidate();
System.out.println("sessionMap失效了....");
}
(2)和Servlet API耦合的方式:可以访问更多的Servlet API对象,且可以调用其原生的方法。
--》使用ServletActionContext
代码:
HttpServletRequest request=ServletActionContext.getRequest();
HttpSession session=ServletActionContext.getRequest().getSession();
ServletContext servletContext=ServletActionContext.getServletContext();
分别获取到HttpServletRequest 、HttpSession 、ServletContext 对象。
--》实现ServletXxxAware接口(implements ServletRequestAware,ServletContextAware,ServletResponseAware)
代码:
@Override
public void setServletResponse(HttpServletResponse response) {
this.response=response;
}
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext=servletContext;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request=request;
}
private HttpServletRequest request;
private ServletContext servletContext;
private HttpServletResponse response;
通过重写对应的set方法,获取所需要的HttpServletRequest 、ServletContext 、HttpServletResponse 对象。
四、关于struts2的请求扩展名
1.在struts2-core文件下寻找文件/org/apache/struts2/default.properties,寻找到struts.action.extension=action,,这里定义了以action和空结尾的请求扩展名均可以响应请求
2.在struts.xml文件中配置相关信息,如下:
<constant name="struts.action.extension" value="action,do,,"></constant>
定义了以action,do和空的请求扩展名结尾的请求均可以响应相应的action
五、ActionSupport
1.ActionSupport是默认的Action类:若某个action节点没有配置class属性,则ActionSupport数默认待执行的Action类,而该类里面的execute()方法极为要执行的方法。
2.ActionSupport实现了Action,Validateable,ValidationAware,TextProvider,LocaleProvider,Serializable接口,使得ActionSupport类功能更为强大。
六、Result
1.result是action的子节点
2.result代表action方法执行后可能会去的一个节点
3.一个action可以配置多个result子节点
4.result中有两个属性
①name:表示action中所代表的类可能去的方法的返回值,默认为"success"
②type:定义的属性类在struts2-core-2.3.15.3.jar/struts-default.xml目录下,默认为:dispatcher
常用的:
》dispatcher:转发。
》redirect:重定向
》redirectAction:重定向到一个Action
注:通过redirect的响应类型也可以便捷的实现redirectAction的功能。
<result type="redirectAction">
<param name="actionName">TestRedirectAction</param>
<param name="namespace">/Justin</param>
</result>
<package name="Justin" extends="struts-default">
<action name="TestRedirectAction">
<result>/pages/success.jsp</result>
</action>
</package>
OR
<result type="redirect">/Justin/TestRedirectAction</result>
》chain:转发到一个Action
注:不能通过type=dispatcher的方式转发到一个Action。
<result type="chain">
<param name="actionName">TestRedirectAction</param>
<param name="namespace">/Justin</param>
</result>
七、通配符映射匹配和动态方法调用
1.通配符映射,解决action个数偏多的问题
匹配原则:①若找到多个匹配,没有通配符的胜出
②被通配符匹配的URI的子串可以用{1},{2}...来引用
③{0}匹配整个URI
④如找到的通配符不只一个,按在配置文件中的先后顺序匹配
在struts2.5之前的版本
通配符{1}、{2}....只能放在result的name属性中,或者action的class类中,不可以放在method和和result的type属性中,否则会有There is no result type defined for type '{1}' mapped with name '{1}'或There is no result type defined for type '{1}' mapped with name 'redirect'. Did you mean '{1}'? - result的报错。
2.了解内容(暴露了URI的信息):
步骤
①打开允许动态方法调用的开关
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
②在URI的后面加上要调用的方法,即
/struts-app2/Product.action: Struts 调用 Product 类的 execute
/struts-app2/Product!save.action: Struts 调用 Product 类的 save() 方法
八、OGNL
1.值栈(ValueStack)
分为两个逻辑部分:
》Map栈:实际上是OgnlContext类型,是一个Map,也是对ActionContext的一个引用,里面的保存着着各种Map:
requestMap,sessionMap,applicationMap,parametersMap,attr。
》对象栈:实际上是CompoundRoot类型,是一个使用ArrayList定义的栈。里面保存着各种和当前Action实例相关的对象,是一个数据结构意义的栈。
2.Struts利用s:property标签和OGNL表达式来读取值栈中的属性值。
①值栈中的属性值:
》对于对象栈:对象栈中某一个对象的属性值
》Map栈:request,session,application的一个属性值 或 一个请求参数的值。
②读取对象栈中对象的属性:
》若想访问Object Stack里的某个对象的属性,可以使用一下几种形式之一:
object.propertyName 或者object["propertyName"]或object['propertyName']
》ObjectStack里的对象可以通过一个从零开始的下标来引用。ObjectStack里的栈顶对象可以用[0]来引用,它下面的那个对象可以用[1]引用。
》[n]的含义是从第n个开始搜索,而不只是只搜索第n个对象
》若从栈顶对象开始搜索,则可以省略下标部分
》结合s:property标签:<s:property value="[0].message"/>等价于<s:property value="message"/>
③默认情况下,Action对象会被Struts2自动的放到值栈的栈顶。
九、通用标签
1、在JSP页面上可以利用OGNL访问到值栈里的对象属性。若希望访问到值栈中的ContextMap中的数据,需要给OGNL表达式加上前缀#,若没有#,搜索将在ObjectStack里进行。
使用<s:property value=""/>获取对象,property标签有三个属性:
名字 | 类型 | 默认值 | 说明 |
default | String | 可选,如果value的值为null或者没有给定,显示该属性值 | |
escape | boolean | true | 可选,是否对HTML特殊字符进行转义 |
value | String | <来自栈顶对象> | 将要显示的值 |
示例:
java代码中定义:
ActionContext actionContext=ActionContext.getContext();
Map<String, Object> sessionMap=actionContext.getSession();
sessionMap.put("Test", "TestSession");
页面中OGNL:
<s:property value="#session.Test"/>
java代码中(getter和setter或者通过ValueStack对象栈把对象加到对象栈中):
private int productId;
private String productName;
private String productDesc;
private double productPrice;
页面中OGNL:
ProductId:<s:property value="productId"/>
ProductName:<s:property value="productName"/>
productDesc:<s:property value="productDesc"/>
productPrice:<s:property value="productPrice"/>
2.url标签
3.param标签:
4.set标签:
代码:
<s:set value="'productName'" name="productName" scope="session"></s:set>
ProductName:<s:property value="#session.productName"/>
5.push标签:
6.if、else和elseif
7.iterator标签(类似于c:forEach标签)用于完成遍历,每次遍历都会把元素依次压入和弹出ValueStack栈
<%
List<String> list=new ArrayList<String>();
list.add("开心");
list.add("麻花");
list.add("逗开花");
request.setAttribute("list", list);
%>
<s:iterator status=""></s:iterator>
<s:iterator value="#request.list" var="li" status="status">
index:${status.index}<s:property value="li"/>count:${status.count}<br>
</s:iterator>
7.sort标签:在jsp页面中就可以进行排序,而不用通过与数据库交互完成
创建类实现Comparator接口,重写compare接口(对字符串进行的排序):
public class ProductComparator implements java.util.Comparator<Product>{
@Override
public int compare(Product o1, Product o2) {
return o1.getProductName().compareTo(o2.getProductName());
}
}
在Jsp页面中获取comparator比较器,并对需要的集合进行排序:
Java代码:
ActionContext actionContext=ActionContext.getContext();
Map<String, Object> sessionMap=actionContext.getSession();
Product p1=new Product(2001,"AAA","nice",1200.0);
Product p2=new Product(2002,"BBB","nice",1200.0);
Product p3=new Product(2003,"CCC","nice",1200.0);
Product p4=new Product(2004,"DDD","nice",1200.0);
List<Product> products=new ArrayList<Product>();
products.add(p2);products.add(p3);products.add(p1);products.add(p4);
sessionMap.put("products", products);
Jsp页面中
<s:sort comparator="#request.comparator" source="#session.products" var="products1"></s:sort>
8.date标签
<s:date name="" format="" var=""/> name里指定Java中对应的Date对象,format指定格式,var表示另名为。
9.a标签:
<s:iterator value="#session.products" var="product">
<!-- 使用%{}对其进行强制OGNL解析 -->
<s:a href="getProductName?name=%{productName}">${productName}</s:a>
</s:iterator>
十、主题
主题: 为了让所有的 UI 标签能够产生同样的视觉效果而归集到一起的一组模板. 即风格相近的模板被打包为一个主题
simple: 把 UI 标签翻译成最简单的 HTML 对应元素, 而且会忽视行标属性
xhtml: xhtml 是默认的主题. 这个主题的模板通过使用一个布局表格提供了一种自动化的排版机制.
css_xhtml: 这个主题里的模板与 xhtml 主题里的模板很相似, 但它们将使用 css 来进行布局和排版
ajax: 这个主题里的模板以 xhtml 主题里德模板为基础, 但增加了一些 Ajax 功能.
修改主题:
通过 UI 标签的 theme 属性
在一个表单里, 若没有给出某个 UI 标签的 theme 属性, 它将使用这个表单的主题
在 page, request, session 或 application 中添加一个 theme 属性
修改 struts.properties 文件中的 struts.ui.theme 属性.
十一、拦截器
1)、arameters 拦截器将把表单字段映射到 ValueStack 栈的栈顶对象的各个属性中. 如果某个字段在模型里没有匹配的属性, Param 拦截器将尝试 ValueStack 栈中的下一个对象。
2)、当用户触发 add 请求时, ModelDriven 拦截器将调用 EmployeeAction 对象的 getModel() 方法, 并把返回的模型(Employee实例)压入到 ValueStack 栈.
接下来 Parameters 拦截器将把表单字段映射到 ValueStack 栈的栈顶对象的各个属性中. 因为此时 ValueStack 栈的栈顶元素是刚被压入的模型(Employee)对象, 所以该模型将被填充. 如果某个字段在模型里没有匹配的属性, Param 拦截器将尝试 ValueStack 栈中的下一个对象。
3)、paramsPrepareParamsStack拦截器