前面花一周时间学习了servlet+jsp+mysql, 并且简单实现了登录注册等操作。对Servlet应用有了基础了解!

关于Struct2这个经常听说,但是自己没有用过。今天在这学习总结下,目的是学完后知道Struct2是怎么回事,后面怎么可以简单应用。

著名的SSH三大框架分别为:表现层(Struts)、业务逻辑层(Spring),持久化层(Hibernate).

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

Struts2作为表现层的框架设计存在,hibernate处于数据持久层。Spring处于业务逻辑层,担任连接Struts2和Hibernate桥梁的角色。

一:sturts.xml文件解析

 <?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> <constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" /> <package name="zxl" namespace="/" extends="struts-default"> <action name="Demo01Action" class="action.Demo01Action" method="execute">
<result name="success">/index.jsp</result>
</action>
<action name="HelloAction" class="action.HelloAction" method="execute">
<result name="success">/HelloWorld.jsp</result>
</action> <action name="LoginAction" class="action.LoginAction" method="execute">
<result name="success">/welcome.jsp</result>
</action>
</package> <include file="example.xml"/>
<include file="struts-constant.xml"/>
<include file="struts-dynamic.xml"/>
<include file="struts-actionsupport.xml"/>
<!-- Add packages here -->
</struts>

package:将Action配置封装,就是可以在package中配置很多action,用来管理action的,一般情况下package是针对模块划分的,

  name属性:给包起个名字,起到标识作用,随便起。不能与其他包名重复

  namespace属性:给 action 的访问路径中定义一个命名空间(action的前缀)

1、namespace与URL有关
    2、如果namespace=”/”; 那么在url中项目名称后面紧接着跟action中name的名称
    http://localhost:8080/struts/helloworldAction
    3、如果namespace为”/base”; 那么就应该在项目名称后面加上base
    http://localhost:8080/struts/base/helloworldAction 可以请求到页面
    http://localhost:8080/struts/base/a/helloworldAction 也可以请求到
    但是这个会先找 base/a 下的 helloworldAction,其次是寻找 base 下的 helloworldAction
    4、在url中加了几层命名空间,则在转向到jsp页面时,jsp的路径也会加几个命名空间的名字的路径
    5、如果采用上述的命名空间的形式,命名空间有什么的名称,在webroot下就应该建立什么样的文件夹
  extends属性:继承一个指定包 struts-default 在core核心包最下面 struts-deffault.xml168行 必选

  abstract属性:包是否为抽象的;标识性属性,该包不能独立运行专门被继承。和name一样给开发看的

action元素:配置action类
  name属性:决定了Action 访问资源名
  class属性:action的完整类名
  method属性:指定调用Action中的那个方法来处理请求
 
result元素:结果配置,action类中的方法必须返回一个字符串。
  name属性:标识结果处理。返回的字符串要和result标签中的name属性的名称对应,Name的值可以省略,
                           其默认值是“success”与action方 法的返回值对应
  type属性:指定调用那一个 result 类来处理结果(转发|重定向)默认使用转发
 
include引入:引入其他struts配置文件<include file="struts-constant.xml"/>

二、简单例子

 到此处已经在本地按照帖子的内容本地练习了几个Struts2Demo例子,如下:
 
 

一共写了三个action, 下面给出具体例子:

 package action;

 public class Demo01Action {

     public String execute(){
System.out.println("访问到了。。。。。。");
return "success";
}
}
 package action;

 public class HelloAction {

     public String execute(){

         System.out.println("hello, world");
return "success";
} }

下面看一下我们配置的struts.xml, 这个文件直接放在src路径下,

 <?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> <constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" /> <package name="zxl" namespace="/" extends="struts-default"> <action name="Demo01Action" class="action.Demo01Action" method="execute">
