Struts2.0开发手册:Java Web开发的MVC框架

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Struts2.0是基于Struts1.x改进的Java Web MVC框架,本手册深入探讨其核心概念、配置及实践方法。内容包括Action和结果类型处理、拦截器的灵活性、OGNL表达式的使用、XML和注解配置选项、丰富的插件生态、全局异常处理、国际化支持以及单元测试友好的特点。开发人员通过阅读,可深入了解Struts2.0的高级特性并掌握实际项目开发的最佳实践。 三大框架中文文档中的struts2.0开发手册(程序员必看)

1. Struts2.0 MVC框架概述

Struts2.0是一个经典的Java Web应用框架,它基于MVC(Model-View-Controller)设计模式,是企业级Java应用开发的重要组成部分。Struts2.0在继承了Struts1.x的核心优势同时,也引入了WebWork框架的特性,从而成为一个更加灵活、功能强大的框架。

1.1 Struts2.0框架的起源与发展

1.1.1 从Struts1.x到Struts2.0的演变

Struts2.0是Struts1.x的后继者。在1.x版本中,开发者遇到了诸多限制,如对Action的耦合度高、难以维护和扩展。Struts2.0应运而生,采纳了WebWork的拦截器和值栈等概念,显著提升了框架的性能、灵活性和可维护性。

1.1.2 Struts2.0的核心特点与优势

Struts2.0的显著特点是其轻量级的拦截器机制。拦截器提供了一个简便的方式来进行请求处理的预处理和后处理。Struts2.0还拥有强大的数据类型转换、丰富的结果类型、易用的验证框架和与Ajax的无缝整合等优势。

在学习和使用Struts2.0时,开发者会发现它对资源文件的良好组织、对主题和模板的内建支持以及对国际化(i18n)和本地化(l10n)的全面支持,这都极大地促进了国际化Web应用的开发。

2. Action与结果类型的工作机制

2.1 Action的概念与生命周期

2.1.1 Action接口的作用与实现方式

在Struts2框架中,Action是控制器(Controller)的核心组件,它负责接收用户的输入并将其转化为业务逻辑的执行。Action接口是所有Action类的父接口,它定义了一个执行方法 execute() 。当用户提交表单或者请求一个操作时,Struts2框架会创建Action实例,并调用这个 execute() 方法。开发者通常不直接实现Action接口,而是继承一个类,如 ActionSupport ,该类已经提供了 execute() 方法的默认实现以及许多辅助方法和属性。

public class MyAction extends ActionSupport {
    private String name;
    private int age;

    @Override
    public String execute() {
        // 实现业务逻辑
        return SUCCESS;
    }
}

2.1.2 Action生命周期各阶段详解

Action的生命周期包括实例化、初始化、执行 execute() 方法和销毁四个阶段:

  • 实例化 :Struts2容器使用无参构造器创建Action的实例。
  • 初始化 :如果Action有 @PostConstruct 注解的方法或者实现了 Initializable 接口,则此阶段会调用它们。
  • 执行 :Struts2容器调用Action的 execute() 方法。此方法返回一个字符串,通常是“success”、“error”或者指定的其他结果名称。
  • 销毁 :在Web应用关闭或者服务器停止时,如果Action实现了 DisposableBean 接口或者有 @PreDestroy 注解的方法,它们将被调用。

2.2 结果类型的选择与配置

2.2.1 常见结果类型介绍:dispatcher、redirect等

在Struts2中,结果类型定义了当Action执行完成后视图(View)如何被呈现。最常见的结果类型包括:

  • dispatcher :这是默认的结果类型,用于将请求转发到视图组件,如JSP页面。
  • redirect :用于重定向用户到另一个URL,这类似于Servlet中的 HttpServletResponse.sendRedirect 方法。
  • chain :用于继续执行另一个Action的操作。
  • redirectAction :此结果类型允许重定向到另一个Action,同时可以传递参数。

配置结果类型时,可以在Action类的 execute() 方法中返回结果名称,然后在struts.xml中定义对应的结果名称和类型。

2.2.2 结果类型配置的最佳实践

配置结果类型时,一个最佳实践是使用 <result> 元素来指定视图名称和结果类型,如:

<action name="myAction" class="com.example.MyAction">
    <result name="success">/pages/success.jsp</result>
    <result name="error" type="redirectAction">
        <param name="actionName">login</param>
        <param name="executionContext">ERROR</param>
    </result>
</action>

在这个例子中,成功执行 execute() 方法将结果转发到 success.jsp 页面,而在错误情况下则重定向到 login Action。

2.3 实现Action与视图的交互

