Web笔记-Struts2一

Struts2简介(摘自百度)

struts是开源框架。使用Struts的目的是为了帮助我们减少在运用MVC设计模型来开发Web应用的时间。如果我们想混合使用Servlets和JSP的优点来建立可扩展的应用,struts是一个不错的选择。Struts 是Apache软件基金会(ASF)赞助的一个开源项目。它最初是Jakarta项目中的一个子项目,并在2004年3月成为ASF的顶级项目。它通过采用JavaServlet/JSP技术,实现了基于JavaEEWeb应用的MVC设计模式的应用框架,是MVC经典设计模式中的一个经典产品。
一句话:Struts2是MVC框架的一个实现。Struts2是由Struts+Webwork组成。核心是Webwork。

环境搭建
  • jar包拷贝:
    以struts-2.5.12为例,需要我们导入如下jar包:
    commons-fileupload-1.3.3.jar
    commons-io-2.4.jar
    commons-lang3-3.6.jar
    commons-logging-1.1.3.jar
    freemarker-2.3.23.jar
    javassist-3.20.0-GA.jar
    log4j-core-2.8.2.jar
    log4j-api-2.8.2.jar
    ognl-3.1.12.jar
    struts2-core-2.5.12.jar

  • 配置控制器:web.xml添加struts预处理执行过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>Struts2-HelloWorld</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
  • src根目录中创建添加struts.xml配置文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
<?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" />
<package name="xx" extends="struts-default">
<action name="xxx" class="cn.imeina.struts2.action.HelloStruts"
method="xxxx">
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
  • 启动tomcat
Struts执行过程

Struts UML执行流程

  • struts.xml是何时被加载?应用被启动时。
  • 动作类的生命周期:每次请求都会重新实例化。
  • StrutsPrepareAndExecuteFilter过滤所有资源:并非所有资源都会进入struts2框架。
    默认:请求地址以action或者没有后缀的动作会进入。
  • Struts框架配置文件及其加载顺序
加载顺序 配置文件的名称 所在位置 说明
1 default.properties struts2-core-2.5.12.jar/org/apache/struts包中 不能修改
2 struts-default.xml struts2-core-2.5.12.jar包中 不能修改
3 struts-plugin.xml struts2-*-plugin.jar struts2插件的jar包中,不能修改
4 struts.xml 应用的classpath’s top 我们可用
5 struts.properties 应用的classpath’s top 我们可用
6 web.xml 应用的WEB-INF目录中 我们可用

后面的会覆盖前面的,推荐使用配置文件struts.xml

Struts框架中struts.xml配置
  • package元素
    作用:使动作配置分包管理,如同java类分包;
    属性:
  1. name:必须的、唯一的、包的名称;
  2. extends:struts2种允许包与包之间继承。比如:p2包继承p1包,p2包就可以使用p1包中的所有配置信息。一般需要继承struts-default包;
    struts-default在struts-default.xml配置中定义;
    
1
2
3
4
<package name="struts-default" abstract="true">
<result-types></result-types><!-- 结果类型 -->
<interceptors></interceptors><!-- 拦截器 -->
</package>
  1. abstract:如果一个包中,没有元素,可以将包申明为抽象的,抽象包是用来被继承的;
  2. namespace:命名空间。一般取值为“/”开头的字符串。命名空间+包中的动作名称共同组成了访问路径。默认值是“”(而不是/)。
    • Default Namespace:
      The default namespace is “” - an empty string.
    • Root Namespace:
      A root namespace (“/“) is also supported.
    • Namespace Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<package name="default">
<action name="foo" class="mypackage.simpleAction">
<result name="success" type="dispatcher">greeting.jsp</result>
</action>
<action name="bar" class="mypackage.simpleAction">
<result name="success" type="dispatcher">bar1.jsp</result>
</action>
</package>
<package name="mypackage1" namespace="/">
<action name="moo" class="mypackage.simpleAction">
<result name="success" type="dispatcher">moo.jsp</result>
</action>
</package>
<package name="mypackage2" namespace="/barspace">
<action name="bar" class="mypackage.simpleAction">
<result name="success" type="dispatcher">bar2.jsp</result>
</action>
</package>

struts框架查询动作流程

  • action元素
    作用:配置动作
    属性:
  1. name:动作名称。
  2. class:类的全路径(框架会通过反射来进行类的实例化)
    该属性可以不配置,它默认执行的是com.opensymphony.xwork2.ActionSupport中的execute()方法;
    ActionSupport类实现了Action接口实现了其execute()方法,并默认返回了SUCCESS常量字符串;
  3. method:动作方法名称。可以不配置,默认执行ececute()方法;
    动作方法执行前会经过很多的拦截器(AOP面向切面编程)。虽然没有配置,但是有默认的拦截器起作用(struts-default.xml中有配置)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="debugging"/>
</interceptor-stack>
<interceptor-stack name="completeStack">
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
  • constant元素
    作用:覆盖框架已经定义好的常量值:
    属性:
    name:常量名称
    value:常量值
    常量值存在于default.properties文件中(struts2-core-2.xxx.jar/org/apache/struts包中)
    开发常用的常量值:
