- 1WEB 基础HTTP / Browser / WebServer静态页面写死,人人看到一样
- 2Servlet手写 if-else 分发不可扩展,无生命周期/并发管理
- 3JSP:参数散字符串参数散成一堆 String,取值靠字段名硬记
- 3JSP:scriptlet 塞逻辑scriptlet 把逻辑塞进页面,代码与 HTML 糊在一起
- 3JavaBean:数据对象化对象全靠 new、层层硬依赖
- 4Spring IoCWeb 路由仍手写 web.xml/if-else、手动取参绑定,展示/业务/数据访问没分开
- 5MVC · SpringMVC数据在库里,访问是重复样板 + 拼串有注入风险
- 6MySQLJava 连库要手写五步,连接与资源管理全手动
- 7JDBCSQL 与 Java 混写、结果集逐行手映射、没有动态 SQL
- 8MyBatis四份配置 + web.xml 装配繁琐,部署要外部 Tomcat
- 9SpringBoot链尾 · 不考核
进阶拓展(可选)
进阶拓展(可选):SSM 之后的技术版图
定位:本页是可选进阶拓展,不占核心课时、不并入期中/期末范围。学完 SSM 主线后,用一节课的时间把「SSM 之后」常见的五块技术串起来——Spring Data、模板引擎(Thymeleaf)、EL·JSTL、反射与注解、泛型——理解它们各自解决什么问题、和前面学的东西怎么衔接。(Spring Boot 已单列模块9,见该章。)能真实编译运行的纯 Java 片段用
CodePlayground,泛型擦除用GenericEraseDemo交互演示。
模块9 指针:Spring Boot(约定大于配置、starter 依赖、自动配置、内嵌 Tomcat +
java -jar)已独立成**模块9「SpringBoot」**章,本章不再重复,只把它作为「SSM 之后的第一站」顺带一提。
一、Spring Data:把 Mapper 的样板再省一层
模块8 MyBatis 里,每个实体都要写「Mapper 接口 + XML 映射文件」。Spring Data 更激进——连接口都不用你写全:
- Spring Data JPA:定义一个继承
JpaRepository<T, ID>的接口,findById/save/findAll/delete等常用 CRUD 直接可用;自定义查询用方法名约定(如findByEmailAndGender)自动翻译成语句。 - Spring Data JDBC / Mongo:同一套 Repository 抽象,换存储只换 starter。
对比一下三层持久化技术要写多少东西:
| 技术 | 持久层要写什么 |
|---|---|
| 原生 JDBC | Connection / Statement / ResultSet 全手写 |
| MyBatis(模块8) | Mapper 接口 + XML(SQL 自己写,显式可控) |
| Spring Data JPA | 只写 Repository 接口,SQL 由框架生成 |
取舍:MyBatis 的 SQL 显式、可控、调优友好;Spring Data 更「约定化」、上手快,但复杂查询仍需下沉到 JPQL / 原生 SQL。生产里两者常见混用。
二、模板引擎(Thymeleaf):JSP 的现代替代
模块3 学的 JSP 把 Java 代码和 HTML 混在一起,维护性差。现代 SpringMVC / Spring Boot 项目普遍用服务端模板引擎,Thymeleaf 最典型:
- 自然模板:页面就是合法 HTML,浏览器直接打开也能看(JSP 不行)。
- EL 表达式 +
th:*属性:${user.name}、th:each、th:if等属性替换 JSP 的<% %>/<%= %>。
<!-- Thymeleaf:在 HTML 属性里用 th:* 前缀,未渲染时也是合法 HTML -->
<tr th:each="dept : ${depts}">
<td th:text="${dept.deptName}"></td>
</tr>
三、EL 与 JSTL:JSP 里的表达式与标签库
如果还在维护 JSP(模块3),EL 表达式和 JSTL 标签库是绕不开的:
- EL 表达式
${...}:从 request / session / application 作用域取值,替代<%= %>。${param.name}取请求参数,${sessionScope.user}取会话属性。 - JSTL:一组标准标签,
<c:forEach>(循环)、<c:if>(条件)、<fmt>(格式化),替代 JSP 里的 Java 程序片<% %>。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:forEach var="w" items="${requestScope.words}">
<li><c:out value="${w.word}"/></li>
</c:forEach>
衔接:EL/JSTL 是「JSP 时代」的写法;Thymeleaf 是「框架时代」的等价能力。两者都在解决同一件事——把取值 / 循环 / 条件用声明式语法表达,而不是在页面里嵌 Java 代码。
四、反射与注解:IoC 的底层支撑
模块4 Spring IoC 能「扫描 @Component、按 @Autowired 注入」,靠的就是反射 + 注解这对组合拳:
- 反射(Reflection):运行时通过
Class对象拿到类名、方法、字段,用newInstance()/getMethod().invoke()动态创建对象、调用方法——容器不必在编译期写死new。 - 注解(Annotation):
@Component/@Autowired本质是「带@Retention(RUNTIME)的标记」,反射可以getAnnotation()读出来,据此决定装配规则。
下面用 CodePlayground 在线真实编译运行一段纯 Java 代码(可编辑你的版本,观察反射在运行时读取类与方法信息):
交互实验:浏览器里编译运行 Java(CodePlayground)
未连接左边写 Java,点「运行」——源码经 WebSocket+STOMP 发给后端(端口 8081),真实javac编译 + java 运行,输出推回你的浏览器。先选一个预置程序试试:
← 点「运行」看编译/运行结果
💡 最小可运行程序:UTF-8 中文输出 + 表达式求值。
ws://<host>:8081/ws)→ 后端 STOMP /app/run → 沙箱编译运行 → 结果推回你的会话专属队列 /queue/result-<你的id>。每个浏览器标签页只收自己的结果,互不串台。五、泛型:类型安全的参数化
模块8/10 里 List<String>、Map<String, Object> 大量出现。泛型让集合「声明时指定元素类型」,编译期就能查错;但 Java 的泛型是**擦除(erasure)**实现的——运行时类型信息被去掉。用下面的交互组件逐行看编译器如何擦除 List<String>:
交互实验:泛型声明 vs 擦除后字节码(GenericEraseDemo)
泛型只存在于编译期:javac 把 List<String> 擦成裸的 List,元素按 Object 处理;编译器在「取出」处自动插入强转。 点击任意一行,看编译器对它的处理:
← 点击任意一行,看编译器做了什么(去掉类型参数 / 插入强转 / 不变)
| 表达式 | 结果 | 说明 |
|---|---|---|
| names.getClass().getName() | "java.util.ArrayList" | 类名里没有 <String>——类型参数在运行时根本不存在。 |
| names instanceof ArrayList | true | 运行时只能判断具体类(ArrayList),无法判断「装的是什么类型」。 |
| names.getClass() == nums.getClass() | true | names 是 List<String>、nums 是 List<Integer>——擦除后两者在 JVM 里是同一个类。 |
List<String> strings = new ArrayList<>();
strings.add("Tom");正常泛型用法:编译期类型安全,一切如常。
结论:泛型检查只发生在编译期——原始类型(raw type)绕过检查后,错误元素能混进集合,直到「取出」那行才以 ClassCastException 的形式爆炸。
要点:泛型只存在于编译期;
List<String>运行时就是一份裸List,取出元素时编译器自动插入强转。这也是为什么不能new T()、不能instanceof List<String>。
讨论问题
- MyBatis 与 Spring Data JPA 各适合什么场景?为什么很多项目两者混用?
- Thymeleaf 的「自然模板」相比 JSP 有什么实际好处(预览 / 维护 / 安全)?
- 反射 + 注解如何共同支撑 Spring IoC 的「扫描并注入」?没有反射,@Autowired 还能工作吗?
- Java 泛型为什么是「擦除」而非「重载」?这带来哪些限制(不能
new T()、不能instanceof参数化类型)?
学习测验
学习小测验
Spring Data JPA 中,定义一个继承 JpaRepository 的接口后,常用 CRUD 方法
Thymeleaf 相比 JSP 的一个显著优点是
JSP 中 EL 表达式 ${param.name} 的作用是
Spring IoC 能扫描 @Component 并按 @Autowired 注入,底层依赖
Java 泛型 List<String> 在运行时是