<result name="success">/index.jsp</result>
</action>
<action name="HelloAction" class="action.HelloAction" method="execute">
<result name="success">/HelloWorld.jsp</result>
</action> <action name="LoginAction" class="action.LoginAction" method="execute">
<result name="success">/welcome.jsp</result>
</action>
</package> <include file="example.xml"/>
<include file="struts-constant.xml"/>
<include file="struts-dynamic.xml"/>
<include file="struts-actionsupport.xml"/>
<!-- Add packages here -->
</struts>

看看我们配置的action,执行相应的class和其函数,然后返回String,若是“success”,则会跳转到对应的jsp页面。

看一下对应的jsp配置:

index.jsp

 <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!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=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
Hi, Struts2!!! </body>
</html>

HelloWord.jsp

 <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%
String path = request.getContextPath();
int i=0;
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> <html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<a href="HelloAction">hello</a> <br>
i:<%=i%><br>
</body>
</html>

然后我们看一下web.xml配置

<?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>Struts2Demo</display-name> <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> <welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>

主要看清楚上面filter配置,下面一节会给出一般filter的介绍,后面一节会给出struts2这个filter StatusPrepareAndExecuteFilter源码分析

现在我们可以通过浏览器访问一下action:

我们可以看到通过浏览器访问,最后显示出来jsp页面。只是在Struts.xml中配置了一下action。 而我们定义的action中只定义了一个execute函数。看桑去很简单,也没有传参数HttpServletRequest和HttpServletResponse等。可以在此比较下Servlet和Struts2,  这个简单例子体现不出Struts2的优势。

我们再看第三个action例子,一个简单登录场景:

LoginAction.java

 package action;
import login.User;
public class LoginAction { User user; /**
* @return the user
*/
public User getUser() {
return user;
} /**
* @param user the user to set
*/
public void setUser(User user) {
this.user = user;
} public String execute(){ return "success";
}
}

User.java

 package login;

 public class User {

     private String name;
private String password;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
}

下面看一下登录的jsp,

login.jsp,  在web.xml中配置了,可以直接通过项目工程名访问。

 <%@ 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>登录实例</title>
</head>
<body>
<form action = "LoginAction.action" method="post">
<p>用户名 <input type = "text" name="user.name"/>
</p>
<p>密码 <input type = "text" name="user.password"/>
</p>
<input type = "submit" value = "登录"/>
</form>
</body>
</html>

欢迎登录界面welcome.jsp

 <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!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=ISO-8859-1">
<title>登陆成功</title>
</head>
<body>
<p>您的用户名是:<s:property value="user.name"/>
</p>
<p>您的密码是:<s:property value="user.password"/>
</p>
</body>
</html>

然后看一下运行效果:

上面这个例子中,有一个地方没明白:这个user.name是怎么和User.java联系起来的,这个值是怎么传递的?????

到此三个例子也没看出Struts2的优势在哪,并且通过Servlet都可以完成!

三、Struts2原理

提到Struts2原理,一般都是Struts2官方文档中的那张图,下面贴一张类似的图,从一个博客中贴过来的,基本一样。

第一步:请求action,那么就会经过StrutsPrePareAndExecuteFilter, 这里会做两件事情,就是下面的两步,

第二步:通过ActionMapping将请求中的各种数据封装起来,拿到请求中的各种参数数据。

第三步:给自己找一个代理对象ActionProxy,来帮助我们处理事情。注意,这个ActionProxy实际上不做任何事情,而是指挥别人做。

第四步:ActionProxy叫ConfigManager获取struts.xml中的各种配置信息,其中struts.xml就有action的类权限定类名等信息,这样就可以通过action的名字找到其位置了。

第五步:有了ActionMapping获取的请求数据和ConfigManager获取的struts.xml中的数据,就叫ActionInvacation来查找对应的action

第六步:在找到action之前会经历一系列的拦截器,struts内部默认实现的。找到action后就相当于我们的servlet,在其中执行一些业务代码,然后跳转到目标页面,响应回去。struts的整个过程就结束了。

此时再回头看我们前面的例子:

我们需要做的就是:配置struts.xml, web.xml,编写action.java ,跳转页面jsp等。

action类实现的三种方式

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

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

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

下面我们看一下官方struts文档介绍:Struts2的官方文档附带了Struts2的架构图。从这张图可以很好的去理解Struts2

从这个上面也可以看出,我们用户需要修改哪几部分:struts.xml,   action,    jsp等。

关于图中的Key:

Servlet Filters:过滤器链,客户端的所有请求都要经过Filter链的处理。
    Struts Core:Struts2的核心部分,但是Struts2已经帮我们做好了,我们不需要去做这个
    Interceptors,Struts2的拦截器。Struts2提供了很多默认的拦截器,可以完成日常开发的绝大部分工作;而我们自定义的拦截器,用来实现实际的客户业务需要的功能。
    User Created,由开发人员创建的,包括struts.xml、Action、Template,这些是每个使用Struts2来进行开发的人员都必须会的。
1.FilterDispatcher是整个Struts2的调度中心,也就是MVC中的C(控制中心),根据ActionMapper的结果来决定是否处理请求,如果ActionMapper指出该URL应该被Struts2处理,那么它将会执行Action处理,并停止过滤器链上还没有执行的过滤器。
2.ActionMapper 会判断这个请求是否应该被Struts2处理,如果需要Struts2处理,ActionMapper会返回一个对象来描述请求对应的ActionInvocation的信息。
3.ActionProxy,它会创建一个ActionInvocation实例,位于Action和xwork之间,使得我们在将来有机会引入更多的实现方式,比如通过WebService来实现等。
4.ConfigurationManager是xwork配置的管理中心,可以把它看做struts.xml这个配置文件在内存中的对应。
5.struts.xml,是开发人员必须光顾的地方。是Stuts2的应用配置文件,负责诸如URL与Action之间映射关系的配置、以及执行后页面跳转的Result配置等。
6.ActionInvocation:真正调用并执行Action,它拥有一个Action实例和这个Action所依赖的拦截器实例。ActionInvocation会按照指定的顺序去执行这些拦截器、Action以及相应的Result。
Interceptor(拦截器):是Struts2的基石,类似于JavaWeb的Filter,拦截器是一些无状态的类,拦截器可以自动拦截Action,它们给开发者提供了在Action运行之前或Result运行之后来执行一些功能代码的机会。
7.Action:用来处理请求,封装数据
详细运行流程

1.当用户的发出请求,比如http:localhost:8080/Struts2Demo/HelloAction.action,请求会被Tomcat接收到,Tomcat服务器来选择处理这个请求的Web应用,那就是由helloworld这个web工程来处理这个请求。

2.web容器会去读取Struts2Demo这个工程的web.xml,在web.xml中进行匹配,但发现,由struts2这个过滤器来进行处理(也就是StrutsPrepareAndExecuteFilter),根据Filter的配置,找到FilterDispatch(Struts2的调度中心)

3.然后会获取FilterDispatcher实例,然后回调doFilter方法,进行真正的处理
PS:FilterDispatcher是任何一个Struts2应用都需要配置的,通常情况下,web.xml文件中还有其他过滤器时,FilterDispatcher是放在滤器链的最后;如果在FilterDispatcher前出现了如SiteMesh这种特殊的过滤器,还必须在SiteMesh前引用Struts2的ActionContextCleanUp过滤器

对应Struts2的架构图如下
 

4.这时FilterDispatcher会将请求转发给ActionMapper。ActionMapper负责识别当前的请求是否需要Struts2做出处理。ActionMapper就类似于公司的保安,来识别是不是当前客户是不是我公司的人

 

5.如果需要Struts2处理,ActionMapper会通知FilterDispatcher,需要处理这个请求,FilterDispatcher会停止过滤器链以后的部分,(这也就是为什么,FilterDispatcher应该出现在过滤器链的最后的原因)。然后建立一个ActionProxy实例,这个对象作为Action与xwork之间的中间层,会代理Action的运行过程。

