暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Struts2入门及struts.xml的配置

Java笔记录 2019-02-22
439
Struts2入门及struts.xml配置


为什么要使用Struts2 ?


之前开发都是使用的Servlet + JSP + JavaBean,开发流程很是凌乱,Servlet在完成对用户请求的处理后,下一个页面是谁,如何跳转过去,这些都是在Servlet中完成的,导致

Servlet既要处理请求又要负责页面的流程,使得Servlet功能不够单一。


除此之外之前的开发模式导致数据传递无序,使用JavaBean传来传去,在数据嵌套的时候使用JavaBean往往感到力不从心。


缺乏辅助功能,几乎所有的东西都要从头开始,没有统一的分发调度、验证框架、国际化、本地化、例外消息处理等。


什么是Struts2 ?


Struts2其实就是基于MVC的轻量级web应用框架,所谓的框架就是能完成一部分内容的半成品软件,所谓的轻量级就是小号更少的资源而且拥有更快的速度。


来看下Struts2和MVC的关系



根据实例区分之前的开发模式与Struts2的区别


简单的注册登录系统,没有使用JavaBean,这里使用了两个

Servlet,一个是登录用的LoginServlet,如下

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if("".equals(username.trim()))
            response.getWriter().write("用户名不能为空");
        if("admin".equals(username) && "123456".equals(password))
            request.getRequestDispatcher("/login_reister/success.jsp").forward(request,response);
        else
            request.getRequestDispatcher("/login_reister/defeat.jsp").forward(request,response);
    }


另一个是注册使用的RegisterServlet,如下

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if(!username.equals("admin"))
            request.getRequestDispatcher("/login_reister/success.jsp").forward(request,response);
        else
            request.getRequestDispatcher("/login_reister/defeat.jsp").forward(request,response);
    }


上面两个登录注册页面分别对应了一个Servlet,以此来处理jsp页面的数据,相当的麻烦。


使用Struts2实现登录注册

首先使用IDEA新建struts2项目,使用外部的lib(官网下载的),目录如下所示

之后add as library即可。

别忘了一定要把web.xml改一下,把<filter-class>改成这样:

org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter


配置过的web.xml如下所示


<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>


接下来就是编写Action了,把继承了ActionSupport类的类叫做Action,Action类是处理请求的类。

用于登录注册的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;
    }

    public String login(){
        if("admin".equals(username) && "123456".equals(password)) {
            System.out.println("登录成功");
            return "success";
        }
        return "defeat";
    }
    public String register(){
        if(!("admin".equals(username))) {
            System.out.println("注册成功");
            return "success";
        }
        return "defeat";
    }



接下来就是struts.xml


<struts>
    <package name="login_register" extends="struts-default" >
        <action name="login" class="com.demo.tests.HelloAction" method="login">
            <result>success.jsp</result>
        </action>
        <action name="register" class="com.demo.tests.HelloAction" method="register">
            <result>success.jsp</result>
        </action>
    </package>
</struts>



再接着就是一个登录或者是注册表单了

<form action="login.action" method="post">
    用户名:<input type="text" name="username" ><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>


结果


可以看到和使用Servlet结果一致。


通过对比可知:
同样是登录功能,使用Servlet+JSP实现起来比较思路简单单,但是当存在多个功能需要对提交的信息进行处理时,每一个JSP页面都必须要有一个Servlet与之对应,想想就很是麻烦。使用Struts2虽然步骤可能有点多,但是工作量小了很多,登录注册功能同时实现在一个Action类中,只要编写不同的表单对应各自的action即可。


struts2工作原理和执行流程图


先放一张Struts2官方的架构图。



通过观察上图可知执行流程:

1、首先客户端提交一个HttpServletRequest请求到Tomcat服务器。


2、请求被一系列的过滤器处理,先是

ActionContextCleanUp,然后是Other Filters(如SiteMesh等),最后是FilterDispatcher过滤器。

FilterDispatcher是控制器的核心,就是MVCStruts 2实现中控制层(Controller)的核心。


3、FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个请求(HttpServletRequest),如果

ActionMapper决定调用某个Action,则FilterDispatcher把请求的处理转交给ActionProxy。


