SSH开发模式——Struts2(第三小节)

struts2框架的知识点,虽然分了几个小节,感觉内容还是挺多的,但是你仅仅是入门了而已,想要进一步地提升自己,你得有一颗持之以恒的学习的心,最后的内容我都将在这篇博客中讲到,所以篇幅可能会有点长,希望大家能够耐心阅读。

首先介绍一下struts2的配置。
还记得我们创建的test.jsp文件吗?直接看到这篇博客的同学们也不用去翻阅我之前的博客,因为我在之前的博客中只是简单地介绍了使用,而并没有深入,我并没有讲解每一步的作用,和为什么要这样写。所以,直接从该篇博客开始阅读学习也是可以的,我将从最基础的配置开始重新进行讲解,并讲述每一步的作用、原因。

那么test.jsp文件里的代码很简单,就是一个超链接。

<%@ page language="java" pageEncoding="utf-8" contentType="text/html; charset=utf-8"%>
<%@ taglib uri="/struts-tags"   prefix="s"%>
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
    </head>
  <body>
       入门的路径:<br>
      <a href="${pageContext.request.contextPath}/primer/helloWorldAction.action">helloWorld</a><br>
  </body>
</html>

那就介绍一下访问helloWorld应用的路径的设置。
在struts2中,访问struts2中action的URL路径由两部份组成:
包的命名空间+action的名称
例如: 访问本例子HelloWorldAction的URL路径为: /primer/helloWorldAction.action (注意:完整路径为:http://localhost:端口/内容路径/primer/helloWorldAction.action)。另外我们也可以加上.action后缀访问此Action。

 <package name="primer" namespace=“/primer“   extends="struts-default">
      <action name="helloWorldAction" class="cn.itcast.primer.HelloWorldAction">
        <result name="success" type="dispatcher">/success.jsp</result>
      </action>
 </package>

路径中的action名称必须和你在package标签下配置的action标签的name属性一致。

接下来我们在test.jsp文件中加入如下代码。

       测试Action名称的搜索顺序:<br>
        <a href="${pageContext.request.contextPath}/primer/primer/primer/helloWorldAction.action">helloWorld</a><br>
        <a href="${pageContext.request.contextPath}/primer/primer/helloWorldAction.action">helloWorld</a><br>
        <a href="${pageContext.request.contextPath}/primer/helloWorldAction.action">helloWorld</a><br>

     没有为action指定class<br>
        <a href="${pageContext.request.contextPath}/primer/actionNoClass.action">helloWorld</a><br>

      测试struts2 输出没有命名空间helloworld:<br>
        <a href="${pageContext.request.contextPath}/primer/userAction.action">helloWorld</a><br>

如果我们去点击这三个请求链接会发生什么呢?
你们试着点击一下就会发现,这三个请求链接都能被正确地处理运行。那我们就想,为什么没有配置却能够正确运行呢?这是因为在struts2中,当你点击请求链接时,它会对Action进行一个搜索。以第一个链接为例,<a href="${pageContext.request.contextPath}/primer/primer/primer/helloWorldAction.action">helloWorld</a>,当你点击链接时,会去搜索/primer/primer/primer/helloWorldAction.action,当查询不到时,会搜索/primer/primer/helloWorldAction.action,查询不到时,会搜索/primer/helloWorldAction.action,以此类推,直到Action被找到。所以如果我这么写,<a href="${pageContext.request.contextPath}/primer/primer/aaa/helloWorldAction.action">helloWorld</a>,程序就会报错。

那如果没有为action标签配置class属性,程序会有问题吗?
在package标签中添加一个action标签。

<action name="actionNoClass">
        <result name="success">/primer/success.jsp</result>
</action>

此时我们运行并点击,会发现程序仍然正确运行了,那问题来了,我连class都没配置,它是如何运行得到结果success,并跳转页面的呢?
我们查阅struts-default.xml文件,看到最后几行的配置

 <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />

你明白了吗?在没有为action指定class的时候,struts2框架默认会执行该Action。而我们查阅ActionSupport类的源码时,找到了一个方法。

public static final String SUCCESS = "success";

public String execute() throws Exception {
        return SUCCESS;
}

这个方法再熟悉不过了吧,所以为什么没有配置class属性也能正常运行,相信你已经明白了。

如果请求的路径查找不到action的情况下,程序运行会抛出异常 ,可以通过配置当找不到action的情况下,会执行默认的action

<package name="primer"  namespace="/"  extends="struts-default">
     <!--指定默认的action引用,如果该包下没有对应action配置,则启用该配置-->
     <default-action-ref name="helloWorldAction"></default-action-ref>

     <action name="helloWorldAction" class="cn.itcast.primer.HelloWorldAction">
            <result name="success" type="dispatcher">/success.jsp</result>
      </action>
     <action name="actionNoClass">
          <result>/success.jsp</result>
     </action>
 </package>

接下来我们来了解一下ActionSupport类,它是我们没有指定class执行的默认Action。
它远比Action接口强大,所以我们在编写Action类时可以改为继承ActionSupport类。

相信很多同学在开始的时候对这个.action的后缀表示无法理解,为什么写.action?我们来了解一下。
StrutsPrepareAndExecuteFilter是Struts 2框架的核心控制器,它负责拦截由/*指定的所有用户请求,当用户请求到达时,该Filter会过滤用户的请求。默认情况下,如果用户请求的路径不带后缀或者后缀以.action结尾,这时请求将被转入Struts 2框架处理,否则Struts 2框架将略过该请求的处理。

根据配置文件:struts2-core-2.1.8.1.jar包下的 org.apache.struts2/default.properties文件定义的常量决定
struts.action.extension=action,,

默认处理的后缀是可以通过常量”struts.action.extension“进行修改的,如下面配置Struts 2只处理以.do为后缀的请求路径:

<struts>
    <constant name="struts.action.extension" value="do"/>
</struts>

如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。如:

 <constant name="struts.action.extension" value="do,go"/>

我们还有第二种方式来修改后缀。
在struts.properties中配置常量, (struts.properties文件放置在src下)
struts.action.extension=do.go
既然有两种方式,那么如果我两种方式都实现了,它会启用哪个配置呢?我就不卖关子了,如果你两种方式都实现了,struts2框架会启用struts.properties的配置。那这是为什么呢?我可以给你解释一下。
因为常量可以在多个配置文件中进行定义,所以我们需要了解下struts2加载常量的搜索顺序:
1 struts-default.xml
2 struts-plugin.xml
3 struts.xml
4 struts.properties(自己创建)
5 web.xml
如果在多个文件中配置了同一个常量,则后一个文件中配置的常量值会覆盖前面文件中配置的常量值。
通俗点说,越后执行的文件优先级越高。
虽然实现方式有两种,但是不建议大家使用第二种自己创建配置文件的方式。

然后是常用的常量介绍。
指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的输出

该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。
如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开

设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭

配置当国际化文件修改时,重新加载该国际化资源文件,默认值是false(不重新加载),true为重新加载

当struts的配置文件修改后,系统是否自动重新加载该文件,默认值是false(不重新加载),true为重新加载

开发模式下使用,这样可以打印出更详细的错误信息,默认值为false(生产环境下使用),开发阶段最好打开

默认的视图主题

与spring集成时,指定由spring负责action对象的创建

该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性
为 false

上传文件的大小限制

接下来是第二个部分,struts2的结果类型。
我们新建文件夹resulttype,然后创建form.jsp文件

<%@ page language="java" pageEncoding="utf-8" contentType="text/html; charset=utf-8"%>
<%@ taglib uri="/struts-tags"   prefix="s"%>
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
    </head>
  <body>
    <form action="${pageContext.request.contextPath}/resulttype/resulttypeAction.action"
          name="form1"  method="post">
      <input type="submit" value="提交">
    </form>
  </body>
</html>

然后我们创建出对应的Action,这次我们不实现Action接口了,而是继承ActionSupport类。

public class ResultTypeAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        System.out.println("ResultTypeAction ...");

        HttpServletRequest request = ServletActionContext.getRequest();
        request.setAttribute("username", "username_request");

        return "success";
    }
}

对其进行配置,在struts.xml文件中添加

<package name="resulttype" namespace="/resulttype" extends="struts-default">
        <action name="resulttypeAction" class="cn.itcast.action.ResultTypeAction">
            <result name="success">/resulttype/success.jsp</result>
        </action>
</package>

转向的success.jsp页面如下

<%@ page language="java" pageEncoding="utf-8" contentType="text/html; charset=utf-8"%>
<%@ taglib uri="/struts-tags"   prefix="s"%>
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
    </head>
  <body>
            resulttype :   ${requestScope.username}
  </body>
</html>

点击提交按钮,页面成功显示保存在request范围的数据,这说明了什么?说明我的转向方式一定是转发,如果是重定向的话数据就取不到了。其实,在result标签里有一个type属性,它可以用来设置转向方式,只不过它默认是"dispatcher"。
这是第一种设置转向的方式,我们也有第二种。

<result name="success" type="dispatcher">
        <param name="location">/resulttype/success.jsp</param>
</result>

这样配置result标签也能实现转向。这个location指的是要转发到的页面。这种方式的实现原理在struts-default.xml文件中也能被找到,我就不带大家看了,感兴趣的同学可以自己研究一下。了解了转发,那重定向如何实现?这太简单了,将type值改为"redirect"即可。
注意了,重定向中,转向到jsp才能这样写,而如果想转向到action,你需要这样配置:

<result name="success" type="redirectAction">
    <param name="actionName">helloWorldAction</param>
    <param name="namespace">/primer</param>
</result>

最后一个部分就是struts2通配符与动态方法的调用。
在说这个之前先来拓展一个知识点。
我们先新建一个test.jsp文件。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <a href="${pageContext.request.contextPath }/bookAction.action">提交</a>
</body>
</html>

里面只有一个超链接,然后配置struts.xml文件,相信配置已经难不倒各位了,那我就对action作如下配置。

<action name="bookAction" class="cn.itcast.action.BookAction">
    <result name="success">/success.jsp</result>
    <result name="add">/bookaction.jsp</result>
</action>

然后创建BookAction.java文件。

public class BookAction extends ActionSupport{
    @Override
    public String execute() throws Exception {
        System.out.println("BookAction ...");
        return "success";
    }

    public String add(){
        System.out.println("add ...");
        return "add";
    }
}

我们运行项目,然后点击提交,页面会转向success.jsp文件,那么我如果想点击页面从而跳转到我们配置的bookaction.jsp文件呢?其实很简单,在action标签中有一个method属性,只需将它的值设置为方法名即可。那这个自定义的方法是不是可以随便编写呢?当然是不行的。它必须由public关键字修饰,必须有返回值,该方法不能传参,总结来说,就是除了方法名和execute方法一样,其它的都必须和它一样。到这里有人就会说了,你这句话有问题,execute方法抛出了异常,而自定义的方法却没有抛出,我解释一下,这是因为我们写的测试代码过于简单,以至于没有异常可供处理,所以你可以不抛异常,但是当代码很复杂的时候,程序或多或少都会有异常,这时候就必须抛出异常了。

这部分就先这样,回到我们的重点,通配符。
我们在test.jsp文件中添加三个超链接。

    通配符映射示例(1):<br>
    <a href="${pageContext.request.contextPath}/a_add.action"> 通配符映射示例(1)</a><br>
    <a href="${pageContext.request.contextPath}/b_add.action"> 通配符映射示例(1)</a><br>
    <a href="${pageContext.request.contextPath}/c_add.action"> 通配符映射示例(1)</a><br>
    <br>
    <br>
    <br>

然后配置struts.xml。

<action name="a_add" class="cn.itcast.action.BookAction" method="add">
    <result name="success">/success.jsp</result>
    <result name="add">/bookaction.jsp</result>
</action>
<action name="b_add" class="cn.itcast.action.BookAction" method="add">
    <result name="success">/success.jsp</result>
    <result name="add">/bookaction.jsp</result>
</action>
<action name="c_add" class="cn.itcast.action.BookAction" method="add">
    <result name="success">/success.jsp</result>
    <result name="add">/bookaction.jsp</result>
</action>

运行程序,程序正常运行,但是这样的配置显然很麻烦,有没有什么简单一点的写法呢?这时候通配符就派上用场了,我们把之前的配置都删掉,然后编写如下配置。

<action name="*_add" class="cn.itcast.action.BookAction" method="add">
    <result name="success">/success.jsp</result>
    <result name="add">/bookaction.jsp</result>
</action>

运行项目是没有问题的。这个号就是通配符,有些语言基础的同学应该都了解,我就不多说了。
下面给出struts2通配符的知识点。
一个 Web 应用可能有成百上千个 action 声明. 可以利用 struts 提供的通配符映射机制把多个彼此相似的映射关系简化为一个映射关系
通配符映射规则
若找到多个匹配, 没有通配符的那个将胜出
若指定的动作不存在, Struts 将会尝试把这个 URI 与任何一个包含着通配符
的动作名及进行匹配
若 Struts 找到的带有通配符的匹配不止一个, 最后一个匹配将胜出
被通配符匹配到的 URI 字符串的子串可以用 {1}, {2} 来引用. {1} 匹配第一个子串, {2} 匹配第二个子串…{0} 匹配整个 URI

  • 可以匹配零个或多个字符, 但不包括 / 字符. 如果想把 / 字符包括在内, 需要使用 **. 如果需要对某个字符进行转义, 需要使用 。

最后就是动态方法调用了。
动态方法调用: 通过 url 动态调用 Action 中的方法
如果Action中存在多个方法时,我们可以使用!+方法名调用指定方法
默认情况下, Struts 的动态方法调用处于激活状态, 若想禁用该功能, 则可以在 struts.xml 文件中添加如下 constant 元素:

以上面的项目为例,我可以不再action中配置method,而在超链接的url地址中作如下修改:

<a href="${pageContext.request.contextPath }/bookAction!add.action">提交</a>

这样我也能在点击提交按钮后调用配置action中的add方法。这就是动态方法调用。

到这里,struts2框架的学习就结束了,当然,struts2框架的知识远不止如此,感兴趣的同学可以继续深入学习,我这里就先告一段落了。

原文地址:https://www.cnblogs.com/blizzawang/p/11411778.html

时间: 2024-10-07 02:01:35

SSH开发模式——Struts2(第三小节)的相关文章

SSH开发模式——Struts2(第一小节)

在制定了学习计划的学习过程中,我感觉学习还是很有效率的.很短的时间内,我便学习完了JavaWeb的连接池.DbUtils框架及其一些工具类的使用. 学无止境,学习这些知识还远远不够,所以,在接下来的时间里,我将对JavaWeb中的SSH开发模式进行一个简单的学习,并用博客记录学习进度. 开发模式相信大家都有接触或听说,但又觉得这个东西很神秘,的确,这看不见摸不着的东西确实很让人好奇,所以,从今天开始,我将带着大家去揭开它神秘的面纱. 我会把整个开发模式分为三部分,第一部分:Struts2,第二部

SSH开发模式——Struts2(第二小节)

上一小节已经学会了如何去搭建Struts2的开发环境,该篇博客我们继续深入Struts2,了解Struts2框架的拦截器. 首先对我们在web.xml文件配置的过滤器进行一个源码的分析. 在StrutsPrepareAndExecuteFilter源码中,有一个init()方法,它调用方法获得了一个Dispatcher对象,这就是我们要分析的关键了.进入到它的源码,在其init()方法中调用了init_TraditionalXmlConfigurations()方法,该方法的源码如下: priv

SSH开发模式——Struts2进阶

在之前我有写过关于struts2框架的博客,好像是写了三篇,但是之前写的内容仅仅是struts2的一些基础知识而已,struts2还有很多有趣的内容等待着我们去发掘.我准备再写几篇关于struts2的高级内容,之前的一些基础知识我就不会再提了,所以,在看进阶篇的struts2时,我希望你有一定的struts2框架的基础,没有的话也不要紧,因为入门struts2非常简单,随手看几篇博客就算入门了,但要想灵活运用它,我们就得付出大量的时间和精力,让我们为了共同的目标奋进吧. 那就先补充一些知识点,这

MVC开发模式的数据运行流程

对于java中经典的开发模式MVC,有一些感触!现说一下Java中数据的运行流程,由于我技术有限,有错的话欢迎提出,不喜勿喷! 我们知道在MVC开发模式,包括三部分视图层V(view).控制层C(Controller)和模型层M(model),那么在一个项目中,这三部分又是指的什么呢? 视图层:顾名思义指的是看到的界面,通常也就是我们所说的JSP页面. 控制层:指的是servlet. 模型层:除了这两部分,剩下的所有. 在这里我将用画图的形式显示一下,数据的流转方式 1.当我们在JSP页面点击一

EF3:Entity Framework三种开发模式实现数据访问

前言 Entity Framework支持Database First.Model First和Code Only三种开发模式,各模式的开发流程大相径庭,开发体验完全不一样.三种开发模式各有优缺点,对于程序员没有哪种模式最好,只有哪种模式更适合.接下来我将分别使用这三种开发模式实现同一数据库模型的数据持久化功能.希望通过实践能帮助你找到更适合你的开发模式 Database First Database First开发模式指以数据库设计为基础,并根据数据库自动生成实体数据模型,从而驱动整个开发流程

MVC学习之数据库开发模式:三种开发模式总结:

先介绍下三种开发模式的使用方法: 1.数据库优先: 数据库开发之:数据库优先主要步骤: 1.在数据库中建立好数据库和所需要得到表 2.选中Models文件夹,添加新项目--数据--ADO.NET实体数据模型……在生成数据库页面选着从数据库中生成 在完成2之后,会在web.config里面自动生成数据库连接字符串 3.创建控制器和对应的视图页面 4.在控制器中创建数据上下文实例对象,该对象是通过连接数据库字符串的名字来创建的. 2.代码优先: 数据库开发之代码优先步骤: 1.在Models文件夹中

EntityFramework 学习 一 三种开发模式

Entity Framework支持3种不同的开发方法 1.Code First 2.Model First 3.Database First Code First 使用Code First开发模式,你完全避免与EDMX间的开发工作.你首先写好POCO,然后从这些POCO类中创建数据库 喜欢使用DDD(Domain-Driven Desing)领域驱动设计的开发者,更喜欢先编写领域类,然后生成数据库来持久化数据 Model First 使用Model First开发模式,你通过EDMX 设计器创

微信公众号开发入门笔记(三):编辑模式与开发模式

(一)编辑模式与开发模式的区别 微信公众号后台分为编辑模式和开发模式,这两种模式是互斥的,也就是如果当前开启的是编辑模式(即默认的模式),那么开发模式必须是关闭状态的:如果当前开启的是开发模式,那么编辑模式状态必须是关闭的(此时自动消息回复.自定义菜单等都不可用). (二)开发模式下数据交互的原理 一张图说明问题: 所以我们需要实现的主要业务逻辑就在微信公众号服务器后台.

Java Struts2 (三)

一.国际化概念(了解) 1.什么是国际化 软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的.符合来访者阅读习惯的页面或数据. 2.什么需要国际化 程序:需要国际化. 数据:是什么样的就是什么样的. 比如: 用户注册的表单,有用户名,密码这5个汉字,在zh_CN语言环境,显示的就是用户名和密码.但是在en_US语言环境,显示的就应该是username和password.这就是程序. 用户名输入的是[张三],密码输入的是[test],那无论在