Struts2配置和使用

Struts2

Struts2是前端处理的框架,处理访问服务器的请求,代替servlet技术.
Struts2有着优秀的架构思想,如可插拔式设计,AOP思想等
核心是拦截器interceptor,将一些常用的功能封装在拦截器中.

Struts2架构

HttpServletRequest请求发送到ActionMapper,返回一个ActionMapping对象,包含了此次请求要访问的资源信息,ActionMapper提供了HTTP请求与Action执行之间的映射,ActionMapper会判断这个请求是否应该被Struts2处理,需要的话会继续发送到ActionProxy(Action代理)对象,通过Configuration Manager(配置的管理中心)读取Struts.xml中的配置信息,
ActionProxy汇总了请求信息和配置信息,然后使用ActionInvocation真正调用并执行Action(Struts2中的动作执行单元,用来处理用户请求并封装业务所需数据),ActionInvocation拥有一个Action实例及其依赖的拦截器实例,经过拦截器,Action,result,Template(不同视图类型的页面模版,如JSP),拦截器最后返回HttpServletResponse完成此次会话.

这里写图片描述

  • 橙色表示Servlet Filters,所有请求都要经过过滤器链的处理。
  • 浅蓝色表示Struts Core,Struts2的核心部分。
  • 浅绿色表示Interceptors,Struts2的拦截器。
  • 黄色表示User
    created,由开发人员创建,包括struts.xml,Action,Template,是每个使用Struts2进行开发的人员必须会的部分。

框架搭建流程

  1. 书写Action
  2. 配置struts.xml(放在src目录下,可以在别的包中书写多个struts.xml,通过include引入)
  3. 在web.xml中配置Struts2核心过滤器StrutsPrepareAndExecuteFilter
Struts2需要的包可以通过解压struts的zip包后,在apps中解压struts2-blank.war,在lib目录下查看
<!-- 引入其他struts配置文件 -->
    <include file="cn/itheima/b_dynamic/struts.xml"></include>

struts.xml配置

<!-- i18n:国际化. 解决post提交乱码 -->
    <constant name="struts.i18n.encoding" value="UTF-8"></constant>
    <!-- 指定访问action时的后缀名 
        http://localhost:8080/struts2Demo/hello/HelloAction.do
    -->
    <constant name="struts.action.extension" value="action"></constant>
    <!-- 指定struts2是否以开发模式运行
            1.热加载主配置.(不需要重启即可生效)
            2.提供更多错误信息输出,方便开发时的调试
     -->
    <constant name="struts.devMode" value="true"></constant>



    <!-- package:将Action配置封装.就是可以在Package中配置很多action,可以看作配置Action的容器
            name属性: 给包起个名字,起到标识作用.可以随意命名.但是不能其他包名重复.
            namespace属性:给action的访问路径中定义一个命名空间
            extends属性: 继承一个 指定包,继承包中的配置
            abstract属性:包是否为抽象的; 标识性属性.标识该包不能独立运行.专门被继承
      -->
    <package name="hello" namespace="/hello" extends="struts-default" >
        <!-- action元素:配置action类
                name属性: 决定了Action访问资源名.
                class属性: action的完整类名
                method属性: 指定调用Action中的哪个方法来处理请求
         -->
        <action name="HelloAction" class="cn.test.demo.HelloAction" method="hello" >
            <!-- result元素:结果配置 
                    name属性: 标识结果处理的名称.与action方法的返回值对应.
                    type属性: 指定调用哪一个result类来处理结果,默认使用转发.
                    标签体:填写页面的相对路径
            -->
            <result name="success" type="dispatcher" >/hello.jsp</result>
        </action>
    </package>
    <!-- 引入其他struts配置文件 -->
    <include file="cn/test/demo1/struts.xml"></include>
    <include file="cn/test/demo2/struts.xml"></include>

struts-default.xml在struts2-core-2.3.24.jar中

Struts2常量配置可以在struts2-core-2.3.24.jar/org.apache.struts2/default.properties中查看

Struts2常量配置有三种方式

1.在src下建一个struts.properties以键值对的形式配置

2.在web.xml中使用

<context-param>
    <param-name>struts.i18n.encoding</param-name>
    <param-value>UTF-8</param-value>
  </context-param>

