通过Struts了解MVC框架,兼说如何在面试中利用Struts证明自己

    虽然目前Struts MVC框架不怎么用了,但它确是个能帮助大家很好地入门Web MVC框架,而且,一些历史项目可能还用Struts,反正技多不压身,大家如果能在面试中通过项目证明自己Struts这块也很熟,这也是个非常好的加分项。

    这里我们就从搭建Struts基本框架入手,再深入讲解些面试中常会靠到的Struts知识点,本文的文字和案例根据java web轻量级开发面试教程改编。

///////////////////////////////////////////////////////////////////////////////////////

1 搭建Struts框架

1.1 开发前端的JSP代码

    创建一个Java Web项目,名为strutsDemo,在其中的WebRoot目录下,创建前端的JSP代码calSum.jsp。    

 1 1    <%@ page language="java" pageEncoding="GBK" %>
 2 2    <%@ taglib prefix="s" uri="/struts-tags"%>
 3 3    <html>
 4 4    <head>
 5 5    <title>输入操作数</title>
 6 6    </head>
 7 7    <body>
 8 8    求和<br/>
 9 9    <s:form action="mystruts/calSum" >
10 10    <s:textfield name="num1" label="数1"/>
11 11    <s:textfield name="num2"  label="数2" />
12 12    <s:submit value="求和" />
13 13    </s:form>
14 14    </body>
15 15    </html>

    这个页面的效果下图所示。

    在第2行里引入了Struts的标签,前缀是s,所以可以用s:form和s:textfield来定义form和文本框。

    在第9行到第13行的form里,定义了两个输入框和一个提交按钮。当用户输入两个数字后,单击“求和”按钮后,本页面将根据定义在第9行的定义,跳转到mystruts/calSum.action。

1.2 在web.xml里声明使用Struts

    如果要使用基于Struts的MVC,则必须要在web.xml里声明,否则系统服务器是不会知道在项目里用到了基于Struts的MVC处理器。web.xml的代码如下。

