整理struts2的概述、入门、执行过程、源代码、核心配置文件、分模块开发、action编写方式、action访问方法介绍
Struts2入门:
概述:
Struts2的框架是应用在web层的框架-显示层
Struts2是在struts1和webwork之上发展的全新的框架
Struts可以解决的问题:
图。
Strut2的版本:
Web层常见的框架:
- springMVC
- struts2
入门案例:
开发流程:
- 导入jar包:
- Apps的目录下的War包放入到tomcat可以运行
- Docs是文档
- Src是源代码
- Lib是jar包
直接到apps下的实例程序中找jar包
- 创建action
- 访问aciton,默认执行action类中的execute()方法
package com.pshdhx.action;
import com.opensymphony.xwork2.ActionSupport;
public class HelloAction extends ActionSupport{ public String execute() throws Exception { return "ok"; } } |
-
- 配置action类的访问路径
- 创建struts2的核心配置文件,名称和位置是固定的,名称是struts.xml,位置在src目录下。
- 从apps下的*.war文件的实例程序中找到dtd约束
- 配置action类的访问路径
<!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="com.pshdhx.action.HelloAction"> <!-- 配置方法的返回值到页面 --> <result name="ok">/hello.jsp</result> </action> </package> </struts> |
访问路径:
http://localhost/struts2_day01/hello.action 404不能访问
配置文件的过程由过滤器做,需要配置过滤器
<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> |
Struts2的执行过程:
Servlet默认是第一次访问时创建
过滤器是启动服务器时创建
过滤器操作:
- 获取到访问的路径,hello.action
- 到src下边找到strut2.xml文件,使用dom4j进行解析内容,拿着hello值到xml文件中匹配name属性是否一样
- 匹配name属性的值一样,都是hello,找到name属性所在标签的class属性,得到action的全路径,反射实现class的功能
- 反射代码,得到字节码文件
Class clazz = Class.forName(“action全路径”); //得到的方法是execute Method method = clazz.getMethod(“execute”); //方法执行 Object obj = method.invoke(); |
- 得到action方法的返回值,配置result的name值,进行页面跳转。
Struts2的源代码:
过滤器源代码:
Init(),过滤器服务器启动时创建,执行init方法
Default.properties Struts-default.xml Struts-plugin.xml Struts.xml :配置action和常量 Struts.properties :配置常量 Web.xml :配置核心过滤器和常量 |
Struts2的核心配置文件:
名称和位置固定 :src下的struts2.xml
Package:
类似于代码中的包,区分不同的action,要配置action,必须先写package标签,在package里边才能配置action。
Name:属性值和其本身的功能没有关系,类似于id,在一个配置文件中可以写多个package标签,但是name属性值不能相同。
Extends:属性值固定为 struts-default。写了这个属性之后,在package里边配置的类,就有了action的功能。
Namespace:属性值和action标签里的name属性值构成访问的路径 / hello.action,默认是/,可以不写。
Action:
配置action的访问的路径
Name属性:与namespace的属性值构成访问路径
Class属性:action类的全路径
Method属性:默认执行的是execute方法,让action里的多个方法进行执行,可使用method方法进行定义。
Result:
根据返回值到不同的路径中去。不仅是页面,有可能是action
Name属性:和你方法的返回值一样
Type属性:配置如何到路径中去。默认值是转发的操作,还有可以是重定向的操作。转发操作:启动一次,地址栏不变。
Struts2的常量的配置:
在struts.xml文件中定义<constant name=”” ></constant>标签。
<constant name="struts.i18n.encoding" value="UTF-8"></constant> |
在struts.properties文件中配置
struts.i18n.encoding=UTF-8 |
表单提交到action里边,在action可以获取表单的提交数据
表单提交数据有中文,有乱码问题,解决
Post提交直接设置编码
Get提交做编码转换
如果在action获取表单通过post提交中文,中文的乱码方式解决了,不需要自己处理乱码问题。
在web.xml文件中进行配置
Struts2的分模块的开发【协同开发】:
每个人都可以写配置文件,把写的配置文件引入到struts.xml文件中
<struts> <!-- 引入其他的配置文件 --> <include file="cn/pshdhx/action/hello.xml"></include> </struts> |
Action的编写方式:
- 就是一个普通类,不继承任何类,也不实现任何接口
- 创建一个类,实现action接口【xwork中的】
- 创建一个类,继承actionsupport类
Action的访问方法介绍:
- 通过配置method属性完成
- Action中有多个方法,method属性是方法的名称
- 通配符book_*
<action name="book_*" class="com.pshdhx.action.HelloAction" method="{1}"></action> |
3.动态访问实现
整理struts2的结果页面操作、在action获取表单数据、struts2提供获取表单数据方式、struts2获取表单元素封装到集合
1、结果页面操作
- 全局结果页面
<package name="local" extends="struts-default" namespace="/"> <!-- 多个界面返回相同的action --> <global-results> <result name="success">/hello.jsp</result> </global-results> <action name="hello" class="com.pshdhx.action.HelloAction"></action> <action name="others" class="com.pshdhx.action.OthersAction"></action> </package> |
- 局部结果页面
既配置了全局页面,也有局部页面,以局部页面为准。
- Result标签的type属性
Type属性是如何到路径去
默认值:做转发操作,dispatch【一次请求,地址栏不发生改变】
重定向操作:redirect【两次请求,地址栏发生变化为*.jsp】
Chain:转发到action,一般因为缓存问题不用
RedirectAction:重定向到action。用处:添加之后到列表页面。
<result name="success" type="redirectAction">others.action</result> |
2、在action获取表单提交的数据
之前在web阶段,提交表单到servlet里边,在servlet里边使用request对象获取到表单属性值,getParameter getParameterMap
表达提交到action,但是action没有request对象,不能直接使用request对象。
1、使用ActionContext类获取
Map<String ,Object> getParameters() ;返回一个包含所有HttpServletRequest参数信息
|
因为方法不是静态的方法,需要创建ActionContext对象 这个ActionContext对象不是new出来的 |
Static ActionContext getContext();获取当前线程的ActionContext对象 |
静态的所以ActionContext.method(); |
public String execute() throws Exception{ //第一种方式使用AcitonContext类获取 //获取ActionContext对象 ActionContext context = ActionContext.getContext(); //调用方法得到表单数据 //key是表单中的name值,value是输入的值 Map<String,Object> map = context.getParameters(); Set<String> keys = map.keySet(); for(String key:keys) { //根据key得到value //数组方式:因为输入项里边可能有复选框情况 Object[] obj = (Object[]) map.get(key); System.out.println(Arrays.toString(obj)); } return NONE; } |
2、使用ServletActionContext类获取
Static HttpServletRequest getRequest(); 获取web应用的HttpServletRequest对象 |
Static HttpServletRequest getResponse(); 获取web应用的HttpServletResponse对象 |
Static ServletContext getServletContext(); 获取web应用的ServletContext对象 |
Static pageContext getPageContext(); 获取web应用的PageContext对象 |
静态方法的最大好处:类名可以直接调用;
public String execute() throws Exception{ //使用ServletActionContext类获取表单数据 HttpServletRequest request = ServletActionContext.getRequest(); String username = request.getParameter("username"); String password = request.getParameter("password"); System.out.println(username+" "+password); return NONE; } |
3、使用接口注入方式获取:
让action实现接口,为了得到request对象
public class FormAction3 extends ActionSupport implements ServletRequestAware{ //使用接口方式得到servletrequest对象 private HttpServletRequest request; @Override public void setServletRequest(HttpServletRequest request) { // TODO Auto-generated method stub this.request = request; } public String execute() throws Exception{ String username = request.getParameter("username"); String password = request.getParameter("password"); System.out.println(username+" "+password); return NONE; } } |
- 在action中操作域对象
- Request域对象
HttpServletRequest request = ServletActionContext.getRequest(); Request.setAttribute(“req”,”reqValue”); |
-
- Session域对象
HttpSession session = request.getSession(); Session.setAttribute(“sess”,”sessValue”); |
-
- ServletContext域对象
ServletContext context = ServletActionContext.getServletContext(); Context.setAttribute(“contextName”,”contextValue”); |
3、struts2提供获取表单数据方式
1、属性封装
使用最原始的方式获取表单元素封装到实体类对象
public String execute() throws Exception{ HttpServletRequest request = ServletActionContext.getRequest(); String username = request.getParameter("username"); String password = request.getParameter("password"); User user = new User(); user.setUsername(username); user.setPassword(password); System.out.println(user); return NONE; } |
直接把表达提交属性封装到action属性中
- 在action成员变量位置定义变量,变量名称与表单输入项的name属性值一样
- 生成变量的set方法,便可以得到表单数据,省去了原始的得到request对象的过程。
- 使用属性封装获取表单数据到action类的属性里边去,不能把数据直接封装到实体类对象里边去。
2、模型驱动封装【重点】
可以直接把表单数据封装到实体类对象中去
- action类实现ModelDriven接口
- 实现接口里边的方法:getModel();把创建的对象返回即可
- 在action里边创建实体类对象
- 前提条件:表单输入项里边的name属性和实体类的属性值一样。
public class FormAction5 extends ActionSupport implements ModelDriven<User>{ private User user = new User();//实体类对象必须实例化,否则会得到null @Override public User getModel() { // TODO Auto-generated method stub return user; } public String execute() throws Exception{ System.out.println(user); return NONE; } } |
使用模型驱动和属性封装注意的问题:不能同时使用两个封装来封装一个表单对象,如果同时使用,那么执行的是模型驱动的方法,属性封装的内容为null。
- 表达式封装
- 在action类里边声明实体类,前提是有了实体类,并且有实体类属性的set和get方法
- 生成实体类的set和get方法
- 在表单输入项的name属性写表达式形式,name=user.usernameèuser实体类的set方法
5、比较表达式封装和模型驱动封装:
1、使用模型驱动只能把数据封装到一个实体类中。
2、使用表达式封装可以把数据封装到不同的实体类对象中去。
4、struts2获取表单数据封装到集合中
1、封装到list集合
1、在action声明List集合
2、生成list的set和get方法
3、在表单输入项里边写表达式封装的方法
<form action="${pageContext.request.contextPath}/list.action" method="post"> 用户名:<input type="text" name="list[0].username" /></br> 密 码:<input type="password" name="list[0].password"/></br><br>
用户名:<input type="text" name="list[1].username" /></br> 密 码:<input type="password" name="list[1].password"/></br><br> <input type="submit" value="提交"/> </form> |
2、封装到map集合
1、声明map集合
2、生成set和get方法
3、在表单输入项的name属性写表达式
<form action="${pageContext.request.contextPath}/map.action" method="post"> 用户名:<input type="text" name="map[0].username" /></br> 密 码:<input type="password" name="map[0].password"/></br><br>
用户名:<input type="text" name="map[1].username" /></br> 密 码:<input type="password" name="map[1].password"/></br><br> <input type="submit" value="提交"/> </form> |
public class FormMapAction extends ActionSupport{ private Map<Integer,User> map; public Map<Integer, User> getMap() { return map; } public void setMap(Map<Integer, User> map) { this.map = map; } public String execute() throws Exception{ System.out.println(map); return NONE; } }
|
struts2的ognl、值栈、foreach标签+EL表达式获取值栈元素
Ognl概述:
在web阶段学习过表达式EL:只能用在jsp中获取域对象里边的值。
也是一种表达式:功能更加强大,在struts2里边操作值栈数据,一般把ognl放在struts2里边进行操作;和struts2标签一起使用操作值栈,但它不是struts2的一部分,是一个单独的项目:
支持静态方法调用;调用objNamemethodName().
支持静态方法调用和值访问;@类全名@方法名(值).
支持赋值操作和表达式串联
访问ognl上下文和ActionContext
操作集合对象
1、导入jar包,在struts2里边有jar包
Ognl入门案例:
- 使用struts2标签+ognl计算字符串长度
- 在java代码中,调用字符串.length()实现
- 使用struts2标签
- 在使用jstl时候,导入jar包之外,在jsp页面导入标签库
使用struts2标签的时候,在jsp中引入struts2的标签库
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <s:property value="'pshdhx'.length()"/> </body> </html> |
什么是值栈:
在web阶段,在servlet里边进行操作,把数据放到域对象里边,在页面中使用el表达式获取到,域对象在一定范围之内,可以存放值和取值。
在struts之中,本身有存储机制,类似于域对象,可以存取数据。
在action之中,把数据放到值栈之中,在页面中取得值栈数据。
Servlet和action的区别:
- Servlet默认在第一次访问时创建,创建一次,单实例对象
- Action在访问时创建,每次访问都是创建一个action对象,多实例对象。
值栈的存放位置:
每次访问action的时候,都会产生一个action对象
在每个action对象里边都会有一个值栈对象,只有一个
获取值栈对象:
- 使用ActionContext类里边的方法得到值栈对象。也可获取表单数据
ActionContext context = ActionContext.getContext(); ValueStack stack = context.getValueStack(); |
值栈的内部结构:
- 值栈分为两部分:
第一部分root,结构是list集合
一般的操作都是root里边的数据
第二部分context,结构是map集合
Context处打断点,服务器debug执行,得到如下画面:
向值栈中存放数据:
- 访问action,执行action的方法有返回值,配置返回值到jsp页面中去,使用<s:debug>标签可以值栈的结构和存储值。
- Action里边也有值栈对象,但只是值栈的引用。
向值栈中放数据:
- 获取值栈对象,调用值栈中的set方法放入数据
- Map结构,根据名称获取它的值。
<s:property value=”username”/> |
- 调用值栈里边的push方法
- String结构,只有设置的值,根据数组获取它的值。
<s:property value=”[0].top”/> //表示取到数组元素的第一个值,即栈顶元素的值。 |
- 在action里边定义变量,生成get方法,可以放入值栈中。
- 可以向值栈中放入实例化的实体类对象。
- 可以向值栈中放入list集合。
- 实例化list对象
- 生成get方法
- 实例化user对象,多个,list.add();
从值栈中获取数据:
- 使用struts标签+ognl表达式获取值栈的数据
- <s:property value=”表达式”/>
- 可以获取属性值
- 可以得到对象
- 可以获取list集合
List[0].username; |
<s:iterator value=”list” > <s:property value=”username”/> </s:iterator> |
遍历list集合,得到每个user对象 机制:把每次遍历出来的user对象放到Context里边 获取context里边数据特点:写ognl表达式,使用#获取数据对象。 <s:iterator value=”list” var=”user”> <s:property value=”#user.username”/> </s:iterator> |
使用foreach标签+El表达式获取值栈元素:
- 导入jstl包+stand包
- 引入标签库
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> |
<c:forEach items="${list}" var="user"> ${user.username } ${user.password } </c:forEach> |
EL表达式获取域对象的值
向域对象里边放值使用setAttribute方法,获取值使getAttribute方法;
底层增强request对象里边的方法,getAttribute方法
首先从request域里边获取值,获取到,直接返回;
如果从request域里边获取不到值,到值栈中把值获取出来,把值方法域对象里边去;
查看源代码:
增强request方法,有多种模式,有动态代理,继承。
Class StrutsRequestWrapper extends HttpServletRequestWrapper |
Public Object getAttribute(String key) |
#的使用:值栈的context里边的数据
获取request对象的值:
<s:property value=”#request.req”/> |
%的使用:在struts2标签里边使用ognl表达式,如果直接再struts2表单标签里边使用ognl表达式不识别,只有在%之后才识别。
普通:<input type=”text” name=”username” value=”${req}”> |
Ognl:<s:textfield name=”username” value=”%{#request.req}”></s:textfield>,否则会当成字符串处理。 |
整理拦截器概述、底层原理、过滤器和拦截器的区别、自定义登录拦截器、struts2的标签库、表单标签
拦截器概述
只是struts2的概念,把框架的功能都是封装在拦截器中。
Struts2里边有很多的拦截器,不是每次所有拦截器都执行,只会执行一些默认的拦截器。
Struts2里边默认的拦截器的位置:默认的常量在core包中的default.property里边。默认的拦截器在struts-default.xml文件中。
拦截器在什么时候执行:
拦截器在action对象创建之后和action的方法执行之前
拦截器底层原理
- 拦截器的底层使用了aop的思想
- 文字描述:Aop叫做面向切面编程。有个基本的功能,想要扩展功能,不改变源代码实现。
- 流程图:
- 责任链的设计模式
- 在java中,有很多设计模式,责任链是其中一种,与web中的过滤链相似。
- 过滤链:一个请求可以有多个过滤器进行过滤,每个过滤器只有做放行操作才能到下一个过滤器。
- 要一次性执行多次操作,有添加,修改,删除操作,首先执行添加操作,做类似于放行的操作,之后依次进行。
Aop思想和责任链模式如何应用到拦截器里边
拦截器在action创建之后,在action方法执行之前执行。
在action方法执行之前使用使用拦截器,执行过程中使用使用aop思想。在action里边没有直接调用拦截器的方法,使用配置文件的方式进行操作。在struts-default.xml文件中。
在拦截器执行的时候,执行很多的拦截器,这个过程使用责任链模式。
执行action
Execute.executeAction(request,reponse,mapping); |
创建action对象,使用动态代理模式
ActionProxy proxy = getContainer.getInstance(ActionProxyFactory.class).createActionProxy( Namespace,name,method,extraContext,true,false); |
执行很多的拦截器,遍历执行,放行。
If(interceptor.hasNext()) |
执行action的方法
Proxy.execute(); Return invocation.invoke(); |
过滤器和拦截器的区别
过滤器:它可以过滤jsp,html,servlet,图片等路劲。
拦截器:它只会拦截action中的方法。
自定义登录拦截器
- 拦截器结构:
Class ModelDrivenInterceptor extends AbstractInterceptor implements Interceptor |
Void init(); Void destory(); String interceptor(ActionInvocation invocation); |
开发中建议使用继承MethodFilterInterceptor类实现 可以让action中的某个方法不进行拦截。 |
拦截器和action的关系 不是在action中调用拦截器的方法,而是通过配置文件的方式进行操作。 |
需求:在项目中,有很多action的超链接,实现只有是在登录的时候,才能点击点击action的超链接实现功能,如果不是登录状态,返回登录的界面。
使用session的域对象判断登录的状态:判断session里边是否有值。
- 实现登录的基本功能,成功之后向session中放值。
Request.getSession().setAttribute(“username”,username); |
- 添加登录拦截器的功能:判断session中是否有username的值。
|
对action方法不进行拦截:
Struts2标签库(会用)
同一行: