0%

Spring Boot 使用 JSP 详解:从依赖配置到视图渲染全流程

虽然 Spring Boot 推荐使用 Thymeleaf、Freemarker 等模板引擎,但在迁移传统 SSH/SSM 项目时,仍需支持 JSP 视图。由于 Spring Boot 对 JSP 的支持并非默认集成,需手动配置依赖、资源路径和视图解析器。从 “依赖配置→目录结构→视图解析→常见问题” 四个维度,详细讲解 Spring Boot 集成 JSP 的完整流程,帮你顺利实现 JSP 页面渲染。

核心背景:为什么 Spring Boot 不默认支持 JSP?

Spring Boot 推荐使用 嵌入式容器(如 Tomcat)和 可执行 JAR 打包,而 JSP 存在两个关键限制,导致其未被默认支持:

  1. JSP 编译依赖 Servlet 容器:JSP 需要 Tomcat 的 jasper 引擎编译为 Servlet 类,而嵌入式 Tomcat 默认不包含 jasper 依赖;
  2. JAR 包无法直接包含 JSP:JSP 文件需放在 WEB-INF 目录下,而 Spring Boot 默认的 JAR 打包结构中没有 WEB-INF,需手动配置资源路径映射。

因此,集成 JSP 的核心是 “添加 JSP 编译依赖” 和 “配置 JSP 资源目录”。

Spring Boot 集成 JSP 的完整步骤

步骤 1:添加 JSP 相关依赖

需引入两个核心依赖:tomcat-embed-jasper(JSP 编译引擎)和 jstl(JSP 标准标签库,可选但推荐)。

Maven 依赖配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<dependencies>
<!-- 1. Spring Boot Web 依赖(包含嵌入式 Tomcat) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 2. JSP 编译引擎(嵌入式 Tomcat 需手动引入) -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<!-- scope 无需设置为 provided,嵌入式 Tomcat 需要加载该依赖 -->
</dependency>

<!-- 3. JSTL 标签库(可选,使用 JSP 标签时需引入,如 c:forEach) -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
<exclusions>
<!-- 排除旧的 servlet-api 依赖,避免冲突 -->
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
依赖说明:
阅读全文 »

Spring BeanDefinition 详解:Bean 的 “元数据蓝图”

BeanDefinition 是 Spring 中描述 Bean 的核心元数据接口,它像一份 “蓝图”,定义了 Bean 的创建规则、属性配置、依赖关系等关键信息。Spring 容器正是基于这些元数据完成 Bean 的实例化、属性注入和生命周期管理。本文将从接口定义、核心属性、实现类体系三个维度,全面解析 BeanDefinition 的设计与作用。

BeanDefinition 核心接口:定义 Bean 的元数据规范

BeanDefinition 接口继承了 AttributeAccessor(属性访问)和 BeanMetadataElement(元数据元素)接口,为 Bean 定义了一套完整的元数据规范。其核心作用是 “描述 Bean 的所有特征,让 Spring 容器知道如何创建和管理这个 Bean”。

核心属性分类

BeanDefinition 的属性可分为基础配置依赖关系生命周期角色标识四大类,对应 XML 配置中的<bean>标签属性或注解配置的元信息:

类别 核心属性 对应 XML 配置示例
基础配置 类名(beanClassName)、作用域(scope)、是否抽象(abstract) <bean class="com.User" scope="singleton" abstract="false"/>
依赖关系 父 Bean(parentName)、依赖 Bean(dependsOn)、工厂 Bean(factoryBeanName) <bean parent="baseBean" depends-on="dataSource" factory-bean="userFactory"/>
生命周期 懒加载(lazyInit)、初始化方法(initMethodName)、销毁方法(destroyMethodName) <bean lazy-init="true" init-method="init" destroy-method="close"/>
装配规则 自动装配候选(autowireCandidate)、首选 Bean(primary) <bean autowire-candidate="true" primary="true"/>
角色标识 角色(role):区分用户定义 Bean 和 Spring 内部 Bean -

关键方法解析

(1)作用域相关
1
2
3
4
5
6
7
8
// 设置作用域(singleton/prototype等)
void setScope(String scope);
// 获取作用域
String getScope();
// 判断是否为单例(简化方法,等价于 scope == SCOPE_SINGLETON)
boolean isSingleton();
// 判断是否为原型(简化方法,等价于 scope == SCOPE_PROTOTYPE)
boolean isPrototype();
  • 单例(SCOPE_SINGLETON):容器中仅存在一个实例,默认值;
  • 原型(SCOPE_PROTOTYPE):每次getBean()都创建新实例。
(2)依赖与继承相关
1
2
3
4
5
6
7
// 设置父Bean名称(实现Bean配置继承)
void setParentName(String parentName);
String getParentName();

// 设置依赖的Bean(被依赖Bean优先初始化)
void setDependsOn(String... dependsOn);
String[] getDependsOn();
阅读全文 »

网络通信的分层封装与解析过程

在计算机网络中,数据的传输并非直接发送原始信息,而是通过分层封装的方式,在每一层为数据添加必要的控制信息(首部),确保数据能跨越复杂网络准确到达目标。接收方则通过逆向解析,逐层剥离首部,最终获取原始数据。以下是完整的通信流程解析:

数据发送:分层封装的全过程

