目 录
struts是工作在web层的一个框架,基于拦截器机制,用来接收参数封装参数,调用service,处理参数,转发调转页面,
要使用它,首先要创建一个action类,action类实际上就是一个servlet,创建action要继承actionSupport类,同时action是单线程多实例的,其中默认的方法是execut(),也可以自己定义其他的方法,返回值是字符串格式,因为他要匹配配置文件中result标签的name属性。现在我们要配置他的环境配置文件,首先要在web.xml中配置struts的核心过滤器,StrutsPrepareAndExecuteFilter,之后我们要配置映射文件,struts.xml放在src目录下,格式固定,其中配置我们的访问路径和跳转路径和跳转方式等,package标签是包标签,action是类标签,result是跳转标签,
Struts
Struts简介
Struts是一个基于MVC的web框架,他的本质上就是一个servlet,以webwork为核心采用拦截器的机制来处理请求,工作在web层,用来接收参数,封装成对象,调用service,跳转页面。
配置环境---页面提交参数进行封装,或接受---调用api访问各个域---利用xml转发---
查询的api
解压目录\struts-2.3.24\docs\docs\tag-reference.html
Struts的简单实现
String的简单实现,建立项目导入jar包,创建类,创建前端页面,创建并配置xml,内容动作实现。
1. Struts中action类的创建方式
创建action有三种实现方式
就是默认的 public string execute(){}
success:成功之后的跳转
none:不跳转
error:错误之后的跳转
login:跳转到登录页面
input:我们不使用 struts 内部使用 struts执行中遇到错误后跳转到这里
-
他本身就实现了action接口
外加知识点
1.Action是多实例的。
2.Servlet是单例多线程的,第一次请求来的时候,通过init来创建servlet,之后调用service调用业务逻辑,以后每次请求来的话都会调用一次service,当servlet销毁或当服务器关闭时,调用方法关闭servlet
2. Struts的环境配置
-
2.1 web.xml的配置
使用Struts需要在web.xml中配置他的前端控制器,就是一个过滤器
配置前端控制器 <filter-class>里 需要用ctrl+shift+T 搜索类类名StrutsPrepareAndExecuteFilter粘贴全限定名
<filter>
<filter-name>Demo1</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Demo1</filter-name>
<url-pattern>/*</url-pattern>
//解决内部请求问题
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
-
2.2 struts.xml的配置
struts.xml放在src文件夹下,格式名称位置固定,用来配置action的映射关系,还有配置环境属性,环境常量值等,这里算是一个重要控制器,详情见下
-
2.2.1映射关系的配置
<packagename="Demo1"namespace="/"extends="struts-default">
<action name="Demo1"class="Test.Demo1" method="execute">
<result name="DEMO1" type="dispatcher">/1.jsp</result>
</action>
</package>
package标签:
name属性: | 全局唯一,作用给包起名,随意。 |
namespace属性: | 名称空间,请求路径的父路径,用来和action标签的name属性组成访问路径,现在写/ |
extends: | 继承某个包一般使用struts-default 默认拦截器 |
action标签
name属性: | 请求子路径名,和package组成项目的相对路径,一般写类名 |
class属性: | action类的全限定名 |
method: | 执行其中的哪个方法,默认execute |
name属性: | action类中方法返回的值。用来定位跳转哪个页面 |
标签体: | 跳转到哪里,跳转的页面的全限定名, |
type属性: | 配置跳转的方式 其中的值: 到jsp: dispatcher:默认值 请求转发到 jsp Redirect:重定向到jsp 到action: Chain:转发到action RedirectAction:重定向到action
Stream:文件下载 |
input视图: | struts内部发生错误的时候,返回一个input,只需要在action中提供一个input视图,type使用默认(转发),跳转路径:从那里来回那里去 <result name="input"></result> |
-
2.2.2包含其他xml的配置
<includefile="Test/struts_hello.xml"></include>
-
2.2.3常量的配置
例:配置后缀名
<constantname="struts.action.extension"value="abc,,"></constant>
常量的配置都在/org/apache/struts2/default.properties 里。用来配置一些响应的设置。
-
2.2.2全局的结果页面配置
package标签下有一个 global-result,他要写在result标签的前边
<global-results >
<resultname="success">/success.jsp</result>
<!--name不写的话默认是success -->
</global-results>
-
-
时机:
在filter初始化的时候完成的
-
加载顺序:(从上往下)
struts准备好的(我们不能修改)
default.properties (默认的配置)
struts-default.xml
struts-plugin.xml
-
我们自己编写
struts.xml
struts.properties
web.xml
注意:后面的配置文件中会把前面配置文件中的同名的配置覆盖
3. ServletApi的访问
用来接收接收参数,访问域,添加参数。一共有三种方式,详见下:
-
3.1 ☆通过ActionContext的Api方式访问
//获取ActionContext对象
ActionContext context=ActionContext.getContext();
//获取请求的参数的方法
Map<String, Object> map = context.getParameters();
//向request 域中添加参数
context.put("request", map);
//向session域里添加参数
context.getSession().put("session", "session");
//向servletContext域中添加参数
context.getApplication().put("servletContext", "servletContext");
-
3.2☆通过ServletActionContext的静态方法访问
//获取request对象
HttpServletRequest request = ServletActionContext.getRequest();
//获取参数
Map<String, String[]> map = request.getParameterMap();
//向域中放数据
request.setAttribute("", "");
request.getSession().setAttribute("", "");
ServletActionContext.getServletContext().setAttribute("", "");
-
3.3 通过接口注入访问
//实现ServletRequestAware,SessionAware,ServletContextAware接口
//实现接口的方法
//设置私有属性参数
private HttpServletRequest request;
private Map<String, Object> session;
private ServletContext application;
//获取请求的参数
Map<String, String[]> map = request.getParameterMap();
//向域中添加参数
request.setAttribute("", "");
session.put("", "");
application.setAttribute("", "");
4. 接收参数时封装成对象的方式☆☆☆
-
4.1 属性驱动的方式
-
方式一:
-
属性的set方式
在action类中添加和参数名一致的私有字段 ,并提供set方法 ,接收参数直接赋值到字段上
//设置私有字段接受参数
private String user;
private Integer password;
//设置set方法使其可以修改
publicvoid setUser(String user) {
this.user = user;
}
publicvoid setPassword(Integer password) {
this.password = password;
}
@Override
public String execute() throws Exception {
//可以直接调用参数
System.out.println(user+"---"+password);
returnNONE;
}
-
页面表达式方式(ognl表达式)
在action提供一个成员bean并提供get、set,在表单页面提交页面的提交名称是bean.属性,直接实现封装
//添加一个bean私有字段
private User user;
//提供get、set方法
public User getUser() {
-
returnuser;
}
publicvoid setUser(User user) {
this.user = user;
}
在页面上name是bean字段名.属性
<inputtype="text"name="user.user"/>
<inputtype="text"name="user.password"/>
@Override
public String execute() throws Exception {
//可直接调用封装完的bean
System.out.println(user);
returnNONE;
}
-
-
4.2 模型驱动的方式
1.action实现接口 ModelDriver
2.action中提供一个bean成员 初始化
3.实现接口中的方法(geyModel方法)
4.在getModel的方法中将bean对象返回
//实现ModelDriven接口
publicclassDemo6extends ActionSupport implements ModelDriven<User>
//创建一个实例化的私有字段
private User user=new User();
//重写接口方法 返回bean对象
@Override
public User getModel() {
returnuser;
}
@Override
public String execute() throws Exception {
//可直接调用
System.out.println(user);
returnNONE;
}
-
4.3 参数的批量封装方式
-
封装list
在action中提供list私有字段 提供get、set
在页面的提交名为 name="集合名称[index].user属性
private List<User> list;
-
public List<User> getList() {
returnlist;
}
publicvoid setList(List<User> list) {
this.list = list;
}
@Override
public String execute() throws Exception {
for (User user : list) {
System.out.println(user);
}
returnNONE;
}
页面:
<inputtype="text"name="list[0].password">
-
封装map
在action中提供map私有字段 提供get、set
在页面的提交名为 name="集合名称['键名'].user属性"
private Map<String, User> map;
public Map<String, User> getMap() {
returnmap;
}
publicvoid setMap(Map<String, User> map) {
this.map = map;
}
@Override
public String execute() throws Exception {
for (String key: map.keySet()) {
System.out.println(map.get(key));
}
returnsuper.execute();
}
页面:
<inputtype="text"name="map['d'].password">
-
OLGN表达式语言(主要用来在页面调取值栈的值)
-
OGNL简介:(struts2的默认表达式语言) OGNL的全称是对象图导航语言,是一种功能强大的开源表达式语言,可以通过表达式语法,存取java对象的任意值,调用java对象的方法,遍历整个对象的结构图,实现必要的类型转化。
-
作用: 调用对象的方法,访问类的静态属性和方法,访问ognlContext和actioncontext
-
OGNL的结构:
表达式
它表明了这次操作要 做什么
跟对象(root)
它表明了这次操作要 对谁操作
Context对象
它表明了这次操作要 在哪里操作
上下文环境Context是一个Map 类型的对象,在表达式中访问Context中的对象,需要使用"#对象名称"
-
OGNL在struts中的应用:
导入<%@taglibprefix="s"uri="/struts-tags"%>
调用对象方法:<s:propertyvalue="'world'.length()"/><br>
访问类的静态属性:<s:propertyvalue="@java.lang.Math@PI"/><br>
访问类静态方法:<s:propertyvalue="@java.lang.Math@random()"/>
-
值栈valueStack (域)
-
6.1 概述:
ValueStack 是 Struts 的一个接口,字面意义为值栈, OgnlValueStack 是 ValueStack 的实现类,客户端发起一个请求 struts2 架构会创建一个 action 实例同时创建一个 OgnlValueStack 值栈实例,OgnlValueStack 贯穿整个 Action 的生命周期, struts2 中使用 OGNL 将请求 Action 的参数封装为对象存储到值栈中,并通过 OGNL 表达式读取值栈中的对象属性值。
ValueStack实际上就是一个容器。它由Struts框架创建,当前端页面如jsp发送一个请求时,Struts的默认拦截器会将请求中的数据进行封装,并入ValueStack的栈顶。
其实可以认为struts框架的临时的数据中转站.当一次请求来的时候,struts框架会为每一个action创建一个值栈,值栈就将请求的参数放进来.然后我们操作action,若将数据放入域中的时候,struts框架还会将域中的数据放入值栈中.
-
6.2 值栈的内部结构:
两部分:
-
map(ognl上下文)(map就是context上下文对象,其中包含的各个域)
其中储存了一些引用:
parameters:请求参数
request:request域中的数据
session:session域中的数据
application:servletContext域中的数据
attr:该 Map 按如下顺序来检索某个属性: request, session, application
-
CompoundRoot:(root)(root存的基本都是对象,称之为对象栈/域,以后基本都是操作它,替换各个域)
存储了 action 实例,它作为 OgnlContext 的 Root 对象。CompoundRoot 继承 ArrayList 实现压栈和出栈功能, 拥有栈的特点,先进后出,后进先出,最后压进栈的数据在栈顶。 我们把它称为对象栈 。
-
6.3 valueStack和actionContext的关系
当我们访问一个action的时候,struts框架会为每一个action创建一个ActionContext,且为每一个action创建一个值栈,然后将值栈放入ActionContext中,ActionContext会将自己放入到当前线程中
-
6.4 获取值栈
★方式1:通过ActionContext对象来获取(因为值栈在ActionContext中)
ValueStack stack1 =ActionContext.getContext().getValueStack();
方式2:通过request域获取值栈
ServletActionContext.getRequest().getAttribute("struts.valueStack")
-
6.5 往值栈中放入数据
-
★往root中放入数据,
方式1:调用值栈的set和push方法
//获取值栈
-
ValueStack vs = ActionContext.getContext().getValueStack();
//创建数据
User user = new User();
user.setUsername("tom");
user.setPassword("123");
//通过push
vs.push(user);
//通过set方法:
本质上先创建一个map集合 ,将set中的key和value先放入map然
后将map放入root中
vs.set("sex", "男");
方式2:通过action的成员属性
因为action本身就在root中所以action的成员属性也就在root中了,提供get
-
往context中放入数据
put()
getsession.put()
getApplication().put()
-
6.6 从值栈中获取数据:★
-
通过ognl获取
获取root中
<s:property value="属性名"/>
获取context中 需要加#号
<s:property value="#..."/>
-
例:获取session中数据:<s:property value="#session.skey"/><br>
遍历root中的list 加上var的时候 会把var中的数据放入context
<s:iterator value="list" var="ss">
<s:property value="#ss"/>
</s:iterator>
-
通过EL表达式获取
${属性名}:在struts中查找: 从page,request,值栈中(root和context大map中),session,application中
${属性名} 相当于调用 pageContext.findAttribute(key)
-
特殊字符的使用
#号的使用
-
获取 context 的数据
<s:property value="#request.name"/>
-
用于构建一个 Map 集合
<s:radio list="#{'1':'男','2':'女'}" name="sex" label="性别"></s:radio>
%号的使用
%强制解析 OGNL 表达式
<s:textfield name="name" value="%{#request.name}"/>
%强制不解析 OGNL 表达式
<s:property value="%{'#request.name'}"/>
$号的使用
在配置文件中(xml和properites)获取值栈中的数据
-
拦截器(struts的核心)
-
7.1 过滤器简介
只能拦截action方法
多个拦截器称之为拦截器栈,(拦截器链)
主要的逻辑写在intercept方法中
-
7.2 过滤器和拦截器的区别
拦截器是基于java的反射机制的,而过滤器是基于回调函数的
拦截器不依赖于servlet容器,过滤器依赖于servlet容器
拦截器只能对action请求起作用,而过滤器几乎对所有请求都起作用
拦截器可以访问action上下文,值栈例的对象,而过滤器不能
在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
执行的顺序:过滤前—>拦截前—>action处理—>拦截后—>过滤后
-
7.3 Struts的执行流程
请求--->strutsPrepareAndExecuteFilter(doFilter)--->判断当次访问的路径是否是一个action(结果:若是,继续往核心走,结果:若不是,直接放行了)
若是action继续往核心走-->拿到访问的路径和action之后--生成action的代理对象--->action执行类-->会判断是否有拦截器(若有拦截器,依次执行)-->若没有需要执行的拦截器了放行到action-->action执行-->找到执行的result-->执行指定的资源--->倒序执行拦截器链-->执行过滤器的放行后的操作--->web服务器(生成响应信息)
-
7.4 自定义拦截器
-
7.4.1 编写一个类
实现Interceptor接口 或者继承某些实现类MethodFilterInteceptor 或者 AbstractInterceptor
-
7.4.1 编写配置文件(struts)
-
<packagename="action"namespace="/"extends="struts-default">
<!--注册单个拦截器 interceptors拦截器的容器-->
<!--
<interceptors>
注册单个拦截器 设置拦截器的名字 和拦截器的权限定名
<interceptor name="MyInterceptor1" class="web.interceptor.MyInterceptor1"></interceptor>
</interceptors>
<action name="action" class="web.action.action" >
在action中使用拦截器 直接使用拦截器的名字调用注册的拦截器
<interceptor-ref name="MyInterceptor1"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
-->
<!--注册拦截器栈 -->
<interceptors>
<!--注册每个拦截器 -->
<interceptorname="MyInterceptor1"class="web.interceptor.MyInterceptor1"></interceptor>
<interceptorname="MyInterceptor2"class="web.interceptor.MyInterceptor2"></interceptor>
<interceptorname="MyInterceptor3"class="web.interceptor.MyInterceptor3"></interceptor>
<!-- 注册拦截器栈 就是把上边注册的拦截器来了一个引用 方便后边调用 -->
<interceptor-stackname="MyInterceptor">
<interceptor-refname="MyInterceptor1"></interceptor-ref>
<interceptor-refname="MyInterceptor2"></interceptor-ref>
<interceptor-refname="MyInterceptor3"></interceptor-ref>
</interceptor-stack>
</interceptors>
<actionname="action"class="web.action.action">
<!--调用拦截器栈 -->
<interceptor-refname="MyInterceptor"></interceptor-ref>
</action>
</package>