49、使用 Spring 构建班级名册应用

使用 Spring 构建班级名册应用

1. 引言

在开发班级名册应用时,我们可以借助 Spring 框架来实现依赖注入和应用程序的连接。使用 Spring DI 容器是 Spring 开发的基础技能,几乎所有其他 Spring 特性(如安全、AOP、MVC、REST)都依赖于核心的 Spring DI 容器。接下来,我们将详细介绍如何将班级名册应用转换为 Spring 应用。

2. 项目目标

为了将班级名册应用转换为 Spring 应用,我们需要完成以下任务:
- 添加 Spring 库到 POM 文件
- 添加 Spring 配置文件到项目
- 将 App 类中的依赖注入和应用连接代码转换为使用 Spring
- 将单元测试转换为使用 Spring

3. 包含 Spring 库

要使用 Spring 框架,我们需要确保 Maven POM 文件中包含 Spring 框架库。打开 pom.xml 文件,验证是否包含以下代码依赖:

<?xml version="1.0" encoding="UTF-8"?>
<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.sg</groupId>
    <artifactId>ClassRoster</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.6.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>5.6.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.6.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project>

特别要检查以下依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.0.RELEASE</version>
</dependency>

只要 Spring 框架依赖在 <dependencies> 节点内,即使各个依赖的顺序不同,也不会有问题。

如何确定依赖项

有两种方法可以确定 Maven 依赖项:
- 访问项目网站 :许多项目网站会直接提供 Maven 依赖项,只需复制粘贴到 POM 文件即可。例如,Spring 核心框架的 Maven 条目可以在 Spring Boot 的 Maven 插件页面(docs.spring.io/spring-boot/docs/current/maven-plugin/usage.html)找到。
- 使用搜索引擎搜索 :例如,在 Google 上搜索 “JUnit maven dependency”,搜索结果的顶部通常会有 JUnit 5 的 Maven 依赖项页面(mvnrepository.com/artifact/junit/junit/)。

4. 添加 Spring 配置文件

在引入 Spring 库后,我们需要添加应用程序上下文配置文件。一种定义 Spring DI 容器和应用程序上下文的方法是使用 XML 配置文件。我们通常将所有 bean 定义在 applicationContext.xml 文件中,但这不是强制要求,你可以使用任何文件名。

操作步骤如下:
1. 在项目的 src/main/resources 文件夹中创建 applicationContext.xml 文件(如果该文件夹不存在,需要手动创建),并复制以下代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- Bean definitions go here -->
</beans>

这是一个空的 applicationContext 文件模板,预填充了 Spring 容器的 XML 命名空间条目和一些额外的 Spring 特性。所有 bean 连接定义将出现在 “Bean definitions go here” 注释之后和 </beans> 标签之前。

  1. 在项目的 src/test/resources 文件夹中执行相同的操作(可能需要手动创建该文件夹)。这个 applicationContext.xml 文件将用于单元测试的单独配置。
5. 将 App 类转换为使用 Spring

现在,我们要将 App 类中的手动依赖注入代码转换为使用 Spring 进行依赖注入。具体来说,我们将把 App 类 main 方法中的代码移动到 applicationContext.xml 文件中。

App 类的 main 方法原始代码如下:

public static void main(String[] args) {
    UserIO myIo = new UserIOConsoleImpl();
    ClassRosterView myView = new ClassRosterView(myIo);
    ClassRosterDao myDao = new ClassRosterDaoFileImpl();
    ClassRosterAuditDao myAuditDao = new ClassRosterAuditDaoFileImpl();
    ClassRosterServiceLayer myService = new ClassRosterServiceLayerImpl(myDao, myAuditDao);
    ClassRosterController controller = new ClassRosterController(myService, myView);
    controller.run();
}
定义 Bean

在修改 applicationContext.xml 文件之前,我们需要了解一些用于定义 bean 的标签和属性:
- bean 标签 :用于定义我们希望 Spring 容器实例化的对象。
- id 属性 :用于为 Spring 容器实例化的特定 bean 指定别名,类似于 Map 中的键。
- class 属性 :指定我们希望 Spring 容器实例化的类的完全限定名,必须包含完整的包名。
- constructor-arg 标签 :嵌套在 bean 标签中,用于指示 Spring 在实例化 bean 时将参数传递给构造函数。
- ref 属性 :用于引用之前定义的 bean,其值必须是 applicationContext.xml 文件中另一个 bean 的 id。

