本文还有配套的精品资源,点击获取
简介: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
// 获取特定参数
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 文件中,每个
name 属性指定Action的名称,用于后续通过URL请求触发该Action。 class 属性指定Action类的完整路径。 method 属性指定了被调用的方法,此处为execute方法。
配置技巧:
分层配置: 将 struts.xml 拆分成多个模块化的配置文件,可以在不同的环境中动态加载特定的配置,增加项目的可维护性。 动态方法调用(DMI): 通过 method 属性的通配符可以启用DMI,允许通过请求参数指定调用的方法名,但需谨慎使用,因为它可能带来安全风险。 动态结果视图: 使用OGNL表达式在结果视图配置中动态选择返回的JSP页面或其他视图,可以更加灵活地控制显示逻辑。
2.2.2 Action映射和方法映射的区别和选择
在Struts2中,Action映射和方法映射是两个不同的概念。Action映射负责将请求URL映射到具体的Action类和其方法上,而方法映射则是在Action映射的基础上,指定了具体调用Action类中的哪个方法。
Action映射 是最基础的映射方式,通常情况下,一个Action映射对应一个Action类。在这种情况下,Struts2默认调用Action类中的 execute 方法。 方法映射 则提供了更精细的控制。通过在
选择使用Action映射还是方法映射取决于具体的应用场景:
如果Action类是单一职责,且只有一个主要的操作(如表单提交的处理),则推荐使用默认的Action映射,即不指定 method 属性。 如果Action类需要处理多种不同的业务逻辑(如增删改查),则推荐使用方法映射。这样可以通过不同的URL请求调用不同的方法,同时保持Action类的职责单一。
在方法映射中, 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
String expression = "#list.{#this.contains('a')}";
上述表达式将返回一个新的List,其中包含原List中所有包含字母"a"的元素。
过滤是集合操作中的一个常用功能。OGNL的过滤器语法十分直观,可以很方便地对集合进行筛选。例如:
List
String expression = "#list.{?#this.contains('a')}";
这个表达式会筛选出List中包含字母"a"的元素,结果为 ["Apple", "Banana"] 。 {?...} 表示过滤操作, #this 代表当前遍历到的元素。
过滤操作不仅仅限于List,Map的值也可以进行过滤。假设有一个Map,我们可以这样过滤出所有值为奇数的键值对:
Map
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:
在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文件中配置
上述配置中,当 LoginAction 的 execute 方法返回 "success" 结果时,Struts2会使用 dispatcher 结果类型将请求转发到 /welcome.jsp 页面。
5.1.2 页面跳转与数据传递的实现
Struts2提供了多种方式来实现页面跳转和数据传递。除了使用
例如,如果需要在跳转时传递用户信息到 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:
确保在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.