Struts2入门
Struts2基本概述
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架。其全新的Struts 2的体系结构与Struts 1的体系结构差别巨大。Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts 2可以理解为WebWork的更新产品。虽然从Struts 1到Struts 2有着太大的变化,但是相对于WebWork,Struts 2的变化很小。
WEB 层的框架都会基于前端控制器的模式
什么是前端控制器模式呢?传统方式的开发,有一次请求就会对应一个Servlet。这样会导致出现很多 Servlet。而Struts2将所有的请求都先经过一个前端控制器,在前端控制器中实现框架的部分功能,剩下具体操作要提交到具体的Action中。那么所有的请求都会经过前端控制器,那用什么来实现前端控制器呢?过滤器就是最好的一个实现方式,因为需要所有的请求都可以被过滤器拦截 ,然后在过滤器中实现部分的功能 。所以Struts2的前端控制器也是有过滤器来实现的。
Struts入门案例
首先到Struts2的官网:https://struts.apache.org/下载。
Struts2开发包的目录结构
创建web项目,拷入jar包
可以解压apps目录下的struts2-blank.war文件,然后将WEB-INF目录下的lib拷贝到web项目的lib目录下就行了。其jar包如下:
Struts2项目依赖的基础JAR包说明
文件名
|
说 明
|
asm-3.3.jar
|
操作Java字节码的类库
|
asm-commons-3.3.jar
|
提供了基于事件的表现形式
|
asm-tree-3.3.jar
|
提供了基于对象的表现形式
|
struts2-core-2.3.24.jar
|
Struts2框架的核心类库
|
xwork-core-2.3.24.jar
|
WebWork核心库,Struts2的构建基础
|
ognl-3.0.6.jar
|
对象图导航语言(Object Graph Navigation Language),struts2框架通过其读写对象的属性
|
freemarker-2.3.22.jar
|
Struts2标签模板使用的类库
|
javassist-3.11.0.GA.jar
|
javaScript字节码解释器
|
commons-fileupload-1.3.1.jar
|
Struts2文件上传组件依赖包
|
commons-io-2.2.jar
|
Struts2的输入输出,上传文件依赖的jar包
|
commons-lang-2.4.jar
|
包含一些数据类型工具 ,是对java.lang包的增强
|
log4j-api-2.2.jar
|
Struts2的日志管理组件依赖包的api
|
log4j-core-2.2.jar
|
Struts2的日志管理组件依赖包
|
创建页面index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Struts2的案例</title>
</head>
<body>
<%--
通过超链接访问我们写的一个动作类
动作类:就是struts2中用于处理请求的类。
动作方法:动作类中接收请求的方法。
struts2的核心控制器(StrutsPrepareAndExecuteFilter)默认会拦下以.action为后缀的url(或者没有任何后缀的URL),送入struts2核心内部,
--%>
<a href="${pageContext.request.contextPath}/hello.action">Hello Struts2.action</a>
<br/>
<a href="${pageContext.request.contextPath}/hello">Hello Struts2</a>
</body>
</html>
编写一个Action
package com.pc.struts2.web.action;
/**
* Struts测试类
*
* 它里面的方法都是动作方法
* 动作方法编写规范:
* 1、访问修饰符必须是public
* 2、返回值类型必须是String
* 3、方法不能有参数
* @author Switch
*/
public class HelloAction {
/**
* 动作方法的作用就是负责处理请求
* @return
*/
public String helloworld() {
System.out.println("Hello World");
System.out.println("Hello Struts2");
// 对应于struts.xml文件配置的result元素
return "success";
}
}
配置类根目录下的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>
<package name="pack1" extends="struts-default">
<action name="hello" class="com.pc.struts2.web.action.HelloAction" method="helloworld">
<result name="success" type="dispatcher">/success.jsp</result>
</action>
</package>
</struts>
在web.xml中配置核心过滤器
<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>
PS:访问主机名/项目名/就能测试Struts2是否成功搭建了。
Struts2的执行流程
步骤:
1、客户端请求,生成相应的HttpServletRequest对象
2、Struts2核心过滤器,StrutsPrepareAndExecuteFilter进行拦截,(如果满足要求,进行拦截,不满足要求,放行)
3、ActionMapper动作映射类,将请求的路径与struts.xml中的配置进行对比,找到匹配的动作类
4、经过核心过滤器,然后创建匹配的动作类的代理类对象,进行一系列的配置,(读取配置文件struts.xml,确定执行那个方法)
5、通过一些拦截器,对数据进行预处理,比如说请求参数的封装就是在这进行
6、进入动作方法,进行业务处理
7、动作方法返回结果视图的名字,到ActionMapper找到对应的结果视图,进行结果视图预处理
8、反向经过5中的拦截器
9、生成HttpServletResponse对象,返回给客户端。
Struts2的执行过程
Struts2配置文件的加载顺序
首先进入StrutsPrepareAndExecuteFilter该类的init方法
从源代码可以看出加载顺序是这样的:
配置文件
|
作用
| 能否更改 |
default.properties
|
struts2默认配置文件,主要配置一些key,value类的属性
|
不能改
|
struts-default.xml
|
struts2默认配置文件,主要配置一些模板类的东西
|
不能改
|
struts-plugin.xml
|
struts2默认配置文件,配置插件
|
不能改
|
struts.xml
|
配置Action以及常量
|
能改,推荐配置(修改)这个
|
struts.properties
|
配置常量
|
能改
|
web.xml
|
配置核心过滤器及常量
|
能改
|
PS:在web.xml中最后加载的内容都是和struts2配置相关的。
当配置重复时,后加载的覆盖先加载的。
default.properties
struts.i18n.encoding=UTF-8
|
struts2中的默认字符集,它解决了post请求的中文乱码。get没解决。
|
struts.multipart.maxSize=2097152
|
上传文件的最大限制是2MB
|
struts.action.extension=action,,
|
默认拦截的URL后缀为.action和没有后缀
|
struts.devMode = false
|
开启开发者模式。好处是修改struts.xml不用重启服务器
|
struts-default.xml
<bean class="com.opensymphony.xwork2.ObjectFactory" name="struts"/>
|
指定实例化Action类的工厂
|
struts.xml文件的配置
Struts2 框架的核心配置文件是struts.xrnl 文件,该文件主要用来配置Action和请求的对应关系。
package的配置
<!-- package标签:
作用:分包来管理动作配置。把配置文件按照面向对象的思想来管理
属性:
name属性:指定包的名称。必须写,且必须唯一。
extends属性:指定当前包的父包。子包自动具备父包的配置。我们一般都继承struts-default包。
struts-default包在struts-default.xml中定义着。如果不继承该包,就不能使用struts2的核心功能。
abstract属性:把当前包声明为抽象包。抽象包就是用来被继承。里面可以定义一些公共的配置。
只有没有action标签的包才能声明为抽象包。
namespace属性:它是把访问URL按照模块化来管理。
以后我们在浏览器地址栏中访问的URL就变成了
名称空间+动作名称(指的是action标签中name属性的取值)
例如:/user/add_User.action
名称空间的写法:
必须以/开头。后面不能是中文。
可以允许有多级。例如:/n1/n2/n3
名称空间有默认值:
默认值是:""
-->
action的配置
<!-- action标签:
作用:定义动作名称和动作类以及动作方法的对应关系。
属性:
name属性:指定的是动作名称。必须唯一。
class属性:指定的是动作类
method属性:指定的是动作方法名称。
定义动作类的三种方式:
第一种:无侵入式的 例如HelloAction 不用
第二种:实现Action接口 例如Hello2Action 不用
第三种:继承ActionSupport 例如Hello3Action 实际开发中采用的方式
访问Action的方式
使用通配符来访问
-->
result的配置
<!-- result标签:
作用:配置结果视图。当动作方法的返回值和该标签name属性一致时,采用type属性指定的方式,前往指定的地址。
属性:
name属性:逻辑结果视图。和动作方法的返回值保持一致。success是name属性的默认值
type属性:采用何种方式前往指定的地址。
常用取值:
dispatcher:请求转发(默认值)
redirect:重定向。它不仅可以重定向到一个页面,也可以重定向到另外一个动作。
redirectAction:重定向到另外一个动作
-->
Struts2中result预定义的type
属性
|
说明
|
chain
|
用来处理Actíon链,被跳转的Action中仍能获取上个页面的值,如request信息。
|
dispatcher
|
用来转向页面,通常处理JSP,是默认的结果类型。
|
freemarker
|
用来整合FreeMarker模板结果类型。
|
httpheader
|
用来处理特殊的HTTP行为结果类型。
|
redirect
|
重定向到一个URL,被跳转的页面中丢失传递的信息。
|
redirectAction
|
重定向到一个Action,跳转的页面中丢失传递的信息。
|
stream
|
向浏览器发送InputStream对象,通常用来处理文件下载,还可用于Ajax数据。
|
velocity
|
用来整合Velocity模板结果类型。
|
xslt
|
用来整合XML/XSLT结果类型。
|
plainText
|
显本原始文件内容,例如文件源代码。
|
postback
|
使得当前请求参数以表单形式提交
|
Struts2常量的配置
Struts2的这些常量大多在默认的配置文件中己经配置好,但根据用户需求的不同,开发的要求也不同,可能需要修改这些常量值 ,修改的方法就是在配置文件对常量进行重新配置。
Struts2常量配置共有3种方式,分别如下:
- 在 struts.xm1文件中使用<constant>元素配置常量。
- 在 struts.properhes文件中配置常量。
- 在web.xml文件中通过<init-param>元素配置常量。
<?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:配置文件的key。属性value:配置文件的值 -->
<constant name="struts.devMode" value="true"/>
<!-- 设置默认访问url的后缀为.struts2 -->
<constant name="struts.action.extension" value="struts2"/>
<package name="pack1" extends="struts-default">
<action name="hello" class="com.pc.struts2.web.action.HelloAction" method="helloworld">
<result name="success" type="dispatcher">/success.jsp</result>
</action>
</package>
</struts>
struts.action.extension=do
<?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_2_5.xsd" id="WebApp_ID" version="2.5">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>html</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
分模块开发的配置
<struts>
<!--包含了4个配置文件-->
<!--不指定路径默认在src下找--〉
<include file="struts-1.xml"/>
<include file="struts-2.xml"/>
<include file="struts-3.xml"/>
<!--配置文件在具体包中时的方式-->
<include file="com/pc/action/struts4.xml"/>
<Istruts>
Action的三种编写方式
简单的POJO类
package com.pc.struts2.web.action;
/**
* Struts测试类
*
* 它里面的方法都是动作方法
* 动作方法编写规范:
* 1、访问修饰符必须是public
* 2、返回值类型必须是String
* 3、方法不能有参数
* @author Switch
*/
public class HelloAction {
/**
* 动作方法的作用就是负责处理请求
* @return
*/
public String helloworld() {
System.out.println("Hello World");
System.out.println("Hello Struts2");
// 对应于struts.xml文件配置的result元素
return "success";
}
}
实现Action接口
package com.pc.struts2.web.action;
import com.opensymphony.xwork2.Action;
/**
* 创建方式2,实现Action接口
* @author Switch
*/
public class Hello2Action implements Action{
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
Action接口中提供了 5个己经定义的常量如下:
- SUCCESS 代表成功
- NONE 代表页面不跳转
- ERROR 代表跳转到错误页面
- INPUT 数据校验的时候跳转的路径
- LOGIN 用来跳转到登录页面
继承ActionSupport类
package com.pc.struts2.web.action;
import com.opensymphony.xwork2.ActionSupport;
/**
* 实现方法三:继承ActionSupport类
* @author Switch
*/
public class Hello3Action extends ActionSupport{
public String sayHello(){
return SUCCESS;
}
}
Action的访问
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:配置文件的key。属性value:配置文件的值 -->
<constant name="struts.devMode" value="true"/>
<!-- 设置默认访问url的后缀为.action -->
<constant name="struts.action.extension" value="action"/>
<!-- package标签:
作用:分包来管理动作配置。把配置文件按照面向对象的思想来管理
属性:
name属性:指定包的名称。必须写,且必须唯一。
extends属性:指定当前包的父包。子包自动具备父包的配置。我们一般都继承struts-default包。
struts-default包在struts-default.xml中定义着。如果不继承该包,就不能使用struts2的核心功能。
abstract属性:把当前包声明为抽象包。抽象包就是用来被继承。里面可以定义一些公共的配置。
只有没有action标签的包才能声明为抽象包。
namespace属性:它是把访问URL按照模块化来管理。
以后我们在浏览器地址栏中访问的URL就变成了
名称空间+动作名称(指的是action标签中name属性的取值)
例如:/user/add_User.action
名称空间的写法:
必须以/开头。后面不能是中文。
可以允许有多级。例如:/n1/n2/n3
名称空间有默认值:
默认值是:""
-->
<package name="myDefault" extends="struts-default" abstract="true">
<!-- 定义一些公共的配置:针对当前web工程的 -->
</package>
<package name="pack1" extends="myDefault" namespace="">
<!-- action标签:
作用:定义动作名称和动作类以及动作方法的对应关系。
默认class是ActionSupport,默认method是execute
属性:
name属性:指定的是动作名称。必须唯一。
class属性:指定的是动作类
method属性:指定的是动作方法名称。
定义动作类的三种方式:
第一种:无侵入式的 例如HelloAction 不用
第二种:实现Action接口 例如Hello2Action 不用
第三种:继承ActionSupport 例如Hello3Action 实际开发中采用的方式
访问Action的方式
使用通配符来访问
-->
<action name="hello" class="com.pc.struts2.web.action.HelloAction" method="helloworld">
<result name="success" type="dispatcher">/success.jsp</result>
</action>
</package>
<!-- 访问动作的最原始方式 -->
<!-- <package name="crud" extends="myDefault" namespace="/crud">
<action name="add_User" class="com.pc.struts2.web.action.UserAction" method="addUser">
<result name="success">/success.jsp</result>
</action>
<action name="update_User" class="com.pc.struts2.web.action.UserAction" method="updateUser">
<result name="success">/success.jsp</result>
</action>
<action name="delete_User" class="com.pc.struts2.web.action.UserAction" method="deleteUser">
<result name="success">/success.jsp</result>
</action>
<action name="find_User" class="com.pc.struts2.web.action.UserAction" method="findUser">
<result name="success">/success.jsp</result>
</action>
</package> -->
<!-- 使用通配符来访问动作 通配符是* -->
<package name="crud" extends="myDefault" namespace="/crud">
<!-- 动作名称格式为*_*,可以匹配如add_User,add_Product -->
<!-- 可以通过{第几个通配符}来代表相应字符串 -->
<action name="*_*" class="com.pc.struts2.web.action.{2}Action" method="{1}{2}">
<result name="success" type="dispatcher">/success.jsp</result>
</action>
</package>
</struts>
user.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户操作</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/crud/add_User.action">添加用户</a>
<a href="${pageContext.request.contextPath}/crud/update_User.action">修改用户</a>
<a href="${pageContext.request.contextPath}/crud/delete_User.action">删除用户</a>
<a href="${pageContext.request.contextPath}/crud/find_User.action">查询用户</a>
</body>
</html>
product.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>商品操作</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/crud/add_Product.action">添加商品</a>
<a href="${pageContext.request.contextPath}/crud/update_Product.action">修改商品</a>
<a href="${pageContext.request.contextPath}/crud/delete_Product.action">删除商品</a>
<a href="${pageContext.request.contextPath}/crud/find_Product.action">查询商品</a>
</body>
</html>
package com.pc.struts2.web.action;
import com.opensymphony.xwork2.ActionSupport;
/**
* 产品Action
*
* @author Switch
* @data 2016年11月16日
* @version V1.0
*/
public class ProductAction extends ActionSupport {
public String addProduct() {
System.out.println("添加产品");
return "success";
}
public String updateProduct() {
System.out.println("更新产品");
return "success";
}
public String deleteProduct() {
System.out.println("删除产品");
return "success";
}
public String findProduct() {
System.out.println("查找产品");
return "success";
}
}
package com.pc.struts2.web.action;
import com.opensymphony.xwork2.ActionSupport;
/**
* 用户Action
*
* @author Switch
* @data 2016年11月16日
* @version V1.0
*/
public class UserAction extends ActionSupport {
public String addUser() {
System.out.println("添加用户");
return "success";
}
public String updateUser() {
System.out.println("更新用户");
return "success";
}
public String deleteUser() {
System.out.println("删除用户");
return "success";
}
public String findUser() {
System.out.println("查找用户");
return "success";
}
}
package com.pc.struts2.web.action;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
/**
* 访问ServletAPI的方式
*
* 使用Struts2框架提供了一个工具类:
* ServletActionContext
* 它里面提供了对应的静态方法,可以直接获取ServletAPI
*
* 有一个需要注意的问题:
* org.apache.struts2.dispatcher.StrutsRequestWrapper@4637b3
* org.apache.catalina.connector.ResponseFacade@1f2f2f7
* org.apache.catalina.session.StandardSessionFacade@12d77c1
* org.apache.catalina.core.ApplicationContextFacade@1133ff
*
* requet对象已经不是原来tomcat提供的了,而是被struts2框架包装过了。
* 包装使用的是装饰者模式。
* 装饰者模式的作用是对方法进行增强。
*
* @author Switch
*/
public class ActionAPITest extends ActionSupport {
/**
* 在Struts2框架中使用ServletAPI
* @return
*/
public String useServletAPI() {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
HttpSession session = request.getSession();
ServletContext application = ServletActionContext.getServletContext();
System.out.println(request);
System.out.println(response);
System.out.println(session);
System.out.println(application);
return "success";
}
}