Struts2 框架入门

Struts2

JAVA基础学完,肯定是要面临三大框架的学习的,作为初学者,了解三大框架的原理,设计目的是首要任务,只有在把握了框架的设计目的以后,才能有针对性的取学习使用框架,这里从strue2框架开始,介绍三大框架,让新手能有一个总的了解跟思维导图。

1、什么是Struts2?

  • Struts2 是一个非常优秀的MVC框架,基于Model2 设计模型,由传统Struts1和WebWork两个经典框架发展而来
  • Strust2 核心功能
    (1)允许POJO(Plain Old Java Objects)对象 作为Action
    (2)Action的execute 方法不再与Servlet API耦合,更易测试
    (3)支持更多视图技术(JSP、FreeMarker、Velocity)
    (4)基于Spring AOP思想的拦截器机制,更易扩展
    (5)更强大、更易用输入校验功能

概念:轻量级的MVC框架,主要解决了请求分发的问题,重心在控制层和表现层。低侵入性,与业务代码的耦合度很低。Struts2实现了MVC,并提供了一系列API,采用模式化方式简化业务开发过程。

与Servlet对比

  • 优点:业务代码解耦,提高开发效率
  • 缺点:执行效率偏低,需要使用反射、解析XML等技术手段,结构复杂

不同框架实现MVC的方式

Servlet:

Struts2:
 

spring:

2、定位

SSH框架系统从职责上分为四层:表示层、业务逻辑层、数据持久层和域模块层(实体层)。

这里写图片描述

Struts2作为表现层的框架设计存在,Hibernate处于数据持久层,Spring处于业务逻辑层,担任连接Struts和Hibernate桥梁的角色。系统的整个层次关系可以一目了然。

3、技术优势

Struts2有两方面的技术优势

  • 一是所有的Struts2应用程序都是基于client/server HTTP交换协议,The Java Servlet
    API揭示了java Servlet只是Java API的一个很小子集,这样我们可以在业务逻辑部分使用功能强大的Java语言进行程序设计。
  • 二是提供了对MVC的一个清晰的实现,这一实现包含了很多参与对所以请求进行处理的关键组件,如:拦截器、OGNL表达式语言、堆栈。

这里写图片描述

  • ActionServlet,前端控制器

    1、根据相应的规则截取Http请求的URL
    2、将Http请求分发到相应的Action处理

  • ActionForm,相当于实体

    1、收集表单数据,将表单数据转换成相应的数据类型

  • Action,业务层控制器

    1、 取得表单数据
    2、调用业务逻辑
    3、返回转向信息

因为struts2有这样目标,并且有这样的优势,所以,这是我们学习struts2的理由,下面,我们在深入剖析一下struts的工作原理。

4、Strusts2的工作原理

  • 工作流程图
  • 这里写图片描述

  • 工作原理图

这里写图片描述

(1) 客户端(Client)向Action发用一个请求(Request)
(2) Container通过web.xml映射请求,并获得控制器(Controller)的名字
(3) 容器(Container)调用控制器(StrutsPrepareAndExecuteFilter或FilterDispatcher)。在Struts2.1以前调用FilterDispatcher,Struts2.1以后调用StrutsPrepareAndExecuteFilter
(4) 控制器(Controller)通过ActionMapper获得Action的信息
(5) 控制器(Controller)调用ActionProxy
(6) ActionProxy读取struts.xml文件获取action和interceptor stack的信息。
(7) ActionProxy把request请求传递给ActionInvocation
(8) ActionInvocation依次调用action和interceptor
(9) 根据action的配置信息,产生result
(10) Result信息返回给ActionInvocation
(11) 产生一个HttpServletResponse响应
(12) 产生的响应行为发送给客服端。

StrutsPrepareAndExecuteFilter或FilterDispatcher)。在Struts2.1以前调用FilterDispatcher,Struts2.1以后调StrutsPrepareAndExecuteFilter,那么,他们之间真正的区别目的在哪里呢,作者特地去百度了下。

  • StrutsDispatch和StrutsPrepareAndExecuteFilter区别

