发表文章

[最新] Struts2的使用与配置文件浅析(一)

yutaostruggle 2月前 1

struts2简介

struts2是在struts1的基础上,融合了另一个web框架Webwork,已Webwork作为核心,与struts1已经有了很大的区别。struts2与springMVC都是MVC框架,区别如下:

  1. 框架机制:struts2采用Filter(StrutsPrepareAndExecuteFilter)实现,SpringMVC采用Servlet(DispatcherServlet)实现。
  2. 拦截机制:struts2框架是类级别的拦截,每次请求就会创建一个Action,和Spring整合时struts2的ActionBean注入作用域是原型模式prototype(否则会出现线程并发问题), 然后通过setter、getter将request数据注入到属性;Struts2中,一个Action对应一个request,response上下文,在接收参数时,可以通过属性接收,这说明属性参数是让多个方法共享的。SpringMVC是方法级别的拦截,一个方法对应一个Request上下文,所以方法直接基本上是独立的,独享request,response数据。而每个方法同时又何一个url对应,参数的传递是直接注入到方法中的,是方法所独有的。处理结果通过ModeMap返回给框架;与Spring整合时SpringMVC的Controller Bean默认为单例模式Singleton,因为没有共享属性所以线程是安全的
  3. 性能方面:SpringMVC可以实现零配置(注解),SpringMVC是基于方法的拦截,只加载一次单例模式bean注入。而struts2是类级别的拦截,每次请求都会创建一个新的Action实例,加载所有的属性值注入。因此SpringMVC开发效率和性能高于struts2。
  4. 拦截器:struts2有自己的拦截Interceptor机制,SpringMVC采用的是独立的Aop方式,Struts2的配置文件相对会比SpringMVC大。
  5. 配置方面:SpringMVC与Spring是无缝的,可以实现100%零配置
  6. 集成方面:SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。

Struts2架构

struts2

处理流程:

  1. 客户端发起HTTP请求
  2. 核心过滤器StrutsPrepareAndExecuteFilter拦截请求,将请求转发到Action映射器
  3. Action映射器负责识别当前请求是否需要交给Struts2处理,Action映射器返回需要Struts2处理的信息,StrutsPrepareAndExecuteFilter会创建一个Action代理
  4. Action代理通过询问配置管理器从struts.xml中获取需要调用的Action信息
  5. Action代理创建相关请求的Action对象(代理模式),调用相关的方法之前,会先执行struts2的一系列拦截器(如参数拦截器注入属性值等)
  6. 默认调用execute方法(也可以通过相关配置指定调用的方法)返回字符串去匹配响应的页面
  7. 获取模板页面渲染后生成最终返回的页面,在倒序执行拦截的方法
  8. 生成HTTP响应返回给客户端

Struts2入门案例

(1)编辑web.xml配置文件,配置struts2核心拦截器

 <!-- 配置struts2的前端控制器(Filter) -->
 <filter>
    <filter-name>s2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
 </filter>
 <filter-mapping>
    <filter-name>s2</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>

(2)编写请求表单login.jsp

<h3>${errorMessage }</h3>
<form action="login" method="post">
    UserName:<input type="text" name="userName"/><br/>
    Password:<input type="password" name="password"/><br/>
    <input type="submit" value="login"/>
</form>

(3)编写控制器Action类处理用户请求LoginAction

public class LoginAction implements Action{
    private String userName;
    private String password;

    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;
    }
    private String errorMessage;

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    @Override
    public String execute() throws Exception {
        System.out.println("before:"+this.userName);
        String userName = new String(this.userName.getBytes("iso-8859-1"),"GBK");
        System.out.println("after:"+userName);
        if("admin".equals(userName)&&"123".equals(password)){           
            ActionContext ac = ActionContext.getContext();
            Map<String,Object> request = (Map<String,Object>)ac.get("request");
            request.put("message", "requestMessage");
            return SUCCESS;
        }else{
            this.errorMessage = "用户名或者密码错误";
            return LOGIN;
        }
    }
}