6.ActionProxy对象在被创建出来的时候,并不知道要运行哪个Action,它手里只有从FilterDispatcher中拿到的请求的URL。
而真正知道要运行哪个Action的是ConfigurationManager。因为只有它才能读取我们的strtus.xml。(在服务器启动的时候,ConfigurationManager就会把struts.xml中的所有信息读到内存里,并缓存,当ActionProxy带着URL向他询问要运行哪个Action的时候,就可以直接匹配、查找并回答了)

7.ActionProxy知道自己该干什么事之后(运行哪个Action、相关的拦截器以及所有可能使用的result信息),然后马上建立ActionInvocation对象了,ActionInvocation对象描述了Action运行的整个过程。注意:Action完整的调用过程都是由ActionInvocation对象负责

8.在execute方法之前,好像URL请求中的参数已经赋值到了Action的属性上,这就是我们的"雷锋"—拦截器。
拦截器的运行被分成两部分,一部分在Action之前运行,一部分在Result之后运行,而且顺序是刚好反过来的。也就是在Action执行前的顺序,比如是拦截器1、拦截器2、拦截器3,那么运行Result之后,再次运行拦截器的时候,顺序就变成拦截器3、拦截器2、拦截器1了。

这就好比,你要去奶奶家,需要通过 水泊梁山->盘丝洞 -> 索马里,到了奶奶家,看奶奶回来的时候,就必须要通过 索马里 -> 盘丝洞 -> 水泊梁山。

所以ActionInvocation对象执行的时候需要通过很多复杂的过程,按照指定拦截器的顺序依次执行。


 9.到了奶奶家,然后执行Action的execute方法

10.然后根据execute方法返回的结果(Result),去struts.xml中匹配选择下一个页面

11.根据结果(Result)找到页面后,在页面上(有很多Struts2提供的模板),可以通过Struts2自带的标签库来访问需要的数据,并生成最终页面.注意:这时还没有给客户端应答,只是生成了页面.

12.最后,ActionInvocation对象倒序执行拦截器,从奶奶家回来

13.ActionInvocation对象执行完毕后,已经得到响应对象(HttpServletResponse)了,最后按与过滤器(Filter)配置定义相反的顺序依次经过过滤器,向客户端展示出响应的结果

经过上面详细解释,到这一步应该对Struts的大致结构和运行顺序有了一定的了解!

下面一部讲解struts源码分析!

https://blog.csdn.net/yonggeit/article/details/82686363-------Servlet的优缺点

https://blog.csdn.net/u011958281/article/details/74685659-----struts2原理

https://www.cnblogs.com/konrad/p/6426790.html-----介绍的比较深入,知识点

https://www.cnblogs.com/whgk/p/6542505.html----讲解的非常好

https://blog.csdn.net/wjw0130/article/details/46371847----对官方struts讲解非常清楚!

