Struts2框架核心概念与实战工具详解

2025-10-11 16:46:09

Struts2框架核心概念与实战工具详解

本文还有配套的精品资源,点击获取

简介:Struts2是一个流行Java Web框架,基于MVC设计模式。本文将探讨Struts2的关键特性和使用相关工具的实践,包括Action类、OGNL表达式语言、拦截器、结果类型以及配置灵活性。同时,还将介绍集成开发环境(IDE)的支持、构建工具如Maven或Gradle,以及调试和测试工具等。安全问题也被提及,强调及时更新框架的重要性。整体上,本文旨在帮助开发者通过深入了解Struts2,提高Web应用开发的效率和安全性。

1. Struts2框架概述

Struts2的历史与发展

Struts2是Apache Software Foundation管理的开源Web应用框架,起源于经典的Struts框架,并在2007年引入了WebWork框架的优秀特性,形成了全新的Struts2框架。最初由Craig McClanahan创建,旨在简化Web层开发的复杂性,并提供了一套丰富的工具和组件以支持模型-视图-控制器(MVC)设计模式。Struts2自推出以来,因其易于学习和使用,迅速成为Java社区中广受欢迎的框架之一。

Struts2的核心组件和工作原理

Struts2框架的核心包括模型(Model)、视图(View)和控制器(Controller)。在Struts2中,控制器主要由Action类实现,负责业务逻辑的处理。模型代表了应用的数据结构,通常是POJO(Plain Old Java Object)类。视图则是由JSP或FreeMarker等模板技术生成的页面。

工作时,用户的请求先被过滤器(FilterDispatcher或StrutsPrepareAndExecuteFilter)接收,然后过滤器将请求转发给Struts2框架进行处理。框架通过配置文件(struts.xml)查找相应的Action映射,并利用IoC(控制反转)容器管理对象的生命周期,最后,根据Action的执行结果选择视图进行数据展示。

Struts2与其它框架的比较分析

Struts2与早期的Struts以及其竞争对手如Spring MVC相比,具有自己独特的优势和特点。Struts2的拦截器机制提供了灵活强大的请求处理能力,其OGNL(Object-Graph Navigation Language)表达式语言简化了数据的访问和处理。与Spring MVC相比,Struts2的配置相对简单,对开发者友好,但在性能方面,由于内部使用了更多的反射机制,可能略逊一筹。选择Struts2还是Spring MVC往往取决于项目需求、团队熟悉程度以及对性能和易用性的权衡。

2. Action类与控制器

2.1 Action类的设计与实现

2.1.1 Action接口的理解和应用

Struts2框架中的Action类是MVC模式中的C(控制器)部分的核心,它用于处理用户请求,并返回结果视图。Action接口提供了一组方法,这些方法在用户执行操作时由Struts2框架调用。理解并应用Action接口对于构建基于Struts2的Web应用程序至关重要。

Action接口定义了以下四个方法:

execute(): 这是最常用的方法,用于执行业务逻辑。当Action类是作为请求处理的一部分被调用时,这个方法将被Struts2框架执行。 input(): 该方法用于处理表单验证失败时的情况。如果在validate()方法中验证失败,它将返回一个字符串,这个字符串作为返回值将用户重定向回输入表单。 validate(): 此方法用于执行表单验证逻辑。如果验证失败,返回null或非空字符串,Struts2框架将调用input()方法。 reset(): 当需要重置Action类的状态,以便重新使用时,可以调用此方法。例如,为重复表单输入提供重置功能。

public class MyAction implements Action {

@Override

public String execute() throws Exception {

// 执行业务逻辑

return SUCCESS;

}

@Override

public String input() throws Exception {

// 处理输入验证失败的逻辑

return INPUT;

}

@Override

public void validate() {

// 执行验证逻辑

// 如果有验证错误,可通过ActionContext的put方法设置错误消息

}

}

在上述代码中, execute 方法是处理用户请求的核心, input 方法用于处理输入验证失败的场景,而 validate 方法则执行具体的验证逻辑,如果有验证错误,需要通过 ActionContext 的 put 方法来设置错误消息。 reset 方法可以为空,除非有特殊的重置需求。