3.在struts.xml中(常用这种)

<constant name="struts.devMode" value="true"></constant>

动态方法调用两种方式

1.在访问路径上加上!方法名.后缀名
如 xxx!save.action
使用这种方法要在struts.xml中配置一个常量

<!-- 配置动态方法调用是否开启常量
                默认是关闭的,需要开启
         -->
    <constant name="struts.enable.DynamicMethodInvocation" value="false"></constant>

2.使用通配符

<!-- 动态方法调用方式2:通配符方式
                 使用{1} 取出第一个星号通配的内容
              -->
            <action name="Demo1Action_*" class="cn.itheima.b_dynamic.Demo1Action" method="{1}" >
                <result name="success" >/hello.jsp</result>
            </action>

访问时会将*匹配的内容记录下来,然后通过{1}将匹配到的内容取出来

书写Action类

方式1:创建POJO类

//方式1: 创建一个类.可以是POJO
//POJO:不用继承任何父类.也不需要实现任何接口.
//使struts2框架的代码侵入性更低.
public class DemoAction {

}

方式2:实现Action接口

//方式2: 实现一个接口Action
// 里面有execute方法,提供action方法的规范.
// Action接口预置了一些字符串.可以在返回结果时使用.为了方便
public class Demo4ction implements Action {

    @Override
    public String execute() throws Exception {
        return null;
    }

}

方式3:继承ActionSupport

//方式3: 继承一个类.ActionSupport
// 帮我们实现了 Validateable, ValidationAware, TextProvider, LocaleProvider .
//如果我们需要用到这些接口的实现时,不需要自己来实现了.
public class DemoAction  extends ActionSupport{

}

结果处理的四种方式

  1. 转发(地址不变)
  2. 重定向
  3. 转发到Action
  4. 重定向到Action
    1.转发
<action name="Demo1Action" class="cn.test.demo.Demo1Action" method="execute" >
            <result name="success" type="dispatcher" >/hello.jsp</result>
        </action>

相当于

RequsetDispatcher dispatcher = request.getRequestDispatcher(finalLocation);
dispatcher.forward(request,response);

2.重定向

<action name="Demo2Action" class="cn.test.demo.Demo2Action" method="execute" >
            <result name="success" type="redirect" >/hello.jsp</result>
        </action>

作用相当于

response.sendRedirect(finalLocation);

3.转发到Action

<action name="Demo3Action" class="cn.itheima.a_result.Demo3Action" method="execute" >
             <result name="success" type="chain">
                    <!-- action的名字 -->
                 <param name="actionName">Demo1Action</param>
                    <!-- action所在的命名空间 -->
                 <param name="namespace">/</param>
             </result>
        </action>

4.重定向到Action

<action name="Demo4Action" class="cn.itheima.a_result.Demo4Action" method="execute" >
            <result  name="success"  type="redirectAction">
                 <!-- action的名字 -->
                 <param name="actionName">Demo1Action</param>
                 <!-- action所在的命名空间 -->
                 <param name="namespace">/</param>
            </result>
        </action>

访问ServletAPI的方式

在Strust2中,有一个内置对象叫ActionContext(数据中心),通过该对象可以获得之前Servlet中的对象,比如:requst对象,response对象等
ActionContext中包含了原生request,response,servletContext,requestScope,sessionScope,applicationScope,
attrScope,param还有valueStack(值栈)
我们需要用到这些的时候,都可以从ActionContext中获得
ActionContext可以代替request使用,生命周期和request一致,每次请求时会创建一个和请求对应的ActionContext,请求结束
后销毁,ActionContext创建后会与ThreadLocal绑定,我们可以从ThreadLocal获取,ActionContext创建,ActionContext创建时
只是把这些域收集起来,销毁时也只是销毁ActionContext,不会影响这些域原有的生命周期.

在action中获得原生ServletAPI
1.通过ActionContext

public class DemoAction extends ActionSupport {