1    <?xml version="1.0" encoding="UTF-8"?>
2    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
3    <filter>
4    <filter-name>struts2</filter-name>
5    <filter-class>
6            org.apache.struts2.dispatcher.FilterDispatcher            
7    </filter-class>
8    </filter>
9    <filter-mapping>
10    <filter-name>struts2</filter-name>
11    <url-pattern>/*</url-pattern>
12    </filter-mapping>
13    </web-app>

    从第2行到第13行之间的web-app元素里,我们声明了两件事:

    (1)通过第11行的url-pattern,说明/*,也就是任何请求,都将由名为struts2的过滤器来处理。

    (2)在第3行到第8行之间,指定了struts2这个过滤器它的后台处理类。

综合上述两点可知,本项目的任何请求,都将由Struts的后台处理类来处理。     

1.3 配置struts.xml文件 

    在calSum.jsp里指定了form跳转的目的地。

    <s:form action="mystruts/calSum" >

    那么这个目的地究竟是哪里?一起来看一下struts.xml这个配置文件。    

1    <?xml version="1.0" encoding="UTF-8" ?>
2    <!DOCTYPE struts PUBLIC
      "-//Apache Software Foundation//DTD Struts Configuration2.0//EN"
      "http://struts.apache.org/dtds/struts-2.0.dtd">
3    <struts>
4    <package name="struts2" namespace="/mystruts"
5       extends="struts-default">
6    <action name="calSum" class="action.myAction">
7    <result name="Positive">/positive.jsp</result>
8    <result name="Negative">/negative.jsp</result>
9    </action>
10    </package>
11    </struts>   

    在第4和第5行里,能看到名为calSum的action处于/mystruts这个命名空间里,它所对应的是action.myAction这个处理类。也就是说,calSum.jsp的请求最终是由action.myAction接收和处理。

1.4 开发Action类

     随后开发myAction.java,它是放在action这个package下的。    

1	package action;
2	import com.opensymphony.xwork2.ActionSupport;
3	public class myAction extends ActionSupport
4	{
5	    private int num1;
6	    private int num2;
7	
8	    public String execute() throws Exception
9	    {
10		// 如果和大于等于0,则跳到positive.jsp页面
11		if (getSum() >= 0)  
12	        {
13	            return "Positive";
14	        }
15		//否则跳到negative.jsp页面
16	        else  
17	        {
18	            return "Negative";
19	        }
20	    }   
21	    public int getNum1() {
22			return num1;
23		}
24		public void setNum1(int num1) {
25			this.num1 = num1;
26		}
27		public int getNum2() {
28			return num2;
29		}
30		public void setNum2(int num2) {
31			this.num2 = num2;
32		}
33		public int getSum()
34	    {
35	        return num1 + num2;  // 计算两个整数的代码数和
36	    }
37	}

    作为一个Struts的Action,本类继承了ActionSupport类。当一个请求最终到达本Action时,如果没有额外的配置,就会如同本类一样,由execute方法来处理请求。

    在第8行的execute方法里可能看到,如果两个数的和大于0,则返回Positive字符串,反之则返回Negative。这两个返回是和struts.xml里的配置相对应的。

    在struts.xml的第6行和第7行里,看到有如下的配置。

    <result name="Positive">/positive.jsp</result>

    <result name="Negative">/negative.jsp</result>

    这说明根据不同的字符串,Struts处理容器将会跳转到两个不同的jsp里。在这个Action代码里,并没有给num1和num2赋值,这是因为它们和calSum.jsp里form中的两个输入框同名,所以会自动拿到我们输入的值。

1.5 开发两个跳转结果页面

    上文提到过,Action的execute方法里返回的不同字符串后,Struts MVC处理器会读取struts.xml里的配置,并相应地,跳转到不同的页面。下面就来编写这两个页面的代码。先来看一下positive.jsp。   

1	<%@ page language="java" pageEncoding="GBK"%>
2	<%@ taglib prefix="s" uri="/struts-tags" %>
3	<html>
4	<head>
5	<title>显示和</title>
6	</head>
7	<body>
8	结果大于或等于0,<h1><s:property value="sum" /></h1>
9	</body>
10	</html>

     这里的关键代码是在第8行,通过一个Struts的标签,来获取在Action里名为”sum”的属性对象。在myAction.java里,定义了一个getSum的方法,所以就会自动生成一个sum的属性。结果是两个操作数之和。

    Negative.jsp代码和positive.jsp很相似。唯一的差别在第8行,这里的叙述文字是“结果小于0”。   

1	<%@ page language="java" pageEncoding="GBK"%>
2	<%@ taglib prefix="s" uri="/struts-tags" %>
3	<html>
4	<head>
5	<title>显示和</title>
6	</head>
7	<body>
8	结果小于0,<h1><s:property value="sum" /></h1>
9	</body>
10	</html>

2 通过运行,了解Struts的工作流程

   现在来总结一下整个程序的运行和跳转流程。

    第一,打开Tomcat服务器,并在浏览器里输入http://localhost:8080/strutsDemo/calSum.jsp,能看到如下图所示的页面

    当输入两个数字,并单击“求和”按钮后,根据如下form里的定义,会跳转到mystruts/calSum里。

    <s:form action="mystruts/calSum" >    

    第二,根据web.xml的定义,可知这个跳转请求将由struts来处理。再根据struts.xml的定义,得知这个请求最终将由myAction.java来处理。

    <action name="calSum" class="action.myAction">

        <result name="Positive">/positive.jsp</result>

       <result name="Negative">/negative.jsp</result>

    </action>

    第三,在myAction.java的execute方法里,根据最终sum的值,分别返回两个不同的字符串,从上文struts.xml片段的第3行和第4行得知,根据两个不同的返回值,会跳转到两个不同的页面里。

3 和JSP+Servlet+JavaBean框架的比较

    在一个项目里,我们应更关注“业务该怎么处理”这个问题,而不应把大多数精力放在调试JSP到Servlet之类的跳转上。

    Struts给我们提供了一套跳转机制,我们可以简单地通过编写struts.xml和web.xml,就能比较省心地实现从前端JSP跳转到具体业务处理类的功能。而且,也只需在Action类里编写返回字符串,同时在struts.xml里编写返回字符串和跳转页面的对应关系,就能根据业务执行结果方便地跳转回前端页面。

    Struts框架是基于MVC的,它的View部分主要由JSP页面实现。Controler部分主要由Action类来承担,而Model部分主要由ActionForm组成。需要说明的是,在Struts2.0以上的版本里,开发者不需要额外定义ActionForm,由用户在前端Form里传入的数据将被自动封装成ActionFrom对象,并被最终转发给Action。

    通过下表对比一下Struts和前文提到的JSP+Servlet+JavaBean框架,综合各项对比的指标,Struts略优于JSP+Servlet+JavaBean框架。

比较项

Struts

JSP+Servlet+JavaBean

结论

如何在后端接收前端传来的参数

参数组装成ActionForm,并自动发送到Action里

需要在Servlet里编写接收参数的代码

Struts比较省心

如何把前端的请求发送到合适的处理页面

可以在struts.xml里统一定义请求和处理类的对应关系

可以在web.xml里统一定义请求和处理类的对应关系

基本持平

后端处理请求的方式

定义在Action里

大多定义在Servlet类的doPost或doGet方法里

基本持平

如何把后端的处理结果再回传到前端

可以在struts.xml里统一地定义处理结果和返回页面的对应关系

需要在Servlet里手动地跳转

Struts略优

项目的开发方式

程序员的工作量比较少,在必要的地方(比如Action类和Struts.xml)里填写必要的代码即可,Struts处理器能方便地实现MVC之间的跳转

程序员可能得操心必要的细节,比如Servlet里如何接收参数,如何跳转到前端,等等

Struts的开发流程比较省心

4 对Struts框架的进一步了解

    Struts作为一个基于MVC的框架,能很好地处理跳转业务,能让程序员把精力更多地集中到业务开发上,通过它,程序员能很好地了解框架编程的思路和一般方法。

    不过任何框架都不是十全十美的,当你比较熟悉Struts框架后,一定能感受到它在项目开发里的一些缺陷。对于Struts的局限性,不同的人有不同的观点。但是请大家记住,在面试时,当你结合你的项目自信地说出Struts框架的局限时,即使面试官和你的观点不一致,他也一定会认为你对Struts有足够的认识。这里罗列出一些局限性供大家参考,如表所示。

局限性

结合项目说明

为每个请求创建一个Action

Struts2里,会为每个http请求实例化一个Action 对象,这对处理高并发会有些难度

对Action 执行前和后的处理支持不大好

比如每次进到Action前我们需要打印内存使用量,执行后需要记录跳转目标URL,这个当然可以直接写到Action里,但大家比较下Spring的AOP处理方式,就会发现单纯把前后处理写到Action里有什么不足

对跳转的支持

如果在一个Action里,根据处理结果可能会跳转到10个页面,那么代码可能会比较烦琐。而且一旦跳转目标页面出现变更,比如换了目录,那么在修改配置文件后,可能要求重新部署和重启Web服务器,无法实现轻量级修改

安全性上的瑕疵

我们可以通过类似方式直接执行Action里的方法:http://url:8080/proName/userLogin!list 但事实上,该系统需要用户先登录才能开放用户列表。虽然我们可以通过定义拦截器来弥补这个缺陷,但毕竟属于额外的工作量

属于侵入式

在使用Struts时,需要继承struts的类,而且要编写execute方法。这样Struts框架就侵入到项目里了。比如做的是银行业务,如果哪天要把这套业务移植到其他Spring等框架项目里,可能工作量就比较大了

5 关于Struts面试点的归纳

   Struts的地位似乎有些尴尬,一些小型(比如10个页面左右)的商业项目可能直接会用JSP+Servlet+JavaBean+DB的开发模式,一些大型基于企业级的项目往往采用Spring+MyBatis的框架。

    我们在面试初级程序员时,如果候选人没有在商业项目里用过Struts框架,这很正常,如果他在学校或者培训机构学过Struts,这或许也可以成为一个加分项。但如果我们看到某人在最近的商业项目里用过,那么就会详细问原因,为什么这个公司现在还要用Struts框架?反而有不少人,在这个问题上会弄巧成拙。我们听到的最多的合理回答是,基于某种原因,比如历史原因或者客户要求,这个项目还是得用Struts框架。

    具体到面试题,大家可以从网上找,在必要的时候,大家也可以多多益善地突击准备。我们给大家推荐回答问题的方式是“结合项目”,请大家看如下的问题点。

    第一,说明在这个项目里,都用到了Struts的哪些组件,比如拦截器或者验证器,你是怎么用的?

    第二,结合项目,说明自己做了哪些工作,比如在Action里,你怎么和业务以及数据库代码耦合?

    第三,能结合项目,告诉考官一些技术细节,比如拦截器是怎么用的,在该项目里结合一个需求,告诉考官拦截器的工作流程和开发方式。或者结合项目说明下验证器的用法。

    也就是说,任何技术都别停留在纸上,需要结合项目说明。

    第四,说明使用Struts框架给这个项目带来哪些痛点?

    第五,和Spring框架相比,你感觉各自有什么优缺点,请结合项目说明,不要空谈。

    当你学好了Spring框架后就知道该怎么说?

    第六,你的项目经常会扩展,业务实现方式也经常会变更,结合Struts框架说明一旦出现变更了你需要做哪些事?

    比如需要更改业务,你该更改哪些文件?一旦更改了代码,如何部署到服务器上?

    第七,这个项目的访问量是多少?最高的并发访问量能达到多少?Struts框架能否很好地处理高并发的情况?

    关于常用的技术问题,在本章里都已经提到,我们通过如下问题点来对本章做个总结。

    ①在Struts2里,如何实现一个Action?

    ②怎么指定进入Action后该调用哪个方法?

    ③定义验证器的步骤是什么?

    ④定义拦截器的步骤是什么?

    ⑤Struts2中的type类型有哪些?如果不写type,默认是什么?

    ⑥如何通过配置type类型,实现一个Action往另外一个Action的跳转?

    ⑦描述下Struts MVC的工作流程和开发模式。

    ⑧和JSP+Servlet+JavaBean的开发模式相比,Struts MVC有哪些好处,同时,说明下Struts框架有哪些不足。     

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java思维导图

rpc思维导图,让rpc不再难懂

解析 RPC(Remote Procedure Call),远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。 ? 在O...

39290
来自专栏信安之路

web测试方法工具篇

之前写过一个文章《web应用渗透测试流程》,这个文章的主要内容是关于一个web应用如何进行测试,测试什么地方,没有过多的提供使用的工具,只是一个针对web测试的...

18600
来自专栏PHP在线

缓存更新的套路

看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中。然而,这个是逻辑是错误的。试想,两个并发操作,一个是更新操作...

388130
来自专栏一枝花算不算浪漫

【python】Python 资源大全中文版

66120
来自专栏Janti

你可以这么理解五种I/O模型

因为项目需要,接触和使用了Netty,Netty是高性能NIO通信框架,在业界拥有很好的口碑,但知其然不知其所以然。

21050
来自专栏阮一峰的网络日志

计算机是如何启动的?

从打开电源到开始操作,计算机的启动是一个非常复杂的过程。 ? 我一直搞不清楚,这个过程到底是怎么回事,只看见屏幕快速滚动各种提示...... 这几天,我查了一些...

36350
来自专栏友弟技术工作室

Python 资源大全中文版

GitHub 上有一个 Awesome - XXX 系列的资源整理,资源非常丰富,涉及面非常广。awesome-python 是 vinta 发起维护的 Pyt...

1K50
来自专栏CSDN技术头条

为Symfony2和Redis正名,基于PHP的10亿请求/周网站打造

【编者按】如果你还在Symfony2和Redis使用中存在这样的错误观念:不能使用Redis作为主要存储;Symfony2的功能很多,以至于它的运行很慢,那么不...

25050
来自专栏Vamei实验室

被解放的姜戈01 初试天涯

Django是Python下的一款网络服务器框架。Python下有许多款不同的框架。Django是重量级选手中最有代表性的一位。许多成功的网站和APP都基于Dj...

1.8K60
来自专栏猫哥学前班

猫哥网络编程系列:HTTP PEM 万能调试法

注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新。 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么...

42060

扫码关注云+社区

领取腾讯云代金券