常量名称 取值 说明
struts.devMode true/false 开启开发模式。该模式开启后配置文件修改后会自动加载,出错时可打印错误信息。
struts.i18n.reload true/false properties文件修改后会自动加载
struts.configuration.xml.reload true/false xml修改后会自动加载
struts.action.extension action,, struts2框架处理的uri后缀。默认是action或者没有,可以配置多个值,用逗号分隔
struts.i18n.encoding UTF-8 struts2框架默认编码,自己可修改
struts.objectFactory.spring.autoWire name 与spring集成使用
struts.multipart.maxSize 2097152: 2M Struts中进行文件上传时文件大小限制
struts.serve.static.browserCache true/false 是否允许浏览器进行缓存静态资源
struts.enable.DynamicMethodInvocation true/false 是否允许动态方法调用
struts.ui.theme xhtml Struts2标签库中默认使用的样式主题
struts.ui.templateDir template 样式模版存在什么文件夹中
struts.objectFactory spring 与spring集成使用
  • include元素
    把所有配置都放到struts.xml有以下缺点:
  1. 所有配置都在一个文件,会显的凌乱。
  2. 代码管理部方便,容易导致冲突产生。
    可以使用include元素
    1
    2
    3
    <include file="user.xml"></include>
    <include file="xxx.xml"></include>
    ...
  • result元素
    作用:用来产生结果输出
    属性:
    name:逻辑视图名称。它的值和当前动作方法返回值对应。默认值是”success”
    type:结果类型。默认是”dispatcher”,请求转发。
    常用结果类型:
    在struts-default.xml中struts-default的package中有定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<package name="struts-default" abstract="true" strict-method-invocation="true">
<result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/><!-- 动作执行完毕后,转发到另外一个动作类 -->
<result-type name="dispatcher" class="org.apache.struts2.result.ServletDispatcherResult" default="true"/><!-- 动作执行完毕后,使用转发技术转发到指定页面 -->
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
<result-type name="httpheader" class="org.apache.struts2.result.HttpHeaderResult"/>
<result-type name="redirect" class="org.apache.struts2.result.ServletRedirectResult"/><!-- 动作执行完毕后,使用重定向到指定页面 -->
<result-type name="redirectAction" class="org.apache.struts2.result.ServletActionRedirectResult"/><!--动作执行完毕后,使用重定向到另一个action-->
<result-type name="stream" class="org.apache.struts2.result.StreamResult"/><!-- 动作执行完毕后,转向一个输出流(文件下载中用到) -->
<result-type name="velocity" class="org.apache.struts2.result.VelocityResult"/>
<result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
<result-type name="plainText" class="org.apache.struts2.result.PlainTextResult" />
<result-type name="postback" class="org.apache.struts2.result.PostbackResult" />
</result-types>
</package>
  • param元素
    作用:用于配置参数。
    属性:可在result标签的type属性对应的类中查找对应的name值。
1
2
3
4
5
6
7
8
9
10
<package name="p2" namespace="/" extends="struts-default">
<action name="demo2">
<result type="dispatcher">/success.jsp</result>
<!-- 该写法和上面写法效果相同 -->
<result type="dispatcher">
<!-- dispatcher对应的类为:org.apache.struts2.result.ServletDispatcherResult,在该类中可找到location变量-->
<param name="location">/success.jsp</param>
</result>
</action>
</package>
Struts2中的动作类
  • 动作类的编写:
  1. 方式一:动作类就是一个普通的JavaBean(POJO:Plain Old Java Object)

    1
    2
    3
    4
    5
    6
    public class HelloAction{
    //动作方法公有,必须返回String
    public String sayHello(){
    return "success";
    }
    }
  2. 方法二:动作类实现com.opensymphony.xwork2.Action接口
    该接口中的内容:

常量名称 对应字符串 说明
SUCCESS “success” 转向成功页
NONE “none” 不转向任何页
ERROR “error” 转向错误页
INPUT “input” 回显时使用
LOGIN “login” 转向登录页
String execute() 默认动作方法
1
2
3
4
5
6
7
8
9
10
11
12
public class HelloAction implements Action{
public String sayHello(){
return SUCCESS;
}
public String execute() throws Exception{
return null;
}
}
  1. 方法三:继承com.opensymphony.xwork2.ActionSupport类(推荐使用该方式)
    1
    2
    3
    4
    5
    6
    7
    public class HelloAction extends ActionSupport{
    public String sayHello(){
    return SUCCESS;
    }
    }
  • 动作方法的调用:
  1. 动作类的生命周期:每次访问都会由框架进行类的实例化(多例,不会导致线程安全问题)。
  2. 请求的动作是什么?动作类中需要编写对应的动作方法。
  3. 通配符*。
    使用方式一:
    若访问路径为:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    http://localhost:8080/project/user/add.action
    http://localhost:8080/project/user/edit.action
    http://localhost:8080/project/user/delete.action
    http://localhost:8080/project/user/query.action
    <package name="p2" namespace="/user" extends="struts-default">
    <action name="*" class="cn.imeina.struts2.action.UserAction" method="{1}">
    <result name="success">/{1}.jsp</result>
    </action>
    </package>