2.3.1 Action与JSP页面的数据传递

Struts2提供了多种方式在Action和JSP页面之间传递数据。最简单的方式是将Action对象的属性设置为私有,并提供公共的getter和setter方法。在 execute() 方法中,可以通过这些方法设置数据,然后在JSP页面中通过EL表达式访问它们。

public class MyAction extends ActionSupport {
    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
    @Override
    public String execute() {
        setMessage("Hello World!");
        return SUCCESS;
    }
}

在JSP页面中,可以通过 ${message} 访问这个属性。

2.3.2 数据校验和验证框架集成

为了保证数据质量,Struts2提供了内建的数据校验机制。开发者可以通过在Action类中定义校验规则来实现这一功能。此外,Struts2还集成了Jakarta Commons Validator来支持更复杂的校验需求。

public class MyAction extends ActionSupport {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public String validate() {
        if (username == null || username.isEmpty()) {
            addFieldError("username", "Username cannot be empty!");
        }
        if (password == null || password.isEmpty()) {
            addFieldError("password", "Password cannot be empty!");
        }
        return super.validate();
    }
    @Override
    public String execute() {
        return SUCCESS;
    }
}

在这个例子中,如果用户名或密码为空,相应的错误信息将被捕获,并且用户将被带回到输入页面。

这样,我们就完成了第二章的详细内容,关于Action与结果类型的工作机制,涵盖了Action的基本概念、结果类型的配置以及与视图的交互等多个方面。在下一章中,我们将探索Struts2框架中的拦截器,并了解如何自定义和优化拦截器行为。

3. 拦截器的配置与自定义

拦截器是Struts2.0框架中重要的组成部分,它是框架提供的一种强大机制,用于在请求处理流程中的不同点插入用户自定义的行为。拦截器可以在请求被处理之前进行预处理操作,或在处理之后进行清理和附加操作,从而实现代码的复用和职责的分离。

3.1 拦截器的工作原理与应用场景

3.1.1 拦截器与过滤器的区别

拦截器和过滤器都是用于控制HTTP请求和响应的组件,但是它们在Web应用架构中的位置和作用有所不同。过滤器属于Servlet API的一部分,它拦截请求和响应在进入或离开Servlet之前,能够对几乎所有的资源进行过滤,包括静态资源如图片、HTML页面和JavaScript文件等。

而拦截器是Struts2.0框架特有的,它只对框架内部的请求处理过程起作用。拦截器工作在Action执行前后,可以访问到值栈中的对象,与框架的其他部分如Action、Result等紧密集成。

3.1.2 拦截器在Struts2.0中的作用

拦截器在Struts2.0中扮演了非常关键的角色,主要有以下几点作用:

  • 日志记录 :可以记录用户请求的详细信息,帮助追踪和分析问题。
  • 验证 :可以在Action执行之前对用户输入的数据进行验证。
  • 权限检查 :检查用户是否有权访问请求的资源。
  • 数据封装 :封装请求数据到值栈中,便于后续处理。
  • 性能监控 :在请求处理前后记录时间,用于性能监控和分析。

3.2 配置Struts2.0的内建拦截器

3.2.1 常见内建拦截器的功能与配置

Struts2.0提供了大量内建的拦截器,每个拦截器都有其特定的功能和默认配置。以下是一些常用的内建拦截器:

  • PrepareInterceptor :在Action执行之前,为Action准备数据。
  • ParamsInterceptor :读取请求参数,并根据Action的属性名映射到值栈。
  • ValidationInterceptor :执行验证逻辑,如果验证失败,将返回到表单页面。
  • ConversionErrorInterceptor :处理类型转换错误。
  • ProfilingInterceptor :提供性能监控数据。

要在Struts2.0配置文件中启用这些拦截器,你需要将它们添加到默认的拦截器栈中,如下所示:

<interceptors>
    <interceptor-stack name="myStack">
        <interceptor-ref name="defaultStack"/>
        <!-- 自定义拦截器 -->
        <interceptor-ref name="myCustomInterceptor" />
    </interceptor-stack>
</interceptors>
<action name="example" class="com.example.ExampleAction">
    <interceptor-ref name="myStack" />
    <!-- 其他配置 -->
</action>

3.2.2 拦截器栈的创建与应用

拦截器栈是拦截器的集合,它允许你将多个拦截器按顺序组织起来,形成一个拦截链。在处理请求时,拦截器栈中的拦截器会依次执行。

创建拦截器栈的步骤如下:

  1. 定义拦截器栈。
  2. 在栈中添加拦截器。
  3. 指定栈应用到特定的Action或全局配置。

