一、概述
1.运用场景:
应用于三层架构中web层的框架(显示层的运用),是经典MVC模型的web应用的变体。
2.与struts1的对比:
struts2是在struts1基于webwork发展的全新的框架,完全脱胎换骨的全新框架
struts1代码严重依赖于servletAPI,属于侵入性框架。
3.解决的问题(解决的痛点):
web阶段时一个模块(比如用户管理),如果有多个功能(登陆、注册等等),都要分别写一个servlet,容易发生servlet暴增的问题
struts2的解决思路:
对于请求,struts2会有一个过滤器拦截请求,把不同的操作都在一个类中写不同的方法而在过滤器里会根据不同的操作执行不同的方法
在struts2中,web里的servlet有一个全新的叫法,叫 action (调用某个java类的方法进行预处理也是进行一些业务逻辑处理等)
使用的版本:
2.3.24-all 一个比较稳定的版本
二、入门案例(必须是web项目,应用于web层的框架)
第一步:导包(包中的apps为一些示例的代码,把war包直接放入tomcat即可运行)
lib目录中100多个jar包(多导一些不该导的会报错)
到apps中找到实例程序中直接可以找到
直接找到第一个war包(blank的),使用好压打开,找到lib里的jar包直接复制即可
将复制jar包导入项目lib目录即可(13个jar包)
导包完成后应该有如下包:
第二步:创建action:
* 访问sevlet时执行service()方法,再通过反射选择doGet/doPost方法
写servlet时继承HttpServlet,然后再在web.xml中配置
* 访问action时同样会默认执行一个类似service()的方法:execute()方法
写action时也是类似,也要配置访问路径
action的三种编写方式:(表单提交有几种?有多种,常用的为两种而已)
一、创建普通类,这个类不继承任何类,也不实现任何接口
二、创建类,实现接口 Action
【常用】三、创建类,继承类 ActionSupport
第三步:创建execute()方法
此方法是默认的,当然是可以创建其它方法的,后面会详细讲到
二、三步完成后应该有如下的一个Action了:
package cn.action;
import com.opensymphony.xwork2.ActionSupport;
//编写acion最常用的方式,继承这个实现了Action接口的类
public class PersonAction extends ActionSupport {
@Override
public String execute() throws Exception {
//也可以直接使用常量,因为这个类实现了Action这个接口,当然,ActionSupport可以省略
//return ActionSupport.SUCCESS;
return SUCCESS;
}
}
第四步:配置web.xml,以及核心配置文件struts2.xml
配置文件与Hibernate类似 名称位置固定:struts.xml
编写xml时第一步也是引入约束文件:可以在示例程序中找struts.xml中找到
具体的配置见配置文件
1)配置过滤器时可以去找示例程序里的web.xml,这里贴出配置完过滤器后的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>struts2_01</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>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>
2)先给出核心配置文件的示例,后面会做进一步的讲述
<?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" namespace="/" extends="struts-default">
<!-- name:访问路径,类似于Servlet的url-pattern;class-action类的全路径。-->
<action name="hello" class="cn.action.HelloAction">
<!-- 配置方法的返回值到页面,
类似于//转发到result.jsp
request.getRequestDispatcher("/jsptext/result.jsp").forward(request, response); -->
<result name="ok">/hello.jsp</result>
</action>
</package>
</struts>
接下来环境搭建完成后我们可以测试一下:
访问路径:http://localhost:8080/struts201/hello.action
复习一下访问路径为 协议://域名:端口号/项目名/资源名
(.action是可以省略的,只有杂牌的少数浏览器不能访问)
直接这样访问时出现404,原因是没配过滤器,一定要记得!,因为功能都是通过过滤器实现
小结流程就是:导包->建action->编写相关的方法->完成配置文件
三、基本执行过程
浏览器地址栏输入地址,发送请求;
到过滤器里面来(因为拦截是拦截的/*,拦截所有);
在过滤器(服务器启动时创建)里首先获取请求路径,得到资源名(切分字符串得到hello这个字符串);
然后到src下面找到struts.xml文件使用dom4j进行解析,拿hello这个值去找<action>标签里去匹配name属性值是否一样;
第二步匹配到<action>里的name属性值后,找到name所在<action>里class值,使用反射实现功能。
(使用反射是得到class字节码文件,也就是得到了类的完整信息:Class.forName(),
再得到execute()方法:clazz.getMethod(),
再执行方法:m.invoke(),
再得到返回值,匹配srtuts.xml文件中找到<action>里的<result>标签的name属性值,最后就可以跳转到hello.jsp)
查看过滤器源码:web.xml中配置这里按住ctrl找源码(或者ctrl + shift + T)
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
过滤器类名:StrutsPrepareAndExecuteFilter
public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter
实现了Filter 是一个过滤器,里面的方法:
#init() 加载配置文件(包括struts自带的配置文件与我们写的struts.xml等):我们关心两个配置文件:
struts.xml:配置action
web.xml:配置过滤器
四、核心配置文件struts.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.i18n.encoding" value="UTF-8"></constant>
<!-- <package name="default" namespace="/" extends="struts-default">
name:访问路径,类似于Servlet的url-pattern;class-action类的全路径。
<action name="hello" class="cn.action.HelloAction">
配置方法的返回值到页面,
类似于//转发到result.jsp
request.getRequestDispatcher("/jsptext/result.jsp").forward(request, response);
<result name="ok">/hello.jsp</result>
</action>
</package> -->
<include file="cn/action/hello.xml"></include>
<!-- 配置用法演示访问不同方法的BookAction -->
<!-- <package name="actionDemo" namespace="/" extends="struts-default">
method里为要访问的的方法的名称(不要加())
<action name="saleAction" class="cn.action.BookAction" method="sale"></action>
<action name="buyAction" class="cn.action.BookAction" method="buy"></action>
</package> -->
<!-- 通配符的方式实现 -->
<package name="actionDemo2" namespace="/" extends="struts-default">
<!-- book_* 可以匹配例如book_buy book_sale等
一般method的写法为 {1} 表示匹配第一个*号
也就是输入book_buy method会自动匹配buy那个method
-->
<action name="book_*" class="cn.action.BookAction" method="{1}"></action>
</package>
<include file="cn/action/hello.xml"></include>
</struts>
1)名称位置固定:struts.xml 位于src下
2)配置文件中有三个标签(根标签与约束文件引入等不再赘述):
package:
类似于代码中的包,用于区分不同的action,要配置action,必须要先配置package
三个主要属性:
name属性:和功能本身没有关系,在一个配置文件中有多个package标签,但name属性不能相同,比如这里name可以写hellostruts
namespace属性:命名空间:和action里的name属性构成访问地址(namespace默认为 / ),
比如这里就是/hello(对应地址里的/hello.action)(当然.action可以省略)
extends属性:表示继承关系,属性值为固定值,配置后表示此package里的类才具有action的功能,
也就是让类具有action的功能(就像一个类继承了HttpServlet才叫servlet)
一般namespace和extends都写成默认即可
action:
配置action的访问路径
属性:
name属性:和namespace构成访问路径,同一个包下的不同action间内容不能相同
class属性:一般的class属性都是写类的全限定名,这里也是,指的是action的全限定名(底层是反射)
method属性:默认执行的是execute()方法,这里可以执行action里的其他定义方法
result子标签
根据action里的返回值,配置到不同的路径去(不一定要去别的页面,去别的action也可以)
属性:
name属性:和方法的返回值一样,内容/hello.jsp表示要去的路径(/为一般的写法,要记得带/)
type属性:配置如何到路径去(转发或重定向),默认是转发。(注意转发和重定向的区别)
更多的结果页介绍见day02
五、其它配置概述
1)常量的配置:
例如设置编码:常用的方式是:
在struts标签下配置:<constant name="struts.i18n.encoding" value="UTF-8"></constant>
默认有两个属性:name 和 value (值在default.propertites找,此文件的打开路径见图)
2)介绍常用常量(常量封装了一部分功能):
struts.i18n.encoding=UTF-8
表单提交数据到action,如果有中文,可能出现乱码
之前过滤器需要判断请求方式,再处理
这个常量,如果表单提交方式为POST提交,常量可以解决
3)分模块的开发:
应用场景:协同开发时,每个人单独写一个配置文件,再把配置文件引入核心配置文件(类似CSS的外部式引入)
新建一个hello.xml,在核心配置文件中引入,注意文件的写法
4)对action的其他方法【重点】:
有三种方式(主要是前面两种方式)
一、通过action标签的method属性 例如 method="add"; 填入方法名称即可
例如案例的BookAction
package cn.action;
import com.opensymphony.xwork2.ActionSupport;
public class BookAction extends ActionSupport {
public String buy(){
System.out.println("buy buy buy");
System.out.println("no no no");
return NONE;
}
public String sale(){
System.out.println("sale sale sale");
return NONE;
}
}
<!-- method里为要访问的的方法的名称(不要加()) -->
<action name="saleAction" class="cn.action.BookAction" method="sale"></action>
<action name="buyAction" class="cn.action.BookAction" method="buy"></action>
虽然可以通过不同的路径执行不同的方法,但如果有成千上万的方法,那得配置成千上万条<action>
所以引出第二种方式
【最常用】二、使用通配符的方式
在action的name属性写 * ;* 表示匹配任意的内容
<package name="actionDemo2" namespace="/" extends="struts-default">
<!-- book_* 可以匹配例如book_buy book_sale等
一般method的写法为 {1} 表示匹配第一个*号
也就是输入book_buy method会自动匹配buy那个method
-->
<action name="book_*" class="cn.action.BookAction" method="{1}"></action>
</package>
通配符大概执行流程:
http://localhost:8080/struts201/book_buy(已省略action)
配置文件中的 book_* 就变成了 book_buy ,也就是*变成了 buy
method="{1}" struts认识这个{1} 的格式,method就取到了buy 这个值
三、动态访问的方式(只做了解)
在访问路径里使用 !
先开启常量,再访问时例如 /day01/AAction!add.action
大致的流程:
搭建环境
创建action (使用常用方式) 注意返回值
配置struts.xml以及web.xml的过滤器
<package> 三个属性 name extends namespace
<action> 注意三个属性 name class method
<result> 注意属性 name 以及值为要跳转的路径