2.1.2 ActionContext类的作用和使用方法

ActionContext是Struts2中的一个类,用于存储与当前请求相关的各种对象,例如Action实例、值栈(Value Stack)和参数映射(Parameter Map)。它提供了一个线程安全的方式来获取和设置这些对象的值,这对于在Action类和拦截器(Interceptor)之间共享数据非常有用。

ActionContext的实例通常通过 ActionContext.getContext() 方法获取,这个方法会返回当前线程的ActionContext对象,因此它是线程安全的。

public class MyAction extends ActionSupport {

@Override

public String execute() throws Exception {

ActionContext context = ActionContext.getContext();

// 获取值栈对象

ValueStack stack = context.getValueStack();

// 将对象添加到值栈中

stack.push(new MyObject());

// 获取参数映射

Map parameters = context.getParameters();

// 获取特定参数

String parameterValue = (String) parameters.get("paramName");

return SUCCESS;

}

}

在上述代码中,通过 ActionContext.getContext() 获取当前ActionContext对象,然后可以通过它访问值栈和参数映射。值栈是一个保存了Action数据的对象,拦截器和标签库可以从中提取和操作数据。 parameters 包含了当前请求的参数值。需要注意的是, parameters 的使用越来越少,因为现在推荐使用OGNL表达式来访问请求参数。

2.2 控制器的配置与应用

2.2.1 struts.xml的配置规则和技巧

Struts2的控制器配置主要是通过 struts.xml 文件实现的。这个配置文件指定了每个Action的映射信息、结果类型以及拦截器栈等。掌握 struts.xml 的配置规则是进行Struts2应用开发的基础。

struts.xml 文件中,每个 元素对应一个Action映射。例如:

/pages/success.jsp

/pages/form.jsp

name 属性指定Action的名称,用于后续通过URL请求触发该Action。 class 属性指定Action类的完整路径。 method 属性指定了被调用的方法,此处为execute方法。 标签定义了返回结果的逻辑视图,可以指定不同的返回值名称(如"success"和"input")。

配置技巧:

分层配置: 将 struts.xml 拆分成多个模块化的配置文件,可以在不同的环境中动态加载特定的配置,增加项目的可维护性。 动态方法调用(DMI): 通过 method 属性的通配符可以启用DMI,允许通过请求参数指定调用的方法名,但需谨慎使用,因为它可能带来安全风险。 动态结果视图: 使用OGNL表达式在结果视图配置中动态选择返回的JSP页面或其他视图,可以更加灵活地控制显示逻辑。

2.2.2 Action映射和方法映射的区别和选择

在Struts2中,Action映射和方法映射是两个不同的概念。Action映射负责将请求URL映射到具体的Action类和其方法上,而方法映射则是在Action映射的基础上,指定了具体调用Action类中的哪个方法。

Action映射 是最基础的映射方式,通常情况下,一个Action映射对应一个Action类。在这种情况下,Struts2默认调用Action类中的 execute 方法。 方法映射 则提供了更精细的控制。通过在 标签中定义 method 属性,可以指定调用Action类中的任何方法。这为实现复用Action类提供了可能,因为同一个Action类可以处理多种不同的业务逻辑。

选择使用Action映射还是方法映射取决于具体的应用场景:

如果Action类是单一职责,且只有一个主要的操作(如表单提交的处理),则推荐使用默认的Action映射,即不指定 method 属性。 如果Action类需要处理多种不同的业务逻辑(如增删改查),则推荐使用方法映射。这样可以通过不同的URL请求调用不同的方法,同时保持Action类的职责单一。

/user/add_success.jsp

/user/process_success.jsp

/user/process_input.jsp

在方法映射中, processUser 方法可以是执行特定业务逻辑的方法。通过URL访问 userAction 时,会调用该方法,并根据返回的结果类型跳转到相应的JSP页面。

