Struts2 请求响应流程及创建步骤
最近在对Struts2框架的项目进行源代码业务逻辑漏洞分析,趁机把之前学的struts2、自己对struts的简单理解整理一下。有不对的地方还请各位看官大神多指教。
对于新项目开发,不建议使用Struts2框架,其含有太多的漏洞,如Struts2-045远程命令执行、S2-057远程命令执行等高危漏洞。
一、简介
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互,Struts2在Struts1融合webwork。
ONGL表达式:就是对象图形化导航语言,在前端页面中,访问action的属性、方法;类似于对JSP的封装,使得编程更加方便。
工作流程:
(1)客户端浏览器发送HTTP请求到Web应用
(2)Web容器将请求传递到标准ActionContextCleanUp过滤器以消除属性,而不让后续过滤器清楚,以延长Action中属性(包括自定义属性)的生命周期。
(3)再经过如StiMesh等其他过滤器后,请求传递给StrutsPrepareAndExecuteFilter核心控制器
(4)StrutsPrepareAndExecuteFilter调用ActionMapper(Action映射器)确定调用哪个Action,再将控制权转移给ActionProxy代理
(5)ActionProxy代理调用配置管理器ConfigurationManager从配置文件struts.xml中读取配置信息,然后创建ActionInvocation对象
(6)ActionInvocation在调用拦截器链中的拦截器后再调用Action,根据Action返回的结果字符串查找对应的Result
(7)Result调用视图模板,再以相反的顺序执行拦截器链,返回HTTP响应
(8)HTTP响应以相反的顺序返回给核心控制器StrutsPrepareAndExecuteFilter以及其他web.xml中定义的过滤器,最终返回给客户端。
二、创建过程
(一)创建Dynamic Web Project,记得选择“Generate web.xml deployment descriptor”
(二)拷贝相关struts2的jar包,加入项目中
(三)web.xml中配置struts2,即配置filter和filter-mapping
<filter>
<filter-name>Struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(四)创建struts2.xml文件(非注解,传统方式)
struts2.xml文件头配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
根据下文实际情况,配置Action、interceptor等。
(五)创建Action,继承ActionSupport,如果涉及参数传递,建议通过实现ModelDriven<T>,封装对象实现。
创建用户操作Action:UserAction
public class UserAction extends ActionSupport implements ModelDriven<User> {
public User user = new User();
public String login() throws Exception {
// 封装User
// 调用UserService中的判断用户是否存在的方法
UserService userService = new UserService();
boolean isSuccess = userService.findUser(user);
// 拿到返回值
if (isSuccess) {
// 成功 跳转到获取所有帖子的请求 在session域中放置user对象
ActionContext.getContext().getSession().put("user", user);
return "getAllPaste";
} else {
// 失败 添加错误信息 转发到登录界面login.jsp
ActionContext.getContext().put("error", "用户名或者密码错误!!");
return "login";
}
}
@Override
public User getModel() {
// TODO Auto-generated method stub
return user;
}
}
创建帖子操作Action:PasteAction
public class PasteAction extends ActionSupport {
public String getAllPaste() throws Exception {
PasteService pasteService = new PasteService();
List<Paste> pasteList = pasteService.findAllPaste();
ActionContext.getContext().put("pasteList", pasteList);
return "paste";
}
}
(六)在struts2.xml文件中,配置上述两个Action(采用“动态方法”调用)
1、开启动态方法调用:
<constant name="struts.devMode" value="true" />
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
2、允许动态方法调用的方法设置:
package下设置:<global-allowed-methods>regex:.*</global-allowed-methods>,代表所有方法均允许动态调用。
一个响应后,有四种处理方式:转发、重定向、转发到Action、重定向到Action。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<package name="fourm" namespace="/" extends="struts-default">
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="UserAction_*" class="com.xm.web.UserAction" method="{1}">
<!-- 转发到Action -->
<!-- <result name="getAllPaste" type="chain">PasteAction_getAllPaste</result> -->
<!-- 重定向到Action -->
<result name="getAllPaste" type="redirectAction">PasteAction_getAllPaste</result>
<!-- 转发 -->
<result name="login">/login.jsp</result>
</action>
<action name="PasteAction_*" class="com.xm.web.PasteAction" method="{1}">
<result name="paste">/paste.jsp</result>
</action>
</package>
</struts>
(七)创建拦截器,继承MethodFilterInterceptor,实现doIntercept方法
public class UserIntercept extends MethodFilterInterceptor {
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
// 获取session
Map<String, Object> session = ActionContext.getContext().getSession();
// 判断session域中是否有user
Object object = session.get("user");
if (object == null) {
// 没有-->重定向到login.jsp
return "toLogin";
} else {// 如果有-->放行
return invocation.invoke();
}
}
}
(八)在struts2.xml文件中,配置上述拦截器,在package中
1) 配置拦截器:<interceptors>...</interceptors>
2)注册拦截器:<interceptor...></interceptor>
3)注册拦截器栈:<interceptor-stack name="myStack">...</interceptor-stack>
4)指定拦截器:<default-interceptor-ref name="myStack"></default-interceptor-ref>
5) 配置全局结果集,避免对每个Action都配置。<global-results>...</global-results>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.devMode" value="true" />
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<package name="fourm" namespace="/" extends="struts-default">
<!-- 配置拦截器 -->
<interceptors>
<!-- 注册拦截器 -->
<interceptor name="UserIntercept" class="com.xm.web.intercept.UserIntercept"></interceptor>
<!-- 注册拦截器栈 -->
<interceptor-stack name="myStack">
<!-- 引入自己的拦截器 -->
<interceptor-ref name="UserIntercept">
<param name="excludeMethods">login</param><!-- 不拦截该请求 -->
</interceptor-ref>
<!-- 引入struts自带的拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 指定默认拦截器栈 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
<!-- 配置全局结果集 -->
<global-results>
<!-- 重定向 -->
<result name="toLogin" type="redirect">/login.jsp</result>
</global-results>
<global-allowed-methods>regex:.*</global-allowed-methods>
<action name="UserAction_*" class="com.xm.web.UserAction" method="{1}">
<!-- 转发到Action -->
<!-- <result name="getAllPaste" type="chain">PasteAction_getAllPaste</result> -->
<!-- 重定向到Action -->
<result name="getAllPaste" type="redirectAction">PasteAction_getAllPaste</result>
<!-- 转发 -->
<result name="login">/login.jsp</result>
</action>
<action name="PasteAction_*" class="com.xm.web.PasteAction" method="{1}">
<result name="index">/index.jsp</result>
</action>
</package>
</struts>
三、其他内容
(一)Struts2注解开发(现阶段主流)
1. xml文件与注解互换
@Namespace来代替<package namespace=””>
@ParentPackage来代替<package extends=””>
@Action来描述关于<action>配置
value属性<action name=””>
使用@Action的results来描述关于结果类型的配置<result>
<result name=”” type=””>
@Action(results={@Result(name=””,type=””,location=””)})
2. 其他注解
@Actions
作用:可以通过多个映射来访问同一个action;
@Results
类似于全局的结果视图;
@InterceptorRef
它是用于处理拦截器的。
(二)OGNL表达式
OGNL是Object-Graph Navigation Language(对象图导航语言)的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。
Struts2框架内置了OGNL,OGNL本身也是一个项目,它是可以单独使用。
OGNL作用:
支持对象的操作,调用对象的方法;
支持静态成员访问;
支持赋值操作与表达串联;
访问OGNL上下文,访问ActionContext;
操作集合对象。
Strtus2框架中如何使用ognl表达式
在struts2框架中我们使用ognl表达式的作用是从valueStack中获取数据,在struts2框架中可以使用ognl+valueStack达到在页面(jsp)上来获取相关的数据,要想在jsp页面上使用ognl表达式,就需要结合struts2框架的标签<s:property value=”表达式”>来使用。