(4)src目录下struts.xml中配置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>
     <package name="struts01" namespace="/" extends="struts-default">   <!--包名name随便取,namespace命名空间,extends继承struts-core包下struts-default.xml配置-->
          <!--处理login请求,默认执行execute方法-->
          <action name="login" class="com.bwf.struts01.controllers.LoginAction"  >
            <!--根据返回字符串映射响应页面-->
            <result name="success" >/welcome.jsp</result>
            <result name="login" type="redirect">/login.jsp</result>
        </action> 
     </package>
</struts>

struts2配置文件

Struts2核心配置文件是struts.xml,该文件主要负责管理业务控制器Action,
struts2还有其他配置文件通过核心过滤器的init初始化方法来加载,加载顺序如下(配置可覆盖):

    default.properties:该文件保存在struts2-core-2.3.32.jar中的org.apache.struts2包里面,保存一些常量,可以使用constant来配置。 

    struts-default.xml :该文件保存在struts2-core-2.3.32.jar中,定义了
            一些struts2的基础Bean和struts2内建支持的结果类型,还struts2内建的拦截器
            (拦截器有很多,分为一系列的拦截器块,我们默认使用defaultStack拦截器块) 

    struts-plugin.xml :该文件保存在struts-xxx-2.3.32.jar等struts2插件jar包中。 

    struts.xml:是web应用默认的自己的struts2配置文件 

    struts.properties :是struts2的默认配置文件 

    web.xml:web应用的配置文件 

struts2常量(constant)

struts2配置文件中常用常量

struts.i18n.encoding:该常量指定struts2应用默认使用的字符集。 

struts.objectFactory.spring.autoWire:和spring框架整合有关。 

struts.multipart.parser:指定文件上传用的组件。默认为jakarta(即common-fileupload上传组件) 

struts.multipart.saveDir:指定上传文件的临时保存路径  

struts.multipart.maxSize:指定上传中整个请求所允许上传的最大字节数。 

struts.action.extension:指定struts2需要处理的请求后缀。默认值为.action或者什么都不写 

struts.serve.static.browserCache:设置浏览器是否缓存静态内容,当应用处于开发阶段时,我们希望不缓存,可设置为false  

struts.enable.DynamicMethodInvocation:设置struts2是否支持动态方法调用,默认值为true 

struts.devMode:设置struts2是否使用开发模式。如果设置为true,为开发模式,修改struts.xml配置文件不需要重启服务器,会显示更多更友好的错误提示。 

struts.ui.theme:指定视图主题。 

struts.url.includeParams:指定struts2生成url时是否包含请求参数。有none,get和all三个值。分别对应不包含,仅包含get类型请求参数和包含全部请求参数。 

修改struts2常量

在struts.xml文件中配置

<constant name="struts.i18n.encoding" value="utf-8"/>
<constant name="struts.devMode" value="true"/>
<constant name="struts.action.extension" value="do"/>
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>

在web.xml文件中配置常量

<init-param>
   <param-name>struts.action.extension</param-name>
    <param-value>do</param-value>
</init-param>  

bean配置(了解即可)

struts2是一个高度可扩展的框架。框架的大部分核心组件,并不是硬编码写在代码中,而是以自己的IOC容器管理框架的核心组件。 

struts2以可配置的方式来管理核心组件,从而允许开发者很方便的扩展该框架的核心组件,当开发者需要扩展,替换核心组件时,只需要提供自己组件的实现类,将其部署在struts2的IoC容器中即可。

struts-default.xml文件中配置了大量的struts2框架的内置Bean

<struts>
    <!--
        class:必填属性。指定了Bean实例的实现类
        type:可选属性。制定了Bean实例实现的struts2规范,该规范通过某个接口实现
        name:可选属性。Bean实例的名字
        scope:可选属性。指定Bean实例的作用域request/session/singleton/thread
        static:可选属性。指定Bean是否使用静态方法注入
        optional:可选属性。指定该Bean是否是一个可选Bean
    -->
    <bean name="myHandler" class="com.bwf.struts01.exception.MyUnkownAction" type="com.opensymphony.xwork2.UnknownHandler"/>