FilterDispatcher是struts2.0.x到2.1.2版本的核心过滤器.!
StrutsPrepareAndExecuteFilter是自2.1.3开始就替代了FilterDispatcher的.!
这样的改革当然是有好处的.!
为什么这么说.? 应该知道如果我们自己定义过滤器的话, 是要放在strtus2的过滤器之前的, 如果放在struts2过滤器之后,你自己的过滤器对action的过滤作用就废了,不会有效!除非你是访问jsp/html!
那我现在有需求, 我必须使用Action的环境,而又想在执行action之前拿filter做一些事, 用FilterDispatcher是做不到的.!
那么StrutsPrepareAndExecuteFilter可以把他拆分成StrutsPrepareFilter和StrutsExecuteFilter,可以在这两个过滤器之间加上我们自己的过滤器.!
给你打个比喻, 现在有病人要做手术, 现在struts2要做两件事, 搭病床(环境),执行手术.! 那么打麻药的工作呢.? 不可能要病人站着打吧, 所以必须有病床的环境,打完麻药之后再动手术.! 这个比喻非常形象了!

5、Struts2的下载和安装

  • 下载

    http://struts.apache.org/download.cgi 去下载Struts2 最新版

  • struts2目录结构

    apps 该文件夹包含了基于struts2 的示例应用,这些示例应用对于学习者是非常有用的
    docs 该文件夹下包含了struts2 相关文档,包括struts2 快速入门、struts2的文档以及API文档等
    lib 该文件夹下包含了Struts2框架和核心类库,以及struts2第三方插件类库
    src 该文件夹下包含了Struts2框架的全部源代码
    开发时没必要将lib目录下jar文件全部复制到项目中

  • Struts运行必要jar包

    struts2-core-2.3.1.1.jar:Struts 2框架的核心类库
    xwork-core-2.3.1.1.jar:Command模式框架,WebWork和Struts2都基于xwork
    ognl-3.0.3.jar:对象图导航语言(Object Graph Navigation Language),
    struts2框架通过其读写对象的属性
    freemarker-2.3.18.jar:Struts 2的UI标签的模板使用FreeMarker编写
    commons-logging-1.1.x.jar:ASF出品的日志包,Struts 2框架使用这个日志包来支持Log4J和JDK 1.4+的日志记录。
    commons-fileupload-1.2.2.jar: 文件上传组件,2.1.6版本后需要加入此文件
    commons-io-2.0.1.jar:传文件依赖的jar包
    commons-lang-2.5.jar:对java.lang包的增强

    开发中为了方便导入,可以使用app/struts2-blank.war 携带jar包

6、第一个Struts2应用入门

只需要五步,即可完成。

1、导入jar包

2、在web.xml中配置过滤器

3、核心Action类。

4、配置struts.xml

5、测试

第一步:非常简单,jar包肯定是记不住的,但是我们要会找。在下载的Struts的jar包中,我使用的是struts-2.3.15.1版本,其中的目录结构需要了解。

这里注意一点,lib下面有100多个jar包,并不需要导入这么多,我们在apps(案例)中找jar包即可,apps-blank.war是最简单的案例,我们把其后缀名改为zip,然后解压,找到其中的lib目录下的jar包复制就行了

第二步:配置过滤器,这个也简单,我们学过过滤器了,配置就跟配置servlet一样。

<filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>

第三步:编写核心Action类

Action类可以有三种不同的类型

1、普通类,POJO,什么接口也不实现,什么类也不继承

2、实现Action接口

3、继承ActionSupport类。

这里我们使用普通类即可,最终我们会选择使用继承ActionSupport类,具体原因看下面。

action类实现的三种方式

1、普通类,上面写helloworld就是使用的普通类

2、实现Action接口,重写excute方法,接口中就声明这一个方法。