选择合适的映射方式,可以提高应用的可维护性和扩展性。理解这两种映射的区别,有助于在实际开发中作出恰当的设计决策。

3. OGNL表达式语言

3.1 OGNL基础语法

3.1.1 变量的声明和引用

在Java Web应用中,Struts2框架使用OGNL(Object-Graph Navigation Language)来处理Web层的数据表达式。OGNL是Java的一个开源库,它提供了一种强大的方式来获取和设置Java对象属性的值。变量的声明和引用在OGNL表达式中是基础,允许开发者在表达式中存储数据,并在需要时访问它们。

变量的声明在OGNL中非常简单,只需要使用 # 符号来定义一个新的变量名,然后赋值。例如:

String name = "World";

String expression = "#name";

在上述代码中,我们定义了一个名为 name 的变量,并将其值设置为字符串 "World" 。然后我们使用OGNL表达式 "#name" 来引用这个变量。在Struts2的上下文中,这样的表达式通常被放在Action类或者JSP页面中的标签属性里。

变量的引用则直接通过变量名来进行。如果在Action类中有相应的属性或方法,OGNL将自动根据变量名去访问该属性或方法的值。例如:

public class MyAction {

private String name = "John";

public String getName() {

return name;

}

}

在这个例子中,如果在OGNL表达式中引用 name ,OGNL将首先查找是否有名为 name 的属性,然后查找名为 getName 的getter方法,并最终返回"John"。

在实际应用中,OGNL变量的作用域通常是当前Action的生命周期,因此在同一个Action中声明的变量可以在OGNL表达式中被自由地引用。

3.1.2 集合的操作和过滤

OGNL提供了强大的表达式语言来操作集合,包括数组、List、Map等。集合的操作和过滤是数据处理的重要组成部分,OGNL通过简洁的语法支持这些操作。

例如,如果你有一个List对象,你可以使用OGNL进行迭代:

List list = Arrays.asList("Apple", "Banana", "Cherry");

String expression = "#list.{#this.contains('a')}";

上述表达式将返回一个新的List,其中包含原List中所有包含字母"a"的元素。

过滤是集合操作中的一个常用功能。OGNL的过滤器语法十分直观,可以很方便地对集合进行筛选。例如:

List list = Arrays.asList("Apple", "Banana", "Cherry");

String expression = "#list.{?#this.contains('a')}";

这个表达式会筛选出List中包含字母"a"的元素,结果为 ["Apple", "Banana"] 。 {?...} 表示过滤操作, #this 代表当前遍历到的元素。

过滤操作不仅仅限于List,Map的值也可以进行过滤。假设有一个Map,我们可以这样过滤出所有值为奇数的键值对:

Map map = new HashMap<>();

map.put("one", 1);

map.put("two", 2);

map.put("three", 3);

String expression = "#{map.{?#value % 2 != 0}}";

此表达式将输出一个Map,其中只包含值为奇数的键值对,例如: {"one"=1, "three"=3} 。

以上展示了OGNL在处理集合时的强大功能,它简化了代码量,同时提供了高度的可读性和易用性,这对于Java Web开发来说非常有用。在Struts2应用中,这些特性被广泛地应用于处理表单数据、执行业务逻辑以及数据展示等方面。

3.2 OGNL高级特性

3.2.1 OGNL的类型转换和类型安全

OGNL在处理类型转换时采用了一种宽松的策略,这意味着OGNL表达式通常会尝试自动将一种类型的对象转换为另一种期望的类型。这种自动转换功能在大多数情况下是非常方便的,但也可能导致类型安全问题,特别是在复杂的表达式中。

例如,假设有一个字符串"123",OGNL可以直接将其转换为一个整数:

String value = "123";

int number = (Integer) Ognl.getValue("#value", null, null, Integer.class);

在这个例子中,OGNL会自动将字符串"123"转换为整数123,执行类型转换。

类型安全是指代码中的表达式不会导致类型转换异常,它能够确保转换过程中的正确性和可预测性。OGNL通过内置的类型转换器和自定义的转换逻辑来提升类型安全。