    public String execute() throws Exception {
        //request域=> map (struts2并不推荐使用原生request域)
        //不推荐
        Map<String, Object> requestScope = (Map<String, Object>) ActionContext.getContext().get("request");
        //推荐
        ActionContext.getContext().put("name", "requestTom");
        //session域 => map
        Map<String, Object> sessionScope = ActionContext.getContext().getSession();
        sessionScope.put("name", "sessionTom");
        //application域=>map
        Map<String, Object> applicationScope = ActionContext.getContext().getApplication();
        applicationScope.put("name", "applicationTom");

        return SUCCESS;
    }
}

2.通过ServletActionContext

public class DemoAction extends ActionSupport {
    //并不推荐
    public String execute() throws Exception {
        //原生request
        HttpServletRequest request = ServletActionContext.getRequest();
        //原生session
        HttpSession session = request.getSession();
        //原生response
        HttpServletResponse response = ServletActionContext.getResponse();
        //原生servletContext
        ServletContext servletContext = ServletActionContext.getServletContext();
        return SUCCESS;
    }
}

3.通过实现接口方式

public class DemoAction extends ActionSupport implements ServletRequestAware {

    private HttpServletRequest request;

    public String execute() throws Exception { 

        System.out.println("原生request:"+request);
        return SUCCESS;
    }

    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }
}

Struts2获取参数

Action生命周期
1.每次请求到来时,都会创建一个新的Action实例
2.Action是线程安全的.可以使用成员变量接收参数

1.属性驱动获得参数

<form action="${pageContext.request.contextPath}/DemoAction">
        用户名:<input type="text" name="name" /><br>
        年龄:<input type="text" name="age" /><br>
        生日:<input type="text" name="birthday" /><br>
        <input type="submit" value="提交" />
    </form>