</struts>
public class MyUnkownAction implements UnknownHandler{
    /**
     * -handleUnknownAction:用户请求未知Action时,该方法会被回调
     * -handleUnknownActionMethod:用户请求指定Action的未知方法时,该方法会被回调
     * -handleUnknownResult:Action处理结束后返回一个未知Result时,该方法会被回调 
     */

    @Override
    public ActionConfig handleUnknownAction(String namespace, String actionName) throws XWorkException {
        System.out.println(actionName+"不存在");
        return null;
    }

    @Override
    public Result handleUnknownResult(ActionContext actionContext, String actionName, ActionConfig actionConfig,
            String resultCode) throws XWorkException {
        System.out.println(resultCode+"不存在");
        return null;
    }

    @Override
    public Object handleUnknownActionMethod(Object action, String methodName) {
        System.out.println(methodName+"不存在");
        return null;
    }
}

分文件编写

实际项目中,将struts2配置文件拆分成多个配置文件来进行模块化设计,提高配合文件的可读性

<struts>
    <include file="struts1.xml"/>
    <include file="struts2.xml"/>
    .......
</struts>   

package配置

 <!--
      name:必选属性。配置包名,是包的唯一标识
      extends:可选属性。表示继承其他包,一般指定继承struts-default
      abstract:可选属性。指定该包是否为抽象包,抽象包不可定义Action
      namespace:可选属性。定义命名空间,用于分模块,同一命名空间不可定义同名的Action;请求url会带有命名空间,默认命名空间为""
      strict-method-invocation:可选属性。struts 2.5默认为true,用于限制DynamicMethodInvocation,
          未通过method属性配置或<allowed-methods>标签标明的方法将不允许被访问,启用DMI需要设置为false,
  -->
  <package name="demo" extends="struts-default" abstract="false" namespace="" strict-method-invocation="true">
  </package>

命名空间的匹配优先级为:精准命名空间 > 根命名空间 > 默认命名空间。

package内部配置

 <package name="demo" extends="struts-default" abstract="false" namespace="/" strict-method-invocation="true">

        <!--result类型和处理类,默认的有chain、dispatcher、freemarker、httpheader、redirect、redirect、
        Action、stream、velocity、xslt、plainText、postback-->
        <result-types>
            <result-type name="" class=""></result-type>
        </result-types>

        <!--注册拦截器和拦截器栈-->
        <interceptors>
            <!--拦截器-->
            <interceptor name="" class=""/>
            <!--拦截器栈-->
            <interceptor-stack name="">
                <interceptor-ref name=""/>
            </interceptor-stack>
        </interceptors>

        <!--默认拦截器或拦截器栈配置,默认为defaultStack-->
        <default-interceptor-ref name="defaultStack"/>

        <!--当没有Action匹配时,使用默认Action-->
        <default-action-ref name="fileDl"/>

         <!--当Action没有配置class时,使用ActionSupport处理-->
        <default-class-ref class="com.opensymphony.xwork2.ActionSupport"/>

        <!--全局result配置-->
        <global-results>
            <result name="success" type="redirect">/success.jsp</result>
            <result name="error" type="dispatcher">/error.jsp</result>
        </global-results>

        <!--全局可访问的方法,配置Action可访问的方法,中间用逗号隔开-->
        <global-allowed-methods>execute,input</global-allowed-methods>

        <!--全局异常映射,发生对应异常时返回result-->
        <global-exception-mappings>
            <exception-mapping exception="java.sql.SQLException" result="error"></exception-mapping>
        </global-exception-mappings>

        <!--Action配置-->
        <action name="login" class="com.bwf.struts01.controllers.LoginAction" method="execute" converter="">
            <!--参数注入-->
            <param name="username">yt</param>
            <!--当前Action结果result映射-->
            <result name="success" type="redirect">/success.jsp</result>
            <!--使用自定义拦截器,默认拦截器栈会失效,因此需要引用-->
            <interceptor-ref name="defaultStack"/>
            <interceptor-ref name="">
                <param name=""></param>
            </interceptor-ref>
            <!--当前Action中异常处理-->
            <exception-mapping exception="java.lang.ArrayIndexOutOfBoundsException" result="error"/>
            <!--当前Action允许的访问的方法-->
            <allowed-methods>execute</allowed-methods>
        </action>

    </package>

