Struts2第一天

Struts2第一天

 

整体课程安排:3天知识点+2天练习

第一天:入门(action和result结果集)--一般的请求+响应

第二天:请求数据处理相关(参数接收、类型转换、合法性校验、国际化)

第三天:拦截器、响应数据处理相关(值栈、OGNL、struts2标签)

第四天、第五天练习。(文件的上传下载+CRUD综合练习)

 

课程内容:

  1. Struts2概述(struts2框架、前世今生、开发包下载、开发包结构)
  2. 快速入门HelloWorld(入门理论、示例、运行流程分析)
  3. Struts2运行原理(运行原理图、相关概念简介-核心控制器、拦截器、Action、结果集、核心配置文件、DTD约束提示配置)
  4. Struts常用配置(核心配置文件种类和加载顺序、Action相关映射配置详解、Action默认处理类和默认Action、常量配置、配置文件分离)
  5. Action的访问相关(Action的三种书写格式、Action的方法执行三种方式)
  6. Action使用Servlet相关API(直接调用、间接调用)
  7. result结果集的使用(局部结果集和全局结果集、结果集的类型type)

 

课程目标:

  1. 学会使用基本的请求和响应
  2. 学会action的最主要的编写方式(ActionSupport)
  3. 学会如何调用action中的指定方法(通配符)
  4. 获取servelt API(静态方法调用)
  5. 掌握结果集的使用

 

  1. 概述

    1. Struts2是什么

 

Struts2是一个非常优秀的、免费开源的MVC框架(Model2设计模型),用于创建Web应用。

 

  • 框架

框架是可以重复使用的一些或一整套代码,通常与具体业务无关,也可以认为是软件的半成品。

框架的好处:规范开发流程。

  • MVC

全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计模式,或软件设计思想。

  1. 视图-view:负责数据的显示。 
  2. 模型-model:负责数据的处理。 
  3. 控制器-controller:负责调度不同的逻辑代码(model)并显示到视图(view)。 
    MVC
    的设计思想在很多中语言中都有实现,例如java.net

 

JSP规范提出了两种用JSP技术建立应用程序的开发模式,分别称作JSP Model 1 和JSP Model 2:

  • Model1: JSP (控制、显示)+ JavaBean (数据处理)

    缺点:页面代码太多,加载速度慢,调试麻烦。

 

  • Model2 : Servlet (控制)+ JSP(显示) + JavaBean(数据处理)--符合MVC思想架构模式。

    适合大型项目

 

Java web企业应用开发根据又根据Model2(也可以说是根据MVC思想)制定了三层结构体系(来自于JavaEE规范)

  • 表现层(页面数据显示、页面跳转调度)jsp/servlet
  • 业务层(业务处理和功能逻辑、事务控制)service
  • 持久层(数据存取和封装、和数据库打交道)dao

 

Struts2就是一个表现层框架,可以用来简化表现层代码开发的。

 

Struts2核心功能:了解

允许POJO对象作为action

Action中的servlet API不再与方法耦合

支持更多视图技术(jsp、freemarker、velocity)

基于Spring AOP思想的拦截器机制

 

  1. struts2 由来

百度百科:

 

Struts2由传统Struts1和WebWork两个经典框架发展而来。

历史由来:

Java兴起 98(最早进行java开发分方向 j2se j2ee j2me

J2EE 企业级应用软件开发

2000 年左右出现struts1 (几乎所有开发人员都在用

随着互联网的发展struts1 设计慢慢开始存有缺陷和不足

Webwork框架的出现

该框架的设计思想比struts1 先进的多,例如:引入拦截器机制、 ognl 表达式语言

 

struts2是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架,Struts 2以WebWork为核心,但开发流程类似于struts1。

 

Struts2的漏洞事件:

  1. 软件开发包

官网地址:http://struts.apache.org/

官方网站提供了两大系列版本1.x和2.x,分别成为Struts1和Struts2。

最新版本分别为:1.3.10 和2.5.2。

本课程学习Struts2。

 

开发包下载:

官方最新版本:struts-2.5.2-all.zip

 

本次课程使用的版本是:2.3.15.3

 

 

  1. struts2 开发包结构

使用框架需要导入jar包(也就是人家写好的一些代码)

解压之后,源码和jar包都在里面了。

src文件夹下的是源码

 

在lib文件夹中有很多的struts需要用到的包,包括和spring的整合包,json的插件包等等

总共126个jar,实际上在我们开发的时候用不到这么多。

 

docs中的文档几乎看不懂,要快速入门我们可以看一下apps中的一些案例:

解压之后的struts2-blank中就是一些简单的应用,结构如下 ;

打开其中的web.xml:里面就配置了struts2需要用到的过滤器

 

struts.xml :struts2的灵魂文件

 

有了web.xml和struts.xml的配置文件,还需要jar包,jar包在lib文件夹中。

 

总结13个jar包的用途:

  1. Struts2快速入门

    1. 理论

Struts2和Servlet开发对比

Servlet:

缺点:一个功能对应一个请求,一个请求对应一个serlvet,每一个servlet中都可能有重复的代码。

 

Struts:

 

Struts2的基本运行流程图:

Web.xml作用:配置前端控制器

Struts.xml作用:配置请求分发

 

【小结】

所有的重复代码都交给前端控制器去调用完成和调度,开发者只需要在Aciton中编写业务处理相关代码即可。

  1. 入门

 

  1. 创建工程

选择jdk版本,不要选yes,否则就使用了jdk1.5的版本,对后面使用注解支持不好,要用jdk1.5以上的。

当然也可以改成jdk1.7的。

 

  1. 导入jar包

Jar包地址: \Struts_2.3.15.3\struts-2.3.15.3\apps\struts2-blank\WEB-INF\lib下的13个jar包

 

  1. 配置web.xml

Ctrl+shift+T :然后输入StrutsPrepareAndExecuteFilter后可以联想出该文件,然后复制它的绝对路径即可

<?xml version="1.0" encoding="UTF-8"?>

<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

 

    <display-name>struts</display-name>

    <!-- 配置sturts前端控制器 -->

    <filter>

        <filter-name>struts</filter-name>

        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>struts</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

    <welcome-file-list>

        <welcome-file>index.html</welcome-file>

        <welcome-file>index.htm</welcome-file>

        <welcome-file>index.jsp</welcome-file>

        <welcome-file>default.html</welcome-file>

        <welcome-file>default.htm</welcome-file>

        <welcome-file>default.jsp</welcome-file>

    </welcome-file-list>

</web-app>

 

  1. 编写请求页面

创建页面:

hello.jsp :

success.jsp :

  1. 编写action

创建包和action :

编写一个处理具体业务的action,必须实现Action接口

具体内容如下:

public class HelloAction implements Action{

    //exectue为实现Action接口后默认执行的方法,String是返回的结果集视图名称

    //通过这个结果集视图名称到struts.xml中可以找到对应跳转的结果集视图

    @Override

    public String execute() throws Exception {

        System.out.println("hello world!");

        //响应页面跳转:

        //返回的结果集视图名称:名字随便取(必须在struts.xml中能找到相同名称的配置)

        return "success";

    }

}

 

 

  1. 配置struts.xml

1、可以重上述案例的struts.xml中复制过来

2、Struts.xml中的约束路径:在struts2-core核心jar包下的struts-2.3.dtd中

配置完成后如果还是不能联想出struts相关的标签名称,那是因为没有配置相应的dtd约束文件

注意:如果电脑可以上网,就会自动给你下载dtd约束文件。

如果不能上网就需要手动配置dtd约束文件,手动配置如下:

复制:http://struts.apache.org/dtds/struts-2.3.dtd,打开window属性

Laction的文件路径为:之前解压文件struts-2.3.15.3\src\core\src\main\resources下的struts-2.3.dtd

点击确定后,关闭struts.xml并且重新打开,此时用alt+/就可以联想出相关标签.

 

 

 

 

在工厂的src目录下创建一个struts.xml文件,然后将上述约束复制到struts.xml中

Struts内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <package name="default" extends="struts-default" namespace="/">

    <!—配置action和访问的类之间的对应关系 -->

    <!-- name:请求的虚拟路径名称 class:指向的具体路径 -->

        <action name="hello" class="cn.itcast.struts2.a_hello.HelloAction">

        <!-- name:action中通过String值来找到这个标签,并返回相应的结果集视图 -->

        <result name="success">/a_hello/result.jsp</result>

        </action>

    </package>

 

</struts>

 

 

 

 

  1. 测试

发布到tomcat :

启动tomcat :

测试访问:

1、控制台打印:

2、显示视图

 

 

关联源代码:

选择开发包:

 

  1. 执行流程分析

客户端发送请求,请求路径经过前端控制器,前端控制器读取struts.xml中的配置来分发到HelloAction中,执行默认方法后返回结果集视图名称,在struts.xml中找到相应的结果集视图并显示。

由此可见:struts.xml是这个过程中的核心,通过这个struts.xml才能找到具体的action以及响应结果集视图。

 

 

实际上在前端控制器走第三步分发action请求之前,还调用了一组拦截器,由于咱们并没有关于拦截器的业务因此什么都没有感觉到。

  1. Struts运行原理分析

 

StrutsPrepareAndExecuteFilter (准备 和 执行):它是Struts2的核心控制器,它采用前端控制器模式,对用户的请求进行控制处理。相当于我们的学校的前台。

Interceptor拦截器,Struts2可复用的代码功能都是基于(通过)它来实现的。struts2有很多内置拦截器,用来实现不同的功能。我们看看有哪些默认的拦截器:

参考 struts-core.jar 提供 的struts-default.xml 配置文件

    默认情况下, 访问每个Action ,默认拦截器defaultStack会从上往下依次执行

通过断点调试发现:其中包含的这些拦截器都会依次执行(按照从上倒下的顺序),即可依次实现不同的功能。 而这些功能都是通用的、经常用到的(重复的),都由拦截器来实现。

随便找一个找到具体的类进行断点调试即可

 

 

Action是执行具体的业务逻辑代码的,它在拦截器之后执行。(演示。。。)

【查看类型代码】shift+ctrl+t

通过断点调试看到,前端控制器在分发action之前就调用了拦截器。

 

  1. ConfigBrowser插件(了解)

 

ConfigBrowser可以用来查看struts2的各类配置。

 

知识点:如何使用struts2的插件。

Strut22的插件的安装,只需要将插件复制到工程的lib中即可

导入插件包 ,启动项目 ,访问:

http://IP地址:端口/项目名称/config-browser/index.action

通过路径,查看struts2 Action 配置加载情况

 

  1. 常用配置

    1. 核心配置文件的分类及读取顺序

关键词:核心配置文件的种类和加载顺序,前端控制器会依次加载依次配置文件。

Struts2的核心配置文件有两大类共6种方式,按照加载顺序分别说明如下:

第一类:框架内置的配置文件:

  • Struts2框架内置的常量配置文件:default.properties,位于struts-core.jar包的org.apache.struts2包下。作用:定义了一些常量(键值对)。一些功能开关。
  • Struts2框架内置的核心配置文件:struts-default.xml,位于struts-core.jar包下。作用:定义了Bean元素、结果集类型、拦截器等。注意默认包:

struts.xml中extends :

实际就是继承了struts-default

 

在struts2的框架体系中,struts.xml中的package主要是用来实现一些配置的复用,在使用时编写子包来继承struts-default,如此就可以复用struts-default中的一些功能。

 

  • Struts2框架插件配置文件:struts-plugin.xml,位于每个插件包的根目录。作用:用于扩展插件的一些配置。

     

    随便复制一个struts的插件包到工程中,里面就有struts-plugin.xml。

每一个插件包中的struts-plugin.xml配置都不一样

 

 

第二大类:用户自定义的配置文件:

  • 用户自定义核心文件配置struts.xml位于用户工程的src下。作用:用于用户开发的相关配置,如配置package、action等。

    一般都会继承struts-default,即继承struts-default.xml中的配置,否则就无法使用结果集以及拦截器的配置。

  • 用户自定义常量配置文件:struts.properties,一般位于用户工程的src下。只能用于配置一些常量(覆盖内置的default.properties中的常量配置

    一般也不太用,可以在struts.xml中直接配置常量

     

  • web.xml中配置struts2常量(了解)

 

【注意】

  1. 配置文件加载的顺序问题:后加载的配置文件的配置内容,可以覆盖先加载的配置文件的配置内容。因此,自定义的可以覆盖默认的配置。
  2. 开发人员主要采用struts.xml(可配置action映射、常量等) 或者 struts.properties (只能配置常量)

 

 

注意:以上第一类的3个配置文件都是不能做修改的,全部配置文件的读取顺序为:1、default.properties---2、 struts-default.xml---3、 struts-plugin.xml---4、struts.xml---5、struts.properties---6、web.xml中的常量配置

 

当然,常量的配置一般不在struts.properties和web.xml中来配置,在struts.xml中配置即可

 

  1. 核心配置文件struts.xml

关键字:package、action、result、constant(常量的配置)

  1. <package>

    package标签:用来管理Action和result, 实现包内配置复用 (通过包继承实现 )

     

  • name属性:包的名称,在struts容器中必须具有唯一性
  • extends属性:继承父package(中的功能),通常都继承struts-default(默认包内定义大量结果集类型和拦截器)
  • namespace属性:名称空间用来标识一个路径,来区分不同action的访问路径

 

 

 

【示例】

演示不同的包中相同的action通过不同的名称空间来访问。

 

步骤一:创建新的包和action

创建包:

action:

//编写action需要实现action接口

public class HelloAction implements Action{

    //默认执行的方法

    @Override

    public String execute() throws Exception {

        System.out.println("hello world ......config!");

        return "success";

    }

    

}

 

步骤二:修改struts.xml

亲:如果HelloAction是复制粘帖的话,记得把class中的绝对路径换成新的HelloAction。

创建一个新的package:

<struts>

    <!-- 配置常量 -->

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

    <!-- package name:包名随便取但是需要保证唯一性 extends:用来继承核心包 -->

    <package name="default" extends="struts-default" namespace="/">

 

        <!-- action:具体请求的分发 name:请求名称 class:具体要执行的类的路径 -->

        <action name="hello" class="cn.itcast.struts.a_hello.HelloAction">

            <!-- 配置结果集响应 name:结果集视图名称 /a_hello/result.jsp:需要响应的结果集视图 -->

            <result name="success">/a_hello/result.jsp</result>

        </action>

    </package>

 

 

        

    <package name="default1" extends="struts-default" namespace="/config">

        <action name="hello1" class="cn.itcast.struts.b_config.HelloAction">

            <result name="success">/a_hello/result.jsp</result>

        </action>

    </package>

     </struts>

 

注意:在同一个package下,action的name属性也不能重复,必须是唯一的。

 

步骤三:测试

访问测试:http://127.0.0.1:8080/struts2_day01/config/hello.action

 

 

Action的访问路径= IP地址:端口+namespace包名称空间 + action的name属性

  1. <action>

    action标签:用来管理具体的Action,实现请求和响应相关。

     

  • name属性:action的名字,用于配置请求
  • class属性:action对应的类,该类编写了action具体业务逻辑代码。
  1. <result>

    result标签:结果集视图,用于配置响应,标签内的值是响应的地址

     

  • name属性:结果集(结果集视图)的名字,action会根据该名字跳转到对应的地址。

 

 

 

 

  1. 配置项的默认值

    1. package-namespace默认值

步骤一:再次创建一个新的package

不写namespace:即为默认值

    <!-- 默认值 -->

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

        <!-- 配合默认action -->

        <default-action-ref name="errorAction"></default-action-ref>

        <!-- 配置默认action的具体映射 -->

        <action name="errorAction" class="cn.itcast.struts.b_config.HelloAction">

            <!-- 配置结果集 -->

            <result >/errorPage/errorPage.jsp</result>

        </action>

      

        <action name="hello2" >

            <result >/a_hello/result.jsp</result>

        </action>

    </package>

 

步骤二:测试访问

访问无误

注意:不设置namespace的话,期默认值是namespace="",而不是很多人以为的namespace="/"

由于期访问路径一样是http://127.0.0.1:8080/struts2_day01/hello.action,所以会造成很多人的误解。

 

步骤四:分析

默认值到底是namespace=""还是namespace="/",从配置第二个package就可以看出来:

如果第二个package配置namespace=""的话就会产生冲突以至于报错,而如果配置成namespace="/"的话就不报错了,由此可见namesapce的默认值应该是namespace=""。

 

  1. result-name默认值

步骤一:修改Struts.xml

不写namespace:即为默认值

    <!-- 默认值 -->

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

        <!-- 配合默认action -->

        <default-action-ref name="errorAction"></default-action-ref>

        <!-- 配置默认action的具体映射 -->

        <action name="errorAction" class="cn.itcast.struts.b_config.HelloAction">

            <!-- 配置结果集 -->

            <result >/errorPage/errorPage.jsp</result>

        </action>

    

        <action name="hello2" >

            <result >/a_hello/result.jsp</result>

        </action>

    </package>

 

步骤二:测试

测试访问hello,执行结果无误

 

步骤三:分析

如果result标签中的name值不配置的话,其默认值是success,但是如果使用默认值的话需要在action中返回结果集名称为SUCCESS

 

  1. action-class默认值

步骤一:修改struts.xml

设置默认的action-class(即不在action标签中配置class属性)

    <!-- 默认值 -->

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

        <!-- 配合默认action -->

        <default-action-ref name="errorAction"></default-action-ref>

        <!-- 配置默认action的具体映射 -->

        <action name="errorAction" class="cn.itcast.struts.b_config.HelloAction">

            <!-- 配置结果集 -->

            <result >/errorPage/errorPage.jsp</result>

        </action>

      

        <action name="hello2" >

            <result >/a_hello/result.jsp</result>

        </action>

    </package>

 

 

步骤二:测试请求

请求成功,但是后台不打印任何数据

 

步骤三:分析

如果不指定action标签中的class,那么会默认执行com.opensymphony.xwork2. ActionSupport,并执行其中的execute方法。

 

由于是使用的默认class—ActionSupport,因此后台没有执行任何逻辑,直接返回了SUCCESS结果集视图名称,跳转到指定页面。

 

 

  1. 默认action

通常我们的请求路径如果找不到相应的action就会报错如下:

我们可以配置一个默认的action,一旦找不到相应的action就会执行默认action。

 

【示例】

步骤一:修改struts.xml

配置默认action:

<!-- 配置默认值 -->

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

    <!-- 配置默认action -->

    <default-action-ref name="errorAction"/>

    

    <action name="errorAction" class="cn.itcast.struts.b_config.HelloAction">

        <result>/errorPage/errorPage.jsp</result>

    </action>    

      

        <!-- action:具体请求的分发 name:请求名称 class:具体要执行的类的路径 -->

        <action name="hello1" >

            <!-- 配置结果集响应 name:结果集视图名称 /result.jsp:需要响应的结果集视图 -->

            <result >/a_hello/result.jsp</result>

        </action>

 

    </package>

 

步骤二:创建响应页面

测试访问一个不存在的action:跳转到指定的错误页面-errorPage.jsp

errorpage.jsp需要配置加载所需图片:

<div align="center"><img src="./images/404-xsy.jpg"/></div>

页面内容:

<body>

<div align="center"><img alt="图片" src="b_config/404-xsy.jpg"></div>

</body>

 

步骤三:测试

 

【面试知识】

区分Action默认处理类(class)和默认执行的Action

  • Action默认处理类:是配置了action,但没有指定action的class,会自动调用执行默认的action类,该action在struts2的struts-default.xml文件中有配置内置默认的,也可以自定义一个进行覆盖(一般很少这样做)。

  • 默认执行的action:是用户访问的路径中找不到这个action,那么struts2会去寻找被访问的包中是否有配置一个默认执行的action,如果有配置,则执行默认配置的action,如果没有配置,则显示action找不到的错误信息哦

 

 

 

【扩展了解】

访问action的时候,struts有个内部规律(了解)

如果你访问的路径中,没有定义action,会自动向上层路径寻找。

http://127.0.0.1:8080/struts2_day01/aa/bb/cc/hello.action

先在aa/bb/cc/找helloAction

找到就ok,找不到,继续:

aa/bb/中找hello.action

……..

一直找到hello.action

 

其实最终会找到根目录下的hello.action:http://127.0.0.1:8080/struts2_day01/aa/bb/cc/hello.action

 

 

访问测试:

缺点:代码可读性不好,不建议这样做。

 

  1. <constant>常量配置

default.properties定义了struts2框架的大量常量,开发者可以通过改变这些常量来满足应用的需求。

要修改这些常量,可以通过自定义核心配置来覆盖默认的值(后加载的配置文件常量,可以对先加载配置文件进行覆盖),有如下三种方式(开启开发者模式):

  • 配置src/struts.xml

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

  • 配置src/struts.properties

struts.devModel = true

  • 配置web.xml

 

 

【常用常量分析】

  • struts.i18n.encoding=UTF-8

    相当于 request.setCharacterEncoding("utf-8"); 解决post 请求乱码问题。

    因此,在Struts2开发时,无需关注post 乱码问题。

 

  • struts.devMode=true

开发模式下使用,这样可以打印出更详细、友好的错误信息

当设置开发者模式devMode =true 会激活xml配置文件自动重新加载功能。

  • struts.configuration.xml.reload=true :修改struts.xml 配置后,无需重启服务器;
  • struts.i18n.reload = true,国际化文件修改之后也不需要重启服务器。会自动加载生效。

 

  • struts.action.extension=action,,

    Action请求映射路径 默认扩展名

问题: http://localhost:8080/struts2_day1/hello 也可以访问 HelloAction

    如果请求路径 必须以.action结尾

 

  • struts.ui.theme=xhtml

    设置页面标签显示样式

 

  • struts.enable.DynamicMethodInvocation=true

    访问Action 支持 动态方法调用

 

  • struts.multipart.maxSize=2097152

    上传文件的大小限制

 

小结:

如果需要更改某个常量的值,在default.properties中找到变量,将名字复制到struts.xml中进行覆盖它的值。

  1. 配置文件的分离

 

【开发场景】

在大部分应用里,随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿。为了避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,我们可以将一个struts.xml配置文件分解成多个配置文件,然后在struts.xml文件中包含其他配置文件。下面的struts.xml通过<include>元素指定多个配置文件:

 

<struts>

    <include file="struts-part1.xml"/>

    <include file="struts-part2.xml"/>

</struts>

 

通过这种方式,我们就可以将Struts 2的Action按模块添加在多个配置文件中。

Struts.xml引用其他配置文件

如下:

 

  1. Action的编写和方法访问

    1. Action编写的三种方式

Struts2支持三种书写Action的方式

 

  1. 自定义类实现Action

步骤一:新建包和action

新建一个包:cn.itcast.struts.c_action

Action : 

public class Demo1Action implements Action{

 

    @Override

    public String execute() throws Exception {

        System.out.println("action的第一中编写方式:实现action接口");

        return NONE;

    }

 

}

 

步骤二:配置Struts.xml :

不配置结果集视图

<!-- action的第一种编写方式:实现action接口 -->        

        <action name="demo1" class="cn.itcast.struts.c_action.Demo1Action"/>

 

步骤三:测试

执行结果没有响应,原因是返回了NONE的结果集名称

后台打印:

 

【内置的视图名称】

Action 接口提供一组 常用的内置的逻辑视图名称:

  • SUCCESS 成功视图
  • NONE 没有结果视图,用户自己生成响应数据
  • ERROR 错误视图
  • INPUT 输入视图 (数据输入非法,要求用户重新输入)
  • LOGIN 登陆视图 (如果用户未登陆,使用登陆视图)
  1. 自定义类继承ActionSupport(重点)

步骤一:编写Action

public class Demo2Action extends ActionSupport{

    @Override

    public String execute() throws Exception {

        System.out.println("action的第二中编写方式:实现ActionSupport");

        return NONE;

    }

}

 

步骤二:配置Struts.xml

<!-- action的第二中编写方式:实现ActionSupport -->

        <action name="demo2" class="cn.itcast.struts.c_action.Demo2Action"/>

 

步骤三:测试

 

 

 

这个编写方式是我们最常用的,ActionSupport实现了更多的接口,更加有利于扩展。

 

  1. 自定义POJO(了解)

POJO(Plain Old Java Object简单的Java对象),实际就是普通的JavaBean。

struts2使用反射的机制来进行调用执行。

【注意】关于execute方法的编写要求,必须满足:

  • public修饰符
  • String返回值
  • 无参数方法

 

步骤一:编写Action

需要手动编写execute方法---固定为 public Stirng execute(){}(还没有讲到方法编写,这是暂时的写法)

public class Demo3Action {

    public String execute(){

        System.out.println("action的第三种编写方式:自定义pojo作为action");

        return "none";

    }

}

 

 

步骤二:配置Struts.xml 

<!-- action的第三种编写方式:自定义pojo作为action -->

        <action name="demo3" class="cn.itcast.struts.c_action.Demo3Action"/>

 

步骤三:测试

后台打印:

 

其实,pojo的方式,底层使用反射机制,自动调用execute方法

 

【小结】

一般情况下都使用继承ActionSupport类的方法

其他两种,大家了解就行了。

 

  1. Action的方法编写(重点)

问题:是不是默认只能执行execute这个方法?是不是只能写一个方法呢?

否。

Action访问指定方法的方式:

  1. execute
  2. 可以通过method属性来指定需要执行的方法
  3. 通过通配符来指定需要执行的方法(重点)
  4. 通过动态方法调用来执行需要执行的方法

 

一个action类中可以编写N个方法。

但Action类中的可执行的方法必须满足(名字可以任意):

  • public修饰符
  • String返回值
  • 方法无参数

 

  1. 通过设置method属性来调用action中的方法

通过action标签中的method属性来指定所要执行的方法

【示例】

步骤一:创建新的包名和Action 

新建一个包:cn.itcast.struts.d_method

Action :

public class UserAction extends ActionSupport{

    @Override

    public String execute() throws Exception {

        System.out.println("默认方法执行!");

        return super.execute();

    }

    

    public String login(){

        System.out.println("登录成功");

        return NONE;

    }

    

    public String register(){

        System.out.println("注册成功");

        return NONE;

        

    }

}

 

步骤二:创建响应页面

Login.jsp:

<body>

<h1>用户登录成功!</h1>

</body>

Register.jsp

<body>

<h1>用户注册成功!</h1>

</body>

Success.jsp:

<body>

    <h1>success!</h1>

</body>

 

 

步骤三:配置Struts.xml

<!-- action访问指定方法 -->

        <!-- 方法login方法 -->

        <action name="user_login" class="cn.itcast.struts.d_method.UserAction" method="login">

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

        </action>

        <!-- 访问register -->

        <action name="user_register" class="cn.itcast.struts.d_method.UserAction" method="register">

            <result name="register">/d_method/register.jsp</result>

        </action>

 

步骤四:测试

执行请求:由于有两个方法,因此需要执行两次请求。

执行注册请求:

 

步骤五:分析

 

注意:如果访问路径名称以及返回结果集视图使用通配符以及{1}的话,需要保证,请求路径的名称能在action标签中找到,如果使用{1}来访问指定方法和响应结果集的话,要保证方法名称和响应的结果集视图名称一致,而且必须保证结果集视图页面的名称也要一致

 

 

问题:如果要写的业务方法非常多,那是不是每一个方法都要写一个action,感觉非常繁琐。

有没有更好的方法解决?

  1. 使用通配符进行方法调用

单纯使用method属性来配置action的方法,如要调用不同的方法,需要配置不同的action。配置较多。

解决方案就是使用通配符,可实现仅通过一个method属性,就可以配置一个action中的N方法的访问。

  1. 单个通配符的使用

步骤一:Action 

使用之前的例子即可

 

步骤二:配置Struts.xml

 

步骤三:测试

执行请求

后台打印:

 

 

步骤四:分析

 

  1. 两个通配符的使用

【示例】

步骤一:Action 

使用之前的例子即可

 

步骤二:配置Struts.xml 

 

步骤三:测试

执行请求

后台打印:

 

一般两个*就差不多是极限了,三个的话就没法看了,可读性非常差。

 

  1. 动态方法调用(了解)

【示例】

步骤一:需要开启常量中的动态方法调用

 

步骤二:Action 

使用之前的例子即可

 

步骤三:配置Struts.xml 

需要开启动态方法调用:

配置action :

 

步骤四:测试

执行请求

后台打印:

 

步骤五:分析

 

  1. 方法总结

【小结】

action方法调用:

  1. 默认的execute方法调用。
  2. method属性指定调用方法。虽可以任意调用任何的方法,但一个方法需要配置一个action。
  3. method属性+通配符。可以使用一个配置,调用N方法和结果集。(重点--推荐)
  4. 动态方法调用,可以不配置method属性也能随意调用aciton中的任意方法。但必须开启动态方法调用,而且不能通过一个result标签随意配置N个结果集。
    1. Action访问Servlet相关API

struts2默认情况下将servlet api都隐藏起来了,为了简化开发。但很多时候,我们还需要调用servlet api,比如,向session中放入一个登录用户。

分析通过3种方式操作servlet的api。

  • 解耦方式(了解)
  • 接口注入方式(了解)
  • 静态方法(重点)

 

  1. 解耦合方式调用(间接调用)-了解

解耦相对于耦合,这里举例:

编写自己的Servlet的时候的调用方法doGet(HttpServletRequest, HttpServletReponse) ,需要直接在代码中依赖servletContext的 request和 response,这就是耦合。

    Struts2设计思想就是与Servlet API 解耦合,编写Action 代码中可以不再直接依赖Servlet的任何API,简化开发,也便于测试(方法简单无参)。

    那如果我们想调用这些API呢?比如向session中放入登录用户、向request中放入一个值给页面响应用。

    struts2为我们提供了一个API,可间接调用servlet api,这个api叫做:ActionContext 类 (Action 上下文 )。(可以理解该类就是一个工具类)

    【回顾了解】上下文: 与容器相关,获取容器相关对象、信息 ---- 类似于一个工具类 (如servletcontext,可以拿到一些关于web应用服务范围的一些对象信息,pageContext可以拿到关于jsp页面的一些对象信息)。

    该API提供大量间接操作Servlet API (request、 response、 session、application) 方法:

 

提示:间接操作是指面向map的操作,而不是直接操作相关对象。通过操作map就相当于操作相关对象。

 

【示例】

步骤一:创建一个新的包和类

//解耦方式调用servlet API

public class IndirectAction extends ActionSupport{

    @Override

    public String execute() throws Exception {

        Map<String, Object> map = ActionContext.getContext().getParameters();

        String[] str = (String[]) map.get("name");

        System.out.println(str[1]);

        Map requestMap = (Map) ActionContext.getContext().get("request");

        requestMap.put("name", str[1]);

        Map<String, Object> sessionMap = ActionContext.getContext().getSession();

        sessionMap.put("name", "session_name");

        return SUCCESS;

    }

}

 

 

步骤二:配置struts.xml

<!-- 解耦方式调用servlet API -->

        <action name="indirect" class="cn.itcast.struts.e_servlet.IndirectAction">

            <result>/e_servlet/success.jsp</result>

        </action>

 

 

步骤三:配置响应页面

结果页面success.jsp:

 

步骤四:测试

请求url

 

  1. 接口注入方式操作Servlet API(了解)

获取Context需要实现ServletContextAware

获取Request需要实现ServletRequestAware

获取Response需要实现ServletResponseAware

【示例】

步骤一:编写Action 

public class InjectAction extends ActionSupport implements ServletRequestAware,

        ServletContextAware {

 

    private HttpServletRequest request;

    private ServletContext context;

 

    @Override

    public String execute() throws Exception {

        String name = request.getParameter("name");

        request.setAttribute("name", name);

 

        request.getSession().setAttribute("name", "郭芙蓉");

 

        return super.execute();

    }

 

    @Override

    public void setServletRequest(HttpServletRequest request) {

        this.request = request;

    }

 

    @Override

    public void setServletContext(ServletContext context) {

        this.context = context;

 

    }

}

 

步骤二:Struts.xml 

需要创建一个新的结果集视图injectDemo.jsp

<!-- 接口注入方式调用servlet API -->

        <action name="inject" class="cn.itcast.struts.e_servlet.InjectAction">

            <result>/e_servlet/success.jsp</result>

        </action>

 

 

步骤三:测试

执行请求

 

  1. 通过ServletActionContext 类的静态方法直接获取Servlet API (推荐

 

步骤一:编写Action 

public class DirectAction extends ActionSupport{

    @Override

    public String execute() throws Exception {

        

        String name = ServletActionContext.getRequest().getParameter("name");

        ServletActionContext.getRequest().setAttribute("name", name);

        

        ServletActionContext.getRequest().getSession().setAttribute("name", "苏菲玛索");

        

        return super.execute();

    }

 

}

 

步骤二:配置Struts.xml 

配置响应结果集:

<!-- 静态方法直接调用 -->

        <action name="direct" class="cn.itcast.struts.e_servlet.DirectAction">

            <result>/e_servlet/success.jsp</result>

        </action>

 

 

步骤三:测试

执行请求

 

 

【扩展问题】

ServletActionContext 获取 request方法 是 static的, 有没有线程问题 ?

    会不会出现,获取错request对象的情况 ---- 不会的 (底层:ThreadLocal

    存储着每个线程的变量副本,每个线程只能取自己的value。

 

  1. result结果集的使用

该节分为两个知识点:

  1. 局部结果集和全局结果集。
  2. 结果集类型。

 

  1. 局部结果集和全局结果集

    1. 局部结果集

在<action> 标签内部配置的<result>元素。

作用范围:只对当前Action有效

【举例】

步骤一:创建包和类

创建工程:

ProductAction :

public class ProductAction extends ActionSupport {

    @Override

    public String execute() throws Exception {

        System.out.println("默认执行的方法!");

        

        return super.execute();

    }

    

    public String save (){

        System.out.println("保存商品成功!");

        return "save";

    }

}

 

步骤二:配置Struts.xml 

<!-- 结果集的使用:局部结果集 -->

        <action name="product_save" class="cn.itcast.struts.f_result.ProductAction" method="save">

            <result name="save">/f_result/save.jsp</result>

        </action>

 

 

步骤三:创建响应页面

 

save.jsp:

 

步骤四:测试

执行请求:报错,找不到product这个类

原因是:之前的双通配符的配置的作用使我们发送的请求走错地方了,要先把这个配置给注释掉。

 

再次测试:

注意:如果有用到两个或者两个以上的通配符,此时要注意在这个通配符所在的action标签的下方有没有用到其他通配符的action,如果有,就可能发生不可预知的错误。

 

 

问题:如果有几个action中的响应结果集都是指向同一个jsp页面—index.jsp,是不是每一个action都要配置一下?

答 :可以使用全局结果集

 

 

  1. 全局结果集

在包的标签中的<global-results>中配置

作用范围:对package内所有Action生效

 

一般是用来对几个不同的action响应相同的结果集视图使用的

 

【举例】 ProductAction和UserAction都有方法需要响应同一个结果集视图

步骤一:给两个不同的action配置相同的结果集视图

UserAction:使用之间的action即可

public class UserAction extends ActionSupport{

    @Override

    public String execute() throws Exception {

        System.out.println("默认方法执行!");

        return super.execute();

    }

    

    public String login(){

        System.out.println("登录成功");

        return "login";

    }

    

    public String register(){

        System.out.println("注册成功");

        return "register";

        

    }

}

ProductAction :

public class ProductAction extends ActionSupport {

    @Override

    public String execute() throws Exception {

        System.out.println("默认执行的方法!");

        

        return super.execute();

    }

    

    public String save (){

        System.out.println("保存商品成功!");

        return "save";

    }

}

 

 

步骤二:配置Struts.xml 

配置全局结果集并把局部结果集注释掉:

 

提示:该标签有配置顺序,将鼠标悬停在<package >标签上是可见如下提示

 

注意:局部结果集会覆盖全局结果集

 

步骤三:创建结果集视图

success.jsp :

 

步骤四:测试

 

访问无误

 

补充

注意:package中的任何标签配置都是有顺序的。

 

  1. 结果集类型

作用:控制响应的方式转发、重定向)

配置<result> 元素时, name是逻辑视图名称, type是结果集类型。

Struts2提供的常用结果集类型都定义在struts-default.xml 中:

内置的结果集类型:最常用的就是红框中的几个结果集类型

  1. 转发-dispatcher

dispatcher(默认值):请求转发。(最常用)

作用:服务器内部是同一次请求,可采用request传递数据,URL不变。

 

【举例】

步骤一:action

修改ProductAction中的save方法:添加数据

 

public class ProductAction extends ActionSupport{

    @Override

    public String execute() throws Exception {

        System.out.println("执行默认方法!");

        return SUCCESS;

    }

    

    public String save(){

        System.out.println("保存商品成功!");

        ServletActionContext.getRequest().setAttribute("name","iphone 7 plus");

        return "save";

    }

}

 

 

步骤二:配置struts.xml

 

步骤三:修改save.jsp页面,显示数据:

 

步骤四:测试

执行请求

 

  1. 重定向-redirect

步骤一:配置struts.xml

 

全局的结果集配置:

 

还是利用上述的save方法做举例,修改strust.xml中的结果集类型即可。

<!-- 结果集的使用:局部结果集 -->

        <action name="product_*" class="cn.itcast.struts.f_result.ProductAction"

            method="{1}">

            <!-- 结果集类型的默认值:转发 -->

            <!-- <result name="save" type="dispatcher">/f_result/save.jsp</result> -->

            <!-- 结果集类型的重定向 -->

            

            <!-- <result type="redirect">/f_result/success.jsp</result> -->

        </action>

 

步骤二:测试

执行请求

 

  1. 重定向到Action- redirectAction

 

 

之前的转发和重定向都是指向页面,但有的时候我们需要执行action,例如:当做完新增商品之后,需要重新查询商品列表,这个时候就需要指向action了

【举例】

商品保存后重定向到查询action

 

步骤一:action

ProductAction中的save方法保持不变,新增一个findAll方法:

public class ProductAction extends ActionSupport{

    @Override

    public String execute() throws Exception {

        System.out.println("执行默认方法!");

        return SUCCESS;

    }

    

    public String save(){

        System.out.println("保存商品成功!");

        ServletActionContext.getRequest().setAttribute("name","iphone 7 plus");

        return "save";

    }

    

    public String findAll(){

        System.out.println("查询所有商品成功!");

        return "findAll";

    }

}

 

 

步骤二:Struts.xml :修改save结果集视图

 

步骤三:测试

执行请求:发送新增商品的请求,执行完新增商品后重定向到product_findAll这个action,最后转发到index.jsp页面显示hello world

 

步骤四:分析

 

【result标签复杂写法】(了解)

其他写法:使用<param>标签传递参数的写法

注意param中的name属性值可以参考结果集相应的类:

 

 

 

 

  1. 课程内容整理

    1. 示例的编写步骤

创建一个案例需要的步骤:

  1. 创建项目
  2. 导包
  3. 在web.xml中配置前端控制器
  4. 创建包
  5. 创建提交数据的页面
  6. 配置struts.xml
  7. 测试
    1. 常用配置的注意事项

总格6个配置文件,分成两大类:

  1. 框架内置的配置文件:不能修改

    default.properties :常量配置

    struts-default.xml :配置了struts需要的bean、各类结果集以及拦截器(默认执行的拦截器栈-defaultStack

    struts-plugin.xml :struts的插件包需要的配置文件

  2. 用户自定义的配置文件:

    struts.xml:前端控制器会读取该配置文件中的标签来判断应该分发给哪个action,并且执行哪个action中的方法,最后响应哪一个结果集视图。

    struts.properties:只是用来配置常量的(了解)

    web.xml :配置常量(了解)

    潜规则:后面配置的常量会覆盖前面配置的常量

     

    加载顺序:1)default.properties  2)struts-default.xml  3)struts-plugin.xml 4)struts.xml 5)struts.properties 6)web.xml配置常量