要实现更精细的类型转换控制,可以自定义OGNL的类型转换器:

public class CustomTypeConverter implements TypeConverter {

@Override

public Object convertValue(Map context, Object target, Object property, Type type) {

// 实现类型转换逻辑

}

}

然后在OGNL的配置中注册这个转换器。

虽然OGNL提供了方便的类型转换能力,但是类型不匹配的自动转换可能会导致运行时错误,因此建议在开发中谨慎使用,并尽可能明确指定转换目标类型,确保类型安全。

3.2.2 在Struts2中整合OGNL表达式

OGNL表达式在Struts2框架中得到了广泛的应用,尤其是在ActionContext中。Struts2通过OGNL提供了对Action类的属性访问和方法调用的能力。

为了在Struts2中整合OGNL表达式,首先需要理解OGNL上下文的概念。在Struts2中,OGNL上下文是一个包含了Web应用中所有可用数据的容器,其中的数据可以是Action类的实例,也可以是其他Map、List等集合对象。

通过OGNL表达式,可以非常简单地访问Action类的属性:

public class MyAction extends ActionSupport {

private String username;

public String execute() {

// Action的业务逻辑

return SUCCESS;

}

}

在Struts2的配置文件中,可以这样配置Action:

/success.jsp

在JSP页面中,可以使用OGNL表达式来显示用户名:

这将输出 MyAction 实例中 username 属性的值。

除了访问属性,OGNL表达式也可以用来执行Action类中的方法:

这将调用 MyAction 类中的 getUsername 方法,并将结果输出。

为了进一步提升性能和安全性,Struts2还允许开发者配置OGNL访问控制,防止对敏感数据或方法的访问。

整合OGNL表达式到Struts2框架中,让Web应用的数据处理变得更加灵活和强大。通过OGNL,开发者可以轻松地实现数据绑定、动态表单验证、页面导航逻辑等,这些都是构建动态Web应用所必需的功能。因此,深入理解OGNL在Struts2中的运用,对于提升开发效率和应用质量是十分关键的。

4. 拦截器机制

4.1 拦截器的基本概念

4.1.1 拦截器的生命周期和执行顺序

拦截器(Interceptor)是Struts2框架中非常重要的一个特性,它允许我们在Action执行之前或之后进行某些操作。拦截器的生命周期和执行顺序是理解其工作原理的关键。

拦截器的生命周期可以分为以下几个主要阶段: 1. 初始化(init):在拦截器被加载时调用,只执行一次。 2. 拦截(intercept):在Action执行前后调用,对请求进行处理。 3. 销毁(destroy):在拦截器从容器中移除时调用,只执行一次。

当一个请求进入Struts2框架时,拦截器会按照在struts.xml中配置的顺序被激活。Struts2会为每个请求创建一个拦截器栈(Interceptor Stack),这些拦截器将按照栈的顺序依次执行其intercept方法。

拦截器的执行顺序可以概括为: 1. 执行栈中第一个拦截器的 init 方法。 2. 按照配置顺序,依次执行栈中每个拦截器的 intercept 方法。 3. Action执行完成。 4. 按照相反的顺序,依次执行栈中每个拦截器的 intercept 方法。 5. 执行栈中最后一个拦截器的 destroy 方法。

以下是一个简化的示例代码,展示如何定义一个拦截器:

public class MyInterceptor implements Interceptor {

private String name;

public void init() {

// 初始化代码

}

public void destroy() {

// 销毁代码

}

public String intercept(ActionInvocation invocation) throws Exception {

// 在Action执行前的操作

String result = invocation.invoke(); // 执行下一个拦截器或Action

// 在Action执行后操作

return result;

}

// 设置器方法,用于通过struts.xml配置文件注入属性

public void setName(String name) {

this.name = name;

}

}

4.1.2 自定义拦截器的创建和配置

创建自定义拦截器涉及几个步骤,包括编写拦截器代码、配置拦截器以及注册拦截器到拦截器栈中。下面是创建和配置拦截器的步骤:

编写拦截器代码 : 自定义拦截器需要实现 Interceptor 接口或者继承 AbstractInterceptor 类。实现 intercept 方法用于控制请求和响应的流程。

public class MyCustomInterceptor extends AbstractInterceptor {

@Override

public String intercept(ActionInvocation invocation) throws Exception {

// 在Action调用之前执行的代码

String result = invocation.invoke(); // 继续调用下一个拦截器或Action

// 在Action调用之后执行的代码

return result;

}

}

配置拦截器 : 在 struts.xml 文件中,将自定义拦截器配置为一个bean,并定义它的具体属性。

someValue

注册拦截器到拦截器栈 : 创建一个拦截器栈,并将自定义的拦截器添加到栈中。

使用拦截器栈 : 在需要使用该拦截器栈的action中引用它。

通过以上步骤,自定义拦截器就可以被系统所识别并在请求处理时执行相应的逻辑。这种方式提供了极高的灵活性,允许开发者在不修改核心框架代码的情况下,增加额外的处理逻辑。

4.2 拦截器的应用与案例分析

4.2.1 常见内置拦截器的原理和用途

Struts2框架提供了一些内置的拦截器,它们在处理请求时发挥着重要作用。了解这些内置拦截器的原理和用途,有助于我们更好地使用和扩展拦截器功能。

ParamsInterceptor :默认情况下包含在 defaultStack 中,此拦截器负责将请求参数映射到Action的属性上。它利用OGNL表达式来实现这一映射过程。 ConversionErrorInterceptor :在类型转换失败时,此拦截器捕获转换错误,并将其存储在Action上下文中,方便后续的错误处理。 PrepareInterceptor :此拦截器用于在Action方法执行前进行属性的初始化工作,例如调用setter方法或执行其他准备工作。 ValidationInterceptor :当Action类上添加了验证注解时,此拦截器负责调用验证器(Validator)来验证Action属性的有效性。 ModelDrivenInterceptor :处理实现了 ModelDriven 接口的Action,此拦截器可以将Action包装的对象模型推入值栈中。

这些内置拦截器的组合使用,构成了Struts2框架的核心处理流程,从而使得Web应用开发更加高效和方便。

4.2.2 如何编写高效的拦截器逻辑

编写高效的拦截器逻辑需要遵循几个关键原则。这些原则不仅适用于拦截器,同样适用于多数编程实践。

单一职责原则 :每个拦截器应当只关注于一项功能,避免在拦截器中添加过多的职责。 拦截器链中的顺序 :按照逻辑处理顺序合理安排拦截器的执行顺序。 性能考量 :避免在拦截器中执行耗时操作,应当尽量减少拦截器的处理时间和占用的系统资源。 代码复用 :利用Struts2框架提供的内置拦截器,以及继承和组合的方式复用代码,避免重复编写相似功能的拦截器。 异常处理 :合理处理异常,不要让异常中断拦截器链,应提供默认行为或记录日志以便后续分析。

以下是一个高效拦截器的简单代码示例:

public class ProfilingInterceptor extends AbstractInterceptor {

private static final Logger logger = LoggerFactory.getLogger(ProfilingInterceptor.class);

@Override

public String intercept(ActionInvocation invocation) throws Exception {

long startTime = System.currentTimeMillis();

String result = invocation.invoke(); // 执行Action或下一个拦截器

long endTime = System.currentTimeMillis();

logger.info("Action execution time: {} ms", (endTime - startTime));

return result;

}

}

在上面的代码中, ProfilingInterceptor 拦截器简单地记录了Action执行所耗费的时间。通过记录这些性能数据,开发者可以对性能瓶颈进行分析和优化。在实际应用中,应根据需求添加日志级别控制和性能指标的详细记录,以支持后续的性能分析工作。

5. 结果类型处理与项目实践

5.1 结果类型处理机制

5.1.1 结果类型的定义和配置

在Struts2中,结果类型处理机制是定义如何响应用户请求的关键。结果类型指的是当动作执行完成后,Struts2框架用来处理动作结果的组件。Struts2框架预定义了多种结果类型,如 chain 、 dispatcher 、 freemarker 、 httpheader 、 stream 、 velocity 和 xslt 等。