4、ActionProxy通过ConfigurationManager(也就是

struts.xml),询问框架的配置文件,找到Action。


5、ActionProxy创建一个ActionInvocation实例,同时

ActionInvocation通过代理模式调用Action,但是在调用之前ActionInvocation会根据配置加载Action相关的所有

Interceptor(拦截器)。

6、Action执行完毕后,ActionInvocation负责根据

struts.xml中的配置找到对应的返回结果result。

下面这个图更加形象的解释了Struts2的执行流程


struts.xml配置文件


package


在struts2中使用包来管理Action,这里的包和java中的包十分类似,这里的包主要用于管理一组业务功能相关的Action


package所具有的属性:

 name:必须有的,这里的包也可以继承,包的名字就是继承的关键,是引用该包的唯一标识,包名不能重复出现。

extends:可选属性,指定该包继承的父包,子包可以从父包继承到拦截器、action等配置,继承多个包时用逗号分开,一般情况下继承的都是默认包(struts-default)。

namespace:也是可选属性,定义包的命名空间,默认为"",其运用原理是package的name属性作为其唯一标识,同一个命名空间内不能出现相同name值的package,否则前面定义的package会被后面的覆盖,此时改放不同的命名空间下就可以了,处理时记得是 命名空间+Action名,例如:


<package name="login" extends="struts-default" namespace="/login">
        <action name="login" class="HelloAction" method="execute">
            <result>success.jsp</result>
            <result name="defeat">defeat.jsp</result>
        </action>
    </package>


访问时就要使用:

http://localhost:8080/login/login.action

来进行访问。


abstract:可选属性,指定此包是否是一个抽象包,如果为

true,则不能包含action。


action


action映射是框架中基本的工作单元,action映射就是将一个请求URI映射到一个action类,当一个请求匹配某个action名字时,框架就使用这个映射来确定如何处理请求。

struts.xml文件中的每一个action元素就是一个action映射。

action的name和class属性分别给给出了action的名称和Action类的位置。


一个action类处理多个请求


方法一:

method属性:可以通过method属性来指定action调用的方法,所指定的方法必须返回一个String。

实例:


<package name="login_register" extends="struts-default">
        <action name="login" class="HelloAction" method="login">
            <result>success.jsp</result>
        </action>
        <action name="register" class="HelloAction" method="register">
            <result>success.jsp</result>
        </action>
</package>


访问的时候可以这样:

<a href="login.action">登录</a>
<a href="register.action">注册</a>


方法二:

在实际应用中,随着应用程序的不断扩大,我们不得不管理数量庞大的 Action。例如,一个系统中,用户的操作可分为登录和注册两部分,一个请求对应一个 Action 的话,我们将要编写两个 Action 来处理用户请求。在具体开发过程中,为了减少 Action 的数量,通常在一个 Action 中编写不同的方法(必须遵守 execute 方法相同的格式)处理不同的请求,如编写 UserAction,其中 login()方法处理登录请求,

register()方法处理注册请求。此时可以采用动态方法调用

(Dynamic Method Invocation,DMI)来处理。动态方法调用是指表单元素的 action 并不是直接等于某个 Action 的名称。

使用格式:

<form action="Action名字!方法名字.action">  ! 后直接跟Action中方法名.action


注意: 需要配置打开动态方法调用

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


并且在result标签下还要加上<allowed-methods>调用的方法名,如果不止一个方法,方法名之间用逗号隔开。


对刚才的登录注册改善实例:

struts.xml


<struts>
    <constant name="struts.enable.DynamicMethodInvocation" value="true" />
    <package name="user" extends="struts-default" >
        <action name="user" class="com.demo.tests.HelloAction">
            <result>success.jsp</result>
            <allowed-methods>login,register</allowed-methods>
        </action>
    </package>
</struts>


以登录为例,登录表单


<form action="user!login.action">
    用户名:<input type="text" name="username" ><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="提交">
</form>


方法三:

使用通配符


随着web应用程序规模增加,所需的action也会增多,从而导致了大量的action映射,使用通配符可以减少action配置的数量,使一些具有类似行为的acting或者action的方法可以使用通用的样式来配置。 