3、继承ActionSupport类,可以不必重写execute方法,只需要写自己想要的方法即可,一般开发中就使用这种方法,为什么呢?因为方便,ActionSupport类提供了一些我们所需要的常量,比如success字符串常量,内部还实现了execute方法,我们就不必自己写了。那么很多人就问,这不是多此一举吗?继承它跟不继承它的区别不大呀?哈哈,这样举个例子吧,你想追一个女孩子,有一天哪个女孩子哭了,擦泪的纸巾在女孩子的旁边,那个女孩子完全可以自己拿纸巾,但是你为了追她,体现自己好的一面,肯定是自己去拿纸巾出来递给她,虽然可能你拿比她自己拿更麻烦一点,但是这样让她对你更有好感呀, 那么这个继承actionSupport提供的一些常量等,也就是这个道理。并且它还不止止这点功能,它自己内部帮我实现了很多接口,后面会有讲解到,现在就晓得,以后写的话就通过这种方式去写action类。

第四步:编写struts.xml

写的时候忘记了格式,也没关系,找模版。从图中也可以看出,struts.xml文件就放在src下即可

struts.xml的配置详解

注意:action.class可以不写,有默认值,为ActionSuppport类的全县定名,下面会有讲到,action.method也可以不写,默认值为execute,result.name也可以不写,默认值为success。

核心代码 

<struts>

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

        <action name="Demo01Action" class="com.wuhao.struts2.test.Demo01Action" method="execute">
            <result name="success">
                /index.jsp
            </result>
        </action>
    </package>

</struts>

第五步:测试

http://localhost:8080/struts2-hello/Demo01Action其中用加粗标记的就是我们在struts.xml中设置的package的namespace+action中的name。通过/Demo01Action到struts.xml中就能找到在default包下的名为Demo01Action的action,然后通过class找到该action的所在位置,通过method找到需要执行的方法,通过方法的返回值找到result中是否有对应的值,找到了则进行跳转。

7、两个重要的配置文件

注意:这里解释一下struts.xml中的package继承问题。上面继承了一个struts-default的包,想要查看它中的内容很简单,在我们加入的struts2-core-2.3.15.1.jar包找到struts-default.xml,在该配置文件中就有package为struts-default的内容。

第一个需要知道的配置文件:struts-default.xml

从名字上看,就应该知道该是struts的一个默认的配置文件,而我们前面编写的一个startus.xml中应该会使用该默认配置文件中的内容,其中的格式跟我们写的struts.xml是一样的。

分两大部分,

第一部分 全是bean开头的配置,暂时不管他是干嘛用的,后面会学习,而我们的重点是第二部分

第二部分 看到了熟悉的内容,package,并且该package的名字为struts-default。这就是我们需要查找的包,其中的内容包括了三个部分

1、<result-types></result-types>看到这里我们就明白为什么我们的结果中跳转页面的方式默认是dispatcher(转发),因为在继承的struts-default包中将其设置成了默认的,还有很多其他的type可选择,比如其中的redirect,就是重定向,比如redirectAction,从一个action跳到另一个action中执行。比如stream,文件上传时用的,等等这些等后面会详细讲到。有个大概映像即可

2、<interceptors></interceptors>,这里是一系列的过滤器,就是我们讲的架构图中的那一系列拦截器,就是在这里给配置的。这里具体不讲解,后面会有章节进行讲解,有映像即可

3、最后一个是两个零碎的配置

321行:配置说默认的一个拦截器为defaultStack,这是一个拦截器栈,其内容在第二部分中,
323行,这里说的class为在我们action中的class,如果不写则为com.opensymphony.xwork2.ActionSupport。ActionSupport这个类就我们下面要讲解的action继承它来当action,那时候再与普通类当action有什么区别。

总结:struts-default.xml的功能就是将一些已经有的功能加入到配置文件中,然后让我们编写的struts.xml继承其中的包,那么我们就具备了这些功能,不用自己手动编写了,如果想在上面添加功能,在编写即可。到这里为止应该就解决了为什么要继承struts-default这个包了把。

第二个配置文件:default.properties,这是一个常量的配置文件。其中放的都市常量。  

比如:

struts.i18n.encoding=UTF-8  设置请求乱码和响应乱码的常量

struts.objectFactory = spring  这种带spring的都市和spring整合时需要用到的。现在不用管