修改 src/main/resources 中的 applicationContext.xml 文件,使其如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- Bean definitions go here -->
    <bean id="userIO" class="com.sg.classroster.ui.UserIOConsoleImpl"/>
    <bean id="view" class="com.sg.classroster.ui.ClassRosterView">
        <constructor-arg ref="userIO"/>
    </bean>
    <bean id="classRosterDao" class="com.sg.classroster.dao.ClassRosterDaoFileImpl"/>
    <bean id="auditDao" class="com.sg.classroster.dao.ClassRosterAuditDaoFileImpl"/>
    <bean id="serviceLayer" class="com.sg.classroster.service.ClassRosterServiceLayerImpl">
        <constructor-arg ref="classRosterDao"/>
        <constructor-arg ref="auditDao"/>
    </bean>
    <bean id="controller" class="com.sg.classroster.controller.ClassRosterController">
        <constructor-arg ref="serviceLayer"/>
        <constructor-arg ref="view"/>
    </bean>
</beans>
修改 App 类

修改 App 类的 main 方法,替换为以下代码:

public static void main(String[] args) {
    // 注释掉原有的手动实例化代码
    // UserIO myIo = new UserIOConsoleImpl();
    // ClassRosterView myView = new ClassRosterView(myIo);
    // ClassRosterDao myDao = new ClassRosterDaoFileImpl();
    // ClassRosterAuditDao myAuditDao = new ClassRosterAuditDaoFileImpl();
    // ClassRosterServiceLayer myService = new ClassRosterServiceLayerImpl(myDao, myAuditDao);
    // ClassRosterController controller = new ClassRosterController(myService, myView);
    // controller.run();

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    ClassRosterController controller = ctx.getBean("controller", ClassRosterController.class);
    controller.run();
}

ApplicationContext 是保存 applicationContext.xml 文件中定义的应用程序上下文的 Java 对象。我们使用 ClassPathXmlApplicationContext 实现,并将 Spring 应用程序上下文配置文件的名称传递给其构造函数。通过 getBean 方法可以从 Spring 应用程序上下文中检索 bean,该方法接受两个参数:要检索的 bean 的 id 和 bean 的类型。

6. 转换单元测试以使用 Spring

我们只需要将服务层单元测试转换为使用 Spring 应用程序上下文,因为只有服务层使用了依赖注入。

操作步骤如下:
1. 将 ClassRosterServiceLayerTest 类构造函数中的代码移动到 applicationContext.xml 文件中。 ClassRosterServiceLayerTest 类的构造函数原始代码如下:

public ClassRosterServiceLayerTest() {
    // wire the Service Layer with stub implementations of the Dao and
    // Audit Dao
    ClassRosterDao dao = new ClassRosterDaoStubImpl();
    ClassRosterAuditDao auditDao = new ClassRosterAuditDaoStubImpl();
    service = new ClassRosterServiceLayerImpl(dao, auditDao);
}
  1. 修改 src/test/resources 中的 applicationContext.xml 文件,使其如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- Bean definitions go here -->
    <bean id="classRosterDao" class="com.sg.classroster.dao.ClassRosterDaoFileImpl"/>
    <bean id="classRosterDaoStub" class="com.sg.classroster.dao.ClassRosterDaoStubImpl"/>
    <bean id="auditDaoStub" class="com.sg.classroster.dao.ClassRosterAuditDaoStubImpl"/>
    <bean id="serviceLayer" class="com.sg.classroster.service.ClassRosterServiceLayerImpl">
        <constructor-arg ref="classRosterDaoStub"/>
        <constructor-arg ref="auditDaoStub"/>
    </bean>
</beans>

与应用程序本身的 applicationContext.xml 文件相比,这里只定义了 DAO 和服务层的 bean,并且使用了存根版本的 DAO。

  1. 修改 ClassRosterServiceLayerTest 类的构造函数:
public ClassRosterServiceLayerTest() {
    // 注释掉原有的手动实例化代码
    // wire the Service Layer with stub implementations of the Dao and
    // Audit Dao
    // ClassRosterDao dao = new ClassRosterDaoStubImpl();
    // ClassRosterAuditDao auditDao = new ClassRosterAuditDaoStubImpl();
    // service = new ClassRosterServiceLayerImpl(dao, auditDao);

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    service = ctx.getBean("serviceLayer", ClassRosterServiceLayer.class);
}
7. 异常情况

虽然 Spring 容器可以帮助我们构建灵活、松散耦合的应用程序,但将依赖项外部化到 XML 配置文件可能会导致一些运行时错误,因为编译器无法捕获这些错误。以下是一些常见的错误:
| 错误类型 | 描述 |
| ---- | ---- |
| 拼写错误的 bean 类属性 | 所有 bean 类必须使用正确拼写的完全限定类名,否则 Spring 容器将抛出错误,指示无法实例化该 bean。 |
| ref 属性中 bean id 拼写错误 | 在 ref 属性中引用另一个 bean 时,其名称必须与原始 bean 定义中的名称完全一致。 |
| 格式错误的 XML | applicationContext.xml 文件必须是格式良好的 XML,此类错误通常会在错误消息中指出发生错误的行和列。 |
| 错误使用 value 属性 | 在构造函数或 setter 注入中,应使用 ref 属性传递对象引用,而不是使用 value 属性传递字面量值。 |

这些错误消息会显示在 NetBeans 控制台输出中。另外,还可以使用注解或 Java 代码为 Spring 容器提供配置元数据,这两种方式可以更好地处理上述错误,因为元数据是用 Java 代码编写的。

以下是将班级名册应用转换为 Spring 应用的流程图:

graph LR
    A[添加 Spring 库到 POM 文件] --> B[添加 Spring 配置文件]
    B --> C[将 App 类转换为使用 Spring]
    C --> D[转换单元测试以使用 Spring]

通过以上步骤,我们可以将班级名册应用成功转换为使用 Spring 框架的应用程序,利用 Spring 的依赖注入和应用程序连接功能,提高代码的可维护性和可测试性。

使用 Spring 构建班级名册应用

8. 总结关键步骤

为了更清晰地回顾整个将班级名册应用转换为 Spring 应用的过程,我们将关键步骤总结如下:

步骤 操作内容
1 包含 Spring 库:在 pom.xml 文件中添加 Spring 相关依赖,可通过项目网站或搜索引擎确定依赖项。
2 添加 Spring 配置文件:在 src/main/resources src/test/resources 文件夹中分别创建 applicationContext.xml 文件,并使用预定义的模板。
3 转换 App 类:将 App 类 main 方法中的手动依赖注入代码迁移到 applicationContext.xml 文件,修改 main 方法以使用 Spring 容器实例化对象。
4 转换单元测试:将服务层单元测试的构造函数代码迁移到 src/test/resources 中的 applicationContext.xml 文件,修改测试类构造函数以使用 Spring 容器。
5 处理异常情况:注意常见的 XML 配置文件错误,如 bean 类属性拼写错误、ref 属性中 bean id 拼写错误等。
9. 代码解释与分析
App 类转换代码分析

在 App 类的 main 方法中,我们从手动实例化对象转变为使用 Spring 容器。原代码通过手动创建每个对象并传递依赖,而修改后的代码使用 ClassPathXmlApplicationContext 加载 applicationContext.xml 文件,并通过 getBean 方法从容器中获取所需的对象。

// 原代码
public static void main(String[] args) {
    UserIO myIo = new UserIOConsoleImpl();
    ClassRosterView myView = new ClassRosterView(myIo);
    ClassRosterDao myDao = new ClassRosterDaoFileImpl();
    ClassRosterAuditDao myAuditDao = new ClassRosterAuditDaoFileImpl();
    ClassRosterServiceLayer myService = new ClassRosterServiceLayerImpl(myDao, myAuditDao);
    ClassRosterController controller = new ClassRosterController(myService, myView);
    controller.run();
}

// 修改后代码
public static void main(String[] args) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    ClassRosterController controller = ctx.getBean("controller", ClassRosterController.class);
    controller.run();
}

这样做的好处是将对象的创建和依赖管理从代码中分离出来,提高了代码的可维护性和可测试性。当需要更改依赖关系时,只需要修改 applicationContext.xml 文件,而不需要修改 Java 代码。