数据从应用层产生到通过物理介质发送,需经过应用层、传输层、网络层、数据链路层的逐层处理,每一层都会在数据前添加该层的首部信息。

1. 应用层:数据的生成与编码

  • 操作:用户通过应用程序(如浏览器、邮件客户端)生成原始数据(如网页请求、邮件内容),并按照应用层协议(如 HTTP、SMTP)进行编码和格式化。
  • 示例:浏览器生成一个 HTTP 请求报文,包含请求方法(GET)、目标 URL、协议版本等信息。
  • 输出:应用层数据(无首部,仅原始内容)。

2. 传输层:添加端口与可靠性控制

  • 操作:传输层(TCP 或 UDP)接收应用层数据,在其前端添加传输层首部,核心信息包括:
    • 源端口号:标识发送方的应用程序(如浏览器用随机端口);
    • 目标端口号:标识接收方的应用程序(如 HTTP 服务用 80 端口);
    • 序号与确认号(TCP 特有):确保数据按序传输和可靠确认;
    • 校验和:用于检测数据传输过程中的损坏。
  • 示例:TCP 为 HTTP 请求添加首部,源端口为 12345,目标端口为 80,序号为 1000。
  • 输出:传输层报文(= 传输层首部 + 应用层数据)。

3. 网络层:添加 IP 地址与路由信息

  • 操作:网络层(IP 协议)接收传输层报文,将其作为自身数据,在前端添加IP 首部,核心信息包括:
    • 源 IP 地址:发送方设备的逻辑地址(如 192.168.1.100);
    • 目标 IP 地址:接收方设备的逻辑地址(如 203.0.113.5);
    • 协议字段:标识上层协议(如 TCP=6,UDP=17);
    • 生存时间(TTL):限制数据包的传输跳数,防止环路。
  • 示例:IP 首部中源 IP 为 192.168.1.100,目标 IP 为 203.0.113.5,协议字段为 6(表示上层是 TCP)。
  • 输出:IP 数据报(= IP 首部 + 传输层报文)。

4. 数据链路层:添加 MAC 地址与链路控制信息

阅读全文 »

MAC 地址:数据链路层的身份标识

MAC 地址(Media Access Control Address,介质访问控制地址)是数据链路层中用于唯一标识网络设备的物理地址,相当于设备在局域网中的 “身份证”,其核心作用是在同一数据链路(如以太网、Wi-Fi)中区分不同的节点,确保数据帧能准确送达目标设备。

MAC 地址的基本特性

  1. 唯一性
    每个网络接口(如网卡、无线网卡)的 MAC 地址全球唯一,由设备制造商在生产时写入硬件芯片(如网卡的 ROM),通常无法修改(部分设备支持软件伪造,但不符合标准规范)。这一特性确保了在同一链路中不会出现地址冲突。

  2. 固定性
    与可动态分配的 IP 地址不同,MAC 地址是 “烧录” 在硬件中的固定值,除非更换网卡,否则设备的 MAC 地址不会改变。例如,手机的 Wi-Fi 模块和电脑的有线网卡都有各自独立的 MAC 地址。

  3. 格式规范
    MAC 地址为48 位二进制数,通常以十六进制表示,格式为 6 组两位数字(或字母),各组之间用冒号(:)或连字符(-)分隔。例如:

    • 00:1A:2B:3C:4D:5E
    • 00-1A-2B-3C-4D-5E

    其中,前 24 位为厂商代码(由 IEEE 分配给设备制造商),后 24 位为厂商内部编号,用于区分同一厂商生产的不同设备。

MAC 地址的作用场景

MAC 地址仅在同一数据链路层中生效,其核心功能是实现 “链路内的点对点通信”,具体场景包括:

阅读全文 »

Elasticsearch 配置详解:从基础到高级优化

Elasticsearch 的配置直接影响集群的性能、稳定性和安全性。配置分为静态配置(仅通过配置文件设置,需重启生效)和动态配置(可通过 API 实时修改)。本文将系统解析核心配置项,包括网络、脚本、快照、线程池、索引等关键模块。

配置类型与优先级

  1. 静态配置
    • 定义位置:elasticsearch.yml(主配置文件)、jvm.options(JVM 参数)。
    • 生效方式:修改后需重启节点。
    • 涵盖范围:网络绑定、端口、JVM 堆大小、节点角色等基础参数。
  2. 动态配置
    • 定义方式:通过 /_cluster/settings API 设置。
    • 生效方式:实时生效,无需重启。
    • 涵盖范围:集群级参数(如副本数、刷新间隔)、线程池设置等。
  3. 优先级:显式配置(elasticsearch.yml 或 API)> 默认值;动态配置覆盖静态配置中可动态修改的参数。

网络配置:节点通信与连接

网络配置是集群部署的基础,确保节点间通信和客户端连接正常,主要包括 HTTP 层(客户端交互)和 Transport 层(节点间内部通信)。

核心网络参数(静态配置)

参数 作用 示例值
network.host 节点绑定的 IP 或主机名(默认 localhost 0.0.0.0(允许所有网卡)
network.bind_host 绑定的网络接口(默认同 network.host 192.168.1.100
network.publish_host 向集群其他节点宣告的 IP(默认同 network.host 192.168.1.100

HTTP 配置(客户端交互)

控制 HTTP 接口(默认 9200 端口)的行为,用于客户端(如 Kibana、API 调用)连接:

阅读全文 »