struts.multipart.saveDir=    文件上传时所存放的临时路径

struts.action.extension=action,,  访问action时的后缀名可以为action,也可以什么都不写,就是通过这个常量设置

struts.enable.DynamicMethodInvocation = true  是否采用动态方法,比如Demo01Action!add  通过!add来动态确定执行的哪个方法,在配置文件中就不用写method属性了

struts.devMode = false    开发者模式,如果改为true,则修改了struts等配置文件,不用重启服务器即可生效,并且错误提示信息更多

struts.ui.theme=xhtml     struts自带控件的一些布局,但是一般使用simple,页面的美化由美工处理。

以上说的都是一些常见的常量,其他的等遇到了在说,重点了解设置编码和开发者模式和布局。其中这些常量的值可以在struts.xml通过<constant name="" value="">来配置。

8、Action访问的三种方式

前面几个部分介绍了什么是struts2?Struts2的helloworld,并且知道了struts2的架构流程图。知道了struts2的两个比较重要的配置文件的内容,现在来说说对于action访问的方式,在struts1中访问action,一般是带有后缀名为.do,而现在是为.action,为什么能这样写的原因在上面说明了,default-properties文件中就有这样一个常量来说明使用什么后缀访问。可以为.action也可以不写。所以在访问action时,一般为:http://localhost:8080/xxx/xxxAction.action

但是写了几次helloworld之后,会发现一个缺点,一个action中有多少个方法,那么就需要在struts.xml中配置多少个个action,并且每个action就method的值改变了,其他都不变,所以为了改变这种状态,有三种方法可以解决。

第一种方法:在struts.xml中的action属性标签中用method属性指定方法名(不怎么推荐使用)

第二种方法:动态方法的调用

在struts.xml中开启动态方法的使用。struts.enable.DynamicMethodInvocation = true

那么就可以直接使用http://localhost:8080/xxx/xxxAction!add  直接调用xxxAction中的add方法了,并且在struts.xml中的action配置中,就不需要配置method属性的值了。这样做就解决了写死method值的问题

第三种方法:通配符的使用

这个比较重要,使用的比较多,即,<action name="userAction"> , action.name可以使用通配符星号(*),在action.class、aciton.method、result.name 处可以使用{n}方式匹配星号,举个例子就明白了

案例一:<action name="userAction_*"> 在action.class、action.method、result.name三个地方可以使用{1}来获取第一个星号所匹配的内容

请求路径:…./userAction_add   

<action name="userAction_* class="..." method="{1}"/>

那么{1}拿到的内容则是add,将执行add方法

案例二:<action name="userAction_*_*">  {1}匹配第一个* {2}匹配第二个*    

请求路径 :…/userAction_add_success <action name="userAction_*_*" method="{1}"><result name="{2}">    

{1}匹配add方法,{2}匹配返回值的名称success   

案例三:使用_*_,通过{1}{2}{3}获得,可以自己尝试。

注意:package.namaspace的特点,当namespace为”/a”时,正常通过/a/xxxAction就能访问到,但是如果/a/b/c/xxxAction是否能访问到呢?答案是YES,因为会一层一层往下找,什么意思呢?

http://localhost:8080/xxx/a/b/c/xxxAction 找不到,往下一层找

http://localhost:8080/xxx/a/b/xxxAction找,也找不到,继续往下

http://localhost:8080/xxx/a/xxxAction 我们这里配置的namespace为”/a”,所以就找到了,如果我们namespace=”/”,那么/a/b/c/xxxAction就访问不到了,只有/xxxAction能访问到。但是如果namespace=”“,那就找得到,什么都不写的意思是不管什么路径都能匹配到。

9、 Action的动态结果的配置

含义:在实际运行当中,Action类的处理业务的过程中,可能由于业务条件的复杂,会跳转到不同页面,那么为了节省result的配置,我们一般会采用动态结果的配置。其实很像我们在servlet中进行全局的forward的配置。

UserAction.java

public class UserAction extends ActionSupport {
    private String nextResult;
    ...
}

Struts2.xml

