struts2总结
1、Struts2简单入门
1.1 struts2的概述
1.1.1 什么是Struts2?
★总结:struts2是一个基于MVC设计模式的WEB层框架。类似于servlet,但是相对于前端控制器等方面来说,两者有所区别。
1.1.2 使用Struts2的好处
1.web层的框架基于前端控制器的设计
2.struts的优势:
– 项目开源,使用及拓展方便,天生优势。
– 提供Exception处理机制
– 提供强大的、可以有效减页面代码的标签
1.2 struts2的入门使用
1.2.1 准备工作
1.下载struts2的开发环境
http://struts.apache.org/
2. 解压struts2的开发包解析文件用途
apps :Struts2提供的应用,war文件:web项目打成war包。直接放入到tomcat可以允许。
docs :Struts2的开发文档和API
lib :Strtus2框架的开发的jar包
src :Struts2的源码
1.2.2 创建Web项目,引入jar包
1.2.3 创建一个dome.jsp文件
<body>
<h1>Struts2入门</h1>
<h3><a href="${pageContext.request.contextPath }/hello.action">点击我执行</a></h3>
</body>
1.2.4 编写一个Action类并进行配置
public class HelloAction {
/**
* 提供一个方法,方法名是固定的,不能传任何参数
* @return
*/
public String execute() {
System.out.println("测试类执行了");
return "success";
}
}
对Action类配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- 配置Struts2常量,配置后在网页地址后必须加上.action才能访问 -->
<constant name="struts.action.extension" value="action"/>
<!-- struts为了管理配置,进行包管理 -->
<package name="demo" extends="struts-default" namespace="/">
<!-- 配置action -->
<action name="hello" class="com.test.HelloAction">
<!-- 配置跳转页面 -->
<result name="success">success.jsp</result>
</action>
</package>
</struts>
1.2.5 在web.xml文件中配置核心过滤器
<!-- 配置前端核心控制器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<!-- 修改常量(常在struts.xml中配置) -->
<!-- <init-param>
<param-name>struts.action.extension</param-name>
<param-value>action</param-value>
</init-param> -->
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
1.2.6 配置核心文件struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- 配置Struts2常量,配置后在网页地址后必须加上.action才能访问 -->
<constant name="struts.action.extension" value="action"></constant>
<!-- 引入各个模块配置文件-->
<include file="com/test/struts_demo1.xml"/>
</struts>
1.2.7 创建一个跳转success.jsp页面
<body>
<h3>跳转成功</h3>
</body>
1.3 struts2的执行流程
当用户访问某一个Action的时候,先经过核心过滤器,在核心过滤器中执行一组拦截器(这组拦截器实现部分功能),执行目标Action,根据Action的返回值,进行页面跳转。
1.4 struts2的常见配置
1.4.1 Action的配置
package标签称为包,这个包与Java中的包的概念不一致。包为了更好管理action的配置。
-
package标签的属性
name :包的名称,只有在一个项目中不重名即可。
extends :继承哪个包,通常值为struts-default。
namespace :名称空间,与标签中的name属性共同决定访问路径。
> 名称空间有三种写法:
----- 带名称的名称空间 :namespace=”/aaa”
----- 跟名称空间 :namespance=”/”
----- 默认名称空间 :namespace=””abstract :抽象的,用于其他包的继承。
action标签配置Action类。
- action标签的属性
name :与namespace共同决定访问路径
class :Action类的全路径
method :执行Action中的哪个方法的方法名,默认值execute
converter :用于设置类型转换器
1.4.2 常量的配置
在Struts2的框架中,提供了非常多的常量:(default.properties)
struts.i18n.encoding=UTF-8 ----Struts2中所有的post请求的中文乱码不用处理。
struts.action.extension=action ----Struts2请求的默认的扩展名。默认扩展名是.action或者什么都不写。
在Struts2中修改一些常量的值:
修改常量的值,可以有三个位置进行修正
1.web.xml中进行修改
<!-- 配置前端核心控制器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<!-- 修改常量(常在struts.xml中配置) -->
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>action</param-value>
</init-param>
</filter>
2.struts.properties中进行修改
struts.action.extension=action
3.在struts.xml中进行修改
<constant name="struts.action.extension" value="action"></constant>
1.4.3 分模块开发配置
在struts.xml文件中引入Action类的配置文件
<!-- 引入各个模块配置文件-->
<include file="com/test/struts_demo1.xml"/>
1.5 struts2的Action的编写
1.5.1 Action的编写的三种方式
1 Action类是一个POJO类
package com.test2;
/**
* Action编写方式1:action是一个pojo类
* @author 11312
*
*/
public class ActionDemo1 {
public String execute() {
System.out.println("Action编写方式1执行了");
return null;
}
}
2 Action类实现一个Action的接口
package com.test2;
import com.opensymphony.xwork2.Action;
/**
* action编写方式2:实现action接口
* @author 11312
*
*/
public class ActionDemo2 implements Action{
@Override
public String execute() throws Exception {
System.out.println("实现action接口的实现发方法实现了");
return NONE;
}
}
3 Action类继承ActionSupport类(常用)
package com.test2;
import com.opensymphony.xwork2.ActionSupport;
/**
* action编写方法3:继承ActionSupport类
* @author 11312
*
*/
public class ActionDemo3 extends ActionSupport{
public String execute() {
System.out.println("action编写方法3:继承ActionSupport类,实现了");
return NONE;
}
}
1.5.2 Action的访问
1 通过method设置访问
<!-- 通过方法的方式访问 -->
<action name="userFind" class="com.test3.UserAction" method="find"/>
<action name="userUpdate" class="com.test3.UserAction" method="update"/>
<action name="userSave" class="com.test3.UserAction" method="save"/>
<action name="userDelete" class="com.test3.UserAction" method="delete"/>
2通过通配符的方式进行配置(常用)
<!--通过通配符访问 -->
<action name="product_*" class="com.test3.ProductAction" method="{1}"/>
3 通过动态方法访问
<!-- 动态访问 -->
<action name="customer" class="com.test3.CustomerAction"/>
开启动态访问
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
三种方式的访问路径
<h1>Action的访问</h1>
<h3>通过method方式</h3>
<a href="${ pageContext.request.contextPath }/userFind.action">查询用户</a><br/>
<a href="${ pageContext.request.contextPath }/userUpdate.action">修改用户</a><br/>
<a href="${ pageContext.request.contextPath }/userDelete.action">删除用户</a><br/>
<a href="${ pageContext.request.contextPath }/userSave.action">保存用户</a><br/>
<h3>通过通配符的方式</h3>
<a href="${ pageContext.request.contextPath }/product_find.action">查询商品</a><br/>
<a href="${ pageContext.request.contextPath }/product_update.action">修改商品</a><br/>
<a href="${ pageContext.request.contextPath }/product_delete.action">删除商品</a><br/>
<a href="${ pageContext.request.contextPath }/product_save.action">保存商品</a><br/>
<h3>通过动态方法访问的方式</h3>
<a href="${ pageContext.request.contextPath }/customer!find.action">查询客户</a><br/>
<a href="${ pageContext.request.contextPath }/customer!update.action">修改客户</a><br/>
<a href="${ pageContext.request.contextPath }/customer!delete.action">删除客户</a><br/>
<a href="${ pageContext.request.contextPath }/customer!save.action">保存客户</a><br/>
2. struts2数据的封装和servlet的API的访问
2.1 Struts2的Servlet的API的访问
1.完全解耦合的方式:只能访问雨中的数据(**)
>编写jsp
<h1>struts2的servlet的API访问方式一:完全解耦合方式</h1>
<form action="${pageContext.request.contextPath }/ActionDemo1.action" method="post">
用户:<input type="text" name="name"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
>编写Action
/**
* 方式1:通过完全解耦合方式
* @author 11312
*
*/
public class ActionDemo1 extends ActionSupport{
@Override
public String execute() throws Exception {
//一、接收参数
//利用struts2中的actionContext对象
ActionContext context = ActionContext.getContext();
//调用actionContext中的方法
Map<String, Object> map = context.getParameters();//类似于request.getParameterMap();
//遍历对象中的数据
for (String key : map.keySet()) {
String[] values = (String[]) map.get(key);
System.out.println(key + " "+Arrays.toString(values));
}
//二、向域中对象存入数据
context.put("reqName", "reqValue");//相当于request.setAttribute();
context.getSession().put("sessName", "sessValue");//相当于session.setAttribute();
context.getApplication().put("appName", "appValue");//相当于application.setAttribute();
return "success";
}
}
***注意:这种方式只能获得代表request、session、application的数据的Map集合,不能操作这些对象的本身的方法。
2.原生的方式:既可以操作数据,也可以获得方法(**)
>jsp页面
<h1>struts2的servlet的API访问方式二:servlet的API的原生方式</h1>
<form action="${pageContext.request.contextPath }/ActionDemo2.action" method="post">
用户:<input type="text" name="name"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
>Action页面
package com.demo1;
import java.util.Arrays;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
/**
* 方式二:servlet原生API方式
*/
public class ActionDemo2 extends ActionSupport{
@Override
public String execute() throws Exception {
//一、接收数据
HttpServletRequest request = ServletActionContext.getRequest();
Map<String, String[]> map = request.getParameterMap();
for (String key : map.keySet()) {
String[] values = map.get(key);
System.out.println(key+" "+Arrays.toString(values));
}
//二、向域中存取数据
request.setAttribute("reqName", "reqValue");
request.getSession().setAttribute("sessName", "名字");
ServletActionContext.getServletContext().setAttribute("appName", "appValue");
return super.execute();
}
}
***注意:这种方式可以操作域对象的数据,同时也可以获得对象的方法
3.接口注入方式(了解)
编写jsp
<h1>struts2的servlet的API访问方式三:接口注入方式</h1>
<form action="${pageContext.request.contextPath }/ActionDemo3.action" method="post">
用户:<input type="text" name="name"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
编写Action
package com.demo1;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.util.ServletContextAware;
import com.opensymphony.xwork2.ActionSupport;
/**
* 方式三:使用接口注入方式
* @author 11312
*
*/
public class ActionDemo3 extends ActionSupport implements ServletRequestAware,ServletContextAware{
private HttpServletRequest request;
private ServletContext context;
@Override
public String execute() throws Exception {
//一、接收数据
//通过接口注入获得request对象
Map<String, String[]> map = request.getParameterMap();
for (String key : map.keySet()) {
String[] values = map.get(key);
System.out.println(key+" "+values);
}
//二、向域中存入数据
request.setAttribute("reqName", "reqValue");
request.getSession().setAttribute("sessName", "sessValue");
context.setAttribute("appName", "appvalue");
return super.execute();
}
public void setServletRequest(HttpServletRequest request) {
this.request=request;
}
@Override
public void setServletContext(ServletContext context) {
this.context = context;
}
}
Servlet是单例的,多个程序访问同一个Servlet只会创建一个Servlet的实例。Action是多例的,一次请求,创建一个Action的实例(不会出现线程安全的问题)。
2.2 Struts2的结果页面配置
1.结果页面分类:
全局结果页面:全局结果页面指的是,在包中配置一次,其他的在这个包中的所有的action只要返回了这个值,都可以跳转到这个页面。
针对这个包下的所有的action的配置都有效。
<package name="demo1" extends="struts-default" namespace="/">
<global-results>
<result name="success">/demo1/success.jsp</result>
</global-results>
<action name="ActionDemo1" class="com.demo1.ActionDemo1" >
</action>
<action name="ActionDemo2" class="com.demo1.ActionDemo2" >
</action>
<action name="ActionDemo3" class="com.demo1.ActionDemo3" >
</action>
</package>
局部结果页面:局部结果页面指的是,只能在当前的action中的配置有效。
针对当前的action有效
<package name="demo1" extends="struts-default" namespace="/">
<global-results>
<result name="success">/demo1/success.jsp</result>
</global-results>
<action name="ActionDemo1" class="com.demo1.ActionDemo1" >
<result name="success">/demo1/success.jsp</result>
</action>
<action name="ActionDemo2" class="com.demo1.ActionDemo2" >
</action>
<action name="ActionDemo3" class="com.demo1.ActionDemo3" >
</action>
</package>
2.result标签的配置(**)
- result标签用于配置页面的跳转。在result标签上有两个属性:
– name属性 :逻辑视图的名称。默认值:success
– type属性 :页面跳转的类型。值如下 :
-------- dispatcher :默认值,请求转发。(Action转发JSP)
-------- redirect :重定向。(Action重定向JSP)
-------- chain :转发。(Action转发Action)
-------- redirectAction :重定向。(Action重定向Action)
-------- stream :Struts2中提供文件下载的功能。
2.3 Struts2的数据封装
属性驱动
1.提供set方法的方式(少用)
2.页面提供OGNL表达式方式
Action类
jsp
3.模型驱动(重点)
Action类
jsp
模型驱动方式最常用的方式:
缺点:只能同时向一个对象中封装数据。
使用第二种可以向多个对象中同时封装数据:
2.4 Struts2的INPUT逻辑视图的配置
Action接口中提供了五个逻辑视图的名称:
SUCCESS
ERROR
LOGIN
INPUT :input在某些拦截器中会使用。
NONE
2.5 Struts2的复杂类型的数据封装(了解)
1.封装到List集合
jsp
Action
2.封装到Map集合
jsp
Action
3 OGNL&ValueStack
3.1OGNL表达式
3.1.1什么是OGN表达式?
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。可以代替EL表达式功能。
3.1.2 OGNL的作用
- 支持对象方法调用
- 支持类静态方法调用和值访问,表达式格式 @[类全名(包括包路径)]@[方法名|值名]
- 支持赋值操作和表达式串联
- 访问OGNL上下文和ActionContext
- 操作集合对象
3.1.3 OGNL三要素
1.表达式(做什么)
2.根对象(谁操作)
3.Context对象(在那里执行),在表达式访问Context中的对象,需要使用“#”号加上对象名
3.1.4 OGNL表达式使用入门
1.使用OGNL表达式准备工作
导包(struts2的包中包含OGNL的jar包)
2.编写demo1.jsp文件
需要映入taglib标签。struts2中只有一个标签就是<%@ taglib uri="/struts-tags" prefix=“s” %>
3.编写Action类
4.编写跳转后的页面(该页面中会使用OGNL表达式获取值栈中的值)
5.OGNL表达式可以在jsp,xml,properties等文件中使用
3.2 ValueStack(栈中的数据在任何地方都可取)
3.2.1 什么是值栈?
ValueStack实际上就是一个容器。它由Struts框架创建,当前端页面如jsp发送一个请求时,Struts的默认拦截器会将请求中的数据进行封装,并入ValueStack的栈顶。
valueStack其实类似一个数据中转站(Struts2的框架当中的数据就会都保存到了ValueStack中)。
- ValueStack接口,实现类OgnlValueStack对象
- ValueStack贯穿整个Action的生命周期。(Action对象一旦被创建,框架就会创建一个ValueStack对像)
3.2.2 值栈的内部结构
Value Stack主要有两个主要的区域:
- root区域:其实就是一个ArrayList。里面一般放对象。获取root的数据不需要加#号
- context区域:其实就是一个Map。里面放置的是web开发的常用的对象数据的引用。获取context数据需要加#号。
- request
- session
- application
- parameters
- attr
3.2.3 ActionContext和ValueStack的
servletContext:servlet 的上下文
ActionContext:Action的上下文
- 通过源码查看到:当请求过来的时候,执行过滤器中的doFilter方法,在这个方法中创建ActionContext 过程中,创建ValueStack对象,将ValueStack对象传递给ActionContext对象。所以可以通过ActionContext获取值栈对象
- ActionContext对象之所以能够访问Servlet的API(访问是与对象的数据)。因为在七内部有值栈可以引用。
3.2.4 获取值栈对象
1.通过ActionContext获取
//一种:通过ActionContext获取
ValueStack ValueStack1 = ActionContext.getContext().getValueStack();
2.通过request获取
//2通过request获取
ValueStack ValueStack1 = ServletActionContext.getContext().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
两者获取的是同一个对象,因为在ActionContext获取到数据的时候会传递给request一份。一个Action对象只会有一个ValueStack
3.2.5 操作值栈
1.在Action中提供属性的get方法的方式
– 默认的情况下,将Action对象压入值栈
Action类:
/**
* 操作值栈中的值:方式一:在Action对象中提供属性的get方法
* @author 11312
*
*/
public class ValueStackDemo1 extends ActionSupport{
//提供get方法
private User user;
public User getUser() {
return user;
}
@Override
public String execute() throws Exception {
//向ValueStack中存值
user = new User("望山","12354");
return SUCCESS;
}
}
jsp获取值栈数据:
<s:debug></s:debug>
<-- 方式一的获取:利用Action在值栈中的特性-->
<s:property value="user.username"/>
<s:property value="user.password"/>
2.使用ValueStack中本身的方法的方式(常用)
Action类:
/**
* 操作值栈中的值:方式二 :在Action对象中提供属性的get方法
* @author 11312
*
*/
public class ValueStackDemo2 extends ActionSupport{
@Override
public String execute() throws Exception {
//获取值栈对象
ValueStack valueStack = ActionContext.getContext().getValueStack();
//使用 push(Object obj); 或 set(String key,Object obj); 方式,向ValueStack中存值
User user = new User("望山","12354");
//现在user在栈顶
valueStack.push(user);
//现在name在栈顶
valueStack.set("name", "张");
return SUCCESS;
}
}
jsp获取值栈数据:
<!-- 方式二调用值栈方法实现 -->
<s:property value="username"/>
<s:property value="password"/>
<s:property value="name"/>
3.2.6 从值栈中获取数据
获取值栈中的数据就是在页面中使用OGNL表达式
- 获取root的数据,不需要加#号
- 获取context数据,需要加#号
1.获取一个对象数据
jsp获取值栈数据:
<!-- 获取一个对象数据 -->
<s:property value="username"/>
<s:property value="password"/>
2.获取一个集合数据
Action:
//向值栈中保存一个集合
List<User> list = new ArrayList<User>();
list.add(new User("aa","11"));
list.add(new User("bb","22"));
list.add(new User("cc","33"));
ActionContext.getContext().getValueStack().set.("list",list);
//想context中存
ServletActionContext.getRequest().setAttribute("name","wang1");
ServletActionContext.getRequest().getSession().setAttribute("name","wang2");
ServletActionContext.getServletContext().setAttribute("name","wang3");
jsp:
<!-- 获取集合数据 -->
<s:property value="list[0].username"/>
<s:property value="list[0].password"/>
<s:property value="list[1].username"/>
<s:property value="list[1].password"/>
<s:property value="list[2].username"/>
<s:property value="list[2].password"/>
<!-- 获取context中数据 -->
<s:property value="#request.name"/>
<s:property value="#session.name"/>
<s:property value="#application.name"/>
<!-- 接收参数 -->
<s:property value="#parameters.id"/>
3.2.7 EL能够访问值栈
原因: 因为Struts2的框架的底层对request.getAttribute(String name);
3.2.8 OGNL表达式特殊字符
1.#
获取context中的数据
<h1>#号用法</h1>
<h3>获取context的数据</h3>
<%
request.setAttribute("name", "wang");
%>
<s:property value="#request.name"/>
<h3>构建map结合</h3>
<s:iterator var="i" value="{'aa','bb','cc'}">
<s:property value="i"/>--<s:property value="#i"/><br>
</s:iterator>
<s:iterator value="{'aa':'11','bb':'21','cc':'31'}">
<s:property value="key"/>--<s:property value="value"/><br>
</s:iterator>
<s:radio list="{'男','女'}" name="gender" label="性别" />
2.%
强制解析OGNL()
<%
request.setAttribute("name", "wang");
%>
姓名:<s:textfield name="name" value="%{#request.name}"/>
3.$
在配置文件中使用OGNL
- 属性文件
- 国际化地方 配置.properties
- user.Welcome = 欢迎,${#session.user.username}
- xml文件
- 文件下载 filename=${文件名}
Struts2 的拦截器(*****)
拦截器的概述
1.什么是拦截器
- Interceptor:拦截器,起到拦截Action的作用。
Filter:过滤器,过滤从客户端向服务器发送的请求。
Interceptor:拦截器,拦截是客户端对Action的访问。更细粒度化的拦截。(拦截 Action中的具体的方法)。
-Struts2框架核心的功能都是依赖拦截器实现。
2.Struts2的执行流程
客户端向服务器发送一个Action的请求,执行核心过滤器(doFilter)方法。在这个方法中,调用executeAction()方法,在这个方法内部调用dispatcher.serviceAction();在这个方法内部创建一个Action代理,最终执行的是Action代理中的execute(),在代理中执行的execute方法中调用ActionInvocation的invoke方法。在这个方法内部递归执行一组拦截器(完成部分功能),如果没有下一个拦截器,就会执行目标Action,根据Action的返回的结果进行页面跳转。
拦截器入门
1.搭建Strtus2的环境
2.编写拦截器类
编写一个类实现Interceptor接口或者继承AbstractInterceptor类。
/**
* 自定义的拦截器一
* @author jt
*
*/
public class InterceptorDemo1 extends AbstractInterceptor{
@Override
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("InterceptorDemo1执行了...");
String obj = invocation.invoke();
System.out.println("InterceptorDemo1执行结束了...");
return obj;
}
}
3.对拦截器进行配置
定义拦截器进行配置
定义一个拦截器栈的方式
CRM的权限拦截器
实现用户登录的共能
1.创建表和实体
创建表
CREATE TABLE `sys_user` (
`user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`user_code` varchar(32) NOT NULL COMMENT '用户账号',
`user_name` varchar(64) NOT NULL COMMENT '用户名称',
`user_password` varchar(32) NOT NULL COMMENT '用户密码',
`user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
2.创建实体
3.提交数据到Action
4.Action–>Service–>DAO
编写Service
编写DAO
5.根据结果进行页面跳转
实现权限拦截器
1.编写权限拦截器
2.配置权限拦截器
Struts2的标签库
通用的标签
判断标签<s:if>、<s:elseif>、<s:esle>
<s:iterator>
其他常用的标签
<s:property/>
<s:debug/>
<s:date />----在页面上进行日期格式化。