例如,创建一个名为 myStack 的拦截器栈,并将 PrepareInterceptor ValidationInterceptor 加入其中:

<interceptors>
    <interceptor-stack name="myStack">
        <interceptor-ref name="defaultStack"/>
        <interceptor-ref name="prepare"/>
        <interceptor-ref name="validation"/>
    </interceptor-stack>
</interceptors>

然后,可以在Action中引用这个栈:

<action name="example" class="com.example.ExampleAction">
    <interceptor-ref name="myStack"/>
    <!-- 其他配置 -->
</action>

3.3 自定义拦截器的开发与应用

3.3.1 自定义拦截器的基本步骤

开发自定义拦截器需要遵循以下步骤:

  1. 创建拦截器类,继承 AbstractInterceptor MethodFilterInterceptor
  2. 实现 intercept 方法或覆盖 doIntercept 方法。
  3. 在方法中编写自定义逻辑。
  4. struts.xml 中配置拦截器。
  5. 将拦截器加入到拦截器栈中。

以下是创建一个简单的自定义拦截器的代码示例:

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class MyCustomInterceptor extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        // 在请求处理之前执行的代码
        System.out.println("Before Action");

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

        // 在请求处理之后执行的代码
        System.out.println("After Action");

        return result;
    }
}

配置这个拦截器需要在 struts.xml 中进行:

<interceptors>
    <interceptor name="myCustomInterceptor" class="com.example.MyCustomInterceptor"/>
    <!-- 其他配置 -->
</interceptors>

3.3.2 拦截器链的构造与优化策略

构造拦截器链时,需要考虑拦截器的执行顺序对整体处理流程的影响。拦截器通常按照配置文件中声明的顺序执行,但在使用过滤器时,顺序可能不同。为了优化性能,应该尽量减少不必要的拦截器调用,只在需要的时候调用特定的拦截器。

可以通过以下策略进行优化:

  • 过滤不必要的请求 :使用过滤器或拦截器预检请求,减少对非目标请求的处理。
  • 异步处理 :对于执行时间较长的操作,可以考虑使用异步方式。
  • 缓存结果 :如果拦截器的某些结果可以预知,那么可以考虑缓存这些结果以避免重复计算。
  • 日志优化 :合理安排日志记录的级别和内容,避免不必要的I/O操作。

自定义拦截器赋予了开发者强大的灵活性来控制请求的处理逻辑,使得Struts2.0的应用程序更加模块化和易于维护。通过上述方法,开发者可以根据实际需求进行高效的拦截器开发和配置,从而优化应用程序的性能和用户体验。

4. OGNL表达式语言的使用

4.1 OGNL表达式语言基础

4.1.1 OGNL的语法特点与规则

OGNL,即 Object-Graph Navigation Language,是一种功能强大的表达式语言,它允许在Java对象的图中进行导航、数据访问和数据操作。在Struts2.0框架中,OGNL用于处理请求参数、访问动作类的属性以及执行动态方法调用等。

OGNL 表达式通常包含以下几种类型的元素: - 属性访问 :使用点号( . )来访问对象的属性。例如, user.name 可以访问 user 对象的 name 属性。 - 方法调用 :使用圆括号( () )来调用对象的方法。例如, user.getName() 可以调用 user 对象的 getName 方法。 - 数组和集合索引 :使用方括号( [] )来访问数组或集合中的元素。例如, users[0] 可以访问 users 集合的第一个元素。 - 逻辑运算符 :如 && (逻辑与)、 || (逻辑或)、 ! (逻辑非)等。 - 数学运算符 :如 + (加)、 - (减)、 * (乘)、 / (除)等。

4.1.2 OGNL在Struts2.0中的应用范围

在Struts2.0中,OGNL不仅可以用于在动作类和视图之间传递数据,还用于动态表达式计算、类型转换和动作链的定义。

举例来说,当一个动作类返回一个字符串结果,可以通过OGNL表达式直接在页面上显示:

<result name="success" type="dispatcher">/success.jsp?message=${message}</result>

此例中 ${message} 就是一个OGNL表达式,用于在视图中显示动作类中 message 属性的值。

OGNL还被用来配置动态方法调用,支持通过一个字符串参数来调用动作类中对应的方法,如下所示:

<action name="userAction" class="com.example.UserAction" method="execute">
    <result name="success">/user_success.jsp</result>
    <result name="error">/user_error.jsp</result>
</action>

在上述配置中, method 属性可以是OGNL表达式,使得方法调用动态化。

4.2 OGNL的高级功能与技巧