```
//准备与参数键名称相同的属性
    private String name;
    //自动类型转换 只能转换8大基本数据类型以及对应包装类
    private Integer age;
    //支持特定类型字符串转换为Date ,例如 yyyy-MM-dd
    private Date   birthday;

2.对象驱动

<form action="${pageContext.request.contextPath}/DemoAction">
        用户名:<input type="text" name="user.name" /><br>
        年龄:<input type="text" name="user.age" /><br>
        生日:<input type="text" name="user.birthday" /><br>
        <input type="submit" value="提交" />
    </form>
//准备user对象属性
    private User user;

3.模型驱动

<form action="${pageContext.request.contextPath}/Demo10Action">
        用户名:<input type="text" name="name" /><br>
        年龄:<input type="text" name="age" /><br>
        生日:<input type="text" name="birthday" /><br>
        <input type="submit" value="提交" />
    </form>
public class Demo10Action extends ActionSupport implements ModelDriven<User> {
    //准备user 成员变量
    private User user =new User();

    public String execute() throws Exception { 

        System.out.println(user);

        return SUCCESS;
    }

    @Override
    public User getModel() {
        return user;
    }
}

集合类型参数封装

list:<input type="text" name="list" /><br>
        list:<input type="text" name="list[3]" /><br>
        map:<input type="text" name="map['haha']" /><br>
//list
    private List<String> list;
    //Map
    private Map<String,String> map;

OGNL对象视图导航语言

例:${user.addr.name}
EL取值范围是是一个内置对象:requestScope,sessionScope,applicationScope,pageScope,pageContext,params,pagamValues,
header,headerValues,cookie,initParams
OGNL从OGNLContext中取值
OGNLContext由ROOT和Context两部分组成
Root可放置任何对象,一般放置当前访问的Action对象,Context必须是Map

//准备工作
    public void fun1() throws Exception{
        //准备ONGLContext
            //准备Root
            User rootUser = new User("tom",18);
            //准备Context
            Map<String,User> context = new HashMap<String,User>();
            context.put("user1", new User("jack",18));
            context.put("user2", new User("rose",22));
        OgnlContext oc = new OgnlContext();
        //将rootUser作为root部分
        oc.setRoot(rootUser);
        //将context这个Map作为Context部分
        oc.setValues(context);
        //书写OGNL
        Ognl.getValue("", oc, oc.getRoot());
    }

基本取值

//取出root中user对象的name属性
        String name = (String) Ognl.getValue("name", oc, oc.getRoot());
//取出context中键为user1对象的name属性
        String name = (String) Ognl.getValue("#user1.name", oc, oc.getRoot());

赋值

//将root中的user对象的name属性赋值
        Ognl.getValue("name='jerry'", oc, oc.getRoot());
String name2 = (String) Ognl.getValue("#user1.name='aa',#user1.name", oc, oc.getRoot());

调用方法

//调用root中user对象的setName方法
        Ognl.getValue("setName('aa')", oc, oc.getRoot());
        String name = (String) Ognl.getValue("getName()", oc, oc.getRoot());

        String name2 = (String) Ognl.getValue("#user1.setName('bb'),#user1.getName()", oc, oc.getRoot());

调用静态方法和静态成员变量

String name = (String) Ognl.getValue("@cn.test.demo.HahaUtils@echo('aaa!')", oc, oc.getRoot());
        Double pi = (Double) Ognl.getValue("@java.lang.Math@PI", oc, oc.getRoot());

创建对象(List,Map)

//创建list对象
        Integer size = (Integer) Ognl.getValue("{'tom','jerry','jack','rose'}.size()", oc, oc.getRoot());
        String name = (String) Ognl.getValue("{'tom','jerry','jack','rose'}[0]", oc, oc.getRoot());
        String name2 = (String) Ognl.getValue("{'tom','jerry','jack','rose'}.get(1)", oc, oc.getRoot());
Integer size2 = (Integer) Ognl.getValue("#{'name':'tom','age':18}.size()", oc, oc.getRoot());
        String name3  = (String) Ognl.getValue("#{'name':'tom','age':18}['name']", oc, oc.getRoot());
        Integer age  = (Integer) Ognl.getValue("#{'name':'tom','age':18}.get('age')", oc, oc.getRoot());

在Struts中提供了ValueStack作为ognlContext
ValueStack也由两部分组成,Root和Context
可用list来模拟栈的原理

//push压栈
list.add(0,Object);
//pop弹栈
list.remove(0);

**访问栈中属性的特点.由上到下,默认情况下,栈中放置当前访问的Action对象
Context部分就是ActionContext数据中心**

值栈对象与ActionContext对象是互相引用的,所以可以通过ActionContext获得ValueStack对象

ValueStack vs = ActionContext.getContext().getValueStack();

struts2与ognl结合的体现
1.参数接受
2.配置文件中

<action name="Demo3Action" class="cn.test.demo.Demo3Action" method="execute" >
            <result name="success" type="redirectAction" >
                <param name="actionName">Demo1Action</param>
                <param name="namespace">/</param>
                <!-- 如果添加的参数struts"看不懂".就会作为参数附加重定向的路径之后.
                     如果参数是动态的.可以使用${}包裹ognl表达式.动态取值
                 -->
                <param name="name">${name}</param>
            </result>
        </action>

3.struts2标签

<!-- 遍历标签 iterator -->
<!-- ------------------------------------- -->
<s:iterator value="#list" >
    <s:property /><br>
</s:iterator>
<!-- ------------------------------------- --><hr>
<s:iterator value="#list" var="name" >
    <s:property value="#name" /><br>
</s:iterator>
<!-- ------------------------------------- --><hr>
<s:iterator begin="1" end="100" step="1"  >
    <s:property />|
</s:iterator>
<!-- ------------------if else elseif------------------- --><hr>

<s:if test="#list.size()==4">
    list长度为4!
</s:if>
<s:elseif test="#list.size()==3">
    list长度为3!
</s:elseif>
<s:else>
    list不3不4!
</s:else>

<!-- ------------------property 配合ognl表达式页面取值 ------------------- --><hr>

<s:property value="#list.size()" />
<s:property value="#session.user.name" />

request对象的getAttribute方法查找顺序
request域->ValueStack的Root部分->ValueStack的Context部分

自定义拦截器

拦截器生命周期:随项目的启动而创建,随项目关闭而销毁
自定义拦截器的三种方式
方式一:

public class MyInterceptor implements Interceptor

方式二:

//帮我们空实现了init 和 destory方法. 我们如果不需要实现这两个方法,就可以只实现intercept方法
public class MyInterceptor2 extends AbstractInterceptor

方式三:

//继承:MethodFilterInterceptor 方法过滤拦截器
//功能: 定制拦截器拦截的方法.
//  定制哪些方法需要拦截.
//  定制哪些方法不需要拦截
public class MyInterceptor3 extends MethodFilterInterceptor{

    @Override
    protected String doIntercept(ActionInvocation invocation) throws Exception {
        //前处理
        System.out.println("MyInterceptor3 的前处理!");
        //放行
        String result = invocation.invoke();
        //后处理
        System.out.println("MyInterceptor3 的后处理!");
        //返回值,跳出循环
        return result;
    }
}

拦截器api
放行

invocation.invoke();

前后处理

//前处理
        System.out.println("MyInterceptor3 的前处理!");
        //放行
        String result = invocation.invoke();
        //后处理
        System.out.println("MyInterceptor3 的后处理!");

放行

//不执行后续的拦截器以及Action,直接交给Result处理结果.进行页面跳转
        return result;

拦截器配置

<interceptors>
    <!-- 1.注册拦截器 -->
        <interceptor name="myInter3" class="cn.test.demo.MyInterceptor3"></interceptor>
    <!-- 2.注册拦截器栈 -->
        <interceptor-stack name="myStack">
            <!-- 自定义拦截器引入(建议放在20个拦截器之前) -->
            <interceptor-ref name="myInter3">
                <!-- 指定哪些方法不拦截
                 <param name="excludeMethods">add,delete</param> -->
                 <!-- 指定哪些方法需要拦截 -->
                 <param name="includeMethods">add,delete</param>
            </interceptor-ref>
            <!-- 引用默认的拦截器栈(20个) -->
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </interceptor-stack>    
    </interceptors>
    <!-- 3.指定包中的默认拦截器栈 -->
        <default-interceptor-ref name="myStack"></default-interceptor-ref>
        <action name="Demo1Action_*" class="cn.test.demo.Demo1Action" method="{1}" >
            <!-- 为Action单独指定走哪个拦截器(栈) 
            <interceptor-ref name="myStack"></interceptor-ref>-->
            <result name="success" type="dispatcher" >/index.jsp</result>
        </action>
    </package>

步骤1:注册拦截器

<!-- 1.注册拦截器 -->
        <interceptor name="myInter3" class="cn.test.demo.MyInterceptor3"></interceptor>

步骤2:配置拦截器栈

<!-- 2.注册拦截器栈 -->
        <interceptor-stack name="myStack">
            <!-- 自定义拦截器引入(建议放在20个拦截器之前) -->
            <interceptor-ref name="myInter3">
                <!-- 指定哪些方法不拦截
                 <param name="excludeMethods">add,delete</param> -->
                 <!-- 指定哪些方法需要拦截 excludeMethods和includeMethods不能同时配置->
                 <param name="includeMethods">add,delete</param>
            </interceptor-ref>
            <!-- 引用默认的拦截器栈(20个) -->
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </interceptor-stack>

步骤3:指定包中默认拦截器栈

<default-interceptor-ref name="myStack"></default-interceptor-ref>
        <action name="Demo1Action_*" class="cn.test.demo.Demo1Action" method="{1}" >
            <!-- 为Action单独指定走哪个拦截器(栈) 
            <interceptor-ref name="myStack"></interceptor-ref>-->
            <result name="success" type="dispatcher" >/index.jsp</result>
        </action>

定制拦截方法

<!-- 指定哪些方法不拦截
                 <param name="excludeMethods">add,delete</param> -->
                 <!-- 指定哪些方法需要拦截 -->
                 <param name="includeMethods">add,delete</param>

全局结果集

<global-results>
    <result name="toLogin" type="redirect">/login.jsp</result>
</global-results>

struts2的异常处理
在package中

<!--全局异常映射-->
<global-exception-mappings>
    <exception-mapping result="error" exception="异常完整类名"/>
</global-exception-mappings>

然后在Action中配置结果页面

<result name="error">/login.jsp</result>

在页面上显示异常信息

<s:property value="exception.message">

Struts2整合spring时,要在struts.xml中配置一个常量

<!-- #  struts.objectFactory = spring   将action的创建交给spring容器    
            struts.objectFactory.spring.autoWire = name spring负责装配Action依赖属性
            -->
    <constant name="struts.objectFactory" value="spring"></constant>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值