通配符即 *,用于匹配0个或多个字符,在配置action时,可以在action元素的name属性中使用 *,类匹配任意字符,例如

<action name="user_*" class="com.demo.tests.{1}Action" method="{1}">
     <result>{1}.jsp</result>
</action>


上述映射仅仅会匹配所有的以user_开头的URI,如user_login,user_register等。

在上述配置中还有一个特殊的记号{1},这是作为占位字符使用,它将被通配符所匹配的值所替换 

在action映射和acting结果中,通配符的值可以用记号{N}来访问,N是从1-9的数字,指出替换的是哪一个通配符匹配的值,整个请求URI可以用记号{0}来访问。比如:


<action name="*_*" class="com.demo.tests.{1}Action" method="{2}">
    <result>{0}.jsp</result>
</action>


注意:使用通配符的时候也要加上<allowed-methods>

例如

 <action name="*_*" class="com.demo.tests.HelloAction" method="{2}">
       <result>success.jsp</result>
       <allowed-methods>login,register</allowed-methods>
</action>


设置默认action


如果我们请求一个不存在的 Action,那么结果将会是在页面上出现 HTTP 404 的错误。

为了解决这个问题,Struts 2 框架允许我们指定一个默认的 Action,即如果没有一个 Action

匹配请求,那么默认的 Action 将被执行。

配置默认的 Action 通过<default-action-ref…/>元素来完成


例如

 <default-action-ref name="default"></default-action-ref>
<action name="default" class="com.demo.tests.DefaultAction">
   <result>default.jsp</result>
</action>


这样就把本action设置成了默认的。


result


一个result代表了一个可能的输出,当Action类的方法执行完成时,它返回一个字符串的结果码,struts2根据这个结果码选择对应的result,向用户输出。 result元素有两个属性 

name:指定result的名称 

type:指定result的类型,不同类型的result代表了不同类型的结果输出 

在result元素中,可以使用param子元素来指定这个结果对应的实际资源的位置。param元素有一个必须的属性name,用于指定参数名,param元素的内容给出参数值。如果要指定资源的位置,name属性的值需要设置location


比如

<result name="success" type="dispatcher">
    <!-- param 元素作为result的子元素,用于为该类型的result设置参数 -->
    <param name="location">/success.jsp</param>
</result>


来看下result的type常用的都有哪些


chain:用于Action链式处理 

dispatcher:转发,相当于forward

redirect:用于重定向

redirectAction:用于重定向到另外的action映射 


1、dispatcher:请求转发,底层调用RequestDispatcher的forward()或include()方法,dispatcher是type属性的默认值,通常用于转向一个JSP,localtion指定JSP的位置,parse如果为false表示location的值不会被当作

OGNL解析,默认为true。


2、redirect:重定向,新页面无法显示Action中的数据,因为底层调用response.sendRedirect("")方法,无法共享请求范围内的数据,参数与dispatcher用法相同。


3、redirect-action:重定向到另一个Action,参数与

chain用法相同,允许将原Action中的属性指定新名称带入新Action中,可以在Result标签中添加 <param name=”b”>${a} </param>,这表示原Action中的变量a的值被转给b,下一个Action可以在值栈中使用b来操作,注意如果值是中文,需要做一些编码处理,因为Tomcat默认是不支持URL直接传递中文的。



4、chain:将action的带着原来的状态请求转发到新的

action,两个action共享一个ActionContext,actionName指定转向的新的Action的名字,method指定转向哪个方法,namespace指定新的Action的名称空间,不写表示与原Action在相同的名称空间;skipActions指定一个使用 , 连接的Action的name组成的集合,一般不建议使用这种类型的结果。


全局result


在某些场景中,可能有多个action需要访问同一个结果,例如在论坛系统中,用户在发帖、回帖、搜索帖子时都需要先登录,那么我们就可以配置一个全局的login结果,这样action就不需要一 一配置login结果了。 


比如

<global-results>
    <result name="error">/error.jsp</result>
    <result name="login" type="redirectAction">login!input</result>
</global-results>



总结
本篇主要介绍了Struts2产生的背景,学习了Struts2的较之之前的模式优点,以及struts.xml的配置。







文章转载自Java笔记录,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论