上述配置后续会逐步讨论

Struts2的Action

Action是业务控制器,负责处理用户的请求,需要在struts.xml中配置。

Action的创建

(1)采用低侵入的方式创建,不需要实现或继承任何接口和类

public class SimpleAction {
    public String execute() throws Exception{
        System.out.println("in SimpleAction#execute...");
        return Action.SUCCESS;
    }
}

(2)实现Action接口,Action接口定义了五个常量和execute方法

public interface Action {
    String SUCCESS = "success";
    String NONE = "none";
    String ERROR = "error";
    String INPUT = "input";
    String LOGIN = "login";

    String execute() throws Exception;
}

(3)继承Action接口的实现类ActionSupport,该类提供了很多的默认方法,包括获取国际化信息,数据校验的方法等。大大简化了Action的开发。(推荐

Action的调用

无论何种方式创建的Action,当我们请求Action时都会默认调用它的execute方法,当然我们也可以通过配置来执行我们指定的方法。

method属性

public class UserAction extends ActionSupport{
    public String selectUser() {
        return "success";
    }
    public String addUser() {
        return "success";
    }
    public String delUser() {
        return "success";
    }
    public String updateUser() {
        return "success";
    }
}
<!--struts.xml中配置Action-->

<struts>
   <package name="user" namespace="/user" extends="struts-default">
       <action name="selectUser" class="com.bwf.struts01.controllers.UserAction" method="selectUser">
           <result name="success">/welcome.jsp</result>
           <result name="error">/error.jsp</result>
       </action>
       <action name="addUser" class="com.bwf.struts01.controllers.UserAction" method="addUser">
           <result name="success">/welcome.jsp</result>
           <result name="error">/error.jsp</result>
       </action>
       <action name="delUser" class="com.bwf.struts01.controllers.UserAction" method="delUser">
           <result name="success">/welcome.jsp</result>
           <result name="error">/error.jsp</result>
       </action>
       <action name="updateUser" class="com.bwf.struts01.controllers.UserAction" method="updateUser">
           <result name="success">/welcome.jsp</result>
           <result name="error">/error.jsp</result>
       </action>
   </package>
</struts>

由上面配置我们发现随着Action的增多,配置文件相当的冗余,struts2提供了通配符来解决上述问题。

通配符

特殊符号 意义
* 匹配除了斜杠(’/’)字符之外的零个或多个字符
** 匹配零个或多个字符,包括斜杠(’/’)字符
\ 反斜线字符用作转义序列,所以\*匹配字符星号(*),\\匹配字符反斜杠(\)

之前的配置可使用通配符合成如下配置

 <!--通配符*尽量放在末尾,否则可能会引起一些bug-->
 <action name="user*" class="com.bwf.struts01.controllers.UserAction" method="{1}User">
    <result name="success">/{1}.jsp</result>
     <result name="error">/error.jsp</result>
 </action>

{n}表示第几个通配符,n的范围是0~9,其中0表示完整的请求路径,如useradd。如果希望Action的name属性包含/,需要配置常量<constant name="struts.enable.SlashesInActionNames" value="true"/>,但是一般不建议这样做。

需要注意的:

  1. 使用通配符方法映射和使用!符号的“动态方法调用”可能会重叠,需要禁用动态调用
  2. .对于Struts2.3之前的版本可以不配置<allowed-methods>,但是对于之后的版本需要配置<allowed-methods>,负责无法访问

动态方法调用

启用动态方法调用(Dynamic Method Invocation)需要配置常量,官方文档说,DMI存在安全性问题,因此默认是关闭的

<constant name="struts.enable.DynamicMethodInvocation" value="true" />

动态调用url格式为:actionName!methodName

struts 2.3以后使用动态调用需要配置package属性strict-method-invocation="false",或者global-allowed-methodsallowed-methods指定允许访问的方法。

Action中访问Servlet API

(1)通过ActionContext的子类ServletActionContext访问

@Override
public String execute() throws Exception {
    PageContext pageContext = ServletActionContext.getPageContext();
    HttpServletRequest request = ServletActionContext.getRequest();
    HttpSession session = request.getSession();
    ServletContext servletContext = ServletActionContext.getServletContext();
    HttpServletResponse response = ServletActionContext.getResponse();
    return "success";
}

(二)实现ServletContextAware,ServletRequestAware,ServletResponseAware三个接口(是不是与Spring的Aware接口很相似),它是通过struts内建拦截器ServletConfig通过instanceof判断Action是否属于ServletContextAware,ServletRequestAware,ServletResponseAware类型,并且调用其setter方法

public class ServletAPIAction extends ActionSupport implements ServletContextAware,ServletRequestAware,ServletResponseAware { 
   //定义三个参数
    private HttpServletRequest request;
    private HttpServletResponse response;
    private ServletContext context;

    public String execute() throws Exception {

        return null;
    } 
    //实现接口中设置参数的方法
    @Override
    public void setServletResponse(HttpServletResponse response) {
        this.response=response;

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

    }
    @Override
    public void setServletContext(ServletContext context) {
        this.context=context;

    }
}

result处理

当Action处理完用户请求都会返回一个字符串,该字符串通过<result…>进行配置,根据其结果类型做出不同的处理。

struts内建结果类型

struts的内建的结果类型配置在struts-default.xml的<result-types>中

    -chain:Action链式处理。当一个Action处理完成之后,系统并不想转发到视图资源,而是希望下一个Action进行处理,此时就需要这个类型。  

    -dispatcher:请求转发到JSP/HTML等视图,默认结果类型

    -redirect:重定向到视图

    -redirectAction:重定向到其他Action 

    -stream:向浏览器返回一个InputStream的结果类型(一般用于文件下载)

    -freemarker:返回freemarker视图

    -velocity:返回velocity视图

    -xslt:返回xml/xslt视图

    -plainText:用于显示某个页面原始代码

    -httpheader:返回http请求头信息

    -postback:将请求参数以form的形式提交到指定地点

对于不同包之间的请求转发或重定向,我们可以注入actionName和namespace属性

<package name="test" extends="struts-default">

    <action name="demo1" class="com.cad.struts2.Hello" >
        <result type="chain"> 
            <param name="actionName">demo2</param>
            <param name="namespace">/user</param>
        </result>
    </action>

</package> 
<package name="test1" extends="struts-default" namespace="/user">
    <action name="demo2" >
        <result name="success" >/success.jsp</result>
        <result name="error">/error.jsp</result>
    </action>
</package> 

自定义结果类型

(1)继承StrutsResultSupport类

public class ImageResult extends StrutsResultSupport {

    @Override
    protected void doExecute(String s, ActionInvocation actionInvocation) throws Exception {
        FileInputStream fis = new FileInputStream("E:\\java\\javasrc\\javaweb\\struts01\\WebContent\\WEB-INF\\classes\\WEB-INF\\files\\channel.png");
        ServletOutputStream out = ServletActionContext.getResponse().getOutputStream();
        int len = -1;
        while ((len = fis.read())!=-1) {
            out.print((char)len);
            out.flush();
        }
        out.close();
        fis.close();
    }
}

(2)编写Action

public class ImageAction extends ActionSupport {
}

(3)注册自定义结果类型和Action

 <package name="result" namespace="/result" extends="struts01">
    <result-types>
        <result-type name="image" class="com.bwf.struts01.result.ImageResult"></result-type>
    </result-types>

    <action name="image" class="com.bwf.struts01.controllers.ImageAction">
        <result name="success" type="image"></result>
    </action>
 </package>

定义全局的result和结果类型

由于在struts01包中定义的result-type只能在struts01包及其子包中使用,因此result包继承struts01包即可。global-results配置全局的result。

<package name="struts01" namespace="/" extends="struts-default">
     <result-types>
         <result-type name="image" class="com.bwf.struts01.result.ImageResult"></result-type>
     </result-types>
     <global-results>
         <result name="success" type="image">
            <param name="width">100</param>
             <param name="height">100</param>
         </result>
     </global-results>
</package>
相关推荐
最新评论 (0)
返回
发表文章
yutaostruggle
文章数
39
评论数
0
注册排名
795891