3、默认的Action :配置错误请求需要默认执行的action,一般用来配置友好提示。

  1. Action的编写方式

  1. 实现Action接口(掌握)
  2. 继承ActionSupport(重点,必须掌握)
  3. 自定义pojo作为action(了解)
    1. Action访问的方法

  4. execute方法:访问action默认执行
  5. method属性:访问指定方法
  6. 通配符的使用:可以通过*表示占位{1}表示第一颗的占位。(重点掌握)

    注意事项:如果有两个通配符,先注意下方是不是有其他的通配符的使用,以免造成访问路径的错误。

  7. 动态方法调用:不需要配置method属性,通过!后面的单词来调用指定的方法,需要配置常量-开启动态方法调用。

 

  1. Action访问servlet API

  1. 解耦方式调用servlet API 
  2. 接口注入方式调用servlet API :实现接口方法,并且通过setter方法进行对象的传递。
  3. 静态方法调用:推荐使用

 

  1. Result结果集的使用

  1. 分为全局和局部结果集
  2. 结果集类型的使用:dispatcher 、redirect、redirectAction、stream

 

  1. 重点和小结

 

课后作业练习

需求:开发一个登录的小业务。

业务详情:

用户输入的用户名密码错误,跳回登录页面,让用户重新登录。

用户输入的用户名密码正确,重定向到主页,显示成功字样。--SUCCESS

技术选型:Struts2(Web层)

 

 

posted @ 2017-01-10 21:46  beyondcj  阅读(226)  评论(0编辑  收藏  举报