Struct2 基础介绍的更多相关文章

  1. Web3D编程入门总结——WebGL与Three.js基础介绍

    /*在这里对这段时间学习的3D编程知识做个总结,以备再次出发.计划分成“webgl与three.js基础介绍”.“面向对象的基础3D场景框架编写”.“模型导入与简单3D游戏编写”三个部分,其他零散知识 ...

  2. C++ 迭代器 基础介绍

    C++ 迭代器 基础介绍 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围.迭代器就如同一个指针.事实上,C++的指针也是一种迭代器.但是,迭代器不仅仅是指针,因此你不能认为他们一定 ...

  3. Node.js学习笔记(一)基础介绍

    什么是Node.js 官网介绍: Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js us ...

  4. Node.js 基础介绍

    什么是Node.js 官网介绍: Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js us ...

  5. 1、git基础介绍及远程/本地仓库、分支

    1. Git基础介绍 基于Git进行开发时,首先需要将远程仓库代码clone到本地,即为本地仓库.后续大部分时间都是基于本地仓库上的分支进行编码,最后将本地仓库的代码合入远程仓库. 1.1. 远程仓库 ...

  6. git基础介绍

    git基础介绍 这是git操作的基础篇,是以前的写的操作文档,就没有进行手打,直接把图片贴进来了,你们担待哈,有不正确的地方可以指正出来,我将在第一时间去修改,多谢哈! 一.文件状态:git系统的文件 ...

  7. OSPF基础介绍

    OSPF基础介绍 一.RIP的缺陷 1.以跳数评估的路由并非最优路径 2.最大跳数16导致网络尺度小 3.收敛速度慢 4.更新发送全部路由表浪费网络资源 二.OSPF基本原理 1.什么是OSPF a& ...

  8. iOS系统及客户端软件测试的基础介绍

    iOS系统及客户端软件测试的基础介绍 iOS现在的最新版本iOS5是10月12号推出,当前版本是4.3.5 先是硬件部分,采用iOS系统的是iPad,iPhone,iTouch这三种设备,其中iPho ...

  9. 高通camera结构(摄像头基础介绍)

    摄像头基础介绍 一.摄像头结构和工作原理. 拍摄景物通过镜头,将生成的光学图像投射到传感器上,然后光学图像被转换成电信号,电信号再经过模数转换变为数字信号,数字信号经过DSP加工处理,再被送到电脑中进 ...

随机推荐

  1. 关于__cmp__的使用

    __cmp__是python的类中所使用的特殊函数,一般用于对类对象列表的排序. 举个例子,假设需要对Student类的对象列表按照其成绩grade属性进行排序,那么可以这么设计: class Stu ...

  2. ubuntu10.04 搭建海思开发环境

    (1)Ubuntu 10.04.4 LTS (Lucid Lynx) 下载地址:http://old-releases.ubuntu.com/releases/lucid/ (2)passwd roo ...

  3. 阿里云 RDS for MySQL 物理备份文件恢复到自建数据库

    想把阿里云的Mysql 生成的RAS 文件.tar文件 恢复到本地自建mysql, 遇到的坑.希望帮助大家 阿里云提供的地址 https://help.aliyun.com/knowledge_det ...

  4. mybatis-plus报org.apache.ibatis.binding.BindingException分析【转载】

    这个问题整整纠结了我四个多小时,心好累啊...不废话... 背景:Spring整合Mybatis 报错:org.apache.ibatis.binding.BindingException: Inva ...

  5. 常用Docker命令

    1.镜像操作 获取镜像 docker pull NAME[:TAG] #如果不显示指定TAG,默认选择latest标签 查看本地所有镜像 docker images 查看镜像详细信息 docker i ...

  6. Java学习--枚举

    枚举类型enum,地位等同于class,interface 使用enum定义的枚举类型,也是一种变量类型,可用于声明变量 枚举的一些特征 1.它不能有public的构造函数,这样做可以保证客户代码没有 ...

  7. Spring.xml中配置注解context:annotation-config和context:component-scan简述

    XML中context:annotation-config和context:component-scan简述 <context:annotation-config/> 中文意思:<上 ...

  8. react项目如何修改默认3000端口号

    在运行react项目时,经常会遇到默认的3000端口被占用的情况,此时不想查找哪个程序占用了3000端口,想使用其他端口继续运行. 打开项目中的node_modules文件夹,找到react_scri ...

  9. splice() 方法通过删除现有元素和/或添加新元素来更改一个数组的内容。

    var myFish = ["angel", "clown", "mandarin", "surgeon"]; //从第 ...

  10. 第二次oo博客作业--多线程电梯

    这次的系列作业是写一个电梯调度,主要目的是让我们熟悉多线程. 第一次作业是一个傻瓜电梯的调度问题,要求也很简单,即每次接一个人就行了.我只用了两个线程,一个是输入线程,一个是电梯线程,输入线程负责从标 ...