struts的入门:
1.下载struts
2.新建项目
导入jar包.
struts解压目录/apps/struts-blank.war
解压以后就有所须要的jar包
3.配置struts前端控制器
在web.xml中配置filter
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4.新建一个index.jsp
编写一个a标签
<a href="/s2_day01/hello">a_入门</a>
5.新建一个类(action)
一个普通的类
提供一个公共的有返回值的,返回值类型string,名称为execute的方法
6.建立配置文件
名称:struts.xml
位置:src目录
导入约束
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
package 标签:
name属性:起个包名,保证这个项目中惟一
extends属性:声明当前包继承于某个包 通常使用的默认值"struts-default"
namespace属性:和action标签的name属性组成访问路径的
action标签:建立路径和类的对应关系
name属性:和namespace属性组成访问路径的
class属性:自定义的action的全限定名
result标签:配置逻辑视图(action的返回值)和资源的跳转的
name属性:action中方法的返回值(逻辑视图)
7.跳转到1.jsp
a.让action中的方法有一个返回值 返回值任意 bb
b.在struts.xml配置返回值对应的页面 默认使用的是请求转发
struts的简易的执行流程(只是方便你们理解的,过程是不许确.在第四天的时候讲准确的执行流程)
参考excle
经过刚才的执行流程:
filter的init方法主要的做用之一:加载配置文件
filter的doFilter方法的做用,才是执行拦截器和action的
加载的配置文件有那些?
struts提供好的
default.properties :提供了一些常量
struts-default.xml :配置了默认的拦截器及跳转方式等操做
struts-plugin.xml :struts的一些插件的配置文件(如今暂时没有)
咱们本身编写的
★struts.xml :主要配置action和路径的对应关系等一系列主要信息
struts.properties:提供了一些常量(通常咱们不提供)
web.xml中过滤器的初始化参数
注意:
由于咱们配置加载是有顺序的,全部后面配置的同名配置会把以前的配置覆盖掉.
------------------------------------------
配置文件详解
常量的配置:
咱们能够在struts.xml,struts.properties,web.xml中配置
推荐在struts.xml
在struts.xml中经过 <constant name="" value=""/>
例如:
<!-- action的后缀名 -->
<constant name="struts.action.extension" value="abc"/>
了解:
在struts.properties配置常量
在src下本身建立一个struts.properties
struts.action.extension=abc
理解:
在web.xml中配置过滤器的初始化参数
<!-- 配置filter的初始化参数 -->
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>xyz</param-value>
</init-param>前端
常见的常量:
struts.action.extension:配置后缀名
struts.devMode:开发中模式 这个版本的默认值 false(若值为true的时候,配置文件修改后不须要重启服务器,可是有安全问题)
----------------------------
action的配置:
package标签:
name属性:起个包名,保证这个项目中惟一,方便让别人继承用的.
extends属性:声明当前包继承于某个包 通常使用咱们直接或者间接继承"struts-default" 就可使用这个包下的全部内容
namespace属性:和action标签的name属性组成访问路径的
写法:
不写 等价于 namespace=""
根路径 namespace="/"
带路径 namespace="/customer" ★
action标签:建立路径和类的对应关系
name属性:和namespace属性组成访问路径的 注意:版本不一样,写法不同.咱们的版本中不能出现 "/" (其实就是一个常量的配置问题:struts.enable.SlashesInActionNames)
class属性:自定义的action的全限定名
method属性:配置action要执行的方法名称 默认值:execute
-------------------------------
include的配置
将其余的自定义struts的配置文件包含到struts.xml中.方便团队开发维护.
例如:
<include file="cn/itcast/a_hello/struts_hello.xml"></include>
--------------------------------------------------
action的编写方式
(了解)方式1:普通的类
(理解)方式2:实现Action接口
提供了5个字符串常量(逻辑视图)
success:成功访问的时候
error:错误的时候
login:往登陆页走的时候
none:页面不跳转
input:struts内部使用,当struts内部发生错误的时候,返回input
★方式3:继承ActionSupport类
action的访问方式
(了解)方式1:经过设置method访问
★★方式2:通配符配置
<!-- 通配符配置 -->
<action name="demo2_*" class="cn.itcast.c_access.Demo2AccessAction" method="{1}"></action>
变态的写法:
类名:ProductAction,OrderAction
方法名:save ,update
访问路径:
/ProductAction_save.action
/OrderAction_save.action
配置文件:
<action name="*_*" class="cn.itcast.c_access.{1}" method="{2}"></action>
★方式3:动态方法执行方式
前提:
开启容许动态方法执行
在struts.xml中配置一个常量
struts.enable.DynamicMethodInvocation=true
路径写法:
/user!方法名.action
配置文件
<action name="user" class="cn.itcast.c_access.UserAction"></action>
案例分析:
看图
技术点:
获取request对象
ServletActionContext.getRequest();
-----------------------------------------
struts入门
获取请求
页面跳转
入门案例:
导入jar包:解压目录下/apps/struts-blank.war
编写action类:
方式3:继承ActionSupport类
配置文件:
web.xml中配置核心过滤器 StrutsPrepareAndExecuteFilter
在src下本身建立一个struts.xml
导入约束
package标签
name属性
namespace属性
extends属性
action标签
name属性
class属性
method属性
result标签
name属性
标签体:服务器内部路径
----------------------
简易执行流程
配置文件及其加载顺序
struts提供好的
咱们本身编写的
注意:
后面的同名配置会覆盖以前的配置
配置文件中:
常量的配置
在struts.xml经过constant标签配置
include配置
包含其余的struts文件.团队开发中使用
action的访问方式
方式2:通配符配置
方式3:动态方法执行方式
*-*-*--*-*-*-*-*-*-*-**-*-*-*-*--*-*-*-*-*-*-*-*-*-java
访问servlet的api方式
★方式1:经过ServletActionContext的静态方法访问
getRequest()
getResponse()
getServletContext()
(了解)方式2:经过接口注入的方式
咱们须要让本身的action实现如下几个接口
ServletRequestAware
ServletResponseAware
SessionAware
ServletContextAwareweb
(理解)方式3:经过ActionContext的方法访问
获取ActionContext对象(当成工具类使用)
ActionContext context = ActionContext.getContext();
获取请求参数
Map<String , Object > context.getParameters()
域操做:
(至关于)往request域中放入数据:put(String key,Object Value)
往session域中放入数据: getSession().put(String key,Object Value)
往application域中放入数据: getApplication().put(String key,Object Value)
★action是多实例的
result配置:
action标签下有result标签:用来配置页面跳转
name属性:逻辑视图的名称(方法的返回值) 默认值:success
type属性:跳转的方式
经常使用值:
dispatcher 转发到jsp上 默认值
redirect 重定向到jsp上
chain 转发到action上
redirectAction 重定向到action上
扩展:
stream 文件下载
标签体:跳转的路径的
跳转到jsp上 写jsp的内部路径
跳转到当前包下的action上 直接写action的名字
配置方式分类:
全局结果页面配置:供当前包下的全部action共享.
经过package标签下的子标签
global-results
局部结果页面配置:仅当前action可使用的
就是在action下配置result标签
封装数据
★方式1:属性驱动set方式(适用参数个数少,例如分页)
表单以前怎么写 如今还怎么写
在action中须要提供一些属性的set方法
★方式2:属性驱动页面表达式方式(ognl表达式,封装到多个对象中)
修改表单里面的每一个子标签的name属性 javabean对象名称.属性名称
在action中提供一个javabean对象且提供他的get和set方法
例如:
action中提供一个成员属性 private User uu; //提供get和set方法
标签子标签中name属性写法 <input type="text" name="uu.username"/>
★★方式3:模型驱动(ModelDriven)
页面写法仍是之前的写法
1.要求action实现ModelDriven接口
2.在action要提供一个javabean的成员字段且必须初始化
3.重写接口中getModel的方法
4.经过getModel方法将javabean的成员字段返回
批量封装
大前提:
须要在action提供给一个集合(list仍是map),提供集合的set和get方法
批量封装成list
页面表达式写法:
name="集合属性名称[index].bean属性名"
例如: name="ll[1].username"
批量封装成map
页面表达式写法:
name="集合属性名称['键名'].bean属性名"
例如:
name="mm['aa'].age"
搭建环境:
导入jar包
hibernate
驱动
日志
struts
导入页面
配置文件:
hibernate.cfg.xml
log4j.properties
struts.xml
web.xml中配置核心过滤器
建立持久化类和映射文件(复制)
建立action,service,dao
配置action
展现全部的客户
客户保存
步骤:
1.修改menu.htm中 "新增客户"的链接
/crm_/jsp/customer/add.jsp(不推荐)
可使用转发的方式访问jsp
/crm/customer_addUI.action
2.在action中提供一个addUI的方法
直接转发到jsp便可
3.修改add.jsp中表单信息
action属性
子标签的name属性
4.在action提供一个保存的方法 save方法
模型驱动
在save方法中获取封装后的对象
调用service完成保存操做
重定向到customer_findAll.actionapache
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-编程
ognl表达式:咱们主要用它在页面上来获取值栈的数据.el也能够获取值栈中的数据
值栈:ValueStack 自己就是一个容器(一系列集合),存放请求参数和各大域中的数据及其它的数据
ognl表达式:
对象图导航语言,是一种表达式语言
struts2的默认表达式语言是ognl
主要做用:
调用对象的方法
访问类的静态属性
访问类的静态方法
★获取值栈中的数据.
....
演示一下在jsp中使用ognl表达式(了解)
调用对象的方法:获取 字符串"hello"的长度 <s:property value="'hello'.length()"/><br>
<!-- 格式:@类的全限定名@属性名 -->
访问类中的静态属性:获取 π 的值 <s:property value="@java.lang.Math@PI"/><br>
<!--
格式:@类的全限定名@方法名()
注意:配置容许ognl访问静态方法 struts.ognl.allowStaticMethodAccess
-->
访问类中的静态方法:获取随机数 <s:property value="@java.lang.Math@random()"/><br>
值栈:
ValueStack
百度百科上:
ValueStack实际上就是一个容器。它由Struts框架建立,当前端页面如jsp发送一个请求时,
Struts的默认拦截器会将请求中的数据进行封装,并放入ValueStack
个人理解:
我把他称之为 struts的临时数据中转站.当请求来的时候,struts框架会为每个请求建立一个值栈.
struts会将请求中的数据及其余域中的数据封装到值栈中.当请求结束的时候,值栈也就销毁了.
以前获取参数的时候,找request对象,今天咱们经过值栈获取请求参数
以前获取域中的数据的时候,找各个域,今天咱们经过值栈获取各个域中的数据
以前咱们往域中放入数据的时候,找各个域.今天咱们也能够经过值栈放到各个域中数据.
ValueStack是一个接口,咱们使用的是实现类 OgnlValueStack,ValueStack是贯穿action的生命周期的.
值栈的结构
一系列集合,主要分红两部分
root 本质上就是一个list集合(咱们之后主要往root中存放数据)
context 本质上就是一个map集合 map<String ,Object >
主要存放的数据有如下内容
key value
request request域中的数据(map)
session session域中的数据(map) ★
application application域中的数据(map) ★
attr 四个域中的数据按顺序又存放了一遍. map
parameters 请求的参数 (map)
root root对象(地址值)
自定义key 自定义value 至关于往request中存放数据
ActionContext和值栈的关系.
actioncontext叫作action的上下文.咱们就把它当成是一个工具类
源码描述:
当一次请求来的时候,struts框架会为每个请求建立一个值栈.还会建立一个ActionContext对象.
将全部的数据放入值栈的context区域,将值栈再放入ActionContext中
继续将ActionContext绑定到当前线程中.(ThreadLocal) 上面的操做都是struts帮咱们完成的
最后,咱们获取数据或者操做数据的地方 在action中或者jsp中.如何在action中获取ActionContext对象.
由于一次请求对应的是一个线程.只须要经过获取当前线程绑定的actioncontext对象便可.就是咱们以前学习的
ActionContext.getContext();
ActionContext中有全部的数据(请求参数及各个域中的数据).
咱们把值栈中的Context赋值给了ActionContext中的context集合.以后获取域中数据或请求参数的时候直接找actoincontext中的context集合便可.
获取值栈
ActionContext.getContext().getValueStack();
往值栈中存放数据(通常是在action存放)
往root中存数据(★★)
方式1:经过值栈的api的api
push(Object obj)
set(String key,Object value):底层是先建立一个map集合,而后将数据放入map集合中,而后再将map放入root中
结论:
push对象,set集合.
方式2:经过Action的成员属性
由于action自己就放在root中.
往context中存数据
注意:
操做值栈的Context 只须要操做ActionContext中的context
往request域中放入数据 至关于 put(String,Object)
往session域中放入数据 getSession().put(String,Object)
往application域中放入数据 getApplication().put(String,Object)
struts往值栈的context中放入数据的时候,给一些域起个两个key,一个是长名字的key,一个是短名字的key.
长名字的key是struts底层使用的.为了方便咱们获取数据另外起个短名字的key
从值栈中获取数据(通常是在jsp上获取)
获取root中的数据
经过 <s:property value="ognl表达式"/> 获取数据
ognl直接写对象的属性名称或者写key名称
获取context中的数据
经过 <s:property value="ognl表达式"/> 获取数据
ognl #key名
el获取context中的数据,也能够获取root中的数据.
${username}
以前在web这样写的时候,依次从小到大四个域中查询指定名称的值.底层调用的是pageContext中findAttribute(key)的方法
findAttribute方法的底层:
先调用pageContext.getAttribute(key)
判断是否能获取到值.
若获取到了,直接返回,且结束该次查找.
若没有获取到,调用request.getAttribute(key)
判断是否能获取到值.
若获取到了,直接返回,且结束该次查找.
若没有获取到,调用session.getAttribute(key)
判断是否能获取到值.
若获取到了,直接返回,且结束该次查找.
若没有获取到,调用application.getAttribute(key)
判断是否能获取到值.
若获取到了,直接返回,且结束该次查找.
若没有获取到,返回null
咱们的${username}对findAttribute方法返回值进行了改造,若返回值为null则返回一个""
${}或者ognl方式不存在空指针异常和角标越界异常.
今天咱们使用el的时候也能够获取到root中的数据,这是怎么作的呢?
获取的顺序:
pageContext--request--root--context(大map)--session--application
就是struts对request.getAttribute方法进行了加强
使用的是装饰者模式对request进行了包装
先调用request原来的方法,看看是否有返回值,若没有返回值调用valuestack对象的findValue(key)
findValue方法是先找root中数据,root中没有再去找context(大map)中的数据.
从而也就能解释下put到context中的数据 至关于放入request域中了
<s:property/>标签的底层也是java代码,代码其实也是调用了findValue(key)
例如:
获取put到context中的数据:<s:property value="#rkey"/><br/>
获取put到context中的数据:<s:property value="#request.rkey"/><br/>
获取put到context中的数据:<s:property value="rkey"/><br/>
★最终的结论
使用ognl获取root中的数据 <s:property value="属性名称或者key的名称"/>
使用ognl获取context中的数据 <s:property value="#key名称"/>
最重要的一句话 使用el也能够获取值栈中的数据.
ognl的特殊符号使用
#
★主要做用:
获取context中的数据
手动构建一个map集合 在struts的form标签中使用
%
主要做用:
强制计算ognl表达式
struts标签的文本框:<s:textfield value="%{#request.username}" name=""></s:textfield>
$
主要做用:
在struts的配置文件(xml或者properties)中获取值栈中的数据.
例如在文件下载时使用.
<result name="aa" type="stream">
<param name="content-disposition">attachment;filename=${filename}</param>
</result>
★循环:
<s:iterator value="{'男','女'}" var="s">
<s:property value="#s"/>
</s:iterator>
<s:iterator value="{'男','女'}">
<s:property/>
</s:iterator>
s:iterator有begin,end,step,var,value,status(至关于c标签中varStatus)
★判断:
<s:if test=""></s:if>
<s:elseif test=""></s:elseif>
<s:else test=""></s:else>
使用值栈和ognl替代以前的request域和el|jstl
以前查询客户list放入request域中,今天放入值栈(root)中
以前在list.jsp遍历的时候使用的el|jstl,今天咱们可使用ognl和struts标签配置 api
*-*-*-**-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*浏览器
struts的注解开发
拦截器:只能拦截对action的访问,struts的核心.
和咱们以前过滤器很类似
filter:能过滤全部的请求和响应
拦截器:只能拦截对action的访问
其实就是在action(方法)执行以前或者以后,加入一些可重用的代码,也能够阻止方法的执行.(aop:面向切面编程)
动态代理
一次请求有可能匹配到多个过滤器,咱们把这些过滤器称之为过滤器链 FilterChain
访问某一个方法的时候也会匹配到多个拦截器,咱们把这些拦截器称之为拦截器链.在struts中通常称之为拦截器栈
Interceptor:接口
intercept(ActionInvocation invocation) :执行拦截操做的----相似于filter的doFilter
invocation.invoke();至关于放行操做 ---- 相似于 chain.doFilter(..)
----------------------------------------
struts的简易执行流程(不许确)
struts的较为详细执行流程(准确)
请求-->核心过滤器-->doFilter方法中作了一系列操做(设置编码,建立actioncontext和值栈,包装request),而后判断
这次请求访问的是不是actoin
若不是action:放行
如果action:继续往struts的核心中走
---------------------------------------------------------
是action:继续往struts的核心中走-->建立一个action的代理对象-->将执行权交个ActionInvocation对象,将这次访问全部执行
的拦截器放入一个集合中,顺序执行这些拦截器-->执行目标action中方法-->根据result再跳转到相应的资源上-->倒序执行这些
拦截器-->走核心过滤器放行方法以后的操做,到达咱们的服务器-->服务器拿到数据以后,解析成响应行,头,体,返回给浏览器
自定义拦截器:
1.编写一个拦截器(实现Interceptor或者继承Interceptor的实现类:例如,MethodFilterInterceptor,这个拦截器能够指定对某些方法拦截,也能够指定对某些方法进行忽略)
2.配置拦截器
方式1:
a.注册拦截器
b.绑定路径(在action中使用拦截器)
方式2:
a.注册拦截器栈
b.绑定路径(在action中使用拦截器栈)
例如:
方式1:
--<package name="demo1" namespace="/" extends="struts-default">
-- <!-- 配置拦截器 -->
-- <interceptors>
-- <!-- 1.注册拦截器 -->
-- <interceptor name="Demo1MyInterceptor" class="cn.itcast.interceptor.a_hello.Demo1MyInterceptor"></interceptor>
-- </interceptors>
--
--
-- <action name="demo1" class="cn.itcast.interceptor.a_hello.Demo1Action">
--
-- <!-- 2.绑定路径,配置这个action执行的时候会执行那些拦截器 -->
-- <interceptor-ref name="Demo1MyInterceptor"></interceptor-ref>
--
-- <!-- 注意:一旦在action中显式的声明了使用某个拦截器,默认的拦截器就再也不执行了.咱们须要显式的配置下默认的拦截器 -->
-- <interceptor-ref name="defaultStack"></interceptor-ref>
-- </action>
--</package>
方式2:
--<package name="demo1" namespace="/" extends="struts-default">
-- <!-- 配置拦截器栈 -->
-- <interceptors>
-- <!-- 注册拦截器 -->
-- <interceptor name="Demo1MyInterceptor" class="cn.itcast.interceptor.a_hello.Demo1MyInterceptor"></interceptor>
-- <interceptor name="Demo2MyInterceptor" class="cn.itcast.interceptor.a_hello.Demo2MyInterceptor"></interceptor>
-- <interceptor name="Demo3MyInterceptor" class="cn.itcast.interceptor.a_hello.Demo3MyInterceptor"></interceptor>
--
--
-- <!-- 注册拦截器栈 -->
-- <interceptor-stack name="MyStack">
-- <interceptor-ref name="Demo1MyInterceptor"></interceptor-ref>
-- <interceptor-ref name="Demo2MyInterceptor">
-- <!-- 对execute方法进行忽略,就是不拦截,多个方法用逗号隔开便可 -->
-- <param name="excludeMethods">execute</param>
-- </interceptor-ref>
-- <interceptor-ref name="Demo3MyInterceptor"></interceptor-ref>
-- </interceptor-stack>
-- </interceptors>
--
--
-- <action name="demo1" class="cn.itcast.interceptor.a_hello.Demo1Action">
--
-- <!-- 2.绑定路径,配置这个action执行的时候会执行那个拦截器栈 -->
-- <interceptor-ref name="MyStack"></interceptor-ref>
--
-- <!-- 注意:一旦在action中显式的声明了使用某个拦截器,默认的拦截器就再也不执行了.咱们须要显式的配置下默认的拦截器 -->
-- <interceptor-ref name="defaultStack"></interceptor-ref>
-- </action>
--</package>
案例-权限拦截
步骤:
1.先作登陆
建立User表,插入一条记录
建立user的持久化类和映射文件(hibernate 03)
建立user的action,service,dao;配置action
把login.htm改为login.jsp
修改表单的提交路径: /crm_/user_login.action
须要给用户名和密码提供name属性
须要在Action提供一个login方法
调用service的find4login(user),查询有无此对象
如有:将用户放入session中,重定向到 index.htm上. 在页面上取出session中用户名称
若无:生成错误提示信息,请求转发到login.jsp上.在页面上取出错误信息.
2.再作拦截
自定义拦截器
判断session中有无用户
如有:放行
若无:生成错误提示信息,转发到登陆页面,放行
拦截那些action
客户里面的全部action
用户里面的全部action
细节:
1.在拦截器中获取action
ActionSupport action = (ActionSupport) invocation.getAction();
2.添加错误提示信息及在页面上展现错误信息
action中: addActionMessage("权限不足,请先登陆"); 或者 addActionError("权限不足,请先登陆");
jsp中: 使用struts标签获取<s:actionmessage/> 或者 <s:actionerror/>
3.在login.jsp中写一段js代码
判断login.jsp是否在最大的窗口中打开,若不是的话,就让他是最大的窗口
if(top.location != self.location){
top.location = self.location;
}
struts的注解开发
xml中配置了
package 继承于谁,名称空间
action 访问路径和类的对应,要执行的方法,结果页面跳转
拦截器
注解:
导入jar包.
struts的解压目录下/lib/struts2-convention-plugin-2.3.24.jar
须要在action中提供注解
类上的注解
@ParentPackage("struts-default")//声明父包 至关于extends属性
@Namespace("/")//声明名称空间
扩展:
@Results({@Result(name="",type="",location="")})//至关于全局的结果配置,仅适用于当前action下的全部方法
方法上的注解
@Action(value="user_save")
还有:
@Action(value="user_save",results={
@Result(name="aa",location="/1.jsp"),
@Result(name="bb",type="redirect",location="/2.jsp")
}
)
扩展:
拦截器没有注解,拦截器还须要在xml中配置,咱们能够经过注解配置访问那个方法的时候使用某个拦截器
@Action(value="save",interceptorRefs={
@InterceptorRef(value="Demo1MyInterceptor")
})
注意:
action必须存在于 action | actions | struts | struts2这些包下安全