<action name="user" class="action.UserAction">
    <result>/{nextResult}</result>
</action>

10、接收用户数据(推荐使用的实现ModelDriven的接口)

在这篇博客中我只是介绍常用的,并且在实际项目中效率较高的方法。我之所以推荐ModelDriven接口的方法,原因就是可以很好的分离显示界面和业务逻辑的分离(解耦性)。

实现ModelDriven接口

步骤:

  • 实现用户登录功能
  • 创建User.java类
  • 声明用户登录信息
  • 创建无参构造
  • 创建Action类
  • 实现com.opensymphony.xwork2.ModelDriven接口
  • 声明User类对象并实例化
  • 实现getModel ()方法,返回User类对象
  • 创建JSP页面
  • 表单元素使用”属性”设置name属性

注意:

1) 首先,action要实现ModelDriven的接口,默认实现getModel()方法

2) 要在action中自己来实例化user的对象,而不像前面一种方法是有struts2的框架实现的

3) 比较突出的就是在jsp页面中,表单元素的name属性,直接用名字就可以来

UserAction.java

public class UserAction implements ModelDriven<User>  {
    //要实例化
    private User user=new User();

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
    public String myfun() throws Exception {
        System.out.println("username="+user.getUsername());
        System.out.println("password="+user.getPassword());
        System.out.println("myfun.....");
        //用来进行处理
        if(user.getUsername().equals(user.getPassword())){
            return "success";
        }else{
            return "error";
        }


    }

    public User getModel() {
        // TODO Auto-generated method stub
        return user;
    }



}

login.jsp

<form action="loginuser.action" method="post">
    <!-- 需要注意的是要保证表单中的name的命名要和Action中属性的命名保持一致 -->
        用户名:<input type="text" name="username" id="username"><br>
        密     码:<input type="password" name="password" id="password">
        <br>
        <input type="submit" value="提交">

    </form>

11、在Action中访问Servlet API

访问Servlet API的实际项目中有两种的方法访问Servlet API

1)解耦的方法(实现三大接口程序RequestAware,ApplicationAware,SessionAware)

public class UserAction2 implements ModelDriven<User> ,RequestAware,SessionAware,ApplicationAware{

    private User user = new User();

    private Map<String, Object> requestMap;
    private Map<String, Object> sessionMap;
    private Map<String, Object> applicationMap;


    public void setApplication(Map<String, Object> applicationMap) {
        this.applicationMap=applicationMap;

    }

    public void setSession(Map<String, Object> sessionMap) {
        this.sessionMap=sessionMap;
    }

    public void setRequest(Map<String, Object> requestMap) {
            this.requestMap=requestMap;

    }


    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String myfun() throws Exception {
        System.out.println("username=" + user.getUsername());
        System.out.println("password=" + user.getPassword());
        System.out.println("myfun2.....");
        // 用来进行处理
        if (user.getUsername().equals(user.getPassword())) {

            sessionMap.put("Succ", "成功的哇2!!!");
            Bookbiz bookbiz=new Bookbiz();

            applicationMap.put("books",bookbiz.getBooks());

            return "success";
        } else {

            requestMap.put("errorMsg", "登陆失败了2");
            return "error";
        }

    }


    public User getModel() {
        // TODO Auto-generated method stub
        return user;
    }

注意:在非解耦的方式中,struts2框架已经将对应的四大应用作用域给封装到了Map集合中,所以这里一开始定义的三个Map集合中可以相当于操作四大作用域对象

2)非解耦的方法(实现两大接口程序ServletReuqestAware,ServletContextAware):非解耦的意思就是说直接操作的Servlet API对象

public class UserAction4 implements ModelDriven<User>,ServletRequestAware,ServletContextAware{

    private User user = new User();

    private HttpServletRequest request;
    private HttpSession session;
    private ServletContext application;

    public void setServletContext(ServletContext application) {
        this.application = application;

    }

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

    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
………………

注意:在实现接口中只实现了request和application的获取
在实际项目开发当中,需要的获取session的方法是通过Httpsession session= request.getsession();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值