4.2.1 集合和Map的操作

OGNL提供了强大的集合操作功能。可以对集合进行过滤、映射和排序等操作。例如,可以使用OGNL表达式筛选出用户列表中的女性用户:

userList.{? #this.gender == 'female'}

在这个表达式中, userList 是用户的集合, #this.gender == 'female' 是过滤条件,表示筛选出性别为女性的用户。

同样,可以对用户列表进行排序:

userList.{#this.name}

此表达式将根据用户的 name 属性进行自然排序。

4.2.2 类型转换和动态方法调用

OGNL允许对对象的类型进行转换。例如,可以将字符串转换为整数:

${"123".parseInt()}

在实际应用中,这样的类型转换经常用于处理表单提交的数据。

OGNL也支持动态方法调用,允许在动作类中根据字符串参数调用不同的方法:

${actionInstance.doSomeAction("arg1", "arg2")}

这里的 doSomeAction 方法可以是动态传入的,通过OGNL解析这个方法名字符串并调用实际的方法。

4.3 OGNL在安全和性能上的考量

4.3.1 OGNL的安全隐患及防范措施

OGNL本身是非常强大的,但在使用时也要注意安全问题。OGNL表达式可以访问和修改任何对象的属性,因此如果用户输入未经严格验证,就有可能造成安全漏洞。

为防范这种情况,可以采取如下措施: - 限制OGNL访问 :通过配置安全相关的拦截器,例如 struts2ognlProvideValueStackAccess ,限制OGNL对值栈的访问。 - 使用安全拦截器 :使用如 struts2-prevent-ognl 等拦截器,阻止潜在的OGNL注入攻击。 - 输入验证 :在应用层面进行严格的输入验证,确保用户输入的内容不包含恶意代码。

4.3.2 性能调优技巧和最佳实践

由于OGNL在解析和执行表达式时会消耗资源,因此在性能方面也需要注意以下调优技巧: - 使用静态方法调用 :静态方法不需要创建对象实例,执行更快,应尽可能使用。 - 避免复杂表达式 :复杂表达式会消耗更多资源,在可能的情况下进行简化。 - 缓存结果 :对于重复使用的复杂表达式,可以考虑将其结果缓存起来,以减少重复计算。

下面是一个具体的代码块示例,展示了如何利用OGNL在Struts2.0中设置值栈的属性,并在视图中访问该属性。

// 在Action中设置值栈属性
ActionContext.getContext().setValue("message", "Hello, OGNL!");
<!-- 在JSP页面中访问OGNL表达式 -->
<p>Message from OGNL: ${message}</p>

在这个例子中,我们通过ActionContext将一个消息设置到值栈中,并在JSP页面中通过OGNL表达式访问这个值。需要注意的是,这个表达式在执行前会通过OGNL解析器进行解析,它会从值栈中检索 message 属性的值并显示出来。

总结来说,OGNL在Struts2.0框架中扮演了非常重要的角色,它的强大功能和灵活性使得数据处理和流程控制变得非常方便。但与此同时,正确且安全地使用OGNL也是每个开发者需要注意的问题。通过遵循最佳实践和采取必要的防范措施,我们可以最大化OGNL的效用,同时最小化安全风险。

5. 实际项目开发中的最佳实践

5.1 代码组织与项目结构优化

在实际开发中,良好的代码组织和项目结构能够提升开发效率,便于团队协作,同时也是系统维护和扩展的关键。以下是针对Struts2.0项目进行代码组织与结构优化的几个建议:

5.1.1 模块化开发和包结构设计

模块化开发是将大型项目拆分为更小、更易于管理的部分的过程。在Struts2.0中,我们通常根据功能和职责来划分模块。比如,我们可以创建如下包结构:

  • com.example.action :存放所有的Action类。
  • com.example.dao :存放数据访问对象(DAO)。
  • com.example.util :存放工具类和通用模块。
  • com.example.model :存放业务对象(Java Beans)。

在每个包内,我们还可以进一步细分,比如根据功能模块划分子包,如 com.example.action.user com.example.action.product 。这样的结构清晰,有助于代码的维护和理解。

5.1.2 多环境配置与管理

在开发过程中,我们通常需要区分不同的环境,如开发环境、测试环境和生产环境。为了更好地管理不同环境下的配置,我们可以采用如下策略:

  • src/main/resources 目录下创建环境相关的配置文件,如 development.properties test.properties production.properties
  • 利用Maven或Gradle的profiles功能,通过构建脚本切换不同环境下的配置文件。

例如,使用Maven时,可以在 pom.xml 中配置不同的profiles,如下所示:

<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <env>development</env>
        </properties>
    </profile>
    <profile>
        <id>prod</id>
        <properties>
            <env>production</env>
        </properties>
    </profile>
</profiles>

5.2 与现代技术栈的整合策略

Struts2.0是一个成熟的MVC框架,但在现代的项目中,可能需要与其他技术栈整合,以充分利用现有技术的优势。下面介绍如何将Struts2.0与Spring、Hibernate进行整合以及如何集成响应式编程和Web服务。

5.2.1 整合Spring和Hibernate

整合Spring框架可以为Struts2.0提供依赖注入、事务管理等功能,而整合Hibernate则可以提供一个轻量级的ORM解决方案。

整合步骤大致如下:

  1. 添加Spring和Hibernate的依赖到项目中。
  2. 创建Spring的配置文件,配置数据源、session工厂以及事务管理器。
  3. 在Struts的配置文件中引用Spring的配置文件。
  4. 利用Spring的依赖注入功能,在Action中注入所需的DAO类。

这里是一个简化的整合示例:

<!-- Spring配置文件(applicationContext.xml) -->
<beans>
    <!-- 数据源配置 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <!-- 数据库连接参数 -->
    </bean>
    <!-- Session工厂配置 -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <!-- Hibernate属性配置 -->
    </bean>
    <!-- 事务管理器配置 -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    <!-- Action中注入DAO -->
    <bean id="userAction" class="com.example.action.UserAction">
        <property name="userService" ref="userService"/>
    </bean>
    <bean id="userService" class="com.example.service.UserService">
        <!-- 注入DAO等 -->
    </bean>
</beans>

5.2.2 响应式编程与Web服务集成

响应式编程是近年来非常热门的一个概念,能够帮助开发者创建异步的、非阻塞的,并且基于事件的系统。与Web服务集成则能够使得我们的应用能够被外部应用调用。

集成策略可以包括:

  • 使用如Spring WebFlux这样的响应式编程框架来处理Web层请求。
  • 利用RESTful API或SOAP Web服务来暴露内部数据和功能。

整合示例代码可能如下:

// Spring WebFlux控制器
@RestController
public class ReactiveController {
    @GetMapping("/users")
    public Flux<User> getAllUsers() {
        // 返回用户列表的响应式流
        return userService.getAllUsers();
    }
}

5.3 性能优化与维护策略

性能优化和维护是项目生命周期中不可或缺的环节,它们能够确保应用的高性能、高可用性和长期稳定性。

5.3.1 常见性能瓶颈分析与优化

性能瓶颈分析通常涉及以下几个方面:

  • 数据库查询优化:索引优化、查询语句优化。
  • 会话管理优化:会话持久化、分布式会话。
  • 并发处理优化:使用线程池、异步处理。

性能优化方法例如:

  • 对于数据库查询,可以使用专业的分析工具来发现慢查询,并进行优化。
  • 通过配置Struts2.0的 struts.concurrency-Control 参数来限制并发访问。
  • 使用缓存机制,如使用EHCache或Redis来减少数据库访问。

5.3.2 代码重构与系统升级的最佳实践

随着技术的发展和业务的变化,系统升级和代码重构是不可避免的。以下是一些最佳实践:

  • 保持代码的高内聚低耦合,便于模块替换和扩展。
  • 定期进行代码审查,避免技术债务累积。
  • 使用自动化测试和持续集成工具来保证重构不会引入新问题。

举个简单的代码重构例子:

// 糟糕的代码,函数职责不清晰
public String getUserList() {
    // 业务逻辑过于复杂
    // 这里可能涉及到获取用户数据、格式化输出等多个职责
}

// 重构后的代码,函数职责单一
public List<User> getUsers() {
    // 简单地获取用户数据,其它逻辑交给其它方法处理
}

public String getUserList() {
    List<User> users = getUsers();
    // 对users进行格式化并返回
}

以上就是对实际项目开发中,代码组织、模块化、技术栈整合以及性能优化与维护策略的一些建议和最佳实践。通过这些方法,可以确保在不断变化的业务和技术环境中保持应用的稳定和高效。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Struts2.0是基于Struts1.x改进的Java Web MVC框架,本手册深入探讨其核心概念、配置及实践方法。内容包括Action和结果类型处理、拦截器的灵活性、OGNL表达式的使用、XML和注解配置选项、丰富的插件生态、全局异常处理、国际化支持以及单元测试友好的特点。开发人员通过阅读,可深入了解Struts2.0的高级特性并掌握实际项目开发的最佳实践。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值