1.前置知识
1.1 Tomcat
Tomcat 是一个开源的轻量级 Web (Http) 服务器和 Servlet 容器。它实现了 Java Servlet 等 Java EE 规范的核心功能,常用于部署和运行 Java Web 应用程序。换言之,Tomcat 就是一个严格遵循 Servlet 规范开发出来的、可以独立安装和运行的 Java Web 服务器/Servlet 容器。
核心功能:
- Servlet 容器:支持 Servlet 的执行,处理 HTTP 请求和响应。
- Web 服务器:提供静态资源 (如 HTML) 的访问能力,支持基本的 HTTP 服务。
目录结构:
- bin: 存放可执行文件,如 startup.bat。
- conf: 存放配置文件。
- lib: 存放 Tomcat 运行所需的 jar 文件。
- logs: 存储日志文件。
- temp: 存放临时文件,如上传的文件或缓存数据。
- webapps: 默认 web 应用部署目录。
- work: 服务器的工作目录,存放运行时生成的临时文件 (编译文件)。
1.2 Servlet
1.2.1 定义
Servlet 是 Java 语言编写的、运行在服务器端的程序,它遵循一套标准的 API 规范 (Tomcat 是这套规范的一个具体实现/容器,并提供了让 Servlet 与前端交互的运行时环境)。
1.2.2 API 示范
创建项目/配置文件:
- 在 IDEA 中创建 Maven 项目。
- 在 pom.xml 文件中添加 servlet 依赖 (置于
<project> 标签下)。
<dependencies>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
- 在 main 路径下创建 webapp/Web-INF/web.xml,在 xml 文件中添加以下内容。
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
- 配置插件以便启动项目。
API 示例:
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/method")
public class MethodServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
System.out.println("doPost");
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().write("doPost");
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {
System.out.println("doPut");
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().write("doPut");
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException {
System.out.println("doDelete");
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().write("doDelete");
}
}
1.2.3 生命周期
定义:Servlet 生命周期由 Web 容器 (如 Tomcat) 管理,包含加载、初始化、处理请求和销毁四个阶段。每个阶段对应特定的方法调用,开发者可通过重写这些方法实现自定义逻辑。
- 类加载:Web 容器通过类加载器加载 Servlet 类 (通常首次请求触发或容器启动时预加载,字节码文件被加载到内存但未实例化)。
- 实例化:确认 Servlet 类成功加载后立刻执行,在整个 Web 容器中每种 Servlet 类 (如 HttpServlet) 只会有一个实例化对象。
- 初始化:Web 容器调用刚刚创建好的 Servlet 实例的
init(ServletConfig config) 方法,在整个 servlet 实例的生命周期中仅调用一次,主要作用是读取配置和资源加载。若初始化失败,抛出 ServletException,Servlet 不会被加入可用队列。
- 处理请求:Web 容器为每个请求创建线程,调用
service(ServletRequest req, ServletResponse res) 方法。service() 方法根据 HTTP 请求类型 (get/post) 调用 doGet() 或 doPost()。
- 销毁:Web 容器调用 destroy() 方法,Servlet 实例被标记为垃圾回收。
2.SpringBoot
Servlet 是 Java EE 规范中处理 Web 请求的核心组件,但随着应用复杂度提升,Servlet 的直接使用显得笨重。Spring 框架通过一系列抽象和扩展,简化了企业级应用开发。
我们可以用一个非常形象的比喻来贯穿始终:建造一座房子。
第一阶段:Servlet 时代 - 自己烧砖砌墙
- 目标:建造一个能遮风挡雨的房子 (一个能处理 HTTP 请求的 Web 应用)。
- 你的工作状态:
- 材料:你有最基础的原材料——泥土 (Java 语言) 和水 (JVM)。你需要自己烧制砖块 (编写 Servlet 类)。
- 工具:只有简单的泥瓦刀 (Servlet API)。
- 过程:
- 你为每一面墙、每一扇门都亲手烧制一块特定的砖 (编写 LoginServlet, UserServlet, OrderServlet)。
- 你亲自规划每块砖的位置 (在 web.xml 中配置大量的
<servlet> 和 <servlet-mapping>)。
- 你亲自搅拌水泥,一块一块地砌墙 (在每个 Servlet 的 doGet/doPost 方法中手动解析参数、处理业务、组装 HTML)。
- 核心特点:
- 高度灵活:你可以造出任何形状的砖。
- 极其繁琐:大量重复性劳动 (每个 Servlet 都有获取参数、关闭连接等样板代码)。
- 难以维护:砖块之间紧密耦合 (对象依赖硬编码),想换一扇窗 (修改功能) 可能会牵动整面墙。
- 依赖外部:房子建在别人的地上 (需要将 war 包部署到外部的 Tomcat 服务器)。
- 总结:Servlet 提供了 Web 开发的基础能力,但开发效率极低,代码冗余且难以维护。
第二阶段:Spring 时代 - 使用预制件和设计图纸
- 目标:用更高效、更标准化的方式建造一个结构更好、更易扩展的房子。
- 你的工作状态:
- 材料:你不再烧砖,而是使用工厂提供的标准化预制件 (Spring Bean,如
@Controller, @Service)。
- 核心创新:你聘请了一位神奇的管家 (IoC 容器)。你不再亲自'砌砖'(用 new 实例化对象),只需告诉管家你需要什么 (用
@Autowired 声明依赖)。管家会自动把预制件 (Bean) 按照图纸 (配置) 组装好,送到你手上 (依赖注入 DI)。
- 过程:
- 一个总大门 (DispatcherServlet):房子只有一个入口,所有访客 (请求) 都先到这里。
- 管家调度:总大门处的接待员 (DispatcherServlet) 根据访客需求,呼叫房子里对应的专业房间 (
@Controller 中的方法) 来接待。
- 开发者只需专注于房间内的专业服务 (业务逻辑),而不用关心访客是怎么进来的。
- 核心特点:
- 解耦:预制件之间是松耦合的,易于更换和测试。
- 专业化:AOP(面向切面编程) 可以像'装修队'一样,非侵入式地为所有房间统一安装中央空调(日志、安全、事务)。
- 效率提升:避免了大量重复劳动,结构清晰。
- 配置复杂:绘制详细的'组装图纸'(配置 Spring) 本身成了一项复杂的工作。
- 总结:Spring 框架通过 IoC/DI 和 AOP 等理念,解决了代码耦合和重复劳动问题,但引入了显著的配置复杂度。
Spring Boot 1.0.0 正式发布于 2014 年 4 月 1 日,标志着该框架的首次稳定版本发布。SpringBoot 基于 Spring Framework 4 进行设计,显著减少了开发者的配置工作量,彻底消除了 Spring 的配置地狱。
- 约定大于配置:约定了默认配置。
- Start 机制:是一种依赖管理机制,每个 Starter 包含特定功能所需的依赖库和自动配置类,开发者只需引入对应 Starter 即可快速启用功能模块。
- 嵌入式容器:内置了 Tomcat 等嵌入式容器,无需部署 war 文件到外部容器,直接运行即可启动应用。
3.Spring Web MVC
3.1 概述
官方描述:Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,并从一开始就在 Spring 框架中。正式名称'Spring Web MVC',来自其源模块的名称 (spring-webmvc),但它通常被称为'Spring MVC'。
MVC 的起源与发展:MVC (Model-View-Controller) 模式最初由挪威计算机科学家 Trygve Reenskaug 于 1978 年在施乐帕克研究中心 (Xerox PARC) 提出,目的是为 Smalltalk 编程语言设计用户界面。其核心思想是将应用程序的逻辑分为三个独立组件:
- Model:处理数据逻辑和业务规则。
- View:负责数据展示和用户界面。
- Controller:接收用户输入并协调 Model 与 View 的交互。
Spring MVC 与 MVC 的关系:Spring MVC 是 MVC 模式在 Spring 框架中的具体化,同时扩展了传统 MVC 的功能以适应现代 Web 开发需求。
3.2 必需工具
Postman:主要用于 API 的开发和测试。它提供了一个用户友好的界面,支持发送 HTTP 请求、管理请求历史、自动化测试以及团队协作。
Fiddler:是一个网络调试代理工具,主要用于监控和分析 HTTP/HTTPS 流量。它可以捕获设备与服务器之间的所有请求和响应,支持修改请求、重放请求以及性能分析。
3.3 RequestMapping
作用:是 Spring MVC 中最核心、最基础的注解之一,用于将 HTTP 请求映射到具体的方法上。
注解级别:类 + 方法。
- 作为类注解:可以为整个类提供一个统一的 url 前缀 (可有可无)。
- 作为方法注解:指定该方法负责处理哪个 url 的请求 (强制要求)。
@RequestMapping("/HelloController")
@RestController
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET, produces = "application/json")
public String hello() {
return "{\"Hello\" : World}";
}
@RequestMapping("/receiveAge1")
public String receiveAge1(Integer age) {
return "接收到参数 age:" + age;
}
@RequestMapping("/receiveAge2")
public String receiveAge2(int age) {
return "接收到参数 age:" + age;
}
@RequestMapping("/receiveArray")
public String receiveArray(String[] array) {
return "接收到参数 array:" + Arrays.toString(array);
}
@RequestMapping("/receivePerson")
public String receivePerson(Person person) {
return + person;
}
}
3.4 RequestBody
作用:将 HTTP 请求体中的 json 数据绑定到 Java 对象 (方法注解)。
注解级别:方法。
@RequestMapping("/receivePerson")
public String receivePerson(@RequestBody Person person) {
return "接收到参数 person:" + person;
}
3.5 RequestParam
作用:是 Spring MVC 框架中从 HTTP 请求中提取参数/查询字符串的注解,主要用于将请求参数绑定到控制器方法的参数上。
注解级别:方法。
@RequestMapping("/receiveRename")
public String receiveRename(@RequestParam(value = "name", required = false) String userName) {
return "接收到参数 name:" + userName;
}
注意:需要接收多个同名参数时 (如 param=value1¶m=value2),直接绑定到 List 类型需通过该注解明确声明。
(1) 在 Spring MVC 中,参数绑定机制对集合类型和数组类型的处理存在差异。
(2) 使用 ArrayList<String> 作为方法参数时,必须显式添加 @RequestParam 注解,原因如下:
- 默认绑定规则:Spring 默认将单个请求参数的值绑定到简单类型 (如 String、int) 或单个对象。对于集合类型,框架无法自动推断是否需要将多个同名参数合并为集合。
- 需要明确指示:@RequestParam 注解会告知 Spring 将同名请求参数的值收集到一个集合中。
(3) 数组 (如 String[]) 无需 @RequestParam 注解即可正确接收,原因如下:
- 内置支持:Spring 对数组类型有原生支持,能自动将多个同名请求参数值绑定到数组。这是框架的默认行为,无需额外配置。
@RequestMapping("/receiveList1")
public String receiveList1(ArrayList<String> list) {
return "接收到参数 list:" + list;
}
@RequestMapping("/receiveList2")
public String receiveList2(@RequestParam(required = false) ArrayList<String> list) {
return "接收到参数 list:" + list;
}
@RequestMapping("/receiveList3")
public String receiveList3(List<String> list) {
return "接收到参数 list:" + list;
}
后端报错:java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List。
receiveList3 方法使用 List<String> 接口类型而非具体实现类。Spring 虽然支持接口类型参数绑定,但需要满足特定条件:必须配合 @RequestParam 注解使用,不能直接使用未注解的接口类型参数。
报错根本原因:Spring 尝试实例化 List 接口失败 (接口不可实例化)。
3.6 PathVariable
作用:用于从 URL 路径中提取变量值并绑定到方法的参数上。
注解级别:方法。
@RequestMapping("/receivePath/{article}/{blog}")
public String receivePath(@PathVariable(value = "article", required = false) Integer title,
@PathVariable(value = "blog", required = false) String content) {
return "接收到参数 article:" + title + " blog:" + content;
}
3.7 RequestPart
作用:用于处理 HTTP 请求中的 multipart/form-data 类型数据,通常用于文件上传或同时上传文件和其他表单字段的场景。
注解级别:方法。
@RequestMapping("/receiveFile")
public String receiveFile(@RequestPart(value = "file", required = false) MultipartFile imgFile,
@RequestParam(value = "userName", required = false) String name) {
return "用户:" + name + ",接收到文件:" + imgFile.getOriginalFilename();
}
3.8 Controller & ResponseBody & RestController
Controller
- 作用:是 Spring MVC 中的核心注解,用于标记一个类作为 Web 请求的处理器 (声明一个类是一个 Spring MVC 控制器),负责处理 HTTP 请求并返回视图。
- 注解级别:类。
ResponseBody
- 作用:指示方法返回值应直接写入 HTTP 响应体,而非通过视图解析器渲染。
- 注解级别:类 + 方法。
@RequestMapping("/ControllerResponse")
@Controller
public class ControllerResponse {
@RequestMapping("/HTMLView")
public String HTMLView() {
return "/show.html";
}
@ResponseBody
@RequestMapping("/HTMLData")
public String HTMLData() {
return "/show.html";
}
}
RestController
- 作用:是 Spring MVC 中的一个组合注解,它结合了
@Controller 和 @ResponseBody 的功能,标记的类所有方法返回值默认直接作为 HTTP 响应体 (JSON/XML 等格式),无需额外视图渲染。
- 注解级别:类。