Java - 框架之 Struts2
一. Package 标签
1. 标签属性:
name : 包的名称,只有在一个项目中不重名即可。
extends : 继承哪个包,默认为 struts-default。
namespace : 名称空间,与<action> 标签中的 name 属性决定访问路径
- 名称空间写法:
- 带名称的: namespace="/a"
- 不带名称: namespace="/"
- 默认空间: namespace=""
二. action 相关配置
1. action 标签配置 Action 类
2. action 标签的属性
- name : 与 namespace 共同决定访问路径。
- class : Action类的全路径。
- method : 执行Action中的哪个方法的方法名,默认 execute。
- converter : 用户设置类型转换器。
三. 分模块开发配置
include : 用于导入其它的 struts.xml 文件
<include file="xxx/struts.xml">
四. Action 三种编写方式:
1. Action 类是一个POJO的类 (简单的类-没有继承,接口...)
public class ActionDemo1{ public String execute(){ System.out.println("Action1"); return null; } }
2. 实现一个Action接口
public class ActionDemo2 implements Action{ @Override public String execute() throws Exception { System.out.println("Action2"); return null; } }
3. Action类 继承 ActionSupport 类 (常用) ******
public class ActionDemo3 extends ActionSupport{ @Override public String execute() throws Exception { System.out.println("Action3"); return None; } }
五. Action的三种访问方式
1. method 的配置 :
请求路径:
<a href="${ pageContext.request.contextPath }/userFind.action">跳转</a>
接收配置路径(struts.xml):
<package name="demo3" extends="struts-default" namespace="/"> <action name="userFind" class="com.xx.demo1.UserAction" method="find"></action> <action name="userUpdate" class="com.xx.demo1.UserAction" method="update"></action> <action name="userDelete" class="com.xx.demo1.UserAction" method="delete"></action> <action name="userSave" class="com.xx.demo1.UserAction" method="save"></action> </package>
类中:
public class UserAction extends ActionSupport{ public String find(){ return None; } ... }
2. 通配符(常用) ******
请求路径:
<a href="${ pageContext.request.contextPath }/product_find.action">跳转</a>
<action name="product_*" class="com.xxx.ProductAction" method="{1}"></action>
public class ProductAction extends ActionSupport{ public String find(){ return None; } ... }
3. 动态方法访问
<a href="${ pageContext.request.contextPath }/customer!find"></a>
# 开启动态方法访问
<constant name="struts.endable.DynamicMethodInvocation" value="true" /> <action name="customer" class="com.xxx.CustomerAction"></action>
类中:
public class CustomerAction extends ActionSupport{ public String find(){ return None; } ... }
注意: Servlet 是单例的,Action 是多例的 (不会出现线程安全问题)
六. 访问Servlet API 的三种方式 :
1. 完全解耦和的方式
注意:这种方式只能获取代表 request, session, application 的数据的 Map 集合, 不能操作这些对象本身的方法
# 编写 jsp
<form action="${ pageContext.request.contextPath }/requestDemo1.action" method="post"> 姓名:<input type="text" name="name"> 密码:<input type="password" name="pwd"> <input type="submit" value="go"> </form>
# 编写Action
public class RequestDemo1 extends ActionSupport{ @Override public String execute() throws Exception{ // 1. 接收参数 ActionContext context = ActionContext.getContext(); Map<String, Object> map = context.getParamters(); for(String key : map.KeySet()){ String[] values = (String[]) map.get(key); } // 2. 向域对象保存数据 context.put("k1","v1"); // 相当于 request.setAttribute(); context.getSession().put("k2","v2"); // 相当于 session.setAttribute(); context.getApplication().put("k3","v3"); // 相当于 application.setAttribute(); return SUCCESS; } }
2. 原生的方式访问
注意:可以操作域对象的数据,同时也可以获取对象的方法
# 编写 Action
public class RequestDemo1 extends ActionSupport{ @Override public String execute() throws Exception{ // 1. 接收参数 ActionContext context = ServletActionContext.getRequest(); Map<String, String[]> map = context.getParamterMap(); for(String key : map.KeySet()){ String[] values = map.get(key); } // 2. 向域对象保存数据 // 向 request 中保存数据 request.setAttribute("k1","v1"); // 向 session 中保存数据 request.getSession().setAttribute("k2","v2"); // 向 application 中保存数据 ServletActionContext.getServletContext().setAttribute("k3","v3"); return SUCCESS; } }
3. 接口注入方式
public class RequestDemo3 extends ActionSupport implements ServletRequestAware, ServletContextAware{ private HttpServletRequest request; private ServletContext context; @Override public String execute() throws Exception{ // 1. 接受参数 Map<String, String[] map = request.getParamterMap(); Map<String, String[]> map = context.getParamterMap(); for(String key : map.KeySet()){ String[] values = map.get(key); } // 2. 向域对象保存数据 // 向 request 中保存数据 request.setAttribute("k1","v1"); // 向 session 中保存数据 request.getSession().setAttribute("k2","v2"); // 向 application 中保存数据 context.setAttribute("k3","v3"); return super.execute(); } @Override public void setServletRequest(HttpServletRequest request){ this.request = request; } @Override public void setServletContext(ServletContext context){ this.context = context; } }
七. 页面显示配置
1. 全局/局部 结果页面
- 全局指的是包中一次配置,在这个包中所有 action 返回了这个值,就可以跳转这个页面
<global-results> <result name="success">/demo1/demo1.jsp</result> </global-results> <action name="requestDemo1" class="com.xx"> // 局部 <result name="success">/demo1/demo1.jsp</result> </action> // 全局 <action name="requestDemo2" class="com.xx"></action> <action name="requestDemo3" class="com.xx"></action>
2. result 标签的配置
- result 标签用于配置页面的跳转,在 result 标签上有两个属性:
name : 逻辑视图的名称,默认值 success。
type : 页面跳转的类型。
- dispatcher : 默认类型,请求转发 (Action 转发 JSP)
- redirect : 重定向。 (Action 重定向 JSP)
- chain : 转发。 (Action 转发 Action)
- redirectAction : 重定向。 (Action 重定向 Action)
- stream : Struts2 中提供文件下载的功能。
八. Struts2 的数据封装
1. 属性驱动:提供属性的 set 方法
# 编写 Action
public class UserAction1 extends ActionSupport { private String name; private String pwd; // 属性的 set 方法: public void setName(String name){ this.name=name; } public void setPwd(String pwd){ this.pwd=pwd; } @Override public String execute() thows Exception { // 接收数据 System.out.println(name); System.out.println(pwd); // 封装数据 User user = new User(); user.setName(user); user.setPwd(pwd); return NONE; } }
2. 属性驱动:页面中提供表达式
# 页面
<form> // Action 对象的属性名(user.跟set方法名一直) <input type="text" name="user.name"> </form>
# 编写 Action
public class UserAction1 extends ActionSupport { // 提供一个 User 对象 private User user; // 提供 user 的 get和set 方法: get必给 public User getUser(){ return user; } public void setUser(User user){ this.user = user; } @Override public String execute() throws Execption { System.out.println(user); return NONE; } }
3. 模型驱动 (常用)
# 编写 Action
// 手动提供实例对象 private User user = new User(); @Override public User getModel() { return user; } @Override public String execute() throws Exception { System.out.println(user); return NONE; }
九. Struts 的复杂类型数据封装
1. 封装数据到 List 集合中
# 编写 JSP
<input type="text" name="products[0].name"> <input type="text" name="products[0].price"> <input type="text" name="products[1].name"> <input type="text" name="products[2].price">
# 编写 Action
public class ProductAction1 extends ActionSupport{ private List<product> products; // 提供set 和 get 方法 public List<Product> setProducts(){ this.products = products; } public List<Product> getProducts(){ return products; } @Override public String execute() throws Exception{ for(Product product : products) { System.out.rpint(product); } return NONE; } }
2. 封装数据到 Map 集合中
# 编写 JSP
<input type="text" name="map["a"].name"> <input type="text" name="map["a"].price"> <input type="text" name="map["b"].name"> <input type="text" name="map["b"].price">
# 编写 Action
public class ProductAction1 extends ActionSupport{ private Map<String, Product> map; // 提供set 和 get 方法 public Map<String, Product> getMap(){ return map; } public void setMap<Map<String, Product> map){ this.map = map; } @Override public String execute() throws Exception{ for(Product key : map.KeySet()) { Product product = map.get(key); System.out.rpint(key+ "" +product); } return NONE; } }
十. OGNL
0. 值栈(ValueStack)
类似于一个数据中转站( Struts2 框架中的数据都存储在了 ValueStack 中 )
- ValueStack 接口,实现类 OgnlValueStack 对象。
- ValueStack 贯穿整个 Action 的生命周期 (Action一旦创建,框架就会创建一个 ValueStack 对象)。
// 值栈内部结构
Root : CompoundRoot, 就是一个 ArrayList;
Context : OgnlContext, 就是一个Map。
1. 调用对象的方法
<s:property value="'字符串'.length()" />
2. 访问对象的静态方法
// 静态方法访问在 Struts2 中默认是关闭的 <s:property value="@java.lang.Math@random()" /> // 开启静态方法访问权限 <constant name="struts.ongl.allowStaticMethodAccess" value="true" />
3. 操作值栈 - 存入数据
// 方式一:使用 Action 本身在值栈中的特性 public class ValueStackDemo3 extends ActionSupport{ private User user; // 需要提供 get 方法 public User getUser(){ return user; } @Override public String execute() throws Exception{ // ValueStack 中存值 user = new User("a","2"); return SUCCESS; } }
// 方式二:使用值栈中的方法实现 public class ValueStackDemo4 extends ActionSupport{ @Override public String execute() throws Exception{ ValueStack valueStack = ActionContext.getContext().getValueStack(); // 此时 User在栈顶的位置 User user = new User("b","3"); ValueStack.push(user); //创建一个Map集合,将Map加入栈中 ValueStack.set("name","zs"); return super.execute(); } }
3. 操作值栈 - 获取数据
public class ValueStackDemo5 extends ActionSupport{ @Override public String execute() throws Exception{ // 向值栈中保存一个对象 User user = new User("a","1"); ActionContext.getContext().getValueStack().push(user); // 向值栈中保存一个集合 List<User> list = new ArrayList<User>(); list.add(new User("b","1")); list.add(new User("c","1")); list.add(new User("d","1")); ActionContext.getContext().getValueStack().set("list", list); // 向 context 中存入数据 ServletActionContext.getRequest().setAttribute("name","q1"); ServletActionContext.getRequest().getSession.setAttribute("name","q2"); ServletActionContext.getServletContext().setAttribute("name","q3"); return super.execute(); } }
# XML 文件
# 获取一个对象的数据 <s:property value="username" /> <s:property value="password" /> # 获取集合中的数据 <s:property value="list[0].username" /> <s:property value="list[0].password" /> <s:property value="list[1].username" /> <s:property value="list[1].password" /> # 获取context中的数据 <s:property value="#request.name" /> <s:property value="#session.name" /> <s:property value="#application.name" /> <s:property value="#attr.name" /> // 接收参数: xxx?id=1 <s:property value="#paramters.id" />
十一. OGNL 符号
0. 获取 context 的数据:
<% request.setAttribute("name","q1"); %>
1. 使用 # 构建map 集合
<s:iterator var="entry" value="#{ 'a':'1', 'b':'2', 'c':'3' }" <s:property value="key" /> - <s:property value="value" /> <s:property value="#entry.key"> - <s:property value="#entry.value" /> </s:iterator> <s:radio list="#{'1':'男', '2':'女'}" name="sex" label="性别" />
2. 使用 %
<% request.setAttribute("name","q1"); %> // 强制解析为 OGNL <s:textfield name="name" value="%{#request.name}" /> // 强制不解析 OGNL <s:property value="%{'#request.name'}" />
3. 使用 $
// 属性文件
# 国际化
// XML文件 <param name="COntent-Disposition">filename=${ 文件名 }</param>
十二. Struts2 拦截器
1. 编写拦截器
public class InterceptorDemo1 extends AbstractInterceptor{ @Override public String intercept(ActionInvocation invocation) throws Exception{ System.out.prinln("拦截器"); return invocation.invoke(); } }
2. 拦截器配置
方式一:
// 方式一: 定义拦截器配置 <package name="demo1" extends"struts-default" namespace="/"> // 定义拦截器 <interceptors> <interceptor name="interceptorDemo1" class="com.xx.InterceptorDemo1" /> <interceptor name="interceptorDemo2" class="com.xx.InterceptorDemo2" /> </interceptors> <action name="actionDemo1" class="com.xxx.ActionDemo1"> <result>/demo1/demo1.jsp</result> // 引入拦截器 (注意:一旦引入自定义拦截器,默认拦截器就不会执行了) <interceptor-ref name="defaultStack" /> // 引入默认拦截器 <interceptor-ref name="interceptorDemo1" /> // 自定义拦截器 <interceptor-ref name="interceptorDemo2" /> // 自定义拦截器 </action> </package>
方式二:
// 方式二: 定义拦截器栈 <package name="demo1" extends"struts-default" namespace="/"> <interceptors> <interceptor name="interceptorDemo1" class="com.xx.InterceptorDemo1" /> <interceptor name="interceptorDemo2" class="com.xx.InterceptorDemo2" /> // 定义拦截器栈 <interceptor-stack name="myStack"> <interceptor-ref name="defaultStack" /> // 引入默认拦截器 <interceptor-ref name="interceptorDemo1" /> // 自定义拦截器 <interceptor-ref name="interceptorsDemo2" /> // 自定义拦截器 </interceptor-stack> </interceptors> <action name="actionDemo1" class="com.xxx.ActionDemo1"> <result>/demo1/demo1.jsp</result> // 引入拦截器栈 <interceptor-ref name="myStack" /> </action> </package>
十三. 通用标签库
1. 导入
<$@ taglib uri="/struts-tags" prefix="s" %>
2. 判断标签
<s:set var="i" value="1" scope="request" /> <s:if test="#request.i>3"> 大于3 </s:if> <s:elseif test="#request.i<3"> 小于3 </s:if> <s:else> 等于3 </s:if>
3. 循环标签
// 遍历 list <s:iterator var="i" value="{'a','b','c'}"> <s:property value="#i"> </s:iterator>s // 遍历 map <s:iterator var="entry" value="#{'aaa':'111', 'bbb':'222', 'ccc':'333'}"> <s:property value="#entry.key" /> -- <:property value="#entry.value" /> </s:iterator> // 遍历 数字 <s:iterator var="i" begin="1" end="10" step="1"> <s:property value="#i" /> </s:iterator>
十三. UI标签库
文档走起..
十四. Struts2 执行流程
请求-> 核心过滤器-> 创建 ActionProxy 方法, 在这个内部-> ActionInvocation.invoke() 在这个方法中递归执行一组拦截器
-> Action -> Result(最终返回一个字符) -> 拦截器之后的代码..