【SpringMVC 笔记】- 13 - 整合 SSM
一、SSM 整合概述
SSM(Spring + SpringMVC + MyBatis)是企业级 Java Web 开发中主流的轻量级框架组合,整合核心目标是:
- 让 Spring 作为核心容器,管理所有层的 Bean(Service、Dao、Controller 等),实现依赖注入(DI)和控制反转(IOC);
- Spring 整合 MyBatis:由 Spring 管理 MyBatis 的 SqlSessionFactory、数据源(DataSource),简化 MyBatis 的配置,同时整合事务管理;
- Spring 整合 SpringMVC:由 SpringMVC 处理前端请求,通过 Spring 容器实现 Controller 与 Service 层的解耦,统一 Bean 的管理。
二、环境准备
1. 引入相关依赖(Maven)
整合 SSM 需引入核心依赖,包括 Spring 核心、SpringMVC、MyBatis、MyBatis-Spring 整合包、数据库驱动、连接池、Servlet 相关、Thymeleaf(视图解析)等,示例pom.xml配置如下:
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.zzz</groupId>
<artifactId>ssm-integration</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<spring.version>6.1.5</spring.version>
<mybatis.version>3.5.16</mybatis.version>
<mybatis-spring.version>3.0.3</mybatis-spring.version>
<mysql.version>8.0.33</mysql.version>
<druid.version>1.2.20</druid.version>
<servlet-api.version>4.0.1</servlet-api.version>
<thymeleaf-spring.version>3.1.2.RELEASE</thymeleaf-spring.version>
</properties>
<dependencies>
<!-- Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- SpringMVC依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- MyBatis核心依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- MyBatis与Spring整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope>
</dependency>
<!-- 德鲁伊连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<!-- Thymeleaf与Spring整合 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring6</artifactId>
<version>${thymeleaf-spring.version}</version>
</dependency>
<!-- Lombok(可选,简化实体类) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<optional>true</optional>
</dependency>
</dependencies>
<!-- 构建配置:指定JDK版本、编译插件、WAR插件 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 创建包结构
遵循分层开发规范,创建如下包结构(基于com.zzz.ssm根包):
com.zzz.ssm
├── config // 配置类(Spring、SpringMVC、MyBatis、数据源等)
├── handler // 控制器(SpringMVC的Controller)
├── service // 服务层(接口+实现类)
│ └── impl
├── mapper // Mapper接口(MyBatis的Dao层)
├── pojo // 实体类(与数据库表映射)
└── utils // 工具类(可选)
3. 创建 webapp 目录
在src/main下创建webapp目录(Web 应用核心目录),用于存放静态资源(JS、CSS、图片)、页面文件(HTML/Thymeleaf),目录结构:
src/main/webapp
├── static // 静态资源目录
│ └── js // JS文件(Vue、Axios等)
├── WEB-INF // 受保护目录(存放视图文件,可选)
└── index.html // 首页(测试页面)
三、Spring 整合 MyBatis
1. 编写 jdbc.properties 配置文件
在src/main/resources(类根路径)下创建jdbc.properties,配置数据库连接信息,解耦数据源配置:
properties
# 数据库驱动(MySQL8.x为com.mysql.cj.jdbc.Driver)
jdbc.driver=com.mysql.cj.jdbc.Driver
# 数据库连接URL(指定字符集、时区)
jdbc.url=jdbc:mysql://localhost:3306/ssm_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
# 数据库用户名
jdbc.username=root
# 数据库密码
jdbc.password=123456
# 连接池初始大小
jdbc.initialSize=5
# 连接池最大活跃数
jdbc.maxActive=10
# 连接池最大等待时间
jdbc.maxWait=3000
2. 编写数据源配置类(DataSourceConfig)
在config包下创建DataSourceConfig,用于加载数据库配置、创建数据源(Druid),交由 Spring 管理:
java
package com.zzz.ssm.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.sql.SQLException;
/**
* 数据源配置类:加载数据库配置、创建数据源、配置事务管理器
*/
@Configuration
@PropertySource("classpath:jdbc.properties") // 加载jdbc.properties配置文件
public class DataSourceConfig {
// 从配置文件注入属性
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.initialSize}")
private int initialSize;
@Value("${jdbc.maxActive}")
private int maxActive;
@Value("${jdbc.maxWait}")
private int maxWait;
/**
* 创建Druid数据源Bean,交由Spring管理
*/
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setInitialSize(initialSize);
dataSource.setMaxActive(maxActive);
dataSource.setMaxWait(maxWait);
// 可选:配置连接池其他参数(如过滤、监控)
try {
dataSource.setFilters("stat");
} catch (SQLException e) {
e.printStackTrace();
}
return dataSource;
}
/**
* 配置事务管理器:基于数据源的事务管理器,供Spring事务控制使用
*/
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
3. 编写 MyBatis 配置类(MyBatisConfig)
在config包下创建MyBatisConfig,整合 MyBatis 与 Spring,配置SqlSessionFactory、扫描 Mapper 接口:
java
package com.zzz.ssm.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.io.IOException;
/**
* MyBatis配置类:整合MyBatis与Spring
*/
@Configuration
public class MyBatisConfig {
/**
* 创建SqlSessionFactoryBean:MyBatis核心工厂,由Spring管理
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws IOException {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
// 设置数据源(依赖DataSourceConfig的dataSource Bean)
factoryBean.setDataSource(dataSource);
// 设置MyBatis配置文件(可选,如配置别名、插件等)
// factoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
// 设置实体类别名包(简化Mapper.xml中的类型引用)
factoryBean.setTypeAliasesPackage("com.zzz.ssm.pojo");
// 扫描Mapper.xml文件(可选,若Mapper接口与XML同包可省略)
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
return factoryBean;
}
/**
* 配置Mapper扫描器:自动扫描指定包下的Mapper接口,生成代理对象交由Spring管理
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
// 指定Mapper接口所在包
scannerConfigurer.setBasePackage("com.zzz.ssm.mapper");
// 指定SqlSessionFactoryBean的名称(默认可省略)
scannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
return scannerConfigurer;
}
}
4. 编写 Spring 核心配置类(SpringConfig)
在config包下创建SpringConfig,作为 Spring 核心配置类,扫描组件、开启事务管理:
java
package com.zzz.ssm.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Spring核心配置类:整合各子配置、扫描组件、开启事务
*/
@Configuration
// 扫描Service、Mapper、Pojo等层的组件(排除Controller,由SpringMVC扫描)
@ComponentScan(basePackages = "com.zzz.ssm",
excludeFilters = @ComponentScan.Filter(type = org.springframework.context.annotation.FilterType.ANNOTATION,
classes = org.springframework.stereotype.Controller.class))
// 导入数据源、MyBatis配置类
@Import({DataSourceConfig.class, MyBatisConfig.class})
// 开启事务管理(基于注解)
@EnableTransactionManagement
public class SpringConfig {
}
四、Spring 整合 SpringMVC
1. 编写 Web 应用初始化类(WebAppInitializer)
替代传统web.xml,实现WebApplicationInitializer接口,配置 Spring 容器、SpringMVC 前端控制器:
java
package com.zzz.ssm.config;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
/**
* Web应用初始化类:替代web.xml,配置Spring容器和SpringMVC前端控制器
*/
public class WebAppInitializer implements org.springframework.web.WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
// 1. 配置Spring根容器(非Web层:Service、Mapper等)
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(SpringConfig.class); // 注册Spring核心配置类
// 添加Spring容器监听器
servletContext.addListener(new ContextLoaderListener(rootContext));
// 2. 配置SpringMVC容器(Web层:Controller)
AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
mvcContext.register(SpringMvcConfig.class); // 注册SpringMVC配置类
// 3. 配置DispatcherServlet(SpringMVC前端控制器)
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcherServlet", new DispatcherServlet(mvcContext));
dispatcher.setLoadOnStartup(1); // 启动时加载
dispatcher.addMapping("/"); // 拦截所有请求(排除静态资源)
}
}
2. 编写 SpringMVC 配置类(SpringMvcConfig)
在config包下创建SpringMvcConfig,配置视图解析、静态资源处理、视图控制器、组件扫描等:
java
package com.zzz.ssm.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring6.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import org.thymeleaf.templateresolver.TemplateResolver;
/**
* SpringMVC配置类:配置视图解析、静态资源、视图控制器等
*/
@Configuration
@EnableWebMvc // 开启SpringMVC注解驱动
@ComponentScan(basePackages = "com.zzz.ssm.handler") // 扫描Controller
public class SpringMvcConfig implements WebMvcConfigurer {
/**
* 配置Thymeleaf视图解析器(可选,若使用Thymeleaf)
*/
// @Bean
// public ThymeleafViewResolver thymeleafViewResolver(TemplateResolver templateResolver) {
// ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
// viewResolver.setTemplateResolver(templateResolver);
// viewResolver.setCharacterEncoding("UTF-8");
// return viewResolver;
// }
// /**
// * 配置Thymeleaf模板解析器
// */
// @Bean
// public TemplateResolver templateResolver(ServletContext servletContext) {
// ServletContextTemplateResolver resolver = new ServletContextTemplateResolver(servletContext);
// resolver.setPrefix("/WEB-INF/templates/"); // 视图文件前缀
// resolver.setSuffix(".html"); // 视图文件后缀
// resolver.setTemplateMode("HTML");
// resolver.setCharacterEncoding("UTF-8");
// return resolver;
// }
/**
* 开启静态资源处理:让SpringMVC放行静态资源(如JS、CSS)
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable(); // 启用默认Servlet处理静态资源
}
/**
* 配置视图控制器:直接映射请求到视图,无需编写Controller
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 访问根路径"/"时,直接跳转至index视图(对应webapp/index.html)
registry.addViewController("/").setViewName("index");
}
}
五、添加事务控制
Spring 整合 MyBatis 后,通过注解实现声明式事务管理,步骤如下:
第一步:在 SpringConfig 中开启事务管理
已在SpringConfig中添加@EnableTransactionManagement注解,开启注解驱动的事务管理。
第二步:在 DataSourceConfig 中配置事务管理器
已在DataSourceConfig中创建PlatformTransactionManager类型的transactionManager Bean(基于 Druid 数据源)。
第三步:在 Service 类 / 方法上添加事务注解
在 Service 实现类或方法上添加@Transactional注解,声明事务规则:
java
package com.zzz.ssm.service.impl;
import com.zzz.ssm.mapper.UserMapper;
import com.zzz.ssm.pojo.User;
import com.zzz.ssm.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* UserService实现类:添加事务注解
*/
@Service
@Transactional // 类级别:所有方法均开启事务
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
@Transactional(readOnly = true) // 方法级别:只读事务(优化性能)
public User getById(Long id) {
return userMapper.selectById(id);
}
// 其他业务方法(如新增/修改/删除)可配置事务传播行为、隔离级别等
// @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
// public void saveUser(User user) {
// userMapper.insert(user);
// }
}
六、实现功能测试(用户信息查询)
1. 数据库表设计
创建user表(示例):
sql
CREATE DATABASE IF NOT EXISTS ssm_db DEFAULT CHARACTER SET utf8mb4;
USE ssm_db;
CREATE TABLE IF NOT EXISTS `user` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
`age` INT(3) DEFAULT NULL COMMENT '年龄',
`gender` VARCHAR(10) DEFAULT NULL COMMENT '性别',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 插入测试数据
INSERT INTO `user` (`username`, `age`, `gender`) VALUES ('张三', 20, '男');
2. 编写 POJO 实体类
在pojo包下创建User类,与数据库表映射:
java
package com.zzz.ssm.pojo;
import lombok.Data;
/**
* 用户实体类:与user表映射
*/
@Data // Lombok注解,自动生成get/set/toString等方法
public class User {
private Long id;
private String username;
private Integer age;
private String gender;
}
3. 编写 Mapper 接口(Dao 层)
在mapper包下创建UserMapper接口,定义数据库操作方法:
java
package com.zzz.ssm.mapper;
import com.zzz.ssm.pojo.User;
import org.apache.ibatis.annotations.Select;
/**
* UserMapper接口:MyBatis的Dao层
*/
public interface UserMapper {
/**
* 根据ID查询用户
*/
@Select("SELECT id, username, age, gender FROM user WHERE id = #{id}")
User selectById(Long id);
}
注:也可通过
Mapper.xml编写 SQL,需放在src/main/resources/mapper目录下,与接口名一致。
4. 编写 Service 层(接口 + 实现类)
(1)Service 接口
java
package com.zzz.ssm.service;
import com.zzz.ssm.pojo.User;
/**
* UserService接口:服务层
*/
public interface UserService {
/**
* 根据ID查询用户
*/
User getById(Long id);
}
(2)Service 实现类
java
/**
* UserService实现类:添加事务注解
*/
@Service
@Transactional // 类级别:所有方法均开启事务
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
@Transactional(readOnly = true) // 方法级别:只读事务(优化性能)
public User getById(Long id) {
return userMapper.selectById(id);
}
// 其他业务方法(如新增/修改/删除)可配置事务传播行为、隔离级别等
// @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
// public void saveUser(User user) {
// userMapper.insert(user);
// }
}
5. 编写 Handler(Controller)
在handler包下创建UserHandler,处理前端请求:
java
package com.zzz.ssm.handler;
import com.zzz.ssm.pojo.User;
import com.zzz.ssm.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户控制器:处理用户相关请求
*/
@RestController // 标识为控制器,且返回JSON数据(替代@Controller+@ResponseBody)
@RequestMapping("/users") // 基础请求路径
public class UserHandler {
@Autowired // 依赖注入UserService
private UserService userService;
/**
* 根据ID查询用户
* @param id 用户ID
* @return 用户信息(JSON格式)
*/
@GetMapping("/{id}") // 匹配GET请求:/users/{id}
public User detail(@PathVariable("id") Long id){
return userService.getById(id);
}
}
6. 前端页面与 AJAX 请求
(1)引入静态资源
将vue3.4.21.js、axios.min.js放入webapp/static/js目录下。
(2)编写首页(index.html)
在webapp目录下创建index.html,通过 Vue+Axios 发送 AJAX 请求:
html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>SSM整合测试</title>
<!-- 引入Vue -->
<script th:src="@{/static/js/vue3.4.21.js}"></script>
<!-- 引入Axios -->
<script th:src="@{/static/js/axios.min.js}"></script>
</head>
<body>
<div id="app">
<button @click="getMessage">查看id=1的用户信息</button>
<h1>{{message}}</h1>
</div>
<script th:inline="javascript">
// 创建Vue应用
Vue.createApp({
data(){ // 定义响应式数据
return {
message : '' // 存储用户信息
}
},
methods : { // 定义方法
async getMessage(){ // 异步方法(await需配合async)
// 发送GET请求:/users/1
let response = await axios.get([[@{/}]] + 'users/1')
// 将返回的用户信息转为字符串显示
this.message = JSON.stringify(response.data)
}
}
}).mount("#app") // 挂载到id为app的元素上
</script>
</body>
</html>
七、部署与测试
1. 部署项目
将项目打包为 WAR 包,部署到 Tomcat(或使用 IDEA 的 Tomcat 插件运行)。
2. 测试流程
- 启动 Tomcat,访问
http://localhost:8080/ssm-integration/(项目上下文路径根据实际配置调整); - 点击页面中的「查看 id=1 的用户信息」按钮;
- 页面显示用户信息(如
{"id":1,"username":"张三","age":20,"gender":"男"}),说明 SSM 整合成功。
八、常见问题与注意事项
- 依赖版本冲突:Spring、SpringMVC、MyBatis、MyBatis-Spring 需保证版本兼容(如 Spring6 需搭配 MyBatis-Spring3.x);
- 数据源配置错误 :检查
jdbc.properties中的 URL、用户名、密码,确保数据库服务已启动; - 静态资源无法访问 :需在
SpringMvcConfig中开启configureDefaultServletHandling; - 事务不生效 :
- 确保添加了
@EnableTransactionManagement注解; - 事务注解
@Transactional需加在 Service 层(而非 Controller/Mapper); - 异常需为运行时异常(或配置
rollbackFor指定受检异常);
- 确保添加了
- Mapper 接口扫描失败 :检查
MapperScannerConfigurer的basePackage是否正确,确保 Mapper 接口无语法错误; - 前端 AJAX 跨域(可选) :若前后端分离,需在 SpringMVC 中配置跨域(添加
@CrossOrigin或全局跨域配置)。
九、整合总结
SSM 整合的核心是「分层配置、统一管理」:
- Spring 作为核心容器,通过配置类管理数据源、SqlSessionFactory、事务管理器,实现 Service、Mapper 的依赖注入;
- SpringMVC 负责请求接收与响应,通过注解驱动简化控制器开发,配合静态资源配置、视图控制器提升开发效率;
- MyBatis 专注于数据持久层,通过 Spring 整合后,无需手动管理 SqlSession,简化数据库操作;
- 事务管理通过 Spring 的声明式事务实现,降低代码耦合度,提升可维护性。
通过本次整合,实现了「前端 AJAX 请求 → SpringMVC Controller → Spring Service(事务) → MyBatis Mapper → 数据库」的完整调用链路,为企业级 Web 应用开发奠定基础。