struts2 数据操作 值栈 拦截器
概述:应用在web层的框架,
实在struts1和webwork基础之上发展全新的框架
解决问题:创建很多的servlet,解决写servlet底层的帮助类的麻烦
struts2 里面使用action(类似与过滤器,后进行不同处理)
版本:2.3.24
1导入jar包
2创建action类
(1)访问servlet时候,执行service方法,底层用的是反射
* (2)访问action,访问action的时候,默认执行名称execute方法
package Action;
public class HelloAction {
/**
* (1)访问servlet时候,执行service方法,底层用的是反射
* (2)访问action,访问action的时候,默认执行名称execute方法
*
*/
public String execute(){
return "ok";
}
}
3.创建servlet的时候要继承heepServlet,重写方法,在web.xml里面要进行配置
action类似,配置action类的访问的路径
创建struts2的核心配置文件,名称和位置是固定的,src下,struts.xml
引入dtd的约束
配置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>
<package name="hellodemo" extends="struts-default" namespace="/">
<!--name中写上最终 访问的名称-->
<action name="hello" class="Action.HelloAction">
<!--配置方法的返回值到对应的页面中去-->
<result name="ok">/hello.jsp</result>
</action>
</package>
</struts>
注意:配置过滤器:否则访问不到(struts2实现了过滤器,但是要配置)
web.xml
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
访问路径:
http://127.0.0.1/项目名/hello.action(.action可以不加,但是访问的浏览器版本不好的话最好加上)
基本执行过程:
浏览器发送请求
过滤器:里面做了
过滤器在服务器启动的时候创建,servlet是第一次启动的时候创建
1获取请求路径,得到路径中的hello的值
2到src下面找到struts.xml 使用dom4j解析,得到xml文件中的内容,拿着hello到xml中去匹配对应的action的name值是否一样
3匹配好name之后,找到name属性所在的标签里面的另一个属性class的值,得到action的全路径,通过反射实现全部的功能
(反射:得到类的字节码文件执行操作)让action的方法执行
Class jjj = Class.forName("action全路径");
//得到名称是execute的方法
Method m = jjj.getMethod("execute");
//执行
Object obj = m.invoke();
4.得到action方法的返回值,到struts.xml文件中action标签里找到result标签,匹配result标签name属性值是否一样
如果一样,跳转到配置页面中去
看源代码:很多功能使用过滤器做的,所以可以直接看过滤器即可
StrutsPrepareAndExecuteFilter这是过滤器的名字
结构 :init,dofilter,destory
过滤器在服务器启动的时候创建,执行init方法
init主要加载配置文件
自己创建和struts自己的配置文件
(默认的文件在struts里的、default/plugin/struts.xml、)
**struts.xml和web.xml是自己写的
Struts2 配置
核心配置文件:基本结构配置
名称和位置固定
在配置文件中主要三个标签:package、action、result。标签里面的属性
package:类似于代码中的包,区别于不同的action,必须首先写package标签,在package里面才能配置action
name:属性跟功能本身没有关系,在一个配置文件中可以写多个package标签,name属性值不能相同的
extends:struts-default属性值是固定的,表示写了此属性了之后在package里面配置的类具有action功能
namespace:值要和action里面的name属性值构成访问路径,可以不写,默认就是/,建议写出来
action:
此标签用于配置action访问路径,
name:值要和package里面的namespace属性值构成访问路径,可以不写,默认就是/,建议写出来,在一个package标签中可以写多个action标签,但是name不能相同
class:action的全路径,底层是反射
method:比如在action里面默认执行execute,但是在action里面写上其他的方法,可以通过action来执行,让多个方法进行执行
result:标签用于根据action方法的返回值,配置到不同的路径里面去。不经是页面也可以是action
name:和方法的返回值一样,配置方法的返回值:/hello.jsp
<!--配置方法的返回值到对应的页面中去-->
<result name="ok">/hello.jsp</result>
type:配置如何到路径中去:转发和重定向 默认是转发
struts的默认常量(封装的功能)配置修改:
常用的方式:
在struts.xml里面进行修改
<constant name="struts.i18n.encoding" value="utf-8"></constant>
还有两种方式
src下面创建struts.properties
在web.xml里面进行修改
最常用的常量:
struts.i18n.encoding=utf-8
表单提交数据到action里面,子啊action可以获取表单提交数据
表单提交数据会有中文乱码问题,解决
以往:post 直接设置编码
get做编码转换
如果在action获取表单是post,不需处理中文乱码,但是如果是get还得自己处理。
分模块的开发(实际开发):
单独写配置文件,把配置文件映入到核心配置文件中
<!--引入hello.xml文件-->
<include file="Action/hello.xml"></include>
Action的编写方式
三种:
第一种:创建普通类,此类不继承任何类,也不实现任何接口
package Action;
public class HelloAction {
/**
* (1)访问servlet时候,执行service方法,底层用的是反射
* (2)访问action,访问action的时候,默认执行名称execute方法
*
*/
public String execute(){
return "ok";
}
}
第二种:创建类,实现接口Action用的不多
package Action;
/*
实现接口
*/
import com.opensymphony.xwork2.Action;
public class UserAction implements Action {
@Override
public String execute() throws Exception {
//return "success";
return SUCCESS;//可用接口中的常量作为返回值
}
}
第三种:创建类,继承ActionSupport(该类实现了包含action接口在内的很多结口)最常用
import com.opensymphony.xwork2.ActionSupport;
public class PersonAction extends ActionSupport {
@Override
public String execute() throws Exception {
//return "success";
return SUCCESS;//可用接口中的常量作为返回值
}
}
action的多个方法的访问设置(重点)
三种方式:
第一种:使用action标签的method属性,在这个属性里面写执行的action的方法
大量方法配置会很麻烦
<!--配置action的方法的访问-->
<package name="methoddemo" extends="struts-default" namespace="/">
<!--method属性,写要执行的action里面的方法名称-->
<action name="addAction" class="Method.BookAction" method="add"></action>
<action name="updateAction" class="Method.BookAction" method="update"></action>
第二种:常用的,通过通配符的方式,大量方法适用,在action标签name值写成*
表示:用*匹配任意的内容
比如访问hello, *可以匹配到
比如访问add, *可以匹配到
<!--配置action的方法的访问通配符的方式-->
<package name="methoddemo" extends="struts-default" namespace="/">
<!--
name属性之里面写符号*
执行action里面的add方法,访问book_add,使用book_*可以匹配到,*相当与add
执行action里面的update方法,访问book_update,使用book_*可以匹配到,*相当与update
以上两个路径使用book_*可以匹配到
method属性写*值,{1}表示取到第一个*的值
-->
<action name="book_*" class="Method.BookAction" method="{1}"></action>
</package>
执行流程:
访问路径---》book_*匹配到
第三种:通过动态访问的方式实现(少用)
写法很麻烦,还多
在前端的页面的链接用! 如:useraction!delete.action
如果action方法没有返回值,在配置文件中没有配置,出现404 no result defined,,,
action的方法里有返回值,如果有返回值的时候,类型必须是string
action的方法里没有返回值,如果没有返回值的时候,在result标签中不需要配置
把方法的返回些微void
但是建议写成返回"none"或NONE常量(注意action要继承ActionSupport类)的字符串,也可以不用配置result
public String execute(){
// return "none";
return NONE;
}
servlet改struts2
与servlet很像,将service的调用放在了action类的方法里,使用与对象存储数据
HttpServletReqeust request= ServletActionContext.getRequest();//获取请求,实际就HttpServletReqeust
request.setAttribute("list",list);
结果页面的配置:
创建两个accton都返回success,跳转到公共页面
全局结果页面:解决问题
<action name="book" class="Action.BookAction">
<result name="success">/hello.jsp</result>
</action>
<action name="orders" class="Action.OrdersAction">
<result name="success">/hello.jsp</result>
</action>
解决方法
<package name="demo1" extends="struts-default" namespace="/">
<!--全局结果页面的配置-->
<global-results>
<result name="success">/hello.jsp</result>
</global-results>
<action name="book" class="Action.BookAction">
<!--<result name="success">/hello.jsp</result>-->
</action>
<action name="orders" class="Action.OrdersAction">
<!--<result name="success">/hello.jsp</result>-->
</action>
</package>
局部结果页面:
如:<action name="orders" class="Action.OrdersAction">
<result name="success">/hello.jsp</result>
</action>
当局部和全局冲突时间,以局部为准
<package name="demo1" extends="struts-default" namespace="/">
<!--全局结果页面的配置-->
<global-results>
<result name="success">/hello.jsp</result>
</global-results>
<action name="book" class="Action.BookAction">
<result name="success">/index.jsp</result>
</action>
<action name="orders" class="Action.OrdersAction">
<!--<result name="success">/hello.jsp</result>-->
</action>
</package>
result标签type属性:
type用于指定如何到路径里去
type属性值默认值转发:dispatcher
<result name="success" type="dispathcer">/hello.jsp</result>
重定向:redirect
<action name="book" class="Action.BookAction">
<result name="success">/index.jsp</result>
</action>
<action name="orders" class="Action.OrdersAction">
<result name="success" type="redirect">/hello.jsp</result>
</action>
还有两个值:配置到action的:
chain:转发到action用的少有缓存一般不用
redirectAction:重定向到action
<action name="book" class="Action.BookAction">
<!--action访问名称-->
<result name="success" type="redirectAction">orders</result>
</action>
<action name="orders" class="Action.OrdersAction">
<result name="success" type="redirect">/hello.jsp</result>
</action>
action表单提交数据
web阶段提交表单提交到servlet里面使用request对象里面的方法获取,getParameter,getParameterMap
提交表单到action,但是action没有request对象,不能直接使用request对象
action获取action对象三种方式如下
使用ActionContext类获取
用Map<String Object> getParameters()方法
因为方法不是静态方法,需要创建ActionContext对象
该对象不是new出来的,用static ActionContext getContext()获取当前线程的actionContext对象
具体:
//通过ActionContext类获取
//1获取ActionCOntext对象
ActionContext actionContext = ActionContext.getContext();
//2.调用方法获取表单数据
//key是表单输入的name的属值,value是输入的值
Map<String,Object> map = actionContext.getParameters();
Set<String> keys= map.keySet();
for (String key:keys) {
//得到key的value
Object[] object = (Object[])map.get(key);//考虑到复选框所以用数组
System.out.println(Arrays.toString(object));
}
使用SerevletActionContext类获取
调用类里面的静态方法,得到request对象
//第二种方式使用ServletActionContext类获取
//使用ServletActonContext获取request对象
javax.servlet.http.HttpServletRequest request = ServletActionContext.getRequest();
//调用request里面的方法得到信息
String username = request.getParameter("username");
String password = request.getParameter("password");
String address = request.getParameter("address");
System.out.println(username+" "+password+" "+address);
使用接口注入方式获取
让action实现一个接口,为了得到request
public class Form3DemoAction extends ActionSupport implements ServletRequestAware {
private HttpServletRequest request;
@Override
public void setServletRequest(HttpServletRequest httpServletRequest) {
this.request=httpServletRequest;
}
@Override
public String execute() throws Exception {
//第三种方式使用接口
request.getParameter("");
return NONE;
}
}
在action里面域对象:如javax.servlet.http.HttpServletRequest request = ServletActionContext.getRequest();
1.request\session\servletContext域对象
2.使用ServletActionContext类来操作
//操作三个域对象
// 1.request传输到页面数据
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("req","reqValue");
//2session域,保存登陆状态等
HttpSession session = request.getSession();
session.setAttribute("sess","sessionValue");
//3servletContext,用的少
ServletContext context = ServletActionContext.getServletContext();
context.setAttribute("contname","contvalue");
struts2提供 获取 表单数据方式,简化数据获取方式
原始的方式获取封装到实体类,最有效的方式
//获取表单数据
HttpServletRequest request = ServletActionContext.getRequest();
String username = request.getParameter("username");
String password = request.getParameter("password");
String address = request.getParameter("address");
//封装到实体类的对象
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setAddress(address);
System.out.println(user);
属性封装
可以直接把表单提交的数据封装到action属性里面
实现:
在action成员变量位置定义变量
变量名称和表单输入项的name属性值一样
生成的变量的set方法(set和get)
public class DataDemo1Action extends ActionSupport {
// 使用属性封装获取表单数据
//定义变量
//变量的名称和表单输入项name属性值一样
private String username;
private String password;
private String address;
//生成变量的set和get方法
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String execute() throws Exception {
System.out.println(username+password+address);
return NONE;
}
}
该方式只是获取表单的数据到属性里面,不能把数据直接封装到实体类对象里面
模型驱动封装(最常用,如添加数据的时候)
优点:直接将表单的数据封装到实体类对象的方式,底层是原始的方式
实现:
action实现接口ModelDriven
实现接口里面的方法,getModel方法
把创建对象返回
在action里面创建实体类对象
//使用模型驱动获取方式
public class DataDemo2Action extends ActionSupport implements ModelDriven<User> {
//创建对象
//要求表单实体类属性和实体类对象属性名相同
private User user = new User();
public User getModel() {
//返回创建user对象
return user;
}
@Override
public String execute() throws Exception {
System.out.println(user);
return NONE;
}
}
使用模型驱动和属性封装的时候注意问题:
1.在一个action中,获取表单数据可以属性封装或模型封装,但不能同时使用两者来获取同一个表单数据,如果都用只用模型的
表达式封装(也可以归类为属性封装)
实现过程:
也可以将表单数据封装到实体类对象里面
在action里面声明实体类
生成实体类变量的set和get方法
在表单输入项的name属性值里面写表达式形式
//使用表达式封装
public class DataDemo3Action extends ActionSupport{
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
System.out.println(user);
return NONE;
}
}
<form action="{pageContext.request.contextPath}/data3.action" method="post">
username:<input type="text" name="user.username">
<%--user.username会调用user.setUsername方法--%>
password:<input type="text" name="user.password">
address:<input type="text" name="user.address">
<br>
<input type="submit" value="提交"/>
</form>
比较表达式封装和模型驱动封装
相同:都可以将数据封装到实体类对象里
不同:
模型驱动只能将数据封装到一个实体类里面
在一个action里面不能使用模型驱动把数据封装到不同过的实体类对象里面
使用表达式封装可以将数据封装到不同的实体类对象里面
//使用表达式封装
public class DataDemo3Action extends ActionSupport{
private User user;
private Book book;
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
System.out.println(user);
System.out.println(book.getBname());
return NONE;
}
}
address:<input type="text" name="user.address">
<br>
bname:<input type="text" name="book.bname">
struts2 获取 数据封装到集合中
封装到list集合
在action里面声明list
生成list变量的set和set方法
在表单输入项里面写表达式
public class DataDemo3Action extends ActionSupport{
private User user;
private Book book;
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String execute() throws Exception {
System.out.println(user);
System.out.println(book.getBname());
return NONE;
}
}
<form action="{pageContext.request.contextPath}/list.action" method="post">
username:<input type="text" name="list[0].username">
<%--user.username会调用user.setUsername方法--%>
password:<input type="text" name="list[0].password">
address:<input type="text" name="list[0].address">
<br>
username:<input type="text" name="list[1].username">
<%--user.username会调用user.setUsername方法--%>
password:<input type="text" name="list[1].password">
address:<input type="text" name="list[1].address">
<br>
<input type="submit" value="提交"/>
</form>
封装到map集合
1.声明一个map集合,
2.生成get和set方法
3.在表单输入项的name属性值里面写表达式
//封装数据到一个map集合
public class MapAction extends ActionSupport{
private Map<String,User> map;
public Map<String, User> getMap() {
return map;
}
public void setMap(Map<String, User> map) {
this.map = map;
}
@Override
public String execute() throws Exception {
System.out.println(map);
return NONE;
}
}
<form action="{pageContext.request.contextPath}/map.action" method="post">
<%--
设置map的key
设置value值
--%>
username:<input type="text" name="map['one'].username">
<%--user.username会调用user.setUsername方法--%>
password:<input type="text" name="map['one'].password">
address:<input type="text" name="map['one'].address">
<br>
username:<input type="text" name="map['hhh'].username">
<%--user.username会调用user.setUsername方法--%>
password:<input type="text" name="map['hhh'].password">
address:<input type="text" name="map['hhh'].address">
<br>
<input type="submit" value="提交"/>
</form>
值栈:在struts中可以将数据放到值栈中,在页面中也可以取到
OGNL的概述
在web阶段学过EL表达式只可用与jsp中,获取域对象里面的值,但是在html中就不行,
ognl表达式,比el强大
在struts2中用于操作值栈中的数据,
一般把ognl和struts2中的标签结合使用,用于操作值栈
ognl不是struts2的一部分,单独的项目,场合struts2一起使用
使用ognl,首先要导入ognl的jar包,但是struts2已经提供了
ognl案例:
ognl支持对象方法的调用,
使用ognl和struts2实现计算字符串长度
在java中使用字符串的length()方法
步骤:
引入struts2的标签库
<%@ taglib prefix="s" uri="/struts-tags" %>
使用标签实现操作
<%--
使用ognl+struts2表达式
value:ognl表达式
--%>
<s:property value="'haha'.length()"/>
什么是值栈
在web阶段使用servlet以及域对象进行数据的存入,在页面中通过el表达式进行取出。域对象在一定的范围之内
在struts2中提供了一种存储机制,类似于域对象,是值栈,可以存值和取值
在action里面把数据存放到值栈里面,在页面中也能获取到值栈的数据
servlet和action的区别:
servlet默认在第一次访问的时候创建,创建一次,单实例对象
action创面多次,访问一次创建一次,多实例对象
值栈的存储位置
每次访问action的时候都会创建一个action对象
每个action对象里面都会有 *一个*!值栈对象(只有一个)
获取值栈对象:
获取有两种方式
使用一个ActionContext类里里面你的方法得到值栈对象(常用)
ActionContext context= ActionContext.getContext();
//得到值栈信息
ValueStack stack1 = context.getValueStack();
ValueStack stack2 = context.getValueStack();
System.out.println(stack1==stack2);
每个action中只有一个值栈对象
值栈内部结构
栈:如同水杯,后进先出,放入内容的时候叫做压栈操作,最上面的是栈顶元素
值栈的内部结构:
分为两部分:
root:机构是list集合
一般操作都是root里面数据,对应类是CompoundRoot,继承了ArrayList类
context:结构map集合:主要存的是键值对,context储存的是对象的引用,key主要是request,session,application,parameters,attr,value对应是key代表对象的应用分别为:request对象的引用,HttpSession对象的引用,ServletContext对象的引用,传入的参数,向前面三个域对象的名称都相同,使用attr操作,获取上述域对象里面范围最小的值。
OgnlContext实现了Map接口
向值栈中放数据
使用s:debug标签:使用该标签可以查看值栈结构和存储值
访问action,执行action的方法,返回值配置返回daojsp中,jsp中使用该标签。
在action中没有任何操作,栈顶元素就是Actiuon对象(引用)
action对象里面有值栈对象
值栈对象里面有action引用
向值栈中放数据
三种方式
1.获取值栈对象,调用值栈对象里面的set方法
ActionContext context = ActionContext.getContext();
ValueStack stack = context.getValueStack();
stack.set("username","itcast");
2.获取值栈对象,调用值栈对象里面的push方法
ActionContext context = ActionContext.getContext();
ValueStack stack = context.getValueStack();
//set
stack.set("username","itcast");
//push
stack.push("abasdafsddfasdf");
目前的栈内部:从上倒下
栈顶
java.lang.String
java.util.HashMap
Action.ValueStackDemoAction
栈底
3.在action定义变量,生成变量的get方法(常用,减少空间浪费)
这个方法直接数据放入Action.ValueStackDemoAction,而非如上面两种中自行开辟空间:java.lang.String和java.util.HashMap
public class ValueStackDemoAction extends ActionSupport {
//定义成员变量
private String name;
//get方法生成
public String getName() {
return name;
}
public ValueStackDemoAction(){
System.out.println("action实例化");
}
@Override
public String execute() throws Exception {
//在具体的执行方法里面设置值
name = "fasdfasdfasdfasdf";
// ActionContext context = ActionContext.getContext();
// ValueStack stack = context.getValueStack();
// //set
// stack.set("username","itcast");
// //push
// stack.push("abasdafsddfasdf");
return SUCCESS;
}
}
向值栈中发放对象
1.定义成员变量
2.生成成员变量的get方法
3.在执行的方法里面向对象设置值
public class ObjectDemoAction extends ActionSupport {
private User user = new User();
public User getUser() {
return user;
}
@Override
public String execute() throws Exception {
user.setUsername("asdfasd");
user.setPassword("asdfasdf");
user.setAddress("USA");
return SUCCESS;
}
}
向值栈中放list对象
定义一个list成员变量
生成get
在方法中放入值
public class ListDemoAction extends ActionSupport {
private List<User> lsit = new ArrayList<User>();
public List<User> getLsit() {
return lsit;
}
@Override
public String execute() throws Exception {
User user = new User();
lsit.add(user);
lsit.add(user);
return SUCCESS;
}
}
从值栈中取数据,使用struts2的标签和OGNL表达式取值栈数据
<s:property value="ognl表达式">
1。获取字符串
向值栈中放入字符串
public class ValueStackActioin extends ActionSupport {
private String username;
public String getUsername() {
return username;
}
@Override
public String execute() throws Exception {
username = "hello";
return "success";
}
}
页面获取值栈中的字符串
<%--获取字符串的值,根据名称就可以得到值--%>
<s:property value="username"></s:property>
在jsp中使用struts2的标签和OGNL
2.获取对象
private User user = new User();
public User getUser() {
return user;
}
@Override
public String execute() throws Exception {
username = "hello";
user.setUsername("usernameshelklo");
user.setPassword("asdfasdf");
user.setAddress("asdfasdfasdfasdf");
return "success";
}
<%--获取对象的值--%>
<s:property value="user.username"></s:property>
<s:property value="user.password"></s:property>
<s:property value="user.address"></s:property>
3.获取集合list
private List<User> list = new ArrayList<User>();
public List<User> getList() {
return list;
}
@Override
public String execute() throws Exception {
// username = "hello";
// user.setUsername("usernameshelklo");
// user.setPassword("asdfasdf");
// user.setAddress("asdfasdfasdfasdf");
User user = new User();
user.setUsername("张三");
user.setPassword("1253563");
user.setAddress("华山");
User user1 = new User();
user1.setUsername("李四");
user1.setPassword("1253563");
user1.setAddress("衡山");
list.add(user);
list.add(user1);
return "success";
}
<%--获取值栈中list集合中的数据--%>
<%--第一种方法--%>
<s:property value="list[0].username"></s:property>
<s:property value="list[0].password"></s:property>
<s:property value="list[0].address"></s:property>
<br>
<s:property value="list[1].username"></s:property>
<s:property value="list[1].password"></s:property>
<s:property value="list[1].address"></s:property>
<br>
<%--第二中方法,使用struts2标签,类似jstl的foreach
<s:iterator>遍历值栈中的list集合
<c:foreach item-="" var="user">
${user.username}
</c:foreach>
小心&和!注释方式
--%>
<s:iterator value="list">
<%--遍历list得到list里面每个user对象--%>
<s:property value="username"></s:property>
<s:property value="password"></s:property>
<s:property value="address"></s:property>
<br>
</s:iterator>
<%--第三种方法--%>
<s:iterator value="list" var="user">
<%--娶不到
<s:property value="address"></s:property>
遍历list集合得到每个user对象机制,吧每次遍历出来的user对象放到context里面
这样会加速,在contex里面分配临时空间,key是var的值user 值会放入user对象的引用
获取context里面的数据特点,写ognl表达式
使用特殊符号:#
--%>
<s:property value="#user.username"></s:property>
<s:property value="#user.password"></s:property>
<s:property value="#user.address"></s:property>
</s:iterator>
其他操作:
使用set方法向值栈放数据,获取
<%--获取set方法放入的值--%>
<%--根据名称获取值--%>
<s:property value="itcast"></s:property>
使用push方法向值栈放数据,获取
使用push方法设置值,没有名称,只有设置的值
想值栈放数据,把向值栈放数据存到数组里面,数组名称top,根据数组获取值
<%--获取push方法放入的值--%>
<%--无名称取法,通过默认数组,用ognl的写法,取到数组中的第一个值,实际就是栈顶的值--%>
<s:property value="[0].top"></s:property>
el表达式如何取到值栈中的值
<%--使用foreach标签和el--%>
<c:forEach items="${list}" var="user">
<p>hello this is jstl</p>
${user.username}
${user.password}
${user.address}
</c:forEach>
el表达式为什么获取到值栈数据的值
1.本身用于取与域对象里面的值
2.域对象里面放值使用setAttribute方法,获取值使用getAttribute();
3.底层增强request对象里面的方法getAttribute方法
首先从request域里面获取值,如果获取到,直接返回
如果从request域对象娶不到值,到值栈中把值获取出来,把值放到域对象里面
4.底层实在dofilter里面做了一个增强叫做wrapRequest(request),再往里面有一个StrutsRequestWrapper 继承了HttpServletRequestWrapper,增强的方法是getAttribute。
5.建议:如果把数据放到了值栈中去,不建议用el取,因为会拖慢性能
OGNL的#、%使用
#:可以获取值栈中context里面的数据。context是map类型的结构
向request里面放入值,使用OGNL表达式获取值
public class ContextDemoActioin extends ActionSupport {
@Override
public String execute() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("req","reqValue");
return "success";
}
}
<%--获取context里面的数据,写ognl的时候首先添加上符号
#context的key名称,域对象的名称
--%>
<s:property value="#request.req"></s:property>
</body>
%:在struts2的标签中有一类表单标签
%使用struts2标签里面使用ognl表达式,如果直接在struts2表单标签里面使用ognl表达式不知别,只有%之后才会识别
<%--<s:property value="#request.req"/>--%>
<%--<input type=" text" name="name" value="123"> 这是一个普通输入项--%>
<s:textfield name="username" value="%{#request.req}"></s:textfield>
struts2 拦截器概述
struts是框架,封装了很多功能,都是封装在拦截器里面。
struts2里面封装了很多功能,有很多拦截器,不是每次这些拦截器都执行,每次执行默认的拦截器。
struts2里面默认拦截器位置:corejar包里,有一个struts-default。xml配置文件,里面有一个<interceptor-stack name="defaultStack">就是默认拦截器的位置所在。内有很多拦截器的引用。
拦截器在什么时候进行执行?
在action对象创建之后,方法执行之前执行。拦截器类一般有一个intercept方法进行处理操作。
拦截器底层原理
底层两个原理
aop思想:
aop指的是面向切面编程,有一个基本功能,扩展功能可以不通过修改元代码的形式
比如登陆成功之后做一个用户权限判断(功能扩展),权限判断,不修改源代码(AOP)应对需求变动的时候特别好
AOP更底层的是动态代理技术
责任链模式:
在java中有很多设计模式,责任链是其中一种
责任链和过滤连模式相似
过滤连:一个请求可以有多个过滤器进行过滤,每个过滤器只有通过放行才能到下一个过滤器。
责任链:一次执行多个操作,
先执行操作一,类似放行操作,进行修改操作,类似放行,进行操作三。。。。
AOP和责任链是如何应用到拦截器里面的
拦截器在action对象创建之后,action方法执行之前执行默认拦截器,执行的过程使用的就是aop的思想。(不该源代码就是先功能)action里面并没有显示调用拦截器,而是通过配置的方式实现。
在执行拦截器的时候,执行很多拦截器,这个过程使用责任链模式。(类似放行的方式有序的是拦截器执行)
在具体的执行的时候,从默认的拦截其中挑选使用到的,而拦截器之间的执行用的就是责任链的模式,通过放行逐个执行。
源代码:(类似于放行操作的方法叫做invocation.invoke()的方法)
执行action
execute.executeAction(request,response,mapping)
创建action对象,使用动态代理方式
ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace,name,method,extraContext,true,false)
执行action的方法
proxy.execute();
执行很多拦截器,遍历执行
if(interceptors.hasNext()){}
重要概念:
过滤器和拦截器的区别:
过滤器:理论上可以过滤任意的内容,html,jsp,servlet,图片路径
拦截器:可以拦截内容:action只有这个。
Servlet和action的区别
servlet:一默认的第一次访问的时候创建,创建一次,单实例对象
action:每次访问的时候创建,创建多次,多实例对象
自定义拦截器:
struts2里面有很多拦截器,是有struts2自己封装的功能,但是可能没有需要的功能,我们可以自己创建
拦截器的基本结构:
查看源代码:
继承AbstractInterceptor类
AbstractInterceptor类实现Interceptor接口
Interceptor接口中有三个方法:
void init()初始化,
void destory()销毁
String intercept(ActionInvoication invocation) 拦截逻辑
一般选择继承类,用谁写谁
(2)开发中一般使用另一种方式
写类,继承MethodFilterInterceptor类
让action里面的方法不进行拦截
(3)让拦截器和action有关系,通过配置文件的方式建立关系,aop
案例需求:
自定义登陆拦截器
1需求:登陆状态判断,很多action的超链接,实现只有是登陆的状态,才可以点击action的超链接实现功能,如果不是登陆状态,点击action链接返回登陆页面
2登陆状态:施一公session域对象实现
登陆成功之后,把数据放到session里面
判断session里面是否有值,可以知道是否有登陆状态
3.实现登陆的基本功能。
1.查询数据库判断用户名和密码。
登陆的方法:
public String login(){
HttpServletRequest context = ServletAxtionContext.getRequest();
String username = context.getParameter("username");
String password= context.getParameter("password");
if("admin".equeals(username)&&"250".equals(password)){
request.getSession().setAttribute("username",username);
return "loginsuccess";
}else{
}
return "login";
}
添加登陆拦截器:
判断是否登陆,从session中判断值
实现过程:
创建一个类继承MethodFilterInterceptor类
重新MethodFilterInterceptor类里面的方法拦截器逻辑
//此方法写拦截器的逻辑即可
@Override
protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
//判断session中用户信息
HttpServletRequest context = ServletActionContext.getRequest();
Object object = context.getSession().getAttribute("username");
if(object!=null){
//登陆状态,做一个类似放行的工作
return actionInvocation.invoke();
}else{
//不是
//不执行放行
//到result标签中找到名称是login的值,到配置的路径中去
return "login";
}
}
配置action和拦截器关系(注册拦截器)aop
1.在要拦截的action标签所在的package标签里面声明拦截器
在package中
声明拦截器
<interceptors>
<interceptor name="loginintercept" class="cn.it.interceptor.LoginInterceptor"></interceptor>
</interceptors>
2.在具体的action标签使用声明的拦截器
使用:
在action里面
<interceptor-ref name="loginintercept"></interceptor-ref>
3.struts2 里面执行很多的默认拦截器,但是如果在action里面配置自定义的拦截器,问题:默认的拦截器不会执行
解决办法:把默认拦截器手动使用一次
在action里面:
方法一:把默认的<interceptor-ref>全复制进来,太多
方法二:映入:<interceptor-ref name="defaultStack">,将这些拦截器的外包标签引入即可
配置的拦截器会对action里面的方法都拦截。登陆方法是不需要拦截的否则等不进去
配置不拦截的方法:
直接通过配置方式,是某些方法不拦截
在使用拦截器里面配置:
<interceptor-ref name="loginintercept">
<!--配置某些方法不拦截
excludeMethods:忽略方法
-->
<param name="excludeMethods">方法名1.方法名2</param>
</interceptor-ref>
防止页面打开嵌套:在form标签中添加:target="_parent"
struts2常用标签:
jsp页面中
s:property:和ognl表达式在jsp页面中获取值栈数据
s:iterator: 获取值栈中list集合数据,表示list集合
s:debug: 查看值栈数据,结构
s:if
struts2里面的表单标签:
html中的表单:
form:action method enctype
输入项:大部分在input :type
text,password,radio,checkbox,file,hidden,button,submit,image,reset
不在input中:
select,textarea
对应的;struts2大部分都有
form对应:s:form 常见属性形同
输入项:text的 s:textfield 常见属性相同
注意 有一个label属性:显示输入项的前面说名
password的 s:password
radio的:s:radio 多了一个list属性,
value和显示值一样的时候:list="{'女','男'}"
不一样额时候构建map集合:list="#{‘nv’:'女','nan':"男"}"
checkbox的:s:checkboxlist 多了属性list
list="{'asdf','asdfas','asdfasdf'}"
下拉输入框:s:select 多了list同上
文件上传:s:file
文本域:s:textarea
hidden的:s:hidden
提交的:s:submit value=""
重置的:s:reset
按钮不在一行:可在form标签属性theme=“simple” 全在一行,不好之处