Struts2学习
目录:
1、Servlet Filters(Servlet过滤器):
2、拦截器(Interceptor):
3、Interceptor的调度流程大致如下:
4、 一个请求在Struts2框架中的处理大概分为以下几个步骤 :
5、struts.xml文件:
6、struts.xml配置中的包:
7、web.xml文件:
8、浏览器访问地址:
9、pom.xml:
10、ModelDriven接口的作用:
11、采用在struts.xml文件中进行配置的方法:
12、采用注释的方法:
图0.1 Struts2工作流程
1、Servlet Filters(Servlet过滤器):
①ActionContextCleanUp:延长action中属性的生命周期,包括自定义属性,在访问jsp页面时,让ActionContextCleanUp来清除属性,不让Action自己清除。
附:
ActionContext:包括Session(会话)、Application(应用)、Request(请求)、Locale(语言环境)、ValueStack等信息
ValueStack:当接收到一个.aciton的请求时,会先建立Action类的对象实例,但不会调用Action方法,而是先将Action类的相应属性放置到ValueStack对象的顶层节点,所有的值都是默认的值,Struts2调用拦截器后,拦截器会根据用户请求的参数值去更新ValueStack顶层节点的相应属性的值,ValueStack在请求开始时被创建,在请求结束时消亡。
②SiteMesh:网页母版Layout分层。
③FilterDispatcher:控制器的核心,当FilterDispatcher拦截到用户请求时,大量拦截器会对用户请求进行处理,然后调用用户自定义的Action类中的方法来处理请求。
2、拦截器(Interceptor):
每个拦截器中的代码的执行顺序,在Action之前,拦截器的执行顺序与堆栈中定义的一致;而在Action和Result之后,拦截器的执行顺序与堆栈中定义的顺序相反。
整个拦截器的核心部分是invocation.invoke()这个函数的调用位置。
3、Interceptor的调度流程大致如下:
1)ActionInvocation初始化时,根据配置,加载Action相关的所有Interceptor。
2)通过ActionInvocation.invoke方法调用Action实现时,执行Interceptor。
Interceptor将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、WebWork的许多功能都是有Interceptor实现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在Action执行前后运行。
4、 一个请求在Struts2框架中的处理大概分为以下几个步骤 :
1)客户端初始化一个指向Servlet容器(eg.Tomcat)的请求;
2)请求经过一系列的过滤器(Filter);
3)FilterDispatcher(过滤器转发器)被调用,FilterDispatcher询问ActionMapper来决定这个请是否需要调用某个Action ;
4)ActionMapper进行Url跟Action的映射,如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy(创建一个代理对象);
5)ActionProxy通过ConfigurationManager询问框架的配置文件struts.xml,找到需要调用的Action类 ;
6)ActionProxy创建一个ActionInvocation的实例。
7)ActionInvocation(相当于切面)实例使用命名模式来调用,在调用Action的过程前后,相关拦截器(Intercepter)调用。
8)一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是一个需要被表示的JSP或者FreeMarker的模版引擎。在表示的过程中可以使用Struts2框架中继承的标签。在这个过程中需要涉及到ActionMapper。
附:在上述过程中所有的对象(Action,Results,Interceptors,等)都是通过ObjectFactory来创建的。
5、struts.xml文件:
Struts2的核心配置文件,主要用于配置开发人员编写的action。
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<include file="struts-default.xml"></include>
<!-- 指定被struts2处理的请求后缀类型。多个用逗号隔开 -->
<constant name="struts.action.extension" value="action"/>
<!-- 是否开启动态方法调用 -->
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<!-- 是否使用struts的开发模式。开发模式会有更多的调试信息。默认值为false(生产环境下使用),开发阶段最好打开 -->
<constant name="struts.devMode" value="true"/>
<constant name="struts.i18n.encoding" value="UTF-8" />
<constant name="struts.convention.result.path" value="/WEB-INF/pages"/>
<!-- 进行扫描的根包,该包会被扫描成action -->
<constant name="struts.convention.package.locators" value="action"/>
<!-- 设置浏览器是否缓存静态内容。默认值为true(生产环境下使用),开发阶段最好关闭 -->
<constant name="struts.serve.static.browserCache" value="false" />
<!-- 指定由spring负责action对象的创建 -->
<constant name="struts.objectFactory" value="spring"/>
<!-- 当struts.xml改动后,是否重新加载。默认值为false(生产环境下使用),开发阶段最好打开 -->
<constant name="struts.configuration.xml.reload" value="true"/>
<package name="user" namespace="/user" extends="struts-default">
<action name="viewUser" class="com.mashen.user.action.ViewUserAction">
<result name="success">/WEB-INF/pages/user/view.jsp</result>
<result name="error">/WEB-INF/pages/user/error.jsp</result>
<allowed-methods>view,execute</allowed-methods>
</action>
</package>
</struts>
注意:<constant name="struts.objectFactory" value="spring"/>决定了由Spring负责Action对象的创建,不由Struts创建。
6、struts.xml配置中的包:
1)name:配置包名称,必填,必须唯一,便于其它包配置继承多用于拦截器
2)namespace:配置包命名空间,可选,默认为空字符串,命名空间作为访问该包下Action的路径的一部分。
3)extends:用于继承包配置,内容填某包name属性名称(必填,一般情况下继承默认struts-default),使用struts2默认或自定包功能
7、web.xml文件:
Struts框架是通过Filter启动的,在StrutsPrepareAndExecuteFilter的init()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>struts</display-name>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.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>
8、浏览器访问地址:
http://域名:端口号/应用名/命名空间/action名.后缀名
域名:若为本机访问,则为localhost
端口号:8080
图8.1 端口号查看
应用名:服务器上的虚拟路径path
图8.2 应用名查看
命名空间:在struts.xml上配置的包中的namespace
图8.3 命名空间查看
action名:在struts.xml上配置的包中的action中的name
图8.4 action名查看
后缀名:在struts.xml上配置的包中的action中的name
图8.5 后缀名查看
9、pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mashen</groupId>
<artifactId>struts</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<finalName>struts</finalName>
<!-- 默认源代码和资源文件目录配置 -->
<sourceDirectory>src/main/java </sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-json-plugin</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.5.2</version>
</dependency>
<!-- struts2注解零配置依赖的包 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-convention-plugin</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
</project>
10、ModelDriven接口的作用:
直接把实体类当成页面数据的收集对象,让ViewUserAction实现该接口,同时实现接口中的getModel方法,绑定自定义对象,使其访问时不用加前缀,即不必再通过user.name的形式给name赋值,而可以直接通过name给name赋值。
11、采用在struts.xml文件中进行配置的方法:
<package name="user" namespace="/user" extends="struts-default">
<action name="viewUser" class="com.mashen.user.action.ViewUserAction">
<result name="success">/WEB-INF/pages/user/view.jsp</result>
<result name="error">/WEB-INF/pages/user/error.jsp</result>
<allowed-methods>view,execute</allowed-methods>
</action>
</package>
示例程序:ViewUserAction.java
package com.mashen.user.action;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.mashen.user.domain.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ModelDriven;
public class ViewUserAction implements ModelDriven<User>{
private int aid;
private User user = new User();
public int getAid() {
return aid;
}
public void setAid(int aid) {
this.aid = aid;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String execute(){
System.out.println("excute");
System.out.println("aid:" + aid);//此处应该会输出aid:0,即aid的默认值
System.out.println(user);
HttpServletRequest request = ServletActionContext.getRequest();
System.out.println(request);
this.aid = 100;//设置aid的值为100,使其在页面上输出
ActionContext.getContext().put("age", "20");
return "success";
}
public String view(){
System.out.println("view");
System.out.println(user);
HttpServletRequest request = ServletActionContext.getRequest();
//request.getSession();
System.out.println(request);
this.aid = 333;
ActionContext.getContext().put("age", "21");
return "success";
}
@Override
public User getModel() {
// TODO Auto-generated method stub
return user;
}
}
User实体类User.java
package com.mashen.user.domain;
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
1)未指定方法时,会默认执行程序中excute方法,在浏览器中输入地址:
http://localhost:8080/struts/user/viewUser.action?id=5847&name=remoa
本示例程序运行结果为:
控制台运行结果:
图11.1 控制台运行结果1
页面展示结果:
图11.2 页面展示结果1
2)指定别的方法时,首先修改配置文件struts.xml中<constant name="struts.enable.DynamicMethodInvocation" value="true" /> 的value设置为true,开启动态方法,用!进行访问,在浏览器中输入地址:
http://localhost:8080/struts/user/viewUser!view.action?id=5846&name=Cui
本示例程序运行结果为:
控制台运行结果:
图11.3 控制台运行结果2
页面展示结果:
图11.4 页面展示结果2
12、采用注释的方法:
@Namespace
@ParentPackage:相当于继承了某个包
@Action
@Result
@Results
示例程序:采用注释及用json格式展示
AddUserAction2.java
package com.mashen.user.action;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import com.mashen.user.domain.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
@ParentPackage("json-default")//必须继承这个包才能用json
@Namespace("/user")
@Results({@Result(name="success", location="add.jsp"),
@Result(name="error", location="add.jsp"),
@Result(name="jsonUser",type="json",params={"root", "user", "excludeNullProperties", "false"})})
public class AddUserAction2 extends ActionSupport implements ModelDriven<User>{//实现该类的作用是绑定User
private static final long serialVersionUID = 1L;
private int aid;
private User user = new User();
public int getAid() {
return aid;
}
public void setAid(int aid) {
this.aid = aid;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Action("addUser1")
public String addUser1(){
System.out.println("addUser1");
System.out.println(user);
this.aid = 888;
return "jsonUser";
}
@Action("addUser2")
public String addUser2(){
System.out.println("addUser2");
System.out.println(user);
this.aid = 999;
return "jsonUser";
}
@Action("jsonUser")
public String jsonUser(){
System.out.println(user);
return "jsonUser";
}
@Override
public User getModel() {
// TODO Auto-generated method stub
return user;
}
}
实体类User.java
package com.mashen.user.domain;
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
运行结果:
访问addUser1方法:
http://localhost:8080/struts/user/addUser1.action?id=4005846&name=Cui
控制台运行结果:
图12.1 控制台运行结果1
页面展示结果:
图12.2 页面展示结果1
访问addUser2方法:
http://localhost:8080/struts/user/addUser2.action?id=4005847&name=Remoa
控制台运行结果:
图12.3 控制台运行结果2
页面展示结果:
图12.4 页面展示结果2
注意事项:
ActionSupport类:为Action提供了一些默认实现,主要包括预定义常量,从资源文件中读取文本资源、接收验证错误信息和验证的默认实现。支持多个方法必须继承ActionSupport类,这样就可以在一个类里实现多个逻辑了。
Json支持:
excludeNullProperties:指定是否序列化空的属性,填true或false;
root:这里指定将被Struts2序列化的属性,该属性在action中必须有对应的getter方法,默认将会序列所有有返回值的getter方法的值,而无论该方法是否有对应属性。简单地说,相当于指定一个自定义对象。