使用方式二:

1
2
3
4
5
6
7
8
9
10
11
若访问路径为:
http://localhost:8080/project/user/UserAction_add.action
http://localhost:8080/project/user/UserAction_edit.action
http://localhost:8080/project/user/UserAction_delete.action
http://localhost:8080/project/user/UserAction_query.action
<package name="p2" namespace="/user" extends="struts-default">
<action name="*_*" class="cn.imeina.struts2.action.{1}" method="{2}">
<result name="success">/{2}.jsp</result>
</action>
</package>

  1. DMI:动态方法调用。Dynamic Method Invocation。(不建议使用,容易暴露动作类中的方法)
    在Struts2中动态方法调用,默认是关闭的,需要手动打开。该参数在default.properties中有配置,我们只需覆盖该配置即可。配置如下:
1
2
<!-- 开启动态方法调用-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>

使用:

1
2
3
4
5
6
7
8
9
10
11
若访问路径为:
http://localhost:8080/project/user/userAction!add.action
http://localhost:8080/project/user/userAction!edit.action
http://localhost:8080/project/user/userAction!delete.action
http://localhost:8080/project/user/userAction!query.action
<package name="p2" namespace="/user" extends="struts-default">
<action name="userAction" class="cn.imeina.struts2.action.UserAction">
<result name="success">/success.jsp</result>
</action>
</package>

动作类中访问ServletAPI
  • Struts2优点:
  1. 与Servlet深度解耦。
  2. 动作方法中要使用ServletAPI(ServletContext、ServletRequest、HttpSession)
  • 使用方法:
  1. 方式一:推荐,简单易用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package cn.imeina.struts2.action;
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import org.apache.struts2.ServletActionContext;
    import com.opensymphony.xwork2.ActionSupport;
    public class StrutsAcceessServletAPI extends ActionSupport {
    private static final long serialVersionUID = 1L;
    @Override
    public String execute() throws Exception {
    //或得当前应用的真实路径
    ServletContext sContext = ServletActionContext.getServletContext();
    sContext.setAttribute("tag", 0);//向应用范围内存放数据
    System.out.println("应用真实路径:" + sContext.getRealPath("/"));
    //获取HttpServletRequest对象
    HttpServletRequest request = ServletActionContext.getRequest();
    request.setAttribute("name", "admin");
    //获取HttpSession实例
    HttpSession session = request.getSession();
    session.setAttribute("username", "zhangsan");
    return SUCCESS;
    }
    }
  2. 方式二:解耦方式。通过依赖注入对象的形式注入进来(DI:Dependce Injection)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package cn.imeina.struts2.action;
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import org.apache.struts2.interceptor.ServletRequestAware;
    import org.apache.struts2.util.ServletContextAware;
    import com.opensymphony.xwork2.ActionSupport;
    public class StrutsAcceessServletAPI2 extends ActionSupport implements ServletContextAware, ServletRequestAware{
    private static final long serialVersionUID = 1L;
    private ServletContext context;
    private HttpServletRequest request;
    @Override
    public String execute() throws Exception {
    context.setAttribute("p1", "你好啊");
    request.setAttribute("p2", "你好!");
    request.getSession().setAttribute("p3", "再见哈哈!");
    return SUCCESS;
    }
    //该方法会在动作方法执行之前由框架调用将ServletContext实例注入进来
    @Override
    public void setServletContext(ServletContext context) {
    this.context = context;
    }
    @Override
    public void setServletRequest(HttpServletRequest request) {
    this.request = request;
    }
    }

原理:执行Action动作之前,由servletConfig拦截器进行对象注入。可在rg.apache.struts2.interceptor.ServletConfigInterceptor过滤器中国年查看。

ActionContext操作域对象中的数据

com.opensymphony.xwork2.ActionContext

  • 生命周期:

诞生:用户发出请求时,就创建ActionContext的实例,存放到ThreadLocal中。
活着:一次请求范围中。
死亡:响应结束。

  • 向三个域范围中存放数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package cn.imeina.struts2.action;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class StrutsAcceessServletAPI3 extends ActionSupport {
private static final long serialVersionUID = 1L;
@Override
public String execute() throws Exception {
//获取ActionContext实例,并向请求范围内存放数据
ActionContext actionContext = ActionContext.getContext();
actionContext.put("rp", "rp");
//获取session中的所有属性的map集合,并向session中存放数据
Map<String, Object> sessionAttributes = actionContext.getSession();
sessionAttributes.put("sp", "sp");
//向应用范围存放数据
Map<String, Object> applicationAttributes = actionContext.getApplication();
applicationAttributes.put("ap", "ap");
return SUCCESS;
}
}
如果帮到了你,想打赏支持,喏~