单元测试转换代码分析

在服务层单元测试中,同样将手动实例化对象的代码迁移到 applicationContext.xml 文件。原代码在构造函数中手动创建 DAO 和服务层对象,而修改后的代码使用 Spring 容器获取服务层对象。

// 原代码
public ClassRosterServiceLayerTest() {
    ClassRosterDao dao = new ClassRosterDaoStubImpl();
    ClassRosterAuditDao auditDao = new ClassRosterAuditDaoStubImpl();
    service = new ClassRosterServiceLayerImpl(dao, auditDao);
}

// 修改后代码
public ClassRosterServiceLayerTest() {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    service = ctx.getBean("serviceLayer", ClassRosterServiceLayer.class);
}

这种方式使得单元测试更加灵活,因为可以通过修改 applicationContext.xml 文件轻松更换 DAO 的实现,例如使用存根版本进行测试。

10. 深入理解 Spring 配置文件

applicationContext.xml 文件是 Spring 应用的核心配置文件,其中定义了各个 bean 以及它们之间的依赖关系。以下是对文件中关键部分的详细解释:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- Bean definitions go here -->
    <bean id="userIO" class="com.sg.classroster.ui.UserIOConsoleImpl"/>
    <bean id="view" class="com.sg.classroster.ui.ClassRosterView">
        <constructor-arg ref="userIO"/>
    </bean>
    <bean id="classRosterDao" class="com.sg.classroster.dao.ClassRosterDaoFileImpl"/>
    <bean id="auditDao" class="com.sg.classroster.dao.ClassRosterAuditDaoFileImpl"/>
    <bean id="serviceLayer" class="com.sg.classroster.service.ClassRosterServiceLayerImpl">
        <constructor-arg ref="classRosterDao"/>
        <constructor-arg ref="auditDao"/>
    </bean>
    <bean id="controller" class="com.sg.classroster.controller.ClassRosterController">
        <constructor-arg ref="serviceLayer"/>
        <constructor-arg ref="view"/>
    </bean>
</beans>
  • bean 标签 :每个 bean 标签代表一个要由 Spring 容器管理的对象。 id 属性是该 bean 的唯一标识符, class 属性指定了该 bean 的具体实现类。
  • constructor-arg 标签 :用于在创建 bean 时传递构造函数参数。 ref 属性表示引用另一个已定义的 bean,通过这种方式可以建立 bean 之间的依赖关系。
11. 异常处理的最佳实践

为了避免在运行时出现配置文件相关的错误,我们可以遵循以下最佳实践:

  • 仔细检查类名和 id :在编写 applicationContext.xml 文件时,确保所有 bean 的类名和 id 拼写正确,特别是在使用 ref 属性引用其他 bean 时。
  • 验证 XML 格式 :使用 XML 验证工具或 IDE 的 XML 验证功能,确保 applicationContext.xml 文件的格式正确。
  • 使用注解或 Java 配置 :考虑使用注解(如 @Component @Autowired )或 Java 代码(如 @Configuration 类)来配置 Spring 容器,这样可以在编译时捕获更多错误。
12. 后续扩展与优化建议

将班级名册应用转换为 Spring 应用只是一个开始,我们可以在此基础上进行更多的扩展和优化:

  • 引入 Spring Boot :Spring Boot 可以简化 Spring 应用的开发和部署,提供自动配置和嵌入式服务器等功能。
  • 添加安全功能 :使用 Spring Security 为应用添加身份验证和授权功能,保护应用的敏感数据和接口。
  • 实现 RESTful API :利用 Spring MVC 或 Spring WebFlux 实现 RESTful API,使应用可以与其他系统进行交互。

以下是一个扩展功能的流程图:

graph LR
    A[现有 Spring 班级名册应用] --> B[引入 Spring Boot]
    B --> C[添加 Spring Security 安全功能]
    C --> D[实现 RESTful API]

通过以上步骤和建议,我们不仅成功将班级名册应用转换为 Spring 应用,还为应用的进一步发展和优化奠定了基础。在实际开发中,可以根据项目的具体需求选择合适的扩展方向,不断提升应用的性能和功能。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值