配置结果类型主要通过在struts.xml文件中配置 元素来完成。例如,当用户提交表单后,我们通常希望页面跳转到另一个页面,这时可以使用 dispatcher 类型:

/welcome.jsp

上述配置中,当 LoginAction 的 execute 方法返回 "success" 结果时,Struts2会使用 dispatcher 结果类型将请求转发到 /welcome.jsp 页面。

5.1.2 页面跳转与数据传递的实现

Struts2提供了多种方式来实现页面跳转和数据传递。除了使用 元素直接定义跳转之外,还可以通过 ActionContext 传递数据,或者使用 子元素在 内定义参数传递。

例如,如果需要在跳转时传递用户信息到 welcome.jsp 页面,可以在Action中将用户信息放入 ValueStack 中:

public class LoginAction extends ActionSupport {

public String execute() throws Exception {

// 假设逻辑处理成功,添加用户信息到ValueStack

ActionContext.getContext().getValueStack().push(user);

return SUCCESS;

}

}

然后在 struts.xml 配置中,可以这样配置:

/welcome.jsp

Stack

在 welcome.jsp 页面中,可以通过Struts2标签获取这些参数值:

5.2 结合实际案例的项目实践

5.2.1 Struts2项目结构的最佳实践

构建Struts2项目的最佳实践通常包括以下几点:

Action类 应该保持无状态,以支持框架的重用。 业务逻辑 应该与Action分离,交给服务层处理。 视图技术 的选择应根据项目需求来定,常见的如JSP、Velocity或FreeMarker。 依赖管理 ,建议使用Maven或Gradle来管理项目依赖。 日志记录 ,应当集成日志框架,如Log4j2,记录Action执行过程中的重要信息。

5.2.2 Struts2集成第三方框架的策略

在实际项目中,Struts2需要与其他框架如Spring、Hibernate等集成。一般情况下,可以采用以下策略:

Spring集成 :使用Spring容器管理Struts2的Action,以便于依赖注入和事务管理。 Hibernate集成 :将Hibernate SessionFactory注入到Action中,利用Hibernate进行数据持久化。

例如,可以在 struts.xml 中配置Action使用Spring的Bean:

/welcome.jsp

确保在Spring的配置文件中,已经将 LoginAction 配置为Spring的Bean。

5.2.3 大型项目的模块化和解耦技巧

大型项目通常采用模块化设计,以降低复杂度和提高维护性。Struts2支持通过包划分不同的模块,每个模块可以有自己的 struts.xml 配置文件和Action类。

对于模块间的通信和解耦,可以采用以下策略:

命令模式 :将每个业务操作抽象成一个命令,通过命令调度器进行分发。 事件发布/订阅模式 :允许模块间通过事件进行解耦通信,例如使用Spring的事件模型。

例如,在模块间通信时,可以定义一个事件类,当一个模块完成其业务逻辑后发布事件,其他模块监听此类事件进行相应处理。

请注意,本章节内容展示了如何在Struts2框架中处理结果类型、如何结合实际案例进行项目实践,以及如何在大型项目中应用模块化和解耦技巧。通过具体配置实例和策略说明,结合代码和实际案例,本章节旨在为读者提供清晰、深入的理解和应用指导。

本文还有配套的精品资源,点击获取

简介:Struts2是一个流行Java Web框架,基于MVC设计模式。本文将探讨Struts2的关键特性和使用相关工具的实践,包括Action类、OGNL表达式语言、拦截器、结果类型以及配置灵活性。同时,还将介绍集成开发环境(IDE)的支持、构建工具如Maven或Gradle,以及调试和测试工具等。安全问题也被提及,强调及时更新框架的重要性。整体上,本文旨在帮助开发者通过深入了解Struts2,提高Web应用开发的效率和安全性。

本文还有配套的精品资源,点击获取

最新发表
友情链接

Copyright © 2022 流光追月·网游特刊 All Rights Reserved.